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>
1068 lines
28 KiB
C
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;
|
|
}
|