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

3
src/ec/ref/CMakeLists.txt Executable file
View File

@@ -0,0 +1,3 @@
set(ECX_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ecx)
include(${SELECT_SQISIGN_VARIANT})

508
src/ec/ref/ecx/basis.c Normal file
View File

@@ -0,0 +1,508 @@
#include "isog.h"
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);
}
int ec_is_on_curve(const ec_curve_t* curve, const ec_point_t* P){
fp2_t t0, t1, t2;
// Check if xz*(C^2x^2+zACx+z^2C^2) is a square
fp2_mul(&t0, &curve->C, &P->x);
fp2_mul(&t1, &t0, &P->z);
fp2_mul(&t1, &t1, &curve->A);
fp2_mul(&t2, &curve->C, &P->z);
fp2_sqr(&t0, &t0);
fp2_sqr(&t2, &t2);
fp2_add(&t0, &t0, &t1);
fp2_add(&t0, &t0, &t2);
fp2_mul(&t0, &t0, &P->x);
fp2_mul(&t0, &t0, &P->z);
return fp2_is_square(&t0);
}
static void difference_point(ec_point_t* PQ, const ec_point_t* P, const ec_point_t* Q, const ec_curve_t* curve){
// Given P,Q in affine x-only, computes a deterministic choice for (P-Q)
// The points must be normalized to z=1 and the curve to C=1
fp2_t t0, t1, t2, t3;
fp2_sub(&PQ->z, &P->x, &Q->x); // P - Q
fp2_mul(&t2, &P->x, &Q->x); // P*Q
fp_mont_setone(t1.re);
fp_set(t1.im, 0);
fp2_sub(&t3, &t2, &t1); // P*Q-1
fp2_mul(&t0, &PQ->z, &t3); // (P-Q)*(P*Q-1)
fp2_sqr(&PQ->z, &PQ->z); // (P-Q)^2
fp2_sqr(&t0, &t0); // (P-Q)^2*(P*Q-1)^2
fp2_add(&t1, &t2, &t1); // P*Q+1
fp2_add(&t3, &P->x, &Q->x); // P+Q
fp2_mul(&t1, &t1, &t3); // (P+Q)*(P*Q+1)
fp2_mul(&t2, &t2, &curve->A); // A*P*Q
fp2_add(&t2, &t2, &t2); // 2*A*P*Q
fp2_add(&t1, &t1, &t2); // (P+Q)*(P*Q+1) + 2*A*P*Q
fp2_sqr(&t2, &t1); // ((P+Q)*(P*Q+1) + 2*A*P*Q)^2
fp2_sub(&t0, &t2, &t0); // ((P+Q)*(P*Q+1) + 2*A*P*Q)^2 - (P-Q)^2*(P*Q-1)^2
fp2_sqrt(&t0);
fp2_add(&PQ->x, &t0, &t1);
}
void ec_curve_to_basis_2(ec_basis_t *PQ2, const ec_curve_t *curve){
fp2_t x, t0, t1, t2;
ec_point_t P, Q, Q2, P2, A24;
// Curve coefficient in the form A24 = (A+2C:4C)
fp2_add(&A24.z, &curve->C, &curve->C);
fp2_add(&A24.x, &curve->A, &A24.z);
fp2_add(&A24.z, &A24.z, &A24.z);
fp_mont_setone(x.re);
fp_set(x.im, 0);
// Find P
while(1){
fp_add(x.im, x.re, x.im);
// Check if point is rational
fp2_sqr(&t0, &curve->C);
fp2_mul(&t1, &t0, &x);
fp2_mul(&t2, &curve->A, &curve->C);
fp2_add(&t1, &t1, &t2);
fp2_mul(&t1, &t1, &x);
fp2_add(&t1, &t1, &t0);
fp2_mul(&t1, &t1, &x);
if(fp2_is_square(&t1)){
fp2_copy(&P.x, &x);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
}
else
continue;
// Clear odd factors from the order
xMULv2(&P, &P, p_cofactor_for_2f, P_COFACTOR_FOR_2F_BITLENGTH, &A24);
// Check if point has order 2^f
copy_point(&P2, &P);
for(int i = 0; i < POWER_OF_2 - 1; i++)
xDBLv2(&P2, &P2, &A24);
if(ec_is_zero(&P2))
continue;
else
break;
}
// Find Q
while(1){
fp_add(x.im, x.re, x.im);
// Check if point is rational
fp2_sqr(&t0, &curve->C);
fp2_mul(&t1, &t0, &x);
fp2_mul(&t2, &curve->A, &curve->C);
fp2_add(&t1, &t1, &t2);
fp2_mul(&t1, &t1, &x);
fp2_add(&t1, &t1, &t0);
fp2_mul(&t1, &t1, &x);
if(fp2_is_square(&t1)){
fp2_copy(&Q.x, &x);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
}
else
continue;
// Clear odd factors from the order
xMULv2(&Q, &Q, p_cofactor_for_2f, P_COFACTOR_FOR_2F_BITLENGTH, &A24);
// Check if point has order 2^f
copy_point(&Q2, &Q);
for(int i = 0; i < POWER_OF_2 - 1; i++)
xDBLv2(&Q2, &Q2, &A24);
if(ec_is_zero(&Q2))
continue;
// Check if point is orthogonal to P
if(is_point_equal(&P2, &Q2))
continue;
else
break;
}
// Normalize points
ec_curve_t E;
fp2_mul(&t0, &P.z, &Q.z);
fp2_mul(&t1, &t0, &curve->C);
fp2_inv(&t1);
fp2_mul(&P.x, &P.x, &t1);
fp2_mul(&Q.x, &Q.x, &t1);
fp2_mul(&E.A, &curve->A, &t1);
fp2_mul(&P.x, &P.x, &Q.z);
fp2_mul(&P.x, &P.x, &curve->C);
fp2_mul(&Q.x, &Q.x, &P.z);
fp2_mul(&Q.x, &Q.x, &curve->C);
fp2_mul(&E.A, &E.A, &t0);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_copy(&Q.z, &P.z);
fp2_copy(&E.C, &P.z);
// Compute P-Q
difference_point(&PQ2->PmQ, &P, &Q, &E);
copy_point(&PQ2->P, &P);
copy_point(&PQ2->Q, &Q);
}
void ec_complete_basis_2(ec_basis_t* PQ2, const ec_curve_t* curve, const ec_point_t* P){
fp2_t x, t0, t1, t2;
ec_point_t Q, Q2, P2, A24;
// Curve coefficient in the form A24 = (A+2C:4C)
fp2_add(&A24.z, &curve->C, &curve->C);
fp2_add(&A24.x, &curve->A, &A24.z);
fp2_add(&A24.z, &A24.z, &A24.z);
// Point of order 2 generated by P
copy_point(&P2, P);
for(int i = 0; i < POWER_OF_2 - 1; i++)
xDBLv2(&P2, &P2, &A24);
// Find Q
fp_mont_setone(x.re);
fp_set(x.im, 0);
while(1){
fp_add(x.im, x.re, x.im);
// Check if point is rational
fp2_sqr(&t0, &curve->C);
fp2_mul(&t1, &t0, &x);
fp2_mul(&t2, &curve->A, &curve->C);
fp2_add(&t1, &t1, &t2);
fp2_mul(&t1, &t1, &x);
fp2_add(&t1, &t1, &t0);
fp2_mul(&t1, &t1, &x);
if(fp2_is_square(&t1)){
fp2_copy(&Q.x, &x);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
}
else
continue;
// Clear odd factors from the order
xMULv2(&Q, &Q, p_cofactor_for_2f, (int)P_COFACTOR_FOR_2F_BITLENGTH, &A24);
// Check if point has order 2^f
copy_point(&Q2, &Q);
for(int i = 0; i < POWER_OF_2 - 1; i++)
xDBLv2(&Q2, &Q2, &A24);
if(ec_is_zero(&Q2))
continue;
// Check if point is orthogonal to P
if(is_point_equal(&P2, &Q2))
continue;
else
break;
}
// Normalize points
ec_curve_t E;
ec_point_t PP;
fp2_mul(&t0, &P->z, &Q.z);
fp2_mul(&t1, &t0, &curve->C);
fp2_inv(&t1);
fp2_mul(&PP.x, &P->x, &t1);
fp2_mul(&Q.x, &Q.x, &t1);
fp2_mul(&E.A, &curve->A, &t1);
fp2_mul(&PP.x, &PP.x, &Q.z);
fp2_mul(&PP.x, &PP.x, &curve->C);
fp2_mul(&Q.x, &Q.x, &P->z);
fp2_mul(&Q.x, &Q.x, &curve->C);
fp2_mul(&E.A, &E.A, &t0);
fp_mont_setone(PP.z.re);
fp_set(PP.z.im, 0);
fp2_copy(&Q.z, &PP.z);
fp2_copy(&E.C, &PP.z);
// Compute P-Q
difference_point(&PQ2->PmQ, &PP, &Q, &E);
copy_point(&PQ2->P, &PP);
copy_point(&PQ2->Q, &Q);
}
void ec_curve_to_basis_3(ec_basis_t* PQ3, const ec_curve_t* curve){
fp2_t x, t0, t1, t2;
ec_point_t P, Q, Q3, P3, A24, A3;
// Curve coefficient in the form A24 = (A+2C:4C)
fp2_add(&A24.z, &curve->C, &curve->C);
fp2_add(&A24.x, &curve->A, &A24.z);
fp2_add(&A24.z, &A24.z, &A24.z);
// Curve coefficient in the form A3 = (A+2C:A-2C)
fp2_sub(&A3.z, &A24.x, &A24.z);
fp2_copy(&A3.x, &A24.x);
fp_mont_setone(x.re);
fp_set(x.im, 0);
// Find P
while(1){
fp_add(x.im, x.re, x.im);
// Check if point is rational
fp2_sqr(&t0, &curve->C);
fp2_mul(&t1, &t0, &x);
fp2_mul(&t2, &curve->A, &curve->C);
fp2_add(&t1, &t1, &t2);
fp2_mul(&t1, &t1, &x);
fp2_add(&t1, &t1, &t0);
fp2_mul(&t1, &t1, &x);
if(fp2_is_square(&t1)){
fp2_copy(&P.x, &x);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
}
else
continue;
// Clear non-3 factors from the order
xMULv2(&P, &P, p_cofactor_for_3g, (int)P_COFACTOR_FOR_3G_BITLENGTH, &A24);
// Check if point has order 3^g
copy_point(&P3, &P);
for(int i = 0; i < POWER_OF_3 - 1; i++)
xTPL(&P3, &P3, &A3);
if(ec_is_zero(&P3))
continue;
else
break;
}
// Find Q
while(1){
fp_add(x.im, x.re, x.im);
// Check if point is rational
fp2_sqr(&t0, &curve->C);
fp2_mul(&t1, &t0, &x);
fp2_mul(&t2, &curve->A, &curve->C);
fp2_add(&t1, &t1, &t2);
fp2_mul(&t1, &t1, &x);
fp2_add(&t1, &t1, &t0);
fp2_mul(&t1, &t1, &x);
if(fp2_is_square(&t1)){
fp2_copy(&Q.x, &x);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
}
else
continue;
// Clear non-3 factors from the order
xMULv2(&Q, &Q, p_cofactor_for_3g, (int)P_COFACTOR_FOR_3G_BITLENGTH, &A24);
// Check if point has order 3^g
copy_point(&Q3, &Q);
for(int i = 0; i < POWER_OF_3 - 1; i++)
xTPL(&Q3, &Q3, &A3);
if(ec_is_zero(&Q3))
continue;
// Check if point is orthogonal to P
if(is_point_equal(&P3, &Q3))
continue;
xDBLv2(&P3, &P3, &A24);
if(is_point_equal(&P3, &Q3))
continue;
else
break;
}
// Normalize points
ec_curve_t E;
fp2_mul(&t0, &P.z, &Q.z);
fp2_mul(&t1, &t0, &curve->C);
fp2_inv(&t1);
fp2_mul(&P.x, &P.x, &t1);
fp2_mul(&Q.x, &Q.x, &t1);
fp2_mul(&E.A, &curve->A, &t1);
fp2_mul(&P.x, &P.x, &Q.z);
fp2_mul(&P.x, &P.x, &curve->C);
fp2_mul(&Q.x, &Q.x, &P.z);
fp2_mul(&Q.x, &Q.x, &curve->C);
fp2_mul(&E.A, &E.A, &t0);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_copy(&Q.z, &P.z);
fp2_copy(&E.C, &P.z);
// Compute P-Q
difference_point(&PQ3->PmQ, &P, &Q, &E);
copy_point(&PQ3->P, &P);
copy_point(&PQ3->Q, &Q);
}
void ec_curve_to_basis_6(ec_basis_t* PQ6, const ec_curve_t* curve){
fp2_t x, t0, t1, t2;
ec_point_t P, Q, Q6, P6, R, T, A24, A3;
// Curve coefficient in the form A24 = (A+2C:4C)
fp2_add(&A24.z, &curve->C, &curve->C);
fp2_add(&A24.x, &curve->A, &A24.z);
fp2_add(&A24.z, &A24.z, &A24.z);
// Curve coefficient in the form A3 = (A+2C:A-2C)
fp2_sub(&A3.z, &A24.x, &A24.z);
fp2_copy(&A3.x, &A24.x);
fp_mont_setone(x.re);
fp_set(x.im, 0);
// Find P
while(1){
fp_add(x.im, x.re, x.im);
// Check if point is rational
fp2_sqr(&t0, &curve->C);
fp2_mul(&t1, &t0, &x);
fp2_mul(&t2, &curve->A, &curve->C);
fp2_add(&t1, &t1, &t2);
fp2_mul(&t1, &t1, &x);
fp2_add(&t1, &t1, &t0);
fp2_mul(&t1, &t1, &x);
if(fp2_is_square(&t1)){
fp2_copy(&P.x, &x);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
}
else
continue;
// Clear non-2 factors and non-3 factors from the order
xMULv2(&P, &P, p_cofactor_for_6fg, (int)P_COFACTOR_FOR_6FG_BITLENGTH, &A24);
// Check if point has order 2^f*3^g
copy_point(&P6, &P);
for(int i = 0; i < POWER_OF_2 - 1; i++)
xDBLv2(&P6, &P6, &A24);
for(int i = 0; i < POWER_OF_3 - 1; i++)
xTPL(&P6, &P6, &A3);
if(ec_is_zero(&P6))
continue;
xDBLv2(&T, &P6, &A24);
if (ec_is_zero(&T))
continue;
xTPL(&T, &P6, &A3);
if (ec_is_zero(&T))
continue;
break;
}
// Find Q
while(1){
fp_add(x.im, x.re, x.im);
// Check if point is rational
fp2_sqr(&t0, &curve->C);
fp2_mul(&t1, &t0, &x);
fp2_mul(&t2, &curve->A, &curve->C);
fp2_add(&t1, &t1, &t2);
fp2_mul(&t1, &t1, &x);
fp2_add(&t1, &t1, &t0);
fp2_mul(&t1, &t1, &x);
if(fp2_is_square(&t1)){
fp2_copy(&Q.x, &x);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
}
else
continue;
// Clear non-6 factors from the order
xMULv2(&Q, &Q, p_cofactor_for_6fg, (int)P_COFACTOR_FOR_6FG_BITLENGTH, &A24);
// Check first if point has order 2^f*3^g
copy_point(&Q6, &Q);
for(int i = 0; i < POWER_OF_2 - 1; i++)
xDBLv2(&Q6, &Q6, &A24);
for(int i = 0; i < POWER_OF_3 - 1; i++)
xTPL(&Q6, &Q6, &A3);
if(ec_is_zero(&Q6))
continue;
xDBLv2(&T, &Q6, &A24);
if (ec_is_zero(&T))
continue;
xTPL(&T, &Q6, &A3);
if (ec_is_zero(&T))
continue;
// Check if point P is independent from point Q
xTPL(&R, &P6, &A3);
xTPL(&T, &Q6, &A3);
if(is_point_equal(&R, &T))
continue;
xDBLv2(&R, &P6, &A24);
xDBLv2(&T, &Q6, &A24);
if(is_point_equal(&R, &T))
continue;
break;
}
// Normalize points
ec_curve_t E;
fp2_mul(&t0, &P.z, &Q.z);
fp2_mul(&t1, &t0, &curve->C);
fp2_inv(&t1);
fp2_mul(&P.x, &P.x, &t1);
fp2_mul(&Q.x, &Q.x, &t1);
fp2_mul(&E.A, &curve->A, &t1);
fp2_mul(&P.x, &P.x, &Q.z);
fp2_mul(&P.x, &P.x, &curve->C);
fp2_mul(&Q.x, &Q.x, &P.z);
fp2_mul(&Q.x, &Q.x, &curve->C);
fp2_mul(&E.A, &E.A, &t0);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_copy(&Q.z, &P.z);
fp2_copy(&E.C, &P.z);
// Compute P-Q
difference_point(&PQ6->PmQ, &P, &Q, &E);
copy_point(&PQ6->P, &P);
copy_point(&PQ6->Q, &Q);
}

1461
src/ec/ref/ecx/ec.c Executable file

File diff suppressed because it is too large Load Diff

90
src/ec/ref/ecx/fp2-test.c Normal file
View File

@@ -0,0 +1,90 @@
#include <assert.h>
#include <time.h>
#include <stdio.h>
#include "../generic/include/fp2_tmp.h"
int main()
{
fp2_t fp2_0, fp2_1;
// ------------
fp2_set0(fp2_0);
fp2_set1(fp2_1);
// ------------
int i;
fp2_t a, b, c, d;
fp_t e;
for (i = 0; i < 1024; i++)
{
printf("[%3d%%] Testing fp2_t arithmetic", 100 * i / (int)1024);
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_set0(b);
fp2_copy(c, a);
fp2_neg(a, a);
fp2_sub(c, b, c);
assert(fp2_isequal(a,c) == 1);
fp2_set1(a); // Now a == 1
fp2_set0(b); // 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
fp2_set1(a);
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_issquare(b) );
};
printf("[%2d%%] Tested fp2_t arithmetic:\tNo errors!\n", 100 * i / (int)1024);
printf("-- All tests passed.\n");
return 0;
}

View File

@@ -0,0 +1,298 @@
#include "isog.h"
#include <assert.h>
static inline void AC_to_A24(ec_point_t *A24, ec_curve_t const *E)
{
// A24 = (A+2C : 4C)
fp2_add(&A24->z, &E->C, &E->C);
fp2_add(&A24->x, &E->A, &A24->z);
fp2_add(&A24->z, &A24->z, &A24->z);
}
static inline void A24_to_AC(ec_curve_t *E, ec_point_t const *A24)
{
// (A:C) = ((A+2C)*2-4C : 4C)
fp2_add(&E->A, &A24->x, &A24->x);
fp2_sub(&E->A, &E->A, &A24->z);
fp2_add(&E->A, &E->A, &E->A);
fp2_copy(&E->C, &A24->z);
}
void ec_eval_even(ec_curve_t* image, const ec_isog_even_t* phi,
ec_point_t* points, unsigned short length){
ec_point_t Q4, Q, A24;
copy_point(&Q4, &phi->kernel);
AC_to_A24(&A24, &phi->curve);
for(int i = 0; i < phi->length - 2; i++)
xDBLv2(&Q4, &Q4, &A24);
xDBLv2(&Q, &Q4, &A24);
if(fp2_is_zero(&Q.x)){
xisog_4_singular(&A24, Q4, A24);
xeval_4_singular(points, points, length, Q4);
xeval_4_singular(&Q, &phi->kernel, 1, Q4);
}
else{
xisog_4(&A24, Q4);
xeval_4(points, points, length);
xeval_4(&Q, &phi->kernel, 1);
}
ec_eval_even_strategy(image, points, length, &A24, &Q, phi->length-2);
}
void ec_eval_even_nonzero(ec_curve_t* image, const ec_isog_even_t* phi,
ec_point_t* points, unsigned short length){
ec_point_t Q4, A24;
copy_point(&Q4, &phi->kernel);
AC_to_A24(&A24, &phi->curve);
for(int i = 0; i < phi->length - 2; i++)
xDBLv2(&Q4, &Q4, &A24);
xisog_4(&A24, Q4);
xeval_4(points, points, length);
xeval_4(&Q4, &phi->kernel, 1);
ec_eval_even_strategy(image, points, length, &A24, &Q4, phi->length-2);
}
static void ec_eval_even_strategy(ec_curve_t* image, ec_point_t* points, unsigned short points_len,
ec_point_t* A24, const ec_point_t *kernel, const int isog_len){
assert(isog_len == POWER_OF_2-2);
uint8_t log2_of_e, tmp;
fp2_t t0;
digit_t e_half = (isog_len)>>1;
for(tmp = e_half, log2_of_e = 0; tmp > 0; tmp>>=1, ++log2_of_e);
log2_of_e *= 2; // In order to ensure each splits is at most size log2_of_e
ec_point_t SPLITTING_POINTS[log2_of_e], K2;
copy_point(&SPLITTING_POINTS[0], kernel);
int strategy = 0, // Current element of the strategy to be used
i, j;
int BLOCK = 0, // Keeps track of point order
current = 0; // Number of points being carried
int XDBLs[log2_of_e]; // Number of doubles performed
// If walk length is odd, we start with a 2-isogeny
if(isog_len & 1){
copy_point(&SPLITTING_POINTS[1], &SPLITTING_POINTS[0]);
for(i = 0; i < isog_len-1; i++)
xDBLv2(&SPLITTING_POINTS[1], &SPLITTING_POINTS[1], A24);
xisog_2(A24, SPLITTING_POINTS[1]);
xeval_2(SPLITTING_POINTS, SPLITTING_POINTS, 1);
xeval_2(points, points, points_len);
}
// Chain of 4-isogenies
for(j = 0; j < (e_half - 1); j++)
{
// Get the next point of order 4
while (BLOCK != (e_half - 1 - j) )
{
// A new split will be added
current += 1;
// We set the seed of the new split to be computed and saved
copy_point(&SPLITTING_POINTS[current], &SPLITTING_POINTS[current - 1]);
for(i = 0; i < 2*STRATEGY4[strategy]; i++)
xDBLv2(&SPLITTING_POINTS[current], &SPLITTING_POINTS[current], A24);
XDBLs[current] = STRATEGY4[strategy]; // The number of doublings performed is saved
BLOCK += STRATEGY4[strategy]; // BLOCK is increased by the number of doublings performed
strategy += 1; // Next, we move to the next element of the strategy
}
// Evaluate 4-isogeny
xisog_4(A24, SPLITTING_POINTS[current]);
xeval_4(SPLITTING_POINTS, SPLITTING_POINTS, current);
xeval_4(points, points, points_len);
BLOCK -= XDBLs[current];
XDBLs[current] = 0;
current -= 1;
}
// Final 4-isogeny
xisog_4(A24, SPLITTING_POINTS[current]);
xeval_4(points, points, points_len);
// Output curve in the form (A:C)
A24_to_AC(image, A24);
}
void ec_eval_odd(ec_curve_t* image, const ec_isog_odd_t* phi,
ec_point_t* points, unsigned short length){
ec_point_t ker_plus, ker_minus, P, K, A24, B24;
int i,j,k;
AC_to_A24(&A24, &phi->curve);
// Isogenies with kernel in E[p+1]
copy_point(&ker_plus, &phi->ker_plus);
copy_point(&ker_minus, &phi->ker_minus);
for(i = 0; i < P_LEN; i++){
copy_point(&P, &ker_plus);
for(j = i+1; j < P_LEN; j++){
for(k = 0; k < phi->degree[j]; k++)
xMULv2(&P, &P, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A24);
}
for(k = 0; k < phi->degree[i]; k++){
copy_point(&K, &P);
for(j = 0; j < phi->degree[i]-k-1; j++)
xMULv2(&K, &K, &(TORSION_ODD_PRIMES[i]), p_plus_minus_bitlength[i], &A24);
kps(i, K, A24);
xisog(&B24, i, A24);
xeval(&P, i, P, A24);
xeval(&ker_plus, i, ker_plus, A24);
xeval(&ker_minus, i, ker_minus, A24);
for(j = 0; j < length; j++)
xeval(&points[j], i, points[j], A24);
copy_point(&A24, &B24);
kps_clear(i);
}
}
// Isogenies with kernel in E[p-1]
for(i = P_LEN; i < P_LEN+M_LEN; i++){
copy_point(&P, &ker_minus);
for(j = i+1; j < P_LEN+M_LEN; j++){
for(k = 0; k < phi->degree[j]; k++)
xMULv2(&P, &P, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A24);
}
for(k = 0; k < phi->degree[i]; k++){
copy_point(&K, &P);
for(j = 0; j < phi->degree[i]-k-1; j++)
xMULv2(&K, &K, &(TORSION_ODD_PRIMES[i]), p_plus_minus_bitlength[i], &A24);
kps(i, K, A24);
xisog(&B24, i, A24);
xeval(&P, i, P, A24);
xeval(&ker_minus, i, ker_minus, A24);
for(j = 0; j < length; j++)
xeval(&points[j], i, points[j], A24);
copy_point(&A24, &B24);
kps_clear(i);
}
}
A24_to_AC(image, &A24);
}
void ec_curve_normalize(ec_curve_t *new, ec_isom_t *isom, const ec_curve_t *old){
fp2_t t0, t1, t2, t3, t4, t5;
// Compute the other solutions:
// A'^2 = [ sqrt(A^2-4C^2)*(9C^2-A^2) +- (A^3-3AC^2) ] / [ 2C^2*sqrt(A^2-4C^2) ]
fp2_sqr(&t0, &old->C); //C^2
fp2_add(&t1, &t0, &t0); //2C^2
fp2_add(&t2, &t1, &t1); //4C^2
fp2_sqr(&t3, &old->A); //A^2
fp2_sub(&t2, &t3, &t2); //A^2-4C^2
fp2_sqrt(&t2); //sqrt(A^2-4C^2)
fp2_add(&t0, &t0, &t1); //3C^2
fp2_mul(&t1, &t2, &t1); //2C^2*sqrt(A^2-4C^2)
fp2_sub(&t5, &t3, &t0); //A^2-3C^2
fp2_mul(&t5, &t5, &old->A); //A^3-3AC^2
fp2_add(&t4, &t0, &t0); //6C^2
fp2_add(&t0, &t4, &t0); //9C^2
fp2_sub(&t0, &t0, &t3); //9C^2-A^2
fp2_add(&t3, &t3, &t3); //2A^2
fp2_mul(&t3, &t3, &t2); //2A^2*sqrt(A^2-4C^2)
fp2_mul(&t2, &t2, &t0); //sqrt(A^2-4C^2)*(9C^2-A^2)
fp2_add(&t0, &t2, &t5); //sqrt(A^2-4C^2)*(9C^2-A^2) + (A^3-3AC^2)
fp2_sub(&t2, &t2, &t5); //sqrt(A^2-4C^2)*(9C^2-A^2) - (A^3-3AC^2)
fp2_inv(&t1); //1/2C^2*sqrt(A^2-4C^2)
fp2_mul(&t0, &t0, &t1); // First solution
fp2_mul(&t2, &t2, &t1); // Second solution
fp2_mul(&t1, &t3, &t1); // Original solution
// Chose the lexicographically first solution
if(fp2_cmp(&t0, &t1)==1)
fp2_copy(&t0, &t1);
if(fp2_cmp(&t0, &t2)==1)
fp2_copy(&t0, &t2);
// Copy the solution
fp2_sqrt(&t0);
ec_curve_t E;
fp2_copy(&E.A, &t0);
fp_mont_setone(E.C.re);
fp_set(E.C.im, 0);
ec_isomorphism(isom, old, &E);
fp2_copy(&new->A, &E.A);
fp2_copy(&new->C, &E.C);
}
void ec_isomorphism(ec_isom_t* isom, const ec_curve_t* from, const ec_curve_t* to){
fp2_t t0, t1, t2, t3, t4;
fp2_mul(&t0, &from->A, &to->C);
fp2_sqr(&t0, &t0); //fromA^2toC^2
fp2_mul(&t1, &to->A, &from->C);
fp2_sqr(&t1, &t1); //toA^2fromC^2
fp2_mul(&t2, &to->C, &from->C);
fp2_sqr(&t2, &t2); //toC^2fromC^2
fp2_add(&t3, &t2, &t2);
fp2_add(&t2, &t3, &t2); //3toC^2fromC^2
fp2_sub(&t3, &t2, &t0); //3toC^2fromC^2-fromA^2toC^2
fp2_sub(&t4, &t2, &t1); //3toC^2fromC^2-toA^2fromC^2
fp2_inv(&t3);
fp2_mul(&t4, &t4, &t3);
fp2_sqrt(&t4); //lambda^2 constant for SW isomorphism
fp2_sqr(&t3, &t4);
fp2_mul(&t3, &t3, &t4); //lambda^6
// Check sign of lambda^2, such that lambda^6 has the right sign
fp2_sqr(&t0, &from->C);
fp2_add(&t1, &t0, &t0);
fp2_add(&t1, &t1, &t1);
fp2_add(&t1, &t1, &t1);
fp2_add(&t0, &t0, &t1); // 9fromC^2
fp2_sqr(&t2, &from->A);
fp2_add(&t2, &t2, &t2); // 2fromA^2
fp2_sub(&t2, &t2, &t0);
fp2_mul(&t2, &t2, &from->A); // -9fromC^2fromA+2fromA^3
fp2_sqr(&t0, &to->C);
fp2_mul(&t0, &t0, &to->C);
fp2_mul(&t2, &t2, &t0); //toC^3* [-9fromC^2fromA+2fromA^3]
fp2_mul(&t3, &t3, &t2); //lambda^6*(-9fromA+2fromA^3)*toC^3
fp2_sqr(&t0, &to->C);
fp2_add(&t1, &t0, &t0);
fp2_add(&t1, &t1, &t1);
fp2_add(&t1, &t1, &t1);
fp2_add(&t0, &t0, &t1); // 9toC^2
fp2_sqr(&t2, &to->A);
fp2_add(&t2, &t2, &t2); // 2toA^2
fp2_sub(&t2, &t2, &t0);
fp2_mul(&t2, &t2, &to->A); // -9toC^2toA+2toA^3
fp2_sqr(&t0, &from->C);
fp2_mul(&t0, &t0, &from->C);
fp2_mul(&t2, &t2, &t0); //fromC^3* [-9toC^2toA+2toA^3]
if(!fp2_is_equal(&t2, &t3))
fp2_neg(&t4, &t4);
// Mont -> SW -> SW -> Mont
fp_mont_setone(t0.re);
fp_set(t0.im, 0);
fp2_add(&isom->D, &t0, &t0);
fp2_add(&isom->D, &isom->D, &t0);
fp2_mul(&isom->D, &isom->D, &from->C);
fp2_mul(&isom->D, &isom->D, &to->C);
fp2_mul(&isom->Nx, &isom->D, &t4);
fp2_mul(&t4, &t4, &from->A);
fp2_mul(&t4, &t4, &to->C);
fp2_mul(&t0, &to->A, &from->C);
fp2_sub(&isom->Nz, &t0, &t4);
}
void ec_iso_inv(ec_isom_t* isom){
fp2_t tmp;
fp2_copy(&tmp, &isom->D);
fp2_copy(&isom->D, &isom->Nx);
fp2_copy(&isom->Nx, &tmp);
fp2_neg(&isom->Nz, &isom->Nz);
}
void ec_iso_eval(ec_point_t *P, ec_isom_t* isom){
fp2_t tmp;
fp2_mul(&P->x, &P->x, &isom->Nx);
fp2_mul(&tmp, &P->z, &isom->Nz);
fp2_sub(&P->x, &P->x, &tmp);
fp2_mul(&P->z, &P->z, &isom->D);
}

228
src/ec/ref/ecx/kps.c Normal file
View File

@@ -0,0 +1,228 @@
#include "isog.h"
#include "curve_extras.h"
#include <assert.h>
int sI, sJ, sK; // Sizes of each current I, J, and K
fp2_t I[sI_max][2], // I plays also as the linear factors of the polynomial h_I(X)
EJ_0[sJ_max][3], EJ_1[sJ_max][3]; // To be used in xisog y xeval
ec_point_t J[sJ_max], K[sK_max]; // Finite subsets of the kernel
fp2_t XZJ4[sJ_max], // -4* (Xj * Zj) for each j in J, and x([j]P) = (Xj : Zj)
rtree_A[(1 << (ceil_log_sI_max+2)) - 1], // constant multiple of the reciprocal tree computation
A0; // constant multiple of the reciprocal R0
poly ptree_hI[(1 << (ceil_log_sI_max+2)) - 1], // product tree of h_I(X)
rtree_hI[(1 << (ceil_log_sI_max+2)) - 1], // reciprocal tree of h_I(X)
ptree_EJ[(1 << (ceil_log_sJ_max+2)) - 1]; // product tree of E_J(X)
fp2_t R0[2*sJ_max + 1]; // Reciprocal of h_I(X) required in the scaled remainder tree approach
int deg_ptree_hI[(1 << (ceil_log_sI_max+2)) - 1], // degree of each noed in the product tree of h_I(X)
deg_ptree_EJ[(1 << (ceil_log_sJ_max+2)) - 1]; // degree of each node in the product tree of E_J(X)
fp2_t leaves[sI_max]; // leaves of the remainder tree, which are required in the Resultant computation
// -----------------------------------------------------------
// -----------------------------------------------------------
// Traditional Kernel Point computation (KPs)
// Kernel computation required in tye degree-4 isogeny evaluation
void kps_4(ec_point_t const P)
{
fp2_sub(&K[1].x, &P.x, &P.z);
fp2_add(&K[2].x, &P.x, &P.z);
fp2_sqr(&K[0].x, &P.z);
fp2_add(&K[0].z, &K[0].x, &K[0].x);
fp2_add(&K[0].x, &K[0].z, &K[0].z);
}
void eds2mont(ec_point_t* P)
{
fp2_t t;
fp2_add(&t, &(P->z), &(P->x));
fp2_sub(&(P->z), &(P->z), &(P->x));
fp2_copy(&(P->x), &t);
}
// Differential doubling in Twisted Edwards model
void ydbl(ec_point_t* Q, ec_point_t* const P, ec_point_t const* A)
{
fp2_t t_0, t_1, X, Z;
fp2_sqr(&t_0, &(P->x));
fp2_sqr(&t_1, &(P->z));
fp2_mul(&Z, &(A->z), &t_0);
fp2_mul(&X, &Z, &t_1);
fp2_sub(&t_1, &t_1, &t_0);
fp2_mul(&t_0, &(A->x), &t_1);
fp2_add(&Z, &Z, &t_0);
fp2_mul(&Z, &Z, &t_1);
fp2_sub(&(Q->x), &X, &Z);
fp2_add(&(Q->z), &X, &Z);
}
// Differential addition in Twisted Edwards model
void yadd(ec_point_t* R, ec_point_t* const P, ec_point_t* const Q, ec_point_t* const PQ)
{
fp2_t a, b, c, d, X, Z;
fp2_mul(&a, &(P->z), &(Q->x));
fp2_mul(&b, &(P->x), &(Q->z));
fp2_add(&c, &a, &b);
fp2_sub(&d, &a, &b);
fp2_sqr(&c, &c);
fp2_sqr(&d, &d);
fp2_add(&a, &(PQ->z), &(PQ->x));
fp2_sub(&b, &(PQ->z), &(PQ->x));
fp2_mul(&X, &b, &c);
fp2_mul(&Z, &a, &d);
fp2_sub(&(R->x), &X, &Z);
fp2_add(&(R->z), &X, &Z);
}
// tvelu formulae
void kps_t(uint64_t const i, ec_point_t const P, ec_point_t const A)
{
int j;
int d = ((int)TORSION_ODD_PRIMES[i] - 1) / 2;
// Mapping the input point x(P), which belongs to a
// Montogmery curve model, into its Twisted Edwards
// representation y(P)
fp2_sub(&K[0].x, &P.x, &P.z);
fp2_add(&K[0].z, &P.x, &P.z);
ydbl(&K[1], &K[0], &A); // y([2]P)
for (j = 2; j < d; j++)
yadd(&K[j], &K[j - 1], &K[0], &K[j - 2]); // y([j+1]P)
}
// -----------------------------------------------------------
// -----------------------------------------------------------
// Kernel Point computation (KPs) used in velu SQRT
void kps_s(uint64_t const i, ec_point_t const P, ec_point_t const A)
{
// =================================================================================
assert(TORSION_ODD_PRIMES[i] > gap); // Ensuring velusqrt is used for l_i > gap
// The optimal bounds must corresponds to sI, sJ, and sK
sI = sizeI[i]; // Size of I
sJ = sizeJ[i]; // Size of J
sK = sizeK[i]; // Size of K
assert(sI >= sJ); // Ensuring #I >= #J
assert(sK >= 0); // Recall, it must be that #K >= 0
assert(sJ > 1); // ensuring sI >= sJ > 1
// =================================================================================
// Now, we can proceed by the general case
int j;
// --------------------------------------------------
// Computing [j]P for each j in {1, 3, ..., 2*sJ - 1}
ec_point_t P2, P4;
copy_point(&J[0], &P); // x(P)
// Next computations are required for allowing the use of the function get_A()
fp2_mul(&XZJ4[0], &J[0].x, &J[0].z); // Xj*Zj
fp2_add(&XZJ4[0], &XZJ4[0], &XZJ4[0]); // 2Xj*Zj
fp2_add(&XZJ4[0], &XZJ4[0], &XZJ4[0]); // 4Xj*Zj
fp2_neg(&XZJ4[0], &XZJ4[0]); // -4Xj*Zj
xDBLv2(&P2, &P, &A); // x([2]P)
xADD(&J[1], &P2, &J[0], &J[0]); // x([3]P)
// Next computations are required for allowing the use of the function get_A()
fp2_mul(&XZJ4[1], &J[1].x, &J[1].z); // Xj*Zj
fp2_add(&XZJ4[1], &XZJ4[1], &XZJ4[1]); // 2Xj*Zj
fp2_add(&XZJ4[1], &XZJ4[1], &XZJ4[1]); // 4Xj*Zj
fp2_neg(&XZJ4[1], &XZJ4[1]); // -4Xj*Zj
for (j = 2; j < sJ; j++)
{
xADD(&J[j], &J[j - 1], &P2, &J[j - 2]); // x([2*j + 1]P)
// Next computations are required for allowing the use of the function get_A()
fp2_mul(&XZJ4[j], &J[j].x, &J[j].z); // Xj*Zj
fp2_add(&XZJ4[j], &XZJ4[j], &XZJ4[j]); // 2Xj*Zj
fp2_add(&XZJ4[j], &XZJ4[j], &XZJ4[j]); // 4Xj*Zj
fp2_neg(&XZJ4[j], &XZJ4[j]); // -4Xj*Zj
};
// ----------------------------------------------------------
// Computing [i]P for i in { (2*sJ) * (2i + 1) : 0 <= i < sI}
// and the linear factors of h_I(W)
ec_point_t Q, Q2, tmp1, tmp2;
int bhalf_floor= sJ >> 1;
int bhalf_ceil = sJ - bhalf_floor;
xDBLv2(&P4, &P2, &A); // x([4]P)
swap_points(&P2, &P4, -(uint64_t)(sJ % 2)); // x([4]P) <--- coditional swap ---> x([2]P)
xADD(&Q, &J[bhalf_ceil], &J[bhalf_floor - 1], &P2); // Q := [2b]P
swap_points(&P2, &P4, -(uint64_t)(sJ % 2)); // x([4]P) <--- coditional swap ---> x([2]P)
// .............................................
xDBLv2(&Q2, &Q, &A); // x([2]Q)
xADD(&tmp1, &Q2, &Q, &Q); // x([3]Q)
fp2_neg(&I[0][0], &Q.x);
fp2_copy(&I[0][1], &Q.z);
fp2_neg(&I[1][0], &tmp1.x);
fp2_copy(&I[1][1], &tmp1.z);
copy_point(&tmp2, &Q);
for (j = 2; j < sI; j++){
xADD(&tmp2, &tmp1, &Q2, &tmp2); // x([2*j + 1]Q)
fp2_neg(&I[j][0], &tmp2.x);
fp2_copy(&I[j][1], &tmp2.z);
swap_points(&tmp1, &tmp2, -(uint64_t)1);
}
// ----------------------------------------------------------------
// Computing [k]P for k in { 4*sJ*sI + 1, ..., l - 6, l - 4, l - 2}
// In order to avoid BRANCHES we make allways copy in K[0] and K[1]
// by assuming that these entries are only used when sK >= 1 and
// sK >= 2, respectively.
//if (sK >= 1)
copy_point(&K[0], &P2); // x([l - 2]P) = x([2]P)
//if (sK >= 2)
copy_point(&K[1], &P4); // x([l - 4]P) = x([4]P)
for (j = 2; j < sK; j++)
xADD(&K[j], &K[j - 1], &P2, &K[j - 2]); // x([l - 2*(j+1)]P) = x([2 * (j+1)]P)
// ----------------------------------------------------------------
// ~~~~~~~~ ~~~~~~~~
// | | | |
// Computing h_I(W) = | | (W - x([i]P)) = | | (Zi * W - Xi) / Zi where x([i]P) = Xi/Zi
// i in I i in I
// In order to avoid costly inverse computations in fp, we are gonna work with projective coordinates
product_tree_LENFeq2(ptree_hI, deg_ptree_hI, 0, I, sI); // Product tree of hI
if (!scaled)
{
// (unscaled) remainder tree approach
reciprocal_tree(rtree_hI, rtree_A, 2*sJ + 1, ptree_hI, deg_ptree_hI, 0, sI); // Reciprocal tree of hI
}
else
{
// scaled remainder tree approach
fp2_t f_rev[sI_max + 1];
for (j = 0; j < (sI + 1); j++)
fp2_copy(&f_rev[j], &ptree_hI[0][sI - j]);
if (sI > (2*sJ - sI + 1))
reciprocal(R0, &A0, f_rev, sI + 1, sI);
else
reciprocal(R0, &A0, f_rev, sI + 1, 2*sJ - sI + 1);
};
}
void kps_clear(int i){
if (TORSION_ODD_PRIMES[i] > gap)
{
if (!scaled)
clear_tree(rtree_hI, 0, sizeI[i]);
clear_tree(ptree_hI, 0, sizeI[i]);
}
}

1025
src/ec/ref/ecx/poly-mul.c Normal file

File diff suppressed because it is too large Load Diff

349
src/ec/ref/ecx/poly-redc.c Normal file
View File

@@ -0,0 +1,349 @@
#define _POLY_MUL_REDC_H_
#include "poly.h"
#include <assert.h>
void reciprocal(poly h, fp2_t *c, const poly f, const int lenf, const int n){
// Writes a polynomial to h and a field element to c such that f*h = c mod x^n
// REQUIRES h to have space for n terms
// NOT responsible for terms in h beyond h[n-1]
int i;
// Case when f needs to be padded with zeroes
if(n > lenf)
{
fp2_t fpad[n];
for(i = 0; i < lenf; i++)
fp2_copy(&fpad[i], &f[i]);
for(i = lenf; i < n; i++)
fp2_set(&fpad[i], 0);
reciprocal(h, c, fpad, n, n);
return;
}
// Trivial case
if(n == 0)
{
fp2_set(&*c, 0);
return;
}
// Case n = 1
if(n == 1)
{
fp2_copy(&*c, &f[0]);
fp_mont_setone(h[0].re);fp_set(h[0].im,0);
return;
}
// Case n = 2
if(n == 2)
{
fp2_sqr(&*c, &f[0]);
fp2_copy(&h[0], &f[0]);
fp2_neg(&h[1], &f[1]);
return;
}
// Case n = 3
if(n == 3)
{
fp2_t t0, t1;
fp2_sqr(&t0, &f[1]);
fp2_mul(&t1, &f[0], &f[2]);
fp2_sub(&t1, &t1, &t0);
fp2_mul(&t1, &t1, &f[0]);
reciprocal(h, c, f, 2, 2);
fp2_mul(&h[0], &h[0], &*c);
fp2_mul(&h[1], &h[1], &*c);
fp2_neg(&h[2], &t1);
fp2_sqr(&*c, &*c);
return;
}
// Case n = 4
if(n == 4)
{
fp2_t t0, t1, t2, t3, g[2];
reciprocal(g, &t3, f, 2, 2);
fp2_sqr(&t0, &f[1]);
fp2_mul(&t1, &g[0], &f[2]);
fp2_mul(&t2, &g[0], &f[3]);
fp2_mul(&h[1], &g[1], &f[2]);
fp2_sub(&t0, &t1, &t0);
fp2_add(&t1, &t2, &h[1]);
fp2_mul(&t2, &t0, &g[0]);
fp2_mul(&h[1], &t0, &g[1]);
fp2_mul(&h[3], &t1, &g[0]);
fp2_add(&h[3], &h[1], &h[3]);
fp2_mul(&h[0], &g[0], &t3);
fp2_mul(&h[1], &g[1], &t3);
fp2_neg(&h[2], &t2);
fp2_neg(&h[3], &h[3]);
fp2_sqr(&*c, &t3);
return;
}
// General case
// Compute the reciprocal g mod x^m for m = ceil(n/2)
// Then f*g-c is multiple of x^m so we only care about terms from m to n-1
const int m = n - (n>>1);
fp2_t g[m], t[m], t0;
reciprocal(g, &t0, f, lenf, m);
poly_mul_middle(t, g, m, f, n);
poly_mul_low(t, n-m, g, m, &(t[2*m-n]), n-m);
for(i = 0; i < m; i++)
fp2_mul(&h[i], &g[i], &t0);
for(i = m; i < n; i++)
fp2_neg(&h[i], &t[i-m]);
fp2_sqr(&*c, &t0);
return;
}
void poly_redc(poly h, const poly g, const int leng, const poly f, const int lenf,//
const poly f_rev_inv, const fp2_t c)
{
// Computes h(x) = a * g(x) mod f(x) for some scalar a, writting lenf-1 terms to h.
// REQUIRES an inverse f_rev_inv such that f_rev*f_rev_inv = c mod x^(leng-lenf+1),
// where f_rev is the polynomial with the coefficients of f listed in reverse order.
// The scalar a is equal to c, except for special cases:
// - If leng<lenf (no reduction needed) then a = 1
// - If lenf = leng = 2, then a = f[1]
// - If lenf = leng = 3, then a = f[2]
// - If lenf=2, leng=3 then a = 2*f[1]^2
//
// REQUIRES h to have space for lenf-1 terms
// NOT responsible for terms in h beyond h[lenf-2]
int i;
// Case without reduction
if(leng < lenf)
{
for(i = 0; i < leng; i++)
fp2_copy(&h[i], &g[i]);
for(i = leng; i < lenf-1; i++)
fp2_set(&h[i], 0);
return;
}
// Small cases for f linear
if(lenf == 2)
{
if(leng == 2)
{
fp2_t t0;
fp2_mul(&t0, &g[0], &f[1]);
fp2_mul(&h[0], &g[1], &f[0]);
fp2_sub(&h[0], &t0, &h[0]);
return;
}
if(leng == 3)
{
fp2_t f0f1, f02, f12;
fp2_sqr(&f02, &f[0]);
fp2_sqr(&f12, &f[1]);
fp2_sub(&f0f1, &f[0], &f[1]);
fp2_sqr(&f0f1, &f0f1);
fp2_sub(&f0f1, &f0f1, &f02);
fp2_sub(&f0f1, &f0f1, &f12);
fp2_add(&f02, &f02, &f02);
fp2_add(&f12, &f12, &f12);
fp2_mul(&f02, &f02, &g[2]);
fp2_mul(&f12, &f12, &g[0]);
fp2_mul(&f0f1, &f0f1, &g[1]);
fp2_add(&h[0], &f02, &f12);
fp2_add(&h[0], &h[0], &f0f1);
return;
}
}
// Small case for f cuadratic
if(lenf == 3 && leng == 3)
{
fp2_t f2g1, f2g0, f1g2;
fp2_mul(&f2g1, &g[1], &f[2]);
fp2_mul(&f2g0, &g[0], &f[2]);
fp2_mul(&f1g2, &g[2], &f[1]);
fp2_mul(&h[0], &g[2], &f[0]);
fp2_sub(&h[0], &f2g0, &h[0]);
fp2_sub(&h[1], &f2g1, &f1g2);
return;
}
// General case
fp2_t g_reversed[leng], Q[leng - lenf + 1], Q_reversed[leng - lenf + 1];
for(i = 0; i < leng; i++)
fp2_copy(&g_reversed[i], &g[leng-1-i]);
poly_mul_low(Q, leng-lenf+1, f_rev_inv, leng-lenf+1, g_reversed, leng-lenf+1);
for(i = 0; i < leng - lenf + 1; i++)
fp2_copy(&Q_reversed[i], &Q[leng - lenf - i]);
poly_mul_low(g_reversed, lenf-1, Q_reversed, leng-lenf+1, f, lenf);
for(i = 0; i < lenf-1; i++)
{
fp2_mul(&h[i], &g[i], &c);
fp2_sub(&h[i], &h[i], &g_reversed[i]);
}
return;
}
void reciprocal_tree(poly *R, fp2_t *A, const int leng, const poly H[], const int DEG[],//
const int root, const int n)
{
// Given a product tree H with degrees tree DEG rooted at root and generated
// by n polynomials, writes the reverse-reciprocal polynomials to R and field elements
// to A such that Rev(H[i])*R[i] = A[i] mod x^(N) for all nodes but the leaves.
// The mod is N = deg(parent)-deg(self) for inner nodes, or N = leng - deg(root) for the root.
//
// REQUIRES that leng >= DEG[0] and that R,A have enough space for the tree (see product_tree)
if(n == 0)
return;
const int parent = (root-1) >> 1;
const int brother = root - 1 + 2*(root & 1);
int lenr;
if(root > 0)
lenr = DEG[parent] - DEG[root];
else
lenr = leng - DEG[root];
R[root] = malloc(sizeof(fp2_t)*lenr);
// ----------------------------------
// base cases determined by poly_redc
if(n == 1)
return;
// case for computing g mod f when len(f), len(g) = 3
if (DEG[root] == 2 && lenr == 1)
{
reciprocal_tree(R, A, lenr-1, H, DEG, 2*root+1, n-(n>>1));
reciprocal_tree(R, A, lenr-1, H, DEG, 2*root+2, n>>1);
return;
}
// ----------------------------------
int i;
// When the parent's inverse was calculated to a smaller modulus, need to invert from scratch
if(root == 0 || leng < lenr)
{
for(i = 0; i < lenr && i < DEG[root]+1; i++)
fp2_copy(&R[root][i], &H[root][DEG[root]-i]);
for(i = DEG[root]+1; i < lenr; i++){
fp2_set(&R[root][i], 0);
}
reciprocal(R[root], &(A[root]), R[root], lenr, lenr);
}
else
{
// When parent's inverse was to a greater/equal modulus, this inverse can be obtained from it
for(i = 0; i < lenr; i++)
fp2_copy(&R[root][i], &H[brother][DEG[brother]-i]);
poly_mul_low(R[root], lenr, R[parent], leng, R[root], lenr);
fp2_copy(&A[root], &A[parent]);
}
// Now move on to the children
reciprocal_tree(R, A, lenr-1, H, DEG, 2*root+1, n-(n>>1));
reciprocal_tree(R, A, lenr-1, H, DEG, 2*root+2, n>>1);
return;
}
void multieval_unscaled(fp2_t REM[], const poly g, const int leng, const poly R[], const fp2_t A[],//
const poly H[], const int DEG[], const int root, const int n)
{
// Given the product tree H and reciprocal tree R,A generated by f_0, ... , f_{n-1},
// with corresponding degrees tree DEG[] and rooted at root, writes the constant term
// of c_i*g mod f_i to REM[i]. The constants c_i are unspecified, but are a function
// only of leng and f_0,...,f_{n-1} so they cancel out when taking the ratios of
// remainders of different g's of the same length.
//
// REQUIRES REM to have space for n terms
if(n == 0)
return;
fp2_t g_mod[DEG[root]];
poly_redc(g_mod, g, leng, H[root], DEG[root]+1, R[root], A[root]);
if(n == 1)
{
fp2_copy(&REM[0], &g_mod[0]);
return;
}
multieval_unscaled(REM, g_mod, DEG[root], R, A, H, DEG, 2*root+1, n-(n>>1));
multieval_unscaled(&(REM[n-(n>>1)]), g_mod, DEG[root], R, A, H, DEG, 2*root+2, n>>1);
return;
}
void multieval_scaled(fp2_t REM[], const poly G, const poly H[], //
const int DEG[], const int root, const int n)
{
// Given the product tree H generated by LINEAR f_0,...,f_{n-1} rooted at root and with
// corresponding degrees tree DEG, writes the constant term of c_i * g mod f_i(x) to REM[i]
// The constants c_i are unspecified but are only a function of leng and f_0,...,f_{n-1},
// so they cancel out when taking the ratios of remainders of different g's of the same length.
//
// REQUIRES REM to have space for n terms and n > 1
// Also REQUIRES G = rev((rev(g mod F)) * F_rev_inv mod x^deg(F)-1) where F = H[root]
// and F_rev_inv is its reverse's reciprocal mod x^deg(F)
if(root == 0)
{
if(n == 1)
{
fp2_copy(&REM[0], &G[DEG[root]-1]);
return;
}
else
{
multieval_scaled(REM, G, H, DEG, 2*root+1, n-(n>>1));
multieval_scaled(&(REM[n-(n>>1)]), G, H, DEG, 2*root+2, n>>1);
return;
}
}
const int parent = (root-1) >> 1;
const int brother = root - 1 + 2*(root & 1);
const int uncle = parent - 1 + 2*(parent & 1);
fp2_t fg[DEG[brother]+1];
if(root > 2)
poly_mul_middle(fg, H[brother], DEG[brother]+1, G, DEG[uncle]+1);
else
poly_mul_middle(fg, H[brother], DEG[brother]+1, G, DEG[0]);
if(n == 1)
{
fp2_copy(&REM[0], &fg[DEG[brother]]);
return;
}
multieval_scaled(REM, fg, H, DEG, 2*root+1, n-(n>>1));
multieval_scaled(&(REM[n-(n>>1)]), fg, H, DEG, 2*root+2, n>>1);
return;
}

231
src/ec/ref/ecx/tedwards.c Executable file
View File

@@ -0,0 +1,231 @@
#include <tedwards.h>
#include <assert.h>
// a*x^2+y^2=1+d*x^2*y^2
// a = A.x/A.z + 2, d = A.x/A.z - 2
void ted_init(ted_point_t* P)
{ // Initialize point as identity element (X:Y:Z:T) <- (0:1:1:0)
fp_t one = {0};
memset((digit_t*)P, 0, NWORDS_FIELD*RADIX*8/8);
one[0] = 1;
fp_tomont(P->x.re, one);
}
void copy_ted_point(ted_point_t* P, ted_point_t const* Q)
{
fp2_copy(&(P->x), &(Q->x));
fp2_copy(&(P->y), &(Q->y));
fp2_copy(&(P->z), &(Q->z));
fp2_copy(&(P->t), &(Q->t));
}
void ted_dbl(ted_point_t *Q, ted_point_t const *P, ec_curve_t const* E)
{
// A = X1^2
// B = Y1^2
// C = 2*Z1^2
// D = a*A
// K = (X1+Y1)^2-A-B
// G = D+B
// F = G-C
// H = D-B
// X3 = K*F
// Y3 = G*H
// T3 = K*H
// Z3 = F*G
// TODO: neutral element
fp2_t A, B, C, D, K, G, F, H;
fp2_sqr(&A, &P->x);
fp2_sqr(&B, &P->y);
fp2_sqr(&C, &P->z);
fp2_add(&C, &C, &C);
fp2_mul(&D, &A, &E->A);
fp2_add(&K, &P->x, &P->y);
fp2_sqr(&K, &K);
fp2_sub(&K, &K, &A);
fp2_sub(&K, &K, &B);
fp2_add(&G, &D, &B);
fp2_sub(&F, &G, &C);
fp2_sub(&H, &D, &B);
fp2_mul(&Q->x, &K, &F);
fp2_mul(&Q->y, &G, &H);
fp2_mul(&Q->t, &K, &H);
fp2_mul(&Q->z, &F, &G);
}
void ted_add(ted_point_t* S, ted_point_t const* P, ted_point_t const* Q, ec_curve_t const* E)
{
// A = X1*X2
// B = Y1*Y2
// C = Z1*T2
// D = T1*Z2
// K = D+C
// F = (X1-Y1)*(X2+Y2)+B-A
// G = B+a*A
// H = D-C
// X3 = K*F
// Y3 = G*H
// T3 = K*H
// Z3 = F*G
// TODO: neutral element
ted_point_t res;
if (is_ted_equal(P, Q)) {
ted_dbl(S, P, E);
return;
}
//assert(!is_ted_equal(P, Q));
ted_neg(&res, P);
if (is_ted_equal(&res, Q)) {
ted_init(S);
return;
}
// assert(!ted_equal(&res,Q));
fp2_t A, B, C, D, K, F, G, H, tmp;
fp2_mul(&A, &P->x, &Q->x);
fp2_mul(&B, &P->y, &Q->y);
fp2_mul(&C, &P->z, &Q->t);
fp2_mul(&D, &P->t, &Q->z);
fp2_add(&K, &D, &C);
fp2_add(&F, &Q->x, &Q->y);
fp2_sub(&tmp, &P->x, &P->y);
fp2_mul(&F, &F, &tmp);
fp2_add(&F, &F, &B);
fp2_sub(&F, &F, &A);
fp2_mul(&G, &A, &E->A);
fp2_add(&G, &G, &B);
fp2_sub(&H, &D, &C);
fp2_mul(&res.x, &K, &F);
fp2_mul(&res.y, &G, &H);
fp2_mul(&res.t, &K, &H);
fp2_mul(&res.z, &F, &G);
if (fp2_is_zero(&res.x) && fp2_is_zero(&res.y) && fp2_is_zero(&res.z)) {
ted_dbl(S, P, E);
} else {
copy_ted_point(S, &res);
}
}
void ted_neg(ted_point_t* Q, ted_point_t const* P)
{
fp2_neg(&Q->x, &P->x);
fp2_copy(&Q->y, &P->y);
fp2_copy(&Q->z, &P->z);
fp2_neg(&Q->t, &P->t);
}
static bool xLIFT(fp2_t* y, const ec_point_t* P, const ec_curve_t* curve)
{ // Returns false if it is on the curve, true if it is on the twist
fp2_t z2, tmp1, tmp2, y2;
if (fp2_is_zero(&P->z)) return false;
// (X^2 + Z^2) C
fp2_sqr(&tmp1, &P->x);
fp2_sqr(&z2, &P->z);
fp2_add(&tmp1, &tmp1, &z2);
fp2_mul(&tmp1, &tmp1, &curve->C);
// X^2C + AXZ + Z^2C
fp2_mul(&tmp2, &P->x, &P->z);
fp2_mul(&tmp2, &tmp2, &curve->A);
fp2_add(&tmp1, &tmp1, &tmp2);
// X^3C + AX^2Z + XZ^2C = Z^3(Cx^3 + Ax^2 + Cx) = Z^3 C (B*y^2) = Z C (B*Y^2) // x = X/Z
fp2_mul(&tmp1, &tmp1, &P->x);
// (ZC)^(-1)
fp2_mul(&tmp2, &curve->C, &P->z);
assert(!fp2_is_zero(&tmp2));
fp2_inv(&tmp2);
fp2_mul(&y2, &tmp1, &tmp2); // (B*Y^2)
fp2_copy(y, &y2);
if (fp2_is_square(&y2)) { // on the curve
fp2_sqrt(y);
return false;
} else { // on the twist
fp2_t tmp = fp2_non_residue();
fp2_mul(y, y, &tmp);
fp2_sqrt(y);
return true;
}
}
//void mont_to_ted(ec_point_t* E, ec_point_t const* A, bool twist)
void mont_to_ted(ec_curve_t* ted_curve, ec_curve_t const* curve)
{
fp2_t tmp, two;
// A : y^2 = x^3 + (a/c)x^2 + x
fp2_copy(&tmp, &curve->C);
fp2_inv(&tmp); // 1/c
fp2_mul(&tmp, &tmp, &curve->A); // a/c
fp2_set(&two, 2);
fp2_tomont(&two, &two);
fp2_add(&ted_curve->A, &tmp, &two); // a/c + 2
fp2_sub(&ted_curve->C, &tmp, &two); // a/c - 2
//if (twist) {
// B = Fp2_inv(fp2_non_residue)
// tmp = fp2_non_residue();
// fp2_mul2(&E->x,&tmp);
// fp2_mul2(&E->z,&tmp);
//}
}
void mont_to_ted_point(ted_point_t* Q, ec_point_t const* P, ec_curve_t const* curve)
{
if (fp2_is_zero(&P->z)) {
fp2_set(&Q->x, 0);
fp2_set(&Q->y, 1);
fp2_set(&Q->z, 1);
fp2_set(&Q->t, 0);
fp_tomont(Q->y.re, Q->y.re);
fp_tomont(Q->z.re, Q->z.re);
} else {
fp2_t tmp, y;
xLIFT(&y, P, curve);
fp2_add(&tmp, &P->x, &P->z);
fp2_mul(&Q->x, &P->x, &tmp);
fp2_sub(&Q->y, &P->x, &P->z);
fp2_mul(&Q->y, &Q->y, &y);
fp2_mul(&Q->z, &tmp, &y);
fp2_copy(&Q->t, &Q->z);
fp2_inv(&Q->t);
fp2_mul(&Q->t, &Q->t, &Q->x);
fp2_mul(&Q->t, &Q->t, &Q->y);
}
}
void ted_to_mont_point(ec_point_t* Q, ted_point_t const* P)
{
fp2_add(&Q->x, &P->z, &P->y);
fp2_sub(&Q->z, &P->z, &P->y);
}
bool is_ted_equal(ted_point_t const* P1, ted_point_t const* P2)
{
fp2_t x1z2, y1z2;
fp2_t y2z1, x2z1;
fp2_t t1y2, t2y1;
fp2_mul(&x1z2, &P1->x, &P2->z);
fp2_mul(&y1z2, &P1->y, &P2->z);
fp2_mul(&y2z1, &P2->y, &P1->z);
fp2_mul(&x2z1, &P2->x, &P1->z);
fp2_mul(&t1y2, &P1->t, &P2->y);
fp2_mul(&t2y1, &P2->t, &P1->y);
return fp2_is_equal(&x1z2, &x2z1) && fp2_is_equal(&y1z2, &y2z1) && fp2_is_equal(&t1y2, &t2y1);
}

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

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

File diff suppressed because it is too large Load Diff

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

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

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

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

View 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

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

299
src/ec/ref/ecx/xeval.c Normal file
View File

@@ -0,0 +1,299 @@
#include "isog.h"
#include "ec.h"
#include <assert.h>
// -----------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------
// Traditional isogeny evaluation (xEVAL)
// CrissCross procedure as described in Hisil and Costello paper
void CrissCross(fp2_t *r0, fp2_t *r1, fp2_t const alpha, fp2_t const beta, fp2_t const gamma, fp2_t const delta)
{
fp2_t t_1, t_2;
fp2_mul(&t_1, &alpha, &delta);
fp2_mul(&t_2, &beta, &gamma);
fp2_add(&*r0, &t_1, &t_2);
fp2_sub(&*r1, &t_1, &t_2);
}
// Degree-2 isogeny evaluation with kenerl generated by P != (0, 0)
void xeval_2(ec_point_t* R, ec_point_t* const Q, const int lenQ)
{
fp2_t t0, t1, t2;
for(int j = 0; j < lenQ; j++){
fp2_add(&t0, &Q[j].x, &Q[j].z);
fp2_sub(&t1, &Q[j].x, &Q[j].z);
fp2_mul(&t2, &K[0].x, &t1);
fp2_mul(&t1, &K[0].z, &t0);
fp2_add(&t0, &t2, &t1);
fp2_sub(&t1, &t2, &t1);
fp2_mul(&R[j].x, &Q[j].x, &t0);
fp2_mul(&R[j].z, &Q[j].z, &t1);
}
}
// Degree-4 isogeny evaluation with kenerl generated by P such that [2]P != (0, 0)
void xeval_4(ec_point_t* R, const ec_point_t* Q, const int lenQ)
{
fp2_t t0, t1;
for(int i = 0; i < lenQ; i++){
fp2_add(&t0, &Q[i].x, &Q[i].z);
fp2_sub(&t1, &Q[i].x, &Q[i].z);
fp2_mul(&(R[i].x), &t0, &K[1].x);
fp2_mul(&(R[i].z), &t1, &K[2].x);
fp2_mul(&t0, &t0, &t1);
fp2_mul(&t0, &t0, &K[0].x);
fp2_add(&t1, &(R[i].x), &(R[i].z));
fp2_sub(&(R[i].z), &(R[i].x), &(R[i].z));
fp2_sqr(&t1, &t1);
fp2_sqr(&(R[i].z), &(R[i].z));
fp2_add(&(R[i].x), &t0, &t1);
fp2_sub(&t0, &t0, &(R[i].z));
fp2_mul(&(R[i].x), &(R[i].x), &t1);
fp2_mul(&(R[i].z), &(R[i].z), &t0);
}
}
// Degree-4 isogeny evaluation with kenerl generated by P such that [2]P = (0, 0)
// Must call after xisog_4_singular
void xeval_4_singular(ec_point_t* R, const ec_point_t* Q, const int lenQ, const ec_point_t P)
{
fp2_t t0, t1, t2;
for(int i = 0; i < lenQ; i++){
fp2_add(&t0, &Q[i].x, &Q[i].z);
fp2_sub(&t2, &Q[i].x, &Q[i].z);
fp2_sqr(&t0, &t0);
fp2_sqr(&t2, &t2);
fp2_sub(&R[i].z, &t0, &t2);
if(fp2_is_equal(&P.x, &P.z)){
// Branch for P = (+1,_)
fp2_copy(&t1, &t2);
}
else{
// Branch for P = (-1,_)
fp2_copy(&t1, &t0);
fp2_copy(&t0, &t2);
}
fp2_mul(&R[i].x, &R[i].z, &K[0].x);
fp2_mul(&R[i].z, &R[i].z, &K[1].x);
fp2_mul(&R[i].z, &R[i].z, &t1);
fp2_mul(&t1, &t1, &K[0].z);
fp2_add(&R[i].x, &R[i].x, &t1);
fp2_mul(&R[i].x, &R[i].x, &t0);
}
}
// Isogeny evaluation on Montgomery curves
// Recall: K has been computed in Twisted Edwards model and none extra additions are required.
void xeval_t(ec_point_t* Q, uint64_t const i, ec_point_t const P)
{
int j;
int d = ((int)TORSION_ODD_PRIMES[i] - 1) / 2; // Here, l = 2d + 1
fp2_t R0, R1, S0, S1, T0, T1;
fp2_add(&S0, &P.x, &P.z);
fp2_sub(&S1, &P.x, &P.z);
CrissCross(&R0, &R1, K[0].z, K[0].x, S0, S1);
for (j = 1; j < d; j++)
{
CrissCross(&T0, &T1, K[j].z, K[j].x, S0, S1);
fp2_mul(&R0, &T0, &R0);
fp2_mul(&R1, &T1, &R1);
};
fp2_sqr(&R0, &R0);
fp2_sqr(&R1, &R1);
fp2_mul(&(Q->x), &P.x, &R0);
fp2_mul(&(Q->z), &P.z, &R1);
}
// -----------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------
// Isogeny evaluation (xEVAL) used in velu SQRT
void xeval_s(ec_point_t* Q, uint64_t const i, ec_point_t const P, ec_point_t const A)
{
// =================================================================================
assert(TORSION_ODD_PRIMES[i] > gap); // Ensuring velusqrt is used for l_i > gap
sI = sizeI[i]; // size of I
sJ = sizeJ[i]; // size of J
sK = sizeK[i]; // size of K
assert(sI >= sJ); // Ensuring #I >= #J
assert(sK >= 0); // Recall, it must be that #K >= 0
assert(sJ > 1); // ensuring sI >= sJ > 1
// =================================================================================
// We require the curve coefficient A = A'/C ... well, a multiple of these ones
fp2_t Ap;
fp2_add(&Ap, &A.x, &A.x); // 2A' + 4C
fp2_sub(&Ap, &Ap, &A.z); // 2A'
fp2_add(&Ap, &Ap, &Ap); // 4A'
// --------------------------------------------------------------------------------------------------
// ~~~~~~~~
// | |
// Computing E_J(W) = | | [ F0(W, x([j]P)) * alpha^2 + F1(W, x([j]P)) * alpha + F2(W, x([j]P)) ]
// j in J
// In order to avoid costly inverse computations in fp, we are gonna work with projective coordinates
// In particular, for a degree-l isogeny construction, we need alpha = X/Z and alpha = Z/X (i.e., 1/alpha)
//fp2_t EJ_0[sJ][3]; // EJ_0[j][2] factors of one polynomial to be used in a resultant
fp2_t XZ_add, XZj_add,
XZ_sub, XZj_sub,
AXZ2,
CXZ2,
CX2Z2,
t1, t2;
fp2_add(&XZ_add, &P.x, &P.z); // X + Z
fp2_sub(&XZ_sub, &P.x, &P.z); // X - Z
fp2_mul(&AXZ2, &P.x, &P.z); // X * Z
fp2_sqr(&t1, &P.x); // X ^ 2
fp2_sqr(&t2, &P.z); // Z ^ 2
fp2_add(&CX2Z2, &t1, &t2); // X^2 + Z^2
fp2_mul(&CX2Z2, &CX2Z2, &A.z); // C * (X^2 + Z^2)
fp2_add(&AXZ2, &AXZ2, &AXZ2); // 2 * (X * Z)
fp2_mul(&CXZ2, &AXZ2, &A.z); // C * [2 * (X * Z)]
fp2_mul(&AXZ2, &AXZ2, &Ap); // A' * [2 * (X * Z)]
int j;
for (j = 0; j < sJ; j++)
{
fp2_add(&XZj_add, &J[j].x, &J[j].z); // Xj + Zj
fp2_sub(&XZj_sub, &J[j].x, &J[j].z); // Xj - Zj
fp2_mul(&t1, &XZ_sub, &XZj_add); // (X - Z) * (Xj + Zj)
fp2_mul(&t2, &XZ_add, &XZj_sub); // (X + Z) * (Xj - Zj)
// ...................................
// Computing the quadratic coefficient
fp2_sub(&EJ_0[j][2], &t1, &t2); // 2 * [(X*Zj) - (Z*Xj)]
fp2_sqr(&EJ_0[j][2], &EJ_0[j][2]); // ( 2 * [(X*Zj) - (Z*Xj)] )^2
fp2_mul(&EJ_0[j][2], &A.z, &EJ_0[j][2]); // C * ( 2 * [(X*Zj) - (Z*Xj)] )^2
// ..................................
// Computing the constant coefficient
fp2_add(&EJ_0[j][0], &t1, &t2); // 2 * [(X*Xj) - (Z*Zj)]
fp2_sqr(&EJ_0[j][0], &EJ_0[j][0]); // ( 2 * [(X*Xj) - (Z*Zj)] )^2
fp2_mul(&EJ_0[j][0], &A.z, &EJ_0[j][0]); // C * ( 2 * [(X*Xj) - (Z*Zj)] )^2
// ................................
// Computing the linear coefficient
// C * [ (-2*Xj*Zj)*(alpha^2 + 1) + (-2*alpha)*(Xj^2 + Zj^2)] + [A' * (-2*Xj*Zj) * (2*X*Z)] where alpha = X/Z
fp2_add(&t1, &J[j].x, &J[j].z); // (Xj + Zj)
fp2_sqr(&t1, &t1); // (Xj + Zj)^2
fp2_add(&t1, &t1, &t1); // 2 * (Xj + Zj)^2
fp2_add(&t1, &t1, &XZJ4[j]); // 2 * (Xj + Zj)^2 - (4*Xj*Zj) := 2 * (Xj^2 + Zj^2)
fp2_mul(&t1, &t1, &CXZ2); // [2 * (Xj^2 + Zj^2)] * (2 * [ C * (X * Z)])
fp2_mul(&t2, &CX2Z2, &XZJ4[j]); // [C * (X^2 + Z^2)] * (-4 * Xj * Zj)
fp2_sub(&t1, &t2, &t1); // [C * (X^2 + Z^2)] * (-4 * Xj * Zj) - [2 * (Xj^2 + Zj^2)] * (2 * [ C * (X * Z)])
fp2_mul(&t2, &AXZ2, &XZJ4[j]); // (2 * [A' * (X * Z)]) * (-4 * Xj * Zj)
fp2_add(&EJ_0[j][1], &t1, &t2); // This is our desired equation but multiplied by 2
fp2_add(&EJ_0[j][1], &EJ_0[j][1], &EJ_0[j][1]); // This is our desired equation but multiplied by 4
};
// ---------------------------------------------------------------------
// The faster way for multiplying is using a divide-and-conquer approach
// product tree of EJ_0 (we only require the root)
product_tree_LENFeq3(ptree_EJ, deg_ptree_EJ, 0, EJ_0, sJ);
assert( deg_ptree_EJ[0] == (2*sJ) );
if (!scaled)
{
// unscaled remainder tree approach
multieval_unscaled(leaves, ptree_EJ[0], 2*sJ + 1, rtree_hI, (const fp2_t*)rtree_A, ptree_hI, deg_ptree_hI, 0, sI);
}
else
{
// scaled remainder tree approach
fp2_t G[sI_max], G_rev[sI_max];
poly_redc(G, ptree_EJ[0], 2*sJ + 1, ptree_hI[0], sI + 1, R0, A0);
for (j = 0; j < sI; j++)
fp2_copy(&G_rev[j], &G[sI - 1 - j]);
poly_mul_middle(G_rev, G_rev, sI, R0, sI);
for (j = 0; j < sI; j++)
fp2_copy(&G[j], &G_rev[sI - 1 - j]);
multieval_scaled(leaves, G, ptree_hI, deg_ptree_hI, 0, sI);
};
// Finally, we must multiply the leaves of the outpur of remainders
fp2_t r0;
product(&r0, (const fp2_t*)leaves, sI);
// EJ_1 is just reverting the ordering in the coefficients of EJ_0
for (j = 0; j < sJ; j++){
fp2_copy(&t1, &ptree_EJ[0][j]);
fp2_copy(&ptree_EJ[0][j], &ptree_EJ[0][2*sJ - j]);
fp2_copy(&ptree_EJ[0][2*sJ - j], &t1);
}
if (!scaled)
{
// unscaled remainder tree approach
multieval_unscaled(leaves, ptree_EJ[0], 2*sJ + 1, rtree_hI, (const fp2_t*)rtree_A, ptree_hI, deg_ptree_hI, 0, sI);
}
else
{
// scaled remainder tree approach
fp2_t G[sI_max], G_rev[sI_max];
poly_redc(G, ptree_EJ[0], 2*sJ + 1, ptree_hI[0], sI + 1, R0, A0);
for (j = 0; j < sI; j++)
fp2_copy(&G_rev[j], &G[sI - 1 - j]);
poly_mul_middle(G_rev, G_rev, sI, R0, sI);
for (j = 0; j < sI; j++)
fp2_copy(&G[j], &G_rev[sI - 1 - j]);
multieval_scaled(leaves, G, ptree_hI, deg_ptree_hI, 0, sI);
};
clear_tree(ptree_EJ, 0, sJ);
// Finally, we must multiply the leaves of the outpur of remainders
fp2_t r1;
product(&r1, (const fp2_t*)leaves, sI);
// -------------------------------
// Sometimes the public value sK is equal to zero,
// Thus for avoing runtime error we add one when sK =0
fp2_t hK_0[sK_max + 1], hK_1[sK_max + 1], hk_0, hk_1;
for (j = 0; j < sK; j++)
{
fp2_add(&XZj_add, &K[j].x, &K[j].z); // Xk + Zk
fp2_sub(&XZj_sub, &K[j].x, &K[j].z); // Xk - Zk
fp2_mul(&t1, &XZ_sub, &XZj_add); // (X - Z) * (Xk + Zk)
fp2_mul(&t2, &XZ_add, &XZj_sub); // (X + Z) * (Xk - Zk)
// Case alpha = X/Z
fp2_sub(&hK_0[j], &t1, &t2); // 2 * [(X*Zk) - (Z*Xk)]
// Case 1/alpha = Z/X
fp2_add(&hK_1[j], &t1, &t2); // 2 * [(X*Xk) - (Z*Zk)]
};
// hk_0 <- use product to mulitiply all the elements in hK_0
product(&hk_0, (const fp2_t*)hK_0, sK);
// hk_1 <- use product to mulitiply all the elements in hK_1
product(&hk_1, (const fp2_t*)hK_1, sK);
// ---------------------------------------------------------------------------------
// Now, unifying all the computations
fp2_mul(&t1, &hk_1, &r1); // output of algorithm 2 with 1/alpha = Z/X and without the demoninator
fp2_sqr(&t1, &t1);
fp2_mul(&(Q->x), &t1, &P.x);
fp2_mul(&t2, &hk_0, &r0); // output of algorithm 2 with alpha = X/Z and without the demoninator
fp2_sqr(&t2, &t2);
fp2_mul(&(Q->z), &t2, &P.z);
}

295
src/ec/ref/ecx/xisog.c Normal file
View File

@@ -0,0 +1,295 @@
#include "isog.h"
#include "ec.h"
#include <assert.h>
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// Degree-2 isogeny with kernel generated by P != (0 ,0)
// Outputs the curve coefficient in the form A24=(A+2C:4C)
void xisog_2(ec_point_t* B, ec_point_t const P)
{
fp2_sqr(&B->x, &P.x);
fp2_sqr(&B->z, &P.z);
fp2_sub(&B->x, &B->z, &B->x);
fp2_add(&K[0].x, &P.x, &P.z);
fp2_sub(&K[0].z, &P.x, &P.z);
}
// Degree-4 isogeny with kernel generated by P such that [2]P != (0 ,0)
// Outputs the curve coefficient in the form A24=(A+2C:4C)
void xisog_4(ec_point_t* B, ec_point_t const P)
{
fp2_sqr(&K[0].x, &P.x);
fp2_sqr(&K[0].z, &P.z);
fp2_add(&K[1].x, &K[0].z, &K[0].x);
fp2_sub(&K[1].z, &K[0].z, &K[0].x);
fp2_mul(&B->x, &K[1].x, &K[1].z);
fp2_sqr(&B->z, &K[0].z);
// Constants for xeval_4
fp2_add(&K[2].x, &P.x, &P.z);
fp2_sub(&K[1].x, &P.x, &P.z);
fp2_add(&K[0].x, &K[0].z, &K[0].z);
fp2_add(&K[0].x, &K[0].x, &K[0].x);
}
// Degree-4 isogeny with kernel generated by P such that [2]P = (0 ,0)
void xisog_4_singular(ec_point_t* B24, ec_point_t const P, ec_point_t A24)
{
fp2_copy(&K[0].z, &A24.z);
if(fp2_is_equal(&P.x, &P.z)){
// Case for P=(1,_)
fp2_copy(&K[0].x, &A24.x);
fp2_sub(&K[1].x, &A24.x, &A24.z);
fp2_neg(&B24->z, &K[1].x);
}
else{
// Case for P=(-1,_)
fp2_copy(&K[1].x, &A24.x);
fp2_sub(&K[0].x, &A24.x, &A24.z);
fp2_neg(&B24->z, &K[0].x);
fp2_copy(&B24->z, &K[1].x);
}
fp2_copy(&B24->x, &K[0].z);
}
// xISOG procedure, which is a hybrid between Montgomery and Twisted Edwards
// This tradition fomulae corresponds with the Twisted Edwards formulae but
// mapping the output into Montgomery form
void xisog_t(ec_point_t* B, uint64_t const i, ec_point_t const A)
{
int j;
int d = ((int)TORSION_ODD_PRIMES[i] - 1) / 2; // Here, l = 2d + 1
fp2_t By, Bz, constant_d_edwards, tmp_a, tmp_d;
fp2_copy(&By, &K[0].x);
fp2_copy(&Bz, &K[0].z);
for (j = 1; j < d; j++)
{
fp2_mul(&By, &By, &K[j].x);
fp2_mul(&Bz, &Bz, &K[j].z);
};
// Mapping Montgomery curve coefficients into Twisted Edwards form
fp2_sub(&constant_d_edwards, &A.x, &A.z);
fp2_copy(&tmp_a, &A.x);
fp2_copy(&tmp_d, &constant_d_edwards);
// left-to-right method for computing a^l and d^l
for (j = 1; j < (int)p_plus_minus_bitlength[i]; j++)
{
fp2_sqr(&tmp_a, &tmp_a);
fp2_sqr(&tmp_d, &tmp_d);
if( ( ((int)TORSION_ODD_PRIMES[i] >> ((int)p_plus_minus_bitlength[i] - j - 1)) & 1 ) != 0 )
{
fp2_mul(&tmp_a, &tmp_a, &A.x);
fp2_mul(&tmp_d, &tmp_d, &constant_d_edwards);
};
};
// raising to 8-th power
for (j = 0; j < 3; j++)
{
fp2_sqr(&By, &By);
fp2_sqr(&Bz, &Bz);
};
// Mapping Twisted Edwards curve coefficients into Montgomery form
fp2_mul(&(B->x), &tmp_a, &Bz);
fp2_mul(&(B->z), &tmp_d, &By);
fp2_sub(&(B->z), &(B->x), &(B->z));
}
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// Isogeny construction (xISOG) used in velu SQRT
void xisog_s(ec_point_t* B, uint64_t const i, ec_point_t const A)
{
// =================================================================================
assert(TORSION_ODD_PRIMES[i] > gap); // Ensuring velusqrt is used for l_i > gap
sI = sizeI[i]; // size of I
sJ = sizeJ[i]; // size of J
sK = sizeK[i]; // size of K
assert(sI >= sJ); // Ensuring #I >= #J
assert(sK >= 0); // Recall, L is a prime and therefore it must be that #K > 0
assert(sJ > 1); // ensuring sI >= sJ > 1
// =================================================================================
// We require the curve coefficient A = A'/C ... well, a multiple of these ones
fp2_t Ap;
fp2_add(&Ap, &A.x, &A.x); // 2A' + 4C
fp2_sub(&Ap, &Ap, &A.z); // 2A'
fp2_add(&Ap, &Ap, &Ap); // 4A'
fp2_t ADD_SQUARED[sJ_max], // (Xj + Zj)^2
SUB_SQUARED[sJ_max]; // (Xj - Zj)^2
int j;
// Next loop precompute some variables to be used in the reaminder of xisog
for (j = 0; j < sJ; j++)
{
fp2_sub(&SUB_SQUARED[j], &J[j].x, &J[j].z); // (Xj - Zj)
fp2_sqr(&SUB_SQUARED[j], &SUB_SQUARED[j]); // (Xj - Zj)^2
fp2_sub(&ADD_SQUARED[j], &SUB_SQUARED[j], &XZJ4[j]); // (Xj + Zj)^2
};
// --------------------------------------------------------------------------------------------------
// ~~~~~~~~
// | |
// Computing E_J(W) = | | [ F0(W, x([j]P)) * alpha^2 + F1(W, x([j]P)) * alpha + F2(W, x([j]P)) ]
// j in J
// In order to avoid costly inverse computations in fp, we are gonna work with projective coordinates
// In particular, for a degree-l isogeny construction, we need alpha = 1 and alpha = -1
//fp2_t EJ_0[sJ][3], // quadratic factors of one polynomial to be used in a resultant
// EJ_1[sJ][3]; // quadratic factors of one polynomial to be used in a resultant
// Next loop computes all the quadratic factors of EJ_0 and EJ_1
fp2_t t1;
for (j = 0; j < sJ; j++)
{
// Each SUB_SQUARED[j] and ADD_SQUARED[j] should be multiplied by C
fp2_mul(&EJ_1[j][0], &ADD_SQUARED[j], &A.z);
fp2_mul(&EJ_0[j][0], &SUB_SQUARED[j], &A.z);
// We require the double of tadd and tsub
fp2_add(&EJ_0[j][1], &EJ_1[j][0], &EJ_1[j][0]);
fp2_add(&EJ_1[j][1], &EJ_0[j][0], &EJ_0[j][0]);
fp2_mul(&t1, &XZJ4[j], &Ap); // A' *(-4*Xj*Zj)
// Case alpha = 1
fp2_sub(&EJ_0[j][1], &t1, &EJ_0[j][1]);
fp2_copy(&EJ_0[j][2], &EJ_0[j][0]); // E_[0,j} is a palindrome
// Case alpha = -1
fp2_sub(&EJ_1[j][1], &EJ_1[j][1], &t1);
fp2_copy(&EJ_1[j][2], &EJ_1[j][0]); // E_{1,j} is a palindrome
};
// ---------------------------------------------------------------------
// The faster way for multiplying is using a divide-and-conquer approach
// selfreciprocal product tree of EJ_0 (we only require the root)
product_tree_selfreciprocal_LENFeq3(ptree_EJ, deg_ptree_EJ, 0, EJ_0, sJ);
assert( deg_ptree_EJ[0] == (2*sJ) );
if (!scaled)
{
// (unscaled) remainder tree approach
multieval_unscaled(leaves, ptree_EJ[0], 2*sJ + 1, rtree_hI, (const fp2_t*)rtree_A, ptree_hI, deg_ptree_hI, 0, sI);
}
else
{
// scaled remainder tree approach
fp2_t G[sI_max], G_rev[sI_max];
poly_redc(G, ptree_EJ[0], 2*sJ + 1, ptree_hI[0], sI + 1, R0, A0);
for (j = 0; j < sI; j++)
fp2_copy(&G_rev[j], &G[sI - 1 - j]);
poly_mul_middle(G_rev, G_rev, sI, R0, sI);
for (j = 0; j < sI; j++)
fp2_copy(&G[j], &G_rev[sI - 1 - j]);
multieval_scaled(leaves, G, ptree_hI, deg_ptree_hI, 0, sI);
};
clear_tree(ptree_EJ, 0, sJ);
// Finally, we must multiply the leaves of the outpur of remainders
fp2_t r0;
product(&r0, (const fp2_t*)leaves, sI);
// selfreciprocal product tree of EJ_1 (we only require the root)
product_tree_selfreciprocal_LENFeq3(ptree_EJ, deg_ptree_EJ, 0, EJ_1, sJ);
assert( deg_ptree_EJ[0] == (2*sJ) );
if (!scaled)
{
// (unscaled) remainder tree approach
multieval_unscaled(leaves, ptree_EJ[0], 2*sJ + 1, rtree_hI, (const fp2_t*)rtree_A, ptree_hI, deg_ptree_hI, 0, sI);
}
else
{
// scaled remainder tree approach
fp2_t G[sI_max], G_rev[sI_max];
poly_redc(G, ptree_EJ[0], 2*sJ + 1, ptree_hI[0], sI + 1, R0, A0);
for (j = 0; j < sI; j++)
fp2_copy(&G_rev[j], &G[sI - 1 - j]);
poly_mul_middle(G_rev, G_rev, sI, R0, sI);
for (j = 0; j < sI; j++)
fp2_copy(&G[j], &G_rev[sI - 1 - j]);
multieval_scaled(leaves, G, ptree_hI, deg_ptree_hI, 0, sI);
};
clear_tree(ptree_EJ, 0, sJ);
// Finally, we must multiply the leaves of the outpur of remainders
fp2_t r1;
product(&r1, (const fp2_t*)leaves, sI);
// -------------------------------
// Sometimes the public value sK is equal to zero,
// Thus for avoing runtime error we add one when sK =0
fp2_t hK_0[sK_max + 1], hK_1[sK_max + 1], hk_0, hk_1;
for (j = 0; j < sK; j++)
{
fp2_sub(&hK_0[j], &K[j].z, &K[j].x);
fp2_add(&hK_1[j], &K[j].z, &K[j].x);
};
// hk_0 <- use product to mulitiply all the elements in hK_0
product(&hk_0, (const fp2_t*)hK_0, sK);
// hk_1 <- use product to mulitiply all the elements in hK_1
product(&hk_1, (const fp2_t*)hK_1, sK);
// --------------------------------------------------------------
// Now, we have all the ingredients for computing the image curve
fp2_t A24, A24m,
t24, t24m; // <---- JORGE creo que podemos omitir estas variables, se usan cuando ya no se requiren los valores de la entrada A (podemos cambiar estos t's por B[0] y B[1]
fp2_copy(&A24, &A.x); // A' + 2C
fp2_sub(&A24m, &A.x, &A.z); // A' - 2C
fp2_copy(&Ap, &A24m);
// left-to-right method for computing (A' + 2C)^l and (A' - 2C)^l
for (j = 1; j < (int)p_plus_minus_bitlength[i]; j++)
{
fp2_sqr(&A24, &A24);
fp2_sqr(&A24m, &A24m);
if( ( ((int)TORSION_ODD_PRIMES[i] >> ((int)p_plus_minus_bitlength[i] - j - 1)) & 1 ) != 0 )
{
fp2_mul(&A24, &A24, &A.x);
fp2_mul(&A24m, &A24m, &Ap);
};
};
fp2_mul(&t24m, &hk_1, &r1); // output of algorithm 2 with alpha =-1 and without the demoninator
fp2_sqr(&t24m, &t24m); // raised at 2
fp2_sqr(&t24m, &t24m); // raised at 4
fp2_sqr(&t24m, &t24m); // raised at 8
fp2_mul(&t24, &hk_0, &r0); // output of algorithm 2 with alpha = 1 and without the demoninator
fp2_sqr(&t24, &t24); // raised at 2
fp2_sqr(&t24, &t24); // raised at 4
fp2_sqr(&t24, &t24); // raised at 8
fp2_mul(&A24, &A24, &t24m);
fp2_mul(&A24m, &A24m, &t24);
// Now, we have d = (A24m / A24) where the image Montgomery cuve coefficient is
// B' 2*(1 + d) 2*(A24 + A24m)
// B = ---- = --------- = --------------
// C (1 - d) (A24 - A24m)
// However, we required B' + 2C = 4*A24 and 4C = 4 * (A24 - A24m)
fp2_sub(&t24m, &A24, &A24m); // (A24 - A24m)
fp2_add(&t24m, &t24m, &t24m); // 2*(A24 - A24m)
fp2_add(&t24m, &t24m, &t24m); // 4*(A24 - A24m)
fp2_add(&t24, &A24, &A24); // 2 * A24
fp2_add(&t24, &t24, &t24); // 4 * A24
fp2_copy(&(B->x), &t24);
fp2_copy(&(B->z), &t24m);
}

View File

@@ -0,0 +1,28 @@
#ifndef CURVE_EXTRAS_H
#define CURVE_EXTRAS_H
#include "ec.h"
#include "torsion_constants.h"
typedef struct jac_point_t {
fp2_t x;
fp2_t y;
fp2_t z;
} jac_point_t;
bool ec_is_zero(ec_point_t const* P);
void copy_point(ec_point_t* P, ec_point_t const* Q);
void swap_points(ec_point_t* P, ec_point_t* Q, const digit_t option);
void ec_init(ec_point_t* P);
void xDBLv2(ec_point_t* Q, ec_point_t const* P, ec_point_t const* A24);
void xDBLADD(ec_point_t* R, ec_point_t* S, ec_point_t const* P, ec_point_t const* Q, ec_point_t const* PQ, ec_point_t const* A24);
void xDBLMUL(ec_point_t* S, ec_point_t const* P, digit_t const* k, ec_point_t const* Q, digit_t const* l, ec_point_t const* PQ, ec_curve_t const* curve);
void xDBL(ec_point_t* Q, ec_point_t const* P, ec_point_t const* AC);
void xMUL(ec_point_t* Q, ec_point_t const* P, digit_t const* k, ec_curve_t const* curve);
void xDBLMUL(ec_point_t* S, ec_point_t const* P, digit_t const* k, ec_point_t const* Q, digit_t const* l, ec_point_t const* PQ, ec_curve_t const* curve);
#define is_point_equal ec_is_equal
#define xADD ec_add
#endif

776
src/ec/ref/include/ec.h Normal file
View File

@@ -0,0 +1,776 @@
/** @file
*
* @authors Luca De Feo, Francisco RH
*
* @brief Elliptic curve stuff
*/
#ifndef EC_H
#define EC_H
#include <fp2.h>
#include <ec_params.h>
/** @defgroup ec Elliptic curves
* @{
*/
/** @defgroup ec_t Data structures
* @{
*/
/** @brief Projective point
*
* @typedef ec_point_t
*
* @struct ec_point_t
*
* A projective point in (X:Z) or (X:Y:Z) coordinates (tbd).
*/
typedef struct ec_point_t {
fp2_t x;
fp2_t z;
} ec_point_t;
/** @brief A basis of a torsion subgroup
*
* @typedef ec_basis_t
*
* @struct ec_basis_t
*
* A pair of points (or a triplet, tbd) forming a basis of a torsion subgroup.
*/
typedef struct ec_basis_t {
ec_point_t P;
ec_point_t Q;
ec_point_t PmQ;
} ec_basis_t;
/** @brief An elliptic curve
*
* @typedef ec_curve_t
*
* @struct ec_curve_t
*
* An elliptic curve in projective Montgomery form
*/
typedef struct ec_curve_t {
fp2_t A;
fp2_t C; ///< cannot be 0
} ec_curve_t;
/** @brief An isogeny of degree a power of 2
*
* @typedef ec_isog_even_t
*
* @struct ec_isog_even_t
*/
typedef struct ec_isog_even_t {
ec_curve_t curve; ///< The domain curve
ec_point_t kernel; ///< A kernel generator
unsigned short length; ///< The length as a 2-isogeny walk
} ec_isog_even_t;
/** @brief An odd divisor of p² - 1
*
* @typedef ec_isog_odd_t
*
* Given that the list of divisors of p² - 1 is known, this is
* represented as a fixed-length vector of integer exponents.
*/
typedef uint8_t ec_degree_odd_t[P_LEN + M_LEN];
/** @brief An isogeny of odd degree dividing p² - 1
*
* @typedef ec_isog_odd_t
*
* @struct ec_isog_odd_t
*/
typedef struct ec_isog_odd_t {
ec_curve_t curve;
ec_point_t ker_plus; ///< A generator of E[p+1] ∩ ker(φ)
ec_point_t ker_minus; ///< A generator of E[p-1] ∩ ker(φ)
ec_degree_odd_t degree; ///< The degree of the isogeny
} ec_isog_odd_t;
/** @brief Isomorphism of Montgomery curves
*
* @typedef ec_isom_t
*
* @struct ec_isom_t
*
* The isomorphism is given by the map maps (X:Z) ↦ ( (Nx X - Nz Z) : (D Z) )
*/
typedef struct ec_isom_t {
fp2_t Nx;
fp2_t Nz;
fp2_t D;
} ec_isom_t;
// end ec_t
/** @}
*/
/** @defgroup ec_curve_t Curves and isomorphisms
* @{
*/
/**
* @brief j-invariant.
*
* @param j_inv computed j_invariant
* @param curve input curve
*/
void ec_j_inv(fp2_t* j_inv, const ec_curve_t* curve);
/**
* @brief Isomorphism of elliptic curve
*
* @param isom computed isomorphism
* @param from domain curve
* @param to image curve
*/
void ec_isomorphism(ec_isom_t* isom, const ec_curve_t* from, const ec_curve_t* to);
/**
* @brief In-place inversion of an isomorphism
*
* @param isom an isomorphism
*/
void ec_iso_inv(ec_isom_t* isom);
/**
* @brief In-place evaluation of an isomorphism
*
* @param P a point
* @param isom an isomorphism
*/
void ec_iso_eval(ec_point_t* P, ec_isom_t* isom);
/**
* @brief Given a Montgomery curve, computes a standard model for it and the isomorphism to it.
*
* @param new computed new curve
* @param isom computed isomorphism from `old` to `new`
* @param old A Montgomery curve
*/
void ec_curve_normalize(ec_curve_t *new, ec_isom_t *isom, const ec_curve_t *old);
/** @}
*/
/** @defgroup ec_point_t Point operations
* @{
*/
/**
* @brief Point equality
*
* @param P a point
* @param Q a point
* @return 1 if equal
*/
bool ec_is_equal(const ec_point_t* P, const ec_point_t* Q);
/**
* @brief Reduce Z-coordinate of point in place
*
* @param P a point
*/
void ec_normalize(ec_point_t* P);
/**
* @brief Test whether a point is on a curve
*
* @param curve a curve
* @param P a point
* @return 1 if P is on the curve
*/
int ec_is_on_curve(const ec_curve_t* curve, const ec_point_t* P);
/**
* @brief Point negation
*
* @param res computed opposite of P
* @param P a point
*/
void ec_neg(ec_point_t* res, const ec_point_t* P);
/**
* @brief Point addition
*
* @param res computed sum of P and Q
* @param P a point
* @param Q a point
* @param PQ the difference P-Q
*/
void ec_add(ec_point_t* res, const ec_point_t* P, const ec_point_t* Q, const ec_point_t* PQ);
/**
* @brief Point doubling
*
* @param res computed double of P
* @param P a point
*/
void ec_dbl(ec_point_t* res, const ec_curve_t* curve, const ec_point_t* P);
/**
* @brief Point multiplication
*
* @param res computed scalar * P
* @param curve the curve
* @param scalar an unsigned multi-precision integer
* @param P a point
*/
void ec_mul(ec_point_t* res, const ec_curve_t* curve, const digit_t* scalar, const ec_point_t* P);
/**
* @brief Point multiplication by a scalar of limited length
*
* @param res computed scalar * P
* @param curve the curve
* @param scalar an unsigned multi-precision integer
* @param kbits the bit size of scalar
* @param P a point
*/
void xMULv2(ec_point_t* Q, ec_point_t const* P, digit_t const* k, const int kbits, ec_point_t const* A24);
/**
* @brief Combination P+m*Q
*
* @param R computed P + m * Q
* @param curve the curve
* @param m an unsigned multi-precision integer
* @param P a point
* @param Q a point
* @param PQ the difference P-Q
*/
void ec_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_curve_t const *A);
/**
* @brief Linear combination of points of a basis
*
* @param res computed scalarP * P + scalarQ * Q
* @param curve the curve
* @param scalarP an unsigned multi-precision integer
* @param scalarQ an unsigned multi-precision integer
* @param PQ a torsion basis consisting of points P and Q
*/
void ec_biscalar_mul(ec_point_t* res, const ec_curve_t* curve,
const digit_t* scalarP, const digit_t* scalarQ,
const ec_basis_t* PQ);
/** @}
*/
/** @defgroup ec_dlog_t Discrete logs and bases
* @{
*/
/**
* @brief Generate a Montgomery curve and a 2^f-torsion basis
*
* The algorithm is deterministc
*
* @param PQ2 computed basis of the 2^f-torsion
* @param curve the computed curve
*/
void ec_curve_to_basis_2(ec_basis_t *PQ2, const ec_curve_t *curve);
/**
* @brief Complete a basis of the 2^f-torsion
*
* The algorithm is deterministic
*
* @param PQ2 a basis of the 2^f-torsion containing P as first generator
* @param curve the curve
* @param P a point of order 2^f
*/
void ec_complete_basis_2(ec_basis_t* PQ2, const ec_curve_t* curve, const ec_point_t* P);
/**
* @brief Generate a 3^e-torsion basis
*
* The algorithm is deterministic
*
* @param PQ3 the computed 3^e-torsion basis
* @param curve a curve
*/
void ec_curve_to_basis_3(ec_basis_t* PQ3, const ec_curve_t* curve);
/**
* @brief Generate a 6^e-torsion basis
*
* The algorithm is deterministic
*
* @param PQ6 the computed 2^f*3^g-torsion basis
* @param curve a curve
*/
void ec_curve_to_basis_6(ec_basis_t* PQ6, const ec_curve_t* curve);
/**
* @brief Compute the generalized dlog of R wrt the 2^f-basis PQ2
*
* Ensure that R = scalarP * P + scalarQ * Q
*
* @param scalarP the computed dlog
* @param scalarQ the computed dlog
* @param PQ2 a 2^f-torsion basis
* @param R a point of order dividing 2^f
*/
void ec_dlog_2(digit_t* scalarP, digit_t* scalarQ,
const ec_basis_t* PQ2, const ec_point_t* R, const ec_curve_t* curve);
/**
* @brief Compute the generalized dlog of R wrt the 3^e-basis PQ3
*
* Ensure that R = scalarP * P + scalarQ * Q
*
* @param scalarP the computed dlog
* @param scalarQ the computed dlog
* @param PQ3 a 3^e-torsion basis
* @param R a point of order dividing 3^e
*/
void ec_dlog_3(digit_t* scalarP, digit_t* scalarQ,
const ec_basis_t* PQ3, const ec_point_t* R, const ec_curve_t* curve);
/** @}
*/
/** @defgroup ec_isog_t Isogenies
* @{
*/
/**
* @brief Evaluate isogeny of even degree on list of points
*
* @param image computed image curve
* @param phi isogeny
* @param points a list of points to evaluate the isogeny on, modified in place
* @param length of the list points
*/
void ec_eval_even(ec_curve_t* image, const ec_isog_even_t* phi,
ec_point_t* points, unsigned short length);
/**
* @brief Evaluate isogeny of even degree on list of points, assuming the point (0,0) is not in the kernel
*
* @param image computed image curve
* @param phi isogeny
* @param points a list of points to evaluate the isogeny on, modified in place
* @param length of the list points
*/
void ec_eval_even_nonzero(ec_curve_t* image, const ec_isog_even_t* phi,
ec_point_t* points, unsigned short length);
/**
* @brief Evaluate isogeny of even degree on list of torsion bases
*
* @param image computed image curve
* @param phi isogeny
* @param points a list of bases to evaluate the isogeny on, modified in place
* @param length of the list bases
*/
static inline void ec_eval_even_basis(ec_curve_t* image, const ec_isog_even_t* phi,
ec_basis_t* points, unsigned short length) {
ec_eval_even(image, phi, (ec_point_t*)points, sizeof(ec_basis_t) / sizeof(ec_point_t) * length);
}
/**
* @brief Evaluate isogeny of odd degree on list of points
*
* @param image computed image curve
* @param phi isogeny
* @param points a list of points to evaluate the isogeny on, modified in place
* @param length of the list points
*/
void ec_eval_odd(ec_curve_t* image, const ec_isog_odd_t* phi,
ec_point_t* points, unsigned short length);
/**
* @brief Evaluate isogeny of odd degree on list of torsion bases
*
* @param image computed image curve
* @param phi isogeny
* @param points a list of bases to evaluate the isogeny on, modified in place
* @param length of the list bases
*/
static inline void ec_eval_odd_basis(ec_curve_t* image, const ec_isog_odd_t* phi,
ec_basis_t* points, unsigned short length) {
ec_eval_odd(image, phi, (ec_point_t*)points, sizeof(ec_basis_t) / sizeof(ec_point_t) * length);
}
/** @}
*/
// end ec
/** @}
*/
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////// ORIGINAL VERSION
#if 0
/** @file
*
* @authors Luca De Feo, Francisco RH
*
* @brief Elliptic curve stuff
*/
#ifndef EC_H
#define EC_H
#include <gf.h>
/** @defgroup ec Elliptic curves
* @{
*/
/** @defgroup ec_t Data structures
* @{
*/
/** @brief Projective point
*
* @typedef ec_point_t
*
* @struct ec_point_t
*
* A projective point in (X:Z) or (X:Y:Z) coordinates (tbd).
*/
typedef struct ec_point_t {
fp2_t X;
//fp2_t Y;
fp2_t Z;
} ec_point_t;
/** @brief A basis of a torsion subgroup
*
* @typedef ec_basis_t
*
* @struct ec_basis_t
*
* A pair of points (or a triplet, tbd) forming a basis of a torsion subgroup.
*/
typedef struct ec_basis_t {
ec_point_t P;
ec_point_t Q;
ec_point_t PmQ; // or maybe not
} ec_basis_t;
/** @brief An elliptic curve
*
* @typedef ec_curve_t
*
* @struct ec_curve_t
*
* An elliptic curve in projective Montgomery form
*/
typedef struct ec_curve_t {
fp2_t A;
fp2_t C; ///< cannot be 0
} ec_curve_t;
/** @brief An isogeny of degree a power of 2
*
* @typedef ec_isog_even_t
*
* @struct ec_isog_even_t
*/
typedef struct ec_isog_even_t {
ec_curve_t curve; ///< The domain curve
ec_point_t kernel; ///< A kernel generator
unsigned short length; ///< The length as a 2-isogeny walk
} ec_isog_even_t;
/** @brief An odd divisor of p² - 1
*
* @typedef ec_isog_odd_t
*
* @struct ec_isog_odd_t
*
* Given that the list of divisors of p² - 1 is known, this could be
* represented as a fixed-length vector of integer exponents, possibly
* distinguishing the divisors of p + 1 from those of p - 1.
*/
typedef struct ec_degree_odd_t {
// todo (basically a ushort vector)
} ec_degree_odd_t;
/** @brief An isogeny of odd degree dividing p² - 1
*
* @typedef ec_isog_odd_t
*
* @struct ec_isog_odd_t
*/
typedef struct ec_isog_odd_t {
ec_point_t ker_plus; ///< A generator of E[p+1] ∩ ker(φ)
ec_point_t ker_minus; ///< A generator of E[p-1] ∩ ker(φ)
ec_degree_odd_t degree; ///< The degree of the isogeny
} ec_isog_odd_t;
/** @brief Isomorphism of Montgomery curves
*
* @typedef ec_isom_t
*
* @struct ec_isom_t
*
* The isomorphism is given by the map maps (X:Z) ↦ ( (Nx X - Nz Z) : (D Z) )
* TODO: fix if (X:Y:Z) coordinates.
*/
typedef struct ec_isom_t {
fp2_t Nx;
fp2_t Nz;
fp2_t D;
} ec_isom_t;
// end ec_t
/** @}
*/
/** @defgroup ec_curve_t Curves and isomorphisms
* @{
*/
/**
* @brief j-invariant.
*
* @param j_inv computed j_invariant
* @param curve input curve
*/
void ec_j_inv(fp2_t* j_inv, const ec_curve_t* curve);
/**
* @brief Isomorphism of elliptic curve
*
* @param isom computed isomorphism
* @param from domain curve
* @param to image curve
*/
void ec_isomorphism(ec_isom_t* isom, const ec_curve_t* from, const ec_curve_t* to);
/** @}
*/
/** @defgroup ec_point_t Point operations
* @{
*/
/**
* @brief Point equality
*
* @param P a point
* @param Q a point
* @return 1 if equal
*/
int ec_is_equal(const ec_point_t* P, const ec_point_t* Q);
/**
* @brief Reduce Z-coordinate of point in place
*
* @param P a point
*/
void ec_normalize(ec_point_t* P);
/**
* @brief Test whether a point is on a curve
*
* @param curve a curve
* @param P a point
* @return 1 if P is on the curve
*/
int ec_is_on_curve(const ec_curve_t* curve, const ec_point_t* P);
/**
* @brief Point negation
*
* @param res computed opposite of P
* @param P a point
*/
void ec_neg(ec_point_t* res, const ec_point_t* P);
/**
* @brief Point addition
*
* Needs to be adjusted if (X:Z) arithmetic.
*
* @param res computed sum of P and Q
* @param P a point
* @param Q a point
*/
void ec_add(ec_point_t* res, const ec_point_t* P, const ec_point_t* Q);
/**
* @brief Point doubling
*
* @param res computed double of P
* @param P a point
*/
void ec_dbl(ec_point_t* res, const ec_curve_t* curve, const ec_point_t* P);
/**
* @brief Point multiplication
*
* @param res computed scalar * P
* @param curve the curve
* @param scalar an unsigned multi-precision integer
* @param P a point
*/
void ec_mul(ec_point_t* res, const ec_curve_t* curve, const digit_t* scalar, const ec_point_t* P);
/**
* @brief Linear combination of points of a basis
*
* @param res computed scalarP * P + scalarQ * Q
* @param curve the curve
* @param scalarP an unsigned multi-precision integer
* @param scalarQ an unsigned multi-precision integer
* @param PQ a torsion basis consisting of points P and Q
*/
void ec_biscalar_mul(ec_point_t* res, const ec_curve_t* curve,
const digit_t* scalarP, const digit_t* scalarQ,
const ec_basis_t* PQ);
/** @}
*/
/** @defgroup ec_dlog_t Discrete logs and bases
* @{
*/
/**
* @brief Generate a Montgomery curve and a 2^f-torsion basis
*
* The algorithm is deterministc
*
* @param curve the computed curve
* @param PQ2 a basis of the 2^f-torsion
* @param j_inv a j-invariant
*/
void ec_j_to_basis_2(ec_curve_t* curve, ec_basis_t* PQ2, const fp2_t* j_inv);
/**
* @brief Complete a basis of the 2^f-torsion
*
* The algorithm is deterministc
*
* @param PQ2 a basis of the 2^f-torsion containing P as first generator
* @param curve the curve
* @param P a point of order 2^f
*/
void ec_complete_basis_2(ec_basis_t* PQ2, const ec_curve_t* curve, const ec_point_t* P);
/**
* @brief Generate a 3^e-torsion basis
*
* The algorithm is deterministc
*
* @param PQ3 the computed 3^e-torsion basis
* @param curve a curve
*/
void ec_curve_to_basis_3(ec_basis_t* PQ3, const ec_curve_t* curve);
/**
* @brief Compute the generalized dlog of R wrt the 2^f-basis PQ2
*
* Ensure that R = scalarP * P + scalarQ * Q
*
* @param scalarP the computed dlog
* @param scalarQ the computed dlog
* @param PQ2 a 2^f-torsion basis
* @param R a point of order dividing 2^f
*/
void ec_dlog_2(digit_t* scalarP, digit_t* scalarQ,
const ec_basis_t* PQ2, const ec_point_t* R);
/**
* @brief Compute the generalized dlog of R wrt the 3^e-basis PQ3
*
* Ensure that R = scalarP * P + scalarQ * Q
*
* @param scalarP the computed dlog
* @param scalarQ the computed dlog
* @param PQ3 a 3^e-torsion basis
* @param R a point of order dividing 3^e
*/
void ec_dlog_3(digit_t* scalarP, digit_t* scalarQ,
const ec_basis_t* PQ3, const ec_point_t* R);
/** @}
*/
/** @defgroup ec_isog_t Isogenies
* @{
*/
/**
* @brief Evaluate isogeny of even degree on list of points
*
* @param image computed image curve
* @param phi isogeny
* @param points a list of points to evaluate the isogeny on, modified in place
* @param length of the list points
*/
void ec_eval_even(ec_curve_t* image, const ec_isog_even_t* phi,
ec_point_t* points, unsigned short length);
/**
* @brief Evaluate isogeny of even degree on list of torsion bases
*
* @param image computed image curve
* @param phi isogeny
* @param points a list of bases to evaluate the isogeny on, modified in place
* @param length of the list bases
*/
static inline void ec_eval_even_basis(ec_curve_t* image, const ec_isog_even_t* phi,
ec_basis_t* points, unsigned short length) {
ec_eval_even(image, phi, points, sizeof(ec_basis_t) / sizeof(ec_point_t) * length);
}
/**
* @brief Evaluate isogeny of odd degree on list of points
*
* @param image computed image curve
* @param phi isogeny
* @param points a list of points to evaluate the isogeny on, modified in place
* @param length of the list points
*/
void ec_eval_odd(ec_curve_t* image, const ec_isog_odd_t* phi,
ec_point_t* points, unsigned short length);
/**
* @brief Evaluate isogeny of odd degree on list of torsion bases
*
* @param image computed image curve
* @param phi isogeny
* @param points a list of bases to evaluate the isogeny on, modified in place
* @param length of the list bases
*/
static inline void ec_eval_odd_basis(ec_curve_t* image, const ec_isog_odd_t* phi,
ec_basis_t* points, unsigned short length) {
ec_eval_odd(image, phi, points, sizeof(ec_basis_t) / sizeof(ec_point_t) * length);
}
/** @}
*/
// end ec
/** @}
*/
#endif
#endif

84
src/ec/ref/include/isog.h Normal file
View File

@@ -0,0 +1,84 @@
#ifndef _ISOG_H_
#define _ISOG_H_
#include "curve_extras.h"
#include "poly.h"
extern int sI, sJ, sK; // Sizes of each current I, J, and K
extern fp2_t I[sI_max][2], // I plays also as the linear factors of the polynomial h_I(X)
EJ_0[sJ_max][3], EJ_1[sJ_max][3]; // To be used in xisog y xeval
extern ec_point_t J[sJ_max], K[sK_max]; // Finite subsets of the kernel
extern fp2_t XZJ4[sJ_max], // -4* (Xj * Zj) for each j in J, and x([j]P) = (Xj : Zj)
rtree_A[(1 << (ceil_log_sI_max+2)) - 1], // constant multiple of the reciprocal tree computation
A0; // constant multiple of the reciprocal R0
extern poly ptree_hI[(1 << (ceil_log_sI_max+2)) - 1], // product tree of h_I(X)
rtree_hI[(1 << (ceil_log_sI_max+2)) - 1], // reciprocal tree of h_I(X)
ptree_EJ[(1 << (ceil_log_sJ_max+2)) - 1]; // product tree of E_J(X)
extern fp2_t R0[2*sJ_max + 1]; // Reciprocal of h_I(X) required in the scaled remainder tree approach
extern int deg_ptree_hI[(1 << (ceil_log_sI_max+2)) - 1], // degree of each noed in the product tree of h_I(X)
deg_ptree_EJ[(1 << (ceil_log_sJ_max+2)) - 1]; // degree of each node in the product tree of E_J(X)
extern fp2_t leaves[sI_max]; // leaves of the remainder tree, which are required in the Resultant computation
void eds2mont(ec_point_t* P); // mapping from Twisted edwards into Montogmery
void yadd(ec_point_t* R, ec_point_t* const P, ec_point_t* const Q, ec_point_t* const PQ); // differential addition on Twisted edwards model
void CrissCross(fp2_t *r0, fp2_t *r1, fp2_t const alpha, fp2_t const beta, fp2_t const gamma, fp2_t const delta);
void kps_t(uint64_t const i, ec_point_t const P, ec_point_t const A); // tvelu formulae
void kps_s(uint64_t const i, ec_point_t const P, ec_point_t const A); // svelu formulae
void xisog_4(ec_point_t* B, ec_point_t const P); // degree-4 isogeny construction
void xisog_4_singular(ec_point_t* B24, ec_point_t const P, ec_point_t A24);
void xisog_2(ec_point_t* B, ec_point_t const P); // degree-2 isogeny construction
void xisog_t(ec_point_t* B, uint64_t const i, ec_point_t const A); // tvelu formulae
void xisog_s(ec_point_t* B, uint64_t const i, ec_point_t const A); // svelu formulae
void xeval_4(ec_point_t* R, const ec_point_t* Q, const int lenQ); // degree-4 isogeny evaluation
void xeval_4_singular(ec_point_t* R, const ec_point_t* Q, const int lenQ, const ec_point_t P);
void xeval_2(ec_point_t* R, ec_point_t* const Q, const int lenQ); // degree-2 isogeny evaluation
void xeval_t(ec_point_t* Q, uint64_t const i, ec_point_t const P); // tvelu formulae
void xeval_s(ec_point_t* Q, uint64_t const i, ec_point_t const P, ec_point_t const A); // svelu formulae
// Strategy-based 4-isogeny chain
static void ec_eval_even_strategy(ec_curve_t* image, ec_point_t* points, unsigned short points_len,
ec_point_t* A24, const ec_point_t *kernel, const int isog_len);
void kps_clear(int i); // Clear memory assigned by KPS
// hybrid velu formulae
static inline void kps(uint64_t const i, ec_point_t const P, ec_point_t const A)
{
// Next branch only depends on a fixed public bound (named gap)
if (TORSION_ODD_PRIMES[i] <= gap)
kps_t(i, P, A);
else
kps_s(i, P, A);
}
static inline void xisog(ec_point_t* B, uint64_t const i, ec_point_t const A)
{
// Next branch only depends on a fixed public bound (named gap)
if (TORSION_ODD_PRIMES[i] <= gap)
xisog_t(B, i, A);
else
xisog_s(B, i, A);
}
static inline void xeval(ec_point_t* Q, uint64_t const i, ec_point_t const P, ec_point_t const A)
{
// Next branch only depends on a fixed public bound (named gap)
if (TORSION_ODD_PRIMES[i] <= gap)
xeval_t(Q, i, P);
else
xeval_s(Q, i, P, A);
}
#endif

28
src/ec/ref/include/poly.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef _POLY_H_
#define _POLY_H_
#include <fp2.h>
typedef fp2_t *poly; // Polynomials are arrays of coeffs over Fq, lowest degree first
void poly_mul(poly h, const poly f, const int lenf, const poly g, const int leng);
void poly_mul_low(poly h, const int n, const poly f, const int lenf, const poly g, const int leng);
void poly_mul_middle(poly h, const poly g, const int leng, const poly f, const int lenf);
void poly_mul_selfreciprocal(poly h, const poly g, const int leng, const poly f, const int lenf);
void product_tree(poly H[], int DEG[], const int root, const poly F[], const int LENF, const int n);
void product_tree_LENFeq2(poly H[], int DEG[], const int root, const fp2_t F[][2], const int n);
void product_tree_LENFeq3(poly H[], int DEG[], const int root, const fp2_t F[][3], const int n);
void product_tree_selfreciprocal(poly H[], int DEG[], const int root, const poly F[], const int LENF, const int n);
void product_tree_selfreciprocal_LENFeq3(poly H[], int DEG[], const int root, const fp2_t F[][3], const int n);
void clear_tree(poly H[], const int root, const int n);
void product(fp2_t *c, const fp2_t F[], const int n);
void reciprocal(poly h, fp2_t *c, const poly f, const int lenf, const int n);
void poly_redc(poly h, const poly g, const int leng, const poly f, const int lenf,const poly f_inv, const fp2_t c);
void reciprocal_tree(poly *R, fp2_t *A, const int leng, const poly H[], const int DEG[], const int root, const int n);
void multieval_unscaled(fp2_t REM[], const poly g, const int leng, const poly R[], const fp2_t A[], const poly H[], const int DEG[], const int root, const int n);
void multieval_scaled(fp2_t REM[], const poly G, const poly H[], const int DEG[], const int root, const int n);
#endif /* _POLY_H */

View File

@@ -0,0 +1,50 @@
#ifndef _SDACS_H_
#define _SDACS_H_
static char SDAC_P_0[] = "0";
static char SDAC_P_1[] = "10";
static char SDAC_P_2[] = "100";
static char SDAC_P_3[] = "0100";
static char SDAC_P_4[] = "10000";
static char SDAC_P_5[] = "110000";
static char SDAC_P_6[] = "100000";
static char SDAC_P_7[] = "1100010001";
static char SDAC_P_8[] = "1001010000";
static char SDAC_P_9[] = "0101001000";
static char SDAC_P_10[] = "110110010000";
static char SDAC_P_11[] = "10000000000";
static char SDAC_P_12[] = "1010100001001000";
static char SDAC_M_0[] = "";
static char SDAC_M_1[] = "000";
static char SDAC_M_2[] = "1010";
static char SDAC_M_3[] = "100010";
static char SDAC_M_4[] = "0010000";
static char SDAC_M_5[] = "110000000";
static char SDAC_M_6[] = "1010101010";
static char SDAC_M_7[] = "1010001000";
static char SDAC_M_8[] = "1001000000";
static char SDAC_M_9[] = "0100001000";
static char SDAC_M_10[] ="101101010000";
static char SDAC_M_11[] = "100100010010";
static char SDAC_M_12[] = "010100011000";
static char SDAC_M_13[] = "101010000001";
static char SDAC_M_14[] = "010100001000";
static char SDAC_M_15[] = "1101010010000";
static char SDAC_M_16[] = "1001010001010";
static char SDAC_M_17[] = "101001000000101";
static char *SDACs[31] = {
SDAC_P_0, SDAC_P_1, SDAC_P_2, SDAC_P_3, SDAC_P_4,
SDAC_P_5, SDAC_P_6, SDAC_P_7, SDAC_P_8, SDAC_P_9,
SDAC_P_10, SDAC_P_11, SDAC_P_12,
SDAC_M_0, SDAC_M_1, SDAC_M_2, SDAC_M_3, SDAC_M_4,
SDAC_M_5, SDAC_M_6, SDAC_M_7, SDAC_M_8, SDAC_M_9,
SDAC_M_10, SDAC_M_11, SDAC_M_12, SDAC_M_13, SDAC_M_14,
SDAC_M_15, SDAC_M_16, SDAC_M_17
};
static int LENGTHS[] = {
1, 2, 3, 4, 5, 6, 6, 10, 10, 10, 12, 11, 16, 0, 3, 4, 6, 7, 9, 10, 10, 10, 10, 12, 12, 12, 12, 12, 13, 13, 15
};
#endif

28
src/ec/ref/include/tedwards.h Executable file
View File

@@ -0,0 +1,28 @@
#ifndef TEDWARDS_H
#define TEDWARDS_H
#include <fp2.h>
#include "ec.h"
// a*x^2+y^2=1+d*x^2*y^2
typedef struct ted_point_t {
fp2_t x;
fp2_t y;
fp2_t z;
fp2_t t; // t = x*y/z
} ted_point_t;
void ted_init(ted_point_t* P);
bool is_ted_equal(ted_point_t const* P1, ted_point_t const* P2);
void copy_ted_point(ted_point_t* P, ted_point_t const* Q);
void ted_neg(ted_point_t* Q, ted_point_t const* P);
void ted_dbl(ted_point_t* Q, ted_point_t const* P, ec_curve_t const* E);
void ted_add(ted_point_t* S, ted_point_t const* P, ted_point_t const* Q, ec_curve_t const* E);
void mont_to_ted(ec_curve_t* E, ec_curve_t const* A);
void mont_to_ted_point(ted_point_t* Q, ec_point_t const* P, ec_curve_t const* A);
void ted_to_mont_point(ec_point_t* Q, ted_point_t const* P);
#endif

View File

@@ -0,0 +1,17 @@
set(SOURCE_FILES_EC_${SVARIANT_UPPER}_REF
${ECX_DIR}/poly-mul.c
${ECX_DIR}/poly-redc.c
${ECX_DIR}/ec.c
${ECX_DIR}/tedwards.c
${ECX_DIR}/kps.c
${ECX_DIR}/xisog.c
${ECX_DIR}/xeval.c
${ECX_DIR}/isog_chains.c
${ECX_DIR}/basis.c
)
add_library(${LIB_EC_${SVARIANT_UPPER}} ${SOURCE_FILES_EC_${SVARIANT_UPPER}_REF})
target_include_directories(${LIB_EC_${SVARIANT_UPPER}} PRIVATE ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${INC_PUBLIC} ${INC_GF_${SVARIANT_UPPER}} ${INC_COMMON} ${INC_EC})
target_compile_options(${LIB_EC_${SVARIANT_UPPER}} PRIVATE ${C_OPT_FLAGS})
add_subdirectory(test)

View File

@@ -0,0 +1,36 @@
add_executable(fp2.test_${SVARIANT_LOWER} ${ECX_DIR}/test/fp2-test.c)
target_include_directories(fp2.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_GF_${SVARIANT_UPPER}} ${INC_EC} ${INC_COMMON})
target_link_libraries(fp2.test_${SVARIANT_LOWER} ${LIB_GF_${SVARIANT_UPPER}})
add_executable(poly-mul.test_${SVARIANT_LOWER} ${ECX_DIR}/test/poly-mul-test.c)
target_include_directories(poly-mul.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON})
target_link_libraries(poly-mul.test_${SVARIANT_LOWER} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(poly-redc.test_${SVARIANT_LOWER} ${ECX_DIR}/test/poly-redc-test.c)
target_include_directories(poly-redc.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON})
target_link_libraries(poly-redc.test_${SVARIANT_LOWER} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(mont.test_${SVARIANT_LOWER} ${ECX_DIR}/test/mont-test.c)
target_include_directories(mont.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON} .)
target_link_libraries(mont.test_${SVARIANT_LOWER} ${LIB_PRECOMP_${SVARIANT_UPPER}} ${LIB_INTBIG} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(ec.test_${SVARIANT_LOWER} ${ECX_DIR}/test/ec-test.c ${ECX_DIR}/test/test_extras.c)
target_include_directories(ec.test_${SVARIANT_LOWER} PUBLIC ${ECX_DIR}/test ${INC_GF_${SVARIANT_UPPER}} ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON} .)
target_link_libraries(ec.test_${SVARIANT_LOWER} ${LIB_PRECOMP_${SVARIANT_UPPER}} ${LIB_INTBIG} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(velu.test_${SVARIANT_LOWER} ${ECX_DIR}/test/velu-test.c)
target_include_directories(velu.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON} .)
target_link_libraries(velu.test_${SVARIANT_LOWER} ${LIB_PRECOMP_${SVARIANT_UPPER}} ${LIB_INTBIG} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(isog.test_${SVARIANT_LOWER} ${ECX_DIR}/test/isog-test.c)
target_include_directories(isog.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON} .)
target_link_libraries(isog.test_${SVARIANT_LOWER} ${LIB_PRECOMP_${SVARIANT_UPPER}} ${LIB_INTBIG} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_test(ec_fp2.test_${SVARIANT_LOWER} fp2.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_poly-mul.test_${SVARIANT_LOWER} poly-mul.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_poly-redc.test_${SVARIANT_LOWER} poly-redc.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_mont.test_${SVARIANT_LOWER} mont.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_ec.test_${SVARIANT_LOWER} ec.test_${SVARIANT_LOWER} test ${SQISIGN_TEST_REPS})
add_test(ec_velu.test_${SVARIANT_LOWER} velu.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_isog.test_${SVARIANT_LOWER} isog.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})

View File

@@ -0,0 +1,400 @@
#ifndef EC_TESTS_H
#define EC_TESTS_H
#include "test_extras.h"
#include <stdio.h>
#include <string.h>
#include <bench.h> //////// NOTE: enable later
#include "test-basis.h"
#include "ec_params.h"
// Global constants
extern const digit_t p[NWORDS_FIELD];
// Benchmark and test parameters
static int BENCH_LOOPS = 1000; // Number of iterations per bench
static int TEST_LOOPS = 512; // Number of iterations per test
bool ec_test()
{ // Tests for ecc arithmetic
bool OK = true;
int passed;
ec_point_t P = {0}, Q = {0}, R = {0}, S = {0}, SS = {0}, PQ = {0};
ec_point_t AC = {0};
digit_t k[NWORDS_ORDER] = {0}, l[NWORDS_ORDER] = {0};
printf("\n--------------------------------------------------------------------------------------------------------\n\n");
printf("Testing ecc functions: \n\n");
// Point doubling
passed = 1;
P.x.re[0] = 0xDFD70ED0861BD329; P.x.re[1] = 0x20ACD3758C7F5540; P.x.re[2] = 0x3DCCDC007277F80A; P.x.re[3] = 0x18D6D2A22981DCE1;
P.x.im[0] = 0x3C23730A3F08F38C; P.x.im[1] = 0x98BB973AFD3D954D; P.x.im[2] = 0x8D98ADFC2829AE8A; P.x.im[3] = 0x21A2464D6369AFBA;
P.z.re[0] = 0x01;
AC.z.re[0] = 0x01;
fp2_tomont(&AC.z, &AC.z);
fp2_tomont(&R.x, &P.x);
fp2_tomont(&R.z, &P.z);
xDBL(&S, &R, &AC);
fp2_copy(&SS.x, &S.x); // Copy of S = SS <- 2P
fp2_copy(&SS.z, &S.z);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0x5950EE0A4AF90FC8; R.x.re[1] = 0x16488065A0A98B08; R.x.re[2] = 0xCE65322229DA0FD1; R.x.re[3] = 0x270A35FF781EE204;
R.x.im[0] = 0x564447FD9EC57F6B; R.x.im[1] = 0x2EE24E984294F729; R.x.im[2] = 0x53A6C7360E972C71; R.x.im[3] = 0x4FCF4B9928A7C7E;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2)!=0) { passed=0; goto out0; }
Q.x.re[0] = 0xC46076A670C70053; Q.x.re[1] = 0x97517AFA3AB9ED13; Q.x.re[2] = 0x349644C942EDF993; Q.x.re[3] = 0xBB4A4DB6F29AF9E;
Q.x.im[0] = 0x8B47629FB5A15BB0; Q.x.im[1] = 0x4EC6E809953C1A10; Q.x.im[2] = 0x1F83F0EC6CBB84D6; Q.x.im[3] = 0x1D8417C1D33265D3;
Q.z.re[0] = 0x01;
PQ.x.re[0] = 0x853F66D11BE5534F; PQ.x.re[1] = 0x27C8FD4E52D03D4A; PQ.x.re[2] = 0xF88EA78D0A0C29D2; PQ.x.re[3] = 0x2F6DFB07D397A067;
PQ.x.im[0] = 0xE8DBC4AA34434BA1; PQ.x.im[1] = 0x7A73AE182636F8A0; PQ.x.im[2] = 0x419EC260137868EB; PQ.x.im[3] = 0x129B3E301703D43F;
PQ.z.re[0] = 0x01;
fp2_tomont(&S.x, &Q.x);
fp2_tomont(&S.z, &Q.z);
fp2_tomont(&PQ.x, &PQ.x);
fp2_tomont(&PQ.z, &PQ.z);
xADD(&S, &SS, &S, &PQ);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0xED0BEB8F93AB4FF9; R.x.re[1] = 0x27CF508B80CD49BF; R.x.re[2] = 0x38A6134DFA04B2BA; R.x.re[3] = 0x27B4CB15E109EF1F;
R.x.im[0] = 0x6F731BA6FD227BDE; R.x.im[1] = 0x14C12335341167F8; R.x.im[2] = 0xECA7B60F7866E27A; R.x.im[3] = 0x2A7A79A152880457;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2) != 0) { passed = 0; goto out0; }
fp2_tomont(&R.x, &P.x);
fp2_tomont(&R.z, &P.z);
k[0] = 126;
xMUL(&S, &R, k, (ec_curve_t*)&AC);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0xDE80F87A1203A147; R.x.re[1] = 0xD59E1215928A3B2D; R.x.re[2] = 0xD5A67F83A5A8CE46; R.x.re[3] = 0xA11E162488C9CDF;
R.x.im[0] = 0x9417D0D79A26741B; R.x.im[1] = 0x8B1F47D6F0FE5EEC; R.x.im[2] = 0xE52188DCB054CE36; R.x.im[3] = 0x1A8075A6C3148AB3;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2) != 0) { passed = 0; goto out0; }
fp2_tomont(&R.x, &P.x);
fp2_tomont(&R.z, &P.z);
k[0] = 0xE77AD6B6C6B2D8CD;
k[1] = 0xDE43A0B600F38D12;
k[2] = 0xA35F4A7897E17CE2;
k[3] = 0x10ACB62E614D1237;
xMUL(&S, &R, k, (ec_curve_t*)&AC);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0xD3938B0A68A3E7C0; R.x.re[1] = 0xE0667113208A0595; R.x.re[2] = 0x258F314C84E9CB60; R.x.re[3] = 0x14984BA7CA59AB71;
R.x.im[0] = 0xFE728423EE3BFEF4; R.x.im[1] = 0xBF68C42FE21AE0E4; R.x.im[2] = 0xA8FAF9C9528609CA; R.x.im[3] = 0x1225EC77A1DC0285;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2) != 0) { passed = 0; goto out0; }
fp2_tomont(&R.x, &Q.x);
fp2_tomont(&R.z, &Q.z);
k[0] = 0xE77AD6B6C6B2D8CD;
k[1] = 0xDE43A0B600F38D12;
k[2] = 0xA35F4A7897E17CE2;
k[3] = 0x10ACB62E614D1237;
l[0] = 0x34AB78B6C6B2D8C0;
l[1] = 0xDE6B2D8CD00F38D1;
l[2] = 0xA35F4A7897E17CE2;
l[3] = 0x20ACF4A789614D13;
fp2_inv(&SS.z);
fp2_mul(&SS.x, &SS.x, &SS.z);
fp2_copy(&SS.z, &R.z);
xDBLMUL(&S, &R, k, &SS, l, &PQ, (ec_curve_t*)&AC);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0x554E1ADC609B992F; R.x.re[1] = 0xE407D961F8CC4C42; R.x.re[2] = 0x1CF626AFED5A68CE; R.x.re[3] = 0x6D02692EE110483;
R.x.im[0] = 0x16FB094E831C8997; R.x.im[1] = 0xFDE4ECF31DC5F702; R.x.im[2] = 0x89303D868DFAD7B4; R.x.im[3] = 0xC91ACE81346F22D;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2) != 0) { passed = 0; goto out0; }
out0:
if (passed==1) printf(" ECC arithmetic tests ............................................ PASSED");
else { printf(" ECC arithmetic tests... FAILED"); printf("\n"); return false; }
printf("\n");
return OK;
}
bool dlog_test()
{ // Tests for dlog
bool OK = true;
int passed;
ec_point_t P = {0}, Q = {0}, R = {0}, S = {0}, SS = {0}, PQ = {0};
ec_curve_t AC = {0};
ec_basis_t PQ2;
digit_t scalarP[NWORDS_ORDER], scalarQ[NWORDS_ORDER], k[NWORDS_ORDER] = {0}, l[NWORDS_ORDER] = {0};
digit_t kt[NWORDS_ORDER], lt[NWORDS_ORDER], f1[NWORDS_ORDER] = {0}, f2[NWORDS_ORDER] = {0}, zero[NWORDS_ORDER] = {0}, tpFdiv2[NWORDS_ORDER] = {0}, tpF[NWORDS_ORDER] = {0};
printf("\n--------------------------------------------------------------------------------------------------------\n\n");
printf("Testing dlog functions: \n\n");
// dlog2 testing
passed = 1;
fp2_tomont(&P.x, &xP2);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_tomont(&Q.x, &xQ2);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
fp2_tomont(&PQ.x, &xPQ2);
fp_mont_setone(PQ.z.re);
fp_set(PQ.z.im, 0);
AC.C.re[0] = 0x01;
fp_copy(f1, TWOpFm1);
fp_copy(f2, TWOpF);
fp2_tomont(&AC.C, &AC.C);
copy_point(&PQ2.P, &P);
copy_point(&PQ2.Q, &Q);
copy_point(&PQ2.PmQ, &PQ);
k[0] = 0xFFFFFFFFFFFFFFFF;
k[1] = 0x00000000000007FF;
l[0] = 0xFFFFFFFFFFFFFFFE;
l[1] = 0x00000000000007FF;
for (int n = 0; n < TEST_LOOPS; n++)
{
k[0] -= 1;
l[0] -= 2;
xDBLMUL(&R, &P, k, &Q, l, &PQ, &AC);
ec_dlog_2(scalarP, scalarQ, &PQ2, &R, &AC);
memcpy(kt, k, NWORDS_ORDER*RADIX/8);
memcpy(lt, l, NWORDS_ORDER*RADIX/8);
if (compare_words(k, f1, NWORDS_ORDER) == 1 ||
(compare_words(l, f1, NWORDS_ORDER) == 1 && (compare_words(k, zero, NWORDS_ORDER) == 0 || compare_words(k, f1, NWORDS_ORDER) == 0))) {
if (compare_words(k, zero, NWORDS_ORDER) != 0) {
sub_test(kt, f2, kt, NWORDS_ORDER);
}
if (compare_words(l, zero, NWORDS_ORDER) != 0) {
sub_test(lt, f2, lt, NWORDS_ORDER);
}
}
if (compare_words((digit_t*)scalarP, (digit_t*)kt, NWORDS_ORDER) != 0 || compare_words((digit_t*)scalarQ, (digit_t*)lt, NWORDS_ORDER) != 0) { passed = 0; break; }
}
if (passed == 1) printf(" dlog2 tests ..................................................... PASSED");
else { printf(" dlog2 tests... FAILED"); printf("\n"); return false; }
printf("\n");
// dlog3 testing
passed = 1;
fp2_tomont(&P.x, &xP3);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_tomont(&Q.x, &xQ3);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
fp2_tomont(&PQ.x, &xPQ3);
fp_mont_setone(PQ.z.re);
fp_set(PQ.z.im, 0);
AC.C.re[0] = 0x01;
fp_copy(tpFdiv2, THREEpFdiv2);
fp_copy(tpF, THREEpF);
fp2_tomont(&AC.C, &AC.C);
copy_point(&PQ2.P, &P);
copy_point(&PQ2.Q, &Q);
copy_point(&PQ2.PmQ, &PQ);
k[1] = 0;
l[1] = 0;
k[0] = 0x02153E468B91C6D1;
l[0] = 0x02153E468B91C6D0;
for (int n = 0; n < TEST_LOOPS; n++)
{
k[0] -= 1;
l[0] -= 2;
xDBLMUL(&R, &P, k, &Q, l, &PQ, &AC);
ec_dlog_3(scalarP, scalarQ, &PQ2, &R, &AC);
memcpy(kt, k, NWORDS_ORDER*RADIX/8);
memcpy(lt, l, NWORDS_ORDER*RADIX/8);
if (compare_words(k, tpFdiv2, NWORDS_ORDER) == 1 ||
(compare_words(l, tpFdiv2, NWORDS_ORDER) == 1 && compare_words(k, zero, NWORDS_ORDER) == 0)) {
if (compare_words(k, zero, NWORDS_ORDER) != 0) {
sub_test(kt, tpF, kt, NWORDS_ORDER);
}
if (compare_words(l, zero, NWORDS_ORDER) != 0) {
sub_test(lt, tpF, lt, NWORDS_ORDER);
}
}
if (compare_words((digit_t*)scalarP, (digit_t*)kt, NWORDS_ORDER) != 0 || compare_words((digit_t*)scalarQ, (digit_t*)lt, NWORDS_ORDER) != 0) { passed = 0; break; }
}
if (passed == 1) printf(" dlog3 tests ..................................................... PASSED");
else { printf(" dlog3 tests... FAILED"); printf("\n"); return false; }
printf("\n");
return OK;
}
bool ec_run()
{
bool OK = true;
int n;
unsigned long long cycles, cycles1, cycles2;
ec_point_t P, Q, R, PQ, AC;
digit_t k[NWORDS_ORDER], l[NWORDS_ORDER];
printf("\n--------------------------------------------------------------------------------------------------------\n\n");
printf("Benchmarking ecc arithmetic: \n\n");
// Point doubling
cycles = 0;
for (n=0; n<BENCH_LOOPS; n++)
{
cycles1 = cpucycles();
xDBL(&Q, &P, &AC);
cycles2 = cpucycles();
cycles = cycles+(cycles2-cycles1);
}
printf(" Montgomery x-only doubling runs in .............................. %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
// Point addition
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
cycles1 = cpucycles();
xADD(&R, &Q, &P, &PQ);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" Montgomery x-only addition runs in .............................. %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
// Point multiplication
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
cycles1 = cpucycles();
xMUL(&Q, &P, k, (ec_curve_t*)&AC);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" Montgomery x-only scalar multiplication runs in ................. %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
// Point multiplication
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
cycles1 = cpucycles();
xDBLMUL(&R, &P, k, &Q, l, &PQ, (ec_curve_t*)&AC);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" Montgomery x-only double-scalar multiplication runs in .......... %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
return OK;
}
bool dlog_run()
{
bool OK = true;
int n;
unsigned long long cycles, cycles1, cycles2;
ec_point_t P = {0}, Q = {0}, R = {0}, S = {0}, SS = {0}, PQ = {0};
ec_curve_t AC = {0};
ec_basis_t PQ2;
digit_t scalarP[NWORDS_ORDER], scalarQ[NWORDS_ORDER], k[NWORDS_ORDER] = {0}, l[NWORDS_ORDER] = {0};
printf("\n--------------------------------------------------------------------------------------------------------\n\n");
printf("Benchmarking dlog2: \n\n");
// dlog2 computation
fp2_tomont(&P.x, &xP2);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_tomont(&Q.x, &xQ2);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
fp2_tomont(&PQ.x, &xPQ2);
fp_mont_setone(PQ.z.re);
fp_set(PQ.z.im, 0);
AC.C.re[0] = 0x01;
fp2_tomont(&AC.C, &AC.C);
copy_point(&PQ2.P, &P);
copy_point(&PQ2.Q, &Q);
copy_point(&PQ2.PmQ, &PQ);
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
fprandom_test(k); fprandom_test(l);
xDBLMUL(&R, &P, k, &Q, l, &PQ, &AC);
cycles1 = cpucycles();
ec_dlog_2(scalarP, scalarQ, &PQ2, &R, &AC);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" dlog2 runs in ................................................... %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
// dlog3 computation
fp2_tomont(&P.x, &xP3);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_tomont(&Q.x, &xQ3);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
fp2_tomont(&PQ.x, &xPQ3);
fp_mont_setone(PQ.z.re);
fp_set(PQ.z.im, 0);
copy_point(&PQ2.P, &P);
copy_point(&PQ2.Q, &Q);
copy_point(&PQ2.PmQ, &PQ);
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
fprandom_test(k); fprandom_test(l);
xDBLMUL(&R, &P, k, &Q, l, &PQ, &AC);
cycles1 = cpucycles();
ec_dlog_3(scalarP, scalarQ, &PQ2, &R, &AC);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" dlog3 runs in ................................................... %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
return OK;
}
#endif

View File

@@ -0,0 +1,24 @@
#ifndef TEST_BASIS_H
#define TEST_BASIS_H
#include "fp2.h"
// Full-torsion basis for A=0 (excluding 2^f and huge prime factors)
const fp2_t xPA = {{0x7505815fb30f099e,0x89e78dbb4294c8df,0x7db9b4b1f7716d7b,0x13fcd4c87af65308},{0x93533c1017088fd4,0x6df9e398a1bb4cb1,0xc928f082be2e2b4c,0x17aa7e2906bef0af}};
const fp2_t xQA = {{0xe96336b75eb5a505,0x5640cecad0ad7b5a,0x1394f0771bc58ac1,0x18d92124656d68d9},{0xa54e8e24605754f0,0xe52de9790bbe4bb9,0x3bf9b7833f62e255,0x277a07644ec4f0e2}};
const fp2_t xPQA = {{0xc8fcceb408e3444c,0x9f8ca4d2c05c3287,0x259e496f17c0f529,0x0eb18a51c2a3dd1a},{0x1014dbe2534b8310,0x6b035ee3c371ea12,0x8354ecb4c111db6d,0x178259b78fe08093}};
const fp2_t xPB = {{0xbd0a2f0c9a5378ca,0x74af17405042203d,0x0ccdcb4b7f0b8c15,0x314c70951a92d8bf},{0xe889e6bc5f9842af,0xefb0edbb5e266ab3,0x7bfb9d05f1ba6962,0x0a5f3f4fe6f16514}};
const fp2_t xQB = {{0x137e215438caaf3b,0xc4403ee1b69f1382,0x2b5783edcefa7246,0x3015572698262f66},{0x8e88e4293f84536e,0x8d6dbc277f85ff77,0xb3f17b53b01da916,0x08dd3f4976c5dad1}};
const fp2_t xPQB = {{0xf0c2701a7050d9b9,0xc8fdb069c0234d3a,0x9ec25780f2b101a8,0x221a0565053e8ff4},{0xd8513bf6a05910ae,0x47ff2422258dfb3a,0xb98ccceae31ac407,0x21bcc8e659aaa1b3}};
// 2^f-torsion basis for A=0
const fp2_t xP2 = {{0xfc93bac7df77fd30,0xa8d37e10783215bd,0x4bd2ece4f148039b,0x2bd5b83f5f8c09fb},{0x444112970b59f12f,0x557b8b9beb55c276,0x633f97cd9464df6c,0x00a1b21b593a2dfd}};
const fp2_t xQ2 = {{0x6b4289960273222c,0xa290d8eb8e343a04,0x0c0a333f80a0ed68,0x31a58910e276aff0},{0xb7ca615ad7473865,0xeb6f72f20794f050,0x2941c3fe3203b94f,0x32ad5cbe915e467b}};
const fp2_t xPQ2 = {{0xac9f90005e47b095,0x47eafdafd5168836,0xb88aac8334acdad0,0x1a5cf52a20f665b4},{0x4baa70fb1f5fa99c,0xffb7ddb12c87f1a3,0xdd3a229d370a8484,0x1e992ad0a14baf03}};
// 3^g-torsion basis for A=0
const fp2_t xP3 = {{0x8cf496c2722f340d,0x3e329c5a507ad39c,0xa0c7caa3e4537e25,0x1371d43cf97de48e},{0xa4b94c97b8149e7d,0xd290853fa14704c7,0x158b854173c1b289,0x04c6dcda7872c23f}};
const fp2_t xQ3 = {{0x0f6380fd4c963950,0x101a22a245c4f563,0x601d3e30b21a5f43,0x0becd5f73b067949},{0xd364123c6806057e,0x8ff24fca9e060260,0x3b52df5bfb817901,0x30950462489b838f}};
const fp2_t xPQ3 = {{0xe04cab7169e64a82,0x56df573ea9295c19,0x06cbb6af8e341990,0x0f1046ca03017ca1},{0x2dac3457c35be728,0x2f59af21113f25f9,0xa0dc4f54eec2715d,0x102ecf9a7ff2f2ff}};
#endif

View File

@@ -0,0 +1,17 @@
set(SOURCE_FILES_EC_${SVARIANT_UPPER}_REF
${ECX_DIR}/poly-mul.c
${ECX_DIR}/poly-redc.c
${ECX_DIR}/ec.c
${ECX_DIR}/tedwards.c
${ECX_DIR}/kps.c
${ECX_DIR}/xisog.c
${ECX_DIR}/xeval.c
${ECX_DIR}/isog_chains.c
${ECX_DIR}/basis.c
)
add_library(${LIB_EC_${SVARIANT_UPPER}} ${SOURCE_FILES_EC_${SVARIANT_UPPER}_REF})
target_include_directories(${LIB_EC_${SVARIANT_UPPER}} PRIVATE ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${INC_PUBLIC} ${INC_GF_${SVARIANT_UPPER}} ${INC_COMMON} ${INC_EC})
target_compile_options(${LIB_EC_${SVARIANT_UPPER}} PRIVATE ${C_OPT_FLAGS})
add_subdirectory(test)

View File

@@ -0,0 +1,36 @@
add_executable(fp2.test_${SVARIANT_LOWER} ${ECX_DIR}/test/fp2-test.c)
target_include_directories(fp2.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_GF_${SVARIANT_UPPER}} ${INC_EC} ${INC_COMMON})
target_link_libraries(fp2.test_${SVARIANT_LOWER} ${LIB_GF_${SVARIANT_UPPER}})
add_executable(poly-mul.test_${SVARIANT_LOWER} ${ECX_DIR}/test/poly-mul-test.c)
target_include_directories(poly-mul.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON})
target_link_libraries(poly-mul.test_${SVARIANT_LOWER} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(poly-redc.test_${SVARIANT_LOWER} ${ECX_DIR}/test/poly-redc-test.c)
target_include_directories(poly-redc.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON})
target_link_libraries(poly-redc.test_${SVARIANT_LOWER} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(mont.test_${SVARIANT_LOWER} ${ECX_DIR}/test/mont-test.c)
target_include_directories(mont.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON} .)
target_link_libraries(mont.test_${SVARIANT_LOWER} ${LIB_PRECOMP_${SVARIANT_UPPER}} ${LIB_INTBIG} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(ec.test_${SVARIANT_LOWER} ${ECX_DIR}/test/ec-test.c ${ECX_DIR}/test/test_extras.c)
target_include_directories(ec.test_${SVARIANT_LOWER} PUBLIC ${ECX_DIR}/test ${INC_GF_${SVARIANT_UPPER}} ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON} .)
target_link_libraries(ec.test_${SVARIANT_LOWER} ${LIB_PRECOMP_${SVARIANT_UPPER}} ${LIB_INTBIG} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(velu.test_${SVARIANT_LOWER} ${ECX_DIR}/test/velu-test.c)
target_include_directories(velu.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON} .)
target_link_libraries(velu.test_${SVARIANT_LOWER} ${LIB_PRECOMP_${SVARIANT_UPPER}} ${LIB_INTBIG} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(isog.test_${SVARIANT_LOWER} ${ECX_DIR}/test/isog-test.c)
target_include_directories(isog.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON} .)
target_link_libraries(isog.test_${SVARIANT_LOWER} ${LIB_PRECOMP_${SVARIANT_UPPER}} ${LIB_INTBIG} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_test(ec_fp2.test_${SVARIANT_LOWER} fp2.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_poly-mul.test_${SVARIANT_LOWER} poly-mul.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_poly-redc.test_${SVARIANT_LOWER} poly-redc.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_mont.test_${SVARIANT_LOWER} mont.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_ec.test_${SVARIANT_LOWER} ec.test_${SVARIANT_LOWER} test ${SQISIGN_TEST_REPS})
add_test(ec_velu.test_${SVARIANT_LOWER} velu.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_isog.test_${SVARIANT_LOWER} isog.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})

View File

@@ -0,0 +1,400 @@
#ifndef EC_TESTS_H
#define EC_TESTS_H
#include "test_extras.h"
#include <stdio.h>
#include <string.h>
#include <bench.h> //////// NOTE: enable later
#include "test-basis.h"
#include "ec_params.h"
// Global constants
extern const digit_t p[NWORDS_FIELD];
// Benchmark and test parameters
static int BENCH_LOOPS = 1000; // Number of iterations per bench
static int TEST_LOOPS = 512; // Number of iterations per test
bool ec_test()
{ // Tests for ecc arithmetic
bool OK = true;
int passed;
ec_point_t P = {0}, Q = {0}, R = {0}, S = {0}, SS = {0}, PQ = {0};
ec_point_t AC = {0};
digit_t k[NWORDS_ORDER] = {0}, l[NWORDS_ORDER] = {0};
printf("\n--------------------------------------------------------------------------------------------------------\n\n");
printf("Testing ecc functions: (NOT IMPLEMENTED) \n\n");
/*
// Point doubling
passed = 1;
P.x.re[0] = 0xDFD70ED0861BD329; P.x.re[1] = 0x20ACD3758C7F5540; P.x.re[2] = 0x3DCCDC007277F80A; P.x.re[3] = 0x18D6D2A22981DCE1;
P.x.im[0] = 0x3C23730A3F08F38C; P.x.im[1] = 0x98BB973AFD3D954D; P.x.im[2] = 0x8D98ADFC2829AE8A; P.x.im[3] = 0x21A2464D6369AFBA;
P.z.re[0] = 0x01;
AC.z.re[0] = 0x01;
fp2_tomont(&AC.z, &AC.z);
fp2_tomont(&R.x, &P.x);
fp2_tomont(&R.z, &P.z);
xDBL(&S, &R, &AC);
fp2_copy(&SS.x, &S.x); // Copy of S = SS <- 2P
fp2_copy(&SS.z, &S.z);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0x5950EE0A4AF90FC8; R.x.re[1] = 0x16488065A0A98B08; R.x.re[2] = 0xCE65322229DA0FD1; R.x.re[3] = 0x270A35FF781EE204;
R.x.im[0] = 0x564447FD9EC57F6B; R.x.im[1] = 0x2EE24E984294F729; R.x.im[2] = 0x53A6C7360E972C71; R.x.im[3] = 0x4FCF4B9928A7C7E;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2)!=0) { passed=0; goto out0; }
Q.x.re[0] = 0xC46076A670C70053; Q.x.re[1] = 0x97517AFA3AB9ED13; Q.x.re[2] = 0x349644C942EDF993; Q.x.re[3] = 0xBB4A4DB6F29AF9E;
Q.x.im[0] = 0x8B47629FB5A15BB0; Q.x.im[1] = 0x4EC6E809953C1A10; Q.x.im[2] = 0x1F83F0EC6CBB84D6; Q.x.im[3] = 0x1D8417C1D33265D3;
Q.z.re[0] = 0x01;
PQ.x.re[0] = 0x853F66D11BE5534F; PQ.x.re[1] = 0x27C8FD4E52D03D4A; PQ.x.re[2] = 0xF88EA78D0A0C29D2; PQ.x.re[3] = 0x2F6DFB07D397A067;
PQ.x.im[0] = 0xE8DBC4AA34434BA1; PQ.x.im[1] = 0x7A73AE182636F8A0; PQ.x.im[2] = 0x419EC260137868EB; PQ.x.im[3] = 0x129B3E301703D43F;
PQ.z.re[0] = 0x01;
fp2_tomont(&S.x, &Q.x);
fp2_tomont(&S.z, &Q.z);
fp2_tomont(&PQ.x, &PQ.x);
fp2_tomont(&PQ.z, &PQ.z);
xADD(&S, &SS, &S, &PQ);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0xED0BEB8F93AB4FF9; R.x.re[1] = 0x27CF508B80CD49BF; R.x.re[2] = 0x38A6134DFA04B2BA; R.x.re[3] = 0x27B4CB15E109EF1F;
R.x.im[0] = 0x6F731BA6FD227BDE; R.x.im[1] = 0x14C12335341167F8; R.x.im[2] = 0xECA7B60F7866E27A; R.x.im[3] = 0x2A7A79A152880457;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2) != 0) { passed = 0; goto out0; }
fp2_tomont(&R.x, &P.x);
fp2_tomont(&R.z, &P.z);
k[0] = 126;
xMUL(&S, &R, k, (ec_curve_t*)&AC);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0xDE80F87A1203A147; R.x.re[1] = 0xD59E1215928A3B2D; R.x.re[2] = 0xD5A67F83A5A8CE46; R.x.re[3] = 0xA11E162488C9CDF;
R.x.im[0] = 0x9417D0D79A26741B; R.x.im[1] = 0x8B1F47D6F0FE5EEC; R.x.im[2] = 0xE52188DCB054CE36; R.x.im[3] = 0x1A8075A6C3148AB3;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2) != 0) { passed = 0; goto out0; }
fp2_tomont(&R.x, &P.x);
fp2_tomont(&R.z, &P.z);
k[0] = 0xE77AD6B6C6B2D8CD;
k[1] = 0xDE43A0B600F38D12;
k[2] = 0xA35F4A7897E17CE2;
k[3] = 0x10ACB62E614D1237;
xMUL(&S, &R, k, (ec_curve_t*)&AC);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0xD3938B0A68A3E7C0; R.x.re[1] = 0xE0667113208A0595; R.x.re[2] = 0x258F314C84E9CB60; R.x.re[3] = 0x14984BA7CA59AB71;
R.x.im[0] = 0xFE728423EE3BFEF4; R.x.im[1] = 0xBF68C42FE21AE0E4; R.x.im[2] = 0xA8FAF9C9528609CA; R.x.im[3] = 0x1225EC77A1DC0285;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2) != 0) { passed = 0; goto out0; }
fp2_tomont(&R.x, &Q.x);
fp2_tomont(&R.z, &Q.z);
k[0] = 0xE77AD6B6C6B2D8CD;
k[1] = 0xDE43A0B600F38D12;
k[2] = 0xA35F4A7897E17CE2;
k[3] = 0x10ACB62E614D1237;
l[0] = 0x34AB78B6C6B2D8C0;
l[1] = 0xDE6B2D8CD00F38D1;
l[2] = 0xA35F4A7897E17CE2;
l[3] = 0x20ACF4A789614D13;
fp2_inv(&SS.z);
fp2_mul(&SS.x, &SS.x, &SS.z);
fp2_copy(&SS.z, &R.z);
xDBLMUL(&S, &R, k, &SS, l, &PQ, (ec_curve_t*)&AC);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0x554E1ADC609B992F; R.x.re[1] = 0xE407D961F8CC4C42; R.x.re[2] = 0x1CF626AFED5A68CE; R.x.re[3] = 0x6D02692EE110483;
R.x.im[0] = 0x16FB094E831C8997; R.x.im[1] = 0xFDE4ECF31DC5F702; R.x.im[2] = 0x89303D868DFAD7B4; R.x.im[3] = 0xC91ACE81346F22D;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2) != 0) { passed = 0; goto out0; }
out0:
if (passed==1) printf(" ECC arithmetic tests ............................................ PASSED");
else { printf(" ECC arithmetic tests... FAILED"); printf("\n"); return false; }
printf("\n");
*/
return OK;
}
bool dlog_test()
{ // Tests for dlog
bool OK = true;
int passed;
ec_point_t P = {0}, Q = {0}, R = {0}, S = {0}, SS = {0}, PQ = {0};
ec_curve_t AC = {0};
ec_basis_t PQ2;
digit_t scalarP[NWORDS_ORDER], scalarQ[NWORDS_ORDER], k[NWORDS_ORDER] = {0}, l[NWORDS_ORDER] = {0};
digit_t kt[NWORDS_ORDER], lt[NWORDS_ORDER], f1[NWORDS_ORDER] = {0}, f2[NWORDS_ORDER] = {0}, zero[NWORDS_ORDER] = {0}, tpFdiv2[NWORDS_ORDER] = {0}, tpF[NWORDS_ORDER] = {0};
printf("\n--------------------------------------------------------------------------------------------------------\n\n");
printf("Testing dlog functions: \n\n");
// dlog2 testing
passed = 1;
fp2_tomont(&P.x, &xP2);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_tomont(&Q.x, &xQ2);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
fp2_tomont(&PQ.x, &xPQ2);
fp_mont_setone(PQ.z.re);
fp_set(PQ.z.im, 0);
AC.C.re[0] = 0x01;
fp_copy(f1, TWOpFm1);
fp_copy(f2, TWOpF);
fp2_tomont(&AC.C, &AC.C);
copy_point(&PQ2.P, &P);
copy_point(&PQ2.Q, &Q);
copy_point(&PQ2.PmQ, &PQ);
k[0] = 0xFFFFFFFFFFFFFFFF;
k[1] = 0x00000000000007FF;
l[0] = 0xFFFFFFFFFFFFFFFE;
l[1] = 0x00000000000007FF;
for (int n = 0; n < TEST_LOOPS; n++)
{
k[0] -= 1;
l[0] -= 2;
xDBLMUL(&R, &P, k, &Q, l, &PQ, &AC);
ec_dlog_2(scalarP, scalarQ, &PQ2, &R, &AC);
memcpy(kt, k, NWORDS_ORDER*RADIX/8);
memcpy(lt, l, NWORDS_ORDER*RADIX/8);
if (compare_words(k, f1, NWORDS_ORDER) == 1 ||
(compare_words(l, f1, NWORDS_ORDER) == 1 && (compare_words(k, zero, NWORDS_ORDER) == 0 || compare_words(k, f1, NWORDS_ORDER) == 0))) {
if (compare_words(k, zero, NWORDS_ORDER) != 0) {
sub_test(kt, f2, kt, NWORDS_ORDER);
}
if (compare_words(l, zero, NWORDS_ORDER) != 0) {
sub_test(lt, f2, lt, NWORDS_ORDER);
}
}
if (compare_words((digit_t*)scalarP, (digit_t*)kt, NWORDS_ORDER) != 0 || compare_words((digit_t*)scalarQ, (digit_t*)lt, NWORDS_ORDER) != 0) { passed = 0; break; }
}
if (passed == 1) printf(" dlog2 tests ..................................................... PASSED");
else { printf(" dlog2 tests... FAILED"); printf("\n"); return false; }
printf("\n");
// dlog3 testing
passed = 1;
fp2_tomont(&P.x, &xP3);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_tomont(&Q.x, &xQ3);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
fp2_tomont(&PQ.x, &xPQ3);
fp_mont_setone(PQ.z.re);
fp_set(PQ.z.im, 0);
AC.C.re[0] = 0x01;
fp_copy(tpFdiv2, THREEpFdiv2);
fp_copy(tpF, THREEpF);
fp2_tomont(&AC.C, &AC.C);
copy_point(&PQ2.P, &P);
copy_point(&PQ2.Q, &Q);
copy_point(&PQ2.PmQ, &PQ);
k[1] = 0;
l[1] = 0;
k[0] = 0x02153E468B91C6D1;
l[0] = 0x02153E468B91C6D0;
for (int n = 0; n < TEST_LOOPS; n++)
{
k[0] -= 1;
l[0] -= 2;
xDBLMUL(&R, &P, k, &Q, l, &PQ, &AC);
ec_dlog_3(scalarP, scalarQ, &PQ2, &R, &AC);
memcpy(kt, k, NWORDS_ORDER*RADIX/8);
memcpy(lt, l, NWORDS_ORDER*RADIX/8);
if (compare_words(k, tpFdiv2, NWORDS_ORDER) == 1 ||
(compare_words(l, tpFdiv2, NWORDS_ORDER) == 1 && compare_words(k, zero, NWORDS_ORDER) == 0)) {
if (compare_words(k, zero, NWORDS_ORDER) != 0) {
sub_test(kt, tpF, kt, NWORDS_ORDER);
}
if (compare_words(l, zero, NWORDS_ORDER) != 0) {
sub_test(lt, tpF, lt, NWORDS_ORDER);
}
}
if (compare_words((digit_t*)scalarP, (digit_t*)kt, NWORDS_ORDER) != 0 || compare_words((digit_t*)scalarQ, (digit_t*)lt, NWORDS_ORDER) != 0) { passed = 0; break; }
}
if (passed == 1) printf(" dlog3 tests ..................................................... PASSED");
else { printf(" dlog3 tests... FAILED"); printf("\n"); return false; }
printf("\n");
return OK;
}
bool ec_run()
{
bool OK = true;
int n;
unsigned long long cycles, cycles1, cycles2;
ec_point_t P, Q, R, PQ, AC;
digit_t k[NWORDS_ORDER], l[NWORDS_ORDER];
printf("\n--------------------------------------------------------------------------------------------------------\n\n");
printf("Benchmarking ecc arithmetic: \n\n");
// Point doubling
cycles = 0;
for (n=0; n<BENCH_LOOPS; n++)
{
cycles1 = cpucycles();
xDBL(&Q, &P, &AC);
cycles2 = cpucycles();
cycles = cycles+(cycles2-cycles1);
}
printf(" Montgomery x-only doubling runs in .............................. %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
// Point addition
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
cycles1 = cpucycles();
xADD(&R, &Q, &P, &PQ);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" Montgomery x-only addition runs in .............................. %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
// Point multiplication
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
cycles1 = cpucycles();
xMUL(&Q, &P, k, (ec_curve_t*)&AC);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" Montgomery x-only scalar multiplication runs in ................. %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
// Point multiplication
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
cycles1 = cpucycles();
xDBLMUL(&R, &P, k, &Q, l, &PQ, (ec_curve_t*)&AC);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" Montgomery x-only double-scalar multiplication runs in .......... %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
return OK;
}
bool dlog_run()
{
bool OK = true;
int n;
unsigned long long cycles, cycles1, cycles2;
ec_point_t P = {0}, Q = {0}, R = {0}, S = {0}, SS = {0}, PQ = {0};
ec_curve_t AC = {0};
ec_basis_t PQ2;
digit_t scalarP[NWORDS_ORDER], scalarQ[NWORDS_ORDER], k[NWORDS_ORDER] = {0}, l[NWORDS_ORDER] = {0};
printf("\n--------------------------------------------------------------------------------------------------------\n\n");
printf("Benchmarking dlog2: \n\n");
// dlog2 computation
fp2_tomont(&P.x, &xP2);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_tomont(&Q.x, &xQ2);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
fp2_tomont(&PQ.x, &xPQ2);
fp_mont_setone(PQ.z.re);
fp_set(PQ.z.im, 0);
AC.C.re[0] = 0x01;
fp2_tomont(&AC.C, &AC.C);
copy_point(&PQ2.P, &P);
copy_point(&PQ2.Q, &Q);
copy_point(&PQ2.PmQ, &PQ);
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
fprandom_test(k); fprandom_test(l);
xDBLMUL(&R, &P, k, &Q, l, &PQ, &AC);
cycles1 = cpucycles();
ec_dlog_2(scalarP, scalarQ, &PQ2, &R, &AC);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" dlog2 runs in ................................................... %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
// dlog3 computation
fp2_tomont(&P.x, &xP3);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_tomont(&Q.x, &xQ3);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
fp2_tomont(&PQ.x, &xPQ3);
fp_mont_setone(PQ.z.re);
fp_set(PQ.z.im, 0);
copy_point(&PQ2.P, &P);
copy_point(&PQ2.Q, &Q);
copy_point(&PQ2.PmQ, &PQ);
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
fprandom_test(k); fprandom_test(l);
xDBLMUL(&R, &P, k, &Q, l, &PQ, &AC);
cycles1 = cpucycles();
ec_dlog_3(scalarP, scalarQ, &PQ2, &R, &AC);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" dlog3 runs in ................................................... %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
return OK;
}
#endif

View File

@@ -0,0 +1,24 @@
#ifndef TEST_BASIS_H
#define TEST_BASIS_H
#include "fp2.h"
// Full-torsion basis for A=0 (excluding 2^f and huge prime factors)
const fp2_t xPA = {{0x35b53c72e7494775,0x5791b499bc29710d,0x2060f3aca68fa4ff,0x81150c19a14f523a,0x08af6c81a906d44a,0x00cca2a93efb536e},{0x14eaac356375af76,0x5655011e771be3b4,0x6273ccee274d7754,0x440d6b5b4496c183,0xa3d7f80e9f9111ba,0x0302e153bee01a18}};
const fp2_t xQA = {{0x80c0767d1b7b5fd8,0x24e9039d430ca3b5,0x26485254625dc85a,0x612eaebc345b64d1,0x59669fbd946a4409,0x004c3a8564e16101},{0x0e1eac4e38449c54,0x752c042b4c6675cb,0x88ec0e75c8e9ea0e,0xbf7c4cdbfc4483f0,0xd594cb5474bbc264,0x02f5e2345a9b4654}};
const fp2_t xPQA = {{0x1f5accaff9a7da90,0x91884964774d4cb2,0x0e938e13dd088e63,0x453c9af09879a724,0xb2bd09ec3740312b,0x0007a5837e23aaa1},{0x8e1ac4b319787bd4,0x7cb9fba402f67bfe,0x370b2951f9ec29cf,0x7a020172566f9d17,0x063e31753d703130,0x01551136265bade6}};
const fp2_t xPB = {{0xb702a70a8ae132ad,0x56d8804c83a8e696,0x5ac3e12f4df1792e,0x0a89da435664746e,0xd8758765206844bd,0x01a92f6e9e0e9296},{0x8aaab711b76b0959,0x210e6695ca5e5fdd,0x593be0d75909ca12,0xfbc074d8ebdeb927,0xb61fcc328d3756bc,0x0198a5942855c8bf}};
const fp2_t xQB = {{0x2b6b82b950b61fda,0x0ef2dd717daed334,0x99dee4db0b268ac9,0x3534eb384e1fcaf0,0xbaf112845a4f2d81,0x037f1492d8d815a1},{0x97e80590f9a0556b,0x7d9b4b87a22a7792,0xda4534fe75595b4b,0xbe1092a2733c03e1,0xbf5b1bd147b0d630,0x0125721476e5267f}};
const fp2_t xPQB = {{0xb7d459a56d4aebec,0x6ac7f10ba20e1e71,0x9a95a8928507f7ef,0xc4c5aff6b97f3dfe,0x644beb3e86806b77,0x022319eb6eaf072a},{0x8ad0f6b18934790e,0xdad82b7b38e166bf,0xcb08f5a3ab53d9a9,0xd2ff39b401ba8aba,0xbff9b5e40ed9e5ce,0x03c1773791f554c0}};
// 2^f-torsion basis for A=0
const fp2_t xP2 = {{0x7a26fdb0e5844206,0x0752b2ba140f7dfd,0x1728013f8f5fe257,0xd05f129975ed6bba,0xe736dbce707ad5a8,0x01f861715896d0be},{0xdac046927a0c5352,0x5a42474ac156ff18,0xe887982ff4c5a9ea,0x3875be6432251f1c,0xdfae47315af877ee,0x005627f085582ecc}};
const fp2_t xQ2 = {{0xc4f03ab3db57331b,0xf04261fc3b713778,0xa99b82430c7e40d1,0x5fe52b1324c2a091,0xfcaa2a7049d0f657,0x021f2caa09302141},{0x4a92a1d5ff9f6730,0x6dcd5f600f33783e,0xdb8b4e2e5149b45e,0x993458635c01d0c0,0x5f9bc7d3bb307f91,0x01fcc7eae4712b6a}};
const fp2_t xPQ2 = {{0x7f4ee9c86c4341a2,0x0c867f482063bdfc,0xe46fb7b0fbd479c7,0xddaa716e091be9ad,0x29239eadddf5dc59,0x0231c09c660f0a89},{0xde64fa344dd64237,0xa89aaaed3dd84555,0xbb70924d8fb73f27,0x0869ec018b3366dc,0x47a0356ce742bcbc,0x00547dbda6dc094d}};
// 3^g-torsion basis for A==0
const fp2_t xP3 = {{0x7c878d0ceaa821f0,0xf94db4cab7186625,0x7cff6d5fb0ca7867,0x4e3f5bd19cbca9d6,0x05ec8273d0042548,0x0233a79cf87040b3},{0x060e9f3dcab8192c,0xa94e86d063a46398,0x0e5cc403bfb60867,0x3ea1277f98087283,0xaff1fd95bb094917,0x025041b12719d3b8}};
const fp2_t xQ3 = {{0xb25aaa192bd351b7,0xc5db1962aed7e543,0x1f722ab174319947,0xd1c9bb4a0a5d8aa3,0x351415ec64f88921,0x0288ae044d62c930},{0xb41ede1724f8e06a,0xfb10ce5a83c66629,0x9846173e31a9d448,0x35c94966192f08db,0x72f7252946af3f9c,0x02ea05c971e7b34c}};
const fp2_t xPQ3 = {{0x674703cc3134d90b,0x507e338e496b8f75,0x0c8cb1f138346e4c,0x54cb7ad5ba580da7,0x65750f0bcd0a9857,0x038b435f51669e87},{0xdcdc0116c67589a0,0x45ce94f4d345c827,0x0f2cbfb3c53b73ea,0x03e7951bc98efbb8,0x3335ad0991864858,0x01e151a64210f74f}};
#endif

View File

@@ -0,0 +1,17 @@
set(SOURCE_FILES_EC_${SVARIANT_UPPER}_REF
${ECX_DIR}/poly-mul.c
${ECX_DIR}/poly-redc.c
${ECX_DIR}/ec.c
${ECX_DIR}/tedwards.c
${ECX_DIR}/kps.c
${ECX_DIR}/xisog.c
${ECX_DIR}/xeval.c
${ECX_DIR}/isog_chains.c
${ECX_DIR}/basis.c
)
add_library(${LIB_EC_${SVARIANT_UPPER}} ${SOURCE_FILES_EC_${SVARIANT_UPPER}_REF})
target_include_directories(${LIB_EC_${SVARIANT_UPPER}} PRIVATE ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${INC_PUBLIC} ${INC_GF_${SVARIANT_UPPER}} ${INC_COMMON} ${INC_EC})
target_compile_options(${LIB_EC_${SVARIANT_UPPER}} PRIVATE ${C_OPT_FLAGS})
add_subdirectory(test)

View File

@@ -0,0 +1,36 @@
add_executable(fp2.test_${SVARIANT_LOWER} ${ECX_DIR}/test/fp2-test.c)
target_include_directories(fp2.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_GF_${SVARIANT_UPPER}} ${INC_EC} ${INC_COMMON})
target_link_libraries(fp2.test_${SVARIANT_LOWER} ${LIB_GF_${SVARIANT_UPPER}})
add_executable(poly-mul.test_${SVARIANT_LOWER} ${ECX_DIR}/test/poly-mul-test.c)
target_include_directories(poly-mul.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON})
target_link_libraries(poly-mul.test_${SVARIANT_LOWER} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(poly-redc.test_${SVARIANT_LOWER} ${ECX_DIR}/test/poly-redc-test.c)
target_include_directories(poly-redc.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON})
target_link_libraries(poly-redc.test_${SVARIANT_LOWER} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(mont.test_${SVARIANT_LOWER} ${ECX_DIR}/test/mont-test.c)
target_include_directories(mont.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON} .)
target_link_libraries(mont.test_${SVARIANT_LOWER} ${LIB_PRECOMP_${SVARIANT_UPPER}} ${LIB_INTBIG} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(ec.test_${SVARIANT_LOWER} ${ECX_DIR}/test/ec-test.c ${ECX_DIR}/test/test_extras.c)
target_include_directories(ec.test_${SVARIANT_LOWER} PUBLIC ${ECX_DIR}/test ${INC_GF_${SVARIANT_UPPER}} ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON} .)
target_link_libraries(ec.test_${SVARIANT_LOWER} ${LIB_PRECOMP_${SVARIANT_UPPER}} ${LIB_INTBIG} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(velu.test_${SVARIANT_LOWER} ${ECX_DIR}/test/velu-test.c)
target_include_directories(velu.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON} .)
target_link_libraries(velu.test_${SVARIANT_LOWER} ${LIB_PRECOMP_${SVARIANT_UPPER}} ${LIB_INTBIG} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_executable(isog.test_${SVARIANT_LOWER} ${ECX_DIR}/test/isog-test.c)
target_include_directories(isog.test_${SVARIANT_LOWER} PUBLIC ${INC_GF_${SVARIANT_UPPER}} ${INC_INTBIG} ${INC_PRECOMP_${SVARIANT_UPPER}} ${PROJECT_SOURCE_DIR}/include ../include ${INC_EC} ${INC_COMMON} .)
target_link_libraries(isog.test_${SVARIANT_LOWER} ${LIB_PRECOMP_${SVARIANT_UPPER}} ${LIB_INTBIG} ${LIB_GF_${SVARIANT_UPPER}} ${LIB_EC_${SVARIANT_UPPER}})
add_test(ec_fp2.test_${SVARIANT_LOWER} fp2.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_poly-mul.test_${SVARIANT_LOWER} poly-mul.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_poly-redc.test_${SVARIANT_LOWER} poly-redc.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_mont.test_${SVARIANT_LOWER} mont.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_ec.test_${SVARIANT_LOWER} ec.test_${SVARIANT_LOWER} test ${SQISIGN_TEST_REPS})
add_test(ec_velu.test_${SVARIANT_LOWER} velu.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})
add_test(ec_isog.test_${SVARIANT_LOWER} isog.test_${SVARIANT_LOWER} ${SQISIGN_TEST_REPS})

View File

@@ -0,0 +1,400 @@
#ifndef EC_TESTS_H
#define EC_TESTS_H
#include "test_extras.h"
#include <stdio.h>
#include <string.h>
#include <bench.h> //////// NOTE: enable later
#include "test-basis.h"
#include "ec_params.h"
// Global constants
extern const digit_t p[NWORDS_FIELD];
// Benchmark and test parameters
static int BENCH_LOOPS = 1000; // Number of iterations per bench
static int TEST_LOOPS = 512; // Number of iterations per test
bool ec_test()
{ // Tests for ecc arithmetic
bool OK = true;
int passed;
ec_point_t P = {0}, Q = {0}, R = {0}, S = {0}, SS = {0}, PQ = {0};
ec_point_t AC = {0};
digit_t k[NWORDS_ORDER] = {0}, l[NWORDS_ORDER] = {0};
printf("\n--------------------------------------------------------------------------------------------------------\n\n");
printf("Testing ecc functions: (NOT IMPLEMENTED) \n\n");
/*
// Point doubling
passed = 1;
P.x.re[0] = 0xDFD70ED0861BD329; P.x.re[1] = 0x20ACD3758C7F5540; P.x.re[2] = 0x3DCCDC007277F80A; P.x.re[3] = 0x18D6D2A22981DCE1;
P.x.im[0] = 0x3C23730A3F08F38C; P.x.im[1] = 0x98BB973AFD3D954D; P.x.im[2] = 0x8D98ADFC2829AE8A; P.x.im[3] = 0x21A2464D6369AFBA;
P.z.re[0] = 0x01;
AC.z.re[0] = 0x01;
fp2_tomont(&AC.z, &AC.z);
fp2_tomont(&R.x, &P.x);
fp2_tomont(&R.z, &P.z);
xDBL(&S, &R, &AC);
fp2_copy(&SS.x, &S.x); // Copy of S = SS <- 2P
fp2_copy(&SS.z, &S.z);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0x5950EE0A4AF90FC8; R.x.re[1] = 0x16488065A0A98B08; R.x.re[2] = 0xCE65322229DA0FD1; R.x.re[3] = 0x270A35FF781EE204;
R.x.im[0] = 0x564447FD9EC57F6B; R.x.im[1] = 0x2EE24E984294F729; R.x.im[2] = 0x53A6C7360E972C71; R.x.im[3] = 0x4FCF4B9928A7C7E;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2)!=0) { passed=0; goto out0; }
Q.x.re[0] = 0xC46076A670C70053; Q.x.re[1] = 0x97517AFA3AB9ED13; Q.x.re[2] = 0x349644C942EDF993; Q.x.re[3] = 0xBB4A4DB6F29AF9E;
Q.x.im[0] = 0x8B47629FB5A15BB0; Q.x.im[1] = 0x4EC6E809953C1A10; Q.x.im[2] = 0x1F83F0EC6CBB84D6; Q.x.im[3] = 0x1D8417C1D33265D3;
Q.z.re[0] = 0x01;
PQ.x.re[0] = 0x853F66D11BE5534F; PQ.x.re[1] = 0x27C8FD4E52D03D4A; PQ.x.re[2] = 0xF88EA78D0A0C29D2; PQ.x.re[3] = 0x2F6DFB07D397A067;
PQ.x.im[0] = 0xE8DBC4AA34434BA1; PQ.x.im[1] = 0x7A73AE182636F8A0; PQ.x.im[2] = 0x419EC260137868EB; PQ.x.im[3] = 0x129B3E301703D43F;
PQ.z.re[0] = 0x01;
fp2_tomont(&S.x, &Q.x);
fp2_tomont(&S.z, &Q.z);
fp2_tomont(&PQ.x, &PQ.x);
fp2_tomont(&PQ.z, &PQ.z);
xADD(&S, &SS, &S, &PQ);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0xED0BEB8F93AB4FF9; R.x.re[1] = 0x27CF508B80CD49BF; R.x.re[2] = 0x38A6134DFA04B2BA; R.x.re[3] = 0x27B4CB15E109EF1F;
R.x.im[0] = 0x6F731BA6FD227BDE; R.x.im[1] = 0x14C12335341167F8; R.x.im[2] = 0xECA7B60F7866E27A; R.x.im[3] = 0x2A7A79A152880457;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2) != 0) { passed = 0; goto out0; }
fp2_tomont(&R.x, &P.x);
fp2_tomont(&R.z, &P.z);
k[0] = 126;
xMUL(&S, &R, k, (ec_curve_t*)&AC);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0xDE80F87A1203A147; R.x.re[1] = 0xD59E1215928A3B2D; R.x.re[2] = 0xD5A67F83A5A8CE46; R.x.re[3] = 0xA11E162488C9CDF;
R.x.im[0] = 0x9417D0D79A26741B; R.x.im[1] = 0x8B1F47D6F0FE5EEC; R.x.im[2] = 0xE52188DCB054CE36; R.x.im[3] = 0x1A8075A6C3148AB3;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2) != 0) { passed = 0; goto out0; }
fp2_tomont(&R.x, &P.x);
fp2_tomont(&R.z, &P.z);
k[0] = 0xE77AD6B6C6B2D8CD;
k[1] = 0xDE43A0B600F38D12;
k[2] = 0xA35F4A7897E17CE2;
k[3] = 0x10ACB62E614D1237;
xMUL(&S, &R, k, (ec_curve_t*)&AC);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0xD3938B0A68A3E7C0; R.x.re[1] = 0xE0667113208A0595; R.x.re[2] = 0x258F314C84E9CB60; R.x.re[3] = 0x14984BA7CA59AB71;
R.x.im[0] = 0xFE728423EE3BFEF4; R.x.im[1] = 0xBF68C42FE21AE0E4; R.x.im[2] = 0xA8FAF9C9528609CA; R.x.im[3] = 0x1225EC77A1DC0285;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2) != 0) { passed = 0; goto out0; }
fp2_tomont(&R.x, &Q.x);
fp2_tomont(&R.z, &Q.z);
k[0] = 0xE77AD6B6C6B2D8CD;
k[1] = 0xDE43A0B600F38D12;
k[2] = 0xA35F4A7897E17CE2;
k[3] = 0x10ACB62E614D1237;
l[0] = 0x34AB78B6C6B2D8C0;
l[1] = 0xDE6B2D8CD00F38D1;
l[2] = 0xA35F4A7897E17CE2;
l[3] = 0x20ACF4A789614D13;
fp2_inv(&SS.z);
fp2_mul(&SS.x, &SS.x, &SS.z);
fp2_copy(&SS.z, &R.z);
xDBLMUL(&S, &R, k, &SS, l, &PQ, (ec_curve_t*)&AC);
fp2_inv(&S.z);
fp2_mul(&S.x, &S.x, &S.z);
fp2_frommont(&S.x, &S.x);
R.x.re[0] = 0x554E1ADC609B992F; R.x.re[1] = 0xE407D961F8CC4C42; R.x.re[2] = 0x1CF626AFED5A68CE; R.x.re[3] = 0x6D02692EE110483;
R.x.im[0] = 0x16FB094E831C8997; R.x.im[1] = 0xFDE4ECF31DC5F702; R.x.im[2] = 0x89303D868DFAD7B4; R.x.im[3] = 0xC91ACE81346F22D;
if (compare_words((digit_t*)&R.x, (digit_t*)&S.x, NWORDS_FIELD*2) != 0) { passed = 0; goto out0; }
out0:
if (passed==1) printf(" ECC arithmetic tests ............................................ PASSED");
else { printf(" ECC arithmetic tests... FAILED"); printf("\n"); return false; }
printf("\n");
*/
return OK;
}
bool dlog_test()
{ // Tests for dlog
bool OK = true;
int passed;
ec_point_t P = {0}, Q = {0}, R = {0}, S = {0}, SS = {0}, PQ = {0};
ec_curve_t AC = {0};
ec_basis_t PQ2;
digit_t scalarP[NWORDS_ORDER], scalarQ[NWORDS_ORDER], k[NWORDS_ORDER] = {0}, l[NWORDS_ORDER] = {0};
digit_t kt[NWORDS_ORDER], lt[NWORDS_ORDER], f1[NWORDS_ORDER] = {0}, f2[NWORDS_ORDER] = {0}, zero[NWORDS_ORDER] = {0}, tpFdiv2[NWORDS_ORDER] = {0}, tpF[NWORDS_ORDER] = {0};
printf("\n--------------------------------------------------------------------------------------------------------\n\n");
printf("Testing dlog functions: \n\n");
// dlog2 testing
passed = 1;
fp2_tomont(&P.x, &xP2);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_tomont(&Q.x, &xQ2);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
fp2_tomont(&PQ.x, &xPQ2);
fp_mont_setone(PQ.z.re);
fp_set(PQ.z.im, 0);
AC.C.re[0] = 0x01;
fp_copy(f1, TWOpFm1);
fp_copy(f2, TWOpF);
fp2_tomont(&AC.C, &AC.C);
copy_point(&PQ2.P, &P);
copy_point(&PQ2.Q, &Q);
copy_point(&PQ2.PmQ, &PQ);
k[0] = 0xFFFFFFFFFFFFFFFF;
k[1] = 0x00000000000007FF;
l[0] = 0xFFFFFFFFFFFFFFFE;
l[1] = 0x00000000000007FF;
for (int n = 0; n < TEST_LOOPS; n++)
{
k[0] -= 1;
l[0] -= 2;
xDBLMUL(&R, &P, k, &Q, l, &PQ, &AC);
ec_dlog_2(scalarP, scalarQ, &PQ2, &R, &AC);
memcpy(kt, k, NWORDS_ORDER*RADIX/8);
memcpy(lt, l, NWORDS_ORDER*RADIX/8);
if (compare_words(k, f1, NWORDS_ORDER) == 1 ||
(compare_words(l, f1, NWORDS_ORDER) == 1 && (compare_words(k, zero, NWORDS_ORDER) == 0 || compare_words(k, f1, NWORDS_ORDER) == 0))) {
if (compare_words(k, zero, NWORDS_ORDER) != 0) {
sub_test(kt, f2, kt, NWORDS_ORDER);
}
if (compare_words(l, zero, NWORDS_ORDER) != 0) {
sub_test(lt, f2, lt, NWORDS_ORDER);
}
}
if (compare_words((digit_t*)scalarP, (digit_t*)kt, NWORDS_ORDER) != 0 || compare_words((digit_t*)scalarQ, (digit_t*)lt, NWORDS_ORDER) != 0) { passed = 0; break; }
}
if (passed == 1) printf(" dlog2 tests ..................................................... PASSED");
else { printf(" dlog2 tests... FAILED"); printf("\n"); return false; }
printf("\n");
// dlog3 testing
passed = 1;
fp2_tomont(&P.x, &xP3);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_tomont(&Q.x, &xQ3);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
fp2_tomont(&PQ.x, &xPQ3);
fp_mont_setone(PQ.z.re);
fp_set(PQ.z.im, 0);
AC.C.re[0] = 0x01;
fp_copy(tpFdiv2, THREEpFdiv2);
fp_copy(tpF, THREEpF);
fp2_tomont(&AC.C, &AC.C);
copy_point(&PQ2.P, &P);
copy_point(&PQ2.Q, &Q);
copy_point(&PQ2.PmQ, &PQ);
k[1] = 0;
l[1] = 0;
k[0] = 0x02153E468B91C6D1;
l[0] = 0x02153E468B91C6D0;
for (int n = 0; n < TEST_LOOPS; n++)
{
k[0] -= 1;
l[0] -= 2;
xDBLMUL(&R, &P, k, &Q, l, &PQ, &AC);
ec_dlog_3(scalarP, scalarQ, &PQ2, &R, &AC);
memcpy(kt, k, NWORDS_ORDER*RADIX/8);
memcpy(lt, l, NWORDS_ORDER*RADIX/8);
if (compare_words(k, tpFdiv2, NWORDS_ORDER) == 1 ||
(compare_words(l, tpFdiv2, NWORDS_ORDER) == 1 && compare_words(k, zero, NWORDS_ORDER) == 0)) {
if (compare_words(k, zero, NWORDS_ORDER) != 0) {
sub_test(kt, tpF, kt, NWORDS_ORDER);
}
if (compare_words(l, zero, NWORDS_ORDER) != 0) {
sub_test(lt, tpF, lt, NWORDS_ORDER);
}
}
if (compare_words((digit_t*)scalarP, (digit_t*)kt, NWORDS_ORDER) != 0 || compare_words((digit_t*)scalarQ, (digit_t*)lt, NWORDS_ORDER) != 0) { passed = 0; break; }
}
if (passed == 1) printf(" dlog3 tests ..................................................... PASSED");
else { printf(" dlog3 tests... FAILED"); printf("\n"); return false; }
printf("\n");
return OK;
}
bool ec_run()
{
bool OK = true;
int n;
unsigned long long cycles, cycles1, cycles2;
ec_point_t P, Q, R, PQ, AC;
digit_t k[NWORDS_ORDER], l[NWORDS_ORDER];
printf("\n--------------------------------------------------------------------------------------------------------\n\n");
printf("Benchmarking ecc arithmetic: \n\n");
// Point doubling
cycles = 0;
for (n=0; n<BENCH_LOOPS; n++)
{
cycles1 = cpucycles();
xDBL(&Q, &P, &AC);
cycles2 = cpucycles();
cycles = cycles+(cycles2-cycles1);
}
printf(" Montgomery x-only doubling runs in .............................. %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
// Point addition
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
cycles1 = cpucycles();
xADD(&R, &Q, &P, &PQ);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" Montgomery x-only addition runs in .............................. %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
// Point multiplication
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
cycles1 = cpucycles();
xMUL(&Q, &P, k, (ec_curve_t*)&AC);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" Montgomery x-only scalar multiplication runs in ................. %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
// Point multiplication
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
cycles1 = cpucycles();
xDBLMUL(&R, &P, k, &Q, l, &PQ, (ec_curve_t*)&AC);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" Montgomery x-only double-scalar multiplication runs in .......... %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
return OK;
}
bool dlog_run()
{
bool OK = true;
int n;
unsigned long long cycles, cycles1, cycles2;
ec_point_t P = {0}, Q = {0}, R = {0}, S = {0}, SS = {0}, PQ = {0};
ec_curve_t AC = {0};
ec_basis_t PQ2;
digit_t scalarP[NWORDS_ORDER], scalarQ[NWORDS_ORDER], k[NWORDS_ORDER] = {0}, l[NWORDS_ORDER] = {0};
printf("\n--------------------------------------------------------------------------------------------------------\n\n");
printf("Benchmarking dlog2: \n\n");
// dlog2 computation
fp2_tomont(&P.x, &xP2);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_tomont(&Q.x, &xQ2);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
fp2_tomont(&PQ.x, &xPQ2);
fp_mont_setone(PQ.z.re);
fp_set(PQ.z.im, 0);
AC.C.re[0] = 0x01;
fp2_tomont(&AC.C, &AC.C);
copy_point(&PQ2.P, &P);
copy_point(&PQ2.Q, &Q);
copy_point(&PQ2.PmQ, &PQ);
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
fprandom_test(k); fprandom_test(l);
xDBLMUL(&R, &P, k, &Q, l, &PQ, &AC);
cycles1 = cpucycles();
ec_dlog_2(scalarP, scalarQ, &PQ2, &R, &AC);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" dlog2 runs in ................................................... %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
// dlog3 computation
fp2_tomont(&P.x, &xP3);
fp_mont_setone(P.z.re);
fp_set(P.z.im, 0);
fp2_tomont(&Q.x, &xQ3);
fp_mont_setone(Q.z.re);
fp_set(Q.z.im, 0);
fp2_tomont(&PQ.x, &xPQ3);
fp_mont_setone(PQ.z.re);
fp_set(PQ.z.im, 0);
copy_point(&PQ2.P, &P);
copy_point(&PQ2.Q, &Q);
copy_point(&PQ2.PmQ, &PQ);
cycles = 0;
for (n = 0; n < BENCH_LOOPS; n++)
{
fprandom_test(k); fprandom_test(l);
xDBLMUL(&R, &P, k, &Q, l, &PQ, &AC);
cycles1 = cpucycles();
ec_dlog_3(scalarP, scalarQ, &PQ2, &R, &AC);
cycles2 = cpucycles();
cycles = cycles + (cycles2 - cycles1);
}
printf(" dlog3 runs in ................................................... %7lld cycles", cycles/BENCH_LOOPS);
printf("\n");
return OK;
}
#endif

View File

@@ -0,0 +1,24 @@
#ifndef TEST_BASIS_H
#define TEST_BASIS_H
#include "fp2.h"
// Full-torsion basis for A=0 (excluding 2^f and huge prime factors)
const fp2_t xPA = {{0x3c780e636a5869dc,0xb8a1d106332efe8e,0x7dd946e490e6578e,0x71d1fadbea881f88,0xb94912baba3999f0,0x85343be0a74ca9e1,0x22ae01775a9f7fa4,0x001032ffab70a66e},{0x15908a4b85221a67,0x342f82e6a1db4e1d,0x3d7c806a0d47b041,0x693830fad798c598,0xcfa244134a61827a,0x7f723d6f5d9628cf,0x10da657833d4d027,0x000c48499df01216}};
const fp2_t xQA = {{0x79a766df9c10c642,0x7677cb85097be8be,0x2a21c7f9b84b9deb,0xb263e837f57210ce,0x551d6636b7c7e061,0x78d332581bee10b2,0xce30a9926772e06c,0x00150b5009b1d6ed},{0xbb2f097dae470eb9,0x53940c6df1eb93a9,0x7786a4bab87320c1,0x89d32acc1c91db18,0x733ef7f139fb7f9b,0x7bc336ee25a3901b,0xf7dfe8f5559eeeb1,0x00210555ab63e7f3}};
const fp2_t xPQA = {{0x315ead6fadc8b0d6,0x7da37e8b7e94de95,0xcc6a9e206f513651,0x84fa9fab584acf3d,0x293b25689ac50519,0xe3222bd1c8154964,0x8ad7f39d04a8274f,0x000898edca69c223},{0x3e6c3e1864851e7e,0x01807c724f75ad5e,0xe9cd50eff4e66fb7,0x6c7c19a88fed9707,0x3ab57d0499386a40,0x6b5fd53c6efdc0b5,0x092fe030da27bc43,0x00076f2f409c5f8e}};
const fp2_t xPB = {{0x229e388475511856,0x2f6b17e9ec9258c0,0x0cb28c568697f9f4,0xca039e28512c9f9b,0xd52d823761b0daa2,0xa09c3800e22c5e3b,0x2971022668c3b76a,0x0006e91c4415afd1},{0xbd5059b7406e1dcd,0x9da456ed8c11f1a3,0x1fb30e9cf66f928e,0x867c348b2f488d26,0x9d4b03d8aa4229bc,0x1c01ca1088d145a8,0xc9d6a201d77644a1,0x000a0d45131bf5b0}};
const fp2_t xQB = {{0x712f0e5d0e3b4dfa,0x52260082dda1a07e,0x5a7513dcfd273829,0xc686f0976cbb5dcf,0xf5fc3df004cc7efc,0x615d0c2da4f2fb9f,0x796efbb3f65aede8,0x00028176c42e1d9f},{0xb8779b5a7bd2436b,0x4067b7e09d0ca56c,0xfdbaee6ff27ebe38,0x69310e98174025de,0x71960a10fa15706e,0x08ffb4b3f6efafbf,0xb7116ca162211ea3,0x00253c0f60765f1f}};
const fp2_t xPQB = {{0x0e90506c89b46e0c,0x24ec65d5deb4e5b9,0x8477f7e141db8725,0xf76957ec1940dbd3,0xc2857af32534e715,0x06820654c6bae5f4,0x5ac928ef3c90c1f8,0x0024f724366faeed},{0xf6d7d2fdb06b91c4,0xe603cf05ce3f7555,0x8a0876277637415c,0xa1ef891f00155f8f,0x159db3ac93d39d57,0x5a05683aeaa453ff,0x180c38da2402f6fc,0x000b69d01dcb9107}};
// 2^f-torsion basis for A=0
const fp2_t xP2 = {{0x5d453ee3e6de9bf6,0xb5e51a5e88d8bbf3,0xc91ce6ef41eda957,0x4e0ba74e86fd3385,0xeff87c1def35e01f,0xedcd6c20496988a5,0x91a2c14abdb955fe,0x000be92a3f4de175},{0xa8a13d8e0022a825,0xb26bb70885d42bef,0x2533c31e799596b4,0xc41d58b247fb5ac9,0x8d45fa188fd5cb65,0x1b0593f6e4af948d,0x0ede22e4fcbe17ca,0x0014f54c5d5e1308}};
const fp2_t xQ2 = {{0x90414b2365f868cd,0x68af18688f73fe25,0x46ca4c4b4ca19114,0xadae5e2564f79c98,0xfe3e09af9d00eb08,0x6856810a298a57bf,0x170d41ba9327205d,0x001d588b6744b4ea},{0xfb94e978bcf29be5,0x136700c07b264bd6,0x62a3c89d8466b8f9,0x9f990ca7d3084bd8,0xaab6fb1040e242d0,0x9e9325c5a5c20740,0xa9a6ee97f376e198,0x0003c8eee3581511}};
const fp2_t xPQ2 = {{0x873d426c501eafe6,0xdeb1e87769484669,0x57c38f42bd1fef4d,0x53ca12d14b2ded18,0xb72ef4a808fc9d70,0x59d9a54b1844cca1,0x6ca7ccb15b6a9e49,0x00132a12929654f7},{0xffc6b824b6603270,0xb4152cbd3b607298,0xbe97764acdcb16ce,0x5205b1ec222c3be9,0x0cf5ac18d1eb4984,0xf5233664fd72c328,0x492e775887a3367c,0x001ce6bdfc847b45}};
// 3^g-torsion basis for A=0
const fp2_t xP3 = {{0x807a6abcb56d1915,0x3ab8ff7df809ea8f,0x2bd4f1eba48b23ac,0xeb32542370dde5ff,0xe6c50551eaaf2329,0x545dceaf98f07f09,0x90bfb0e10f3e5b48,0x000cc0084da1b367},{0xbd6f9c82cd4acc13,0x9b39d0711267d8a2,0x0ff31ab9fd38bb36,0xccc169cd75c1a58b,0xd943ad3571e304b4,0xfc3cda0859595d00,0xabda66362732b019,0x00070c5abcf1f329}};
const fp2_t xQ3 = {{0x2b46bbfa6e57a9db,0xa7a5881479d3aaff,0x5c8106d57698b7cb,0xde0ccd3c436cd1ad,0xed351e8fbc28fd8f,0xe18a9a18e4f5bf03,0x9a98961a81073911,0x001ed93f47abe8f2},{0x5dc96ddee6e9a9eb,0x5e8905d15b918006,0xe89cecdc3f9b48f1,0x9d1a98543001e35e,0x0795c7b134dadeba,0x8050c48376f36d87,0xe9f364f7c6fbee1f,0x00061cb05b384f81}};
const fp2_t xPQ3 = {{0xd44970f662987227,0x4c8eda7256920e8d,0x857f42e972e25a0e,0xc66a5b62daa3644d,0x6ab4ded74a464c38,0x4157cc1048b85a3a,0x9916ab1ee4e2305a,0x000c6943137ffba1},{0x0c5118f818e5279d,0xacb0c4a011613c7a,0xb87b4a9cb16a7565,0xc997ccbe0159f318,0x6fc50720bce6f45f,0xbd1916a5ca7789d7,0x3f48f437fdeccc64,0x000674d925340bc4}};
#endif