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:
18
src/ec/ref/ecx/test/ec-test.c
Normal file
18
src/ec/ref/ecx/test/ec-test.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "ec-tests.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc < 3) {
|
||||
printf("Please enter an argument: 'test' or 'bench' and <reps>\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!strcmp(argv[1], "test")) {
|
||||
TEST_LOOPS = atoi(argv[2]);
|
||||
return !(ec_test() & dlog_test());
|
||||
} else if (!strcmp(argv[1], "bench")) {
|
||||
BENCH_LOOPS = atoi(argv[2]);
|
||||
return !(ec_run() & dlog_run());
|
||||
} else {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
142
src/ec/ref/ecx/test/fp2-test.c
Normal file
142
src/ec/ref/ecx/test/fp2-test.c
Normal file
@@ -0,0 +1,142 @@
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <fp2.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
static int BENCH_LOOPS = 1000; // Number of iterations per bench
|
||||
static int TEST_LOOPS = 512; // Number of iterations per test
|
||||
|
||||
bool fp2_isequal(fp2_t a, fp2_t b){
|
||||
return fp_is_equal(a.re, b.re) && fp_is_equal(a.im, b.im);
|
||||
}
|
||||
|
||||
bool fp2_isone(fp2_t a){
|
||||
fp_t one;
|
||||
bool res = 1;
|
||||
fp_mont_setone(one);
|
||||
for(int i = 0; i < NWORDS_FIELD; i++){
|
||||
res = res && (a.re[i] == one[i]);
|
||||
res = res && (a.im[i] == 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
// 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]);
|
||||
}
|
||||
|
||||
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;
|
||||
fp2_t a, b, c, d;
|
||||
fp_t e;
|
||||
|
||||
for (i = 0; i < TEST_LOOPS; i++)
|
||||
{
|
||||
printf("[%3d%%] Testing fp2_t arithmetic", 100 * i / (int)TEST_LOOPS);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
// Random elements of fp
|
||||
fp2_random(&a);
|
||||
fp2_random(&b);
|
||||
fp2_copy(&c, &a);
|
||||
c.re[0] += 1;
|
||||
fp2_copy(&d, &b);
|
||||
d.re[0] -= 1;
|
||||
|
||||
assert(fp2_isequal(a,b) == 0); // different values check --> (a != b)
|
||||
assert(fp2_isequal(c,c) == 1); // equal values check --> 1 (c == c)
|
||||
|
||||
// Testing neg
|
||||
fp2_set(&b, 0);
|
||||
fp2_copy(&c, &a);
|
||||
fp2_neg(&a, &a);
|
||||
fp2_sub(&c, &b, &c);
|
||||
assert(fp2_isequal(a,c) == 1);
|
||||
|
||||
fp_mont_setone(a.re);fp_set(a.im,0); // Now a == 1
|
||||
fp2_set(&b, 0); // Now b == 0
|
||||
|
||||
assert(fp2_is_zero(&a) == 0);
|
||||
assert(fp2_is_zero(&b) == 1);
|
||||
|
||||
// testing c - c
|
||||
fp2_sub(&d, &c, &c);
|
||||
assert(fp2_is_zero(&d) == 1);
|
||||
|
||||
// tetsing c * 0
|
||||
fp2_mul(&d, &c, &b);
|
||||
assert(fp2_is_zero(&d) == 1);
|
||||
|
||||
// tetsing c * 1 ... recall, in Montgomery domain R mod p plays the role of the 1
|
||||
fp_mont_setone(a.re);fp_set(a.im,0);
|
||||
fp2_mul(&d, &c, &a);
|
||||
assert(fp2_isequal(d, c) == 1);
|
||||
|
||||
// fp_set(e, 1); // Now e == 1
|
||||
// fp2_pow(d, e, c);
|
||||
// assert(fp2_isequal(d, c) == 1);
|
||||
|
||||
// fp_set(e, 0); // Now e == 0
|
||||
// fp2_pow(d, e, c);
|
||||
// assert(fp2_isone(d) == 1);
|
||||
|
||||
// fp2_set(a, 1); // Now e == R mod p
|
||||
// fp_random(e);
|
||||
// fp2_pow(d, e, a);
|
||||
// assert(fp2_isone(d) == 1);
|
||||
|
||||
// Testing 1/a by computing (1/a) x a
|
||||
fp2_random(&a);
|
||||
fp2_copy(&b, &a);
|
||||
fp2_inv(&a);
|
||||
fp2_mul(&c, &a, &b);
|
||||
assert(fp2_isone(c) == 1);
|
||||
|
||||
fp2_random(&a);
|
||||
fp2_sqr(&b, &a);
|
||||
assert( fp2_is_square(&b) );
|
||||
|
||||
};
|
||||
|
||||
if(TEST_LOOPS){
|
||||
printf("[%2d%%] Tested fp2_t arithmetic:\tNo errors!\n", 100 * i /TEST_LOOPS);
|
||||
}
|
||||
printf("-- All tests passed.\n");
|
||||
return 0;
|
||||
}
|
||||
1067
src/ec/ref/ecx/test/isog-test.c
Normal file
1067
src/ec/ref/ecx/test/isog-test.c
Normal file
File diff suppressed because it is too large
Load Diff
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;
|
||||
}
|
||||
445
src/ec/ref/ecx/test/poly-mul-test.c
Normal file
445
src/ec/ref/ecx/test/poly-mul-test.c
Normal file
@@ -0,0 +1,445 @@
|
||||
#include <poly.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
bool fp2_isequal(fp2_t a, fp2_t b){
|
||||
return fp_is_equal(a.re, b.re) && fp_is_equal(a.im, b.im);
|
||||
}
|
||||
|
||||
// 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]);
|
||||
}
|
||||
|
||||
void slow_mul(poly h, poly f, int lenf, poly g, int leng){
|
||||
// Computes h = f*g by school method
|
||||
|
||||
fp2_t a, b;
|
||||
int nf, ng, e;
|
||||
int lenh = lenf + leng - 1;
|
||||
|
||||
if(lenh <= 0){
|
||||
return;
|
||||
}
|
||||
|
||||
fp2_t fg[lenh];
|
||||
|
||||
if (leng > lenf){
|
||||
slow_mul(h, g, leng, f, lenf);
|
||||
return;
|
||||
}
|
||||
|
||||
for(e = 0; e < lenh; e++){
|
||||
|
||||
if (lenf - 1 < e){
|
||||
nf = lenf - 1;
|
||||
}
|
||||
else{
|
||||
nf = e;
|
||||
}
|
||||
|
||||
ng = e - nf;
|
||||
fp2_set(&a, 0);
|
||||
while( (ng < leng) & (nf >= 0) ){
|
||||
fp2_mul(&b, &f[nf], &g[ng]);
|
||||
fp2_add(&a, &a, &b);
|
||||
nf--;
|
||||
ng++;
|
||||
}
|
||||
fp2_copy(&fg[e], &a);
|
||||
}
|
||||
for(e = 0; e < lenh; e++){
|
||||
fp2_copy(&h[e], &fg[e]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(){
|
||||
fp2_t fp2_0, fp2_1;
|
||||
#define nmax 16
|
||||
int nf, ng, n, e;
|
||||
fp2_set(&fp2_0, 0);
|
||||
fp_mont_setone(fp2_1.re);fp_set(fp2_1.im,0);
|
||||
|
||||
//TEST MULTIPLICATION BY 0
|
||||
|
||||
for(nf = 2; nf < nmax; nf++){
|
||||
fp2_t f[nf], h[nf-1];
|
||||
|
||||
printf("[%3d%%] Testing multiplication by 0", 100 * nf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(e = 0; e < nf; e++){
|
||||
fp2_random(&f[e]);
|
||||
}
|
||||
poly_mul(h, f, nf, f, 0);
|
||||
for(e = 0; e < nf-1; e++){
|
||||
assert(fp2_is_zero(&h[e])==1);
|
||||
}
|
||||
poly_mul(h, f, 0, f, nf);
|
||||
for(e = 0; e < nf-1; e++){
|
||||
assert(fp2_is_zero(&h[e])==1);
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested multiplication by 0:\t\tNo errors!\n", 100 * nf / nmax);
|
||||
|
||||
|
||||
|
||||
//TEST FOR f, g, h DISJOINT MEMORY SPACES
|
||||
|
||||
for(nf = 1; nf < nmax; nf++){
|
||||
|
||||
printf("[%3d%%] Testing multiplication", 100 * nf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(ng = 1; ng < nmax; ng++){
|
||||
|
||||
fp2_t f[nf]; //Random length nf poly
|
||||
for(e = 0; e < nf; e++){
|
||||
fp2_random(&f[e]);
|
||||
}
|
||||
|
||||
fp2_t g[ng]; // Random length ng poly
|
||||
for(e = 0; e < ng; e++){
|
||||
fp2_random(&g[e]);
|
||||
}
|
||||
|
||||
fp2_t h[nf+ng-1];// Compute product
|
||||
poly_mul(h, f, nf, g, ng);
|
||||
|
||||
fp2_t fg[nf+ng-1]; // Compute the product by school method
|
||||
slow_mul(fg, f, nf, g, ng);
|
||||
|
||||
for(e = 0; e < nf + ng - 1; e++){ // Verify answer term by term
|
||||
assert(fp2_isequal(h[e], fg[e])==1);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested multiplication:\t\t\tNo errors!\n", 100 * nf / nmax);
|
||||
|
||||
|
||||
|
||||
// TEST FOR f, g CONTIGIOUS AND RESULT SAVED OVER THEM
|
||||
|
||||
for(nf = 1; nf < nmax; nf++){
|
||||
|
||||
printf("[%3d%%] Testing multiplication in place", 100 * nf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(ng = 1; ng < nmax; ng++){
|
||||
|
||||
fp2_t h[nf+ng];
|
||||
|
||||
//Random length nf poly
|
||||
for(e = 0; e < nf; e++){
|
||||
fp2_random(&h[e]);
|
||||
}
|
||||
|
||||
// Random length ng poly
|
||||
for(e = 0; e < ng; e++){
|
||||
fp2_random(&h[e+nf]);
|
||||
}
|
||||
|
||||
// Compute the product
|
||||
fp2_t fg[nf+ng-1];
|
||||
slow_mul(fg, h, nf, &(h[nf]), ng); // School method
|
||||
poly_mul(h, h, nf, &(h[nf]), ng); // Karatsuba method
|
||||
|
||||
|
||||
for(e = 0; e < nf + ng - 1; e++){ // Verify answer term by term
|
||||
assert(fp2_isequal(h[e], fg[e])==1);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested multiplication in place:\t\tNo errors!\n", 100 * nf / nmax);
|
||||
|
||||
|
||||
|
||||
//TEST FOR MULTIPLICATION MOD X^N BY 0
|
||||
|
||||
for(nf = 2; nf < nmax; nf++){
|
||||
fp2_t f[nf];
|
||||
|
||||
printf("[%3d%%] Testing mul mod x^n by 0", 100 * nf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(e = 0; e < nf; e++){
|
||||
fp2_random(&f[e]);
|
||||
}
|
||||
|
||||
for(n = 1; n < nmax; n++){
|
||||
fp2_t h[n];
|
||||
poly_mul_low(h, n, f, nf, f, 0);
|
||||
for(e = 0; e < n; e++){
|
||||
assert(fp2_is_zero(&h[e])==1);
|
||||
}
|
||||
poly_mul_low(h, n, f, 0, f, nf);
|
||||
for(e = 0; e < n; e++){
|
||||
assert(fp2_is_zero(&h[e])==1);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested mul mod x^n by 0:\t\t\tNo errors!\n", 100 * nf / nmax);
|
||||
|
||||
|
||||
|
||||
//TEST FOR MULTIPLICATION MOD X^N
|
||||
|
||||
for(nf = 1; nf < nmax; nf++){
|
||||
|
||||
printf("[%3d%%] Testing mul mod x^n", 100 * nf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(ng = 1; ng < nmax; ng++){
|
||||
|
||||
fp2_t f[nf], g[ng], fg[nf+ng-1];
|
||||
poly h;
|
||||
|
||||
//Get random polynomials
|
||||
for(e = 0; e < nf; e++){
|
||||
fp2_random(&f[e]);
|
||||
}
|
||||
for(e = 0; e < ng; e++){
|
||||
fp2_random(&g[e]);
|
||||
}
|
||||
|
||||
//Save regular result to fg
|
||||
slow_mul(fg, f, nf, g, ng);
|
||||
|
||||
//Compute result mod x^n
|
||||
for(n = 1; n < 2*nmax; n++){
|
||||
h = malloc(sizeof(fp2_t)*n);
|
||||
poly_mul_low(h, n, f, nf, g, ng);
|
||||
|
||||
//Compare with expected
|
||||
e = 0;
|
||||
while(e < nf+ng-1 && e < n){
|
||||
assert(fp2_isequal(h[e], fg[e]) == 1);
|
||||
e++;
|
||||
}
|
||||
while(e < n){
|
||||
assert(fp2_is_zero(&h[e]) == 1);
|
||||
e++;
|
||||
}
|
||||
free(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested mul mod x^n:\t\t\tNo errors!\n", 100 * nf / nmax);
|
||||
|
||||
|
||||
|
||||
//TEST FOR POLY_MUL_MIDDLE
|
||||
|
||||
for(nf = 1; nf < 2*nmax; nf+=1){
|
||||
fp2_t f[nf];
|
||||
|
||||
printf("[%3d%%] Testing poly_mul_middle", 100 * nf / (2*nmax));
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(ng = (nf+1)>>1; ng < (nf+1)-((nf+1)>>1); ng++){
|
||||
// This runs from floor((nf+1)/2) to ceil((nf+1)/2)
|
||||
fp2_t g[ng];
|
||||
for(e = 0; e < nf; e++){
|
||||
fp2_random(&f[e]);
|
||||
}
|
||||
for(e = 0; e < ng; e++){
|
||||
fp2_random(&g[e]);
|
||||
}
|
||||
|
||||
fp2_t h[nf+ng-1];
|
||||
slow_mul(h, g, ng, f, nf);
|
||||
poly_mul_middle(g, g, ng, f, nf);
|
||||
|
||||
for(e = 0; e < ng; e++){
|
||||
assert(fp2_isequal(h[e+nf-ng], g[e])==1);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested poly_mul_middle:\t\t\tNo errors!\n", 100 * nf / (2*nmax));
|
||||
|
||||
|
||||
// TEST FOR SELF RECIPROCAL MULTIPLICATION
|
||||
for(nf = 1; nf < nmax; nf++){
|
||||
|
||||
printf("[%3d%%] Testing self reciprocal mul", 100 * nf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(ng = 1; ng < nmax; ng++){
|
||||
|
||||
fp2_t f[nf], g[ng], h[nf+ng-1], fg[nf+ng-1];
|
||||
|
||||
// Get random palyndromes
|
||||
for(e = 0; e < (nf>>1); e++){
|
||||
fp2_random(&f[e]);
|
||||
fp2_copy(&f[nf-1-e], &f[e]);
|
||||
}
|
||||
if(nf & 1){
|
||||
fp2_random(&f[nf>>1]);
|
||||
}
|
||||
|
||||
for(e = 0; e < (ng>>1); e++){
|
||||
fp2_random(&g[e]);
|
||||
fp2_copy(&g[ng-1-e], &g[e]);
|
||||
}
|
||||
if(ng & 1){
|
||||
fp2_random(&g[ng>>1]);
|
||||
}
|
||||
|
||||
// Compute products
|
||||
poly_mul_selfreciprocal(h, g, ng, f, nf);
|
||||
slow_mul(fg, g, ng, f, nf);
|
||||
|
||||
// Compare
|
||||
for(e = 0; e < nf+ng-1; e++){
|
||||
assert(fp2_isequal(fg[e], h[e])==1);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested self reciprocal mul:\t\tNo errors!\n", 100 * nf / nmax);
|
||||
|
||||
// TEST FOR PRODUCT TREES
|
||||
int tree_size, iteration, i;
|
||||
int len, *DEG, LENF;
|
||||
poly *H, *F, h;
|
||||
|
||||
for(tree_size = 1; tree_size < nmax; tree_size++){
|
||||
|
||||
printf("[%3d%%] Testing product tree:\t\t\tSize %d out of %d", 100 * tree_size / nmax, tree_size, nmax-1);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
i = 0;
|
||||
while((1<<i) < tree_size){
|
||||
i++;
|
||||
}
|
||||
DEG = malloc(sizeof(int)*((1<<(i+2))-1));
|
||||
H = malloc(sizeof(poly)*((1<<(i+2))-1));
|
||||
F = malloc(sizeof(poly)*tree_size);
|
||||
h = malloc(sizeof(fp2_t)*(nmax+1)*tree_size);
|
||||
|
||||
for(iteration = 0; iteration < nmax + 1 - tree_size ; iteration++){
|
||||
|
||||
// Generate random list of polynomials
|
||||
LENF = (rand() % nmax)+1;
|
||||
for(i = 0; i < tree_size; i++){
|
||||
F[i] = malloc(sizeof(fp2_t)*LENF);
|
||||
for(e = 0; e < LENF; e++){
|
||||
fp2_random(&F[i][e]);
|
||||
}
|
||||
}
|
||||
product_tree(H, DEG, 0, F, LENF, tree_size);
|
||||
|
||||
// Build product of all polynomials manually
|
||||
len = LENF;
|
||||
|
||||
//for(e = 0; e < LENF[0]; e++){
|
||||
for(e = 0; e < LENF; e++){
|
||||
fp2_copy(&h[e], &F[0][e]);
|
||||
}
|
||||
for(i = 1; i < tree_size; i++){
|
||||
poly_mul(h, h, len, F[i], LENF);
|
||||
len += LENF-1;
|
||||
}
|
||||
|
||||
// Compare to root
|
||||
assert (len == DEG[0]+1);
|
||||
for(e = 0; e < len; e++){
|
||||
assert(fp2_isequal(H[0][e], h[e])==1);
|
||||
}
|
||||
clear_tree(H, 0, tree_size);
|
||||
for(i = 0; i < tree_size; i++){
|
||||
free(F[i]);
|
||||
}
|
||||
|
||||
}
|
||||
free(DEG);
|
||||
free(H);
|
||||
free(F);
|
||||
free(h);
|
||||
}
|
||||
printf("[%3d%%] Tested product tree:\t\t\tNo errors!\n", 100 * tree_size / nmax);
|
||||
|
||||
// TEST FOR SELF RECIPROCAL PRODUCT TREES
|
||||
|
||||
for(tree_size = 1; tree_size < nmax; tree_size++){
|
||||
|
||||
printf("[%3d%%] Testing selfreciprocal product tree:\tSize %d out of %d", 100 * tree_size / nmax, tree_size, nmax-1);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
i = 0;
|
||||
while((1<<i) < tree_size){
|
||||
i++;
|
||||
}
|
||||
DEG = malloc(sizeof(int)*((1<<(i+2))-1));
|
||||
H = malloc(sizeof(poly)*((1<<(i+2))-1));
|
||||
F = malloc(sizeof(poly)*tree_size);
|
||||
h = malloc(sizeof(fp2_t)*(nmax+1)*tree_size);
|
||||
|
||||
for(iteration = 0; iteration < nmax + 1 - tree_size ; iteration++){
|
||||
|
||||
// Generate random list of polynomials
|
||||
LENF = (rand() % nmax)+1;;
|
||||
for(i = 0; i < tree_size; i++){
|
||||
F[i] = malloc(sizeof(fp2_t)*LENF);
|
||||
for(e = 0; e < (LENF>>1); e++){
|
||||
fp2_random(&F[i][e]);
|
||||
fp2_copy(&F[i][LENF-1-e], &F[i][e]);
|
||||
}
|
||||
if(LENF & 1){
|
||||
fp2_random(&F[i][(LENF>>1)]);
|
||||
}
|
||||
}
|
||||
product_tree_selfreciprocal(H, DEG, 0, F, LENF, tree_size);
|
||||
|
||||
// Build product of all polynomials manually
|
||||
len = LENF;
|
||||
for(e = 0; e < LENF; e++){
|
||||
fp2_copy(&h[e], &F[0][e]);
|
||||
}
|
||||
for(i = 1; i < tree_size; i++){
|
||||
poly_mul(h, h, len, F[i], LENF);
|
||||
len += LENF-1;
|
||||
}
|
||||
|
||||
// Compare to root
|
||||
assert (len == DEG[0]+1);
|
||||
for(e = 0; e < len; e++){
|
||||
assert(fp2_isequal(H[0][e], h[e])==1);
|
||||
}
|
||||
clear_tree(H, 0, tree_size);
|
||||
for(i = 0; i < tree_size; i++){
|
||||
free(F[i]);
|
||||
}
|
||||
|
||||
}
|
||||
free(DEG);
|
||||
free(H);
|
||||
free(F);
|
||||
free(h);
|
||||
}
|
||||
printf("[%3d%%] Tested selfreciprocal product tree:\tNo errors!\n", 100 * tree_size / nmax);
|
||||
|
||||
printf("-- All tests passed.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
461
src/ec/ref/ecx/test/poly-redc-test.c
Normal file
461
src/ec/ref/ecx/test/poly-redc-test.c
Normal file
@@ -0,0 +1,461 @@
|
||||
#include "poly.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#define nmax 32
|
||||
|
||||
bool fp2_isequal(fp2_t a, fp2_t b){
|
||||
return fp_is_equal(a.re, b.re) && fp_is_equal(a.im, b.im);
|
||||
}
|
||||
|
||||
// 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]);
|
||||
}
|
||||
|
||||
int main(){
|
||||
fp2_t fp2_0, fp2_1;
|
||||
fp2_set(&fp2_0, 0);
|
||||
fp_mont_setone(fp2_1.re);fp_set(fp2_1.im,0);
|
||||
|
||||
int lenf, leng, n, e, iteration, array_size, tree_size, i, root, brother, *DEG, LENF;
|
||||
poly f, g, h, f_rev, f_rev_inv, *F, *H, *R, g1, g2, REM1, REM2, G1, G2, G1_rev, G2_rev, R0;
|
||||
fp2_t c, *A, *C, ratio, A0;
|
||||
|
||||
f_rev_inv = 0;
|
||||
|
||||
// TEST FOR RECIPROCAL
|
||||
for(lenf = 1; lenf < nmax; lenf++)
|
||||
{
|
||||
printf("[%3d%%] Testing reciprocals", 100 * lenf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
// Get random poly
|
||||
f = malloc(sizeof(fp2_t)*lenf);
|
||||
for(e = 0; e < lenf; e++)
|
||||
fp2_random(&f[e]);
|
||||
|
||||
for(n = 1; n < nmax; n++)
|
||||
{
|
||||
// Get the reciprocal and multiply them
|
||||
h = malloc(sizeof(fp2_t)*n);
|
||||
memset(h, 0, sizeof(fp2_t)*n);
|
||||
reciprocal(h, &c, f, lenf, n);
|
||||
poly_mul_low(h, n, f, lenf, h, n);
|
||||
|
||||
// Compare with expected
|
||||
assert(fp2_isequal(h[0],c));
|
||||
for(e = 1; e < n; e++)
|
||||
assert(fp2_is_zero(&h[e]));
|
||||
free(h);
|
||||
}
|
||||
free(f);
|
||||
}
|
||||
printf("[%3d%%] Tested reciprocals:\t\tNo errors!\n", 100 * lenf / nmax);
|
||||
|
||||
|
||||
|
||||
// TEST FOR REDUCTION
|
||||
for(lenf = 2; lenf < nmax; lenf++)
|
||||
{
|
||||
printf("[%3d%%] Testing polynomial reduction", 100 * lenf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
// Get random poly for the mod
|
||||
f = malloc(sizeof(fp2_t)*lenf);
|
||||
f_rev = malloc(sizeof(fp2_t)*lenf);
|
||||
for(e = 0; e < lenf; e++)
|
||||
{
|
||||
fp2_random(&f[e]);
|
||||
fp2_copy(&f_rev[lenf-1-e], &f[e]);
|
||||
}
|
||||
|
||||
for(leng = 1; leng < nmax; leng++)
|
||||
{
|
||||
// Get random poly to reduce
|
||||
g = malloc(sizeof(fp2_t)*leng);
|
||||
for(e = 0; e < leng; e++){
|
||||
fp2_random(&g[e]);
|
||||
}
|
||||
|
||||
// Get reverse-inverse mod x^(leng-lenf+1)
|
||||
if(leng >= lenf)
|
||||
{
|
||||
f_rev_inv = malloc(sizeof(fp2_t)*(leng-lenf+1));
|
||||
reciprocal(f_rev_inv, &c, f_rev, lenf, leng-lenf+1);
|
||||
}
|
||||
else{
|
||||
fp_mont_setone(c.re);fp_set(c.im,0);
|
||||
}
|
||||
|
||||
// Compute the reduction
|
||||
h = malloc(sizeof(fp2_t)*(lenf-1));
|
||||
poly_redc(h, g, leng, f, lenf, f_rev_inv, c);
|
||||
|
||||
// Reduce manually
|
||||
int leng_red = leng;
|
||||
fp2_t scale, f_e;
|
||||
while(leng_red >= lenf)
|
||||
{
|
||||
fp2_copy(&scale, &f[lenf-1]);
|
||||
fp2_inv(&scale);
|
||||
fp2_mul(&scale, &scale, &g[leng_red-1]);
|
||||
for(e = 0; e < lenf; e++)
|
||||
{
|
||||
fp2_mul(&f_e, &f[e], &scale);
|
||||
fp2_sub(&g[e+leng_red-lenf], &g[e+leng_red-lenf], &f_e);
|
||||
}
|
||||
leng_red--;
|
||||
}
|
||||
|
||||
// Rescale manual result
|
||||
if( leng < lenf){
|
||||
fp_mont_setone(scale.re);fp_set(scale.im,0);
|
||||
}
|
||||
else
|
||||
if(lenf == 2 && leng == 3)
|
||||
{
|
||||
fp2_sqr(&scale, &f[1]);
|
||||
fp2_add(&scale, &scale, &scale);
|
||||
}
|
||||
else
|
||||
fp2_copy(&scale, &c);
|
||||
for(e = 0; e < leng_red; e++)
|
||||
fp2_mul(&g[e], &g[e], &scale);
|
||||
|
||||
|
||||
// Comapre results
|
||||
for(e = leng_red-1; e >= 0; e--)
|
||||
assert(fp2_isequal(h[e], g[e]));
|
||||
for(e = leng_red; e < lenf-1; e++)
|
||||
assert(fp2_is_zero(&h[e]));
|
||||
|
||||
free(g);
|
||||
free(h);
|
||||
if(leng >= lenf)
|
||||
free(f_rev_inv);
|
||||
}
|
||||
free(f);
|
||||
free(f_rev);
|
||||
}
|
||||
printf("[%3d%%] Tested polynomial reduction:\tNo errors!\n", 100 * lenf / nmax);
|
||||
|
||||
|
||||
|
||||
// TEST FOR RECIPROCAL TREES
|
||||
|
||||
for(tree_size = 3; tree_size < nmax; tree_size++)
|
||||
{
|
||||
printf("[%3d%%] Testing reciprocal tree:\t\tTree size %d out of %d", 100 * tree_size / nmax, tree_size, nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
// Compute size of arrays
|
||||
i = 0;
|
||||
while((1<<i) < tree_size){
|
||||
i++;
|
||||
}
|
||||
array_size = (1<<(i+2))-1;
|
||||
|
||||
DEG = malloc(sizeof(int)*array_size);
|
||||
H = malloc(sizeof(poly)*array_size);
|
||||
R = malloc(sizeof(poly)*array_size);
|
||||
F = malloc(sizeof(poly)*tree_size);
|
||||
A = malloc(sizeof(fp2_t)*array_size);
|
||||
|
||||
// Get random polys
|
||||
LENF = 2;
|
||||
for(i = 0; i < tree_size; i++)
|
||||
{
|
||||
F[i] = malloc(sizeof(fp2_t)*LENF);
|
||||
for(e = 0; e < LENF; e++){
|
||||
fp2_random(&F[i][e]);
|
||||
}
|
||||
}
|
||||
|
||||
// Get product tree then reciprocal tree
|
||||
product_tree(H, DEG, 0, F, LENF, tree_size);
|
||||
leng = DEG[0]+1+(rand() % nmax);
|
||||
reciprocal_tree(R, A, leng, H, DEG, 0, tree_size);
|
||||
|
||||
// Check the root
|
||||
root = 0;
|
||||
lenf = leng-DEG[root];
|
||||
f = malloc(sizeof(fp2_t)*lenf);
|
||||
for(e = 0; e < DEG[root]+1 && e < lenf; e++){
|
||||
fp2_copy(&f[e], &H[root][DEG[root]-e]);
|
||||
}
|
||||
for(e = DEG[root]+1; e < lenf; e++){
|
||||
fp2_set(&f[e], 0);
|
||||
}
|
||||
poly_mul_low(f, lenf, f, lenf, R[root], lenf);
|
||||
assert(fp2_isequal(f[0], A[root]));
|
||||
for(e = 1; e < lenf; e++){
|
||||
assert(fp2_is_zero(&f[e]));
|
||||
}
|
||||
free(f);
|
||||
|
||||
// Perform random walks
|
||||
for(iteration = 0; iteration < nmax - tree_size; iteration++)
|
||||
{
|
||||
root = 0;
|
||||
n = tree_size;
|
||||
while(n > 1)
|
||||
{
|
||||
if(rand() & 1)
|
||||
{
|
||||
root = 2*root+1;
|
||||
n = n - (n>>1);
|
||||
}
|
||||
else
|
||||
{
|
||||
root = 2*root+2;
|
||||
n = n>>1;
|
||||
}
|
||||
brother = root - 1 + 2*(root & 1);
|
||||
|
||||
// Check current node
|
||||
if(DEG[root] > 2)
|
||||
{
|
||||
lenf = DEG[brother];
|
||||
f = malloc(sizeof(fp2_t)*lenf);
|
||||
for(e = 0; e < DEG[root]+1 && e < lenf; e++){
|
||||
fp2_copy(&f[e], &H[root][DEG[root]-e]);
|
||||
}
|
||||
for(e = DEG[root]+1; e < lenf; e++){
|
||||
fp2_set(&f[e], 0);
|
||||
}
|
||||
poly_mul_low(f, lenf, f, lenf, R[root], lenf);
|
||||
assert(fp2_isequal(f[0], A[root]));
|
||||
for(e = 1; e < lenf; e++){
|
||||
assert(fp2_is_zero(&f[e]));
|
||||
}
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Clean up
|
||||
for(i = 0; i < tree_size; i++)
|
||||
free(F[i]);
|
||||
clear_tree(H, 0, tree_size);
|
||||
clear_tree(R, 0, tree_size);
|
||||
free(F);
|
||||
free(H);
|
||||
free(R);
|
||||
free(A);
|
||||
free(DEG);
|
||||
}
|
||||
printf("[%3d%%] Tested reciprocal tree:\t\tNo errors!\n", 100 * tree_size / nmax);
|
||||
|
||||
|
||||
|
||||
// TEST FOR REMAINDERS
|
||||
for(tree_size = 2; tree_size < nmax; tree_size++)
|
||||
{
|
||||
printf("[%3d%%] Testing batched remainders:\t\tTree size %d out of %d", 100 * tree_size / nmax, tree_size, nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
// Compute size of arrays
|
||||
i = 0;
|
||||
while((1<<i) < tree_size)
|
||||
i++;
|
||||
array_size = (1<<(i+2))-1;
|
||||
|
||||
DEG = malloc(sizeof(int)*array_size);
|
||||
H = malloc(sizeof(poly)*array_size);
|
||||
R = malloc(sizeof(poly)*array_size);
|
||||
F = malloc(sizeof(poly)*tree_size);
|
||||
A = malloc(sizeof(fp2_t)*array_size);
|
||||
REM1 = malloc(sizeof(fp2_t)*array_size);
|
||||
REM2 = malloc(sizeof(fp2_t)*array_size);
|
||||
C = malloc(sizeof(fp2_t)*tree_size);
|
||||
|
||||
// Get random polys
|
||||
LENF = 2;
|
||||
for(i = 0; i < tree_size; i++)
|
||||
{
|
||||
F[i] = malloc(sizeof(fp2_t)*LENF);
|
||||
for(e = 0; e < LENF; e++)
|
||||
fp2_random(&F[i][e]);
|
||||
}
|
||||
|
||||
// Get product tree, reciprocal tree, and remainders
|
||||
product_tree(H, DEG, 0, F, LENF, tree_size);
|
||||
leng = DEG[0]+1+(rand() % nmax);
|
||||
g1 = malloc(sizeof(fp2_t)*leng);
|
||||
g2 = malloc(sizeof(fp2_t)*leng);
|
||||
for(e = 0; e < leng; e++)
|
||||
{
|
||||
fp2_random(&g1[e]);
|
||||
fp2_random(&g2[e]);
|
||||
}
|
||||
reciprocal_tree(R, A, leng, H, DEG, 0, tree_size);
|
||||
multieval_unscaled(REM1, g1, leng, R, (const fp2_t*)A, H, DEG, 0, tree_size);
|
||||
multieval_unscaled(REM2, g2, leng, R, (const fp2_t*)A, H, DEG, 0, tree_size);
|
||||
|
||||
for(i = 0; i < tree_size; i++)
|
||||
{
|
||||
// Get ratio of the remainder
|
||||
fp2_inv(&REM1[i]);
|
||||
fp2_mul(&ratio, &REM1[i], &REM2[i]);
|
||||
|
||||
// Compute remainders manually
|
||||
f_rev = malloc(sizeof(fp2_t)*LENF);
|
||||
f_rev_inv = malloc(sizeof(fp2_t)*(leng-LENF+1));
|
||||
h = malloc(sizeof(fp2_t)*(LENF-1));
|
||||
for(e = 0; e < LENF; e++)
|
||||
fp2_copy(&f_rev[e], &F[i][LENF-1-e]);
|
||||
reciprocal(f_rev_inv, &c, f_rev, LENF, leng-LENF+1);
|
||||
poly_redc(h, g1, leng, F[i], LENF, f_rev_inv, c);
|
||||
fp2_copy(&REM1[i], &h[0]);
|
||||
poly_redc(h, g2, leng, F[i], LENF, f_rev_inv, c);
|
||||
fp2_copy(&REM2[i], &h[0]);
|
||||
free(f_rev);
|
||||
free(f_rev_inv);
|
||||
free(h);
|
||||
|
||||
// Compare results
|
||||
fp2_inv(&REM1[i]);
|
||||
fp2_mul(&REM1[i], &REM1[i], &REM2[i]);
|
||||
assert(fp2_isequal(REM1[i], ratio));
|
||||
}
|
||||
|
||||
// Clean up
|
||||
for(i = 0; i < tree_size; i++)
|
||||
free(F[i]);
|
||||
free(g1);
|
||||
free(g2);
|
||||
clear_tree(H, 0, tree_size);
|
||||
clear_tree(R, 0, tree_size);
|
||||
free(F);
|
||||
free(H);
|
||||
free(R);
|
||||
free(A);
|
||||
free(DEG);
|
||||
free(REM1);
|
||||
free(REM2);
|
||||
free(C);
|
||||
}
|
||||
printf("[%3d%%] Tested batched remainders:\tNo errors!\n", 100 * tree_size / nmax);
|
||||
|
||||
|
||||
|
||||
// TEST FOR SCALED REMAINDER TREE
|
||||
for(tree_size = 1; tree_size < nmax; tree_size++)
|
||||
{
|
||||
printf("[%3d%%] Testing scaled remainder tree:\tTree size %d out of %d", 100 * tree_size / nmax, tree_size, nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
// Compute size of arrays
|
||||
i = 0;
|
||||
while((1<<i) < tree_size)
|
||||
i++;
|
||||
array_size = (1<<(i+2))-1;
|
||||
|
||||
DEG = malloc(sizeof(int)*array_size);
|
||||
H = malloc(sizeof(poly)*array_size);
|
||||
F = malloc(sizeof(poly)*tree_size);
|
||||
REM1 = malloc(sizeof(fp2_t)*array_size);
|
||||
REM2 = malloc(sizeof(fp2_t)*array_size);
|
||||
|
||||
// Get random polys
|
||||
LENF = 2;
|
||||
for(i = 0; i < tree_size; i++)
|
||||
{
|
||||
F[i] = malloc(sizeof(fp2_t)*LENF);
|
||||
for(e = 0; e < LENF; e++)
|
||||
fp2_random(&F[i][e]);
|
||||
}
|
||||
|
||||
// Get random polys to reduce
|
||||
product_tree(H, DEG, 0, F, LENF, tree_size);
|
||||
leng = DEG[0]+1+(rand() % nmax);
|
||||
g1 = malloc(sizeof(fp2_t)*leng);
|
||||
g2 = malloc(sizeof(fp2_t)*leng);
|
||||
for(e = 0; e < leng; e++)
|
||||
{
|
||||
fp2_random(&g1[e]);
|
||||
fp2_random(&g2[e]);
|
||||
}
|
||||
|
||||
// Get the required initial nodes
|
||||
G1 = malloc(sizeof(fp2_t)*DEG[0]);
|
||||
G2 = malloc(sizeof(fp2_t)*DEG[0]);
|
||||
G1_rev = malloc(sizeof(fp2_t)*DEG[0]);
|
||||
G2_rev = malloc(sizeof(fp2_t)*DEG[0]);
|
||||
R0 = malloc(sizeof(fp2_t)*(leng));
|
||||
f_rev = malloc(sizeof(fp2_t)*(DEG[0]+1));
|
||||
for(e = 0; e < DEG[0]+1; e++)
|
||||
fp2_copy(&f_rev[e], &H[0][DEG[0]-e]);
|
||||
if( DEG[0] > leng-DEG[0])
|
||||
reciprocal(R0, &A0, f_rev, DEG[0]+1, DEG[0]);
|
||||
else
|
||||
reciprocal(R0, &A0, f_rev, DEG[0]+1, leng-DEG[0]);
|
||||
poly_redc(G1, g1, leng, H[0], DEG[0]+1, R0, A0);
|
||||
poly_redc(G2, g2, leng, H[0], DEG[0]+1, R0, A0);
|
||||
for(e = 0; e < DEG[0]; e++)
|
||||
{
|
||||
fp2_copy(&G1_rev[e], &G1[DEG[0]-1-e]);
|
||||
fp2_copy(&G2_rev[e], &G2[DEG[0]-1-e]);
|
||||
}
|
||||
poly_mul_middle(G1_rev, G1_rev, DEG[0], R0, DEG[0]);
|
||||
poly_mul_middle(G2_rev, G2_rev, DEG[0], R0, DEG[0]);
|
||||
for(e = 0; e < DEG[0]; e++)
|
||||
{
|
||||
fp2_copy(&G1[e], &G1_rev[DEG[0]-1-e]);
|
||||
fp2_copy(&G2[e], &G2_rev[DEG[0]-1-e]);
|
||||
}
|
||||
free(G1_rev);free(G2_rev);free(R0);free(f_rev);
|
||||
|
||||
// Compute the scaled remainder trees
|
||||
multieval_scaled(REM1, G1, H, DEG, 0, tree_size);
|
||||
multieval_scaled(REM2, G2, H, DEG, 0, tree_size);
|
||||
|
||||
for(i = 0; i < tree_size; i++)
|
||||
{
|
||||
// Get ratio of the remainder
|
||||
fp2_inv(&REM1[i]);
|
||||
fp2_mul(&ratio, &REM1[i], &REM2[i]);
|
||||
|
||||
// Compute remainders manually
|
||||
f_rev = malloc(sizeof(fp2_t)*LENF);
|
||||
f_rev_inv = malloc(sizeof(fp2_t)*(leng-LENF+1));
|
||||
h = malloc(sizeof(fp2_t)*(LENF-1));
|
||||
for(e = 0; e < LENF; e++)
|
||||
fp2_copy(&f_rev[e], &F[i][LENF-1-e]);
|
||||
reciprocal(f_rev_inv, &c, f_rev, LENF, leng-LENF+1);
|
||||
poly_redc(h, g1, leng, F[i], LENF, f_rev_inv, c);
|
||||
fp2_copy(&REM1[i], &h[0]);
|
||||
poly_redc(h, g2, leng, F[i], LENF, f_rev_inv, c);
|
||||
fp2_copy(&REM2[i], &h[0]);
|
||||
free(f_rev);free(f_rev_inv);free(h);
|
||||
|
||||
// Compare results
|
||||
fp2_inv(&REM1[i]);
|
||||
fp2_mul(&REM1[i], &REM1[i], &REM2[i]);
|
||||
assert(fp2_isequal(REM1[i], ratio));
|
||||
}
|
||||
|
||||
// Clean up
|
||||
for(i = 0; i < tree_size; i++)
|
||||
free(F[i]);
|
||||
free(F);free(g1);free(g2);free(G1);free(G2);
|
||||
clear_tree(H, 0, tree_size);free(H);free(DEG);
|
||||
free(REM1);free(REM2);
|
||||
}
|
||||
printf("[%3d%%] Tested scaled remainder tree:\tNo errors!\n", 100 * tree_size / nmax);
|
||||
|
||||
printf("-- All tests passed.\n");
|
||||
}
|
||||
75
src/ec/ref/ecx/test/test_extras.c
Executable file
75
src/ec/ref/ecx/test/test_extras.c
Executable file
@@ -0,0 +1,75 @@
|
||||
#include "test_extras.h"
|
||||
#include <bench.h>
|
||||
|
||||
// Global constants
|
||||
extern const digit_t p[NWORDS_FIELD];
|
||||
extern const digit_t R2[NWORDS_FIELD];
|
||||
|
||||
|
||||
#if 0
|
||||
int64_t cpucycles(void)
|
||||
{ // Access system counter for benchmarking
|
||||
unsigned int hi, lo;
|
||||
|
||||
asm volatile ("rdtsc\n\t" : "=a" (lo), "=d"(hi));
|
||||
return ((int64_t)lo) | (((int64_t)hi) << 32);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int compare_words(digit_t* a, digit_t* b, unsigned int nwords)
|
||||
{ // Comparing "nword" elements, a=b? : (1) a>b, (0) a=b, (-1) a<b
|
||||
// SECURITY NOTE: this function does not have constant-time execution. TO BE USED FOR TESTING ONLY.
|
||||
int i;
|
||||
|
||||
for (i = nwords-1; i >= 0; i--)
|
||||
{
|
||||
if (a[i] > b[i]) return 1;
|
||||
else if (a[i] < b[i]) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void sub_test(digit_t* out, digit_t* a, digit_t* b, unsigned int nwords)
|
||||
{ // Subtraction without borrow, out = a-b where a>b
|
||||
// SECURITY NOTE: this function does not have constant-time execution. It is for TESTING ONLY.
|
||||
unsigned int i;
|
||||
digit_t res, carry, borrow = 0;
|
||||
|
||||
for (i = 0; i < nwords; i++)
|
||||
{
|
||||
res = a[i] - b[i];
|
||||
carry = (a[i] < b[i]);
|
||||
out[i] = res - borrow;
|
||||
borrow = carry || (res < borrow);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fprandom_test(digit_t* a)
|
||||
{ // Generating a pseudo-random field element in [0, p-1]
|
||||
// SECURITY NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY.
|
||||
unsigned int i, diff = 256-254, nwords = NWORDS_FIELD;
|
||||
unsigned char* string = NULL;
|
||||
|
||||
string = (unsigned char*)a;
|
||||
for (i = 0; i < sizeof(digit_t)*nwords; i++) {
|
||||
*(string + i) = (unsigned char)rand(); // Obtain 256-bit number
|
||||
}
|
||||
a[nwords-1] &= (((digit_t)(-1) << diff) >> diff);
|
||||
|
||||
while (compare_words((digit_t*)p, a, nwords) < 1) { // Force it to [0, modulus-1]
|
||||
sub_test(a, a, (digit_t*)p, nwords);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fp2random_test(fp2_t* a)
|
||||
{ // Generating a pseudo-random element in GF(p^2)
|
||||
// SECURITY NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY.
|
||||
|
||||
fprandom_test(a->re);
|
||||
fprandom_test(a->im);
|
||||
}
|
||||
29
src/ec/ref/ecx/test/test_extras.h
Executable file
29
src/ec/ref/ecx/test/test_extras.h
Executable file
@@ -0,0 +1,29 @@
|
||||
|
||||
#ifndef TEST_EXTRAS_H
|
||||
#define TEST_EXTRAS_H
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <fp.h>
|
||||
#include <fp2.h>
|
||||
#include <curve_extras.h>
|
||||
|
||||
#define PASSED 0
|
||||
#define FAILED 1
|
||||
|
||||
// Access system counter for benchmarking
|
||||
//int64_t cpucycles(void);
|
||||
|
||||
// Comparing "nword" elements, a=b? : (1) a!=b, (0) a=b
|
||||
int compare_words(digit_t* a, digit_t* b, unsigned int nwords);
|
||||
|
||||
// Multiprecision subtraction for testing, assumes a > b
|
||||
void sub_test(digit_t* out, digit_t* a, digit_t* b, unsigned int nwords);
|
||||
|
||||
// Generating a pseudo-random field element in [0, p-1]
|
||||
void fprandom_test(digit_t* a);
|
||||
|
||||
// Generating a pseudo-random element in GF(p^2)
|
||||
void fp2random_test(fp2_t* a);
|
||||
|
||||
#endif
|
||||
298
src/ec/ref/ecx/test/velu-test.c
Normal file
298
src/ec/ref/ecx/test/velu-test.c
Normal file
@@ -0,0 +1,298 @@
|
||||
#include<time.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "isog.h"
|
||||
#include "sdacs.h"
|
||||
#include "ec.h"
|
||||
#include "test-basis.h"
|
||||
|
||||
void random_scalar(fp_t k, const uint8_t j)
|
||||
{
|
||||
for(int i = 0; i < NWORDS_FIELD; i++)
|
||||
k[i] = rand();
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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()
|
||||
{
|
||||
|
||||
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, B, T;
|
||||
fp2_set(&A.x, 0);
|
||||
fp_mont_setone(A.z.re);fp_set(A.z.im,0);
|
||||
|
||||
// fp2_add(&A.x, &A.z, &A.x); // 1
|
||||
// fp2_add(&A.x, &A.x, &A.x); // 2
|
||||
// fp2_add(&A.x, &A.z, &A.x); // 3
|
||||
// fp2_add(&A.x, &A.x, &A.x); // 6
|
||||
|
||||
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, RA, RB;
|
||||
|
||||
// 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) );
|
||||
// ======================================================================================================
|
||||
// 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) );
|
||||
|
||||
// --------------------------------------------------------------
|
||||
fp_t m;
|
||||
random_scalar(m, 0);
|
||||
ladder3pt(&RA, m, &PA, &QA, &PQA, &A);
|
||||
for (i = 0; i < P_LEN; i++)
|
||||
{
|
||||
printf("// Processing the %d-th prime:\t", i + 1);
|
||||
printf("%2d%%", 100 * i / (int)P_LEN);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
copy_point(&T, &RA);
|
||||
for (j = (i+1); j < P_LEN; j++)
|
||||
xMULv2(&T, &T, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
|
||||
assert( !isinfinity(T) );
|
||||
|
||||
kps(i, T, A);
|
||||
if (TORSION_ODD_PRIMES[i] > gap)
|
||||
printf("[\033[0;31m%7" PRId64 "\033[0m] (#I: %3d, #J: %3d, #K: %3d) \n", TORSION_ODD_PRIMES[i], sI, sJ, sK);
|
||||
else
|
||||
printf("[\033[0;31m%7" PRId64 "\033[0m] --------------------------- \n", TORSION_ODD_PRIMES[i]);
|
||||
|
||||
xisog(&B, i, A);
|
||||
|
||||
xeval(&PB, i, PB, A);
|
||||
coeff(&a, B);
|
||||
assert( !isinfinity(PB) );
|
||||
assert( !isrational(PB, a) );
|
||||
|
||||
xeval(&RA, i, RA, A);
|
||||
assert( (!isinfinity(RA) && (i < (P_LEN - 1))) || (isinfinity(RA) && (i == (P_LEN - 1))) );
|
||||
assert( (isrational(RA, a) && (i < (P_LEN - 1))) || (isinfinity(RA) && (i == (P_LEN - 1))) );
|
||||
|
||||
copy_point(&A, &B);
|
||||
// Verifying the order of the image point of PA has been reduced
|
||||
copy_point(&T, &RA);
|
||||
for (j = (i+1); j < P_LEN; j++)
|
||||
xMULv2(&T, &T, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
|
||||
assert( isinfinity(T) );
|
||||
kps_clear(i);
|
||||
};
|
||||
|
||||
fp2_set(&A.x, 0);
|
||||
fp_mont_setone(A.z.re);fp_set(A.z.im,0);
|
||||
|
||||
// fp2_add(&A.x, &A.z, &A.x); // 1
|
||||
// fp2_add(&A.x, &A.x, &A.x); // 2
|
||||
// fp2_add(&A.x, &A.z, &A.x); // 3
|
||||
// fp2_add(&A.x, &A.x, &A.x); // 6
|
||||
|
||||
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) );
|
||||
|
||||
coeff(&a, A);
|
||||
// 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) );
|
||||
|
||||
// ======================================================================================================
|
||||
// Recall, PA, QA, and PQA are expeted to be N-order points, but we require to ensure they are of order N
|
||||
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) );
|
||||
|
||||
random_scalar(m, 1);
|
||||
ladder3pt(&RB, m, &PB, &QB, &PQB, &A);
|
||||
for (i = P_LEN; i < (P_LEN+M_LEN); i++)
|
||||
{
|
||||
printf("// Processing the %d-th prime:\t", i + 1);
|
||||
printf("%2d%%", 100 * i / (int)(P_LEN+M_LEN));
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
copy_point(&T, &RB);
|
||||
for (j = (i+1); j < (P_LEN+M_LEN); j++)
|
||||
xMULv2(&T, &T, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
|
||||
assert( !isinfinity(T) );
|
||||
|
||||
kps(i, T, A);
|
||||
if (TORSION_ODD_PRIMES[i] > gap)
|
||||
printf("[\033[0;31m%7" PRId64 "\033[0m] (#I: %3d, #J: %3d, #K: %3d) \n", TORSION_ODD_PRIMES[i], sI, sJ, sK);
|
||||
else
|
||||
printf("[\033[0;31m%7" PRId64 "\033[0m] --------------------------- \n", TORSION_ODD_PRIMES[i]);
|
||||
|
||||
xisog(&B, i, A);
|
||||
|
||||
xeval(&PA, i, PA, A);
|
||||
coeff(&a, B);
|
||||
assert( !isinfinity(PA) );
|
||||
assert( isrational(PA, a) );
|
||||
|
||||
xeval(&RB, i, RB, A);
|
||||
assert( (!isinfinity(RB) && (i < (P_LEN + M_LEN - 1))) || (isinfinity(RB) && (i == (P_LEN + M_LEN - 1))) );
|
||||
assert( (!isrational(RB, a) && (i < (P_LEN + M_LEN - 1))) || (isinfinity(RB) && (i == (P_LEN + M_LEN - 1))) );
|
||||
|
||||
copy_point(&A, &B);
|
||||
// Verifying the order of the image point of PB has been reduced
|
||||
copy_point(&T, &RB);
|
||||
for (j = (i+1); j < (P_LEN+M_LEN); j++)
|
||||
xMULv2(&T, &T, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
|
||||
assert( isinfinity(T) );
|
||||
kps_clear(i);
|
||||
};
|
||||
|
||||
printf("-- All tests passed!\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user