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:
SQIsign team
2023-06-01 00:00:00 +00:00
committed by Lorenz Panny
commit 28ff420dd0
285 changed files with 70301 additions and 0 deletions

View 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;
}