Files
sqisign/src/ec/ref/ecx/test/isog-test.c
SQIsign team 28ff420dd0 initial version of SQIsign
Co-authored-by: Jorge Chavez-Saab <jorgechavezsaab@gmail.com>
Co-authored-by: Maria Corte-Real Santos <36373796+mariascrs@users.noreply.github.com>
Co-authored-by: Luca De Feo <github@defeo.lu>
Co-authored-by: Jonathan Komada Eriksen <jonathan.eriksen97@gmail.com>
Co-authored-by: Basil Hess <bhe@zurich.ibm.com>
Co-authored-by: Antonin Leroux <18654258+tonioecto@users.noreply.github.com>
Co-authored-by: Patrick Longa <plonga@microsoft.com>
Co-authored-by: Lorenz Panny <lorenz@yx7.cc>
Co-authored-by: Francisco Rodríguez-Henríquez <francisco.rodriguez@tii.ae>
Co-authored-by: Sina Schaeffler <108983332+syndrakon@users.noreply.github.com>
Co-authored-by: Benjamin Wesolowski <19474926+Calodeon@users.noreply.github.com>
2023-07-09 12:48:54 +02:00

1068 lines
28 KiB
C

#include <time.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <inttypes.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
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;
}