387 lines
12 KiB
C
387 lines
12 KiB
C
|
|
#include <time.h>
|
||
|
|
#include <assert.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
|
||
|
|
#include "ec.h"
|
||
|
|
#include "isog.h"
|
||
|
|
#include "test-basis.h"
|
||
|
|
#include <bench.h>
|
||
|
|
|
||
|
|
static int BENCH_LOOPS = 1000; // Number of iterations per bench
|
||
|
|
static int TEST_LOOPS = 128; // Number of iterations per test
|
||
|
|
|
||
|
|
// void random_scalar(fp_t k, const uint8_t j)
|
||
|
|
// {
|
||
|
|
// // To implement a better random function (We must use some of the SHAKE family functions)
|
||
|
|
// do
|
||
|
|
// {
|
||
|
|
// randombytes((void *)k, keyspace_bytes[j]);
|
||
|
|
// } while (fp_issmaller((uint64_t *)k, keyspace_size[j]));
|
||
|
|
// }
|
||
|
|
|
||
|
|
// VERY NOT SECURE (testing only)
|
||
|
|
void fp2_random(fp2_t *a){
|
||
|
|
for(int i = 0; i < NWORDS_FIELD; i++){
|
||
|
|
a->re[i] = rand();
|
||
|
|
a->im[i] = rand();
|
||
|
|
}
|
||
|
|
// Normalize
|
||
|
|
fp2_t one;
|
||
|
|
fp_mont_setone(one.re);fp_set(one.im,0);
|
||
|
|
fp2_mul(&*a, &*a, &one);
|
||
|
|
// Update seed
|
||
|
|
srand((unsigned) a->re[0]);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Affine Montgomery coefficient computation (A + 2C : 4C) --> A/C
|
||
|
|
void coeff(fp2_t *B, ec_point_t const A)
|
||
|
|
{
|
||
|
|
fp2_t t;
|
||
|
|
fp2_add(&t, &A.x, &A.x); // (2 * A24)
|
||
|
|
fp2_sub(&t, &t, &A.z); // (2 * A24) - C24
|
||
|
|
|
||
|
|
fp2_copy(&*B, &A.z);
|
||
|
|
fp2_inv(&*B); // 1 / (C24)
|
||
|
|
fp2_add(&t, &t, &t); // 4*A = 2[(2 * A24) - C24]
|
||
|
|
fp2_mul(&*B, &t, &*B); // A/C = 2[(2 * A24) - C24] / C24
|
||
|
|
}
|
||
|
|
|
||
|
|
// Determines if point is fp2-rational (if not, then it must be a zero trace point)
|
||
|
|
uint8_t isrational(ec_point_t const T, fp2_t const a)
|
||
|
|
{
|
||
|
|
fp2_t XT, tmp, aux, YT_squared;
|
||
|
|
|
||
|
|
fp2_copy(&XT, &T.z);
|
||
|
|
fp2_inv(&XT);
|
||
|
|
|
||
|
|
fp2_mul(&XT, &XT, &T.x);
|
||
|
|
|
||
|
|
fp2_sqr(&tmp, &XT);
|
||
|
|
fp2_mul(&aux, &tmp, &XT);
|
||
|
|
fp2_mul(&tmp, &tmp, &a);
|
||
|
|
fp2_add(&YT_squared, &tmp, &aux);
|
||
|
|
fp2_add(&YT_squared, &YT_squared, &XT);
|
||
|
|
|
||
|
|
return fp2_is_square(&YT_squared);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ladder3pt computes x(P + [m]Q)
|
||
|
|
void ladder3pt(ec_point_t* R, fp_t const m, ec_point_t const* P, ec_point_t const* Q, ec_point_t const* PQ, ec_point_t const* A)
|
||
|
|
{
|
||
|
|
ec_point_t X0, X1, X2;
|
||
|
|
copy_point(&X0, Q);
|
||
|
|
copy_point(&X1, P);
|
||
|
|
copy_point(&X2, PQ);
|
||
|
|
|
||
|
|
int i,j;
|
||
|
|
uint64_t t;
|
||
|
|
for (i = 0; i < NWORDS_FIELD; i++)
|
||
|
|
{
|
||
|
|
t = 1;
|
||
|
|
for (j = 0 ; j < 64; j++)
|
||
|
|
{
|
||
|
|
swap_points(&X1, &X2, -((t & m[i]) == 0));
|
||
|
|
xDBLADD(&X0, &X1, &X0, &X1, &X2, A);
|
||
|
|
swap_points(&X1, &X2, -((t & m[i]) == 0));
|
||
|
|
t <<= 1;
|
||
|
|
};
|
||
|
|
};
|
||
|
|
copy_point(R, &X1);
|
||
|
|
}
|
||
|
|
|
||
|
|
// For computing [(p + 1) / l_i]P, i:=0, ..., (N - 1)
|
||
|
|
void cofactor_multiples(ec_point_t P[], ec_point_t const* A, size_t lower, size_t upper)
|
||
|
|
{
|
||
|
|
assert(lower < upper);
|
||
|
|
if (upper - lower == 1)
|
||
|
|
return ;
|
||
|
|
|
||
|
|
int i;
|
||
|
|
size_t mid = lower + (upper - lower + 1) / 2;
|
||
|
|
copy_point(&(P[mid]), &(P[lower]));
|
||
|
|
for (i = lower; i < (int)mid; i++)
|
||
|
|
xMULv2(&(P[mid]), &(P[mid]), &(TORSION_ODD_PRIMES[i]), p_plus_minus_bitlength[i], A);
|
||
|
|
for (i = (int)mid; i < (int)upper; i++)
|
||
|
|
xMULv2(&(P[lower]), &(P[lower]), &(TORSION_ODD_PRIMES[i]), p_plus_minus_bitlength[i], A);
|
||
|
|
|
||
|
|
cofactor_multiples(P, A, lower, mid);
|
||
|
|
cofactor_multiples(P, A, mid, upper);
|
||
|
|
}
|
||
|
|
|
||
|
|
// The projective x-coordinate point (X : Z) at infinity is such that Z == 0
|
||
|
|
static inline int isinfinity(ec_point_t const P)
|
||
|
|
{
|
||
|
|
return fp2_is_zero(&P.z);
|
||
|
|
}
|
||
|
|
|
||
|
|
int main(int argc, char* argv[])
|
||
|
|
{
|
||
|
|
if (argc > 1) {
|
||
|
|
TEST_LOOPS = atoi(argv[1]);
|
||
|
|
}
|
||
|
|
|
||
|
|
fp2_t fp2_0, fp2_1;
|
||
|
|
fp2_set(&fp2_0, 0);
|
||
|
|
fp_mont_setone(fp2_1.re);fp_set(fp2_1.im,0);
|
||
|
|
|
||
|
|
int i, j;
|
||
|
|
|
||
|
|
ec_point_t A;
|
||
|
|
fp2_set(&A.x, 0);
|
||
|
|
fp_mont_setone(A.z.re);fp_set(A.z.im,0);
|
||
|
|
|
||
|
|
fp2_add(&A.z, &A.z, &A.z); // 2C
|
||
|
|
fp2_add(&A.x, &A.x, &A.z); // A' + 2C
|
||
|
|
fp2_add(&A.z, &A.z, &A.z); // 4C
|
||
|
|
|
||
|
|
// Just to ensure the projective curve coeffientes are different from zero
|
||
|
|
assert( !fp2_is_zero(&A.x) & !fp2_is_zero(&A.x) );
|
||
|
|
|
||
|
|
fp2_t a;
|
||
|
|
coeff(&a, A);
|
||
|
|
|
||
|
|
ec_point_t PA, QA, PQA, PB, QB, PQB;
|
||
|
|
|
||
|
|
// Writing the public projective x-coordinate points into Montogmery domain
|
||
|
|
fp2_tomont(&(PA.x), &(xPA));
|
||
|
|
fp_mont_setone(PA.z.re);fp_set(PA.z.im,0);
|
||
|
|
fp2_tomont(&(QA.x), &(xQA));
|
||
|
|
fp_mont_setone(QA.z.re);fp_set(QA.z.im,0);
|
||
|
|
fp2_tomont(&(PQA.x), &(xPQA));
|
||
|
|
fp_mont_setone(PQA.z.re);fp_set(PQA.z.im,0);
|
||
|
|
|
||
|
|
assert( isrational(PA, a) );
|
||
|
|
assert( isrational(QA, a) );
|
||
|
|
assert( isrational(PQA, a) );
|
||
|
|
|
||
|
|
// ======================================================================================================
|
||
|
|
// Recall, PA, QA, and PQA are expeted to be N-order points, but we require to ensure they are of order N
|
||
|
|
for (j = 0; j < P_LEN; j++)
|
||
|
|
{
|
||
|
|
for (i = 1; i < TORSION_ODD_POWERS[j]; i++)
|
||
|
|
{
|
||
|
|
xMULv2(&PA, &PA, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||
|
|
xMULv2(&QA, &QA, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||
|
|
xMULv2(&PQA, &PQA, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||
|
|
|
||
|
|
assert( isrational(PA, a) );
|
||
|
|
assert( isrational(QA, a) );
|
||
|
|
assert( isrational(PQA, a) );
|
||
|
|
};
|
||
|
|
};
|
||
|
|
assert( !isinfinity(PA) );
|
||
|
|
assert( !isinfinity(QA) );
|
||
|
|
assert( !isinfinity(PQA) );
|
||
|
|
|
||
|
|
ec_point_t P[P_LEN + M_LEN], Q[P_LEN + M_LEN], PQ[P_LEN + M_LEN];
|
||
|
|
copy_point(&(P[0]), &PA);
|
||
|
|
cofactor_multiples(P, &A, 0, P_LEN);
|
||
|
|
copy_point(&(Q[0]), &QA);
|
||
|
|
cofactor_multiples(Q, &A, 0, P_LEN);
|
||
|
|
copy_point(&(PQ[0]), &PQA);
|
||
|
|
cofactor_multiples(PQ, &A, 0, P_LEN);
|
||
|
|
for (j = 0; j < P_LEN; j++)
|
||
|
|
{
|
||
|
|
// x(PA)
|
||
|
|
assert( !isinfinity(P[j]) ); // It must be different from the point at infinity
|
||
|
|
assert( isrational(P[j], a) );
|
||
|
|
xMULv2(&P[j], &P[j], &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||
|
|
assert( isinfinity(P[j]) ); // It must be now the point at infinity
|
||
|
|
// x(QA)
|
||
|
|
assert( !isinfinity(Q[j]) ); // It must be different from the point at infinity
|
||
|
|
assert( isrational(Q[j], a) );
|
||
|
|
xMULv2(&Q[j], &Q[j], &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||
|
|
assert( isinfinity(Q[j]) ); // It must be now the point at infinity
|
||
|
|
// x(PQA)
|
||
|
|
assert( !isinfinity(PQ[j]) ); // It must be different from the point at infinity
|
||
|
|
assert( isrational(PQ[j], a) );
|
||
|
|
xMULv2(&PQ[j], &PQ[j], &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||
|
|
assert( isinfinity(PQ[j]) ); // It must be now the point at infinity
|
||
|
|
};
|
||
|
|
// Writing the public projective x-coordinate points into Montogmery domain
|
||
|
|
fp2_tomont(&(PB.x), &(xPB));
|
||
|
|
fp_mont_setone(PB.z.re);fp_set(PB.z.im,0);
|
||
|
|
fp2_tomont(&(QB.x), &(xQB));
|
||
|
|
fp_mont_setone(QB.z.re);fp_set(QB.z.im,0);
|
||
|
|
fp2_tomont(&(PQB.x), &(xPQB));
|
||
|
|
fp_mont_setone(PQB.z.re);fp_set(PQB.z.im,0);
|
||
|
|
|
||
|
|
assert( !isrational(PB, a) );
|
||
|
|
assert( !isrational(QB, a) );
|
||
|
|
assert( !isrational(PQB, a) );
|
||
|
|
// ======================================================================================================
|
||
|
|
// Recall, PB, QB, and PQB are expeted to be M-order points, but we require to ensure they are of order M
|
||
|
|
for (j = P_LEN; j < (P_LEN + M_LEN); j++)
|
||
|
|
{
|
||
|
|
for (i = 1; i < TORSION_ODD_POWERS[j]; i++)
|
||
|
|
{
|
||
|
|
xMULv2(&PB, &PB, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||
|
|
xMULv2(&QB, &QB, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||
|
|
xMULv2(&PQB, &PQB, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||
|
|
|
||
|
|
assert( !isrational(PB, a) );
|
||
|
|
assert( !isrational(QB, a) );
|
||
|
|
assert( !isrational(PQB, a) );
|
||
|
|
};
|
||
|
|
};
|
||
|
|
assert( !isinfinity(PB) );
|
||
|
|
assert( !isinfinity(QB) );
|
||
|
|
assert( !isinfinity(PQB) );
|
||
|
|
|
||
|
|
copy_point(&(P[P_LEN]), &PB);
|
||
|
|
cofactor_multiples(P, &A, P_LEN, P_LEN + M_LEN);
|
||
|
|
copy_point(&(Q[P_LEN]), &QB);
|
||
|
|
cofactor_multiples(Q, &A, P_LEN, P_LEN + M_LEN);
|
||
|
|
copy_point(&(PQ[P_LEN]), &PQB);
|
||
|
|
cofactor_multiples(PQ, &A, P_LEN, P_LEN + M_LEN);
|
||
|
|
for (j = P_LEN; j < (P_LEN+M_LEN); j++)
|
||
|
|
{
|
||
|
|
// x(PB)
|
||
|
|
assert( !isinfinity(P[j]) ); // It must be different from the point at infinity
|
||
|
|
assert( !isrational(P[j], a) );
|
||
|
|
xMULv2(&P[j], &P[j], &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||
|
|
assert( isinfinity(P[j]) ); // It must be now the point at infinity
|
||
|
|
// x(QB)
|
||
|
|
assert( !isinfinity(Q[j]) ); // It must be different from the point at infinity
|
||
|
|
assert( !isrational(Q[j], a) );
|
||
|
|
xMULv2(&Q[j], &Q[j], &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||
|
|
assert( isinfinity(Q[j]) ); // It must be now the point at infinity
|
||
|
|
// x(PQB)
|
||
|
|
assert( !isinfinity(PQ[j]) ); // It must be different from the point at infinity
|
||
|
|
assert( !isrational(PQ[j], a) );
|
||
|
|
xMULv2(&PQ[j], &PQ[j], &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||
|
|
assert( isinfinity(PQ[j]) ); // It must be now the point at infinity
|
||
|
|
};
|
||
|
|
|
||
|
|
fp2_t m;
|
||
|
|
|
||
|
|
// Writing the public projective x-coordinate points into Montogmery domain
|
||
|
|
fp2_tomont(&(PA.x), &(xPA));
|
||
|
|
fp_mont_setone(PA.z.re);fp_set(PA.z.im,0);
|
||
|
|
fp2_tomont(&(QA.x), &(xQA));
|
||
|
|
fp_mont_setone(QA.z.re);fp_set(QA.z.im,0);
|
||
|
|
fp2_tomont(&(PQA.x), &(xPQA));
|
||
|
|
fp_mont_setone(PQA.z.re);fp_set(PQA.z.im,0);
|
||
|
|
|
||
|
|
assert( isrational(PA, a) );
|
||
|
|
assert( isrational(QA, a) );
|
||
|
|
assert( isrational(PQA, a) );
|
||
|
|
|
||
|
|
fp2_tomont(&(PB.x), &(xPB));
|
||
|
|
fp_mont_setone(PB.z.re);fp_set(PB.z.im,0);
|
||
|
|
fp2_tomont(&(QB.x), &(xQB));
|
||
|
|
fp_mont_setone(QB.z.re);fp_set(QB.z.im,0);
|
||
|
|
fp2_tomont(&(PQB.x), &(xPQB));
|
||
|
|
fp_mont_setone(PQB.z.re);fp_set(PQB.z.im,0);
|
||
|
|
|
||
|
|
assert( !isrational(PB, a) );
|
||
|
|
assert( !isrational(QB, a) );
|
||
|
|
assert( !isrational(PQB, a) );
|
||
|
|
|
||
|
|
ec_point_t R[P_LEN + M_LEN];
|
||
|
|
int k;
|
||
|
|
for (j = 0; j < TEST_LOOPS; j++)
|
||
|
|
{
|
||
|
|
printf("[%3d%%] Testing EC differential arithmetic", 100 * j / TEST_LOOPS);
|
||
|
|
fflush(stdout);
|
||
|
|
printf("\r\x1b[K");
|
||
|
|
fp2_random(&m);
|
||
|
|
ladder3pt(&(R[0]), m.re, &PA, &QA, &PQA, &A);
|
||
|
|
assert( isrational(R[0], a) );
|
||
|
|
for (k = 0; k < P_LEN; k++)
|
||
|
|
{
|
||
|
|
for (i = 1; i < TORSION_ODD_POWERS[k]; i++)
|
||
|
|
{
|
||
|
|
xMULv2(&R[0], &R[0], &(TORSION_ODD_PRIMES[k]), p_plus_minus_bitlength[k], &A);
|
||
|
|
assert( isrational(R[0], a) );
|
||
|
|
};
|
||
|
|
};
|
||
|
|
cofactor_multiples(R, &A, 0, P_LEN);
|
||
|
|
for (i = 0; i < P_LEN; i++)
|
||
|
|
{
|
||
|
|
assert( !isinfinity(R[i]) ); // It must be different from the point at infinity
|
||
|
|
assert( isrational(R[i], a) );
|
||
|
|
xMULv2(&R[i], &R[i], &(TORSION_ODD_PRIMES[i]), p_plus_minus_bitlength[i], &A);
|
||
|
|
assert( isinfinity(R[i]) ); // It must be now the point at infinity
|
||
|
|
};
|
||
|
|
|
||
|
|
fp2_random(&m);
|
||
|
|
ladder3pt(&(R[P_LEN]), m.re, &PB, &QB, &PQB, &A);
|
||
|
|
assert( !isrational(R[P_LEN], a) );
|
||
|
|
for (k = P_LEN; k < (P_LEN+M_LEN); k++)
|
||
|
|
{
|
||
|
|
for (i = 1; i < TORSION_ODD_POWERS[k]; i++)
|
||
|
|
{
|
||
|
|
xMULv2(&R[P_LEN], &R[P_LEN], &(TORSION_ODD_PRIMES[k]), p_plus_minus_bitlength[k], &A);
|
||
|
|
assert( !isrational(R[P_LEN], a) );
|
||
|
|
};
|
||
|
|
};
|
||
|
|
cofactor_multiples(R, &A, P_LEN, P_LEN + M_LEN);
|
||
|
|
for (i = P_LEN; i < (P_LEN+M_LEN); i++)
|
||
|
|
{
|
||
|
|
assert( !isinfinity(R[i]) ); // It must be different from the point at infinity
|
||
|
|
assert( !isrational(R[i], a) );
|
||
|
|
xMULv2(&R[i], &R[i], &(TORSION_ODD_PRIMES[i]), p_plus_minus_bitlength[i], &A);
|
||
|
|
assert( isinfinity(R[i]) ); // It must be now the point at infinity
|
||
|
|
};
|
||
|
|
};
|
||
|
|
|
||
|
|
if(TEST_LOOPS)
|
||
|
|
printf("[%3d%%] Tested EC differential arithmetic:\tNo errors!\n", 100 * j / TEST_LOOPS);
|
||
|
|
printf("-- All tests passed.\n");
|
||
|
|
|
||
|
|
// BENCHMARK xDBLv2
|
||
|
|
unsigned long long cycles, cycles1, cycles2;
|
||
|
|
cycles = 0;
|
||
|
|
ec_point_t PP[TEST_LOOPS], EE[TEST_LOOPS];
|
||
|
|
for(int i = 0; i < TEST_LOOPS; i++){
|
||
|
|
fp2_random(&PP[i].x);
|
||
|
|
fp2_random(&PP[i].z);
|
||
|
|
fp2_random(&EE[i].x);
|
||
|
|
fp2_random(&EE[i].z);
|
||
|
|
}
|
||
|
|
cycles1 = cpucycles();
|
||
|
|
for(int i = 0; i < TEST_LOOPS; i++){
|
||
|
|
xDBLv2(&PP[i], &PP[i], &EE[i]);
|
||
|
|
}
|
||
|
|
cycles2 = cpucycles();
|
||
|
|
cycles = cycles+(cycles2-cycles1);
|
||
|
|
|
||
|
|
printf("xDBLv2 bench: %7lld cycles\n", cycles/TEST_LOOPS);
|
||
|
|
|
||
|
|
// BENCHMARK xIsog4
|
||
|
|
cycles = 0;
|
||
|
|
ec_point_t KK0[TEST_LOOPS], KK1[TEST_LOOPS], KK2[TEST_LOOPS];
|
||
|
|
for(int i = 0; i < TEST_LOOPS; i++){
|
||
|
|
fp2_random(&KK0[i].x);
|
||
|
|
fp2_random(&KK0[i].z);
|
||
|
|
fp2_random(&KK1[i].x);
|
||
|
|
fp2_random(&KK1[i].z);
|
||
|
|
fp2_random(&KK2[i].x);
|
||
|
|
fp2_random(&KK2[i].z);
|
||
|
|
}
|
||
|
|
cycles1 = cpucycles();
|
||
|
|
for(int i = 0; i < TEST_LOOPS; i++){
|
||
|
|
fp2_t t0, t1;
|
||
|
|
fp2_add(&t0, &PP[i].x, &PP[i].z);
|
||
|
|
fp2_sub(&t1, &PP[i].x, &PP[i].z);
|
||
|
|
fp2_mul(&(EE[i].x), &t0, &KK1[i].x);
|
||
|
|
fp2_mul(&(EE[i].z), &t1, &KK2[i].x);
|
||
|
|
fp2_mul(&t0, &t0, &t1);
|
||
|
|
fp2_mul(&t0, &t0, &KK0[i].x);
|
||
|
|
fp2_add(&t1, &(EE[i].x), &(EE[i].z));
|
||
|
|
fp2_sub(&(EE[i].z), &(EE[i].x), &(EE[i].z));
|
||
|
|
fp2_sqr(&t1, &t1);
|
||
|
|
fp2_sqr(&(EE[i].z), &(EE[i].z));
|
||
|
|
fp2_add(&(EE[i].x), &t0, &t1);
|
||
|
|
fp2_sub(&t0, &(EE[i].z), &t0);
|
||
|
|
fp2_mul(&(EE[i].x), &(EE[i].x), &t1);
|
||
|
|
fp2_mul(&(EE[i].z), &(EE[i].z), &t0);
|
||
|
|
}
|
||
|
|
cycles2 = cpucycles();
|
||
|
|
cycles = cycles+(cycles2-cycles1);
|
||
|
|
printf("xeval_4 bench: %7lld cycles\n", cycles/TEST_LOOPS);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|