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:
3
src/ec/ref/CMakeLists.txt
Executable file
3
src/ec/ref/CMakeLists.txt
Executable 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
508
src/ec/ref/ecx/basis.c
Normal 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
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
90
src/ec/ref/ecx/fp2-test.c
Normal 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;
|
||||
}
|
||||
298
src/ec/ref/ecx/isog_chains.c
Normal file
298
src/ec/ref/ecx/isog_chains.c
Normal 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
228
src/ec/ref/ecx/kps.c
Normal 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
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
349
src/ec/ref/ecx/poly-redc.c
Normal 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
231
src/ec/ref/ecx/tedwards.c
Executable 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);
|
||||
}
|
||||
18
src/ec/ref/ecx/test/ec-test.c
Normal file
18
src/ec/ref/ecx/test/ec-test.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "ec-tests.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc < 3) {
|
||||
printf("Please enter an argument: 'test' or 'bench' and <reps>\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!strcmp(argv[1], "test")) {
|
||||
TEST_LOOPS = atoi(argv[2]);
|
||||
return !(ec_test() & dlog_test());
|
||||
} else if (!strcmp(argv[1], "bench")) {
|
||||
BENCH_LOOPS = atoi(argv[2]);
|
||||
return !(ec_run() & dlog_run());
|
||||
} else {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
142
src/ec/ref/ecx/test/fp2-test.c
Normal file
142
src/ec/ref/ecx/test/fp2-test.c
Normal file
@@ -0,0 +1,142 @@
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <fp2.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
static int BENCH_LOOPS = 1000; // Number of iterations per bench
|
||||
static int TEST_LOOPS = 512; // Number of iterations per test
|
||||
|
||||
bool fp2_isequal(fp2_t a, fp2_t b){
|
||||
return fp_is_equal(a.re, b.re) && fp_is_equal(a.im, b.im);
|
||||
}
|
||||
|
||||
bool fp2_isone(fp2_t a){
|
||||
fp_t one;
|
||||
bool res = 1;
|
||||
fp_mont_setone(one);
|
||||
for(int i = 0; i < NWORDS_FIELD; i++){
|
||||
res = res && (a.re[i] == one[i]);
|
||||
res = res && (a.im[i] == 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void fp2_print(char *name, fp2_t const a){
|
||||
fp2_t b;
|
||||
fp2_set(&b, 1);
|
||||
fp2_mul(&b, &b, &a);
|
||||
printf("%s = 0x", name);
|
||||
for(int i = NWORDS_FIELD - 1; i >=0; i--)
|
||||
printf("%016" PRIx64, b.re[i]);
|
||||
printf(" + i*0x");
|
||||
for(int i = NWORDS_FIELD - 1; i >=0; i--)
|
||||
printf("%016" PRIx64, b.im[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// VERY NOT SECURE (testing only)
|
||||
void fp2_random(fp2_t *a){
|
||||
for(int i = 0; i < NWORDS_FIELD; i++){
|
||||
a->re[i] = rand();
|
||||
a->im[i] = rand();
|
||||
}
|
||||
// Normalize
|
||||
fp2_t one;
|
||||
fp_mont_setone(one.re);fp_set(one.im,0);
|
||||
fp2_mul(&*a, &*a, &one);
|
||||
// Update seed
|
||||
srand((unsigned) a->re[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc > 1) {
|
||||
TEST_LOOPS = atoi(argv[1]);
|
||||
}
|
||||
|
||||
fp2_t fp2_0, fp2_1;
|
||||
// ------------
|
||||
fp2_set(&fp2_0, 0);
|
||||
fp_mont_setone(fp2_1.re);fp_set(fp2_1.im,0);
|
||||
// ------------
|
||||
|
||||
int i;
|
||||
fp2_t a, b, c, d;
|
||||
fp_t e;
|
||||
|
||||
for (i = 0; i < TEST_LOOPS; i++)
|
||||
{
|
||||
printf("[%3d%%] Testing fp2_t arithmetic", 100 * i / (int)TEST_LOOPS);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
// Random elements of fp
|
||||
fp2_random(&a);
|
||||
fp2_random(&b);
|
||||
fp2_copy(&c, &a);
|
||||
c.re[0] += 1;
|
||||
fp2_copy(&d, &b);
|
||||
d.re[0] -= 1;
|
||||
|
||||
assert(fp2_isequal(a,b) == 0); // different values check --> (a != b)
|
||||
assert(fp2_isequal(c,c) == 1); // equal values check --> 1 (c == c)
|
||||
|
||||
// Testing neg
|
||||
fp2_set(&b, 0);
|
||||
fp2_copy(&c, &a);
|
||||
fp2_neg(&a, &a);
|
||||
fp2_sub(&c, &b, &c);
|
||||
assert(fp2_isequal(a,c) == 1);
|
||||
|
||||
fp_mont_setone(a.re);fp_set(a.im,0); // Now a == 1
|
||||
fp2_set(&b, 0); // Now b == 0
|
||||
|
||||
assert(fp2_is_zero(&a) == 0);
|
||||
assert(fp2_is_zero(&b) == 1);
|
||||
|
||||
// testing c - c
|
||||
fp2_sub(&d, &c, &c);
|
||||
assert(fp2_is_zero(&d) == 1);
|
||||
|
||||
// tetsing c * 0
|
||||
fp2_mul(&d, &c, &b);
|
||||
assert(fp2_is_zero(&d) == 1);
|
||||
|
||||
// tetsing c * 1 ... recall, in Montgomery domain R mod p plays the role of the 1
|
||||
fp_mont_setone(a.re);fp_set(a.im,0);
|
||||
fp2_mul(&d, &c, &a);
|
||||
assert(fp2_isequal(d, c) == 1);
|
||||
|
||||
// fp_set(e, 1); // Now e == 1
|
||||
// fp2_pow(d, e, c);
|
||||
// assert(fp2_isequal(d, c) == 1);
|
||||
|
||||
// fp_set(e, 0); // Now e == 0
|
||||
// fp2_pow(d, e, c);
|
||||
// assert(fp2_isone(d) == 1);
|
||||
|
||||
// fp2_set(a, 1); // Now e == R mod p
|
||||
// fp_random(e);
|
||||
// fp2_pow(d, e, a);
|
||||
// assert(fp2_isone(d) == 1);
|
||||
|
||||
// Testing 1/a by computing (1/a) x a
|
||||
fp2_random(&a);
|
||||
fp2_copy(&b, &a);
|
||||
fp2_inv(&a);
|
||||
fp2_mul(&c, &a, &b);
|
||||
assert(fp2_isone(c) == 1);
|
||||
|
||||
fp2_random(&a);
|
||||
fp2_sqr(&b, &a);
|
||||
assert( fp2_is_square(&b) );
|
||||
|
||||
};
|
||||
|
||||
if(TEST_LOOPS){
|
||||
printf("[%2d%%] Tested fp2_t arithmetic:\tNo errors!\n", 100 * i /TEST_LOOPS);
|
||||
}
|
||||
printf("-- All tests passed.\n");
|
||||
return 0;
|
||||
}
|
||||
1067
src/ec/ref/ecx/test/isog-test.c
Normal file
1067
src/ec/ref/ecx/test/isog-test.c
Normal file
File diff suppressed because it is too large
Load Diff
386
src/ec/ref/ecx/test/mont-test.c
Normal file
386
src/ec/ref/ecx/test/mont-test.c
Normal file
@@ -0,0 +1,386 @@
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ec.h"
|
||||
#include "isog.h"
|
||||
#include "test-basis.h"
|
||||
#include <bench.h>
|
||||
|
||||
static int BENCH_LOOPS = 1000; // Number of iterations per bench
|
||||
static int TEST_LOOPS = 128; // Number of iterations per test
|
||||
|
||||
// void random_scalar(fp_t k, const uint8_t j)
|
||||
// {
|
||||
// // To implement a better random function (We must use some of the SHAKE family functions)
|
||||
// do
|
||||
// {
|
||||
// randombytes((void *)k, keyspace_bytes[j]);
|
||||
// } while (fp_issmaller((uint64_t *)k, keyspace_size[j]));
|
||||
// }
|
||||
|
||||
// VERY NOT SECURE (testing only)
|
||||
void fp2_random(fp2_t *a){
|
||||
for(int i = 0; i < NWORDS_FIELD; i++){
|
||||
a->re[i] = rand();
|
||||
a->im[i] = rand();
|
||||
}
|
||||
// Normalize
|
||||
fp2_t one;
|
||||
fp_mont_setone(one.re);fp_set(one.im,0);
|
||||
fp2_mul(&*a, &*a, &one);
|
||||
// Update seed
|
||||
srand((unsigned) a->re[0]);
|
||||
}
|
||||
|
||||
// Affine Montgomery coefficient computation (A + 2C : 4C) --> A/C
|
||||
void coeff(fp2_t *B, ec_point_t const A)
|
||||
{
|
||||
fp2_t t;
|
||||
fp2_add(&t, &A.x, &A.x); // (2 * A24)
|
||||
fp2_sub(&t, &t, &A.z); // (2 * A24) - C24
|
||||
|
||||
fp2_copy(&*B, &A.z);
|
||||
fp2_inv(&*B); // 1 / (C24)
|
||||
fp2_add(&t, &t, &t); // 4*A = 2[(2 * A24) - C24]
|
||||
fp2_mul(&*B, &t, &*B); // A/C = 2[(2 * A24) - C24] / C24
|
||||
}
|
||||
|
||||
// Determines if point is fp2-rational (if not, then it must be a zero trace point)
|
||||
uint8_t isrational(ec_point_t const T, fp2_t const a)
|
||||
{
|
||||
fp2_t XT, tmp, aux, YT_squared;
|
||||
|
||||
fp2_copy(&XT, &T.z);
|
||||
fp2_inv(&XT);
|
||||
|
||||
fp2_mul(&XT, &XT, &T.x);
|
||||
|
||||
fp2_sqr(&tmp, &XT);
|
||||
fp2_mul(&aux, &tmp, &XT);
|
||||
fp2_mul(&tmp, &tmp, &a);
|
||||
fp2_add(&YT_squared, &tmp, &aux);
|
||||
fp2_add(&YT_squared, &YT_squared, &XT);
|
||||
|
||||
return fp2_is_square(&YT_squared);
|
||||
}
|
||||
|
||||
// ladder3pt computes x(P + [m]Q)
|
||||
void ladder3pt(ec_point_t* R, fp_t const m, ec_point_t const* P, ec_point_t const* Q, ec_point_t const* PQ, ec_point_t const* A)
|
||||
{
|
||||
ec_point_t X0, X1, X2;
|
||||
copy_point(&X0, Q);
|
||||
copy_point(&X1, P);
|
||||
copy_point(&X2, PQ);
|
||||
|
||||
int i,j;
|
||||
uint64_t t;
|
||||
for (i = 0; i < NWORDS_FIELD; i++)
|
||||
{
|
||||
t = 1;
|
||||
for (j = 0 ; j < 64; j++)
|
||||
{
|
||||
swap_points(&X1, &X2, -((t & m[i]) == 0));
|
||||
xDBLADD(&X0, &X1, &X0, &X1, &X2, A);
|
||||
swap_points(&X1, &X2, -((t & m[i]) == 0));
|
||||
t <<= 1;
|
||||
};
|
||||
};
|
||||
copy_point(R, &X1);
|
||||
}
|
||||
|
||||
// For computing [(p + 1) / l_i]P, i:=0, ..., (N - 1)
|
||||
void cofactor_multiples(ec_point_t P[], ec_point_t const* A, size_t lower, size_t upper)
|
||||
{
|
||||
assert(lower < upper);
|
||||
if (upper - lower == 1)
|
||||
return ;
|
||||
|
||||
int i;
|
||||
size_t mid = lower + (upper - lower + 1) / 2;
|
||||
copy_point(&(P[mid]), &(P[lower]));
|
||||
for (i = lower; i < (int)mid; i++)
|
||||
xMULv2(&(P[mid]), &(P[mid]), &(TORSION_ODD_PRIMES[i]), p_plus_minus_bitlength[i], A);
|
||||
for (i = (int)mid; i < (int)upper; i++)
|
||||
xMULv2(&(P[lower]), &(P[lower]), &(TORSION_ODD_PRIMES[i]), p_plus_minus_bitlength[i], A);
|
||||
|
||||
cofactor_multiples(P, A, lower, mid);
|
||||
cofactor_multiples(P, A, mid, upper);
|
||||
}
|
||||
|
||||
// The projective x-coordinate point (X : Z) at infinity is such that Z == 0
|
||||
static inline int isinfinity(ec_point_t const P)
|
||||
{
|
||||
return fp2_is_zero(&P.z);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc > 1) {
|
||||
TEST_LOOPS = atoi(argv[1]);
|
||||
}
|
||||
|
||||
fp2_t fp2_0, fp2_1;
|
||||
fp2_set(&fp2_0, 0);
|
||||
fp_mont_setone(fp2_1.re);fp_set(fp2_1.im,0);
|
||||
|
||||
int i, j;
|
||||
|
||||
ec_point_t A;
|
||||
fp2_set(&A.x, 0);
|
||||
fp_mont_setone(A.z.re);fp_set(A.z.im,0);
|
||||
|
||||
fp2_add(&A.z, &A.z, &A.z); // 2C
|
||||
fp2_add(&A.x, &A.x, &A.z); // A' + 2C
|
||||
fp2_add(&A.z, &A.z, &A.z); // 4C
|
||||
|
||||
// Just to ensure the projective curve coeffientes are different from zero
|
||||
assert( !fp2_is_zero(&A.x) & !fp2_is_zero(&A.x) );
|
||||
|
||||
fp2_t a;
|
||||
coeff(&a, A);
|
||||
|
||||
ec_point_t PA, QA, PQA, PB, QB, PQB;
|
||||
|
||||
// Writing the public projective x-coordinate points into Montogmery domain
|
||||
fp2_tomont(&(PA.x), &(xPA));
|
||||
fp_mont_setone(PA.z.re);fp_set(PA.z.im,0);
|
||||
fp2_tomont(&(QA.x), &(xQA));
|
||||
fp_mont_setone(QA.z.re);fp_set(QA.z.im,0);
|
||||
fp2_tomont(&(PQA.x), &(xPQA));
|
||||
fp_mont_setone(PQA.z.re);fp_set(PQA.z.im,0);
|
||||
|
||||
assert( isrational(PA, a) );
|
||||
assert( isrational(QA, a) );
|
||||
assert( isrational(PQA, a) );
|
||||
|
||||
// ======================================================================================================
|
||||
// Recall, PA, QA, and PQA are expeted to be N-order points, but we require to ensure they are of order N
|
||||
for (j = 0; j < P_LEN; j++)
|
||||
{
|
||||
for (i = 1; i < TORSION_ODD_POWERS[j]; i++)
|
||||
{
|
||||
xMULv2(&PA, &PA, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
xMULv2(&QA, &QA, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
xMULv2(&PQA, &PQA, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
|
||||
assert( isrational(PA, a) );
|
||||
assert( isrational(QA, a) );
|
||||
assert( isrational(PQA, a) );
|
||||
};
|
||||
};
|
||||
assert( !isinfinity(PA) );
|
||||
assert( !isinfinity(QA) );
|
||||
assert( !isinfinity(PQA) );
|
||||
|
||||
ec_point_t P[P_LEN + M_LEN], Q[P_LEN + M_LEN], PQ[P_LEN + M_LEN];
|
||||
copy_point(&(P[0]), &PA);
|
||||
cofactor_multiples(P, &A, 0, P_LEN);
|
||||
copy_point(&(Q[0]), &QA);
|
||||
cofactor_multiples(Q, &A, 0, P_LEN);
|
||||
copy_point(&(PQ[0]), &PQA);
|
||||
cofactor_multiples(PQ, &A, 0, P_LEN);
|
||||
for (j = 0; j < P_LEN; j++)
|
||||
{
|
||||
// x(PA)
|
||||
assert( !isinfinity(P[j]) ); // It must be different from the point at infinity
|
||||
assert( isrational(P[j], a) );
|
||||
xMULv2(&P[j], &P[j], &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
assert( isinfinity(P[j]) ); // It must be now the point at infinity
|
||||
// x(QA)
|
||||
assert( !isinfinity(Q[j]) ); // It must be different from the point at infinity
|
||||
assert( isrational(Q[j], a) );
|
||||
xMULv2(&Q[j], &Q[j], &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
assert( isinfinity(Q[j]) ); // It must be now the point at infinity
|
||||
// x(PQA)
|
||||
assert( !isinfinity(PQ[j]) ); // It must be different from the point at infinity
|
||||
assert( isrational(PQ[j], a) );
|
||||
xMULv2(&PQ[j], &PQ[j], &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
assert( isinfinity(PQ[j]) ); // It must be now the point at infinity
|
||||
};
|
||||
// Writing the public projective x-coordinate points into Montogmery domain
|
||||
fp2_tomont(&(PB.x), &(xPB));
|
||||
fp_mont_setone(PB.z.re);fp_set(PB.z.im,0);
|
||||
fp2_tomont(&(QB.x), &(xQB));
|
||||
fp_mont_setone(QB.z.re);fp_set(QB.z.im,0);
|
||||
fp2_tomont(&(PQB.x), &(xPQB));
|
||||
fp_mont_setone(PQB.z.re);fp_set(PQB.z.im,0);
|
||||
|
||||
assert( !isrational(PB, a) );
|
||||
assert( !isrational(QB, a) );
|
||||
assert( !isrational(PQB, a) );
|
||||
// ======================================================================================================
|
||||
// Recall, PB, QB, and PQB are expeted to be M-order points, but we require to ensure they are of order M
|
||||
for (j = P_LEN; j < (P_LEN + M_LEN); j++)
|
||||
{
|
||||
for (i = 1; i < TORSION_ODD_POWERS[j]; i++)
|
||||
{
|
||||
xMULv2(&PB, &PB, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
xMULv2(&QB, &QB, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
xMULv2(&PQB, &PQB, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
|
||||
assert( !isrational(PB, a) );
|
||||
assert( !isrational(QB, a) );
|
||||
assert( !isrational(PQB, a) );
|
||||
};
|
||||
};
|
||||
assert( !isinfinity(PB) );
|
||||
assert( !isinfinity(QB) );
|
||||
assert( !isinfinity(PQB) );
|
||||
|
||||
copy_point(&(P[P_LEN]), &PB);
|
||||
cofactor_multiples(P, &A, P_LEN, P_LEN + M_LEN);
|
||||
copy_point(&(Q[P_LEN]), &QB);
|
||||
cofactor_multiples(Q, &A, P_LEN, P_LEN + M_LEN);
|
||||
copy_point(&(PQ[P_LEN]), &PQB);
|
||||
cofactor_multiples(PQ, &A, P_LEN, P_LEN + M_LEN);
|
||||
for (j = P_LEN; j < (P_LEN+M_LEN); j++)
|
||||
{
|
||||
// x(PB)
|
||||
assert( !isinfinity(P[j]) ); // It must be different from the point at infinity
|
||||
assert( !isrational(P[j], a) );
|
||||
xMULv2(&P[j], &P[j], &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
assert( isinfinity(P[j]) ); // It must be now the point at infinity
|
||||
// x(QB)
|
||||
assert( !isinfinity(Q[j]) ); // It must be different from the point at infinity
|
||||
assert( !isrational(Q[j], a) );
|
||||
xMULv2(&Q[j], &Q[j], &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
assert( isinfinity(Q[j]) ); // It must be now the point at infinity
|
||||
// x(PQB)
|
||||
assert( !isinfinity(PQ[j]) ); // It must be different from the point at infinity
|
||||
assert( !isrational(PQ[j], a) );
|
||||
xMULv2(&PQ[j], &PQ[j], &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
assert( isinfinity(PQ[j]) ); // It must be now the point at infinity
|
||||
};
|
||||
|
||||
fp2_t m;
|
||||
|
||||
// Writing the public projective x-coordinate points into Montogmery domain
|
||||
fp2_tomont(&(PA.x), &(xPA));
|
||||
fp_mont_setone(PA.z.re);fp_set(PA.z.im,0);
|
||||
fp2_tomont(&(QA.x), &(xQA));
|
||||
fp_mont_setone(QA.z.re);fp_set(QA.z.im,0);
|
||||
fp2_tomont(&(PQA.x), &(xPQA));
|
||||
fp_mont_setone(PQA.z.re);fp_set(PQA.z.im,0);
|
||||
|
||||
assert( isrational(PA, a) );
|
||||
assert( isrational(QA, a) );
|
||||
assert( isrational(PQA, a) );
|
||||
|
||||
fp2_tomont(&(PB.x), &(xPB));
|
||||
fp_mont_setone(PB.z.re);fp_set(PB.z.im,0);
|
||||
fp2_tomont(&(QB.x), &(xQB));
|
||||
fp_mont_setone(QB.z.re);fp_set(QB.z.im,0);
|
||||
fp2_tomont(&(PQB.x), &(xPQB));
|
||||
fp_mont_setone(PQB.z.re);fp_set(PQB.z.im,0);
|
||||
|
||||
assert( !isrational(PB, a) );
|
||||
assert( !isrational(QB, a) );
|
||||
assert( !isrational(PQB, a) );
|
||||
|
||||
ec_point_t R[P_LEN + M_LEN];
|
||||
int k;
|
||||
for (j = 0; j < TEST_LOOPS; j++)
|
||||
{
|
||||
printf("[%3d%%] Testing EC differential arithmetic", 100 * j / TEST_LOOPS);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
fp2_random(&m);
|
||||
ladder3pt(&(R[0]), m.re, &PA, &QA, &PQA, &A);
|
||||
assert( isrational(R[0], a) );
|
||||
for (k = 0; k < P_LEN; k++)
|
||||
{
|
||||
for (i = 1; i < TORSION_ODD_POWERS[k]; i++)
|
||||
{
|
||||
xMULv2(&R[0], &R[0], &(TORSION_ODD_PRIMES[k]), p_plus_minus_bitlength[k], &A);
|
||||
assert( isrational(R[0], a) );
|
||||
};
|
||||
};
|
||||
cofactor_multiples(R, &A, 0, P_LEN);
|
||||
for (i = 0; i < P_LEN; i++)
|
||||
{
|
||||
assert( !isinfinity(R[i]) ); // It must be different from the point at infinity
|
||||
assert( isrational(R[i], a) );
|
||||
xMULv2(&R[i], &R[i], &(TORSION_ODD_PRIMES[i]), p_plus_minus_bitlength[i], &A);
|
||||
assert( isinfinity(R[i]) ); // It must be now the point at infinity
|
||||
};
|
||||
|
||||
fp2_random(&m);
|
||||
ladder3pt(&(R[P_LEN]), m.re, &PB, &QB, &PQB, &A);
|
||||
assert( !isrational(R[P_LEN], a) );
|
||||
for (k = P_LEN; k < (P_LEN+M_LEN); k++)
|
||||
{
|
||||
for (i = 1; i < TORSION_ODD_POWERS[k]; i++)
|
||||
{
|
||||
xMULv2(&R[P_LEN], &R[P_LEN], &(TORSION_ODD_PRIMES[k]), p_plus_minus_bitlength[k], &A);
|
||||
assert( !isrational(R[P_LEN], a) );
|
||||
};
|
||||
};
|
||||
cofactor_multiples(R, &A, P_LEN, P_LEN + M_LEN);
|
||||
for (i = P_LEN; i < (P_LEN+M_LEN); i++)
|
||||
{
|
||||
assert( !isinfinity(R[i]) ); // It must be different from the point at infinity
|
||||
assert( !isrational(R[i], a) );
|
||||
xMULv2(&R[i], &R[i], &(TORSION_ODD_PRIMES[i]), p_plus_minus_bitlength[i], &A);
|
||||
assert( isinfinity(R[i]) ); // It must be now the point at infinity
|
||||
};
|
||||
};
|
||||
|
||||
if(TEST_LOOPS)
|
||||
printf("[%3d%%] Tested EC differential arithmetic:\tNo errors!\n", 100 * j / TEST_LOOPS);
|
||||
printf("-- All tests passed.\n");
|
||||
|
||||
// BENCHMARK xDBLv2
|
||||
unsigned long long cycles, cycles1, cycles2;
|
||||
cycles = 0;
|
||||
ec_point_t PP[TEST_LOOPS], EE[TEST_LOOPS];
|
||||
for(int i = 0; i < TEST_LOOPS; i++){
|
||||
fp2_random(&PP[i].x);
|
||||
fp2_random(&PP[i].z);
|
||||
fp2_random(&EE[i].x);
|
||||
fp2_random(&EE[i].z);
|
||||
}
|
||||
cycles1 = cpucycles();
|
||||
for(int i = 0; i < TEST_LOOPS; i++){
|
||||
xDBLv2(&PP[i], &PP[i], &EE[i]);
|
||||
}
|
||||
cycles2 = cpucycles();
|
||||
cycles = cycles+(cycles2-cycles1);
|
||||
|
||||
printf("xDBLv2 bench: %7lld cycles\n", cycles/TEST_LOOPS);
|
||||
|
||||
// BENCHMARK xIsog4
|
||||
cycles = 0;
|
||||
ec_point_t KK0[TEST_LOOPS], KK1[TEST_LOOPS], KK2[TEST_LOOPS];
|
||||
for(int i = 0; i < TEST_LOOPS; i++){
|
||||
fp2_random(&KK0[i].x);
|
||||
fp2_random(&KK0[i].z);
|
||||
fp2_random(&KK1[i].x);
|
||||
fp2_random(&KK1[i].z);
|
||||
fp2_random(&KK2[i].x);
|
||||
fp2_random(&KK2[i].z);
|
||||
}
|
||||
cycles1 = cpucycles();
|
||||
for(int i = 0; i < TEST_LOOPS; i++){
|
||||
fp2_t t0, t1;
|
||||
fp2_add(&t0, &PP[i].x, &PP[i].z);
|
||||
fp2_sub(&t1, &PP[i].x, &PP[i].z);
|
||||
fp2_mul(&(EE[i].x), &t0, &KK1[i].x);
|
||||
fp2_mul(&(EE[i].z), &t1, &KK2[i].x);
|
||||
fp2_mul(&t0, &t0, &t1);
|
||||
fp2_mul(&t0, &t0, &KK0[i].x);
|
||||
fp2_add(&t1, &(EE[i].x), &(EE[i].z));
|
||||
fp2_sub(&(EE[i].z), &(EE[i].x), &(EE[i].z));
|
||||
fp2_sqr(&t1, &t1);
|
||||
fp2_sqr(&(EE[i].z), &(EE[i].z));
|
||||
fp2_add(&(EE[i].x), &t0, &t1);
|
||||
fp2_sub(&t0, &(EE[i].z), &t0);
|
||||
fp2_mul(&(EE[i].x), &(EE[i].x), &t1);
|
||||
fp2_mul(&(EE[i].z), &(EE[i].z), &t0);
|
||||
}
|
||||
cycles2 = cpucycles();
|
||||
cycles = cycles+(cycles2-cycles1);
|
||||
printf("xeval_4 bench: %7lld cycles\n", cycles/TEST_LOOPS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
445
src/ec/ref/ecx/test/poly-mul-test.c
Normal file
445
src/ec/ref/ecx/test/poly-mul-test.c
Normal file
@@ -0,0 +1,445 @@
|
||||
#include <poly.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
bool fp2_isequal(fp2_t a, fp2_t b){
|
||||
return fp_is_equal(a.re, b.re) && fp_is_equal(a.im, b.im);
|
||||
}
|
||||
|
||||
// VERY NOT SECURE (testing only)
|
||||
void fp2_random(fp2_t *a){
|
||||
for(int i = 0; i < NWORDS_FIELD; i++){
|
||||
a->re[i] = rand();
|
||||
a->im[i] = rand();
|
||||
}
|
||||
// Normalize
|
||||
fp2_t one;
|
||||
fp_mont_setone(one.re);fp_set(one.im,0);
|
||||
fp2_mul(&*a, &*a, &one);
|
||||
// Update seed
|
||||
srand((unsigned) a->re[0]);
|
||||
}
|
||||
|
||||
void slow_mul(poly h, poly f, int lenf, poly g, int leng){
|
||||
// Computes h = f*g by school method
|
||||
|
||||
fp2_t a, b;
|
||||
int nf, ng, e;
|
||||
int lenh = lenf + leng - 1;
|
||||
|
||||
if(lenh <= 0){
|
||||
return;
|
||||
}
|
||||
|
||||
fp2_t fg[lenh];
|
||||
|
||||
if (leng > lenf){
|
||||
slow_mul(h, g, leng, f, lenf);
|
||||
return;
|
||||
}
|
||||
|
||||
for(e = 0; e < lenh; e++){
|
||||
|
||||
if (lenf - 1 < e){
|
||||
nf = lenf - 1;
|
||||
}
|
||||
else{
|
||||
nf = e;
|
||||
}
|
||||
|
||||
ng = e - nf;
|
||||
fp2_set(&a, 0);
|
||||
while( (ng < leng) & (nf >= 0) ){
|
||||
fp2_mul(&b, &f[nf], &g[ng]);
|
||||
fp2_add(&a, &a, &b);
|
||||
nf--;
|
||||
ng++;
|
||||
}
|
||||
fp2_copy(&fg[e], &a);
|
||||
}
|
||||
for(e = 0; e < lenh; e++){
|
||||
fp2_copy(&h[e], &fg[e]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(){
|
||||
fp2_t fp2_0, fp2_1;
|
||||
#define nmax 16
|
||||
int nf, ng, n, e;
|
||||
fp2_set(&fp2_0, 0);
|
||||
fp_mont_setone(fp2_1.re);fp_set(fp2_1.im,0);
|
||||
|
||||
//TEST MULTIPLICATION BY 0
|
||||
|
||||
for(nf = 2; nf < nmax; nf++){
|
||||
fp2_t f[nf], h[nf-1];
|
||||
|
||||
printf("[%3d%%] Testing multiplication by 0", 100 * nf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(e = 0; e < nf; e++){
|
||||
fp2_random(&f[e]);
|
||||
}
|
||||
poly_mul(h, f, nf, f, 0);
|
||||
for(e = 0; e < nf-1; e++){
|
||||
assert(fp2_is_zero(&h[e])==1);
|
||||
}
|
||||
poly_mul(h, f, 0, f, nf);
|
||||
for(e = 0; e < nf-1; e++){
|
||||
assert(fp2_is_zero(&h[e])==1);
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested multiplication by 0:\t\tNo errors!\n", 100 * nf / nmax);
|
||||
|
||||
|
||||
|
||||
//TEST FOR f, g, h DISJOINT MEMORY SPACES
|
||||
|
||||
for(nf = 1; nf < nmax; nf++){
|
||||
|
||||
printf("[%3d%%] Testing multiplication", 100 * nf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(ng = 1; ng < nmax; ng++){
|
||||
|
||||
fp2_t f[nf]; //Random length nf poly
|
||||
for(e = 0; e < nf; e++){
|
||||
fp2_random(&f[e]);
|
||||
}
|
||||
|
||||
fp2_t g[ng]; // Random length ng poly
|
||||
for(e = 0; e < ng; e++){
|
||||
fp2_random(&g[e]);
|
||||
}
|
||||
|
||||
fp2_t h[nf+ng-1];// Compute product
|
||||
poly_mul(h, f, nf, g, ng);
|
||||
|
||||
fp2_t fg[nf+ng-1]; // Compute the product by school method
|
||||
slow_mul(fg, f, nf, g, ng);
|
||||
|
||||
for(e = 0; e < nf + ng - 1; e++){ // Verify answer term by term
|
||||
assert(fp2_isequal(h[e], fg[e])==1);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested multiplication:\t\t\tNo errors!\n", 100 * nf / nmax);
|
||||
|
||||
|
||||
|
||||
// TEST FOR f, g CONTIGIOUS AND RESULT SAVED OVER THEM
|
||||
|
||||
for(nf = 1; nf < nmax; nf++){
|
||||
|
||||
printf("[%3d%%] Testing multiplication in place", 100 * nf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(ng = 1; ng < nmax; ng++){
|
||||
|
||||
fp2_t h[nf+ng];
|
||||
|
||||
//Random length nf poly
|
||||
for(e = 0; e < nf; e++){
|
||||
fp2_random(&h[e]);
|
||||
}
|
||||
|
||||
// Random length ng poly
|
||||
for(e = 0; e < ng; e++){
|
||||
fp2_random(&h[e+nf]);
|
||||
}
|
||||
|
||||
// Compute the product
|
||||
fp2_t fg[nf+ng-1];
|
||||
slow_mul(fg, h, nf, &(h[nf]), ng); // School method
|
||||
poly_mul(h, h, nf, &(h[nf]), ng); // Karatsuba method
|
||||
|
||||
|
||||
for(e = 0; e < nf + ng - 1; e++){ // Verify answer term by term
|
||||
assert(fp2_isequal(h[e], fg[e])==1);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested multiplication in place:\t\tNo errors!\n", 100 * nf / nmax);
|
||||
|
||||
|
||||
|
||||
//TEST FOR MULTIPLICATION MOD X^N BY 0
|
||||
|
||||
for(nf = 2; nf < nmax; nf++){
|
||||
fp2_t f[nf];
|
||||
|
||||
printf("[%3d%%] Testing mul mod x^n by 0", 100 * nf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(e = 0; e < nf; e++){
|
||||
fp2_random(&f[e]);
|
||||
}
|
||||
|
||||
for(n = 1; n < nmax; n++){
|
||||
fp2_t h[n];
|
||||
poly_mul_low(h, n, f, nf, f, 0);
|
||||
for(e = 0; e < n; e++){
|
||||
assert(fp2_is_zero(&h[e])==1);
|
||||
}
|
||||
poly_mul_low(h, n, f, 0, f, nf);
|
||||
for(e = 0; e < n; e++){
|
||||
assert(fp2_is_zero(&h[e])==1);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested mul mod x^n by 0:\t\t\tNo errors!\n", 100 * nf / nmax);
|
||||
|
||||
|
||||
|
||||
//TEST FOR MULTIPLICATION MOD X^N
|
||||
|
||||
for(nf = 1; nf < nmax; nf++){
|
||||
|
||||
printf("[%3d%%] Testing mul mod x^n", 100 * nf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(ng = 1; ng < nmax; ng++){
|
||||
|
||||
fp2_t f[nf], g[ng], fg[nf+ng-1];
|
||||
poly h;
|
||||
|
||||
//Get random polynomials
|
||||
for(e = 0; e < nf; e++){
|
||||
fp2_random(&f[e]);
|
||||
}
|
||||
for(e = 0; e < ng; e++){
|
||||
fp2_random(&g[e]);
|
||||
}
|
||||
|
||||
//Save regular result to fg
|
||||
slow_mul(fg, f, nf, g, ng);
|
||||
|
||||
//Compute result mod x^n
|
||||
for(n = 1; n < 2*nmax; n++){
|
||||
h = malloc(sizeof(fp2_t)*n);
|
||||
poly_mul_low(h, n, f, nf, g, ng);
|
||||
|
||||
//Compare with expected
|
||||
e = 0;
|
||||
while(e < nf+ng-1 && e < n){
|
||||
assert(fp2_isequal(h[e], fg[e]) == 1);
|
||||
e++;
|
||||
}
|
||||
while(e < n){
|
||||
assert(fp2_is_zero(&h[e]) == 1);
|
||||
e++;
|
||||
}
|
||||
free(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested mul mod x^n:\t\t\tNo errors!\n", 100 * nf / nmax);
|
||||
|
||||
|
||||
|
||||
//TEST FOR POLY_MUL_MIDDLE
|
||||
|
||||
for(nf = 1; nf < 2*nmax; nf+=1){
|
||||
fp2_t f[nf];
|
||||
|
||||
printf("[%3d%%] Testing poly_mul_middle", 100 * nf / (2*nmax));
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(ng = (nf+1)>>1; ng < (nf+1)-((nf+1)>>1); ng++){
|
||||
// This runs from floor((nf+1)/2) to ceil((nf+1)/2)
|
||||
fp2_t g[ng];
|
||||
for(e = 0; e < nf; e++){
|
||||
fp2_random(&f[e]);
|
||||
}
|
||||
for(e = 0; e < ng; e++){
|
||||
fp2_random(&g[e]);
|
||||
}
|
||||
|
||||
fp2_t h[nf+ng-1];
|
||||
slow_mul(h, g, ng, f, nf);
|
||||
poly_mul_middle(g, g, ng, f, nf);
|
||||
|
||||
for(e = 0; e < ng; e++){
|
||||
assert(fp2_isequal(h[e+nf-ng], g[e])==1);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested poly_mul_middle:\t\t\tNo errors!\n", 100 * nf / (2*nmax));
|
||||
|
||||
|
||||
// TEST FOR SELF RECIPROCAL MULTIPLICATION
|
||||
for(nf = 1; nf < nmax; nf++){
|
||||
|
||||
printf("[%3d%%] Testing self reciprocal mul", 100 * nf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
for(ng = 1; ng < nmax; ng++){
|
||||
|
||||
fp2_t f[nf], g[ng], h[nf+ng-1], fg[nf+ng-1];
|
||||
|
||||
// Get random palyndromes
|
||||
for(e = 0; e < (nf>>1); e++){
|
||||
fp2_random(&f[e]);
|
||||
fp2_copy(&f[nf-1-e], &f[e]);
|
||||
}
|
||||
if(nf & 1){
|
||||
fp2_random(&f[nf>>1]);
|
||||
}
|
||||
|
||||
for(e = 0; e < (ng>>1); e++){
|
||||
fp2_random(&g[e]);
|
||||
fp2_copy(&g[ng-1-e], &g[e]);
|
||||
}
|
||||
if(ng & 1){
|
||||
fp2_random(&g[ng>>1]);
|
||||
}
|
||||
|
||||
// Compute products
|
||||
poly_mul_selfreciprocal(h, g, ng, f, nf);
|
||||
slow_mul(fg, g, ng, f, nf);
|
||||
|
||||
// Compare
|
||||
for(e = 0; e < nf+ng-1; e++){
|
||||
assert(fp2_isequal(fg[e], h[e])==1);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[%3d%%] Tested self reciprocal mul:\t\tNo errors!\n", 100 * nf / nmax);
|
||||
|
||||
// TEST FOR PRODUCT TREES
|
||||
int tree_size, iteration, i;
|
||||
int len, *DEG, LENF;
|
||||
poly *H, *F, h;
|
||||
|
||||
for(tree_size = 1; tree_size < nmax; tree_size++){
|
||||
|
||||
printf("[%3d%%] Testing product tree:\t\t\tSize %d out of %d", 100 * tree_size / nmax, tree_size, nmax-1);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
i = 0;
|
||||
while((1<<i) < tree_size){
|
||||
i++;
|
||||
}
|
||||
DEG = malloc(sizeof(int)*((1<<(i+2))-1));
|
||||
H = malloc(sizeof(poly)*((1<<(i+2))-1));
|
||||
F = malloc(sizeof(poly)*tree_size);
|
||||
h = malloc(sizeof(fp2_t)*(nmax+1)*tree_size);
|
||||
|
||||
for(iteration = 0; iteration < nmax + 1 - tree_size ; iteration++){
|
||||
|
||||
// Generate random list of polynomials
|
||||
LENF = (rand() % nmax)+1;
|
||||
for(i = 0; i < tree_size; i++){
|
||||
F[i] = malloc(sizeof(fp2_t)*LENF);
|
||||
for(e = 0; e < LENF; e++){
|
||||
fp2_random(&F[i][e]);
|
||||
}
|
||||
}
|
||||
product_tree(H, DEG, 0, F, LENF, tree_size);
|
||||
|
||||
// Build product of all polynomials manually
|
||||
len = LENF;
|
||||
|
||||
//for(e = 0; e < LENF[0]; e++){
|
||||
for(e = 0; e < LENF; e++){
|
||||
fp2_copy(&h[e], &F[0][e]);
|
||||
}
|
||||
for(i = 1; i < tree_size; i++){
|
||||
poly_mul(h, h, len, F[i], LENF);
|
||||
len += LENF-1;
|
||||
}
|
||||
|
||||
// Compare to root
|
||||
assert (len == DEG[0]+1);
|
||||
for(e = 0; e < len; e++){
|
||||
assert(fp2_isequal(H[0][e], h[e])==1);
|
||||
}
|
||||
clear_tree(H, 0, tree_size);
|
||||
for(i = 0; i < tree_size; i++){
|
||||
free(F[i]);
|
||||
}
|
||||
|
||||
}
|
||||
free(DEG);
|
||||
free(H);
|
||||
free(F);
|
||||
free(h);
|
||||
}
|
||||
printf("[%3d%%] Tested product tree:\t\t\tNo errors!\n", 100 * tree_size / nmax);
|
||||
|
||||
// TEST FOR SELF RECIPROCAL PRODUCT TREES
|
||||
|
||||
for(tree_size = 1; tree_size < nmax; tree_size++){
|
||||
|
||||
printf("[%3d%%] Testing selfreciprocal product tree:\tSize %d out of %d", 100 * tree_size / nmax, tree_size, nmax-1);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
i = 0;
|
||||
while((1<<i) < tree_size){
|
||||
i++;
|
||||
}
|
||||
DEG = malloc(sizeof(int)*((1<<(i+2))-1));
|
||||
H = malloc(sizeof(poly)*((1<<(i+2))-1));
|
||||
F = malloc(sizeof(poly)*tree_size);
|
||||
h = malloc(sizeof(fp2_t)*(nmax+1)*tree_size);
|
||||
|
||||
for(iteration = 0; iteration < nmax + 1 - tree_size ; iteration++){
|
||||
|
||||
// Generate random list of polynomials
|
||||
LENF = (rand() % nmax)+1;;
|
||||
for(i = 0; i < tree_size; i++){
|
||||
F[i] = malloc(sizeof(fp2_t)*LENF);
|
||||
for(e = 0; e < (LENF>>1); e++){
|
||||
fp2_random(&F[i][e]);
|
||||
fp2_copy(&F[i][LENF-1-e], &F[i][e]);
|
||||
}
|
||||
if(LENF & 1){
|
||||
fp2_random(&F[i][(LENF>>1)]);
|
||||
}
|
||||
}
|
||||
product_tree_selfreciprocal(H, DEG, 0, F, LENF, tree_size);
|
||||
|
||||
// Build product of all polynomials manually
|
||||
len = LENF;
|
||||
for(e = 0; e < LENF; e++){
|
||||
fp2_copy(&h[e], &F[0][e]);
|
||||
}
|
||||
for(i = 1; i < tree_size; i++){
|
||||
poly_mul(h, h, len, F[i], LENF);
|
||||
len += LENF-1;
|
||||
}
|
||||
|
||||
// Compare to root
|
||||
assert (len == DEG[0]+1);
|
||||
for(e = 0; e < len; e++){
|
||||
assert(fp2_isequal(H[0][e], h[e])==1);
|
||||
}
|
||||
clear_tree(H, 0, tree_size);
|
||||
for(i = 0; i < tree_size; i++){
|
||||
free(F[i]);
|
||||
}
|
||||
|
||||
}
|
||||
free(DEG);
|
||||
free(H);
|
||||
free(F);
|
||||
free(h);
|
||||
}
|
||||
printf("[%3d%%] Tested selfreciprocal product tree:\tNo errors!\n", 100 * tree_size / nmax);
|
||||
|
||||
printf("-- All tests passed.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
461
src/ec/ref/ecx/test/poly-redc-test.c
Normal file
461
src/ec/ref/ecx/test/poly-redc-test.c
Normal file
@@ -0,0 +1,461 @@
|
||||
#include "poly.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#define nmax 32
|
||||
|
||||
bool fp2_isequal(fp2_t a, fp2_t b){
|
||||
return fp_is_equal(a.re, b.re) && fp_is_equal(a.im, b.im);
|
||||
}
|
||||
|
||||
// VERY NOT SECURE (testing only)
|
||||
void fp2_random(fp2_t *a){
|
||||
for(int i = 0; i < NWORDS_FIELD; i++){
|
||||
a->re[i] = rand();
|
||||
a->im[i] = rand();
|
||||
}
|
||||
// Normalize
|
||||
fp2_t one;
|
||||
fp_mont_setone(one.re);fp_set(one.im,0);
|
||||
fp2_mul(&*a, &*a, &one);
|
||||
// Update seed
|
||||
srand((unsigned) a->re[0]);
|
||||
}
|
||||
|
||||
int main(){
|
||||
fp2_t fp2_0, fp2_1;
|
||||
fp2_set(&fp2_0, 0);
|
||||
fp_mont_setone(fp2_1.re);fp_set(fp2_1.im,0);
|
||||
|
||||
int lenf, leng, n, e, iteration, array_size, tree_size, i, root, brother, *DEG, LENF;
|
||||
poly f, g, h, f_rev, f_rev_inv, *F, *H, *R, g1, g2, REM1, REM2, G1, G2, G1_rev, G2_rev, R0;
|
||||
fp2_t c, *A, *C, ratio, A0;
|
||||
|
||||
f_rev_inv = 0;
|
||||
|
||||
// TEST FOR RECIPROCAL
|
||||
for(lenf = 1; lenf < nmax; lenf++)
|
||||
{
|
||||
printf("[%3d%%] Testing reciprocals", 100 * lenf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
// Get random poly
|
||||
f = malloc(sizeof(fp2_t)*lenf);
|
||||
for(e = 0; e < lenf; e++)
|
||||
fp2_random(&f[e]);
|
||||
|
||||
for(n = 1; n < nmax; n++)
|
||||
{
|
||||
// Get the reciprocal and multiply them
|
||||
h = malloc(sizeof(fp2_t)*n);
|
||||
memset(h, 0, sizeof(fp2_t)*n);
|
||||
reciprocal(h, &c, f, lenf, n);
|
||||
poly_mul_low(h, n, f, lenf, h, n);
|
||||
|
||||
// Compare with expected
|
||||
assert(fp2_isequal(h[0],c));
|
||||
for(e = 1; e < n; e++)
|
||||
assert(fp2_is_zero(&h[e]));
|
||||
free(h);
|
||||
}
|
||||
free(f);
|
||||
}
|
||||
printf("[%3d%%] Tested reciprocals:\t\tNo errors!\n", 100 * lenf / nmax);
|
||||
|
||||
|
||||
|
||||
// TEST FOR REDUCTION
|
||||
for(lenf = 2; lenf < nmax; lenf++)
|
||||
{
|
||||
printf("[%3d%%] Testing polynomial reduction", 100 * lenf / nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
// Get random poly for the mod
|
||||
f = malloc(sizeof(fp2_t)*lenf);
|
||||
f_rev = malloc(sizeof(fp2_t)*lenf);
|
||||
for(e = 0; e < lenf; e++)
|
||||
{
|
||||
fp2_random(&f[e]);
|
||||
fp2_copy(&f_rev[lenf-1-e], &f[e]);
|
||||
}
|
||||
|
||||
for(leng = 1; leng < nmax; leng++)
|
||||
{
|
||||
// Get random poly to reduce
|
||||
g = malloc(sizeof(fp2_t)*leng);
|
||||
for(e = 0; e < leng; e++){
|
||||
fp2_random(&g[e]);
|
||||
}
|
||||
|
||||
// Get reverse-inverse mod x^(leng-lenf+1)
|
||||
if(leng >= lenf)
|
||||
{
|
||||
f_rev_inv = malloc(sizeof(fp2_t)*(leng-lenf+1));
|
||||
reciprocal(f_rev_inv, &c, f_rev, lenf, leng-lenf+1);
|
||||
}
|
||||
else{
|
||||
fp_mont_setone(c.re);fp_set(c.im,0);
|
||||
}
|
||||
|
||||
// Compute the reduction
|
||||
h = malloc(sizeof(fp2_t)*(lenf-1));
|
||||
poly_redc(h, g, leng, f, lenf, f_rev_inv, c);
|
||||
|
||||
// Reduce manually
|
||||
int leng_red = leng;
|
||||
fp2_t scale, f_e;
|
||||
while(leng_red >= lenf)
|
||||
{
|
||||
fp2_copy(&scale, &f[lenf-1]);
|
||||
fp2_inv(&scale);
|
||||
fp2_mul(&scale, &scale, &g[leng_red-1]);
|
||||
for(e = 0; e < lenf; e++)
|
||||
{
|
||||
fp2_mul(&f_e, &f[e], &scale);
|
||||
fp2_sub(&g[e+leng_red-lenf], &g[e+leng_red-lenf], &f_e);
|
||||
}
|
||||
leng_red--;
|
||||
}
|
||||
|
||||
// Rescale manual result
|
||||
if( leng < lenf){
|
||||
fp_mont_setone(scale.re);fp_set(scale.im,0);
|
||||
}
|
||||
else
|
||||
if(lenf == 2 && leng == 3)
|
||||
{
|
||||
fp2_sqr(&scale, &f[1]);
|
||||
fp2_add(&scale, &scale, &scale);
|
||||
}
|
||||
else
|
||||
fp2_copy(&scale, &c);
|
||||
for(e = 0; e < leng_red; e++)
|
||||
fp2_mul(&g[e], &g[e], &scale);
|
||||
|
||||
|
||||
// Comapre results
|
||||
for(e = leng_red-1; e >= 0; e--)
|
||||
assert(fp2_isequal(h[e], g[e]));
|
||||
for(e = leng_red; e < lenf-1; e++)
|
||||
assert(fp2_is_zero(&h[e]));
|
||||
|
||||
free(g);
|
||||
free(h);
|
||||
if(leng >= lenf)
|
||||
free(f_rev_inv);
|
||||
}
|
||||
free(f);
|
||||
free(f_rev);
|
||||
}
|
||||
printf("[%3d%%] Tested polynomial reduction:\tNo errors!\n", 100 * lenf / nmax);
|
||||
|
||||
|
||||
|
||||
// TEST FOR RECIPROCAL TREES
|
||||
|
||||
for(tree_size = 3; tree_size < nmax; tree_size++)
|
||||
{
|
||||
printf("[%3d%%] Testing reciprocal tree:\t\tTree size %d out of %d", 100 * tree_size / nmax, tree_size, nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
// Compute size of arrays
|
||||
i = 0;
|
||||
while((1<<i) < tree_size){
|
||||
i++;
|
||||
}
|
||||
array_size = (1<<(i+2))-1;
|
||||
|
||||
DEG = malloc(sizeof(int)*array_size);
|
||||
H = malloc(sizeof(poly)*array_size);
|
||||
R = malloc(sizeof(poly)*array_size);
|
||||
F = malloc(sizeof(poly)*tree_size);
|
||||
A = malloc(sizeof(fp2_t)*array_size);
|
||||
|
||||
// Get random polys
|
||||
LENF = 2;
|
||||
for(i = 0; i < tree_size; i++)
|
||||
{
|
||||
F[i] = malloc(sizeof(fp2_t)*LENF);
|
||||
for(e = 0; e < LENF; e++){
|
||||
fp2_random(&F[i][e]);
|
||||
}
|
||||
}
|
||||
|
||||
// Get product tree then reciprocal tree
|
||||
product_tree(H, DEG, 0, F, LENF, tree_size);
|
||||
leng = DEG[0]+1+(rand() % nmax);
|
||||
reciprocal_tree(R, A, leng, H, DEG, 0, tree_size);
|
||||
|
||||
// Check the root
|
||||
root = 0;
|
||||
lenf = leng-DEG[root];
|
||||
f = malloc(sizeof(fp2_t)*lenf);
|
||||
for(e = 0; e < DEG[root]+1 && e < lenf; e++){
|
||||
fp2_copy(&f[e], &H[root][DEG[root]-e]);
|
||||
}
|
||||
for(e = DEG[root]+1; e < lenf; e++){
|
||||
fp2_set(&f[e], 0);
|
||||
}
|
||||
poly_mul_low(f, lenf, f, lenf, R[root], lenf);
|
||||
assert(fp2_isequal(f[0], A[root]));
|
||||
for(e = 1; e < lenf; e++){
|
||||
assert(fp2_is_zero(&f[e]));
|
||||
}
|
||||
free(f);
|
||||
|
||||
// Perform random walks
|
||||
for(iteration = 0; iteration < nmax - tree_size; iteration++)
|
||||
{
|
||||
root = 0;
|
||||
n = tree_size;
|
||||
while(n > 1)
|
||||
{
|
||||
if(rand() & 1)
|
||||
{
|
||||
root = 2*root+1;
|
||||
n = n - (n>>1);
|
||||
}
|
||||
else
|
||||
{
|
||||
root = 2*root+2;
|
||||
n = n>>1;
|
||||
}
|
||||
brother = root - 1 + 2*(root & 1);
|
||||
|
||||
// Check current node
|
||||
if(DEG[root] > 2)
|
||||
{
|
||||
lenf = DEG[brother];
|
||||
f = malloc(sizeof(fp2_t)*lenf);
|
||||
for(e = 0; e < DEG[root]+1 && e < lenf; e++){
|
||||
fp2_copy(&f[e], &H[root][DEG[root]-e]);
|
||||
}
|
||||
for(e = DEG[root]+1; e < lenf; e++){
|
||||
fp2_set(&f[e], 0);
|
||||
}
|
||||
poly_mul_low(f, lenf, f, lenf, R[root], lenf);
|
||||
assert(fp2_isequal(f[0], A[root]));
|
||||
for(e = 1; e < lenf; e++){
|
||||
assert(fp2_is_zero(&f[e]));
|
||||
}
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Clean up
|
||||
for(i = 0; i < tree_size; i++)
|
||||
free(F[i]);
|
||||
clear_tree(H, 0, tree_size);
|
||||
clear_tree(R, 0, tree_size);
|
||||
free(F);
|
||||
free(H);
|
||||
free(R);
|
||||
free(A);
|
||||
free(DEG);
|
||||
}
|
||||
printf("[%3d%%] Tested reciprocal tree:\t\tNo errors!\n", 100 * tree_size / nmax);
|
||||
|
||||
|
||||
|
||||
// TEST FOR REMAINDERS
|
||||
for(tree_size = 2; tree_size < nmax; tree_size++)
|
||||
{
|
||||
printf("[%3d%%] Testing batched remainders:\t\tTree size %d out of %d", 100 * tree_size / nmax, tree_size, nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
// Compute size of arrays
|
||||
i = 0;
|
||||
while((1<<i) < tree_size)
|
||||
i++;
|
||||
array_size = (1<<(i+2))-1;
|
||||
|
||||
DEG = malloc(sizeof(int)*array_size);
|
||||
H = malloc(sizeof(poly)*array_size);
|
||||
R = malloc(sizeof(poly)*array_size);
|
||||
F = malloc(sizeof(poly)*tree_size);
|
||||
A = malloc(sizeof(fp2_t)*array_size);
|
||||
REM1 = malloc(sizeof(fp2_t)*array_size);
|
||||
REM2 = malloc(sizeof(fp2_t)*array_size);
|
||||
C = malloc(sizeof(fp2_t)*tree_size);
|
||||
|
||||
// Get random polys
|
||||
LENF = 2;
|
||||
for(i = 0; i < tree_size; i++)
|
||||
{
|
||||
F[i] = malloc(sizeof(fp2_t)*LENF);
|
||||
for(e = 0; e < LENF; e++)
|
||||
fp2_random(&F[i][e]);
|
||||
}
|
||||
|
||||
// Get product tree, reciprocal tree, and remainders
|
||||
product_tree(H, DEG, 0, F, LENF, tree_size);
|
||||
leng = DEG[0]+1+(rand() % nmax);
|
||||
g1 = malloc(sizeof(fp2_t)*leng);
|
||||
g2 = malloc(sizeof(fp2_t)*leng);
|
||||
for(e = 0; e < leng; e++)
|
||||
{
|
||||
fp2_random(&g1[e]);
|
||||
fp2_random(&g2[e]);
|
||||
}
|
||||
reciprocal_tree(R, A, leng, H, DEG, 0, tree_size);
|
||||
multieval_unscaled(REM1, g1, leng, R, (const fp2_t*)A, H, DEG, 0, tree_size);
|
||||
multieval_unscaled(REM2, g2, leng, R, (const fp2_t*)A, H, DEG, 0, tree_size);
|
||||
|
||||
for(i = 0; i < tree_size; i++)
|
||||
{
|
||||
// Get ratio of the remainder
|
||||
fp2_inv(&REM1[i]);
|
||||
fp2_mul(&ratio, &REM1[i], &REM2[i]);
|
||||
|
||||
// Compute remainders manually
|
||||
f_rev = malloc(sizeof(fp2_t)*LENF);
|
||||
f_rev_inv = malloc(sizeof(fp2_t)*(leng-LENF+1));
|
||||
h = malloc(sizeof(fp2_t)*(LENF-1));
|
||||
for(e = 0; e < LENF; e++)
|
||||
fp2_copy(&f_rev[e], &F[i][LENF-1-e]);
|
||||
reciprocal(f_rev_inv, &c, f_rev, LENF, leng-LENF+1);
|
||||
poly_redc(h, g1, leng, F[i], LENF, f_rev_inv, c);
|
||||
fp2_copy(&REM1[i], &h[0]);
|
||||
poly_redc(h, g2, leng, F[i], LENF, f_rev_inv, c);
|
||||
fp2_copy(&REM2[i], &h[0]);
|
||||
free(f_rev);
|
||||
free(f_rev_inv);
|
||||
free(h);
|
||||
|
||||
// Compare results
|
||||
fp2_inv(&REM1[i]);
|
||||
fp2_mul(&REM1[i], &REM1[i], &REM2[i]);
|
||||
assert(fp2_isequal(REM1[i], ratio));
|
||||
}
|
||||
|
||||
// Clean up
|
||||
for(i = 0; i < tree_size; i++)
|
||||
free(F[i]);
|
||||
free(g1);
|
||||
free(g2);
|
||||
clear_tree(H, 0, tree_size);
|
||||
clear_tree(R, 0, tree_size);
|
||||
free(F);
|
||||
free(H);
|
||||
free(R);
|
||||
free(A);
|
||||
free(DEG);
|
||||
free(REM1);
|
||||
free(REM2);
|
||||
free(C);
|
||||
}
|
||||
printf("[%3d%%] Tested batched remainders:\tNo errors!\n", 100 * tree_size / nmax);
|
||||
|
||||
|
||||
|
||||
// TEST FOR SCALED REMAINDER TREE
|
||||
for(tree_size = 1; tree_size < nmax; tree_size++)
|
||||
{
|
||||
printf("[%3d%%] Testing scaled remainder tree:\tTree size %d out of %d", 100 * tree_size / nmax, tree_size, nmax);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
// Compute size of arrays
|
||||
i = 0;
|
||||
while((1<<i) < tree_size)
|
||||
i++;
|
||||
array_size = (1<<(i+2))-1;
|
||||
|
||||
DEG = malloc(sizeof(int)*array_size);
|
||||
H = malloc(sizeof(poly)*array_size);
|
||||
F = malloc(sizeof(poly)*tree_size);
|
||||
REM1 = malloc(sizeof(fp2_t)*array_size);
|
||||
REM2 = malloc(sizeof(fp2_t)*array_size);
|
||||
|
||||
// Get random polys
|
||||
LENF = 2;
|
||||
for(i = 0; i < tree_size; i++)
|
||||
{
|
||||
F[i] = malloc(sizeof(fp2_t)*LENF);
|
||||
for(e = 0; e < LENF; e++)
|
||||
fp2_random(&F[i][e]);
|
||||
}
|
||||
|
||||
// Get random polys to reduce
|
||||
product_tree(H, DEG, 0, F, LENF, tree_size);
|
||||
leng = DEG[0]+1+(rand() % nmax);
|
||||
g1 = malloc(sizeof(fp2_t)*leng);
|
||||
g2 = malloc(sizeof(fp2_t)*leng);
|
||||
for(e = 0; e < leng; e++)
|
||||
{
|
||||
fp2_random(&g1[e]);
|
||||
fp2_random(&g2[e]);
|
||||
}
|
||||
|
||||
// Get the required initial nodes
|
||||
G1 = malloc(sizeof(fp2_t)*DEG[0]);
|
||||
G2 = malloc(sizeof(fp2_t)*DEG[0]);
|
||||
G1_rev = malloc(sizeof(fp2_t)*DEG[0]);
|
||||
G2_rev = malloc(sizeof(fp2_t)*DEG[0]);
|
||||
R0 = malloc(sizeof(fp2_t)*(leng));
|
||||
f_rev = malloc(sizeof(fp2_t)*(DEG[0]+1));
|
||||
for(e = 0; e < DEG[0]+1; e++)
|
||||
fp2_copy(&f_rev[e], &H[0][DEG[0]-e]);
|
||||
if( DEG[0] > leng-DEG[0])
|
||||
reciprocal(R0, &A0, f_rev, DEG[0]+1, DEG[0]);
|
||||
else
|
||||
reciprocal(R0, &A0, f_rev, DEG[0]+1, leng-DEG[0]);
|
||||
poly_redc(G1, g1, leng, H[0], DEG[0]+1, R0, A0);
|
||||
poly_redc(G2, g2, leng, H[0], DEG[0]+1, R0, A0);
|
||||
for(e = 0; e < DEG[0]; e++)
|
||||
{
|
||||
fp2_copy(&G1_rev[e], &G1[DEG[0]-1-e]);
|
||||
fp2_copy(&G2_rev[e], &G2[DEG[0]-1-e]);
|
||||
}
|
||||
poly_mul_middle(G1_rev, G1_rev, DEG[0], R0, DEG[0]);
|
||||
poly_mul_middle(G2_rev, G2_rev, DEG[0], R0, DEG[0]);
|
||||
for(e = 0; e < DEG[0]; e++)
|
||||
{
|
||||
fp2_copy(&G1[e], &G1_rev[DEG[0]-1-e]);
|
||||
fp2_copy(&G2[e], &G2_rev[DEG[0]-1-e]);
|
||||
}
|
||||
free(G1_rev);free(G2_rev);free(R0);free(f_rev);
|
||||
|
||||
// Compute the scaled remainder trees
|
||||
multieval_scaled(REM1, G1, H, DEG, 0, tree_size);
|
||||
multieval_scaled(REM2, G2, H, DEG, 0, tree_size);
|
||||
|
||||
for(i = 0; i < tree_size; i++)
|
||||
{
|
||||
// Get ratio of the remainder
|
||||
fp2_inv(&REM1[i]);
|
||||
fp2_mul(&ratio, &REM1[i], &REM2[i]);
|
||||
|
||||
// Compute remainders manually
|
||||
f_rev = malloc(sizeof(fp2_t)*LENF);
|
||||
f_rev_inv = malloc(sizeof(fp2_t)*(leng-LENF+1));
|
||||
h = malloc(sizeof(fp2_t)*(LENF-1));
|
||||
for(e = 0; e < LENF; e++)
|
||||
fp2_copy(&f_rev[e], &F[i][LENF-1-e]);
|
||||
reciprocal(f_rev_inv, &c, f_rev, LENF, leng-LENF+1);
|
||||
poly_redc(h, g1, leng, F[i], LENF, f_rev_inv, c);
|
||||
fp2_copy(&REM1[i], &h[0]);
|
||||
poly_redc(h, g2, leng, F[i], LENF, f_rev_inv, c);
|
||||
fp2_copy(&REM2[i], &h[0]);
|
||||
free(f_rev);free(f_rev_inv);free(h);
|
||||
|
||||
// Compare results
|
||||
fp2_inv(&REM1[i]);
|
||||
fp2_mul(&REM1[i], &REM1[i], &REM2[i]);
|
||||
assert(fp2_isequal(REM1[i], ratio));
|
||||
}
|
||||
|
||||
// Clean up
|
||||
for(i = 0; i < tree_size; i++)
|
||||
free(F[i]);
|
||||
free(F);free(g1);free(g2);free(G1);free(G2);
|
||||
clear_tree(H, 0, tree_size);free(H);free(DEG);
|
||||
free(REM1);free(REM2);
|
||||
}
|
||||
printf("[%3d%%] Tested scaled remainder tree:\tNo errors!\n", 100 * tree_size / nmax);
|
||||
|
||||
printf("-- All tests passed.\n");
|
||||
}
|
||||
75
src/ec/ref/ecx/test/test_extras.c
Executable file
75
src/ec/ref/ecx/test/test_extras.c
Executable file
@@ -0,0 +1,75 @@
|
||||
#include "test_extras.h"
|
||||
#include <bench.h>
|
||||
|
||||
// Global constants
|
||||
extern const digit_t p[NWORDS_FIELD];
|
||||
extern const digit_t R2[NWORDS_FIELD];
|
||||
|
||||
|
||||
#if 0
|
||||
int64_t cpucycles(void)
|
||||
{ // Access system counter for benchmarking
|
||||
unsigned int hi, lo;
|
||||
|
||||
asm volatile ("rdtsc\n\t" : "=a" (lo), "=d"(hi));
|
||||
return ((int64_t)lo) | (((int64_t)hi) << 32);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int compare_words(digit_t* a, digit_t* b, unsigned int nwords)
|
||||
{ // Comparing "nword" elements, a=b? : (1) a>b, (0) a=b, (-1) a<b
|
||||
// SECURITY NOTE: this function does not have constant-time execution. TO BE USED FOR TESTING ONLY.
|
||||
int i;
|
||||
|
||||
for (i = nwords-1; i >= 0; i--)
|
||||
{
|
||||
if (a[i] > b[i]) return 1;
|
||||
else if (a[i] < b[i]) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void sub_test(digit_t* out, digit_t* a, digit_t* b, unsigned int nwords)
|
||||
{ // Subtraction without borrow, out = a-b where a>b
|
||||
// SECURITY NOTE: this function does not have constant-time execution. It is for TESTING ONLY.
|
||||
unsigned int i;
|
||||
digit_t res, carry, borrow = 0;
|
||||
|
||||
for (i = 0; i < nwords; i++)
|
||||
{
|
||||
res = a[i] - b[i];
|
||||
carry = (a[i] < b[i]);
|
||||
out[i] = res - borrow;
|
||||
borrow = carry || (res < borrow);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fprandom_test(digit_t* a)
|
||||
{ // Generating a pseudo-random field element in [0, p-1]
|
||||
// SECURITY NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY.
|
||||
unsigned int i, diff = 256-254, nwords = NWORDS_FIELD;
|
||||
unsigned char* string = NULL;
|
||||
|
||||
string = (unsigned char*)a;
|
||||
for (i = 0; i < sizeof(digit_t)*nwords; i++) {
|
||||
*(string + i) = (unsigned char)rand(); // Obtain 256-bit number
|
||||
}
|
||||
a[nwords-1] &= (((digit_t)(-1) << diff) >> diff);
|
||||
|
||||
while (compare_words((digit_t*)p, a, nwords) < 1) { // Force it to [0, modulus-1]
|
||||
sub_test(a, a, (digit_t*)p, nwords);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fp2random_test(fp2_t* a)
|
||||
{ // Generating a pseudo-random element in GF(p^2)
|
||||
// SECURITY NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY.
|
||||
|
||||
fprandom_test(a->re);
|
||||
fprandom_test(a->im);
|
||||
}
|
||||
29
src/ec/ref/ecx/test/test_extras.h
Executable file
29
src/ec/ref/ecx/test/test_extras.h
Executable file
@@ -0,0 +1,29 @@
|
||||
|
||||
#ifndef TEST_EXTRAS_H
|
||||
#define TEST_EXTRAS_H
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <fp.h>
|
||||
#include <fp2.h>
|
||||
#include <curve_extras.h>
|
||||
|
||||
#define PASSED 0
|
||||
#define FAILED 1
|
||||
|
||||
// Access system counter for benchmarking
|
||||
//int64_t cpucycles(void);
|
||||
|
||||
// Comparing "nword" elements, a=b? : (1) a!=b, (0) a=b
|
||||
int compare_words(digit_t* a, digit_t* b, unsigned int nwords);
|
||||
|
||||
// Multiprecision subtraction for testing, assumes a > b
|
||||
void sub_test(digit_t* out, digit_t* a, digit_t* b, unsigned int nwords);
|
||||
|
||||
// Generating a pseudo-random field element in [0, p-1]
|
||||
void fprandom_test(digit_t* a);
|
||||
|
||||
// Generating a pseudo-random element in GF(p^2)
|
||||
void fp2random_test(fp2_t* a);
|
||||
|
||||
#endif
|
||||
298
src/ec/ref/ecx/test/velu-test.c
Normal file
298
src/ec/ref/ecx/test/velu-test.c
Normal file
@@ -0,0 +1,298 @@
|
||||
#include<time.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "isog.h"
|
||||
#include "sdacs.h"
|
||||
#include "ec.h"
|
||||
#include "test-basis.h"
|
||||
|
||||
void random_scalar(fp_t k, const uint8_t j)
|
||||
{
|
||||
for(int i = 0; i < NWORDS_FIELD; i++)
|
||||
k[i] = rand();
|
||||
}
|
||||
|
||||
// Affine Montgomery coefficient computation (A + 2C : 4C) --> A/C
|
||||
void coeff(fp2_t *B, ec_point_t const A)
|
||||
{
|
||||
fp2_t t;
|
||||
fp2_add(&t, &A.x, &A.x); // (2 * A24)
|
||||
fp2_sub(&t, &t, &A.z); // (2 * A24) - C24
|
||||
|
||||
fp2_copy(&*B, &A.z);
|
||||
fp2_inv(&*B); // 1 / (C24)
|
||||
fp2_add(&t, &t, &t); // 4*A = 2[(2 * A24) - C24]
|
||||
fp2_mul(&*B, &t, &*B); // A/C = 2[(2 * A24) - C24] / C24
|
||||
}
|
||||
|
||||
// Determines if point is fp2-rational (if not, then it must be a zero trace point)
|
||||
uint8_t isrational(ec_point_t const T, fp2_t const a)
|
||||
{
|
||||
fp2_t XT, tmp, aux, YT_squared;
|
||||
|
||||
fp2_copy(&XT, &T.z);
|
||||
fp2_inv(&XT);
|
||||
|
||||
fp2_mul(&XT, &XT, &T.x);
|
||||
|
||||
fp2_sqr(&tmp, &XT);
|
||||
fp2_mul(&aux, &tmp, &XT);
|
||||
fp2_mul(&tmp, &tmp, &a);
|
||||
fp2_add(&YT_squared, &tmp, &aux);
|
||||
fp2_add(&YT_squared, &YT_squared, &XT);
|
||||
|
||||
return fp2_is_square(&YT_squared);
|
||||
}
|
||||
|
||||
// ladder3pt computes x(P + [m]Q)
|
||||
void ladder3pt(ec_point_t *R, fp_t const m, ec_point_t const *P, ec_point_t const *Q, ec_point_t const *PQ, ec_point_t const *A)
|
||||
{
|
||||
ec_point_t X0, X1, X2;
|
||||
copy_point(&X0, Q);
|
||||
copy_point(&X1, P);
|
||||
copy_point(&X2, PQ);
|
||||
|
||||
int i,j;
|
||||
uint64_t t;
|
||||
for (i = 0; i < NWORDS_FIELD; i++)
|
||||
{
|
||||
t = 1;
|
||||
for (j = 0 ; j < 64; j++)
|
||||
{
|
||||
swap_points(&X1, &X2, -((t & m[i]) == 0));
|
||||
xDBLADD(&X0, &X1, &X0, &X1, &X2, A);
|
||||
swap_points(&X1, &X2, -((t & m[i]) == 0));
|
||||
t <<= 1;
|
||||
};
|
||||
};
|
||||
copy_point(R, &X1);
|
||||
}
|
||||
|
||||
// The projective x-coordinate point (X : Z) at infinity is such that Z == 0
|
||||
static inline int isinfinity(ec_point_t const P)
|
||||
{
|
||||
return fp2_is_zero(&P.z);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
fp2_t fp2_0, fp2_1;
|
||||
fp2_set(&fp2_0, 0);
|
||||
fp_mont_setone(fp2_1.re);fp_set(fp2_1.im,0);
|
||||
|
||||
int i, j;
|
||||
|
||||
ec_point_t A, B, T;
|
||||
fp2_set(&A.x, 0);
|
||||
fp_mont_setone(A.z.re);fp_set(A.z.im,0);
|
||||
|
||||
// fp2_add(&A.x, &A.z, &A.x); // 1
|
||||
// fp2_add(&A.x, &A.x, &A.x); // 2
|
||||
// fp2_add(&A.x, &A.z, &A.x); // 3
|
||||
// fp2_add(&A.x, &A.x, &A.x); // 6
|
||||
|
||||
fp2_add(&A.z, &A.z, &A.z); // 2C
|
||||
fp2_add(&A.x, &A.x, &A.z); // A' + 2C
|
||||
fp2_add(&A.z, &A.z, &A.z); // 4C
|
||||
|
||||
// Just to ensure the projective curve coeffientes are different from zero
|
||||
assert( !fp2_is_zero(&A.x) & !fp2_is_zero(&A.x) );
|
||||
|
||||
fp2_t a;
|
||||
coeff(&a, A);
|
||||
|
||||
ec_point_t PA, QA, PQA, PB, QB, PQB, RA, RB;
|
||||
|
||||
// Writing the public projective x-coordinate points into Montogmery domain
|
||||
fp2_tomont(&(PA.x), &(xPA));
|
||||
fp_mont_setone(PA.z.re);fp_set(PA.z.im,0);
|
||||
fp2_tomont(&(QA.x), &(xQA));
|
||||
fp_mont_setone(QA.z.re);fp_set(QA.z.im,0);
|
||||
fp2_tomont(&(PQA.x), &(xPQA));
|
||||
fp_mont_setone(PQA.z.re);fp_set(PQA.z.im,0);
|
||||
|
||||
assert( isrational(PA, a) );
|
||||
assert( isrational(QA, a) );
|
||||
assert( isrational(PQA, a) );
|
||||
|
||||
fp2_tomont(&(PB.x), &(xPB));
|
||||
fp_mont_setone(PB.z.re);fp_set(PB.z.im,0);
|
||||
fp2_tomont(&(QB.x), &(xQB));
|
||||
fp_mont_setone(QB.z.re);fp_set(QB.z.im,0);
|
||||
fp2_tomont(&(PQB.x), &(xPQB));
|
||||
fp_mont_setone(PQB.z.re);fp_set(PQB.z.im,0);
|
||||
|
||||
assert( !isrational(PB, a) );
|
||||
assert( !isrational(QB, a) );
|
||||
assert( !isrational(PQB, a) );
|
||||
// ======================================================================================================
|
||||
// Recall, PA, QA, and PQA are expeted to be N-order points, but we require to ensure they are of order N
|
||||
for (j = 0; j < P_LEN; j++)
|
||||
{
|
||||
for (i = 1; i < TORSION_ODD_POWERS[j]; i++)
|
||||
{
|
||||
xMULv2(&PA, &PA, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
xMULv2(&QA, &QA, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
xMULv2(&PQA, &PQA, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
|
||||
assert( isrational(PA, a) );
|
||||
assert( isrational(QA, a) );
|
||||
assert( isrational(PQA, a) );
|
||||
};
|
||||
};
|
||||
|
||||
assert( !isinfinity(PA) );
|
||||
assert( !isinfinity(QA) );
|
||||
assert( !isinfinity(PQA) );
|
||||
|
||||
// --------------------------------------------------------------
|
||||
fp_t m;
|
||||
random_scalar(m, 0);
|
||||
ladder3pt(&RA, m, &PA, &QA, &PQA, &A);
|
||||
for (i = 0; i < P_LEN; i++)
|
||||
{
|
||||
printf("// Processing the %d-th prime:\t", i + 1);
|
||||
printf("%2d%%", 100 * i / (int)P_LEN);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
copy_point(&T, &RA);
|
||||
for (j = (i+1); j < P_LEN; j++)
|
||||
xMULv2(&T, &T, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
|
||||
assert( !isinfinity(T) );
|
||||
|
||||
kps(i, T, A);
|
||||
if (TORSION_ODD_PRIMES[i] > gap)
|
||||
printf("[\033[0;31m%7" PRId64 "\033[0m] (#I: %3d, #J: %3d, #K: %3d) \n", TORSION_ODD_PRIMES[i], sI, sJ, sK);
|
||||
else
|
||||
printf("[\033[0;31m%7" PRId64 "\033[0m] --------------------------- \n", TORSION_ODD_PRIMES[i]);
|
||||
|
||||
xisog(&B, i, A);
|
||||
|
||||
xeval(&PB, i, PB, A);
|
||||
coeff(&a, B);
|
||||
assert( !isinfinity(PB) );
|
||||
assert( !isrational(PB, a) );
|
||||
|
||||
xeval(&RA, i, RA, A);
|
||||
assert( (!isinfinity(RA) && (i < (P_LEN - 1))) || (isinfinity(RA) && (i == (P_LEN - 1))) );
|
||||
assert( (isrational(RA, a) && (i < (P_LEN - 1))) || (isinfinity(RA) && (i == (P_LEN - 1))) );
|
||||
|
||||
copy_point(&A, &B);
|
||||
// Verifying the order of the image point of PA has been reduced
|
||||
copy_point(&T, &RA);
|
||||
for (j = (i+1); j < P_LEN; j++)
|
||||
xMULv2(&T, &T, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
|
||||
assert( isinfinity(T) );
|
||||
kps_clear(i);
|
||||
};
|
||||
|
||||
fp2_set(&A.x, 0);
|
||||
fp_mont_setone(A.z.re);fp_set(A.z.im,0);
|
||||
|
||||
// fp2_add(&A.x, &A.z, &A.x); // 1
|
||||
// fp2_add(&A.x, &A.x, &A.x); // 2
|
||||
// fp2_add(&A.x, &A.z, &A.x); // 3
|
||||
// fp2_add(&A.x, &A.x, &A.x); // 6
|
||||
|
||||
fp2_add(&A.z, &A.z, &A.z); // 2C
|
||||
fp2_add(&A.x, &A.x, &A.z); // A' + 2C
|
||||
fp2_add(&A.z, &A.z, &A.z); // 4C
|
||||
|
||||
// Just to ensure the projective curve coeffientes are different from zero
|
||||
assert( !fp2_is_zero(&A.x) & !fp2_is_zero(&A.x) );
|
||||
|
||||
coeff(&a, A);
|
||||
// Writing the public projective x-coordinate points into Montogmery domain
|
||||
fp2_tomont(&(PA.x), &(xPA));
|
||||
fp_mont_setone(PA.z.re);fp_set(PA.z.im,0);
|
||||
fp2_tomont(&(QA.x), &(xQA));
|
||||
fp_mont_setone(QA.z.re);fp_set(QA.z.im,0);
|
||||
fp2_tomont(&(PQA.x), &(xPQA));
|
||||
fp_mont_setone(PQA.z.re);fp_set(PQA.z.im,0);
|
||||
|
||||
assert( isrational(PA, a) );
|
||||
assert( isrational(QA, a) );
|
||||
assert( isrational(PQA, a) );
|
||||
|
||||
fp2_tomont(&(PB.x), &(xPB));
|
||||
fp_mont_setone(PB.z.re);fp_set(PB.z.im,0);
|
||||
fp2_tomont(&(QB.x), &(xQB));
|
||||
fp_mont_setone(QB.z.re);fp_set(QB.z.im,0);
|
||||
fp2_tomont(&(PQB.x), &(xPQB));
|
||||
fp_mont_setone(PQB.z.re);fp_set(PQB.z.im,0);
|
||||
|
||||
assert( !isrational(PB, a) );
|
||||
assert( !isrational(QB, a) );
|
||||
assert( !isrational(PQB, a) );
|
||||
|
||||
// ======================================================================================================
|
||||
// Recall, PA, QA, and PQA are expeted to be N-order points, but we require to ensure they are of order N
|
||||
for (j = P_LEN; j < (P_LEN+M_LEN); j++)
|
||||
{
|
||||
for (i = 1; i < TORSION_ODD_POWERS[j]; i++)
|
||||
{
|
||||
xMULv2(&PB, &PB, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
xMULv2(&QB, &QB, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
xMULv2(&PQB, &PQB, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
|
||||
assert( !isrational(PB, a) );
|
||||
assert( !isrational(QB, a) );
|
||||
assert( !isrational(PQB, a) );
|
||||
};
|
||||
};
|
||||
|
||||
assert( !isinfinity(PB) );
|
||||
assert( !isinfinity(QB) );
|
||||
assert( !isinfinity(PQB) );
|
||||
|
||||
random_scalar(m, 1);
|
||||
ladder3pt(&RB, m, &PB, &QB, &PQB, &A);
|
||||
for (i = P_LEN; i < (P_LEN+M_LEN); i++)
|
||||
{
|
||||
printf("// Processing the %d-th prime:\t", i + 1);
|
||||
printf("%2d%%", 100 * i / (int)(P_LEN+M_LEN));
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
copy_point(&T, &RB);
|
||||
for (j = (i+1); j < (P_LEN+M_LEN); j++)
|
||||
xMULv2(&T, &T, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
|
||||
assert( !isinfinity(T) );
|
||||
|
||||
kps(i, T, A);
|
||||
if (TORSION_ODD_PRIMES[i] > gap)
|
||||
printf("[\033[0;31m%7" PRId64 "\033[0m] (#I: %3d, #J: %3d, #K: %3d) \n", TORSION_ODD_PRIMES[i], sI, sJ, sK);
|
||||
else
|
||||
printf("[\033[0;31m%7" PRId64 "\033[0m] --------------------------- \n", TORSION_ODD_PRIMES[i]);
|
||||
|
||||
xisog(&B, i, A);
|
||||
|
||||
xeval(&PA, i, PA, A);
|
||||
coeff(&a, B);
|
||||
assert( !isinfinity(PA) );
|
||||
assert( isrational(PA, a) );
|
||||
|
||||
xeval(&RB, i, RB, A);
|
||||
assert( (!isinfinity(RB) && (i < (P_LEN + M_LEN - 1))) || (isinfinity(RB) && (i == (P_LEN + M_LEN - 1))) );
|
||||
assert( (!isrational(RB, a) && (i < (P_LEN + M_LEN - 1))) || (isinfinity(RB) && (i == (P_LEN + M_LEN - 1))) );
|
||||
|
||||
copy_point(&A, &B);
|
||||
// Verifying the order of the image point of PB has been reduced
|
||||
copy_point(&T, &RB);
|
||||
for (j = (i+1); j < (P_LEN+M_LEN); j++)
|
||||
xMULv2(&T, &T, &(TORSION_ODD_PRIMES[j]), p_plus_minus_bitlength[j], &A);
|
||||
|
||||
assert( isinfinity(T) );
|
||||
kps_clear(i);
|
||||
};
|
||||
|
||||
printf("-- All tests passed!\n");
|
||||
return 0;
|
||||
}
|
||||
299
src/ec/ref/ecx/xeval.c
Normal file
299
src/ec/ref/ecx/xeval.c
Normal 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
295
src/ec/ref/ecx/xisog.c
Normal 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);
|
||||
}
|
||||
28
src/ec/ref/include/curve_extras.h
Normal file
28
src/ec/ref/include/curve_extras.h
Normal 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
776
src/ec/ref/include/ec.h
Normal 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
84
src/ec/ref/include/isog.h
Normal 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
28
src/ec/ref/include/poly.h
Normal 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 */
|
||||
50
src/ec/ref/include/sdacs.h
Normal file
50
src/ec/ref/include/sdacs.h
Normal 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
28
src/ec/ref/include/tedwards.h
Executable 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
|
||||
17
src/ec/ref/lvl1/CMakeLists.txt
Normal file
17
src/ec/ref/lvl1/CMakeLists.txt
Normal 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)
|
||||
36
src/ec/ref/lvl1/test/CMakeLists.txt
Normal file
36
src/ec/ref/lvl1/test/CMakeLists.txt
Normal 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})
|
||||
400
src/ec/ref/lvl1/test/ec-tests.h
Normal file
400
src/ec/ref/lvl1/test/ec-tests.h
Normal 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
|
||||
24
src/ec/ref/lvl1/test/test-basis.h
Normal file
24
src/ec/ref/lvl1/test/test-basis.h
Normal 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
|
||||
17
src/ec/ref/lvl3/CMakeLists.txt
Normal file
17
src/ec/ref/lvl3/CMakeLists.txt
Normal 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)
|
||||
36
src/ec/ref/lvl3/test/CMakeLists.txt
Normal file
36
src/ec/ref/lvl3/test/CMakeLists.txt
Normal 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})
|
||||
400
src/ec/ref/lvl3/test/ec-tests.h
Normal file
400
src/ec/ref/lvl3/test/ec-tests.h
Normal 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
|
||||
24
src/ec/ref/lvl3/test/test-basis.h
Normal file
24
src/ec/ref/lvl3/test/test-basis.h
Normal 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
|
||||
17
src/ec/ref/lvl5/CMakeLists.txt
Normal file
17
src/ec/ref/lvl5/CMakeLists.txt
Normal 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)
|
||||
36
src/ec/ref/lvl5/test/CMakeLists.txt
Normal file
36
src/ec/ref/lvl5/test/CMakeLists.txt
Normal 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})
|
||||
400
src/ec/ref/lvl5/test/ec-tests.h
Normal file
400
src/ec/ref/lvl5/test/ec-tests.h
Normal 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
|
||||
24
src/ec/ref/lvl5/test/test-basis.h
Normal file
24
src/ec/ref/lvl5/test/test-basis.h
Normal 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
|
||||
Reference in New Issue
Block a user