#include #include #include #include #include #include "isog.h" #include "test-basis.h" #include static int BENCH_LOOPS = 1000; // Number of iterations per bench static int TEST_LOOPS = 128; // Number of iterations per test bool curve_equal(ec_curve_t* E1, ec_curve_t* E2){ fp2_t a, b; fp2_mul(&a, &E1->A, &E2->C); fp2_mul(&b, &E2->A, &E1->C); return fp2_is_equal(&a, &b); } void random_scalar(fp_t k) { for(int i = 0; i < NWORDS_FIELD; i++) k[i] = rand(); } void fp2_print(char *name, fp2_t const a){ fp2_t b; fp2_set(&b, 1); fp2_mul(&b, &b, &a); printf("%s = 0x", name); for(int i = NWORDS_FIELD - 1; i >=0; i--) printf("%016" PRIx64, b.re[i]); printf(" + i*0x"); for(int i = NWORDS_FIELD - 1; i >=0; i--) printf("%016" PRIx64, b.im[i]); printf("\n"); } void point_print(char *name, ec_point_t P){ fp2_t a; if(fp2_is_zero(&P.z)){ printf("%s = INF\n", name); } else{ fp2_copy(&a, &P.z); fp2_inv(&a); fp2_mul(&a, &a, &P.x); fp2_print(name, a); } } void curve_print(char *name, ec_curve_t E){ fp2_t a; fp2_copy(&a, &E.C); fp2_inv(&a); fp2_mul(&a, &a, &E.A); fp2_print(name, a); } // Affine Montgomery coefficient computation (A + 2C : 4C) --> A/C void coeff(fp2_t *B, ec_curve_t const *E) { fp2_t t; fp2_add(&t, &E->A, &E->A); // (2 * A24) fp2_sub(&t, &t, &E->C); // (2 * A24) - C24 fp2_copy(&*B, &E->C); 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 } // 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); } static void xTPL(ec_point_t* Q, const ec_point_t* P, const ec_point_t* A3) { /* ----------------------------------------------------------------------------- * * Differential point tripling given the montgomery coefficient A3 = (A+2C:A-2C) * ----------------------------------------------------------------------------- */ fp2_t t0, t1, t2, t3, t4; fp2_sub(&t0, &P->x, &P->z); fp2_sqr(&t2, &t0); fp2_add(&t1, &P->x, &P->z); fp2_sqr(&t3, &t1); fp2_add(&t4, &t1, &t0); fp2_sub(&t0, &t1, &t0); fp2_sqr(&t1, &t4); fp2_sub(&t1, &t1, &t3); fp2_sub(&t1, &t1, &t2); fp2_mul(&Q->x, &t3, &A3->x); fp2_mul(&t3, &Q->x, &t3); fp2_mul(&Q->z, &t2, &A3->z); fp2_mul(&t2, &t2, &Q->z); fp2_sub(&t3, &t2, &t3); fp2_sub(&t2, &Q->x, &Q->z); fp2_mul(&t1, &t2, &t1); fp2_add(&t2, &t3, &t1); fp2_sqr(&t2, &t2); fp2_mul(&Q->x, &t2, &t4); fp2_sub(&t1, &t3, &t1); fp2_sqr(&t1, &t1); fp2_mul(&Q->z, &t1, &t0); } static void xisog_2_singular(ec_point_t* B24, ec_point_t A24){ fp2_t t0, four; fp_mont_setone(four.re); fp_set(four.im, 0); fp2_add(&four, &four, &four); fp2_add(&four, &four, &four); fp2_add(&t0, &A24.x, &A24.x); fp2_sub(&t0, &t0, &A24.z); fp2_add(&t0, &t0, &t0); fp2_inv(&A24.z); fp2_mul(&t0, &t0, &A24.z); fp2_copy(&K[0].x, &t0); fp2_add(&B24->x, &t0, &t0); fp2_sqr(&t0, &t0); fp2_sub(&t0, &t0, &four); fp2_sqrt(&t0); fp2_neg(&K[0].z, &t0); fp2_add(&B24->z, &t0, &t0); fp2_add(&B24->x, &B24->x, &B24->z); fp2_add(&B24->z, &B24->z, &B24->z); } static void xeval_2_singular(ec_point_t* R, const ec_point_t* Q, const int lenQ){ fp2_t t0, t1; for(int i = 0; i < lenQ; i++){ fp2_mul(&t0, &Q[i].x, &Q[i].z); fp2_mul(&t1, &K[0].x, &Q[i].z); fp2_add(&t1, &t1, &Q[i].x); fp2_mul(&t1, &t1, &Q[i].x); fp2_sqr(&R[i].x, &Q[i].z); fp2_add(&R[i].x, &R[i].x, &t1); fp2_mul(&R[i].z, &t0, &K[0].z); } } int main(int argc, char* argv[]) { unsigned long long cycles, cycles1, cycles2; // ----------------- TEST FOR BASIS GENERATION ----------------- // if (argc > 1) { TEST_LOOPS = atoi(argv[1]); } // Initial curve with A = 0 ec_curve_t E; fp2_set(&E.A, 0); fp_mont_setone(E.C.re); fp_set(E.C.im, 0); for(int iter = 0; iter < TEST_LOOPS; iter++){ printf("[%3d%%] Testing basis generation", 100 * iter / (int)TEST_LOOPS); fflush(stdout); printf("\r\x1b[K"); // Curve coefficient A24=(A+2C:4C) ec_point_t A24; fp2_add(&A24.z, &E.C, &E.C); fp2_add(&A24.x, &E.A, &A24.z); fp2_add(&A24.z, &A24.z, &A24.z); fp2_t j; ec_j_inv(&j, &E); // Construct basis for 2^f torsion ec_basis_t B2; ec_curve_to_basis_2(&B2, &E); // Check that basis is rational assert(ec_is_on_curve(&E, &B2.P)); assert(ec_is_on_curve(&E, &B2.Q)); assert(ec_is_on_curve(&E, &B2.PmQ)); // Compute P+Q ec_point_t PpQ; xADD(&PpQ, &B2.P, &B2.Q, &B2.PmQ); // Check the order ec_point_t P2, Q2, PmQ2, PpQ2, R; copy_point(&P2, &B2.P); copy_point(&Q2, &B2.Q); copy_point(&PmQ2, &B2.PmQ); copy_point(&PpQ2, &PpQ); for(int i = 0; i < POWER_OF_2 - 1; i++){ xDBLv2(&P2, &P2, &A24); assert(!ec_is_zero(&P2)); xDBLv2(&Q2, &Q2, &A24); assert(!ec_is_zero(&Q2)); xDBLv2(&PmQ2, &PmQ2, &A24); assert(!ec_is_zero(&PmQ2)); xDBLv2(&PpQ2, &PpQ2, &A24); assert(!ec_is_zero(&PpQ2)); } assert(is_point_equal(&PmQ2, &PpQ2)); xDBLv2(&P2, &P2, &A24); assert(ec_is_zero(&P2)); xDBLv2(&Q2, &Q2, &A24); assert(ec_is_zero(&Q2)); xDBLv2(&PmQ2, &PmQ2, &A24); assert(ec_is_zero(&PmQ2)); xDBLv2(&PpQ2, &PpQ2, &A24); assert(ec_is_zero(&PpQ2)); // Check the complete_basis function fp_t k; random_scalar(k); ladder3pt(&R, k, &B2.P, &B2.Q, &B2.PmQ, &A24); ec_complete_basis_2(&B2, &E, &R); assert(is_point_equal(&R, &B2.P)); // Check that basis is rational assert(ec_is_on_curve(&E, &B2.P)); assert(ec_is_on_curve(&E, &B2.Q)); assert(ec_is_on_curve(&E, &B2.PmQ)); // Compute P+Q xADD(&PpQ, &B2.P, &B2.Q, &B2.PmQ); // Check the order copy_point(&P2, &B2.P); copy_point(&Q2, &B2.Q); copy_point(&PmQ2, &B2.PmQ); copy_point(&PpQ2, &PpQ); for(int i = 0; i < POWER_OF_2 - 1; i++){ xDBLv2(&P2, &P2, &A24); assert(!ec_is_zero(&P2)); xDBLv2(&Q2, &Q2, &A24); assert(!ec_is_zero(&Q2)); xDBLv2(&PmQ2, &PmQ2, &A24); assert(!ec_is_zero(&PmQ2)); xDBLv2(&PpQ2, &PpQ2, &A24); assert(!ec_is_zero(&PpQ2)); } assert(is_point_equal(&PmQ2, &PpQ2)); xDBLv2(&P2, &P2, &A24); assert(ec_is_zero(&P2)); xDBLv2(&Q2, &Q2, &A24); assert(ec_is_zero(&Q2)); xDBLv2(&PmQ2, &PmQ2, &A24); assert(ec_is_zero(&PmQ2)); xDBLv2(&PpQ2, &PpQ2, &A24); assert(ec_is_zero(&PpQ2)); // Curve coefficient A3=(A+2C:A-2C) ec_point_t A3; fp2_copy(&A3.x, &A24.x); fp2_sub(&A3.z, &A3.x, &A24.z); // Construct basis for 3^g torsion ec_basis_t B3; ec_curve_to_basis_3(&B3, &E); // Check that basis is rational assert(ec_is_on_curve(&E, &B3.P)); assert(ec_is_on_curve(&E, &B3.Q)); assert(ec_is_on_curve(&E, &B3.PmQ)); // Compute P+Q xADD(&PpQ, &B3.P, &B3.Q, &B3.PmQ); // Check the order ec_point_t P3, Q3, PmQ3, PpQ3; copy_point(&P3, &B3.P); copy_point(&Q3, &B3.Q); copy_point(&PmQ3, &B3.PmQ); copy_point(&PpQ3, &PpQ); for(int i = 0; i < POWER_OF_3 - 1; i++){ xTPL(&P3, &P3, &A3); assert(!ec_is_zero(&P3)); xTPL(&Q3, &Q3, &A3); assert(!ec_is_zero(&Q3)); xTPL(&PmQ3, &PmQ3, &A3); assert(!ec_is_zero(&PmQ3)); xTPL(&PpQ3, &PpQ3, &A3); assert(!ec_is_zero(&PpQ3)); } xADD(&P2, &PpQ3, &Q3, &P3); assert(is_point_equal(&PmQ3, &P2)); xTPL(&P3, &P3, &A3); assert(ec_is_zero(&P3)); xTPL(&Q3, &Q3, &A3); assert(ec_is_zero(&Q3)); xTPL(&PmQ3, &PmQ3, &A3); assert(ec_is_zero(&PmQ3)); xTPL(&PpQ3, &PpQ3, &A3); assert(ec_is_zero(&PpQ3)); // Construct basis for 2^f*3^g torsion ec_basis_t B6; ec_curve_to_basis_6(&B6, &E); // Check that basis is rational assert(ec_is_on_curve(&E, &B6.P)); assert(ec_is_on_curve(&E, &B6.Q)); assert(ec_is_on_curve(&E, &B6.PmQ)); // Compute P+Q xADD(&PpQ, &B6.P, &B6.Q, &B6.PmQ); // Check the order ec_point_t P6, Q6, PmQ6, PpQ6; copy_point(&P6, &B6.P); copy_point(&Q6, &B6.Q); copy_point(&PmQ6, &B6.PmQ); copy_point(&PpQ6, &PpQ); for(int i = 0; i < POWER_OF_2 - 1; i++){ xDBLv2(&P6, &P6, &A24); assert(!ec_is_zero(&P6)); xDBLv2(&Q6, &Q6, &A24); assert(!ec_is_zero(&Q6)); xDBLv2(&PmQ6, &PmQ6, &A24); assert(!ec_is_zero(&PmQ6)); xDBLv2(&PpQ6, &PpQ6, &A24); assert(!ec_is_zero(&PpQ6)); } for(int i = 0; i < POWER_OF_3 - 1; i++){ xTPL(&P6, &P6, &A3); assert(!ec_is_zero(&P6)); xTPL(&Q6, &Q6, &A3); assert(!ec_is_zero(&Q6)); xTPL(&PmQ6, &PmQ6, &A3); assert(!ec_is_zero(&PmQ6)); xTPL(&PpQ6, &PpQ6, &A3); assert(!ec_is_zero(&PpQ6)); } copy_point(&R, &P6); xDBLv2(&P6, &P6, &A24); assert(!ec_is_zero(&P6)); xTPL(&P6, &P6, &A3); assert(ec_is_zero(&P6)); xTPL(&R, &R, &A3); assert(!ec_is_zero(&R)); xDBLv2(&R, &R, &A24); assert(ec_is_zero(&R)); copy_point(&R, &Q6); xDBLv2(&Q6, &Q6, &A24); assert(!ec_is_zero(&Q6)); xTPL(&Q6, &Q6, &A3); assert(ec_is_zero(&Q6)); xTPL(&R, &R, &A3); assert(!ec_is_zero(&R)); xDBLv2(&R, &R, &A24); assert(ec_is_zero(&R)); copy_point(&R, &PmQ6); xDBLv2(&PmQ6, &PmQ6, &A24); assert(!ec_is_zero(&PmQ6)); xTPL(&PmQ6, &PmQ6, &A3); assert(ec_is_zero(&PmQ6)); xTPL(&R, &R, &A3); assert(!ec_is_zero(&R)); xDBLv2(&R, &R, &A24); assert(ec_is_zero(&R)); copy_point(&R, &PpQ6); xDBLv2(&PpQ6, &PpQ6, &A24); assert(!ec_is_zero(&PpQ6)); xTPL(&PpQ6, &PpQ6, &A3); assert(ec_is_zero(&PpQ6)); xTPL(&R, &R, &A3); assert(!ec_is_zero(&R)); xDBLv2(&R, &R, &A24); assert(ec_is_zero(&R)); // Compute a 2^e-basis with 2^(e-1)*Q=(0,0) copy_point(&P2, &B2.P); copy_point(&Q2, &B2.Q); copy_point(&PmQ2, &B2.PmQ); for(int i = 0; i < POWER_OF_2 - 1; i++){ xDBLv2(&P2, &P2, &A24); xDBLv2(&Q2, &Q2, &A24); xDBLv2(&PmQ2, &PmQ2, &A24); } if(fp2_is_zero(&P2.x)){ copy_point(&Q2, &B2.Q); copy_point(&B2.Q, &B2.P); copy_point(&B2.P, &Q2); } else if(fp2_is_zero(&PmQ2.x)){ copy_point(&Q2, &B2.Q); copy_point(&B2.Q, &B2.PmQ); copy_point(&B2.PmQ, &Q2); } // Compute a 2^e-isogeny ec_isog_even_t isog; random_scalar(k); ladder3pt(&R, k, &B2.P, &B2.Q, &B2.PmQ, &A24); fp2_copy(&isog.curve.A, &E.A); fp2_copy(&isog.curve.C, &E.C); copy_point(&isog.kernel, &R); isog.length = POWER_OF_2; ec_eval_even_nonzero(&E, &isog, &B3.P, 1); } printf("[%2d%%] Tested basis generation:\t\tNo errors!\n", 100); // ----------------- TEST FOR NONZERO 2-ISOGENIES VS 4-ISOGENIES----------------- // // Initial curve with A = 0 fp2_set(&E.A, 0); fp_mont_setone(E.C.re); fp_set(E.C.im, 0); for(int iter = 0; iter < TEST_LOOPS; iter++){ printf("[%3d%%] Testing 2-isog vs 4-isog", 100 * iter / (int)TEST_LOOPS); fflush(stdout); printf("\r\x1b[K"); // Curve coefficient A24=(A+2C:4C) ec_point_t A24, B24, C24; fp2_add(&A24.z, &E.C, &E.C); fp2_add(&A24.x, &E.A, &A24.z); fp2_add(&A24.z, &A24.z, &A24.z); // Compute a 2^e-basis with 2^(e-1)*Q=(0,0) ec_basis_t B0, B1, B2; ec_point_t P4, Q4, PmQ4, P2, Q2, PmQ2, tmp; ec_curve_to_basis_2(&B2, &E); copy_point(&P4, &B2.P); copy_point(&Q4, &B2.Q); copy_point(&PmQ4, &B2.PmQ); for(int i = 0; i < POWER_OF_2 - 2; i++){ xDBLv2(&P4, &P4, &A24); xDBLv2(&Q4, &Q4, &A24); xDBLv2(&PmQ4, &PmQ4, &A24); } xDBLv2(&P2, &P4, &A24); xDBLv2(&Q2, &Q4, &A24); xDBLv2(&PmQ2, &PmQ4, &A24); if(fp2_is_zero(&P2.x)){ copy_point(&tmp, &Q4); copy_point(&Q4, &P4); copy_point(&P4, &tmp); } else if(fp2_is_zero(&PmQ2.x)){ copy_point(&tmp, &Q4); copy_point(&Q4, &PmQ4); copy_point(&PmQ4, &tmp); } // Non-singular 2-isogenies xDBLv2(&P2, &P4, &A24); xisog_2(&B24, P2); xeval_2((ec_point_t*)&B0, (ec_point_t*)&B2, 3); xeval_2(&P2, &P4, 1); xisog_2(&B24, P2); xeval_2((ec_point_t*)&B0, (ec_point_t*)&B0, 3); // Non-singular 4-isogeny xisog_4(&C24, P4); xeval_4((ec_point_t*)&B1, (ec_point_t*)&B2, 3); // Compare results assert(ec_is_equal(&B24, &C24)); assert(ec_is_equal(&B0.P, &B1.P)); assert(ec_is_equal(&B0.Q, &B1.Q)); assert(ec_is_equal(&B0.PmQ, &B1.PmQ)); // Singular 2-isogenies case 1 xisog_2_singular(&B24, A24); xeval_2_singular((ec_point_t*)&B0, (ec_point_t*)&B2, 3); xeval_2_singular(&Q2, &Q4, 1); xisog_2(&B24, Q2); xeval_2((ec_point_t*)&B0, (ec_point_t*)&B0, 3); // Singular 4-isogeny case 1 xisog_4_singular(&C24, Q4, A24); xeval_4_singular((ec_point_t*)&B1, (ec_point_t*)&B2, 3, Q4); // Compare results assert(ec_is_equal(&B24, &C24)); assert(ec_is_equal(&B0.P, &B1.P)); assert(ec_is_equal(&B0.Q, &B1.Q)); assert(ec_is_equal(&B0.PmQ, &B1.PmQ)); // Singular 2-isogenies case 2 fp2_sub(&A24.x, &A24.z, &A24.x); fp2_neg(&Q4.x, &Q4.x); fp2_neg(&P4.x, &P4.x); fp2_neg(&B2.P.x, &B2.P.x); fp2_neg(&B2.Q.x, &B2.Q.x); fp2_neg(&B2.PmQ.x, &B2.PmQ.x); xisog_2_singular(&B24, A24); xeval_2_singular((ec_point_t*)&B0, (ec_point_t*)&B2, 3); xeval_2_singular(&Q2, &Q4, 1); xisog_2(&B24, Q2); xeval_2((ec_point_t*)&B0, (ec_point_t*)&B0, 3); // Singular 4-isogeny case 2 xisog_4_singular(&C24, Q4, A24); xeval_4_singular((ec_point_t*)&B1, (ec_point_t*)&B2, 3, Q4); // Compare results assert(ec_is_equal(&B24, &C24)); assert(ec_is_equal(&B0.P, &B1.P)); assert(ec_is_equal(&B0.Q, &B1.Q)); assert(ec_is_equal(&B0.PmQ, &B1.PmQ)); // Move to next curve xisog_4(&A24, P4); fp2_add(&E.A, &A24.x, &A24.x); fp2_sub(&E.A, &E.A, &A24.z); fp2_sub(&E.A, &E.A, &E.A); fp2_copy(&E.C, &A24.z); } printf("[%2d%%] Tested 2-isog vs 4-isog:\t\tNo errors!\n", 100); // ----------------- TEST FOR NONZERO 2^f ISOGENIES ----------------- // // Initial curve with A = 0 fp2_set(&E.A, 0); fp_mont_setone(E.C.re); fp_set(E.C.im, 0); for(int iter = 0; iter < TEST_LOOPS; iter++){ printf("[%3d%%] Testing 2^f-isogenies (nonzero)", 100 * iter / (int)TEST_LOOPS); fflush(stdout); printf("\r\x1b[K"); // Curve coefficient A24=(A+2C:4C) ec_point_t A24; fp2_add(&A24.z, &E.C, &E.C); fp2_add(&A24.x, &E.A, &A24.z); fp2_add(&A24.z, &A24.z, &A24.z); // Compute a 2^e-basis with 2^(e-1)*Q=(0,0) ec_basis_t B2; ec_point_t P2, Q2, PmQ2; ec_curve_to_basis_2(&B2, &E); copy_point(&P2, &B2.P); copy_point(&Q2, &B2.Q); copy_point(&PmQ2, &B2.PmQ); for(int i = 0; i < POWER_OF_2 - 1; i++){ xDBLv2(&P2, &P2, &A24); xDBLv2(&Q2, &Q2, &A24); xDBLv2(&PmQ2, &PmQ2, &A24); } if(fp2_is_zero(&P2.x)){ copy_point(&Q2, &B2.Q); copy_point(&B2.Q, &B2.P); copy_point(&B2.P, &Q2); } else if(fp2_is_zero(&PmQ2.x)){ copy_point(&Q2, &B2.Q); copy_point(&B2.Q, &B2.PmQ); copy_point(&B2.PmQ, &Q2); } // Generate 3^g-basis and a 2^f-kernel point ec_basis_t B3; fp_t k; ec_point_t R; ec_curve_to_basis_3(&B3, &E); random_scalar(k); ladder3pt(&R, k, &B2.P, &B2.Q, &B2.PmQ, &A24); // Evaluate 2^f-isogeny ec_isog_even_t isog; fp2_copy(&isog.curve.A, &E.A); fp2_copy(&isog.curve.C, &E.C); isog.length = POWER_OF_2; for(int i = isog.length; i < POWER_OF_2; i++) xDBLv2(&R, &R, &A24); copy_point(&isog.kernel, &R); ec_eval_even_nonzero(&E, &isog, (ec_point_t*)&B3, 3); // Curve coefficient A3 = (A+2C:A-2C) ec_point_t A3; fp2_add(&A3.z, &E.C, &E.C); fp2_add(&A3.x, &E.A, &A3.z); fp2_sub(&A3.z, &E.A, &A3.z); // Check order of the pushed 3^g-basis ec_point_t P3, Q3, PmQ3, PpQ, PpQ3; xADD(&PpQ, &B3.P, &B3.Q, &B3.PmQ); copy_point(&P3, &B3.P); copy_point(&Q3, &B3.Q); copy_point(&PmQ3, &B3.PmQ); copy_point(&PpQ3, &PpQ); for(int i = 0; i < POWER_OF_3 - 1; i++){ xTPL(&P3, &P3, &A3); assert(!ec_is_zero(&P3)); xTPL(&Q3, &Q3, &A3); assert(!ec_is_zero(&Q3)); xTPL(&PmQ3, &PmQ3, &A3); assert(!ec_is_zero(&PmQ3)); xTPL(&PpQ3, &PpQ3, &A3); assert(!ec_is_zero(&PpQ3)); } xADD(&R, &PpQ3, &Q3, &P3); assert(is_point_equal(&PmQ3, &R)); xTPL(&P3, &P3, &A3); assert(ec_is_zero(&P3)); xTPL(&Q3, &Q3, &A3); assert(ec_is_zero(&Q3)); xTPL(&PmQ3, &PmQ3, &A3); assert(ec_is_zero(&PmQ3)); xTPL(&PpQ3, &PpQ3, &A3); assert(ec_is_zero(&PpQ3)); } printf("[%2d%%] Tested 2^f-isogenies (nonzero):\tNo errors!\n", 100); // ----------------- TEST FOR 2^f ISOGENIES ----------------- // // Initial curve with A = 0 fp2_set(&E.A, 0); fp_mont_setone(E.C.re); fp_set(E.C.im, 0); cycles = 0; for(int iter = 0; iter < TEST_LOOPS; iter++){ printf("[%3d%%] Testing 2^f-isogenies", 100 * iter / (int)TEST_LOOPS); fflush(stdout); printf("\r\x1b[K"); // Curve coefficient A24=(A+2C:4C) ec_point_t A24; fp2_add(&A24.z, &E.C, &E.C); fp2_add(&A24.x, &E.A, &A24.z); fp2_add(&A24.z, &A24.z, &A24.z); // Compute a 2^e-basis ec_basis_t B2; ec_curve_to_basis_2(&B2, &E); // Generate 3^g-basis and a 2^f-kernel point ec_basis_t B3; fp_t k; ec_point_t R; ec_curve_to_basis_3(&B3, &E); random_scalar(k); ladder3pt(&R, k, &B2.P, &B2.Q, &B2.PmQ, &A24); // Evaluate 2^f-isogeny ec_isog_even_t isog; fp2_copy(&isog.curve.A, &E.A); fp2_copy(&isog.curve.C, &E.C); isog.length = POWER_OF_2; for(int i = isog.length; i < POWER_OF_2; i++) xDBLv2(&R, &R, &A24); copy_point(&isog.kernel, &R); cycles1 = cpucycles(); ec_eval_even_basis(&E, &isog, &B3, 1); cycles2 = cpucycles(); cycles = cycles+(cycles2-cycles1); // Curve coefficient A3 = (A+2C:A-2C) ec_point_t A3; fp2_add(&A3.z, &E.C, &E.C); fp2_add(&A3.x, &E.A, &A3.z); fp2_sub(&A3.z, &E.A, &A3.z); // Check order of the pushed 3^g-basis ec_point_t P3, Q3, PmQ3, PpQ, PpQ3; xADD(&PpQ, &B3.P, &B3.Q, &B3.PmQ); copy_point(&P3, &B3.P); copy_point(&Q3, &B3.Q); copy_point(&PmQ3, &B3.PmQ); copy_point(&PpQ3, &PpQ); for(int i = 0; i < POWER_OF_3 - 1; i++){ xTPL(&P3, &P3, &A3); assert(!ec_is_zero(&P3)); xTPL(&Q3, &Q3, &A3); assert(!ec_is_zero(&Q3)); xTPL(&PmQ3, &PmQ3, &A3); assert(!ec_is_zero(&PmQ3)); xTPL(&PpQ3, &PpQ3, &A3); assert(!ec_is_zero(&PpQ3)); } xADD(&R, &PpQ3, &Q3, &P3); assert(is_point_equal(&PmQ3, &R)); xTPL(&P3, &P3, &A3); assert(ec_is_zero(&P3)); xTPL(&Q3, &Q3, &A3); assert(ec_is_zero(&Q3)); xTPL(&PmQ3, &PmQ3, &A3); assert(ec_is_zero(&PmQ3)); xTPL(&PpQ3, &PpQ3, &A3); assert(ec_is_zero(&PpQ3)); } printf("[%2d%%] Tested 2^f-isogenies:\t\tNo errors! (%7lld cycles)\n", 100, cycles/TEST_LOOPS);\ // ----------------- TEST FOR 3^g ISOGENIES ----------------- // // Initial curve with A = 0 fp2_set(&E.A, 0); fp_mont_setone(E.C.re); fp_set(E.C.im, 0); for(int iter = 0; iter < TEST_LOOPS; iter++){ printf("[%3d%%] Testing 3^g-isogenies", 100 * iter / (int)TEST_LOOPS); fflush(stdout); printf("\r\x1b[K"); // Curve coefficient A24=(A+2C:4C) ec_point_t A24; fp2_add(&A24.z, &E.C, &E.C); fp2_add(&A24.x, &E.A, &A24.z); fp2_add(&A24.z, &A24.z, &A24.z); // Curve coefficient A3=(A+2C:A-2C) ec_point_t A3; fp2_copy(&A3.x, &A24.x); fp2_sub(&A3.z, &A24.x, &A24.z); // Compute bases and a kernel point ec_basis_t B2, B3; fp_t k; ec_point_t R; ec_curve_to_basis_2(&B2, &E); ec_curve_to_basis_3(&B3, &E); random_scalar(k); ladder3pt(&R, k, &B3.P, &B3.Q, &B3.PmQ, &A24); // Evaluate 3^g-isogeny ec_isog_odd_t isog; fp2_copy(&isog.curve.A, &E.A); fp2_copy(&isog.curve.C, &E.C); for(int i = 0; i < P_LEN+M_LEN; i++) isog.degree[i] = 0; isog.degree[0] = rand() % POWER_OF_3 + 1; for(int i = isog.degree[0]; i < POWER_OF_3; i++) xTPL(&R, &R, &A3); copy_point(&isog.ker_plus, &R); ec_eval_odd_basis(&E, &isog, &B2, 1); // Update A24 fp2_add(&A24.z, &E.C, &E.C); fp2_add(&A24.x, &E.A, &A24.z); fp2_add(&A24.z, &A24.z, &A24.z); // Check order of the pushed 2^f-basis ec_point_t P2, Q2, PmQ2, PpQ, PpQ2; xADD(&PpQ, &B2.P, &B2.Q, &B2.PmQ); copy_point(&P2, &B2.P); copy_point(&Q2, &B2.Q); copy_point(&PmQ2, &B2.PmQ); copy_point(&PpQ2, &PpQ); for(int i = 0; i < POWER_OF_2 - 1; i++){ xDBLv2(&P2, &P2, &A24); assert(!ec_is_zero(&P2)); xDBLv2(&Q2, &Q2, &A24); assert(!ec_is_zero(&Q2)); xDBLv2(&PmQ2, &PmQ2, &A24); assert(!ec_is_zero(&PmQ2)); xDBLv2(&PpQ2, &PpQ2, &A24); assert(!ec_is_zero(&PpQ2)); } assert(is_point_equal(&PmQ2, &PpQ2)); xDBLv2(&P2, &P2, &A24); assert(ec_is_zero(&P2)); xDBLv2(&Q2, &Q2, &A24); assert(ec_is_zero(&Q2)); xDBLv2(&PmQ2, &PmQ2, &A24); assert(ec_is_zero(&PmQ2)); xDBLv2(&PpQ2, &PpQ2, &A24); assert(ec_is_zero(&PpQ2)); } printf("[%2d%%] Tested 3^g-isogenies:\t\tNo errors!\n", 100); // ----------------- TEST FOR ODD-DEGREE ISOGENIES ----------------- // for(int iter = 0; iter < TEST_LOOPS/10; iter++){ printf("[%3d%%] Testing odd-degree isogenies", 100 * iter / ((int)TEST_LOOPS/10)); fflush(stdout); printf("\r\x1b[K"); // Initial curve with A = 0 fp2_set(&E.A, 0); fp_mont_setone(E.C.re); fp_set(E.C.im, 0); // Curve coefficient A24=(A+2C:4C) ec_point_t A24; fp2_add(&A24.z, &E.C, &E.C); fp2_add(&A24.x, &E.A, &A24.z); fp2_add(&A24.z, &A24.z, &A24.z); // Compute a 2^f-basis ec_basis_t B2; ec_point_t R; ec_curve_to_basis_2(&B2, &E); // Compute kernel points ec_point_t P, Q, PQ, R_plus, R_minus; fp_t k; fp2_tomont(&P.x, &xPA); fp2_tomont(&Q.x, &xQA); fp2_tomont(&PQ.x, &xPQA); fp_mont_setone(P.z.re); fp_set(P.z.im, 0); fp2_copy(&Q.z, &P.z); fp2_copy(&PQ.z, &P.z); random_scalar(k); ladder3pt(&R_plus, k, &P, &Q, &PQ, &A24); fp2_tomont(&P.x, &xPB); fp2_tomont(&Q.x, &xQB); fp2_tomont(&PQ.x, &xPQB); random_scalar(k); ladder3pt(&R_minus, k, &P, &Q, &PQ, &A24); // Evaluate an odd-degree isogeny ec_isog_odd_t isog; copy_point(&isog.ker_plus, &R_plus); copy_point(&isog.ker_minus, &R_minus); fp2_copy(&isog.curve.A, &E.A); fp2_copy(&isog.curve.C, &E.C); for(int i = 0; i < P_LEN; i++){ isog.degree[i] = rand() % (TORSION_ODD_POWERS[i]+1); int j = isog.degree[i]; while(j < TORSION_ODD_POWERS[i]){ xMULv2(&isog.ker_plus, &isog.ker_plus, &TORSION_ODD_PRIMES[i], p_plus_minus_bitlength[i], &A24); j++; } } for(int i = P_LEN; i < P_LEN+M_LEN; i++){ isog.degree[i] = rand() % (TORSION_ODD_POWERS[i]+1); int j = isog.degree[i]; while(j < TORSION_ODD_POWERS[i]){ xMULv2(&isog.ker_minus, &isog.ker_minus, &TORSION_ODD_PRIMES[i], p_plus_minus_bitlength[i], &A24); j++; } } ec_eval_odd_basis(&E, &isog, &B2, 1); ec_eval_odd(&E, &isog, &R_plus, 1); ec_eval_odd(&E, &isog, &R_minus, 1); // Update A24 fp2_add(&A24.z, &E.C, &E.C); fp2_add(&A24.x, &E.A, &A24.z); fp2_add(&A24.z, &A24.z, &A24.z); // Check order of the pushed 2^f-basis ec_point_t P2, Q2, PmQ2, PpQ, PpQ2; xADD(&PpQ, &B2.P, &B2.Q, &B2.PmQ); copy_point(&P2, &B2.P); copy_point(&Q2, &B2.Q); copy_point(&PmQ2, &B2.PmQ); copy_point(&PpQ2, &PpQ); for(int i = 0; i < POWER_OF_2 - 1; i++){ xDBLv2(&P2, &P2, &A24); assert(!ec_is_zero(&P2)); xDBLv2(&Q2, &Q2, &A24); assert(!ec_is_zero(&Q2)); xDBLv2(&PmQ2, &PmQ2, &A24); assert(!ec_is_zero(&PmQ2)); xDBLv2(&PpQ2, &PpQ2, &A24); assert(!ec_is_zero(&PpQ2)); } assert(is_point_equal(&PmQ2, &PpQ2)); xDBLv2(&P2, &P2, &A24); assert(ec_is_zero(&P2)); xDBLv2(&Q2, &Q2, &A24); assert(ec_is_zero(&Q2)); xDBLv2(&PmQ2, &PmQ2, &A24); assert(ec_is_zero(&PmQ2)); xDBLv2(&PpQ2, &PpQ2, &A24); assert(ec_is_zero(&PpQ2)); // Check order of the pushed R_plus point int last = -1; for(int i = 0; i < P_LEN; i++){ int j = isog.degree[i]; while(j < TORSION_ODD_POWERS[i]){ xMULv2(&R_plus, &R_plus, &TORSION_ODD_PRIMES[i], p_plus_minus_bitlength[i], &A24); if(ec_is_zero(&R_plus)){ last = i; break; } j++; } } assert(last >= 0); for(int i = last+1; i < P_LEN; i++) assert(isog.degree[i] == TORSION_ODD_POWERS[i]); // Check order of the pushed R_minus point last = -1; for(int i = P_LEN; i < P_LEN+M_LEN; i++){ int j = isog.degree[i]; while(j < TORSION_ODD_POWERS[i]){ xMULv2(&R_minus, &R_minus, &TORSION_ODD_PRIMES[i], p_plus_minus_bitlength[i], &A24); if(ec_is_zero(&R_minus)){ last = i; break; } j++; } } assert(last >= 0); for(int i = last+1; i < P_LEN+M_LEN; i++) assert(isog.degree[i] == TORSION_ODD_POWERS[i]); } printf("[%2d%%] Tested odd-degree isogenies:\tNo errors!\n", 100); // ----------------- TEST FOR ISOMORPHISMS ----------------- // // Initial curve with A = 0 fp2_set(&E.A, 0); fp_mont_setone(E.C.re); fp_set(E.C.im, 0); for(int iter = 0; iter < TEST_LOOPS; iter++){ printf("[%3d%%] Testing odd-degree isogenies", 100 * iter / (int)TEST_LOOPS); fflush(stdout); printf("\r\x1b[K"); // Compute jinv fp2_t j; ec_j_inv(&j, &E); // Normalize the curve ec_curve_t Enorm; ec_isom_t isom; ec_curve_normalize(&Enorm, &isom, &E); // Compare j invariants fp2_t jnorm; ec_j_inv(&jnorm, &Enorm); assert(fp2_is_equal(&j, &jnorm)); // Check that normalization is consistent ec_curve_t Enorm2; ec_isom_t isom2; ec_curve_normalize(&Enorm2, &isom2, &Enorm); assert(curve_equal(&Enorm, &Enorm2)); // Compute a basis ec_basis_t B; ec_curve_to_basis_2(&B, &E); // Push it through isomorphism ec_basis_t Bnorm; copy_point(&Bnorm.P, &B.P); ec_iso_eval(&Bnorm.P, &isom); copy_point(&Bnorm.Q, &B.Q); ec_iso_eval(&Bnorm.Q, &isom); copy_point(&Bnorm.PmQ, &B.PmQ); ec_iso_eval(&Bnorm.PmQ, &isom); // Check that the new basis is rational assert(ec_is_on_curve(&Enorm, &Bnorm.P)); assert(ec_is_on_curve(&Enorm, &Bnorm.Q)); assert(ec_is_on_curve(&Enorm, &Bnorm.PmQ)); // Compute P+Q ec_point_t PpQ; xADD(&PpQ, &Bnorm.P, &Bnorm.Q, &Bnorm.PmQ); // // Check the order ec_point_t P2, Q2, PmQ2, PpQ2, R, A24; fp2_add(&A24.z, &Enorm.C, &Enorm.C); fp2_add(&A24.x, &Enorm.A, &A24.z); fp2_add(&A24.z, &A24.z, &A24.z); copy_point(&P2, &Bnorm.P); copy_point(&Q2, &Bnorm.Q); copy_point(&PmQ2, &Bnorm.PmQ); copy_point(&PpQ2, &PpQ); for(int i = 0; i < POWER_OF_2 - 1; i++){ xDBLv2(&P2, &P2, &A24); assert(!ec_is_zero(&P2)); xDBLv2(&Q2, &Q2, &A24); assert(!ec_is_zero(&Q2)); xDBLv2(&PmQ2, &PmQ2, &A24); assert(!ec_is_zero(&PmQ2)); xDBLv2(&PpQ2, &PpQ2, &A24); assert(!ec_is_zero(&PpQ2)); } assert(is_point_equal(&PmQ2, &PpQ2)); xDBLv2(&P2, &P2, &A24); assert(ec_is_zero(&P2)); xDBLv2(&Q2, &Q2, &A24); assert(ec_is_zero(&Q2)); xDBLv2(&PmQ2, &PmQ2, &A24); assert(ec_is_zero(&PmQ2)); xDBLv2(&PpQ2, &PpQ2, &A24); assert(ec_is_zero(&PpQ2)); // Compute a 2^e-basis with 2^(e-1)*Q=(0,0) fp2_add(&A24.z, &E.C, &E.C); fp2_add(&A24.x, &E.A, &A24.z); fp2_add(&A24.z, &A24.z, &A24.z); copy_point(&P2, &B.P); copy_point(&Q2, &B.Q); copy_point(&PmQ2, &B.PmQ); for(int i = 0; i < POWER_OF_2 - 1; i++){ xDBLv2(&P2, &P2, &A24); xDBLv2(&Q2, &Q2, &A24); xDBLv2(&PmQ2, &PmQ2, &A24); } if(fp2_is_zero(&P2.x)){ copy_point(&Q2, &B.Q); copy_point(&B.Q, &B.P); copy_point(&B.P, &Q2); } else if(fp2_is_zero(&PmQ2.x)){ copy_point(&Q2, &B.Q); copy_point(&B.Q, &B.PmQ); copy_point(&B.PmQ, &Q2); } // Compute a 2^e-isogeny ec_isog_even_t isog; fp_t k; random_scalar(k); ladder3pt(&R, k, &B.P, &B.Q, &B.PmQ, &A24); fp2_copy(&isog.curve.A, &E.A); fp2_copy(&isog.curve.C, &E.C); copy_point(&isog.kernel, &R); isog.length = POWER_OF_2; ec_eval_even_nonzero(&E, &isog, &P2, 1); } printf("[%2d%%] Tested curve normalization+isom:\tNo errors!\n", 100); printf("-- All tests passed!\n"); return 0; }