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>
This commit is contained in:
386
src/ec/ref/ecx/test/mont-test.c
Normal file
386
src/ec/ref/ecx/test/mont-test.c
Normal file
@@ -0,0 +1,386 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user