second-round version of SQIsign
Co-authored-by: Marius A. Aardal <marius.andre.aardal@gmail.com> Co-authored-by: Gora Adj <gora.adj@tii.ae> Co-authored-by: Diego F. Aranha <dfaranha@cs.au.dk> Co-authored-by: Andrea Basso <sqisign@andreabasso.com> Co-authored-by: Isaac Andrés Canales Martínez <icanalesm0500@gmail.com> Co-authored-by: Jorge Chávez-Saab <jorgechavezsaab@gmail.com> Co-authored-by: Maria Corte-Real Santos <mariascrsantos98@gmail.com> Co-authored-by: Luca De Feo <github@defeo.lu> Co-authored-by: Max Duparc <max.duparc@epfl.ch> Co-authored-by: Jonathan Komada Eriksen <jonathan.eriksen97@gmail.com> Co-authored-by: Décio Luiz Gazzoni Filho <decio@decpp.net> Co-authored-by: Basil Hess <bhe@zurich.ibm.com> Co-authored-by: Antonin Leroux <antonin.leroux@polytechnique.org> Co-authored-by: Patrick Longa <plonga@microsoft.com> Co-authored-by: Luciano Maino <mainoluciano.96@gmail.com> Co-authored-by: Michael Meyer <michael@random-oracles.org> Co-authored-by: Hiroshi Onuki <onuki@mist.i.u-tokyo.ac.jp> Co-authored-by: Lorenz Panny <lorenz@yx7.cc> Co-authored-by: Giacomo Pope <giacomopope@gmail.com> Co-authored-by: Krijn Reijnders <reijnderskrijn@gmail.com> Co-authored-by: Damien Robert <damien.robert@inria.fr> Co-authored-by: Francisco Rodríguez-Henriquez <francisco.rodriguez@tii.ae> Co-authored-by: Sina Schaeffler <sschaeffle@student.ethz.ch> Co-authored-by: Benjamin Wesolowski <benjamin.wesolowski@ens-lyon.fr>
This commit is contained in:
committed by
Lorenz Panny
parent
ff34a8cd18
commit
91e9e464fe
2
src/ec/ref/CMakeLists.txt
Executable file → Normal file
2
src/ec/ref/CMakeLists.txt
Executable file → Normal file
@@ -1,3 +1,3 @@
|
||||
set(ECX_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ecx)
|
||||
set(LVLX_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lvlx)
|
||||
|
||||
include(${SELECT_SQISIGN_VARIANT})
|
||||
|
||||
@@ -1,508 +0,0 @@
|
||||
#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
1461
src/ec/ref/ecx/ec.c
File diff suppressed because it is too large
Load Diff
@@ -1,90 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,298 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
#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]);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,349 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <fp2.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
static int BENCH_LOOPS = 1000; // Number of iterations per bench
|
||||
static int TEST_LOOPS = 512; // Number of iterations per test
|
||||
|
||||
bool fp2_isequal(fp2_t a, fp2_t b){
|
||||
return fp_is_equal(a.re, b.re) && fp_is_equal(a.im, b.im);
|
||||
}
|
||||
|
||||
bool fp2_isone(fp2_t a){
|
||||
fp_t one;
|
||||
bool res = 1;
|
||||
fp_mont_setone(one);
|
||||
for(int i = 0; i < NWORDS_FIELD; i++){
|
||||
res = res && (a.re[i] == one[i]);
|
||||
res = res && (a.im[i] == 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void fp2_print(char *name, fp2_t const a){
|
||||
fp2_t b;
|
||||
fp2_set(&b, 1);
|
||||
fp2_mul(&b, &b, &a);
|
||||
printf("%s = 0x", name);
|
||||
for(int i = NWORDS_FIELD - 1; i >=0; i--)
|
||||
printf("%016" PRIx64, b.re[i]);
|
||||
printf(" + i*0x");
|
||||
for(int i = NWORDS_FIELD - 1; i >=0; i--)
|
||||
printf("%016" PRIx64, b.im[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// VERY NOT SECURE (testing only)
|
||||
void fp2_random(fp2_t *a){
|
||||
for(int i = 0; i < NWORDS_FIELD; i++){
|
||||
a->re[i] = rand();
|
||||
a->im[i] = rand();
|
||||
}
|
||||
// Normalize
|
||||
fp2_t one;
|
||||
fp_mont_setone(one.re);fp_set(one.im,0);
|
||||
fp2_mul(&*a, &*a, &one);
|
||||
// Update seed
|
||||
srand((unsigned) a->re[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc > 1) {
|
||||
TEST_LOOPS = atoi(argv[1]);
|
||||
}
|
||||
|
||||
fp2_t fp2_0, fp2_1;
|
||||
// ------------
|
||||
fp2_set(&fp2_0, 0);
|
||||
fp_mont_setone(fp2_1.re);fp_set(fp2_1.im,0);
|
||||
// ------------
|
||||
|
||||
int i;
|
||||
fp2_t a, b, c, d;
|
||||
fp_t e;
|
||||
|
||||
for (i = 0; i < TEST_LOOPS; i++)
|
||||
{
|
||||
printf("[%3d%%] Testing fp2_t arithmetic", 100 * i / (int)TEST_LOOPS);
|
||||
fflush(stdout);
|
||||
printf("\r\x1b[K");
|
||||
|
||||
// Random elements of fp
|
||||
fp2_random(&a);
|
||||
fp2_random(&b);
|
||||
fp2_copy(&c, &a);
|
||||
c.re[0] += 1;
|
||||
fp2_copy(&d, &b);
|
||||
d.re[0] -= 1;
|
||||
|
||||
assert(fp2_isequal(a,b) == 0); // different values check --> (a != b)
|
||||
assert(fp2_isequal(c,c) == 1); // equal values check --> 1 (c == c)
|
||||
|
||||
// Testing neg
|
||||
fp2_set(&b, 0);
|
||||
fp2_copy(&c, &a);
|
||||
fp2_neg(&a, &a);
|
||||
fp2_sub(&c, &b, &c);
|
||||
assert(fp2_isequal(a,c) == 1);
|
||||
|
||||
fp_mont_setone(a.re);fp_set(a.im,0); // Now a == 1
|
||||
fp2_set(&b, 0); // Now b == 0
|
||||
|
||||
assert(fp2_is_zero(&a) == 0);
|
||||
assert(fp2_is_zero(&b) == 1);
|
||||
|
||||
// testing c - c
|
||||
fp2_sub(&d, &c, &c);
|
||||
assert(fp2_is_zero(&d) == 1);
|
||||
|
||||
// tetsing c * 0
|
||||
fp2_mul(&d, &c, &b);
|
||||
assert(fp2_is_zero(&d) == 1);
|
||||
|
||||
// tetsing c * 1 ... recall, in Montgomery domain R mod p plays the role of the 1
|
||||
fp_mont_setone(a.re);fp_set(a.im,0);
|
||||
fp2_mul(&d, &c, &a);
|
||||
assert(fp2_isequal(d, c) == 1);
|
||||
|
||||
// fp_set(e, 1); // Now e == 1
|
||||
// fp2_pow(d, e, c);
|
||||
// assert(fp2_isequal(d, c) == 1);
|
||||
|
||||
// fp_set(e, 0); // Now e == 0
|
||||
// fp2_pow(d, e, c);
|
||||
// assert(fp2_isone(d) == 1);
|
||||
|
||||
// fp2_set(a, 1); // Now e == R mod p
|
||||
// fp_random(e);
|
||||
// fp2_pow(d, e, a);
|
||||
// assert(fp2_isone(d) == 1);
|
||||
|
||||
// Testing 1/a by computing (1/a) x a
|
||||
fp2_random(&a);
|
||||
fp2_copy(&b, &a);
|
||||
fp2_inv(&a);
|
||||
fp2_mul(&c, &a, &b);
|
||||
assert(fp2_isone(c) == 1);
|
||||
|
||||
fp2_random(&a);
|
||||
fp2_sqr(&b, &a);
|
||||
assert( fp2_is_square(&b) );
|
||||
|
||||
};
|
||||
|
||||
if(TEST_LOOPS){
|
||||
printf("[%2d%%] Tested fp2_t arithmetic:\tNo errors!\n", 100 * i /TEST_LOOPS);
|
||||
}
|
||||
printf("-- All tests passed.\n");
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,386 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,445 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -1,461 +0,0 @@
|
||||
#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");
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
|
||||
#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
|
||||
@@ -1,298 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,299 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
@@ -1,295 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
82
src/ec/ref/include/biextension.h
Normal file
82
src/ec/ref/include/biextension.h
Normal file
@@ -0,0 +1,82 @@
|
||||
#ifndef _BIEXT_H_
|
||||
#define _BIEXT_H_
|
||||
|
||||
#include <sqisign_namespace.h>
|
||||
#include <ec.h>
|
||||
|
||||
typedef struct pairing_params
|
||||
{
|
||||
uint32_t e; // Points have order 2^e
|
||||
ec_point_t P; // x(P)
|
||||
ec_point_t Q; // x(Q)
|
||||
ec_point_t PQ; // x(P-Q) = (PQX/PQZ : 1)
|
||||
fp2_t ixP; // PZ/PX
|
||||
fp2_t ixQ; // QZ/QX
|
||||
ec_point_t A24; // ((A+2)/4 : 1)
|
||||
} pairing_params_t;
|
||||
|
||||
// For two bases <P, Q> and <R, S> store:
|
||||
// x(P - R), x(P - S), x(R - Q), x(S - Q)
|
||||
typedef struct pairing_dlog_diff_points
|
||||
{
|
||||
ec_point_t PmR; // x(P - R)
|
||||
ec_point_t PmS; // x(P - S)
|
||||
ec_point_t RmQ; // x(R - Q)
|
||||
ec_point_t SmQ; // x(S - Q)
|
||||
} pairing_dlog_diff_points_t;
|
||||
|
||||
typedef struct pairing_dlog_params
|
||||
{
|
||||
uint32_t e; // Points have order 2^e
|
||||
ec_basis_t PQ; // x(P), x(Q), x(P-Q)
|
||||
ec_basis_t RS; // x(R), x(S), x(R-S)
|
||||
pairing_dlog_diff_points_t diff; // x(P - R), x(P - S), x(R - Q), x(S - Q)
|
||||
fp2_t ixP; // PZ/PX
|
||||
fp2_t ixQ; // QZ/QX
|
||||
fp2_t ixR; // RZ/RX
|
||||
fp2_t ixS; // SZ/SX
|
||||
ec_point_t A24; // ((A+2)/4 : 1)
|
||||
} pairing_dlog_params_t;
|
||||
|
||||
// Computes e = e_{2^e}(P, Q) using biextension ladder
|
||||
void weil(fp2_t *r, uint32_t e, const ec_point_t *P, const ec_point_t *Q, const ec_point_t *PQ, ec_curve_t *E);
|
||||
|
||||
// Computes (reduced) z = t_{2^e}(P, Q) using biextension ladder
|
||||
void reduced_tate(fp2_t *r, uint32_t e, const ec_point_t *P, const ec_point_t *Q, const ec_point_t *PQ, ec_curve_t *E);
|
||||
|
||||
// Given two bases <P, Q> and <R, S> computes scalars
|
||||
// such that R = [r1]P + [r2]Q, S = [s1]P + [s2]Q
|
||||
void ec_dlog_2_weil(digit_t *r1,
|
||||
digit_t *r2,
|
||||
digit_t *s1,
|
||||
digit_t *s2,
|
||||
ec_basis_t *PQ,
|
||||
const ec_basis_t *RS,
|
||||
ec_curve_t *curve,
|
||||
int e);
|
||||
|
||||
// Given two bases <P, Q> and <R, S>
|
||||
// where <P, Q> is a basis for E[2^f]
|
||||
// the full 2-torsion, and <R,S> a basis
|
||||
// for smaller torsion E[2^e]
|
||||
// computes scalars r1, r2, s1, s2
|
||||
// such that R = [r1]P + [r2]Q, S = [s1]P + [s2]Q
|
||||
void ec_dlog_2_tate(digit_t *r1,
|
||||
digit_t *r2,
|
||||
digit_t *s1,
|
||||
digit_t *s2,
|
||||
const ec_basis_t *PQ,
|
||||
const ec_basis_t *RS,
|
||||
ec_curve_t *curve,
|
||||
int e);
|
||||
|
||||
void ec_dlog_2_tate_to_full(digit_t *r1,
|
||||
digit_t *r2,
|
||||
digit_t *s1,
|
||||
digit_t *s2,
|
||||
ec_basis_t *PQ,
|
||||
ec_basis_t *RS,
|
||||
ec_curve_t *curve,
|
||||
int e);
|
||||
|
||||
#endif
|
||||
@@ -1,28 +0,0 @@
|
||||
#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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,84 +1,28 @@
|
||||
#ifndef _ISOG_H_
|
||||
#define _ISOG_H_
|
||||
#include <sqisign_namespace.h>
|
||||
#include <ec.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)
|
||||
/* KPS structure for isogenies of degree 2 or 4 */
|
||||
typedef struct
|
||||
{
|
||||
// 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)
|
||||
ec_point_t K;
|
||||
} ec_kps2_t;
|
||||
typedef struct
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
ec_point_t K[3];
|
||||
} ec_kps4_t;
|
||||
|
||||
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);
|
||||
}
|
||||
void xisog_2(ec_kps2_t *kps, ec_point_t *B, const ec_point_t P); // degree-2 isogeny construction
|
||||
void xisog_2_singular(ec_kps2_t *kps, ec_point_t *B24, ec_point_t A24);
|
||||
|
||||
void xisog_4(ec_kps4_t *kps, ec_point_t *B, const ec_point_t P); // degree-4 isogeny construction
|
||||
void xisog_4_singular(ec_kps4_t *kps, ec_point_t *B24, const ec_point_t P, ec_point_t A24);
|
||||
|
||||
void xeval_2(ec_point_t *R, ec_point_t *const Q, const int lenQ, const ec_kps2_t *kps);
|
||||
void xeval_2_singular(ec_point_t *R, const ec_point_t *Q, const int lenQ, const ec_kps2_t *kps);
|
||||
|
||||
void xeval_4(ec_point_t *R, const ec_point_t *Q, const int lenQ, const ec_kps4_t *kps);
|
||||
void xeval_4_singular(ec_point_t *R, const ec_point_t *Q, const int lenQ, const ec_point_t P, const ec_kps4_t *kps);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#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 */
|
||||
@@ -1,50 +0,0 @@
|
||||
#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
|
||||
@@ -1,28 +0,0 @@
|
||||
#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
|
||||
@@ -1,17 +1 @@
|
||||
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)
|
||||
include(../lvlx.cmake)
|
||||
@@ -1,36 +1 @@
|
||||
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})
|
||||
include(../../lvlx_test.cmake)
|
||||
|
||||
@@ -1,400 +0,0 @@
|
||||
#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
|
||||
@@ -1,24 +0,0 @@
|
||||
#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
|
||||
@@ -1,17 +1 @@
|
||||
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)
|
||||
include(../lvlx.cmake)
|
||||
|
||||
@@ -1,36 +1 @@
|
||||
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})
|
||||
include(../../lvlx_test.cmake)
|
||||
|
||||
@@ -1,400 +0,0 @@
|
||||
#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
|
||||
@@ -1,24 +0,0 @@
|
||||
#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
|
||||
@@ -1,17 +1 @@
|
||||
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)
|
||||
include(../lvlx.cmake)
|
||||
|
||||
@@ -1,36 +1 @@
|
||||
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})
|
||||
include(../../lvlx_test.cmake)
|
||||
|
||||
@@ -1,400 +0,0 @@
|
||||
#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
|
||||
@@ -1,24 +0,0 @@
|
||||
#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
|
||||
17
src/ec/ref/lvlx.cmake
Normal file
17
src/ec/ref/lvlx.cmake
Normal file
@@ -0,0 +1,17 @@
|
||||
set(SOURCE_FILES_EC_${SVARIANT_UPPER}_REF
|
||||
${LVLX_DIR}/ec.c
|
||||
${LVLX_DIR}/ec_jac.c
|
||||
${LVLX_DIR}/xisog.c
|
||||
${LVLX_DIR}/xeval.c
|
||||
${LVLX_DIR}/isog_chains.c
|
||||
${LVLX_DIR}/basis.c
|
||||
${LVLX_DIR}/biextension.c
|
||||
)
|
||||
|
||||
add_library(${LIB_EC_${SVARIANT_UPPER}} STATIC ${SOURCE_FILES_EC_${SVARIANT_UPPER}_REF})
|
||||
target_include_directories(${LIB_EC_${SVARIANT_UPPER}} PRIVATE ${INC_COMMON} ${INC_PRECOMP_${SVARIANT_UPPER}} ${INC_PUBLIC} ${INC_MP} ${INC_GF} ${INC_GF_${SVARIANT_UPPER}} ${INC_EC})
|
||||
target_compile_options(${LIB_EC_${SVARIANT_UPPER}} PRIVATE ${C_OPT_FLAGS})
|
||||
target_link_libraries(${LIB_EC_${SVARIANT_UPPER}} ${LIB_PRECOMP_${SVARIANT_UPPER}} ${LIB_MP} ${LIB_GF_${SVARIANT_UPPER}})
|
||||
target_compile_definitions(${LIB_EC_${SVARIANT_UPPER}} PUBLIC SQISIGN_VARIANT=${SVARIANT_LOWER})
|
||||
|
||||
add_subdirectory(test)
|
||||
416
src/ec/ref/lvlx/basis.c
Normal file
416
src/ec/ref/lvlx/basis.c
Normal file
@@ -0,0 +1,416 @@
|
||||
#include "ec.h"
|
||||
#include "fp2.h"
|
||||
#include "e0_basis.h"
|
||||
#include <assert.h>
|
||||
|
||||
uint32_t
|
||||
ec_recover_y(fp2_t *y, const fp2_t *Px, const ec_curve_t *curve)
|
||||
{ // Recover y-coordinate of a point on the Montgomery curve y^2 = x^3 + Ax^2 + x
|
||||
fp2_t t0;
|
||||
|
||||
fp2_sqr(&t0, Px);
|
||||
fp2_mul(y, &t0, &curve->A); // Ax^2
|
||||
fp2_add(y, y, Px); // Ax^2 + x
|
||||
fp2_mul(&t0, &t0, Px);
|
||||
fp2_add(y, y, &t0); // x^3 + Ax^2 + x
|
||||
// This is required, because we do not yet know that our curves are
|
||||
// supersingular so our points live on the twist with B = 1.
|
||||
return fp2_sqrt_verify(y);
|
||||
}
|
||||
|
||||
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 projective x-only, computes a deterministic choice for (P-Q)
|
||||
// Based on Proposition 3 of https://eprint.iacr.org/2017/518.pdf
|
||||
|
||||
fp2_t Bxx, Bxz, Bzz, t0, t1;
|
||||
|
||||
fp2_mul(&t0, &P->x, &Q->x);
|
||||
fp2_mul(&t1, &P->z, &Q->z);
|
||||
fp2_sub(&Bxx, &t0, &t1);
|
||||
fp2_sqr(&Bxx, &Bxx);
|
||||
fp2_mul(&Bxx, &Bxx, &curve->C); // C*(P.x*Q.x-P.z*Q.z)^2
|
||||
fp2_add(&Bxz, &t0, &t1);
|
||||
fp2_mul(&t0, &P->x, &Q->z);
|
||||
fp2_mul(&t1, &P->z, &Q->x);
|
||||
fp2_add(&Bzz, &t0, &t1);
|
||||
fp2_mul(&Bxz, &Bxz, &Bzz); // (P.x*Q.x+P.z*Q.z)(P.x*Q.z+P.z*Q.x)
|
||||
fp2_sub(&Bzz, &t0, &t1);
|
||||
fp2_sqr(&Bzz, &Bzz);
|
||||
fp2_mul(&Bzz, &Bzz, &curve->C); // C*(P.x*Q.z-P.z*Q.x)^2
|
||||
fp2_mul(&Bxz, &Bxz, &curve->C); // C*(P.x*Q.x+P.z*Q.z)(P.x*Q.z+P.z*Q.x)
|
||||
fp2_mul(&t0, &t0, &t1);
|
||||
fp2_mul(&t0, &t0, &curve->A);
|
||||
fp2_add(&t0, &t0, &t0);
|
||||
fp2_add(&Bxz, &Bxz, &t0); // C*(P.x*Q.x+P.z*Q.z)(P.x*Q.z+P.z*Q.x) + 2*A*P.x*Q.z*P.z*Q.x
|
||||
|
||||
// To ensure that the denominator is a fourth power in Fp, we normalize by
|
||||
// C*C_bar^2*(P.z)_bar^2*(Q.z)_bar^2
|
||||
fp_copy(&t0.re, &curve->C.re);
|
||||
fp_neg(&t0.im, &curve->C.im);
|
||||
fp2_sqr(&t0, &t0);
|
||||
fp2_mul(&t0, &t0, &curve->C);
|
||||
fp_copy(&t1.re, &P->z.re);
|
||||
fp_neg(&t1.im, &P->z.im);
|
||||
fp2_sqr(&t1, &t1);
|
||||
fp2_mul(&t0, &t0, &t1);
|
||||
fp_copy(&t1.re, &Q->z.re);
|
||||
fp_neg(&t1.im, &Q->z.im);
|
||||
fp2_sqr(&t1, &t1);
|
||||
fp2_mul(&t0, &t0, &t1);
|
||||
fp2_mul(&Bxx, &Bxx, &t0);
|
||||
fp2_mul(&Bxz, &Bxz, &t0);
|
||||
fp2_mul(&Bzz, &Bzz, &t0);
|
||||
|
||||
// Solving quadratic equation
|
||||
fp2_sqr(&t0, &Bxz);
|
||||
fp2_mul(&t1, &Bxx, &Bzz);
|
||||
fp2_sub(&t0, &t0, &t1);
|
||||
// No need to check if t0 is square, as per the entangled basis algorithm.
|
||||
fp2_sqrt(&t0);
|
||||
fp2_add(&PQ->x, &Bxz, &t0);
|
||||
fp2_copy(&PQ->z, &Bzz);
|
||||
}
|
||||
|
||||
// Lifts a basis x(P), x(Q), x(P-Q) assuming the curve has (A/C : 1) and the point
|
||||
// P = (X/Z : 1). For generic implementation see lift_basis()
|
||||
uint32_t
|
||||
lift_basis_normalized(jac_point_t *P, jac_point_t *Q, ec_basis_t *B, ec_curve_t *E)
|
||||
{
|
||||
assert(fp2_is_one(&B->P.z));
|
||||
assert(fp2_is_one(&E->C));
|
||||
|
||||
fp2_copy(&P->x, &B->P.x);
|
||||
fp2_copy(&Q->x, &B->Q.x);
|
||||
fp2_copy(&Q->z, &B->Q.z);
|
||||
fp2_set_one(&P->z);
|
||||
uint32_t ret = ec_recover_y(&P->y, &P->x, E);
|
||||
|
||||
// Algorithm of Okeya-Sakurai to recover y.Q in the montgomery model
|
||||
fp2_t v1, v2, v3, v4;
|
||||
fp2_mul(&v1, &P->x, &Q->z);
|
||||
fp2_add(&v2, &Q->x, &v1);
|
||||
fp2_sub(&v3, &Q->x, &v1);
|
||||
fp2_sqr(&v3, &v3);
|
||||
fp2_mul(&v3, &v3, &B->PmQ.x);
|
||||
fp2_add(&v1, &E->A, &E->A);
|
||||
fp2_mul(&v1, &v1, &Q->z);
|
||||
fp2_add(&v2, &v2, &v1);
|
||||
fp2_mul(&v4, &P->x, &Q->x);
|
||||
fp2_add(&v4, &v4, &Q->z);
|
||||
fp2_mul(&v2, &v2, &v4);
|
||||
fp2_mul(&v1, &v1, &Q->z);
|
||||
fp2_sub(&v2, &v2, &v1);
|
||||
fp2_mul(&v2, &v2, &B->PmQ.z);
|
||||
fp2_sub(&Q->y, &v3, &v2);
|
||||
fp2_add(&v1, &P->y, &P->y);
|
||||
fp2_mul(&v1, &v1, &Q->z);
|
||||
fp2_mul(&v1, &v1, &B->PmQ.z);
|
||||
fp2_mul(&Q->x, &Q->x, &v1);
|
||||
fp2_mul(&Q->z, &Q->z, &v1);
|
||||
|
||||
// Transforming to a jacobian coordinate
|
||||
fp2_sqr(&v1, &Q->z);
|
||||
fp2_mul(&Q->y, &Q->y, &v1);
|
||||
fp2_mul(&Q->x, &Q->x, &Q->z);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
lift_basis(jac_point_t *P, jac_point_t *Q, ec_basis_t *B, ec_curve_t *E)
|
||||
{
|
||||
// Normalise the curve E such that (A : C) is (A/C : 1)
|
||||
// and the point x(P) = (X/Z : 1).
|
||||
fp2_t inverses[2];
|
||||
fp2_copy(&inverses[0], &B->P.z);
|
||||
fp2_copy(&inverses[1], &E->C);
|
||||
|
||||
fp2_batched_inv(inverses, 2);
|
||||
fp2_set_one(&B->P.z);
|
||||
fp2_set_one(&E->C);
|
||||
|
||||
fp2_mul(&B->P.x, &B->P.x, &inverses[0]);
|
||||
fp2_mul(&E->A, &E->A, &inverses[1]);
|
||||
|
||||
// Lift the basis to Jacobian points P, Q
|
||||
return lift_basis_normalized(P, Q, B, E);
|
||||
}
|
||||
|
||||
// Given an x-coordinate, determines if this is a valid
|
||||
// point on the curve. Assumes C=1.
|
||||
static uint32_t
|
||||
is_on_curve(const fp2_t *x, const ec_curve_t *curve)
|
||||
{
|
||||
assert(fp2_is_one(&curve->C));
|
||||
fp2_t t0;
|
||||
|
||||
fp2_add(&t0, x, &curve->A); // x + (A/C)
|
||||
fp2_mul(&t0, &t0, x); // x^2 + (A/C)*x
|
||||
fp2_add_one(&t0, &t0); // x^2 + (A/C)*x + 1
|
||||
fp2_mul(&t0, &t0, x); // x^3 + (A/C)*x^2 + x
|
||||
|
||||
return fp2_is_square(&t0);
|
||||
}
|
||||
|
||||
// Helper function which given a point of order k*2^n with n maximal
|
||||
// and k odd, computes a point of order 2^f
|
||||
static inline void
|
||||
clear_cofactor_for_maximal_even_order(ec_point_t *P, ec_curve_t *curve, int f)
|
||||
{
|
||||
// clear out the odd cofactor to get a point of order 2^n
|
||||
ec_mul(P, p_cofactor_for_2f, P_COFACTOR_FOR_2F_BITLENGTH, P, curve);
|
||||
|
||||
// clear the power of two to get a point of order 2^f
|
||||
for (int i = 0; i < TORSION_EVEN_POWER - f; i++) {
|
||||
xDBL_A24(P, P, &curve->A24, curve->is_A24_computed_and_normalized);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function which finds an NQR -1 / (1 + i*b) for entangled basis generation
|
||||
static uint8_t
|
||||
find_nqr_factor(fp2_t *x, ec_curve_t *curve, const uint8_t start)
|
||||
{
|
||||
// factor = -1/(1 + i*b) for b in Fp will be NQR whenever 1 + b^2 is NQR
|
||||
// in Fp, so we find one of these and then invert (1 + i*b). We store b
|
||||
// as a u8 hint to save time in verification.
|
||||
|
||||
// We return the hint as a u8, but use (uint16_t)n to give 2^16 - 1
|
||||
// to make failure cryptographically negligible, with a fallback when
|
||||
// n > 128 is required.
|
||||
uint8_t hint;
|
||||
uint32_t found = 0;
|
||||
uint16_t n = start;
|
||||
|
||||
bool qr_b = 1;
|
||||
fp_t b, tmp;
|
||||
fp2_t z, t0, t1;
|
||||
|
||||
do {
|
||||
while (qr_b) {
|
||||
// find b with 1 + b^2 a non-quadratic residue
|
||||
fp_set_small(&tmp, (uint32_t)n * n + 1);
|
||||
qr_b = fp_is_square(&tmp);
|
||||
n++; // keeps track of b = n - 1
|
||||
}
|
||||
|
||||
// for Px := -A/(1 + i*b) to be on the curve
|
||||
// is equivalent to A^2*(z-1) - z^2 NQR for z = 1 + i*b
|
||||
// thus prevents unnecessary inversion pre-check
|
||||
|
||||
// t0 = z - 1 = i*b
|
||||
// t1 = z = 1 + i*b
|
||||
fp_set_small(&b, (uint32_t)n - 1);
|
||||
fp2_set_zero(&t0);
|
||||
fp2_set_one(&z);
|
||||
fp_copy(&z.im, &b);
|
||||
fp_copy(&t0.im, &b);
|
||||
|
||||
// A^2*(z-1) - z^2
|
||||
fp2_sqr(&t1, &curve->A);
|
||||
fp2_mul(&t0, &t0, &t1); // A^2 * (z - 1)
|
||||
fp2_sqr(&t1, &z);
|
||||
fp2_sub(&t0, &t0, &t1); // A^2 * (z - 1) - z^2
|
||||
found = !fp2_is_square(&t0);
|
||||
|
||||
qr_b = 1;
|
||||
} while (!found);
|
||||
|
||||
// set Px to -A/(1 + i*b)
|
||||
fp2_copy(x, &z);
|
||||
fp2_inv(x);
|
||||
fp2_mul(x, x, &curve->A);
|
||||
fp2_neg(x, x);
|
||||
|
||||
/*
|
||||
* With very low probability n will not fit in 7 bits.
|
||||
* We set hint = 0 which signals failure and the need
|
||||
* to generate a value on the fly during verification
|
||||
*/
|
||||
hint = n <= 128 ? n - 1 : 0;
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
// Helper function which finds a point x(P) = n * A
|
||||
static uint8_t
|
||||
find_nA_x_coord(fp2_t *x, ec_curve_t *curve, const uint8_t start)
|
||||
{
|
||||
assert(!fp2_is_square(&curve->A)); // Only to be called when A is a NQR
|
||||
|
||||
// when A is NQR we allow x(P) to be a multiple n*A of A
|
||||
uint8_t n = start;
|
||||
if (n == 1) {
|
||||
fp2_copy(x, &curve->A);
|
||||
} else {
|
||||
fp2_mul_small(x, &curve->A, n);
|
||||
}
|
||||
|
||||
while (!is_on_curve(x, curve)) {
|
||||
fp2_add(x, x, &curve->A);
|
||||
n++;
|
||||
}
|
||||
|
||||
/*
|
||||
* With very low probability (1/2^128), n will not fit in 7 bits.
|
||||
* In this case, we set hint = 0 which signals failure and the need
|
||||
* to generate a value on the fly during verification
|
||||
*/
|
||||
uint8_t hint = n < 128 ? n : 0;
|
||||
return hint;
|
||||
}
|
||||
|
||||
// The entangled basis generation does not allow A = 0
|
||||
// so we simply return the one we have already precomputed
|
||||
static void
|
||||
ec_basis_E0_2f(ec_basis_t *PQ2, ec_curve_t *curve, int f)
|
||||
{
|
||||
assert(fp2_is_zero(&curve->A));
|
||||
ec_point_t P, Q;
|
||||
|
||||
// Set P, Q to precomputed (X : 1) values
|
||||
fp2_copy(&P.x, &BASIS_E0_PX);
|
||||
fp2_copy(&Q.x, &BASIS_E0_QX);
|
||||
fp2_set_one(&P.z);
|
||||
fp2_set_one(&Q.z);
|
||||
|
||||
// clear the power of two to get a point of order 2^f
|
||||
for (int i = 0; i < TORSION_EVEN_POWER - f; i++) {
|
||||
xDBL_E0(&P, &P);
|
||||
xDBL_E0(&Q, &Q);
|
||||
}
|
||||
|
||||
// Set P, Q in the basis and compute x(P - Q)
|
||||
copy_point(&PQ2->P, &P);
|
||||
copy_point(&PQ2->Q, &Q);
|
||||
difference_point(&PQ2->PmQ, &P, &Q, curve);
|
||||
}
|
||||
|
||||
// Computes a basis E[2^f] = <P, Q> where the point Q is above (0 : 0)
|
||||
// and stores hints as an array for faster recomputation at a later point
|
||||
uint8_t
|
||||
ec_curve_to_basis_2f_to_hint(ec_basis_t *PQ2, ec_curve_t *curve, int f)
|
||||
{
|
||||
// Normalise (A/C : 1) and ((A + 2)/4 : 1)
|
||||
ec_normalize_curve_and_A24(curve);
|
||||
|
||||
if (fp2_is_zero(&curve->A)) {
|
||||
ec_basis_E0_2f(PQ2, curve, f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t hint;
|
||||
bool hint_A = fp2_is_square(&curve->A);
|
||||
|
||||
// Compute the points P, Q
|
||||
ec_point_t P, Q;
|
||||
|
||||
if (!hint_A) {
|
||||
// when A is NQR we allow x(P) to be a multiple n*A of A
|
||||
hint = find_nA_x_coord(&P.x, curve, 1);
|
||||
} else {
|
||||
// when A is QR we instead have to find (1 + b^2) a NQR
|
||||
// such that x(P) = -A / (1 + i*b)
|
||||
hint = find_nqr_factor(&P.x, curve, 1);
|
||||
}
|
||||
|
||||
fp2_set_one(&P.z);
|
||||
fp2_add(&Q.x, &curve->A, &P.x);
|
||||
fp2_neg(&Q.x, &Q.x);
|
||||
fp2_set_one(&Q.z);
|
||||
|
||||
// clear out the odd cofactor to get a point of order 2^f
|
||||
clear_cofactor_for_maximal_even_order(&P, curve, f);
|
||||
clear_cofactor_for_maximal_even_order(&Q, curve, f);
|
||||
|
||||
// compute PmQ, set PmQ to Q to ensure Q above (0,0)
|
||||
difference_point(&PQ2->Q, &P, &Q, curve);
|
||||
copy_point(&PQ2->P, &P);
|
||||
copy_point(&PQ2->PmQ, &Q);
|
||||
|
||||
// Finally, we compress hint_A and hint into a single bytes.
|
||||
// We choose to set the LSB of hint to hint_A
|
||||
assert(hint < 128); // We expect hint to be 7-bits in size
|
||||
return (hint << 1) | hint_A;
|
||||
}
|
||||
|
||||
// Computes a basis E[2^f] = <P, Q> where the point Q is above (0 : 0)
|
||||
// given the hints as an array for faster basis computation
|
||||
int
|
||||
ec_curve_to_basis_2f_from_hint(ec_basis_t *PQ2, ec_curve_t *curve, int f, const uint8_t hint)
|
||||
{
|
||||
// Normalise (A/C : 1) and ((A + 2)/4 : 1)
|
||||
ec_normalize_curve_and_A24(curve);
|
||||
|
||||
if (fp2_is_zero(&curve->A)) {
|
||||
ec_basis_E0_2f(PQ2, curve, f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// The LSB of hint encodes whether A is a QR
|
||||
// The remaining 7-bits are used to find a valid x(P)
|
||||
bool hint_A = hint & 1;
|
||||
uint8_t hint_P = hint >> 1;
|
||||
|
||||
// Compute the points P, Q
|
||||
ec_point_t P, Q;
|
||||
|
||||
if (!hint_P) {
|
||||
// When hint_P = 0 it means we did not find a point in 128 attempts
|
||||
// this is very rare and we almost never expect to need this fallback
|
||||
// In either case, we can start with b = 128 to skip testing the known
|
||||
// values which will not work
|
||||
if (!hint_A) {
|
||||
find_nA_x_coord(&P.x, curve, 128);
|
||||
} else {
|
||||
find_nqr_factor(&P.x, curve, 128);
|
||||
}
|
||||
} else {
|
||||
// Otherwise we use the hint to directly find x(P) based on hint_A
|
||||
if (!hint_A) {
|
||||
// when A is NQR, we have found n such that x(P) = n*A
|
||||
fp2_mul_small(&P.x, &curve->A, hint_P);
|
||||
} else {
|
||||
// when A is QR we have found b such that (1 + b^2) is a NQR in
|
||||
// Fp, so we must compute x(P) = -A / (1 + i*b)
|
||||
fp_set_one(&P.x.re);
|
||||
fp_set_small(&P.x.im, hint_P);
|
||||
fp2_inv(&P.x);
|
||||
fp2_mul(&P.x, &P.x, &curve->A);
|
||||
fp2_neg(&P.x, &P.x);
|
||||
}
|
||||
}
|
||||
fp2_set_one(&P.z);
|
||||
|
||||
#ifndef NDEBUG
|
||||
int passed = 1;
|
||||
passed = is_on_curve(&P.x, curve);
|
||||
passed &= !fp2_is_square(&P.x);
|
||||
|
||||
if (!passed)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
// set xQ to -xP - A
|
||||
fp2_add(&Q.x, &curve->A, &P.x);
|
||||
fp2_neg(&Q.x, &Q.x);
|
||||
fp2_set_one(&Q.z);
|
||||
|
||||
// clear out the odd cofactor to get a point of order 2^f
|
||||
clear_cofactor_for_maximal_even_order(&P, curve, f);
|
||||
clear_cofactor_for_maximal_even_order(&Q, curve, f);
|
||||
|
||||
// compute PmQ, set PmQ to Q to ensure Q above (0,0)
|
||||
difference_point(&PQ2->Q, &P, &Q, curve);
|
||||
copy_point(&PQ2->P, &P);
|
||||
copy_point(&PQ2->PmQ, &Q);
|
||||
|
||||
#ifndef NDEBUG
|
||||
passed &= test_basis_order_twof(PQ2, curve, f);
|
||||
|
||||
if (!passed)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
770
src/ec/ref/lvlx/biextension.c
Normal file
770
src/ec/ref/lvlx/biextension.c
Normal file
@@ -0,0 +1,770 @@
|
||||
#include <biextension.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <mp.h>
|
||||
|
||||
/*
|
||||
* We implement the biextension arithmetic by using the cubical torsor
|
||||
* representation. For now only implement the 2^e-ladder.
|
||||
*
|
||||
* Warning: cubicalADD is off by a factor x4 with respect to the correct
|
||||
* cubical arithmetic. This does not affect the Weil pairing or the Tate
|
||||
* pairing over F_{p^2} (due to the final exponentiation), but would give
|
||||
* the wrong result if we compute the Tate pairing over F_p.
|
||||
*/
|
||||
|
||||
// this would be exactly like xADD if PQ was 'antinormalised' as (1,z)
|
||||
// Cost: 3M + 2S + 3a + 3s
|
||||
// Note: if needed, cubicalDBL is simply xDBL_A24 normalized and
|
||||
// costs 3M + 2S + 2a + 2s
|
||||
|
||||
static void
|
||||
cubicalADD(ec_point_t *R, const ec_point_t *P, const ec_point_t *Q, const fp2_t *ixPQ)
|
||||
{
|
||||
fp2_t t0, t1, t2, t3;
|
||||
|
||||
fp2_add(&t0, &P->x, &P->z);
|
||||
fp2_sub(&t1, &P->x, &P->z);
|
||||
fp2_add(&t2, &Q->x, &Q->z);
|
||||
fp2_sub(&t3, &Q->x, &Q->z);
|
||||
fp2_mul(&t0, &t0, &t3);
|
||||
fp2_mul(&t1, &t1, &t2);
|
||||
fp2_add(&t2, &t0, &t1);
|
||||
fp2_sub(&t3, &t0, &t1);
|
||||
fp2_sqr(&R->z, &t3);
|
||||
fp2_sqr(&t2, &t2);
|
||||
fp2_mul(&R->x, ixPQ, &t2);
|
||||
}
|
||||
|
||||
// Given cubical reps of P, Q and x(P - Q) = (1 : ixPQ)
|
||||
// compute P + Q, [2]Q
|
||||
// Cost: 6M + 4S + 4a + 4s
|
||||
static void
|
||||
cubicalDBLADD(ec_point_t *PpQ,
|
||||
ec_point_t *QQ,
|
||||
const ec_point_t *P,
|
||||
const ec_point_t *Q,
|
||||
const fp2_t *ixPQ,
|
||||
const ec_point_t *A24)
|
||||
{
|
||||
// A24 = (A+2C/4C: 1)
|
||||
assert(fp2_is_one(&A24->z));
|
||||
|
||||
fp2_t t0, t1, t2, t3;
|
||||
|
||||
fp2_add(&t0, &P->x, &P->z);
|
||||
fp2_sub(&t1, &P->x, &P->z);
|
||||
fp2_add(&PpQ->x, &Q->x, &Q->z);
|
||||
fp2_sub(&t3, &Q->x, &Q->z);
|
||||
fp2_sqr(&t2, &PpQ->x);
|
||||
fp2_sqr(&QQ->z, &t3);
|
||||
fp2_mul(&t0, &t0, &t3);
|
||||
fp2_mul(&t1, &t1, &PpQ->x);
|
||||
fp2_add(&PpQ->x, &t0, &t1);
|
||||
fp2_sub(&t3, &t0, &t1);
|
||||
fp2_sqr(&PpQ->z, &t3);
|
||||
fp2_sqr(&PpQ->x, &PpQ->x);
|
||||
fp2_mul(&PpQ->x, ixPQ, &PpQ->x);
|
||||
fp2_sub(&t3, &t2, &QQ->z);
|
||||
fp2_mul(&QQ->x, &t2, &QQ->z);
|
||||
fp2_mul(&t0, &t3, &A24->x);
|
||||
fp2_add(&t0, &t0, &QQ->z);
|
||||
fp2_mul(&QQ->z, &t0, &t3);
|
||||
}
|
||||
|
||||
// iterative biextension doubling
|
||||
static void
|
||||
biext_ladder_2e(uint32_t e,
|
||||
ec_point_t *PnQ,
|
||||
ec_point_t *nQ,
|
||||
const ec_point_t *PQ,
|
||||
const ec_point_t *Q,
|
||||
const fp2_t *ixP,
|
||||
const ec_point_t *A24)
|
||||
{
|
||||
copy_point(PnQ, PQ);
|
||||
copy_point(nQ, Q);
|
||||
for (uint32_t i = 0; i < e; i++) {
|
||||
cubicalDBLADD(PnQ, nQ, PnQ, nQ, ixP, A24);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the monodromy ratio X/Z above as a (X:Z) point to avoid a division
|
||||
// We implicitly use (1,0) as a cubical point above 0_E
|
||||
static void
|
||||
point_ratio(ec_point_t *R, const ec_point_t *PnQ, const ec_point_t *nQ, const ec_point_t *P)
|
||||
{
|
||||
// Sanity tests
|
||||
assert(ec_is_zero(nQ));
|
||||
assert(ec_is_equal(PnQ, P));
|
||||
|
||||
fp2_mul(&R->x, &nQ->x, &P->x);
|
||||
fp2_copy(&R->z, &PnQ->x);
|
||||
}
|
||||
|
||||
// Compute the cubical translation of P by a point of 2-torsion T
|
||||
static void
|
||||
translate(ec_point_t *P, const ec_point_t *T)
|
||||
{
|
||||
// When we translate, the following three things can happen:
|
||||
// T = (A : 0) then the translation of P should be P
|
||||
// T = (0 : B) then the translation of P = (X : Z) should be (Z : X)
|
||||
// Otherwise T = (A : B) and P translates to (AX - BZ : BX - AZ)
|
||||
// We compute this in constant time by computing the generic case
|
||||
// and then using constant time swaps.
|
||||
fp2_t PX_new, PZ_new;
|
||||
|
||||
{
|
||||
fp2_t t0, t1;
|
||||
|
||||
// PX_new = AX - BZ
|
||||
fp2_mul(&t0, &T->x, &P->x);
|
||||
fp2_mul(&t1, &T->z, &P->z);
|
||||
fp2_sub(&PX_new, &t0, &t1);
|
||||
|
||||
// PZ_new = BX - AZ
|
||||
fp2_mul(&t0, &T->z, &P->x);
|
||||
fp2_mul(&t1, &T->x, &P->z);
|
||||
fp2_sub(&PZ_new, &t0, &t1);
|
||||
}
|
||||
|
||||
// When we have A zero we should return (Z : X)
|
||||
uint32_t TA_is_zero = fp2_is_zero(&T->x);
|
||||
fp2_select(&PX_new, &PX_new, &P->z, TA_is_zero);
|
||||
fp2_select(&PZ_new, &PZ_new, &P->x, TA_is_zero);
|
||||
|
||||
// When we have B zero we should return (X : Z)
|
||||
uint32_t TB_is_zero = fp2_is_zero(&T->z);
|
||||
fp2_select(&PX_new, &PX_new, &P->x, TB_is_zero);
|
||||
fp2_select(&PZ_new, &PZ_new, &P->z, TB_is_zero);
|
||||
|
||||
// Set the point to the desired result
|
||||
fp2_copy(&P->x, &PX_new);
|
||||
fp2_copy(&P->z, &PZ_new);
|
||||
}
|
||||
|
||||
// Compute the biextension monodromy g_P,Q^{2^g} (in level 1) via the
|
||||
// cubical arithmetic of P+2^e Q.
|
||||
// The suffix _i means that we are given 1/x(P) as parameter. Warning: to
|
||||
// get meaningful result when using the monodromy to compute pairings, we
|
||||
// need P, Q, PQ, A24 to be normalised (this is not strictly necessary, but
|
||||
// care need to be taken when they are not normalised. Only handle the
|
||||
// normalised case for now)
|
||||
static void
|
||||
monodromy_i(ec_point_t *R, const pairing_params_t *pairing_data, bool swap_PQ)
|
||||
{
|
||||
fp2_t ixP;
|
||||
ec_point_t P, Q, PnQ, nQ;
|
||||
|
||||
// When we compute the Weil pairing we need both P + [2^e]Q and
|
||||
// Q + [2^e]P which we can do easily with biext_ladder_2e() below
|
||||
// we use a bool to decide wether to use Q, ixP or P, ixQ in the
|
||||
// ladder and P or Q in translation.
|
||||
if (!swap_PQ) {
|
||||
copy_point(&P, &pairing_data->P);
|
||||
copy_point(&Q, &pairing_data->Q);
|
||||
fp2_copy(&ixP, &pairing_data->ixP);
|
||||
} else {
|
||||
copy_point(&P, &pairing_data->Q);
|
||||
copy_point(&Q, &pairing_data->P);
|
||||
fp2_copy(&ixP, &pairing_data->ixQ);
|
||||
}
|
||||
|
||||
// Compute the biextension ladder P + [2^e]Q
|
||||
biext_ladder_2e(pairing_data->e - 1, &PnQ, &nQ, &pairing_data->PQ, &Q, &ixP, &pairing_data->A24);
|
||||
translate(&PnQ, &nQ);
|
||||
translate(&nQ, &nQ);
|
||||
point_ratio(R, &PnQ, &nQ, &P);
|
||||
}
|
||||
|
||||
// Normalize the points and also store 1/x(P), 1/x(Q)
|
||||
static void
|
||||
cubical_normalization(pairing_params_t *pairing_data, const ec_point_t *P, const ec_point_t *Q)
|
||||
{
|
||||
fp2_t t[4];
|
||||
fp2_copy(&t[0], &P->x);
|
||||
fp2_copy(&t[1], &P->z);
|
||||
fp2_copy(&t[2], &Q->x);
|
||||
fp2_copy(&t[3], &Q->z);
|
||||
fp2_batched_inv(t, 4);
|
||||
|
||||
// Store PZ / PX and QZ / QX
|
||||
fp2_mul(&pairing_data->ixP, &P->z, &t[0]);
|
||||
fp2_mul(&pairing_data->ixQ, &Q->z, &t[2]);
|
||||
|
||||
// Store x(P), x(Q) normalised to (X/Z : 1)
|
||||
fp2_mul(&pairing_data->P.x, &P->x, &t[1]);
|
||||
fp2_mul(&pairing_data->Q.x, &Q->x, &t[3]);
|
||||
fp2_set_one(&pairing_data->P.z);
|
||||
fp2_set_one(&pairing_data->Q.z);
|
||||
}
|
||||
|
||||
// Weil pairing, PQ should be P+Q in (X:Z) coordinates
|
||||
// We assume the points are normalised correctly
|
||||
static void
|
||||
weil_n(fp2_t *r, const pairing_params_t *pairing_data)
|
||||
{
|
||||
ec_point_t R0, R1;
|
||||
monodromy_i(&R0, pairing_data, true);
|
||||
monodromy_i(&R1, pairing_data, false);
|
||||
|
||||
fp2_mul(r, &R0.x, &R1.z);
|
||||
fp2_inv(r);
|
||||
fp2_mul(r, r, &R0.z);
|
||||
fp2_mul(r, r, &R1.x);
|
||||
}
|
||||
|
||||
// Weil pairing, PQ should be P+Q in (X:Z) coordinates
|
||||
// Normalise the points and call the code above
|
||||
// The code will crash (division by 0) if either P or Q is (0:1)
|
||||
void
|
||||
weil(fp2_t *r, uint32_t e, const ec_point_t *P, const ec_point_t *Q, const ec_point_t *PQ, ec_curve_t *E)
|
||||
{
|
||||
pairing_params_t pairing_data;
|
||||
// Construct the structure for the Weil pairing
|
||||
// Set (PX/PZ : 1), (QX : QZ : 1), PZ/PX and QZ/QX
|
||||
pairing_data.e = e;
|
||||
cubical_normalization(&pairing_data, P, Q);
|
||||
copy_point(&pairing_data.PQ, PQ);
|
||||
|
||||
// Ensure the input curve has A24 normalised and store
|
||||
// in a struct
|
||||
ec_curve_normalize_A24(E);
|
||||
copy_point(&pairing_data.A24, &E->A24);
|
||||
|
||||
// Compute the Weil pairing e_(2^n)(P, Q)
|
||||
weil_n(r, &pairing_data);
|
||||
}
|
||||
|
||||
// two helper functions for reducing the tate pairing
|
||||
// clear_cofac clears (p + 1) // 2^f for an Fp2 value
|
||||
void
|
||||
clear_cofac(fp2_t *r, const fp2_t *a)
|
||||
{
|
||||
digit_t exp = *p_cofactor_for_2f;
|
||||
exp >>= 1;
|
||||
|
||||
fp2_t x;
|
||||
fp2_copy(&x, a);
|
||||
fp2_copy(r, a);
|
||||
|
||||
// removes cofac
|
||||
while (exp > 0) {
|
||||
fp2_sqr(r, r);
|
||||
if (exp & 1) {
|
||||
fp2_mul(r, r, &x);
|
||||
}
|
||||
exp >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// applies frobenius a + ib --> a - ib to an fp2 element
|
||||
void
|
||||
fp2_frob(fp2_t *out, const fp2_t *in)
|
||||
{
|
||||
fp_copy(&(out->re), &(in->re));
|
||||
fp_neg(&(out->im), &(in->im));
|
||||
}
|
||||
|
||||
// reduced Tate pairing, normalizes the points, assumes PQ is P+Q in (X:Z)
|
||||
// coordinates. Computes 1/x(P) and 1/x(Q) for efficient cubical ladder
|
||||
void
|
||||
reduced_tate(fp2_t *r, uint32_t e, const ec_point_t *P, const ec_point_t *Q, const ec_point_t *PQ, ec_curve_t *E)
|
||||
{
|
||||
uint32_t e_full = TORSION_EVEN_POWER;
|
||||
uint32_t e_diff = e_full - e;
|
||||
ec_point_t R;
|
||||
pairing_params_t pairing_data;
|
||||
|
||||
// Construct the structure for the Weil pairing
|
||||
// Set (PX/PZ : 1), (QX : QZ : 1), PZ/PX and QZ/QX
|
||||
pairing_data.e = e;
|
||||
cubical_normalization(&pairing_data, P, Q);
|
||||
copy_point(&pairing_data.PQ, PQ);
|
||||
|
||||
// Ensure the input curve has A24 normalised and store
|
||||
// in a struct
|
||||
ec_curve_normalize_A24(E);
|
||||
copy_point(&pairing_data.A24, &E->A24);
|
||||
|
||||
monodromy_i(&R, &pairing_data, true);
|
||||
|
||||
// we get unreduced tate as R.X, R.Z
|
||||
// reduced tate is -(R.Z/R.X)^((p^2 - 1) div 2^f)
|
||||
// we reuse R.X and R.Z to split reduction step ^(p-1) into frobenius and ^-1
|
||||
fp2_t frob, tmp;
|
||||
fp2_copy(&tmp, &R.x);
|
||||
fp2_frob(&frob, &R.x);
|
||||
fp2_mul(&R.x, &R.z, &frob);
|
||||
fp2_frob(&frob, &R.z);
|
||||
fp2_mul(&R.z, &tmp, &frob);
|
||||
fp2_inv(&R.x);
|
||||
fp2_mul(r, &R.x, &R.z);
|
||||
|
||||
clear_cofac(r, r);
|
||||
// clear remaining 2^e_diff
|
||||
for (uint32_t j = 0; j < e_diff; j++) {
|
||||
fp2_sqr(r, r);
|
||||
}
|
||||
}
|
||||
|
||||
// Functions to compute discrete logs by computing the Weil pairing of points
|
||||
// followed by computing the dlog in Fp^2
|
||||
// (If we work with full order points, it would be faster to use the Tate
|
||||
// pairings rather than the Weil pairings; this is not implemented yet)
|
||||
|
||||
// recursive dlog function
|
||||
static bool
|
||||
fp2_dlog_2e_rec(digit_t *a, long len, fp2_t *pows_f, fp2_t *pows_g, long stacklen)
|
||||
{
|
||||
if (len == 0) {
|
||||
// *a = 0;
|
||||
for (int i = 0; i < NWORDS_ORDER; i++) {
|
||||
a[i] = 0;
|
||||
}
|
||||
return true;
|
||||
} else if (len == 1) {
|
||||
if (fp2_is_one(&pows_f[stacklen - 1])) {
|
||||
// a = 0;
|
||||
for (int i = 0; i < NWORDS_ORDER; i++) {
|
||||
a[i] = 0;
|
||||
}
|
||||
for (int i = 0; i < stacklen - 1; ++i) {
|
||||
fp2_sqr(&pows_g[i], &pows_g[i]); // new_g = g^2
|
||||
}
|
||||
return true;
|
||||
} else if (fp2_is_equal(&pows_f[stacklen - 1], &pows_g[stacklen - 1])) {
|
||||
// a = 1;
|
||||
a[0] = 1;
|
||||
for (int i = 1; i < NWORDS_ORDER; i++) {
|
||||
a[i] = 0;
|
||||
}
|
||||
for (int i = 0; i < stacklen - 1; ++i) {
|
||||
fp2_mul(&pows_f[i], &pows_f[i], &pows_g[i]); // new_f = f*g
|
||||
fp2_sqr(&pows_g[i], &pows_g[i]); // new_g = g^2
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
long right = (double)len * 0.5;
|
||||
long left = len - right;
|
||||
pows_f[stacklen] = pows_f[stacklen - 1];
|
||||
pows_g[stacklen] = pows_g[stacklen - 1];
|
||||
for (int i = 0; i < left; i++) {
|
||||
fp2_sqr(&pows_f[stacklen], &pows_f[stacklen]);
|
||||
fp2_sqr(&pows_g[stacklen], &pows_g[stacklen]);
|
||||
}
|
||||
// uint32_t dlp1 = 0, dlp2 = 0;
|
||||
digit_t dlp1[NWORDS_ORDER], dlp2[NWORDS_ORDER];
|
||||
bool ok;
|
||||
ok = fp2_dlog_2e_rec(dlp1, right, pows_f, pows_g, stacklen + 1);
|
||||
if (!ok)
|
||||
return false;
|
||||
ok = fp2_dlog_2e_rec(dlp2, left, pows_f, pows_g, stacklen);
|
||||
if (!ok)
|
||||
return false;
|
||||
// a = dlp1 + 2^right * dlp2
|
||||
multiple_mp_shiftl(dlp2, right, NWORDS_ORDER);
|
||||
mp_add(a, dlp2, dlp1, NWORDS_ORDER);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// compute DLP: compute scal such that f = g^scal with f, 1/g as input
|
||||
static bool
|
||||
fp2_dlog_2e(digit_t *scal, const fp2_t *f, const fp2_t *g_inverse, int e)
|
||||
{
|
||||
long log, len = e;
|
||||
for (log = 0; len > 1; len >>= 1)
|
||||
log++;
|
||||
log += 1;
|
||||
|
||||
fp2_t pows_f[log], pows_g[log];
|
||||
pows_f[0] = *f;
|
||||
pows_g[0] = *g_inverse;
|
||||
|
||||
for (int i = 0; i < NWORDS_ORDER; i++) {
|
||||
scal[i] = 0;
|
||||
}
|
||||
|
||||
bool ok = fp2_dlog_2e_rec(scal, e, pows_f, pows_g, 1);
|
||||
assert(ok);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Normalize the bases (P, Q), (R, S) and store their inverse
|
||||
// and additionally normalise the curve to (A/C : 1)
|
||||
static void
|
||||
cubical_normalization_dlog(pairing_dlog_params_t *pairing_dlog_data, ec_curve_t *curve)
|
||||
{
|
||||
fp2_t t[11];
|
||||
ec_basis_t *PQ = &pairing_dlog_data->PQ;
|
||||
ec_basis_t *RS = &pairing_dlog_data->RS;
|
||||
fp2_copy(&t[0], &PQ->P.x);
|
||||
fp2_copy(&t[1], &PQ->P.z);
|
||||
fp2_copy(&t[2], &PQ->Q.x);
|
||||
fp2_copy(&t[3], &PQ->Q.z);
|
||||
fp2_copy(&t[4], &PQ->PmQ.x);
|
||||
fp2_copy(&t[5], &PQ->PmQ.z);
|
||||
fp2_copy(&t[6], &RS->P.x);
|
||||
fp2_copy(&t[7], &RS->P.z);
|
||||
fp2_copy(&t[8], &RS->Q.x);
|
||||
fp2_copy(&t[9], &RS->Q.z);
|
||||
fp2_copy(&t[10], &curve->C);
|
||||
|
||||
fp2_batched_inv(t, 11);
|
||||
|
||||
fp2_mul(&pairing_dlog_data->ixP, &PQ->P.z, &t[0]);
|
||||
fp2_mul(&PQ->P.x, &PQ->P.x, &t[1]);
|
||||
fp2_set_one(&PQ->P.z);
|
||||
|
||||
fp2_mul(&pairing_dlog_data->ixQ, &PQ->Q.z, &t[2]);
|
||||
fp2_mul(&PQ->Q.x, &PQ->Q.x, &t[3]);
|
||||
fp2_set_one(&PQ->Q.z);
|
||||
|
||||
fp2_mul(&PQ->PmQ.x, &PQ->PmQ.x, &t[5]);
|
||||
fp2_set_one(&PQ->PmQ.z);
|
||||
|
||||
fp2_mul(&pairing_dlog_data->ixR, &RS->P.z, &t[6]);
|
||||
fp2_mul(&RS->P.x, &RS->P.x, &t[7]);
|
||||
fp2_set_one(&RS->P.z);
|
||||
|
||||
fp2_mul(&pairing_dlog_data->ixS, &RS->Q.z, &t[8]);
|
||||
fp2_mul(&RS->Q.x, &RS->Q.x, &t[9]);
|
||||
fp2_set_one(&RS->Q.z);
|
||||
|
||||
fp2_mul(&curve->A, &curve->A, &t[10]);
|
||||
fp2_set_one(&curve->C);
|
||||
}
|
||||
|
||||
// Given two bases <P, Q> and basis = <R, S> compute
|
||||
// x(P - R), x(P - S), x(R - Q), x(S - Q)
|
||||
static void
|
||||
compute_difference_points(pairing_dlog_params_t *pairing_dlog_data, ec_curve_t *curve)
|
||||
{
|
||||
jac_point_t xyP, xyQ, xyR, xyS, temp;
|
||||
|
||||
// lifting the two basis points, assumes that x(P) and x(R)
|
||||
// and the curve itself are normalised to (X : 1)
|
||||
lift_basis_normalized(&xyP, &xyQ, &pairing_dlog_data->PQ, curve);
|
||||
lift_basis_normalized(&xyR, &xyS, &pairing_dlog_data->RS, curve);
|
||||
|
||||
// computation of the differences
|
||||
// x(P - R)
|
||||
jac_neg(&temp, &xyR);
|
||||
ADD(&temp, &temp, &xyP, curve);
|
||||
jac_to_xz(&pairing_dlog_data->diff.PmR, &temp);
|
||||
|
||||
// x(P - S)
|
||||
jac_neg(&temp, &xyS);
|
||||
ADD(&temp, &temp, &xyP, curve);
|
||||
jac_to_xz(&pairing_dlog_data->diff.PmS, &temp);
|
||||
|
||||
// x(R - Q)
|
||||
jac_neg(&temp, &xyQ);
|
||||
ADD(&temp, &temp, &xyR, curve);
|
||||
jac_to_xz(&pairing_dlog_data->diff.RmQ, &temp);
|
||||
|
||||
// x(S - Q)
|
||||
jac_neg(&temp, &xyQ);
|
||||
ADD(&temp, &temp, &xyS, curve);
|
||||
jac_to_xz(&pairing_dlog_data->diff.SmQ, &temp);
|
||||
}
|
||||
|
||||
// Inline all the Weil pairing computations needed for ec_dlog_2_weil
|
||||
static void
|
||||
weil_dlog(digit_t *r1, digit_t *r2, digit_t *s1, digit_t *s2, pairing_dlog_params_t *pairing_dlog_data)
|
||||
{
|
||||
|
||||
ec_point_t nP, nQ, nR, nS, nPQ, PnQ, nPR, PnR, nPS, PnS, nRQ, RnQ, nSQ, SnQ;
|
||||
|
||||
copy_point(&nP, &pairing_dlog_data->PQ.P);
|
||||
copy_point(&nQ, &pairing_dlog_data->PQ.Q);
|
||||
copy_point(&nR, &pairing_dlog_data->RS.P);
|
||||
copy_point(&nS, &pairing_dlog_data->RS.Q);
|
||||
copy_point(&nPQ, &pairing_dlog_data->PQ.PmQ);
|
||||
copy_point(&PnQ, &pairing_dlog_data->PQ.PmQ);
|
||||
copy_point(&nPR, &pairing_dlog_data->diff.PmR);
|
||||
copy_point(&nPS, &pairing_dlog_data->diff.PmS);
|
||||
copy_point(&PnR, &pairing_dlog_data->diff.PmR);
|
||||
copy_point(&PnS, &pairing_dlog_data->diff.PmS);
|
||||
copy_point(&nRQ, &pairing_dlog_data->diff.RmQ);
|
||||
copy_point(&nSQ, &pairing_dlog_data->diff.SmQ);
|
||||
copy_point(&RnQ, &pairing_dlog_data->diff.RmQ);
|
||||
copy_point(&SnQ, &pairing_dlog_data->diff.SmQ);
|
||||
|
||||
for (uint32_t i = 0; i < pairing_dlog_data->e - 1; i++) {
|
||||
cubicalADD(&nPQ, &nPQ, &nP, &pairing_dlog_data->ixQ);
|
||||
cubicalADD(&nPR, &nPR, &nP, &pairing_dlog_data->ixR);
|
||||
cubicalDBLADD(&nPS, &nP, &nPS, &nP, &pairing_dlog_data->ixS, &pairing_dlog_data->A24);
|
||||
|
||||
cubicalADD(&PnQ, &PnQ, &nQ, &pairing_dlog_data->ixP);
|
||||
cubicalADD(&RnQ, &RnQ, &nQ, &pairing_dlog_data->ixR);
|
||||
cubicalDBLADD(&SnQ, &nQ, &SnQ, &nQ, &pairing_dlog_data->ixS, &pairing_dlog_data->A24);
|
||||
|
||||
cubicalADD(&PnR, &PnR, &nR, &pairing_dlog_data->ixP);
|
||||
cubicalDBLADD(&nRQ, &nR, &nRQ, &nR, &pairing_dlog_data->ixQ, &pairing_dlog_data->A24);
|
||||
|
||||
cubicalADD(&PnS, &PnS, &nS, &pairing_dlog_data->ixP);
|
||||
cubicalDBLADD(&nSQ, &nS, &nSQ, &nS, &pairing_dlog_data->ixQ, &pairing_dlog_data->A24);
|
||||
}
|
||||
|
||||
// weil(&w0,e,&PQ->P,&PQ->Q,&PQ->PmQ,&A24);
|
||||
translate(&nPQ, &nP);
|
||||
translate(&nPR, &nP);
|
||||
translate(&nPS, &nP);
|
||||
translate(&PnQ, &nQ);
|
||||
translate(&RnQ, &nQ);
|
||||
translate(&SnQ, &nQ);
|
||||
translate(&PnR, &nR);
|
||||
translate(&nRQ, &nR);
|
||||
translate(&PnS, &nS);
|
||||
translate(&nSQ, &nS);
|
||||
|
||||
translate(&nP, &nP);
|
||||
translate(&nQ, &nQ);
|
||||
translate(&nR, &nR);
|
||||
translate(&nS, &nS);
|
||||
|
||||
// computation of the reference weil pairing
|
||||
ec_point_t T0, T1;
|
||||
fp2_t w1[5], w2[5];
|
||||
|
||||
// e(P, Q) = w0
|
||||
point_ratio(&T0, &nPQ, &nP, &pairing_dlog_data->PQ.Q);
|
||||
point_ratio(&T1, &PnQ, &nQ, &pairing_dlog_data->PQ.P);
|
||||
// For the first element we need it's inverse for
|
||||
// fp2_dlog_2e so we swap w1 and w2 here to save inversions
|
||||
fp2_mul(&w2[0], &T0.x, &T1.z);
|
||||
fp2_mul(&w1[0], &T1.x, &T0.z);
|
||||
|
||||
// e(P,R) = w0^r2
|
||||
point_ratio(&T0, &nPR, &nP, &pairing_dlog_data->RS.P);
|
||||
point_ratio(&T1, &PnR, &nR, &pairing_dlog_data->PQ.P);
|
||||
fp2_mul(&w1[1], &T0.x, &T1.z);
|
||||
fp2_mul(&w2[1], &T1.x, &T0.z);
|
||||
|
||||
// e(R,Q) = w0^r1
|
||||
point_ratio(&T0, &nRQ, &nR, &pairing_dlog_data->PQ.Q);
|
||||
point_ratio(&T1, &RnQ, &nQ, &pairing_dlog_data->RS.P);
|
||||
fp2_mul(&w1[2], &T0.x, &T1.z);
|
||||
fp2_mul(&w2[2], &T1.x, &T0.z);
|
||||
|
||||
// e(P,S) = w0^s2
|
||||
point_ratio(&T0, &nPS, &nP, &pairing_dlog_data->RS.Q);
|
||||
point_ratio(&T1, &PnS, &nS, &pairing_dlog_data->PQ.P);
|
||||
fp2_mul(&w1[3], &T0.x, &T1.z);
|
||||
fp2_mul(&w2[3], &T1.x, &T0.z);
|
||||
|
||||
// e(S,Q) = w0^s1
|
||||
point_ratio(&T0, &nSQ, &nS, &pairing_dlog_data->PQ.Q);
|
||||
point_ratio(&T1, &SnQ, &nQ, &pairing_dlog_data->RS.Q);
|
||||
fp2_mul(&w1[4], &T0.x, &T1.z);
|
||||
fp2_mul(&w2[4], &T1.x, &T0.z);
|
||||
|
||||
fp2_batched_inv(w1, 5);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fp2_mul(&w1[i], &w1[i], &w2[i]);
|
||||
}
|
||||
|
||||
fp2_dlog_2e(r2, &w1[1], &w1[0], pairing_dlog_data->e);
|
||||
fp2_dlog_2e(r1, &w1[2], &w1[0], pairing_dlog_data->e);
|
||||
fp2_dlog_2e(s2, &w1[3], &w1[0], pairing_dlog_data->e);
|
||||
fp2_dlog_2e(s1, &w1[4], &w1[0], pairing_dlog_data->e);
|
||||
}
|
||||
|
||||
void
|
||||
ec_dlog_2_weil(digit_t *r1,
|
||||
digit_t *r2,
|
||||
digit_t *s1,
|
||||
digit_t *s2,
|
||||
ec_basis_t *PQ,
|
||||
const ec_basis_t *RS,
|
||||
ec_curve_t *curve,
|
||||
int e)
|
||||
{
|
||||
assert(test_point_order_twof(&PQ->Q, curve, e));
|
||||
|
||||
// precomputing the correct curve data
|
||||
ec_curve_normalize_A24(curve);
|
||||
|
||||
pairing_dlog_params_t pairing_dlog_data;
|
||||
pairing_dlog_data.e = e;
|
||||
pairing_dlog_data.PQ = *PQ;
|
||||
pairing_dlog_data.RS = *RS;
|
||||
pairing_dlog_data.A24 = curve->A24;
|
||||
|
||||
cubical_normalization_dlog(&pairing_dlog_data, curve);
|
||||
compute_difference_points(&pairing_dlog_data, curve);
|
||||
|
||||
weil_dlog(r1, r2, s1, s2, &pairing_dlog_data);
|
||||
|
||||
#ifndef NDEBUG
|
||||
ec_point_t test;
|
||||
ec_biscalar_mul(&test, r1, r2, e, PQ, curve);
|
||||
// R = [r1]P + [r2]Q
|
||||
assert(ec_is_equal(&test, &RS->P));
|
||||
ec_biscalar_mul(&test, s1, s2, e, PQ, curve);
|
||||
// S = [s1]P + [s2]Q
|
||||
assert(ec_is_equal(&test, &RS->Q));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Inline all the Tate pairing computations needed for ec_dlog_2_weil
|
||||
// including reduction, assumes a bases PQ of full E[2^e_full] torsion
|
||||
// and a bases RS of smaller E[2^e] torsion
|
||||
static void
|
||||
tate_dlog_partial(digit_t *r1, digit_t *r2, digit_t *s1, digit_t *s2, pairing_dlog_params_t *pairing_dlog_data)
|
||||
{
|
||||
|
||||
uint32_t e_full = TORSION_EVEN_POWER;
|
||||
uint32_t e_diff = e_full - pairing_dlog_data->e;
|
||||
|
||||
ec_point_t nP, nQ, nR, nS, nPQ, PnR, PnS, nRQ, nSQ;
|
||||
|
||||
copy_point(&nP, &pairing_dlog_data->PQ.P);
|
||||
copy_point(&nQ, &pairing_dlog_data->PQ.Q);
|
||||
copy_point(&nR, &pairing_dlog_data->RS.P);
|
||||
copy_point(&nS, &pairing_dlog_data->RS.Q);
|
||||
copy_point(&nPQ, &pairing_dlog_data->PQ.PmQ);
|
||||
copy_point(&PnR, &pairing_dlog_data->diff.PmR);
|
||||
copy_point(&PnS, &pairing_dlog_data->diff.PmS);
|
||||
copy_point(&nRQ, &pairing_dlog_data->diff.RmQ);
|
||||
copy_point(&nSQ, &pairing_dlog_data->diff.SmQ);
|
||||
|
||||
for (uint32_t i = 0; i < e_full - 1; i++) {
|
||||
cubicalDBLADD(&nPQ, &nP, &nPQ, &nP, &pairing_dlog_data->ixQ, &pairing_dlog_data->A24);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < pairing_dlog_data->e - 1; i++) {
|
||||
cubicalADD(&PnR, &PnR, &nR, &pairing_dlog_data->ixP);
|
||||
cubicalDBLADD(&nRQ, &nR, &nRQ, &nR, &pairing_dlog_data->ixQ, &pairing_dlog_data->A24);
|
||||
|
||||
cubicalADD(&PnS, &PnS, &nS, &pairing_dlog_data->ixP);
|
||||
cubicalDBLADD(&nSQ, &nS, &nSQ, &nS, &pairing_dlog_data->ixQ, &pairing_dlog_data->A24);
|
||||
}
|
||||
|
||||
translate(&nPQ, &nP);
|
||||
translate(&PnR, &nR);
|
||||
translate(&nRQ, &nR);
|
||||
translate(&PnS, &nS);
|
||||
translate(&nSQ, &nS);
|
||||
|
||||
translate(&nP, &nP);
|
||||
translate(&nQ, &nQ);
|
||||
translate(&nR, &nR);
|
||||
translate(&nS, &nS);
|
||||
|
||||
// computation of the reference Tate pairing
|
||||
ec_point_t T0;
|
||||
fp2_t w1[5], w2[5];
|
||||
|
||||
// t(P, Q)^(2^e_diff) = w0
|
||||
point_ratio(&T0, &nPQ, &nP, &pairing_dlog_data->PQ.Q);
|
||||
fp2_copy(&w1[0], &T0.x);
|
||||
fp2_copy(&w2[0], &T0.z);
|
||||
|
||||
// t(R,P) = w0^r2
|
||||
point_ratio(&T0, &PnR, &nR, &pairing_dlog_data->PQ.P);
|
||||
fp2_copy(&w1[1], &T0.x);
|
||||
fp2_copy(&w2[1], &T0.z);
|
||||
|
||||
// t(R,Q) = w0^r1
|
||||
point_ratio(&T0, &nRQ, &nR, &pairing_dlog_data->PQ.Q);
|
||||
fp2_copy(&w2[2], &T0.x);
|
||||
fp2_copy(&w1[2], &T0.z);
|
||||
|
||||
// t(S,P) = w0^s2
|
||||
point_ratio(&T0, &PnS, &nS, &pairing_dlog_data->PQ.P);
|
||||
fp2_copy(&w1[3], &T0.x);
|
||||
fp2_copy(&w2[3], &T0.z);
|
||||
|
||||
// t(S,Q) = w0^s1
|
||||
point_ratio(&T0, &nSQ, &nS, &pairing_dlog_data->PQ.Q);
|
||||
fp2_copy(&w2[4], &T0.x);
|
||||
fp2_copy(&w1[4], &T0.z);
|
||||
|
||||
// batched reduction using projective representation
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fp2_t frob, tmp;
|
||||
fp2_copy(&tmp, &w1[i]);
|
||||
// inline frobenius for ^p
|
||||
// multiply by inverse to get ^(p-1)
|
||||
fp2_frob(&frob, &w1[i]);
|
||||
fp2_mul(&w1[i], &w2[i], &frob);
|
||||
|
||||
// repeat for denom
|
||||
fp2_frob(&frob, &w2[i]);
|
||||
fp2_mul(&w2[i], &tmp, &frob);
|
||||
}
|
||||
|
||||
// batched normalization
|
||||
fp2_batched_inv(w2, 5);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fp2_mul(&w1[i], &w1[i], &w2[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
clear_cofac(&w1[i], &w1[i]);
|
||||
|
||||
// removes 2^e_diff
|
||||
for (uint32_t j = 0; j < e_diff; j++) {
|
||||
fp2_sqr(&w1[i], &w1[i]);
|
||||
}
|
||||
}
|
||||
|
||||
fp2_dlog_2e(r2, &w1[1], &w1[0], pairing_dlog_data->e);
|
||||
fp2_dlog_2e(r1, &w1[2], &w1[0], pairing_dlog_data->e);
|
||||
fp2_dlog_2e(s2, &w1[3], &w1[0], pairing_dlog_data->e);
|
||||
fp2_dlog_2e(s1, &w1[4], &w1[0], pairing_dlog_data->e);
|
||||
}
|
||||
|
||||
void
|
||||
ec_dlog_2_tate(digit_t *r1,
|
||||
digit_t *r2,
|
||||
digit_t *s1,
|
||||
digit_t *s2,
|
||||
const ec_basis_t *PQ,
|
||||
const ec_basis_t *RS,
|
||||
ec_curve_t *curve,
|
||||
int e)
|
||||
{
|
||||
// assume PQ is a full torsion basis
|
||||
// returns a, b, c, d such that R = [a]P + [b]Q, S = [c]P + [d]Q
|
||||
|
||||
#ifndef NDEBUG
|
||||
int e_full = TORSION_EVEN_POWER;
|
||||
int e_diff = e_full - e;
|
||||
#endif
|
||||
assert(test_basis_order_twof(PQ, curve, e_full));
|
||||
|
||||
// precomputing the correct curve data
|
||||
ec_curve_normalize_A24(curve);
|
||||
|
||||
pairing_dlog_params_t pairing_dlog_data;
|
||||
pairing_dlog_data.e = e;
|
||||
pairing_dlog_data.PQ = *PQ;
|
||||
pairing_dlog_data.RS = *RS;
|
||||
pairing_dlog_data.A24 = curve->A24;
|
||||
|
||||
cubical_normalization_dlog(&pairing_dlog_data, curve);
|
||||
compute_difference_points(&pairing_dlog_data, curve);
|
||||
tate_dlog_partial(r1, r2, s1, s2, &pairing_dlog_data);
|
||||
|
||||
#ifndef NDEBUG
|
||||
ec_point_t test;
|
||||
ec_biscalar_mul(&test, r1, r2, e, PQ, curve);
|
||||
ec_dbl_iter(&test, e_diff, &test, curve);
|
||||
// R = [r1]P + [r2]Q
|
||||
assert(ec_is_equal(&test, &RS->P));
|
||||
|
||||
ec_biscalar_mul(&test, s1, s2, e, PQ, curve);
|
||||
ec_dbl_iter(&test, e_diff, &test, curve);
|
||||
// S = [s1]P + [s2]Q
|
||||
assert(ec_is_equal(&test, &RS->Q));
|
||||
#endif
|
||||
}
|
||||
665
src/ec/ref/lvlx/ec.c
Normal file
665
src/ec/ref/lvlx/ec.c
Normal file
@@ -0,0 +1,665 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <mp.h>
|
||||
#include <ec.h>
|
||||
|
||||
void
|
||||
ec_point_init(ec_point_t *P)
|
||||
{ // Initialize point as identity element (1:0)
|
||||
fp2_set_one(&(P->x));
|
||||
fp2_set_zero(&(P->z));
|
||||
}
|
||||
|
||||
void
|
||||
ec_curve_init(ec_curve_t *E)
|
||||
{ // Initialize the curve struct
|
||||
// Initialize the constants
|
||||
fp2_set_zero(&(E->A));
|
||||
fp2_set_one(&(E->C));
|
||||
|
||||
// Initialize the point (A+2 : 4C)
|
||||
ec_point_init(&(E->A24));
|
||||
|
||||
// Set the bool to be false by default
|
||||
E->is_A24_computed_and_normalized = false;
|
||||
}
|
||||
|
||||
void
|
||||
select_point(ec_point_t *Q, const ec_point_t *P1, const ec_point_t *P2, const digit_t option)
|
||||
{ // Select points in constant time
|
||||
// If option = 0 then Q <- P1, else if option = 0xFF...FF then Q <- P2
|
||||
fp2_select(&(Q->x), &(P1->x), &(P2->x), option);
|
||||
fp2_select(&(Q->z), &(P1->z), &(P2->z), option);
|
||||
}
|
||||
|
||||
void
|
||||
cswap_points(ec_point_t *P, ec_point_t *Q, const digit_t option)
|
||||
{ // Swap points in constant time
|
||||
// If option = 0 then P <- P and Q <- Q, else if option = 0xFF...FF then P <- Q and Q <- P
|
||||
fp2_cswap(&(P->x), &(Q->x), option);
|
||||
fp2_cswap(&(P->z), &(Q->z), option);
|
||||
}
|
||||
|
||||
void
|
||||
ec_normalize_point(ec_point_t *P)
|
||||
{
|
||||
fp2_inv(&P->z);
|
||||
fp2_mul(&P->x, &P->x, &P->z);
|
||||
fp2_set_one(&(P->z));
|
||||
}
|
||||
|
||||
void
|
||||
ec_normalize_curve(ec_curve_t *E)
|
||||
{
|
||||
fp2_inv(&E->C);
|
||||
fp2_mul(&E->A, &E->A, &E->C);
|
||||
fp2_set_one(&E->C);
|
||||
}
|
||||
|
||||
void
|
||||
ec_curve_normalize_A24(ec_curve_t *E)
|
||||
{
|
||||
if (!E->is_A24_computed_and_normalized) {
|
||||
AC_to_A24(&E->A24, E);
|
||||
ec_normalize_point(&E->A24);
|
||||
E->is_A24_computed_and_normalized = true;
|
||||
}
|
||||
assert(fp2_is_one(&E->A24.z));
|
||||
}
|
||||
|
||||
void
|
||||
ec_normalize_curve_and_A24(ec_curve_t *E)
|
||||
{ // Neither the curve or A24 are guaranteed to be normalized.
|
||||
// First we normalize (A/C : 1) and conditionally compute
|
||||
if (!fp2_is_one(&E->C)) {
|
||||
ec_normalize_curve(E);
|
||||
}
|
||||
|
||||
if (!E->is_A24_computed_and_normalized) {
|
||||
// Now compute A24 = ((A + 2) / 4 : 1)
|
||||
fp2_add_one(&E->A24.x, &E->A); // re(A24.x) = re(A) + 1
|
||||
fp2_add_one(&E->A24.x, &E->A24.x); // re(A24.x) = re(A) + 2
|
||||
fp_copy(&E->A24.x.im, &E->A.im); // im(A24.x) = im(A)
|
||||
|
||||
fp2_half(&E->A24.x, &E->A24.x); // (A + 2) / 2
|
||||
fp2_half(&E->A24.x, &E->A24.x); // (A + 2) / 4
|
||||
fp2_set_one(&E->A24.z);
|
||||
|
||||
E->is_A24_computed_and_normalized = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ec_is_zero(const ec_point_t *P)
|
||||
{
|
||||
return fp2_is_zero(&P->z);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ec_has_zero_coordinate(const ec_point_t *P)
|
||||
{
|
||||
return fp2_is_zero(&P->x) | fp2_is_zero(&P->z);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ec_is_equal(const ec_point_t *P, const ec_point_t *Q)
|
||||
{ // Evaluate if two points in Montgomery coordinates (X:Z) are equal
|
||||
// Returns 0xFFFFFFFF (true) if P=Q, 0 (false) otherwise
|
||||
fp2_t t0, t1;
|
||||
|
||||
// Check if P, Q are the points at infinity
|
||||
uint32_t l_zero = ec_is_zero(P);
|
||||
uint32_t r_zero = ec_is_zero(Q);
|
||||
|
||||
// Check if PX * QZ = QX * PZ
|
||||
fp2_mul(&t0, &P->x, &Q->z);
|
||||
fp2_mul(&t1, &P->z, &Q->x);
|
||||
uint32_t lr_equal = fp2_is_equal(&t0, &t1);
|
||||
|
||||
// Points are equal if
|
||||
// - Both are zero, or
|
||||
// - neither are zero AND PX * QZ = QX * PZ
|
||||
return (l_zero & r_zero) | (~l_zero & ~r_zero * lr_equal);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ec_is_two_torsion(const ec_point_t *P, const ec_curve_t *E)
|
||||
{
|
||||
if (ec_is_zero(P))
|
||||
return 0;
|
||||
|
||||
uint32_t x_is_zero, tmp_is_zero;
|
||||
fp2_t t0, t1, t2;
|
||||
fp2_add(&t0, &P->x, &P->z);
|
||||
fp2_sqr(&t0, &t0);
|
||||
fp2_sub(&t1, &P->x, &P->z);
|
||||
fp2_sqr(&t1, &t1);
|
||||
fp2_sub(&t2, &t0, &t1);
|
||||
fp2_add(&t1, &t0, &t1);
|
||||
fp2_mul(&t2, &t2, &E->A);
|
||||
fp2_mul(&t1, &t1, &E->C);
|
||||
fp2_add(&t1, &t1, &t1);
|
||||
fp2_add(&t0, &t1, &t2); // 4 (CX^2+CZ^2+AXZ)
|
||||
|
||||
x_is_zero = fp2_is_zero(&P->x);
|
||||
tmp_is_zero = fp2_is_zero(&t0);
|
||||
|
||||
// two torsion if x or x^2 + Ax + 1 is zero
|
||||
return x_is_zero | tmp_is_zero;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ec_is_four_torsion(const ec_point_t *P, const ec_curve_t *E)
|
||||
{
|
||||
ec_point_t test;
|
||||
xDBL_A24(&test, P, &E->A24, E->is_A24_computed_and_normalized);
|
||||
return ec_is_two_torsion(&test, E);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ec_is_basis_four_torsion(const ec_basis_t *B, const ec_curve_t *E)
|
||||
{ // Check if basis points (P, Q) form a full 2^t-basis
|
||||
ec_point_t P2, Q2;
|
||||
xDBL_A24(&P2, &B->P, &E->A24, E->is_A24_computed_and_normalized);
|
||||
xDBL_A24(&Q2, &B->Q, &E->A24, E->is_A24_computed_and_normalized);
|
||||
return (ec_is_two_torsion(&P2, E) & ec_is_two_torsion(&Q2, E) & ~ec_is_equal(&P2, &Q2));
|
||||
}
|
||||
|
||||
int
|
||||
ec_curve_verify_A(const fp2_t *A)
|
||||
{ // Verify the Montgomery coefficient A is valid (A^2-4 \ne 0)
|
||||
// Return 1 if curve is valid, 0 otherwise
|
||||
fp2_t t;
|
||||
fp2_set_one(&t);
|
||||
fp_add(&t.re, &t.re, &t.re); // t=2
|
||||
if (fp2_is_equal(A, &t))
|
||||
return 0;
|
||||
fp_neg(&t.re, &t.re); // t=-2
|
||||
if (fp2_is_equal(A, &t))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
ec_curve_init_from_A(ec_curve_t *E, const fp2_t *A)
|
||||
{ // Initialize the curve from the A coefficient and check it is valid
|
||||
// Return 1 if curve is valid, 0 otherwise
|
||||
ec_curve_init(E);
|
||||
fp2_copy(&E->A, A); // Set A
|
||||
return ec_curve_verify_A(A);
|
||||
}
|
||||
|
||||
void
|
||||
ec_j_inv(fp2_t *j_inv, const ec_curve_t *curve)
|
||||
{ // j-invariant computation for Montgommery coefficient A2=(A+2C:4C)
|
||||
fp2_t t0, t1;
|
||||
|
||||
fp2_sqr(&t1, &curve->C);
|
||||
fp2_sqr(j_inv, &curve->A);
|
||||
fp2_add(&t0, &t1, &t1);
|
||||
fp2_sub(&t0, j_inv, &t0);
|
||||
fp2_sub(&t0, &t0, &t1);
|
||||
fp2_sub(j_inv, &t0, &t1);
|
||||
fp2_sqr(&t1, &t1);
|
||||
fp2_mul(j_inv, j_inv, &t1);
|
||||
fp2_add(&t0, &t0, &t0);
|
||||
fp2_add(&t0, &t0, &t0);
|
||||
fp2_sqr(&t1, &t0);
|
||||
fp2_mul(&t0, &t0, &t1);
|
||||
fp2_add(&t0, &t0, &t0);
|
||||
fp2_add(&t0, &t0, &t0);
|
||||
fp2_inv(j_inv);
|
||||
fp2_mul(j_inv, &t0, j_inv);
|
||||
}
|
||||
|
||||
void
|
||||
xDBL_E0(ec_point_t *Q, const ec_point_t *P)
|
||||
{ // Doubling of a Montgomery point in projective coordinates (X:Z) on the curve E0 with (A:C) = (0:1).
|
||||
// Input: projective Montgomery x-coordinates P = (XP:ZP), where xP=XP/ZP, and Montgomery curve constants (A:C) = (0:1).
|
||||
// Output: projective Montgomery x-coordinates Q <- 2*P = (XQ:ZQ) such that x(2P)=XQ/ZQ.
|
||||
fp2_t t0, t1, t2;
|
||||
|
||||
fp2_add(&t0, &P->x, &P->z);
|
||||
fp2_sqr(&t0, &t0);
|
||||
fp2_sub(&t1, &P->x, &P->z);
|
||||
fp2_sqr(&t1, &t1);
|
||||
fp2_sub(&t2, &t0, &t1);
|
||||
fp2_add(&t1, &t1, &t1);
|
||||
fp2_mul(&Q->x, &t0, &t1);
|
||||
fp2_add(&Q->z, &t1, &t2);
|
||||
fp2_mul(&Q->z, &Q->z, &t2);
|
||||
}
|
||||
|
||||
void
|
||||
xDBL(ec_point_t *Q, const ec_point_t *P, const ec_point_t *AC)
|
||||
{ // Doubling of a Montgomery point in projective coordinates (X:Z). Computation of coefficient values A+2C and 4C
|
||||
// on-the-fly.
|
||||
// Input: projective Montgomery x-coordinates P = (XP:ZP), where xP=XP/ZP, and Montgomery curve constants (A:C).
|
||||
// Output: projective Montgomery x-coordinates Q <- 2*P = (XQ:ZQ) such that x(2P)=XQ/ZQ.
|
||||
fp2_t t0, t1, t2, t3;
|
||||
|
||||
fp2_add(&t0, &P->x, &P->z);
|
||||
fp2_sqr(&t0, &t0);
|
||||
fp2_sub(&t1, &P->x, &P->z);
|
||||
fp2_sqr(&t1, &t1);
|
||||
fp2_sub(&t2, &t0, &t1);
|
||||
fp2_add(&t3, &AC->z, &AC->z);
|
||||
fp2_mul(&t1, &t1, &t3);
|
||||
fp2_add(&t1, &t1, &t1);
|
||||
fp2_mul(&Q->x, &t0, &t1);
|
||||
fp2_add(&t0, &t3, &AC->x);
|
||||
fp2_mul(&t0, &t0, &t2);
|
||||
fp2_add(&t0, &t0, &t1);
|
||||
fp2_mul(&Q->z, &t0, &t2);
|
||||
}
|
||||
|
||||
void
|
||||
xDBL_A24(ec_point_t *Q, const ec_point_t *P, const ec_point_t *A24, const bool A24_normalized)
|
||||
{ // Doubling of a Montgomery point in projective coordinates (X:Z).
|
||||
// Input: projective Montgomery x-coordinates P = (XP:ZP), where xP=XP/ZP, and
|
||||
// the Montgomery curve constants A24 = (A+2C:4C) (or A24 = (A+2C/4C:1) if normalized).
|
||||
// Output: projective Montgomery x-coordinates Q <- 2*P = (XQ:ZQ) such that x(2P)=XQ/ZQ.
|
||||
fp2_t t0, t1, t2;
|
||||
|
||||
fp2_add(&t0, &P->x, &P->z);
|
||||
fp2_sqr(&t0, &t0);
|
||||
fp2_sub(&t1, &P->x, &P->z);
|
||||
fp2_sqr(&t1, &t1);
|
||||
fp2_sub(&t2, &t0, &t1);
|
||||
if (!A24_normalized)
|
||||
fp2_mul(&t1, &t1, &A24->z);
|
||||
fp2_mul(&Q->x, &t0, &t1);
|
||||
fp2_mul(&t0, &t2, &A24->x);
|
||||
fp2_add(&t0, &t0, &t1);
|
||||
fp2_mul(&Q->z, &t0, &t2);
|
||||
}
|
||||
|
||||
void
|
||||
xADD(ec_point_t *R, const ec_point_t *P, const ec_point_t *Q, const ec_point_t *PQ)
|
||||
{ // Differential addition of Montgomery points in projective coordinates (X:Z).
|
||||
// Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, and difference
|
||||
// PQ=P-Q=(XPQ:ZPQ).
|
||||
// Output: projective Montgomery point R <- P+Q = (XR:ZR) such that x(P+Q)=XR/ZR.
|
||||
fp2_t t0, t1, t2, t3;
|
||||
|
||||
fp2_add(&t0, &P->x, &P->z);
|
||||
fp2_sub(&t1, &P->x, &P->z);
|
||||
fp2_add(&t2, &Q->x, &Q->z);
|
||||
fp2_sub(&t3, &Q->x, &Q->z);
|
||||
fp2_mul(&t0, &t0, &t3);
|
||||
fp2_mul(&t1, &t1, &t2);
|
||||
fp2_add(&t2, &t0, &t1);
|
||||
fp2_sub(&t3, &t0, &t1);
|
||||
fp2_sqr(&t2, &t2);
|
||||
fp2_sqr(&t3, &t3);
|
||||
fp2_mul(&t2, &PQ->z, &t2);
|
||||
fp2_mul(&R->z, &PQ->x, &t3);
|
||||
fp2_copy(&R->x, &t2);
|
||||
}
|
||||
|
||||
void
|
||||
xDBLADD(ec_point_t *R,
|
||||
ec_point_t *S,
|
||||
const ec_point_t *P,
|
||||
const ec_point_t *Q,
|
||||
const ec_point_t *PQ,
|
||||
const ec_point_t *A24,
|
||||
const bool A24_normalized)
|
||||
{ // Simultaneous doubling and differential addition.
|
||||
// Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, the difference
|
||||
// PQ=P-Q=(XPQ:ZPQ), and the Montgomery curve constants A24 = (A+2C:4C) (or A24 = (A+2C/4C:1) if normalized).
|
||||
// Output: projective Montgomery points R <- 2*P = (XR:ZR) such that x(2P)=XR/ZR, and S <- P+Q = (XS:ZS) such that =
|
||||
// x(Q+P)=XS/ZS.
|
||||
fp2_t t0, t1, t2;
|
||||
|
||||
fp2_add(&t0, &P->x, &P->z);
|
||||
fp2_sub(&t1, &P->x, &P->z);
|
||||
fp2_sqr(&R->x, &t0);
|
||||
fp2_sub(&t2, &Q->x, &Q->z);
|
||||
fp2_add(&S->x, &Q->x, &Q->z);
|
||||
fp2_mul(&t0, &t0, &t2);
|
||||
fp2_sqr(&R->z, &t1);
|
||||
fp2_mul(&t1, &t1, &S->x);
|
||||
fp2_sub(&t2, &R->x, &R->z);
|
||||
if (!A24_normalized)
|
||||
fp2_mul(&R->z, &R->z, &A24->z);
|
||||
fp2_mul(&R->x, &R->x, &R->z);
|
||||
fp2_mul(&S->x, &A24->x, &t2);
|
||||
fp2_sub(&S->z, &t0, &t1);
|
||||
fp2_add(&R->z, &R->z, &S->x);
|
||||
fp2_add(&S->x, &t0, &t1);
|
||||
fp2_mul(&R->z, &R->z, &t2);
|
||||
fp2_sqr(&S->z, &S->z);
|
||||
fp2_sqr(&S->x, &S->x);
|
||||
fp2_mul(&S->z, &S->z, &PQ->x);
|
||||
fp2_mul(&S->x, &S->x, &PQ->z);
|
||||
}
|
||||
|
||||
void
|
||||
xMUL(ec_point_t *Q, const ec_point_t *P, const digit_t *k, const int kbits, const ec_curve_t *curve)
|
||||
{ // The Montgomery ladder
|
||||
// Input: projective Montgomery point P=(XP:ZP) such that xP=XP/ZP, a scalar k of bitlength kbits, and
|
||||
// the Montgomery curve constants (A:C) (or A24 = (A+2C/4C:1) if normalized).
|
||||
// Output: projective Montgomery points Q <- k*P = (XQ:ZQ) such that x(k*P)=XQ/ZQ.
|
||||
ec_point_t R0, R1, A24;
|
||||
digit_t mask;
|
||||
unsigned int bit, prevbit = 0, swap;
|
||||
|
||||
if (!curve->is_A24_computed_and_normalized) {
|
||||
// Computation of A24=(A+2C:4C)
|
||||
fp2_add(&A24.x, &curve->C, &curve->C);
|
||||
fp2_add(&A24.z, &A24.x, &A24.x);
|
||||
fp2_add(&A24.x, &A24.x, &curve->A);
|
||||
} else {
|
||||
fp2_copy(&A24.x, &curve->A24.x);
|
||||
fp2_copy(&A24.z, &curve->A24.z);
|
||||
// Assert A24 has been normalised
|
||||
assert(fp2_is_one(&A24.z));
|
||||
}
|
||||
|
||||
// R0 <- (1:0), R1 <- P
|
||||
ec_point_init(&R0);
|
||||
fp2_copy(&R1.x, &P->x);
|
||||
fp2_copy(&R1.z, &P->z);
|
||||
|
||||
// Main loop
|
||||
for (int i = kbits - 1; i >= 0; i--) {
|
||||
bit = (k[i >> LOG2RADIX] >> (i & (RADIX - 1))) & 1;
|
||||
swap = bit ^ prevbit;
|
||||
prevbit = bit;
|
||||
mask = 0 - (digit_t)swap;
|
||||
|
||||
cswap_points(&R0, &R1, mask);
|
||||
xDBLADD(&R0, &R1, &R0, &R1, P, &A24, true);
|
||||
}
|
||||
swap = 0 ^ prevbit;
|
||||
mask = 0 - (digit_t)swap;
|
||||
cswap_points(&R0, &R1, mask);
|
||||
|
||||
fp2_copy(&Q->x, &R0.x);
|
||||
fp2_copy(&Q->z, &R0.z);
|
||||
}
|
||||
|
||||
int
|
||||
xDBLMUL(ec_point_t *S,
|
||||
const ec_point_t *P,
|
||||
const digit_t *k,
|
||||
const ec_point_t *Q,
|
||||
const digit_t *l,
|
||||
const ec_point_t *PQ,
|
||||
const int kbits,
|
||||
const ec_curve_t *curve)
|
||||
{ // The Montgomery biladder
|
||||
// Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, scalars k and l of
|
||||
// bitlength kbits, the difference PQ=P-Q=(XPQ:ZPQ), and the Montgomery curve constants (A:C).
|
||||
// Output: projective Montgomery point S <- k*P + l*Q = (XS:ZS) such that x(k*P + l*Q)=XS/ZS.
|
||||
|
||||
int i, A_is_zero;
|
||||
digit_t evens, mevens, bitk0, bitl0, maskk, maskl, temp, bs1_ip1, bs2_ip1, bs1_i, bs2_i, h;
|
||||
digit_t sigma[2] = { 0 }, pre_sigma = 0;
|
||||
digit_t k_t[NWORDS_ORDER], l_t[NWORDS_ORDER], one[NWORDS_ORDER] = { 0 }, r[2 * BITS] = { 0 };
|
||||
ec_point_t DIFF1a, DIFF1b, DIFF2a, DIFF2b, R[3] = { 0 }, T[3];
|
||||
|
||||
// differential additions formulas are invalid in this case
|
||||
if (ec_has_zero_coordinate(P) | ec_has_zero_coordinate(Q) | ec_has_zero_coordinate(PQ))
|
||||
return 0;
|
||||
|
||||
// Derive sigma according to parity
|
||||
bitk0 = (k[0] & 1);
|
||||
bitl0 = (l[0] & 1);
|
||||
maskk = 0 - bitk0; // Parity masks: 0 if even, otherwise 1...1
|
||||
maskl = 0 - bitl0;
|
||||
sigma[0] = (bitk0 ^ 1);
|
||||
sigma[1] = (bitl0 ^ 1);
|
||||
evens = sigma[0] + sigma[1]; // Count number of even scalars
|
||||
mevens = 0 - (evens & 1); // Mask mevens <- 0 if # even of scalars = 0 or 2, otherwise mevens = 1...1
|
||||
|
||||
// If k and l are both even or both odd, pick sigma = (0,1)
|
||||
sigma[0] = (sigma[0] & mevens);
|
||||
sigma[1] = (sigma[1] & mevens) | (1 & ~mevens);
|
||||
|
||||
// Convert even scalars to odd
|
||||
one[0] = 1;
|
||||
mp_sub(k_t, k, one, NWORDS_ORDER);
|
||||
mp_sub(l_t, l, one, NWORDS_ORDER);
|
||||
select_ct(k_t, k_t, k, maskk, NWORDS_ORDER);
|
||||
select_ct(l_t, l_t, l, maskl, NWORDS_ORDER);
|
||||
|
||||
// Scalar recoding
|
||||
for (i = 0; i < kbits; i++) {
|
||||
// If sigma[0] = 1 swap k_t and l_t
|
||||
maskk = 0 - (sigma[0] ^ pre_sigma);
|
||||
swap_ct(k_t, l_t, maskk, NWORDS_ORDER);
|
||||
|
||||
if (i == kbits - 1) {
|
||||
bs1_ip1 = 0;
|
||||
bs2_ip1 = 0;
|
||||
} else {
|
||||
bs1_ip1 = mp_shiftr(k_t, 1, NWORDS_ORDER);
|
||||
bs2_ip1 = mp_shiftr(l_t, 1, NWORDS_ORDER);
|
||||
}
|
||||
bs1_i = k_t[0] & 1;
|
||||
bs2_i = l_t[0] & 1;
|
||||
|
||||
r[2 * i] = bs1_i ^ bs1_ip1;
|
||||
r[2 * i + 1] = bs2_i ^ bs2_ip1;
|
||||
|
||||
// Revert sigma if second bit, r_(2i+1), is 1
|
||||
pre_sigma = sigma[0];
|
||||
maskk = 0 - r[2 * i + 1];
|
||||
select_ct(&temp, &sigma[0], &sigma[1], maskk, 1);
|
||||
select_ct(&sigma[1], &sigma[1], &sigma[0], maskk, 1);
|
||||
sigma[0] = temp;
|
||||
}
|
||||
|
||||
// Point initialization
|
||||
ec_point_init(&R[0]);
|
||||
maskk = 0 - sigma[0];
|
||||
select_point(&R[1], P, Q, maskk);
|
||||
select_point(&R[2], Q, P, maskk);
|
||||
|
||||
fp2_copy(&DIFF1a.x, &R[1].x);
|
||||
fp2_copy(&DIFF1a.z, &R[1].z);
|
||||
fp2_copy(&DIFF1b.x, &R[2].x);
|
||||
fp2_copy(&DIFF1b.z, &R[2].z);
|
||||
|
||||
// Initialize DIFF2a <- P+Q, DIFF2b <- P-Q
|
||||
xADD(&R[2], &R[1], &R[2], PQ);
|
||||
if (ec_has_zero_coordinate(&R[2]))
|
||||
return 0; // non valid formulas
|
||||
|
||||
fp2_copy(&DIFF2a.x, &R[2].x);
|
||||
fp2_copy(&DIFF2a.z, &R[2].z);
|
||||
fp2_copy(&DIFF2b.x, &PQ->x);
|
||||
fp2_copy(&DIFF2b.z, &PQ->z);
|
||||
|
||||
A_is_zero = fp2_is_zero(&curve->A);
|
||||
|
||||
// Main loop
|
||||
for (i = kbits - 1; i >= 0; i--) {
|
||||
h = r[2 * i] + r[2 * i + 1]; // in {0, 1, 2}
|
||||
maskk = 0 - (h & 1);
|
||||
select_point(&T[0], &R[0], &R[1], maskk);
|
||||
maskk = 0 - (h >> 1);
|
||||
select_point(&T[0], &T[0], &R[2], maskk);
|
||||
if (A_is_zero) {
|
||||
xDBL_E0(&T[0], &T[0]);
|
||||
} else {
|
||||
assert(fp2_is_one(&curve->A24.z));
|
||||
xDBL_A24(&T[0], &T[0], &curve->A24, true);
|
||||
}
|
||||
|
||||
maskk = 0 - r[2 * i + 1]; // in {0, 1}
|
||||
select_point(&T[1], &R[0], &R[1], maskk);
|
||||
select_point(&T[2], &R[1], &R[2], maskk);
|
||||
|
||||
cswap_points(&DIFF1a, &DIFF1b, maskk);
|
||||
xADD(&T[1], &T[1], &T[2], &DIFF1a);
|
||||
xADD(&T[2], &R[0], &R[2], &DIFF2a);
|
||||
|
||||
// If hw (mod 2) = 1 then swap DIFF2a and DIFF2b
|
||||
maskk = 0 - (h & 1);
|
||||
cswap_points(&DIFF2a, &DIFF2b, maskk);
|
||||
|
||||
// R <- T
|
||||
copy_point(&R[0], &T[0]);
|
||||
copy_point(&R[1], &T[1]);
|
||||
copy_point(&R[2], &T[2]);
|
||||
}
|
||||
|
||||
// Output R[evens]
|
||||
select_point(S, &R[0], &R[1], mevens);
|
||||
|
||||
maskk = 0 - (bitk0 & bitl0);
|
||||
select_point(S, S, &R[2], maskk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
ec_ladder3pt(ec_point_t *R,
|
||||
const digit_t *m,
|
||||
const ec_point_t *P,
|
||||
const ec_point_t *Q,
|
||||
const ec_point_t *PQ,
|
||||
const ec_curve_t *E)
|
||||
{ // The 3-point Montgomery ladder
|
||||
// Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, a scalar k of
|
||||
// bitlength kbits, the difference PQ=P-Q=(XPQ:ZPQ), and the Montgomery curve constants A24 = (A+2C/4C:1).
|
||||
// Output: projective Montgomery point R <- P + m*Q = (XR:ZR) such that x(P + m*Q)=XR/ZR.
|
||||
assert(E->is_A24_computed_and_normalized);
|
||||
if (!fp2_is_one(&E->A24.z)) {
|
||||
return 0;
|
||||
}
|
||||
// Formulas are not valid in that case
|
||||
if (ec_has_zero_coordinate(PQ)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ec_point_t X0, X1, X2;
|
||||
copy_point(&X0, Q);
|
||||
copy_point(&X1, P);
|
||||
copy_point(&X2, PQ);
|
||||
|
||||
int i, j;
|
||||
digit_t t;
|
||||
for (i = 0; i < NWORDS_ORDER; i++) {
|
||||
t = 1;
|
||||
for (j = 0; j < RADIX; j++) {
|
||||
cswap_points(&X1, &X2, -((t & m[i]) == 0));
|
||||
xDBLADD(&X0, &X1, &X0, &X1, &X2, &E->A24, true);
|
||||
cswap_points(&X1, &X2, -((t & m[i]) == 0));
|
||||
t <<= 1;
|
||||
};
|
||||
};
|
||||
copy_point(R, &X1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// WRAPPERS to export
|
||||
|
||||
void
|
||||
ec_dbl(ec_point_t *res, const ec_point_t *P, const ec_curve_t *curve)
|
||||
{
|
||||
// If A24 = ((A+2)/4 : 1) we save multiplications
|
||||
if (curve->is_A24_computed_and_normalized) {
|
||||
assert(fp2_is_one(&curve->A24.z));
|
||||
xDBL_A24(res, P, &curve->A24, true);
|
||||
} else {
|
||||
// Otherwise we compute A24 on the fly for doubling
|
||||
xDBL(res, P, (const ec_point_t *)curve);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ec_dbl_iter(ec_point_t *res, int n, const ec_point_t *P, ec_curve_t *curve)
|
||||
{
|
||||
if (n == 0) {
|
||||
copy_point(res, P);
|
||||
return;
|
||||
}
|
||||
|
||||
// When the chain is long enough, we should normalise A24
|
||||
if (n > 50) {
|
||||
ec_curve_normalize_A24(curve);
|
||||
}
|
||||
|
||||
// When A24 is normalized we can save some multiplications
|
||||
if (curve->is_A24_computed_and_normalized) {
|
||||
assert(fp2_is_one(&curve->A24.z));
|
||||
xDBL_A24(res, P, &curve->A24, true);
|
||||
for (int i = 0; i < n - 1; i++) {
|
||||
assert(fp2_is_one(&curve->A24.z));
|
||||
xDBL_A24(res, res, &curve->A24, true);
|
||||
}
|
||||
} else {
|
||||
// Otherwise we do normal doubling
|
||||
xDBL(res, P, (const ec_point_t *)curve);
|
||||
for (int i = 0; i < n - 1; i++) {
|
||||
xDBL(res, res, (const ec_point_t *)curve);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ec_dbl_iter_basis(ec_basis_t *res, int n, const ec_basis_t *B, ec_curve_t *curve)
|
||||
{
|
||||
ec_dbl_iter(&res->P, n, &B->P, curve);
|
||||
ec_dbl_iter(&res->Q, n, &B->Q, curve);
|
||||
ec_dbl_iter(&res->PmQ, n, &B->PmQ, curve);
|
||||
}
|
||||
|
||||
void
|
||||
ec_mul(ec_point_t *res, const digit_t *scalar, const int kbits, const ec_point_t *P, ec_curve_t *curve)
|
||||
{
|
||||
// For large scalars it's worth normalising anyway
|
||||
if (kbits > 50) {
|
||||
ec_curve_normalize_A24(curve);
|
||||
}
|
||||
|
||||
// When A24 is computed and normalized we save some Fp2 multiplications
|
||||
xMUL(res, P, scalar, kbits, curve);
|
||||
}
|
||||
|
||||
int
|
||||
ec_biscalar_mul(ec_point_t *res,
|
||||
const digit_t *scalarP,
|
||||
const digit_t *scalarQ,
|
||||
const int kbits,
|
||||
const ec_basis_t *PQ,
|
||||
const ec_curve_t *curve)
|
||||
{
|
||||
if (fp2_is_zero(&PQ->PmQ.z))
|
||||
return 0;
|
||||
|
||||
/* Differential additions behave badly when PmQ = (0:1), so we need to
|
||||
* treat this case specifically. Since we assume P, Q are a basis, this
|
||||
* can happen only if kbits==1 */
|
||||
if (kbits == 1) {
|
||||
// Sanity check: our basis should be given by 2-torsion points
|
||||
if (!ec_is_two_torsion(&PQ->P, curve) || !ec_is_two_torsion(&PQ->Q, curve) ||
|
||||
!ec_is_two_torsion(&PQ->PmQ, curve))
|
||||
return 0;
|
||||
digit_t bP, bQ;
|
||||
bP = (scalarP[0] & 1);
|
||||
bQ = (scalarQ[0] & 1);
|
||||
if (bP == 0 && bQ == 0)
|
||||
ec_point_init(res); //(1: 0)
|
||||
else if (bP == 1 && bQ == 0)
|
||||
copy_point(res, &PQ->P);
|
||||
else if (bP == 0 && bQ == 1)
|
||||
copy_point(res, &PQ->Q);
|
||||
else if (bP == 1 && bQ == 1)
|
||||
copy_point(res, &PQ->PmQ);
|
||||
else // should never happen
|
||||
assert(0);
|
||||
return 1;
|
||||
} else {
|
||||
ec_curve_t E;
|
||||
copy_curve(&E, curve);
|
||||
|
||||
if (!fp2_is_zero(&curve->A)) { // If A is not zero normalize
|
||||
ec_curve_normalize_A24(&E);
|
||||
}
|
||||
return xDBLMUL(res, &PQ->P, scalarP, &PQ->Q, scalarQ, &PQ->PmQ, kbits, (const ec_curve_t *)&E);
|
||||
}
|
||||
}
|
||||
335
src/ec/ref/lvlx/ec_jac.c
Normal file
335
src/ec/ref/lvlx/ec_jac.c
Normal file
@@ -0,0 +1,335 @@
|
||||
#include <assert.h>
|
||||
#include <ec.h>
|
||||
|
||||
void
|
||||
jac_init(jac_point_t *P)
|
||||
{ // Initialize Montgomery in Jacobian coordinates as identity element (0:1:0)
|
||||
fp2_set_zero(&P->x);
|
||||
fp2_set_one(&P->y);
|
||||
fp2_set_zero(&P->z);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
jac_is_equal(const jac_point_t *P, const jac_point_t *Q)
|
||||
{ // Evaluate if two points in Jacobian coordinates (X:Y:Z) are equal
|
||||
// Returns 1 (true) if P=Q, 0 (false) otherwise
|
||||
fp2_t t0, t1, t2, t3;
|
||||
|
||||
fp2_sqr(&t0, &Q->z);
|
||||
fp2_mul(&t2, &P->x, &t0); // x1*z2^2
|
||||
fp2_sqr(&t1, &P->z);
|
||||
fp2_mul(&t3, &Q->x, &t1); // x2*z1^2
|
||||
fp2_sub(&t2, &t2, &t3);
|
||||
|
||||
fp2_mul(&t0, &t0, &Q->z);
|
||||
fp2_mul(&t0, &P->y, &t0); // y1*z2^3
|
||||
fp2_mul(&t1, &t1, &P->z);
|
||||
fp2_mul(&t1, &Q->y, &t1); // y2*z1^3
|
||||
fp2_sub(&t0, &t0, &t1);
|
||||
|
||||
return fp2_is_zero(&t0) & fp2_is_zero(&t2);
|
||||
}
|
||||
|
||||
void
|
||||
jac_to_xz(ec_point_t *P, const jac_point_t *xyP)
|
||||
{
|
||||
fp2_copy(&P->x, &xyP->x);
|
||||
fp2_copy(&P->z, &xyP->z);
|
||||
fp2_sqr(&P->z, &P->z);
|
||||
|
||||
// If xyP = (0:1:0), we currently have P=(0 : 0) but we want to set P=(1:0)
|
||||
uint32_t c1, c2;
|
||||
fp2_t one;
|
||||
fp2_set_one(&one);
|
||||
|
||||
c1 = fp2_is_zero(&P->x);
|
||||
c2 = fp2_is_zero(&P->z);
|
||||
fp2_select(&P->x, &P->x, &one, c1 & c2);
|
||||
}
|
||||
|
||||
void
|
||||
jac_to_ws(jac_point_t *Q, fp2_t *t, fp2_t *ao3, const jac_point_t *P, const ec_curve_t *curve)
|
||||
{
|
||||
// Cost of 3M + 2S when A != 0.
|
||||
fp_t one;
|
||||
fp2_t a;
|
||||
/* a = 1 - A^2/3, U = X + (A*Z^2)/3, V = Y, W = Z, T = a*Z^4*/
|
||||
fp_set_one(&one);
|
||||
if (!fp2_is_zero(&(curve->A))) {
|
||||
fp_div3(&(ao3->re), &(curve->A.re));
|
||||
fp_div3(&(ao3->im), &(curve->A.im));
|
||||
fp2_sqr(t, &P->z);
|
||||
fp2_mul(&Q->x, ao3, t);
|
||||
fp2_add(&Q->x, &Q->x, &P->x);
|
||||
fp2_sqr(t, t);
|
||||
fp2_mul(&a, ao3, &(curve->A));
|
||||
fp_sub(&(a.re), &one, &(a.re));
|
||||
fp_neg(&(a.im), &(a.im));
|
||||
fp2_mul(t, t, &a);
|
||||
} else {
|
||||
fp2_copy(&Q->x, &P->x);
|
||||
fp2_sqr(t, &P->z);
|
||||
fp2_sqr(t, t);
|
||||
}
|
||||
fp2_copy(&Q->y, &P->y);
|
||||
fp2_copy(&Q->z, &P->z);
|
||||
}
|
||||
|
||||
void
|
||||
jac_from_ws(jac_point_t *Q, const jac_point_t *P, const fp2_t *ao3, const ec_curve_t *curve)
|
||||
{
|
||||
// Cost of 1M + 1S when A != 0.
|
||||
fp2_t t;
|
||||
/* X = U - (A*W^2)/3, Y = V, Z = W. */
|
||||
if (!fp2_is_zero(&(curve->A))) {
|
||||
fp2_sqr(&t, &P->z);
|
||||
fp2_mul(&t, &t, ao3);
|
||||
fp2_sub(&Q->x, &P->x, &t);
|
||||
}
|
||||
fp2_copy(&Q->y, &P->y);
|
||||
fp2_copy(&Q->z, &P->z);
|
||||
}
|
||||
|
||||
void
|
||||
copy_jac_point(jac_point_t *P, const jac_point_t *Q)
|
||||
{
|
||||
fp2_copy(&(P->x), &(Q->x));
|
||||
fp2_copy(&(P->y), &(Q->y));
|
||||
fp2_copy(&(P->z), &(Q->z));
|
||||
}
|
||||
|
||||
void
|
||||
jac_neg(jac_point_t *Q, const jac_point_t *P)
|
||||
{
|
||||
fp2_copy(&Q->x, &P->x);
|
||||
fp2_neg(&Q->y, &P->y);
|
||||
fp2_copy(&Q->z, &P->z);
|
||||
}
|
||||
|
||||
void
|
||||
DBL(jac_point_t *Q, const jac_point_t *P, const ec_curve_t *AC)
|
||||
{ // Cost of 6M + 6S.
|
||||
// Doubling on a Montgomery curve, representation in Jacobian coordinates (X:Y:Z) corresponding to
|
||||
// (X/Z^2,Y/Z^3) This version receives the coefficient value A
|
||||
fp2_t t0, t1, t2, t3;
|
||||
|
||||
uint32_t flag = fp2_is_zero(&P->x) & fp2_is_zero(&P->z);
|
||||
|
||||
fp2_sqr(&t0, &P->x); // t0 = x1^2
|
||||
fp2_add(&t1, &t0, &t0);
|
||||
fp2_add(&t0, &t0, &t1); // t0 = 3x1^2
|
||||
fp2_sqr(&t1, &P->z); // t1 = z1^2
|
||||
fp2_mul(&t2, &P->x, &AC->A);
|
||||
fp2_add(&t2, &t2, &t2); // t2 = 2Ax1
|
||||
fp2_add(&t2, &t1, &t2); // t2 = 2Ax1+z1^2
|
||||
fp2_mul(&t2, &t1, &t2); // t2 = z1^2(2Ax1+z1^2)
|
||||
fp2_add(&t2, &t0, &t2); // t2 = alpha = 3x1^2 + z1^2(2Ax1+z1^2)
|
||||
fp2_mul(&Q->z, &P->y, &P->z);
|
||||
fp2_add(&Q->z, &Q->z, &Q->z); // z2 = 2y1z1
|
||||
fp2_sqr(&t0, &Q->z);
|
||||
fp2_mul(&t0, &t0, &AC->A); // t0 = 4Ay1^2z1^2
|
||||
fp2_sqr(&t1, &P->y);
|
||||
fp2_add(&t1, &t1, &t1); // t1 = 2y1^2
|
||||
fp2_add(&t3, &P->x, &P->x); // t3 = 2x1
|
||||
fp2_mul(&t3, &t1, &t3); // t3 = 4x1y1^2
|
||||
fp2_sqr(&Q->x, &t2); // x2 = alpha^2
|
||||
fp2_sub(&Q->x, &Q->x, &t0); // x2 = alpha^2 - 4Ay1^2z1^2
|
||||
fp2_sub(&Q->x, &Q->x, &t3);
|
||||
fp2_sub(&Q->x, &Q->x, &t3); // x2 = alpha^2 - 4Ay1^2z1^2 - 8x1y1^2
|
||||
fp2_sub(&Q->y, &t3, &Q->x); // y2 = 4x1y1^2 - x2
|
||||
fp2_mul(&Q->y, &Q->y, &t2); // y2 = alpha(4x1y1^2 - x2)
|
||||
fp2_sqr(&t1, &t1); // t1 = 4y1^4
|
||||
fp2_sub(&Q->y, &Q->y, &t1);
|
||||
fp2_sub(&Q->y, &Q->y, &t1); // y2 = alpha(4x1y1^2 - x2) - 8y1^4
|
||||
|
||||
fp2_select(&Q->x, &Q->x, &P->x, -flag);
|
||||
fp2_select(&Q->z, &Q->z, &P->z, -flag);
|
||||
}
|
||||
|
||||
void
|
||||
DBLW(jac_point_t *Q, fp2_t *u, const jac_point_t *P, const fp2_t *t)
|
||||
{ // Cost of 3M + 5S.
|
||||
// Doubling on a Weierstrass curve, representation in modified Jacobian coordinates
|
||||
// (X:Y:Z:T=a*Z^4) corresponding to (X/Z^2,Y/Z^3), where a is the curve coefficient.
|
||||
// Formula from https://hyperelliptic.org/EFD/g1p/auto-shortw-modified.html
|
||||
|
||||
uint32_t flag = fp2_is_zero(&P->x) & fp2_is_zero(&P->z);
|
||||
|
||||
fp2_t xx, c, cc, r, s, m;
|
||||
// XX = X^2
|
||||
fp2_sqr(&xx, &P->x);
|
||||
// A = 2*Y^2
|
||||
fp2_sqr(&c, &P->y);
|
||||
fp2_add(&c, &c, &c);
|
||||
// AA = A^2
|
||||
fp2_sqr(&cc, &c);
|
||||
// R = 2*AA
|
||||
fp2_add(&r, &cc, &cc);
|
||||
// S = (X+A)^2-XX-AA
|
||||
fp2_add(&s, &P->x, &c);
|
||||
fp2_sqr(&s, &s);
|
||||
fp2_sub(&s, &s, &xx);
|
||||
fp2_sub(&s, &s, &cc);
|
||||
// M = 3*XX+T1
|
||||
fp2_add(&m, &xx, &xx);
|
||||
fp2_add(&m, &m, &xx);
|
||||
fp2_add(&m, &m, t);
|
||||
// X3 = M^2-2*S
|
||||
fp2_sqr(&Q->x, &m);
|
||||
fp2_sub(&Q->x, &Q->x, &s);
|
||||
fp2_sub(&Q->x, &Q->x, &s);
|
||||
// Z3 = 2*Y*Z
|
||||
fp2_mul(&Q->z, &P->y, &P->z);
|
||||
fp2_add(&Q->z, &Q->z, &Q->z);
|
||||
// Y3 = M*(S-X3)-R
|
||||
fp2_sub(&Q->y, &s, &Q->x);
|
||||
fp2_mul(&Q->y, &Q->y, &m);
|
||||
fp2_sub(&Q->y, &Q->y, &r);
|
||||
// T3 = 2*R*T1
|
||||
fp2_mul(u, t, &r);
|
||||
fp2_add(u, u, u);
|
||||
|
||||
fp2_select(&Q->x, &Q->x, &P->x, -flag);
|
||||
fp2_select(&Q->z, &Q->z, &P->z, -flag);
|
||||
}
|
||||
|
||||
void
|
||||
select_jac_point(jac_point_t *Q, const jac_point_t *P1, const jac_point_t *P2, const digit_t option)
|
||||
{ // Select points
|
||||
// If option = 0 then Q <- P1, else if option = 0xFF...FF then Q <- P2
|
||||
fp2_select(&(Q->x), &(P1->x), &(P2->x), option);
|
||||
fp2_select(&(Q->y), &(P1->y), &(P2->y), option);
|
||||
fp2_select(&(Q->z), &(P1->z), &(P2->z), option);
|
||||
}
|
||||
|
||||
void
|
||||
ADD(jac_point_t *R, const jac_point_t *P, const jac_point_t *Q, const ec_curve_t *AC)
|
||||
{
|
||||
// Addition on a Montgomery curve, representation in Jacobian coordinates (X:Y:Z) corresponding
|
||||
// to (x,y) = (X/Z^2,Y/Z^3) This version receives the coefficient value A
|
||||
//
|
||||
// Complete routine, to handle all edge cases:
|
||||
// if ZP == 0: # P == inf
|
||||
// return Q
|
||||
// if ZQ == 0: # Q == inf
|
||||
// return P
|
||||
// dy <- YQ*ZP**3 - YP*ZQ**3
|
||||
// dx <- XQ*ZP**2 - XP*ZQ**2
|
||||
// if dx == 0: # x1 == x2
|
||||
// if dy == 0: # ... and y1 == y2: doubling case
|
||||
// dy <- ZP*ZQ * (3*XP^2 + ZP^2 * (2*A*XP + ZP^2))
|
||||
// dx <- 2*YP*ZP
|
||||
// else: # ... but y1 != y2, thus P = -Q
|
||||
// return inf
|
||||
// XR <- dy**2 - dx**2 * (A*ZP^2*ZQ^2 + XP*ZQ^2 + XQ*ZP^2)
|
||||
// YR <- dy * (XP*ZQ^2 * dx^2 - XR) - YP*ZQ^3 * dx^3
|
||||
// ZR <- dx * ZP * ZQ
|
||||
|
||||
// Constant time processing:
|
||||
// - The case for P == 0 or Q == 0 is handled at the end with conditional select
|
||||
// - dy and dx are computed for both the normal and doubling cases, we switch when
|
||||
// dx == dy == 0 for the normal case.
|
||||
// - If we have that P = -Q then dx = 0 and so ZR will be zero, giving us the point
|
||||
// at infinity for "free".
|
||||
//
|
||||
// These current formula are expensive and I'm probably missing some tricks...
|
||||
// Thought I'd get the ball rolling.
|
||||
// Cost 17M + 6S + 13a
|
||||
fp2_t t0, t1, t2, t3, u1, u2, v1, dx, dy;
|
||||
|
||||
/* If P is zero or Q is zero we will conditionally swap before returning. */
|
||||
uint32_t ctl1 = fp2_is_zero(&P->z);
|
||||
uint32_t ctl2 = fp2_is_zero(&Q->z);
|
||||
|
||||
/* Precompute some values */
|
||||
fp2_sqr(&t0, &P->z); // t0 = z1^2
|
||||
fp2_sqr(&t1, &Q->z); // t1 = z2^2
|
||||
|
||||
/* Compute dy and dx for ordinary case */
|
||||
fp2_mul(&v1, &t1, &Q->z); // v1 = z2^3
|
||||
fp2_mul(&t2, &t0, &P->z); // t2 = z1^3
|
||||
fp2_mul(&v1, &v1, &P->y); // v1 = y1z2^3
|
||||
fp2_mul(&t2, &t2, &Q->y); // t2 = y2z1^3
|
||||
fp2_sub(&dy, &t2, &v1); // dy = y2z1^3 - y1z2^3
|
||||
fp2_mul(&u2, &t0, &Q->x); // u2 = x2z1^2
|
||||
fp2_mul(&u1, &t1, &P->x); // u1 = x1z2^2
|
||||
fp2_sub(&dx, &u2, &u1); // dx = x2z1^2 - x1z2^2
|
||||
|
||||
/* Compute dy and dx for doubling case */
|
||||
fp2_add(&t1, &P->y, &P->y); // dx_dbl = t1 = 2y1
|
||||
fp2_add(&t2, &AC->A, &AC->A); // t2 = 2A
|
||||
fp2_mul(&t2, &t2, &P->x); // t2 = 2Ax1
|
||||
fp2_add(&t2, &t2, &t0); // t2 = 2Ax1 + z1^2
|
||||
fp2_mul(&t2, &t2, &t0); // t2 = z1^2 * (2Ax1 + z1^2)
|
||||
fp2_sqr(&t0, &P->x); // t0 = x1^2
|
||||
fp2_add(&t2, &t2, &t0); // t2 = x1^2 + z1^2 * (2Ax1 + z1^2)
|
||||
fp2_add(&t2, &t2, &t0); // t2 = 2*x1^2 + z1^2 * (2Ax1 + z1^2)
|
||||
fp2_add(&t2, &t2, &t0); // t2 = 3*x1^2 + z1^2 * (2Ax1 + z1^2)
|
||||
fp2_mul(&t2, &t2, &Q->z); // dy_dbl = t2 = z2 * (3*x1^2 + z1^2 * (2Ax1 + z1^2))
|
||||
|
||||
/* If dx is zero and dy is zero swap with double variables */
|
||||
uint32_t ctl = fp2_is_zero(&dx) & fp2_is_zero(&dy);
|
||||
fp2_select(&dx, &dx, &t1, ctl);
|
||||
fp2_select(&dy, &dy, &t2, ctl);
|
||||
|
||||
/* Some more precomputations */
|
||||
fp2_mul(&t0, &P->z, &Q->z); // t0 = z1z2
|
||||
fp2_sqr(&t1, &t0); // t1 = z1z2^2
|
||||
fp2_sqr(&t2, &dx); // t2 = dx^2
|
||||
fp2_sqr(&t3, &dy); // t3 = dy^2
|
||||
|
||||
/* Compute x3 = dy**2 - dx**2 * (A*ZP^2*ZQ^2 + XP*ZQ^2 + XQ*ZP^2) */
|
||||
fp2_mul(&R->x, &AC->A, &t1); // x3 = A*(z1z2)^2
|
||||
fp2_add(&R->x, &R->x, &u1); // x3 = A*(z1z2)^2 + u1
|
||||
fp2_add(&R->x, &R->x, &u2); // x3 = A*(z1z2)^2 + u1 + u2
|
||||
fp2_mul(&R->x, &R->x, &t2); // x3 = dx^2 * (A*(z1z2)^2 + u1 + u2)
|
||||
fp2_sub(&R->x, &t3, &R->x); // x3 = dy^2 - dx^2 * (A*(z1z2)^2 + u1 + u2)
|
||||
|
||||
/* Compute y3 = dy * (XP*ZQ^2 * dx^2 - XR) - YP*ZQ^3 * dx^3*/
|
||||
fp2_mul(&R->y, &u1, &t2); // y3 = u1 * dx^2
|
||||
fp2_sub(&R->y, &R->y, &R->x); // y3 = u1 * dx^2 - x3
|
||||
fp2_mul(&R->y, &R->y, &dy); // y3 = dy * (u1 * dx^2 - x3)
|
||||
fp2_mul(&t3, &t2, &dx); // t3 = dx^3
|
||||
fp2_mul(&t3, &t3, &v1); // t3 = v1 * dx^3
|
||||
fp2_sub(&R->y, &R->y, &t3); // y3 = dy * (u1 * dx^2 - x3) - v1 * dx^3
|
||||
|
||||
/* Compute z3 = dx * z1 * z2 */
|
||||
fp2_mul(&R->z, &dx, &t0);
|
||||
|
||||
/* Finally, we need to set R = P is Q.Z = 0 and R = Q if P.Z = 0 */
|
||||
select_jac_point(R, R, Q, ctl1);
|
||||
select_jac_point(R, R, P, ctl2);
|
||||
}
|
||||
|
||||
void
|
||||
jac_to_xz_add_components(add_components_t *add_comp, const jac_point_t *P, const jac_point_t *Q, const ec_curve_t *AC)
|
||||
{
|
||||
// Take P and Q in E distinct, two jac_point_t, return three components u,v and w in Fp2 such
|
||||
// that the xz coordinates of P+Q are (u-v:w) and of P-Q are (u+v:w)
|
||||
|
||||
fp2_t t0, t1, t2, t3, t4, t5, t6;
|
||||
|
||||
fp2_sqr(&t0, &P->z); // t0 = z1^2
|
||||
fp2_sqr(&t1, &Q->z); // t1 = z2^2
|
||||
fp2_mul(&t2, &P->x, &t1); // t2 = x1z2^2
|
||||
fp2_mul(&t3, &t0, &Q->x); // t3 = z1^2x2
|
||||
fp2_mul(&t4, &P->y, &Q->z); // t4 = y1z2
|
||||
fp2_mul(&t4, &t4, &t1); // t4 = y1z2^3
|
||||
fp2_mul(&t5, &P->z, &Q->y); // t5 = z1y2
|
||||
fp2_mul(&t5, &t5, &t0); // t5 = z1^3y2
|
||||
fp2_mul(&t0, &t0, &t1); // t0 = (z1z2)^2
|
||||
fp2_mul(&t6, &t4, &t5); // t6 = (z1z_2)^3y1y2
|
||||
fp2_add(&add_comp->v, &t6, &t6); // v = 2(z1z_2)^3y1y2
|
||||
fp2_sqr(&t4, &t4); // t4 = y1^2z2^6
|
||||
fp2_sqr(&t5, &t5); // t5 = z1^6y_2^2
|
||||
fp2_add(&t4, &t4, &t5); // t4 = z1^6y_2^2 + y1^2z2^6
|
||||
fp2_add(&t5, &t2, &t3); // t5 = x1z2^2 +z_1^2x2
|
||||
fp2_add(&t6, &t3, &t3); // t6 = 2z_1^2x2
|
||||
fp2_sub(&t6, &t5, &t6); // t6 = lambda = x1z2^2 - z_1^2x2
|
||||
fp2_sqr(&t6, &t6); // t6 = lambda^2 = (x1z2^2 - z_1^2x2)^2
|
||||
fp2_mul(&t1, &AC->A, &t0); // t1 = A*(z1z2)^2
|
||||
fp2_add(&t1, &t5, &t1); // t1 = gamma =A*(z1z2)^2 + x1z2^2 +z_1^2x2
|
||||
fp2_mul(&t1, &t1, &t6); // t1 = gamma*lambda^2
|
||||
fp2_sub(&add_comp->u, &t4, &t1); // u = z1^6y_2^2 + y1^2z2^6 - gamma*lambda^2
|
||||
fp2_mul(&add_comp->w, &t6, &t0); // w = (z1z2)^2(lambda)^2
|
||||
}
|
||||
241
src/ec/ref/lvlx/isog_chains.c
Normal file
241
src/ec/ref/lvlx/isog_chains.c
Normal file
@@ -0,0 +1,241 @@
|
||||
#include "isog.h"
|
||||
#include <assert.h>
|
||||
|
||||
// since we use degree 4 isogeny steps, we need to handle the odd case with care
|
||||
static uint32_t
|
||||
ec_eval_even_strategy(ec_curve_t *curve,
|
||||
ec_point_t *points,
|
||||
unsigned len_points,
|
||||
const ec_point_t *kernel,
|
||||
const int isog_len)
|
||||
{
|
||||
ec_curve_normalize_A24(curve);
|
||||
ec_point_t A24;
|
||||
copy_point(&A24, &curve->A24);
|
||||
|
||||
int space = 1;
|
||||
for (int i = 1; i < isog_len; i *= 2)
|
||||
++space;
|
||||
|
||||
// Stack of remaining kernel points and their associated orders
|
||||
ec_point_t splits[space];
|
||||
uint16_t todo[space];
|
||||
splits[0] = *kernel;
|
||||
todo[0] = isog_len;
|
||||
|
||||
int current = 0; // Pointer to current top of stack
|
||||
|
||||
// Chain of 4-isogenies
|
||||
for (int j = 0; j < isog_len / 2; ++j) {
|
||||
assert(current >= 0);
|
||||
assert(todo[current] >= 1);
|
||||
// Get the next point of order 4
|
||||
while (todo[current] != 2) {
|
||||
assert(todo[current] >= 3);
|
||||
// A new split will be added
|
||||
++current;
|
||||
assert(current < space);
|
||||
// We set the seed of the new split to be computed and saved
|
||||
copy_point(&splits[current], &splits[current - 1]);
|
||||
// if we copied from the very first element, then we perform one additional doubling
|
||||
unsigned num_dbls = todo[current - 1] / 4 * 2 + todo[current - 1] % 2;
|
||||
todo[current] = todo[current - 1] - num_dbls;
|
||||
while (num_dbls--)
|
||||
xDBL_A24(&splits[current], &splits[current], &A24, false);
|
||||
}
|
||||
|
||||
if (j == 0) {
|
||||
assert(fp2_is_one(&A24.z));
|
||||
if (!ec_is_four_torsion(&splits[current], curve))
|
||||
return -1;
|
||||
|
||||
ec_point_t T;
|
||||
xDBL_A24(&T, &splits[current], &A24, false);
|
||||
if (fp2_is_zero(&T.x))
|
||||
return -1; // special isogenies not allowed
|
||||
} else {
|
||||
assert(todo[current] == 2);
|
||||
#ifndef NDEBUG
|
||||
if (fp2_is_zero(&splits[current].z))
|
||||
debug_print("splitting point z coordinate is unexpectedly zero");
|
||||
|
||||
ec_point_t test;
|
||||
xDBL_A24(&test, &splits[current], &A24, false);
|
||||
if (fp2_is_zero(&test.z))
|
||||
debug_print("z coordinate is unexpectedly zero before doubling");
|
||||
xDBL_A24(&test, &test, &A24, false);
|
||||
if (!fp2_is_zero(&test.z))
|
||||
debug_print("z coordinate is unexpectedly not zero after doubling");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Evaluate 4-isogeny
|
||||
ec_kps4_t kps4;
|
||||
xisog_4(&kps4, &A24, splits[current]);
|
||||
xeval_4(splits, splits, current, &kps4);
|
||||
for (int i = 0; i < current; ++i)
|
||||
todo[i] -= 2;
|
||||
xeval_4(points, points, len_points, &kps4);
|
||||
|
||||
--current;
|
||||
}
|
||||
assert(isog_len % 2 ? !current : current == -1);
|
||||
|
||||
// Final 2-isogeny
|
||||
if (isog_len % 2) {
|
||||
#ifndef NDEBUG
|
||||
if (fp2_is_zero(&splits[0].z))
|
||||
debug_print("splitting point z coordinate is unexpectedly zero");
|
||||
ec_point_t test;
|
||||
copy_point(&test, &splits[0]);
|
||||
xDBL_A24(&test, &test, &A24, false);
|
||||
if (!fp2_is_zero(&test.z))
|
||||
debug_print("z coordinate is unexpectedly not zero after doubling");
|
||||
#endif
|
||||
|
||||
// We need to check the order of this point in case there were no 4-isogenies
|
||||
if (isog_len == 1 && !ec_is_two_torsion(&splits[0], curve))
|
||||
return -1;
|
||||
if (fp2_is_zero(&splits[0].x)) {
|
||||
// special isogenies not allowed
|
||||
// this case can only happen if isog_len == 1; otherwise the
|
||||
// previous 4-isogenies we computed ensure that $T=(0:1)$ is put
|
||||
// as the kernel of the dual isogeny
|
||||
return -1;
|
||||
}
|
||||
|
||||
ec_kps2_t kps2;
|
||||
xisog_2(&kps2, &A24, splits[0]);
|
||||
xeval_2(points, points, len_points, &kps2);
|
||||
}
|
||||
|
||||
// Output curve in the form (A:C)
|
||||
A24_to_AC(curve, &A24);
|
||||
|
||||
curve->is_A24_computed_and_normalized = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ec_eval_even(ec_curve_t *image, ec_isog_even_t *phi, ec_point_t *points, unsigned len_points)
|
||||
{
|
||||
copy_curve(image, &phi->curve);
|
||||
return ec_eval_even_strategy(image, points, len_points, &phi->kernel, phi->length);
|
||||
}
|
||||
|
||||
// naive implementation
|
||||
uint32_t
|
||||
ec_eval_small_chain(ec_curve_t *curve,
|
||||
const ec_point_t *kernel,
|
||||
int len,
|
||||
ec_point_t *points,
|
||||
unsigned len_points,
|
||||
bool special) // do we allow special isogenies?
|
||||
{
|
||||
|
||||
ec_point_t A24;
|
||||
AC_to_A24(&A24, curve);
|
||||
|
||||
ec_kps2_t kps;
|
||||
ec_point_t small_K, big_K;
|
||||
copy_point(&big_K, kernel);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
copy_point(&small_K, &big_K);
|
||||
// small_K = big_K;
|
||||
for (int j = 0; j < len - i - 1; j++) {
|
||||
xDBL_A24(&small_K, &small_K, &A24, false);
|
||||
}
|
||||
// Check the order of the point before the first isogeny step
|
||||
if (i == 0 && !ec_is_two_torsion(&small_K, curve))
|
||||
return (uint32_t)-1;
|
||||
// Perform isogeny step
|
||||
if (fp2_is_zero(&small_K.x)) {
|
||||
if (special) {
|
||||
ec_point_t B24;
|
||||
xisog_2_singular(&kps, &B24, A24);
|
||||
xeval_2_singular(&big_K, &big_K, 1, &kps);
|
||||
xeval_2_singular(points, points, len_points, &kps);
|
||||
copy_point(&A24, &B24);
|
||||
} else {
|
||||
return (uint32_t)-1;
|
||||
}
|
||||
} else {
|
||||
xisog_2(&kps, &A24, small_K);
|
||||
xeval_2(&big_K, &big_K, 1, &kps);
|
||||
xeval_2(points, points, len_points, &kps);
|
||||
}
|
||||
}
|
||||
A24_to_AC(curve, &A24);
|
||||
|
||||
curve->is_A24_computed_and_normalized = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
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, &from->C);
|
||||
fp2_mul(&t1, &to->A, &to->C);
|
||||
|
||||
fp2_mul(&t2, &t1, &to->C); // toA*toC^2
|
||||
fp2_add(&t3, &t2, &t2);
|
||||
fp2_add(&t3, &t3, &t3);
|
||||
fp2_add(&t3, &t3, &t3);
|
||||
fp2_add(&t2, &t2, &t3); // 9*toA*toC^2
|
||||
fp2_sqr(&t3, &to->A);
|
||||
fp2_mul(&t3, &t3, &to->A); // toA^3
|
||||
fp2_add(&t3, &t3, &t3);
|
||||
fp2_sub(&isom->Nx, &t3, &t2); // 2*toA^3-9*toA*toC^2
|
||||
fp2_mul(&t2, &t0, &from->A); // fromA^2*fromC
|
||||
fp2_sqr(&t3, &from->C);
|
||||
fp2_mul(&t3, &t3, &from->C); // fromC^3
|
||||
fp2_add(&t4, &t3, &t3);
|
||||
fp2_add(&t3, &t4, &t3); // 3*fromC^3
|
||||
fp2_sub(&t3, &t3, &t2); // 3*fromC^3-fromA^2*fromC
|
||||
fp2_mul(&isom->Nx, &isom->Nx, &t3); // lambda_x = (2*toA^3-9*toA*toC^2)*(3*fromC^3-fromA^2*fromC)
|
||||
|
||||
fp2_mul(&t2, &t0, &from->C); // fromA*fromC^2
|
||||
fp2_add(&t3, &t2, &t2);
|
||||
fp2_add(&t3, &t3, &t3);
|
||||
fp2_add(&t3, &t3, &t3);
|
||||
fp2_add(&t2, &t2, &t3); // 9*fromA*fromC^2
|
||||
fp2_sqr(&t3, &from->A);
|
||||
fp2_mul(&t3, &t3, &from->A); // fromA^3
|
||||
fp2_add(&t3, &t3, &t3);
|
||||
fp2_sub(&isom->D, &t3, &t2); // 2*fromA^3-9*fromA*fromC^2
|
||||
fp2_mul(&t2, &t1, &to->A); // toA^2*toC
|
||||
fp2_sqr(&t3, &to->C);
|
||||
fp2_mul(&t3, &t3, &to->C); // toC^3
|
||||
fp2_add(&t4, &t3, &t3);
|
||||
fp2_add(&t3, &t4, &t3); // 3*toC^3
|
||||
fp2_sub(&t3, &t3, &t2); // 3*toC^3-toA^2*toC
|
||||
fp2_mul(&isom->D, &isom->D, &t3); // lambda_z = (2*fromA^3-9*fromA*fromC^2)*(3*toC^3-toA^2*toC)
|
||||
|
||||
// Mont -> SW -> SW -> Mont
|
||||
fp2_mul(&t0, &to->C, &from->A);
|
||||
fp2_mul(&t0, &t0, &isom->Nx); // lambda_x*toC*fromA
|
||||
fp2_mul(&t1, &from->C, &to->A);
|
||||
fp2_mul(&t1, &t1, &isom->D); // lambda_z*fromC*toA
|
||||
fp2_sub(&isom->Nz, &t0, &t1); // lambda_x*toC*fromA - lambda_z*fromC*toA
|
||||
fp2_mul(&t0, &from->C, &to->C);
|
||||
fp2_add(&t1, &t0, &t0);
|
||||
fp2_add(&t0, &t0, &t1); // 3*fromC*toC
|
||||
fp2_mul(&isom->D, &isom->D, &t0); // 3*lambda_z*fromC*toC
|
||||
fp2_mul(&isom->Nx, &isom->Nx, &t0); // 3*lambda_x*fromC*toC
|
||||
|
||||
return (fp2_is_zero(&isom->Nx) | fp2_is_zero(&isom->D));
|
||||
}
|
||||
|
||||
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_add(&P->x, &P->x, &tmp);
|
||||
fp2_mul(&P->z, &P->z, &isom->D);
|
||||
}
|
||||
143
src/ec/ref/lvlx/test/basis-gen-bench.c
Normal file
143
src/ec/ref/lvlx/test/basis-gen-bench.c
Normal file
@@ -0,0 +1,143 @@
|
||||
#include <bench.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <ec.h>
|
||||
|
||||
#define STRINGIFY2(x) #x
|
||||
#define STRINGIFY(x) STRINGIFY2(x)
|
||||
|
||||
/******************************
|
||||
Util functions
|
||||
******************************/
|
||||
|
||||
int
|
||||
cmp_u64(const void *v1, const void *v2)
|
||||
{
|
||||
uint64_t x1 = *(const uint64_t *)v1;
|
||||
uint64_t x2 = *(const uint64_t *)v2;
|
||||
if (x1 < x2) {
|
||||
return -1;
|
||||
} else if (x1 == x2) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bench_basis_generation(unsigned int n, int iterations)
|
||||
{
|
||||
int i, j;
|
||||
uint64_t cycles1, cycles2;
|
||||
uint64_t cycle_runs[20];
|
||||
|
||||
ec_basis_t basis;
|
||||
ec_curve_t curve;
|
||||
ec_curve_init(&curve);
|
||||
|
||||
// Set a supersingular elliptic curve
|
||||
// E : y^2 = x^3 + 6*x^2 + x
|
||||
fp2_set_small(&(curve.A), 6);
|
||||
fp2_set_one(&(curve.C));
|
||||
ec_curve_normalize_A24(&curve);
|
||||
|
||||
// Full even torsion generation without hints
|
||||
for (i = 0; i < 20; i++) {
|
||||
cycles1 = cpucycles();
|
||||
for (j = 0; j < iterations; j++) {
|
||||
(void)ec_curve_to_basis_2f_to_hint(&basis, &curve, n);
|
||||
}
|
||||
cycles2 = cpucycles();
|
||||
cycle_runs[i] = cycles2 - cycles1;
|
||||
}
|
||||
qsort(cycle_runs + 10, 10, sizeof cycle_runs[0], cmp_u64);
|
||||
printf(" 2^%d torsion generation takes .................................... %" PRIu64 " cycles\n",
|
||||
n,
|
||||
cycle_runs[4] / (iterations));
|
||||
}
|
||||
|
||||
void
|
||||
bench_basis_generation_from_hint(unsigned int n, int iterations)
|
||||
{
|
||||
int i, j;
|
||||
uint64_t cycles1, cycles2;
|
||||
uint64_t cycle_runs[20];
|
||||
|
||||
ec_basis_t basis;
|
||||
ec_curve_t curve;
|
||||
ec_curve_init(&curve);
|
||||
|
||||
// Set a supersingular elliptic curve
|
||||
// E : y^2 = x^3 + 6*x^2 + x
|
||||
fp2_set_small(&(curve.A), 6);
|
||||
fp2_set_one(&(curve.C));
|
||||
ec_curve_normalize_A24(&curve);
|
||||
|
||||
uint8_t hint = ec_curve_to_basis_2f_to_hint(&basis, &curve, n);
|
||||
|
||||
// Full even torsion generation without hints
|
||||
for (i = 0; i < 20; i++) {
|
||||
cycles1 = cpucycles();
|
||||
for (j = 0; j < iterations; j++) {
|
||||
ec_curve_to_basis_2f_from_hint(&basis, &curve, n, hint);
|
||||
}
|
||||
cycles2 = cpucycles();
|
||||
cycle_runs[i] = cycles2 - cycles1;
|
||||
}
|
||||
qsort(cycle_runs + 10, 10, sizeof cycle_runs[0], cmp_u64);
|
||||
printf(" 2^%d torsion generation takes .................................... %" PRIu64 " cycles\n",
|
||||
n,
|
||||
cycle_runs[4] / (iterations));
|
||||
}
|
||||
|
||||
void
|
||||
bench_basis(int iterations)
|
||||
{
|
||||
printf("\n-------------------------------------------------------------------------------------"
|
||||
"-------------------\n\n");
|
||||
printf("Benchmarking E[2^n] basis generation for " STRINGIFY(SQISIGN_VARIANT) ": \n\n");
|
||||
bench_basis_generation(TORSION_EVEN_POWER, iterations);
|
||||
bench_basis_generation(128, iterations);
|
||||
|
||||
printf("\nBenchmarking E[2^n] basis generation with hint for " STRINGIFY(SQISIGN_VARIANT) ": \n\n");
|
||||
bench_basis_generation_from_hint(TORSION_EVEN_POWER, iterations);
|
||||
bench_basis_generation_from_hint(128, iterations);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int iterations = 100 * SQISIGN_TEST_REPS;
|
||||
int help = 0;
|
||||
|
||||
#ifndef NDEBUG
|
||||
fprintf(stderr,
|
||||
"\x1b[31mIt looks like SQIsign was compiled with assertions enabled.\n"
|
||||
"This will severely impact performance measurements.\x1b[0m\n");
|
||||
#endif
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!help && strcmp(argv[i], "--help") == 0) {
|
||||
help = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sscanf(argv[i], "--iterations=%d", &iterations) == 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (help || iterations <= 0) {
|
||||
printf("Usage: %s [--iterations=<iterations>]\n", argv[0]);
|
||||
printf("Where <iterations> is the number of iterations used for benchmarking; if not "
|
||||
"present, uses the default: %d)\n",
|
||||
iterations);
|
||||
return 1;
|
||||
}
|
||||
|
||||
cpucycles_init();
|
||||
|
||||
bench_basis(iterations);
|
||||
return 0;
|
||||
}
|
||||
195
src/ec/ref/lvlx/test/basis-gen-test.c
Normal file
195
src/ec/ref/lvlx/test/basis-gen-test.c
Normal file
@@ -0,0 +1,195 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <ec.h>
|
||||
|
||||
/******************************
|
||||
Test functions
|
||||
******************************/
|
||||
|
||||
int
|
||||
inner_test_generated_basis(ec_basis_t *basis, ec_curve_t *curve, unsigned int n)
|
||||
{
|
||||
unsigned int i;
|
||||
int PASSED = 1;
|
||||
|
||||
ec_point_t P, Q;
|
||||
copy_point(&P, &basis->P);
|
||||
copy_point(&Q, &basis->Q);
|
||||
|
||||
// Double points to get point of order 2
|
||||
for (i = 0; i < n - 1; i++) {
|
||||
xDBL_A24(&P, &P, &curve->A24, curve->is_A24_computed_and_normalized);
|
||||
xDBL_A24(&Q, &Q, &curve->A24, curve->is_A24_computed_and_normalized);
|
||||
}
|
||||
if (ec_is_zero(&P)) {
|
||||
printf("Point P generated does not have full order\n");
|
||||
PASSED = 0;
|
||||
}
|
||||
if (ec_is_zero(&Q)) {
|
||||
printf("Point Q generated does not have full order\n");
|
||||
PASSED = 0;
|
||||
}
|
||||
if (ec_is_equal(&P, &Q)) {
|
||||
printf("Points P, Q are linearly dependent\n");
|
||||
PASSED = 0;
|
||||
}
|
||||
|
||||
if (!fp2_is_zero(&Q.x)) {
|
||||
printf("Points Q is not above the Montgomery point\n");
|
||||
PASSED = 0;
|
||||
}
|
||||
|
||||
// This should give the identity
|
||||
xDBL_A24(&P, &P, &curve->A24, curve->is_A24_computed_and_normalized);
|
||||
xDBL_A24(&Q, &Q, &curve->A24, curve->is_A24_computed_and_normalized);
|
||||
if (!ec_is_zero(&P)) {
|
||||
printf("Point P generated does not have order exactly 2^n\n");
|
||||
PASSED = 0;
|
||||
}
|
||||
if (!ec_is_zero(&Q)) {
|
||||
printf("Point Q generated does not have order exactly 2^n\n");
|
||||
PASSED = 0;
|
||||
}
|
||||
|
||||
if (PASSED == 0) {
|
||||
printf("Test failed with n = %u\n", n);
|
||||
}
|
||||
|
||||
return PASSED;
|
||||
}
|
||||
|
||||
int
|
||||
inner_test_hint_basis(ec_basis_t *basis, ec_basis_t *basis_hint)
|
||||
{
|
||||
int PASSED = 1;
|
||||
|
||||
if (!ec_is_equal(&basis->P, &basis_hint->P)) {
|
||||
printf("The points P do not match using the hint\n");
|
||||
PASSED = 0;
|
||||
}
|
||||
|
||||
if (!ec_is_equal(&basis->Q, &basis_hint->Q)) {
|
||||
printf("The points Q do not match using the hint\n");
|
||||
PASSED = 0;
|
||||
}
|
||||
|
||||
if (!ec_is_equal(&basis->PmQ, &basis_hint->PmQ)) {
|
||||
printf("The points PmQ do not match using the hint\n");
|
||||
PASSED = 0;
|
||||
}
|
||||
|
||||
if (PASSED == 0) {
|
||||
printf("Test failed\n");
|
||||
}
|
||||
|
||||
return PASSED;
|
||||
}
|
||||
|
||||
/******************************
|
||||
Test wrapper functions
|
||||
******************************/
|
||||
|
||||
int
|
||||
test_basis_generation_E0(unsigned int n)
|
||||
{
|
||||
ec_basis_t basis;
|
||||
ec_curve_t curve;
|
||||
|
||||
ec_curve_init(&curve);
|
||||
|
||||
// Set a supersingular elliptic curve
|
||||
// E : y^2 = x^3 + 6*x^2 + x
|
||||
fp2_set_small(&(curve.A), 0);
|
||||
fp2_set_one(&(curve.C));
|
||||
ec_curve_normalize_A24(&curve);
|
||||
|
||||
// Generate a basis
|
||||
(void)ec_curve_to_basis_2f_to_hint(&basis, &curve, n);
|
||||
|
||||
// Test result
|
||||
return inner_test_generated_basis(&basis, &curve, n);
|
||||
}
|
||||
|
||||
int
|
||||
test_basis_generation(unsigned int n)
|
||||
{
|
||||
ec_basis_t basis;
|
||||
ec_curve_t curve;
|
||||
|
||||
ec_curve_init(&curve);
|
||||
|
||||
// Set a supersingular elliptic curve
|
||||
// E : y^2 = x^3 + 6*x^2 + x
|
||||
fp2_set_small(&(curve.A), 6);
|
||||
fp2_set_one(&(curve.C));
|
||||
ec_curve_normalize_A24(&curve);
|
||||
|
||||
// Generate a basis
|
||||
(void)ec_curve_to_basis_2f_to_hint(&basis, &curve, n);
|
||||
|
||||
// Test result
|
||||
return inner_test_generated_basis(&basis, &curve, n);
|
||||
}
|
||||
|
||||
int
|
||||
test_basis_generation_with_hints(unsigned int n)
|
||||
{
|
||||
int check_1, check_2;
|
||||
ec_basis_t basis, basis_hint;
|
||||
ec_curve_t curve;
|
||||
ec_curve_init(&curve);
|
||||
|
||||
// Set a supersingular elliptic curve
|
||||
// E : y^2 = x^3 + 6*x^2 + x
|
||||
fp2_set_small(&(curve.A), 6);
|
||||
fp2_set_one(&(curve.C));
|
||||
ec_curve_normalize_A24(&curve);
|
||||
|
||||
// Generate a basis with hints
|
||||
uint8_t hint = ec_curve_to_basis_2f_to_hint(&basis, &curve, n);
|
||||
|
||||
// Ensure the basis from the hint is good
|
||||
check_1 = inner_test_generated_basis(&basis, &curve, n);
|
||||
|
||||
// Generate a basis using hints
|
||||
ec_curve_to_basis_2f_from_hint(&basis_hint, &curve, n, hint);
|
||||
|
||||
// These two bases should be the same
|
||||
check_2 = inner_test_hint_basis(&basis, &basis_hint);
|
||||
|
||||
return check_1 && check_2;
|
||||
}
|
||||
|
||||
int
|
||||
test_basis(void)
|
||||
{
|
||||
int passed;
|
||||
|
||||
// Test full order
|
||||
passed = test_basis_generation(TORSION_EVEN_POWER);
|
||||
passed &= test_basis_generation_with_hints(TORSION_EVEN_POWER);
|
||||
|
||||
// Test partial order
|
||||
passed &= test_basis_generation(128);
|
||||
passed &= test_basis_generation_with_hints(128);
|
||||
|
||||
// Special case when we have A = 0
|
||||
passed &= test_basis_generation_E0(TORSION_EVEN_POWER);
|
||||
passed &= test_basis_generation_E0(128);
|
||||
|
||||
return passed;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
bool ok;
|
||||
ok = test_basis();
|
||||
if (!ok) {
|
||||
printf("Tests failed!\n");
|
||||
} else {
|
||||
printf("All basis generation tests passed.\n");
|
||||
}
|
||||
return !ok;
|
||||
}
|
||||
113
src/ec/ref/lvlx/test/biextension-bench.c
Normal file
113
src/ec/ref/lvlx/test/biextension-bench.c
Normal file
@@ -0,0 +1,113 @@
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <tools.h>
|
||||
#include <mp.h>
|
||||
#include "biextension.h"
|
||||
#include <rng.h>
|
||||
#include "bench.h"
|
||||
|
||||
#define STRINGIFY2(x) #x
|
||||
#define STRINGIFY(x) STRINGIFY2(x)
|
||||
|
||||
void
|
||||
biextension_bench(uint64_t bench)
|
||||
{
|
||||
uint64_t t0, t1;
|
||||
uint32_t e = TORSION_EVEN_POWER;
|
||||
|
||||
fp2_t r1;
|
||||
ec_curve_t curve;
|
||||
ec_point_t tmp;
|
||||
|
||||
digit_t scal_r1[NWORDS_ORDER];
|
||||
digit_t scal_r2[NWORDS_ORDER];
|
||||
digit_t scal_s1[NWORDS_ORDER];
|
||||
digit_t scal_s2[NWORDS_ORDER];
|
||||
|
||||
ec_basis_t BPQ, BRS;
|
||||
|
||||
// Get constants form curve E6 : y^2 = x^3 + 6*x^2 + x
|
||||
ec_curve_init(&curve);
|
||||
fp2_set_small(&(curve.A), 6);
|
||||
fp2_set_one(&(curve.C));
|
||||
ec_curve_normalize_A24(&curve);
|
||||
|
||||
// Compute 2^e torsion on curve and copy to a second basis
|
||||
(void)ec_curve_to_basis_2f_to_hint(&BPQ, &curve, e);
|
||||
copy_basis(&BRS, &BPQ);
|
||||
|
||||
// Benchmark doubling on the curve
|
||||
printf("\n\nBenchmarking doublings\n");
|
||||
t0 = cpucycles();
|
||||
for (uint64_t i = 0; i < bench; ++i) {
|
||||
ec_dbl_iter(&tmp, e, &BPQ.P, &curve);
|
||||
}
|
||||
t1 = cpucycles();
|
||||
printf("\x1b[34mAvg doubling: %'" PRIu64 " cycles\x1b[0m\n", (t1 - t0) / bench);
|
||||
|
||||
printf("\n\nBenchmarking (Weil) pairings\n");
|
||||
t0 = cpucycles();
|
||||
for (uint64_t i = 0; i < bench; ++i) {
|
||||
weil(&r1, e, &BPQ.P, &BPQ.Q, &BPQ.PmQ, &curve);
|
||||
}
|
||||
t1 = cpucycles();
|
||||
printf("\x1b[34mAvg pairing: %'" PRIu64 " cycles\x1b[0m\n", (t1 - t0) / bench);
|
||||
|
||||
printf("\n\nBenchmarking (Weil) dlogs\n");
|
||||
t0 = cpucycles();
|
||||
for (uint64_t i = 0; i < bench; ++i) {
|
||||
ec_dlog_2_weil(scal_r1, scal_r2, scal_s1, scal_s2, &BPQ, &BRS, &curve, e);
|
||||
}
|
||||
t1 = cpucycles();
|
||||
printf("\x1b[34mAvg pairing dlog: %'" PRIu64 " cycles\x1b[0m\n", (t1 - t0) / bench);
|
||||
|
||||
printf("\n\nBenchmarking (Tate) dlogs\n");
|
||||
t0 = cpucycles();
|
||||
for (uint64_t i = 0; i < bench; ++i) {
|
||||
ec_dlog_2_tate(scal_r1, scal_r2, scal_s1, scal_s2, &BPQ, &BRS, &curve, e);
|
||||
}
|
||||
t1 = cpucycles();
|
||||
printf("\x1b[34mAvg Tate dlog: %'" PRIu64 " cycles\x1b[0m\n", (t1 - t0) / bench);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int iterations = 1000 * SQISIGN_TEST_REPS;
|
||||
int help = 0;
|
||||
|
||||
#ifndef NDEBUG
|
||||
fprintf(stderr,
|
||||
"\x1b[31mIt looks like SQIsign was compiled with assertions enabled.\n"
|
||||
"This will severely impact performance measurements.\x1b[0m\n");
|
||||
#endif
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!help && strcmp(argv[i], "--help") == 0) {
|
||||
help = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sscanf(argv[i], "--iterations=%d", &iterations) == 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (help || iterations <= 0) {
|
||||
printf("Usage: %s [--iterations=<iterations>]\n", argv[0]);
|
||||
printf("Where <iterations> is the number of iterations used for benchmarking; if not "
|
||||
"present, uses the default: %d)\n",
|
||||
iterations);
|
||||
return 1;
|
||||
}
|
||||
|
||||
cpucycles_init();
|
||||
|
||||
printf("Running biextension benchmarks for " STRINGIFY(SQISIGN_VARIANT) ":\n\n");
|
||||
|
||||
biextension_bench(iterations);
|
||||
|
||||
return 0;
|
||||
}
|
||||
259
src/ec/ref/lvlx/test/biextension-test.c
Normal file
259
src/ec/ref/lvlx/test/biextension-test.c
Normal file
@@ -0,0 +1,259 @@
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <tools.h>
|
||||
#include <mp.h>
|
||||
#include "biextension.h"
|
||||
#include <rng.h>
|
||||
#include <bench_test_arguments.h>
|
||||
|
||||
void
|
||||
fp2_exp_2e(fp2_t *r, uint32_t e, const fp2_t *x)
|
||||
{
|
||||
fp2_copy(r, x);
|
||||
for (uint32_t i = 0; i < e; i++) {
|
||||
fp2_sqr(r, r);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
biextension_test()
|
||||
{
|
||||
clock_t t;
|
||||
ec_curve_t curve;
|
||||
ec_basis_t even_torsion;
|
||||
uint32_t e = TORSION_EVEN_POWER;
|
||||
fp2_t one, r1, rr1, rrr1, r2, r3, tp;
|
||||
ec_point_t P, Q, PmQ, A24;
|
||||
ec_point_t tmp, tmp2, PQ, PP, QQ, PPQ, PQQ, PPP, QQQ, PPPQ, PQQQ;
|
||||
|
||||
// Get constants form curve E6 : y^2 = x^3 + 6*x^2 + x
|
||||
ec_curve_init(&curve);
|
||||
fp2_set_small(&(curve.A), 6);
|
||||
fp2_set_one(&(curve.C));
|
||||
ec_curve_normalize_A24(&curve);
|
||||
copy_point(&A24, &curve.A24);
|
||||
|
||||
// Compute 2^e torsion on curve
|
||||
(void)ec_curve_to_basis_2f_to_hint(&even_torsion, &curve, e);
|
||||
copy_point(&P, &even_torsion.P);
|
||||
copy_point(&Q, &even_torsion.Q);
|
||||
copy_point(&PmQ, &even_torsion.PmQ);
|
||||
|
||||
printf("Testing order of points\n");
|
||||
t = tic();
|
||||
ec_dbl_iter(&tmp, e, &P, &curve);
|
||||
TOC_clock(t, "Doublings");
|
||||
assert(ec_is_zero(&tmp));
|
||||
ec_dbl_iter(&tmp, e, &Q, &curve);
|
||||
assert(ec_is_zero(&tmp));
|
||||
ec_dbl_iter(&tmp, e, &PmQ, &curve);
|
||||
assert(ec_is_zero(&tmp));
|
||||
|
||||
printf("Computing Weil pairing\n");
|
||||
xADD(&PQ, &P, &Q, &PmQ);
|
||||
t = tic();
|
||||
|
||||
weil(&r1, e, &P, &Q, &PQ, &curve);
|
||||
TOC_clock(t, "Weil pairing");
|
||||
|
||||
printf("Computing Tate pairing\n");
|
||||
t = tic();
|
||||
|
||||
reduced_tate(&tp, e, &P, &Q, &PQ, &curve);
|
||||
TOC_clock(t, "Tate pairing");
|
||||
|
||||
printf("Testing order of Weil pairing\n");
|
||||
fp2_set_one(&one);
|
||||
fp2_exp_2e(&r2, e - 1, &r1);
|
||||
assert(!fp2_is_equal(&r2, &one));
|
||||
fp2_exp_2e(&r2, e, &r1);
|
||||
assert(fp2_is_equal(&r2, &one));
|
||||
|
||||
printf("Testing order of Tate pairing\n");
|
||||
fp2_set_one(&one);
|
||||
fp2_exp_2e(&r2, e - 1, &tp);
|
||||
assert(!fp2_is_equal(&r2, &one));
|
||||
fp2_exp_2e(&r2, e, &tp);
|
||||
assert(fp2_is_equal(&r2, &one));
|
||||
|
||||
printf("Bilinearity tests\n");
|
||||
weil(&r2, e, &P, &Q, &PmQ, &curve);
|
||||
fp2_inv(&r2);
|
||||
assert(fp2_is_equal(&r1, &r2));
|
||||
|
||||
xDBL_A24(&PP, &P, &A24, false);
|
||||
xDBL_A24(&QQ, &Q, &A24, false);
|
||||
xADD(&PPQ, &PQ, &P, &Q);
|
||||
xADD(&PQQ, &PQ, &Q, &P);
|
||||
|
||||
weil(&r2, e, &PP, &Q, &PPQ, &curve);
|
||||
weil(&r3, e, &P, &QQ, &PQQ, &curve);
|
||||
assert(fp2_is_equal(&r2, &r3));
|
||||
fp2_sqr(&rr1, &r1);
|
||||
assert(fp2_is_equal(&rr1, &r2));
|
||||
|
||||
xADD(&PPP, &PP, &P, &P);
|
||||
xADD(&QQQ, &QQ, &Q, &Q);
|
||||
xADD(&PPPQ, &PPQ, &P, &PQ);
|
||||
xADD(&PQQQ, &PQQ, &Q, &PQ);
|
||||
weil(&r2, e, &PPP, &Q, &PPPQ, &curve);
|
||||
weil(&r3, e, &P, &QQQ, &PQQQ, &curve);
|
||||
assert(fp2_is_equal(&r2, &r3));
|
||||
fp2_mul(&rrr1, &rr1, &r1);
|
||||
assert(fp2_is_equal(&rrr1, &r2));
|
||||
|
||||
printf("dlog tests\n");
|
||||
ec_basis_t BPQ, BRS;
|
||||
digit_t scal_r1[NWORDS_ORDER] = { 0 };
|
||||
digit_t scal_r2[NWORDS_ORDER] = { 0 };
|
||||
digit_t scal_s1[NWORDS_ORDER] = { 0 };
|
||||
digit_t scal_s2[NWORDS_ORDER] = { 0 };
|
||||
digit_t scal_d1[NWORDS_ORDER] = { 0 };
|
||||
digit_t scal_d2[NWORDS_ORDER] = { 0 };
|
||||
|
||||
// original even torsion
|
||||
BPQ = even_torsion;
|
||||
BRS = even_torsion;
|
||||
|
||||
// alternative torsion, just mix the points up a little...
|
||||
// not filling top word so the addition below can overflow into it
|
||||
// so the scalars are "random enough" but we still keep the difference
|
||||
// scal_d1 and scal_d2 required to compute the right multiple of RmS
|
||||
randombytes((unsigned char *)scal_d1, (NWORDS_ORDER - 1) * sizeof(digit_t));
|
||||
randombytes((unsigned char *)scal_d2, (NWORDS_ORDER - 1) * sizeof(digit_t));
|
||||
randombytes((unsigned char *)scal_s1, (NWORDS_ORDER - 1) * sizeof(digit_t));
|
||||
randombytes((unsigned char *)scal_s2, (NWORDS_ORDER - 1) * sizeof(digit_t));
|
||||
|
||||
// Ensure that r1*s2 - r2*s1 is odd such that the matrix
|
||||
// [[r1, r2], [s1, s2]] is invertible
|
||||
scal_s1[0] = (scal_s1[0] & ((digit_t)(-1) - 1)) + 1; // s1 needs to be odd
|
||||
scal_d1[0] = (scal_d1[0] & ((digit_t)(-1) - 1)); // d1 needs to be even to make r1 odd
|
||||
scal_s2[0] = (scal_s2[0] & ((digit_t)(-1) - 1)) + 1; // s2 needs to be odd
|
||||
scal_d2[0] = (scal_d2[0] & ((digit_t)(-1) - 1)) + 1; // d2 needs to be odd to make r2 even
|
||||
|
||||
// Compute r1 and r2 from the difference di = ri - si
|
||||
mp_add(scal_r1, scal_d1, scal_s1, NWORDS_ORDER);
|
||||
mp_add(scal_r2, scal_d2, scal_s2, NWORDS_ORDER);
|
||||
|
||||
ec_biscalar_mul(&BRS.P, scal_r1, scal_r2, e, &BPQ, &curve);
|
||||
ec_biscalar_mul(&BRS.Q, scal_s1, scal_s2, e, &BPQ, &curve);
|
||||
ec_biscalar_mul(&BRS.PmQ, scal_d1, scal_d2, e, &BPQ, &curve);
|
||||
|
||||
printf("mixed\n");
|
||||
|
||||
// Now solve the discrete log
|
||||
ec_dlog_2_weil(scal_r1, scal_r2, scal_s1, scal_s2, &BPQ, &BRS, &curve, e);
|
||||
|
||||
// assert everything matches
|
||||
// R = [r1]P + [r2]Q
|
||||
ec_biscalar_mul(&tmp, scal_r1, scal_r2, e, &BPQ, &curve);
|
||||
assert(ec_is_equal(&tmp, &BRS.P));
|
||||
|
||||
// S = [s1]P + [s2]Q
|
||||
ec_biscalar_mul(&tmp, scal_s1, scal_s2, e, &BPQ, &curve);
|
||||
assert(ec_is_equal(&tmp, &BRS.Q));
|
||||
|
||||
printf("weil solved\n");
|
||||
|
||||
// now repeat using the tate pairing
|
||||
ec_dlog_2_tate(scal_r1, scal_r2, scal_s1, scal_s2, &BPQ, &BRS, &curve, e);
|
||||
|
||||
// assert everything matches
|
||||
// R = [r1]P + [r2]Q
|
||||
ec_biscalar_mul(&tmp, scal_r1, scal_r2, e, &BPQ, &curve);
|
||||
assert(ec_is_equal(&tmp, &BRS.P));
|
||||
|
||||
// S = [s1]P + [s2]Q
|
||||
ec_biscalar_mul(&tmp, scal_s1, scal_s2, e, &BPQ, &curve);
|
||||
assert(ec_is_equal(&tmp, &BRS.Q));
|
||||
|
||||
printf("tate solved\n");
|
||||
|
||||
// now we try with bases for partial torsion E[2^e] with e < e_full
|
||||
int e_full = TORSION_EVEN_POWER;
|
||||
int e_partial = 126;
|
||||
|
||||
ec_dbl_iter(&BRS.P, e_full - e_partial, &BRS.P, &curve);
|
||||
ec_dbl_iter(&BRS.Q, e_full - e_partial, &BRS.Q, &curve);
|
||||
ec_dbl_iter(&BRS.PmQ, e_full - e_partial, &BRS.PmQ, &curve);
|
||||
|
||||
ec_dlog_2_tate(scal_r1, scal_r2, scal_s1, scal_s2, &BPQ, &BRS, &curve, e_partial);
|
||||
|
||||
ec_biscalar_mul(&tmp, scal_r1, scal_r2, e, &BPQ, &curve);
|
||||
ec_dbl_iter(&tmp, e_full - e_partial, &tmp, &curve);
|
||||
assert(ec_is_equal(&tmp, &BRS.P));
|
||||
|
||||
// S = [s1]P + [s2]Q
|
||||
// then S = [2^e_diff] S
|
||||
ec_biscalar_mul(&tmp, scal_s1, scal_s2, e, &BPQ, &curve);
|
||||
ec_dbl_iter(&tmp, e_full - e_partial, &tmp, &curve);
|
||||
assert(ec_is_equal(&tmp, &BRS.Q));
|
||||
|
||||
printf("tate from full basis solved\n");
|
||||
|
||||
ec_dlog_2_tate(scal_r1, scal_r2, scal_s1, scal_s2, &BPQ, &BRS, &curve, e_partial);
|
||||
mp_invert_matrix(scal_r1, scal_r2, scal_s1, scal_s2, e_partial, NWORDS_ORDER);
|
||||
|
||||
// assert everything matches
|
||||
ec_biscalar_mul(&tmp, scal_r1, scal_r2, e, &BRS, &curve);
|
||||
ec_dbl_iter(&tmp2, e_full - e_partial, &BPQ.P, &curve);
|
||||
assert(ec_is_equal(&tmp, &tmp2));
|
||||
|
||||
ec_biscalar_mul(&tmp, scal_s1, scal_s2, e, &BRS, &curve);
|
||||
ec_dbl_iter(&tmp2, e_full - e_partial, &BPQ.Q, &curve);
|
||||
assert(ec_is_equal(&tmp, &tmp2));
|
||||
|
||||
printf("tate to full basis solved\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
uint32_t seed[12] = { 0 };
|
||||
int help = 0;
|
||||
int seed_set = 0;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!help && strcmp(argv[i], "--help") == 0) {
|
||||
help = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!seed_set && !parse_seed(argv[i], seed)) {
|
||||
seed_set = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (help) {
|
||||
printf("Usage: %s [--seed=<seed>]\n", argv[0]);
|
||||
printf("Where <seed> is the random seed to be used; if not present, a random seed is "
|
||||
"generated\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!seed_set) {
|
||||
randombytes_select((unsigned char *)seed, sizeof(seed));
|
||||
}
|
||||
|
||||
print_seed(seed);
|
||||
|
||||
#if defined(TARGET_BIG_ENDIAN)
|
||||
for (int i = 0; i < 12; i++) {
|
||||
seed[i] = BSWAP32(seed[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
randombytes_init((unsigned char *)seed, NULL, 256);
|
||||
|
||||
printf("Running biextension unit tests\n");
|
||||
|
||||
biextension_test();
|
||||
|
||||
// Failures will be caught by asserts in biextension_test
|
||||
printf("\nAll tests passed!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
163
src/ec/ref/lvlx/test/curve-arith-bench.c
Normal file
163
src/ec/ref/lvlx/test/curve-arith-bench.c
Normal file
@@ -0,0 +1,163 @@
|
||||
#include <bench.h>
|
||||
#include <bench_test_arguments.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "test_extras.h"
|
||||
#include <ec.h>
|
||||
#include <isog.h>
|
||||
#include <rng.h>
|
||||
|
||||
#define STRINGIFY2(x) #x
|
||||
#define STRINGIFY(x) STRINGIFY2(x)
|
||||
|
||||
uint64_t
|
||||
bench_xDBL(unsigned int Nbench)
|
||||
{
|
||||
uint64_t cycles0, cycles1;
|
||||
unsigned int i;
|
||||
ec_point_t P[Nbench], A24[Nbench];
|
||||
for (i = 0; i < Nbench; i++) {
|
||||
fp2_random_test(&(P[i].x));
|
||||
fp2_random_test(&(P[i].z));
|
||||
fp2_random_test(&(A24[i].x));
|
||||
fp2_random_test(&(A24[i].z));
|
||||
}
|
||||
cycles0 = cpucycles();
|
||||
for (i = 0; i < Nbench; i++) {
|
||||
xDBL(&P[i], &P[i], &A24[i]);
|
||||
}
|
||||
cycles1 = cpucycles();
|
||||
return cycles1 - cycles0;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
bench_xEVAL4(unsigned int Nbench)
|
||||
{
|
||||
uint64_t cycles0, cycles1;
|
||||
unsigned int i;
|
||||
ec_point_t P[Nbench];
|
||||
ec_kps4_t KPS[Nbench];
|
||||
for (i = 0; i < Nbench; i++) {
|
||||
fp2_random_test(&(P[i].x));
|
||||
fp2_random_test(&(P[i].z));
|
||||
for (int j = 0; j < 3; j++) {
|
||||
fp2_random_test(&(KPS[i].K[j].x));
|
||||
fp2_random_test(&(KPS[i].K[j].z));
|
||||
}
|
||||
}
|
||||
cycles0 = cpucycles();
|
||||
for (i = 0; i < Nbench; i++) {
|
||||
xeval_4(&P[i], &P[i], 1, &KPS[i]);
|
||||
}
|
||||
cycles1 = cpucycles();
|
||||
return cycles1 - cycles0;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
bench_isog_strategy(unsigned int Nbench)
|
||||
{
|
||||
uint64_t cycles0, cycles1;
|
||||
unsigned int i;
|
||||
ec_curve_t E0;
|
||||
ec_isog_even_t phi[Nbench];
|
||||
ec_basis_t basis2;
|
||||
ec_curve_init(&E0);
|
||||
fp2_set_small(&(E0.A), 6);
|
||||
fp2_set_one(&(E0.C));
|
||||
(void)ec_curve_to_basis_2f_to_hint(&basis2, &E0, TORSION_EVEN_POWER);
|
||||
for (i = 0; i < Nbench; i++) {
|
||||
copy_curve(&phi[i].curve, &E0);
|
||||
phi[i].length = TORSION_EVEN_POWER;
|
||||
if (i == 0) {
|
||||
xADD(&phi[i].kernel, &basis2.P, &basis2.Q, &basis2.PmQ);
|
||||
}
|
||||
if (i == 1) {
|
||||
xADD(&phi[i].kernel, &phi[i - 1].kernel, &basis2.Q, &basis2.P);
|
||||
}
|
||||
if (i > 1) {
|
||||
xADD(&phi[i].kernel, &phi[i - 1].kernel, &basis2.Q, &phi[i - 2].kernel);
|
||||
}
|
||||
}
|
||||
cycles0 = cpucycles();
|
||||
for (i = 2; i < Nbench; i++) {
|
||||
if (ec_eval_even(&phi[i].curve, &phi[i], NULL, 0)) {
|
||||
printf("Failed isogeny strategy\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
cycles1 = cpucycles();
|
||||
return cycles1 - cycles0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
uint32_t seed[12] = { 0 };
|
||||
int iterations = 100 * SQISIGN_TEST_REPS;
|
||||
int help = 0;
|
||||
int seed_set = 0;
|
||||
|
||||
#ifndef NDEBUG
|
||||
fprintf(stderr,
|
||||
"\x1b[31mIt looks like SQIsign was compiled with assertions enabled.\n"
|
||||
"This will severely impact performance measurements.\x1b[0m\n");
|
||||
#endif
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!help && strcmp(argv[i], "--help") == 0) {
|
||||
help = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!seed_set && !parse_seed(argv[i], seed)) {
|
||||
seed_set = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sscanf(argv[i], "--iterations=%d", &iterations) == 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (help || iterations <= 0) {
|
||||
printf("Usage: %s [--iterations=<iterations>] [--seed=<seed>]\n", argv[0]);
|
||||
printf("Where <iterations> is the number of iterations used for benchmarking; if not "
|
||||
"present, uses the default: %d)\n",
|
||||
iterations);
|
||||
printf("Where <seed> is the random seed to be used; if not present, a random seed is "
|
||||
"generated\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!seed_set) {
|
||||
randombytes_select((unsigned char *)seed, sizeof(seed));
|
||||
}
|
||||
|
||||
print_seed(seed);
|
||||
|
||||
#if defined(TARGET_BIG_ENDIAN)
|
||||
for (int i = 0; i < 12; i++) {
|
||||
seed[i] = BSWAP32(seed[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
randombytes_init((unsigned char *)seed, NULL, 256);
|
||||
cpucycles_init();
|
||||
|
||||
printf("Benchmarking elliptic curve arithmetic for " STRINGIFY(SQISIGN_VARIANT) ":\n\n");
|
||||
|
||||
uint64_t cycles;
|
||||
|
||||
cycles = bench_xDBL(10 * iterations);
|
||||
printf("Bench xDBL_A24:\t%" PRIu64 " cycles\n", cycles / (10 * iterations));
|
||||
|
||||
cycles = bench_xEVAL4(iterations);
|
||||
printf("Bench xEVAL4:\t%" PRIu64 " cycles\n", cycles / iterations);
|
||||
|
||||
cycles = bench_isog_strategy(iterations);
|
||||
printf("Bench isog strategy:\t%" PRIu64 " cycles\n", cycles / iterations);
|
||||
|
||||
return 0;
|
||||
}
|
||||
404
src/ec/ref/lvlx/test/curve-arith-test.c
Normal file
404
src/ec/ref/lvlx/test/curve-arith-test.c
Normal file
@@ -0,0 +1,404 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "test_extras.h"
|
||||
#include <ec.h>
|
||||
#include <isog.h>
|
||||
#include <rng.h>
|
||||
#include <bench_test_arguments.h>
|
||||
|
||||
/******************************
|
||||
Test functions
|
||||
******************************/
|
||||
|
||||
int
|
||||
test_xDBL_xADD(const ec_curve_t *curve, unsigned int Ntest)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
ec_point_t P, Q, PQ, R1, R2;
|
||||
|
||||
for (i = 0; i < Ntest; i++) {
|
||||
ec_random_test(&P, curve);
|
||||
ec_random_test(&Q, curve);
|
||||
projective_difference_point(&PQ, &P, &Q, curve);
|
||||
|
||||
// 2(P + Q) = 2P + 2Q
|
||||
xADD(&R1, &P, &Q, &PQ);
|
||||
ec_dbl(&R1, &R1, curve);
|
||||
ec_dbl(&P, &P, curve);
|
||||
ec_dbl(&Q, &Q, curve);
|
||||
ec_dbl(&PQ, &PQ, curve);
|
||||
xADD(&R2, &P, &Q, &PQ);
|
||||
if (!ec_is_equal(&R1, &R2)) {
|
||||
printf("Failed 2(P + Q) = 2P + 2Q\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// (P+Q) + (P-Q) = 2P
|
||||
xADD(&R1, &P, &Q, &PQ);
|
||||
ec_dbl(&Q, &Q, curve);
|
||||
xADD(&R1, &R1, &PQ, &Q);
|
||||
ec_dbl(&P, &P, curve);
|
||||
ec_dbl(&PQ, &PQ, curve);
|
||||
if (!ec_is_equal(&R1, &P)) {
|
||||
printf("Failed (P+Q) + (P-Q) = 2P\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
test_xDBLADD(const ec_curve_t *curve, unsigned int Ntest)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
ec_point_t P, Q, PQ, R1, R2;
|
||||
|
||||
ec_point_t A24;
|
||||
AC_to_A24(&A24, curve);
|
||||
|
||||
for (i = 0; i < Ntest; i++) {
|
||||
ec_random_test(&P, curve);
|
||||
ec_random_test(&Q, curve);
|
||||
projective_difference_point(&PQ, &P, &Q, curve);
|
||||
|
||||
xDBLADD(&R1, &R2, &P, &Q, &PQ, &A24, false);
|
||||
xADD(&PQ, &P, &Q, &PQ);
|
||||
if (!ec_is_equal(&R2, &PQ)) {
|
||||
printf("Failed addition in xDBLADD\n");
|
||||
return 1;
|
||||
}
|
||||
ec_dbl(&P, &P, curve);
|
||||
if (!ec_is_equal(&R1, &P)) {
|
||||
printf("Failed doubling in xDBLADD\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
test_xDBL_variants(ec_curve_t *curve, unsigned int Ntest)
|
||||
{
|
||||
unsigned int i;
|
||||
ec_curve_t E;
|
||||
ec_point_t P, R1, R2, R3, R4;
|
||||
ec_point_t A24, A24norm;
|
||||
fp2_t z;
|
||||
|
||||
AC_to_A24(&A24, curve);
|
||||
copy_point(&A24norm, &A24);
|
||||
ec_normalize_point(&A24norm);
|
||||
|
||||
// Randomize projective representation
|
||||
copy_curve(&E, curve);
|
||||
fp2_random_test(&z);
|
||||
fp2_mul(&(E.A24.x), &(A24.x), &z);
|
||||
fp2_mul(&(E.A24.z), &(A24.z), &z);
|
||||
E.is_A24_computed_and_normalized = false;
|
||||
|
||||
for (i = 0; i < Ntest; i++) {
|
||||
ec_random_test(&P, curve);
|
||||
xDBL(&R1, &P, (const ec_point_t *)curve);
|
||||
xDBL_A24(&R2, &P, &(E.A24), false);
|
||||
xDBL_A24(&R3, &P, &A24norm, true);
|
||||
xDBL_E0(&R4, &P);
|
||||
if (!ec_is_equal(&R1, &R2)) {
|
||||
printf("xDBL and xDBL_A24 dont match\n");
|
||||
return 1;
|
||||
}
|
||||
if (!ec_is_equal(&R1, &R3)) {
|
||||
printf("xDBL and xDBL_A24 normalized dont match\n");
|
||||
return 1;
|
||||
}
|
||||
if (!ec_is_equal(&R1, &R4)) {
|
||||
printf("xDBL and xDBL_E0 dont match\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
test_zero_identities(ec_curve_t *curve, unsigned int Ntest)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
ec_point_t P, Q, R, ec_zero;
|
||||
|
||||
fp2_set_one(&(P.x));
|
||||
fp2_set_zero(&(P.z));
|
||||
|
||||
fp2_set_one(&(ec_zero.x));
|
||||
fp2_set_zero(&(ec_zero.z));
|
||||
|
||||
assert(ec_is_zero(&P));
|
||||
|
||||
for (i = 0; i < Ntest; i++) {
|
||||
ec_random_test(&P, curve);
|
||||
|
||||
xADD(&R, &ec_zero, &ec_zero, &ec_zero);
|
||||
if (!ec_is_zero(&R)) {
|
||||
printf("Failed 0 + 0 = 0\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ec_dbl(&R, &P, curve);
|
||||
xADD(&R, &P, &P, &R);
|
||||
if (!ec_is_zero(&R)) {
|
||||
printf("Failed P - P = 0\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ec_dbl(&R, &ec_zero, curve);
|
||||
if (!ec_is_zero(&R)) {
|
||||
printf("Failed 2*0 = 0\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
xADD(&R, &P, &ec_zero, &P);
|
||||
if (!ec_is_equal(&R, &P)) {
|
||||
printf("Failed P + 0 = P\n");
|
||||
return 1;
|
||||
}
|
||||
xADD(&R, &ec_zero, &P, &P);
|
||||
if (!ec_is_equal(&R, &P)) {
|
||||
printf("Failed P + 0 = P\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
xDBLADD(&R, &Q, &P, &ec_zero, &P, &curve->A24, false);
|
||||
if (!ec_is_equal(&Q, &P)) {
|
||||
printf("Failed P + 0 = P in xDBLADD\n");
|
||||
return 1;
|
||||
}
|
||||
xDBLADD(&R, &Q, &ec_zero, &P, &P, &curve->A24, false);
|
||||
if (!ec_is_equal(&Q, &P)) {
|
||||
printf("Failed P + 0 = P in xDBLADD\n");
|
||||
return 1;
|
||||
}
|
||||
if (!ec_is_zero(&R)) {
|
||||
printf("Failed 2*0 = 0 in xDBLADD\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
test_jacobian(const ec_curve_t *curve, unsigned int Ntest)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
ec_point_t P, Q;
|
||||
jac_point_t R, S, T, U, jac_zero;
|
||||
fp2_t t0, t1;
|
||||
|
||||
jac_init(&jac_zero);
|
||||
|
||||
for (i = 0; i < Ntest; i++) {
|
||||
ec_random_test(&P, curve);
|
||||
ec_normalize_point(&P);
|
||||
ec_random_test(&Q, curve);
|
||||
ec_normalize_point(&Q);
|
||||
|
||||
/* Convert to Jacobian coordinates. */
|
||||
fp2_copy(&(S.x), &(P.x));
|
||||
ec_recover_y(&(S.y), &(S.x), curve);
|
||||
fp2_set_one(&(S.z));
|
||||
fp2_copy(&(T.x), &(Q.x));
|
||||
ec_recover_y(&(T.y), &(T.x), curve);
|
||||
fp2_set_one(&(T.z));
|
||||
|
||||
ADD(&R, &jac_zero, &jac_zero, curve);
|
||||
if (!jac_is_equal(&R, &jac_zero)) {
|
||||
printf("Failed 0 + 0 = 0 in jac\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
DBL(&R, &jac_zero, curve);
|
||||
if (!jac_is_equal(&R, &jac_zero)) {
|
||||
printf("Failed 2*0 = 0 in jac\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
jac_neg(&R, &S);
|
||||
ADD(&R, &S, &R, curve);
|
||||
if (!jac_is_equal(&R, &jac_zero)) {
|
||||
printf("Failed P - P = 0 in jac\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ADD(&R, &S, &jac_zero, curve);
|
||||
if (!jac_is_equal(&R, &S)) {
|
||||
printf("Failed P + 0 = P in jac\n");
|
||||
return 1;
|
||||
}
|
||||
ADD(&R, &jac_zero, &S, curve);
|
||||
if (!jac_is_equal(&R, &S)) {
|
||||
printf("Failed P + 0 = P in jac\n");
|
||||
return 1;
|
||||
}
|
||||
ADD(&R, &S, &jac_zero, curve);
|
||||
if (!jac_is_equal(&R, &S)) {
|
||||
printf("Failed 0 + P = P in jac\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
DBL(&R, &S, curve);
|
||||
ADD(&U, &S, &S, curve);
|
||||
if (!jac_is_equal(&R, &U)) {
|
||||
printf("Failed P + P = 2*P in jac\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ADD(&R, &T, &S, curve);
|
||||
ADD(&T, &S, &T, curve);
|
||||
if (!jac_is_equal(&R, &T)) {
|
||||
printf("Failed P + Q = Q + P in jac\n");
|
||||
return 1;
|
||||
}
|
||||
ADD(&R, &T, &S, curve);
|
||||
ADD(&U, &S, &T, curve);
|
||||
if (!jac_is_equal(&R, &U)) {
|
||||
printf("Failed P + Q = Q + P in jac\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Double R to make it different than (T + S).
|
||||
DBL(&R, &R, curve);
|
||||
ADD(&U, &S, &T, curve);
|
||||
ADD(&U, &U, &R, curve);
|
||||
ADD(&R, &R, &T, curve);
|
||||
ADD(&R, &R, &S, curve);
|
||||
if (!jac_is_equal(&R, &U)) {
|
||||
printf("Failed (P + Q) + R = P + (Q + R) in jac\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
jac_to_ws(&R, &t0, &t1, &jac_zero, curve);
|
||||
jac_from_ws(&R, &R, &t1, curve);
|
||||
if (!jac_is_equal(&R, &jac_zero)) {
|
||||
printf("Failed converting to Weierstrass\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
jac_to_ws(&R, &t0, &t1, &S, curve);
|
||||
jac_from_ws(&R, &R, &t1, curve);
|
||||
if (!jac_is_equal(&S, &R)) {
|
||||
printf("Failed converting to Weierstrass\n");
|
||||
return 1;
|
||||
}
|
||||
DBL(&S, &S, curve);
|
||||
jac_to_ws(&R, &t0, &t1, &S, curve);
|
||||
jac_from_ws(&R, &R, &t1, curve);
|
||||
if (!jac_is_equal(&S, &R)) {
|
||||
printf("Failed converting to Weierstrass\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
jac_to_ws(&R, &t0, &t1, &jac_zero, curve);
|
||||
DBLW(&R, &t0, &R, &t0);
|
||||
jac_from_ws(&R, &R, &t1, curve);
|
||||
if (!jac_is_equal(&R, &jac_zero)) {
|
||||
printf("Failed 2*0 = 0 in Weierstrass\n");
|
||||
return 1;
|
||||
}
|
||||
jac_to_ws(&R, &t0, &t1, &S, curve);
|
||||
DBLW(&R, &t0, &R, &t0);
|
||||
jac_from_ws(&R, &R, &t1, curve);
|
||||
DBL(&S, &S, curve);
|
||||
if (!jac_is_equal(&S, &R)) {
|
||||
printf("Failed doubling in Weierstrass\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
uint32_t seed[12] = { 0 };
|
||||
int iterations = 100 * SQISIGN_TEST_REPS;
|
||||
int help = 0;
|
||||
int seed_set = 0;
|
||||
int res = 0;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!help && strcmp(argv[i], "--help") == 0) {
|
||||
help = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!seed_set && !parse_seed(argv[i], seed)) {
|
||||
seed_set = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sscanf(argv[i], "--iterations=%d", &iterations) == 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (help || iterations <= 0) {
|
||||
printf("Usage: %s [--iterations=<iterations>] [--seed=<seed>]\n", argv[0]);
|
||||
printf("Where <iterations> is the number of iterations used for testing; if not "
|
||||
"present, uses the default: %d)\n",
|
||||
iterations);
|
||||
printf("Where <seed> is the random seed to be used; if not present, a random seed is "
|
||||
"generated\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!seed_set) {
|
||||
randombytes_select((unsigned char *)seed, sizeof(seed));
|
||||
}
|
||||
|
||||
print_seed(seed);
|
||||
|
||||
#if defined(TARGET_BIG_ENDIAN)
|
||||
for (int i = 0; i < 12; i++) {
|
||||
seed[i] = BSWAP32(seed[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
randombytes_init((unsigned char *)seed, NULL, 256);
|
||||
|
||||
// Curve A=6
|
||||
ec_curve_t curve;
|
||||
ec_curve_init(&curve);
|
||||
fp2_set_small(&(curve.A), 0);
|
||||
fp2_set_small(&(curve.C), 1);
|
||||
// fp2_random_test(&(curve.C));
|
||||
// fp2_mul(&(curve.A), &(curve.A), &(curve.C));
|
||||
ec_curve_normalize_A24(&curve);
|
||||
|
||||
res |= test_xDBL_xADD(&curve, iterations);
|
||||
res |= test_xDBLADD(&curve, iterations);
|
||||
res |= test_xDBL_variants(&curve, iterations);
|
||||
res |= test_zero_identities(&curve, iterations);
|
||||
res |= test_jacobian(&curve, iterations);
|
||||
|
||||
fp2_random_test(&(curve.C));
|
||||
fp2_mul(&(curve.A), &(curve.A), &(curve.C));
|
||||
ec_curve_normalize_A24(&curve);
|
||||
|
||||
res |= test_xDBL_xADD(&curve, iterations);
|
||||
res |= test_xDBLADD(&curve, iterations);
|
||||
res |= test_xDBL_variants(&curve, iterations);
|
||||
res |= test_zero_identities(&curve, iterations);
|
||||
res |= test_jacobian(&curve, iterations);
|
||||
|
||||
if (res) {
|
||||
printf("Tests failed!\n");
|
||||
} else {
|
||||
printf("All ec arithmetic tests passed.\n");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
116
src/ec/ref/lvlx/test/test_extras.c
Normal file
116
src/ec/ref/lvlx/test/test_extras.c
Normal file
@@ -0,0 +1,116 @@
|
||||
#include "test_extras.h"
|
||||
#include "rng.h"
|
||||
|
||||
// Make n random-ish field elements (for tests only!).
|
||||
void
|
||||
fp_random_test(fp_t *a)
|
||||
{
|
||||
uint8_t tmp[FP_ENCODED_BYTES];
|
||||
|
||||
randombytes(tmp, sizeof(tmp));
|
||||
|
||||
fp_decode_reduce(a, tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
void
|
||||
fp2_random_test(fp2_t *a)
|
||||
{
|
||||
fp_random_test(&(a->re));
|
||||
fp_random_test(&(a->im));
|
||||
}
|
||||
|
||||
// Given an x-coordinate, determines if this is a valid
|
||||
// point on the curve. Assumes C=1.
|
||||
static uint32_t
|
||||
projective_is_on_curve(const ec_point_t *P, const ec_curve_t *curve)
|
||||
{
|
||||
|
||||
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) || fp2_is_zero(&t0);
|
||||
}
|
||||
|
||||
void
|
||||
ec_random_normalized_test(ec_point_t *P, const ec_curve_t *curve)
|
||||
{
|
||||
fp2_set_one(&P->z);
|
||||
while (1) {
|
||||
fp2_random_test(&P->x);
|
||||
if (projective_is_on_curve(P, curve)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ec_random_test(ec_point_t *P, const ec_curve_t *curve)
|
||||
{
|
||||
ec_random_normalized_test(P, curve);
|
||||
fp2_random_test(&P->z);
|
||||
fp2_mul(&P->x, &P->x, &P->z);
|
||||
}
|
||||
|
||||
void
|
||||
projective_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 projective x-only, computes a deterministic choice for (P-Q)
|
||||
// Based on Proposition 3 of https://eprint.iacr.org/2017/518.pdf
|
||||
|
||||
fp2_t Bxx, Bxz, Bzz, t0, t1;
|
||||
|
||||
fp2_mul(&t0, &P->x, &Q->x);
|
||||
fp2_mul(&t1, &P->z, &Q->z);
|
||||
fp2_sub(&Bxx, &t0, &t1);
|
||||
fp2_sqr(&Bxx, &Bxx);
|
||||
fp2_mul(&Bxx, &Bxx, &curve->C); // C*(P.x*Q.x-P.z*Q.z)^2
|
||||
fp2_add(&Bxz, &t0, &t1);
|
||||
fp2_mul(&t0, &P->x, &Q->z);
|
||||
fp2_mul(&t1, &P->z, &Q->x);
|
||||
fp2_add(&Bzz, &t0, &t1);
|
||||
fp2_mul(&Bxz, &Bxz, &Bzz); // (P.x*Q.x+P.z*Q.z)(P.x*Q.z+P.z*Q.x)
|
||||
fp2_sub(&Bzz, &t0, &t1);
|
||||
fp2_sqr(&Bzz, &Bzz);
|
||||
fp2_mul(&Bzz, &Bzz, &curve->C); // C*(P.x*Q.z-P.z*Q.x)^2
|
||||
fp2_mul(&Bxz, &Bxz, &curve->C); // C*(P.x*Q.x+P.z*Q.z)(P.x*Q.z+P.z*Q.x)
|
||||
fp2_mul(&t0, &t0, &t1);
|
||||
fp2_mul(&t0, &t0, &curve->A);
|
||||
fp2_add(&t0, &t0, &t0);
|
||||
fp2_add(&Bxz, &Bxz, &t0); // C*(P.x*Q.x+P.z*Q.z)(P.x*Q.z+P.z*Q.x) + 2*A*P.x*Q.z*P.z*Q.x
|
||||
|
||||
// Normalization: our squareroot always has the same sign as long as P.z, Q.z, and C
|
||||
// are in Fp and C is a square, so the B's should be scaled by C*C_bar^2*P.z_bar^2*Q.Z_bar^2
|
||||
fp_copy(&t0.re, &curve->C.re);
|
||||
fp_neg(&t0.im, &curve->C.im);
|
||||
fp2_sqr(&t0, &t0);
|
||||
fp2_mul(&t0, &t0, &curve->C);
|
||||
fp_copy(&t1.re, &P->z.re);
|
||||
fp_neg(&t1.im, &P->z.im);
|
||||
fp2_sqr(&t1, &t1);
|
||||
fp2_mul(&t0, &t0, &t1);
|
||||
fp_copy(&t1.re, &Q->z.re);
|
||||
fp_neg(&t1.im, &Q->z.im);
|
||||
fp2_sqr(&t1, &t1);
|
||||
fp2_mul(&t0, &t0, &t1);
|
||||
fp2_mul(&Bxx, &Bxx, &t0);
|
||||
fp2_mul(&Bxz, &Bxz, &t0);
|
||||
fp2_mul(&Bzz, &Bzz, &t0);
|
||||
|
||||
// Solving quadratic equation
|
||||
fp2_sqr(&t0, &Bxz);
|
||||
fp2_mul(&t1, &Bxx, &Bzz);
|
||||
fp2_sub(&t0, &t0, &t1);
|
||||
fp2_sqrt(&t0);
|
||||
fp2_add(&PQ->x, &Bxz, &t0);
|
||||
fp2_copy(&PQ->z, &Bzz);
|
||||
}
|
||||
43
src/ec/ref/lvlx/test/test_extras.h
Normal file
43
src/ec/ref/lvlx/test/test_extras.h
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
#ifndef TEST_EXTRAS_H
|
||||
#define TEST_EXTRAS_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <encoded_sizes.h>
|
||||
#include <ec.h>
|
||||
#include <fp.h>
|
||||
#include <fp2.h>
|
||||
|
||||
#define PASSED 0
|
||||
#define FAILED 1
|
||||
|
||||
// Generating a pseudo-random field element in [0, p-1]
|
||||
void fp_random_test(fp_t *a);
|
||||
|
||||
// Generating a pseudo-random element in GF(p^2)
|
||||
void fp2_random_test(fp2_t *a);
|
||||
|
||||
// Generating a random projective x-only point
|
||||
void ec_random_test(ec_point_t *P, const ec_curve_t *curve);
|
||||
|
||||
// Generating a random projective x-only point and normalizing it
|
||||
void ec_random_normalized_test(ec_point_t *P, const ec_curve_t *curve);
|
||||
|
||||
// Point difference
|
||||
void projective_difference_point(ec_point_t *PQ, const ec_point_t *P, const ec_point_t *Q, const ec_curve_t *curve);
|
||||
|
||||
// xDBL
|
||||
void xDBL(ec_point_t *Q, const ec_point_t *P, const ec_point_t *AC);
|
||||
|
||||
// Double-and-add
|
||||
extern void xDBLADD(ec_point_t *R,
|
||||
ec_point_t *S,
|
||||
const ec_point_t *P,
|
||||
const ec_point_t *Q,
|
||||
const ec_point_t *PQ,
|
||||
const ec_point_t *A24,
|
||||
const bool A24_normalized);
|
||||
|
||||
#endif
|
||||
64
src/ec/ref/lvlx/xeval.c
Normal file
64
src/ec/ref/lvlx/xeval.c
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "isog.h"
|
||||
#include "ec.h"
|
||||
#include <assert.h>
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
// 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, const ec_kps2_t *kps)
|
||||
{
|
||||
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, &kps->K.x, &t1);
|
||||
fp2_mul(&t1, &kps->K.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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xeval_2_singular(ec_point_t *R, const ec_point_t *Q, const int lenQ, const ec_kps2_t *kps)
|
||||
{
|
||||
fp2_t t0, t1;
|
||||
for (int i = 0; i < lenQ; i++) {
|
||||
fp2_mul(&t0, &Q[i].x, &Q[i].z);
|
||||
fp2_mul(&t1, &kps->K.x, &Q[i].z);
|
||||
fp2_add(&t1, &t1, &Q[i].x);
|
||||
fp2_mul(&t1, &t1, &Q[i].x);
|
||||
fp2_sqr(&R[i].x, &Q[i].z);
|
||||
fp2_add(&R[i].x, &R[i].x, &t1);
|
||||
fp2_mul(&R[i].z, &t0, &kps->K.z);
|
||||
}
|
||||
}
|
||||
|
||||
// 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, const ec_kps4_t *kps)
|
||||
{
|
||||
const ec_point_t *K = kps->K;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
61
src/ec/ref/lvlx/xisog.c
Normal file
61
src/ec/ref/lvlx/xisog.c
Normal file
@@ -0,0 +1,61 @@
|
||||
#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_kps2_t *kps, ec_point_t *B, const ec_point_t P)
|
||||
{
|
||||
fp2_sqr(&B->x, &P.x);
|
||||
fp2_sqr(&B->z, &P.z);
|
||||
fp2_sub(&B->x, &B->z, &B->x);
|
||||
fp2_add(&kps->K.x, &P.x, &P.z);
|
||||
fp2_sub(&kps->K.z, &P.x, &P.z);
|
||||
}
|
||||
|
||||
void
|
||||
xisog_2_singular(ec_kps2_t *kps, ec_point_t *B24, ec_point_t A24)
|
||||
{
|
||||
// No need to check the square root, only used for signing.
|
||||
fp2_t t0, four;
|
||||
fp2_set_small(&four, 4);
|
||||
fp2_add(&t0, &A24.x, &A24.x);
|
||||
fp2_sub(&t0, &t0, &A24.z);
|
||||
fp2_add(&t0, &t0, &t0);
|
||||
fp2_inv(&A24.z);
|
||||
fp2_mul(&t0, &t0, &A24.z);
|
||||
fp2_copy(&kps->K.x, &t0);
|
||||
fp2_add(&B24->x, &t0, &t0);
|
||||
fp2_sqr(&t0, &t0);
|
||||
fp2_sub(&t0, &t0, &four);
|
||||
fp2_sqrt(&t0);
|
||||
fp2_neg(&kps->K.z, &t0);
|
||||
fp2_add(&B24->z, &t0, &t0);
|
||||
fp2_add(&B24->x, &B24->x, &B24->z);
|
||||
fp2_add(&B24->z, &B24->z, &B24->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_kps4_t *kps, ec_point_t *B, const ec_point_t P)
|
||||
{
|
||||
ec_point_t *K = kps->K;
|
||||
|
||||
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);
|
||||
}
|
||||
32
src/ec/ref/lvlx_test.cmake
Normal file
32
src/ec/ref/lvlx_test.cmake
Normal file
@@ -0,0 +1,32 @@
|
||||
add_executable(curve-arith.test_${SVARIANT_LOWER} ${LVLX_DIR}/test/curve-arith-test.c ${LVLX_DIR}/test/test_extras.c)
|
||||
target_include_directories(curve-arith.test_${SVARIANT_LOWER} PUBLIC ${INC_COMMON} ${INC_MP} ${INC_GF} ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${INC_PUBLIC} ../include ${INC_EC} .)
|
||||
target_link_libraries(curve-arith.test_${SVARIANT_LOWER} ${LIB_EC_${SVARIANT_UPPER}} sqisign_common_test)
|
||||
|
||||
add_executable(biextension.test_${SVARIANT_LOWER} ${LVLX_DIR}/test/biextension-test.c)
|
||||
target_include_directories(biextension.test_${SVARIANT_LOWER} PUBLIC ${INC_COMMON} ${INC_MP} ${INC_GF} ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${INC_PUBLIC} ../include ${INC_EC} .)
|
||||
target_link_libraries(biextension.test_${SVARIANT_LOWER} ${LIB_EC_${SVARIANT_UPPER}} sqisign_common_test)
|
||||
|
||||
add_executable(basis-gen.test_${SVARIANT_LOWER} ${LVLX_DIR}/test/basis-gen-test.c)
|
||||
target_include_directories(basis-gen.test_${SVARIANT_LOWER} PUBLIC ${INC_COMMON} ${INC_MP} ${LVLX_DIR}/test ${INC_GF} ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${INC_PUBLIC} ../include ${INC_EC} .)
|
||||
target_link_libraries(basis-gen.test_${SVARIANT_LOWER} ${LIB_EC_${SVARIANT_UPPER}})
|
||||
|
||||
add_test(curve_arith.test_${SVARIANT_LOWER} curve-arith.test_${SVARIANT_LOWER})
|
||||
add_test(ec_biextension.test_${SVARIANT_LOWER} biextension.test_${SVARIANT_LOWER})
|
||||
add_test(ec_basis_gen.test_${SVARIANT_LOWER} basis-gen.test_${SVARIANT_LOWER})
|
||||
|
||||
add_executable(curve-arith.bench_${SVARIANT_LOWER} ${LVLX_DIR}/test/curve-arith-bench.c ${LVLX_DIR}/test/test_extras.c)
|
||||
target_include_directories(curve-arith.bench_${SVARIANT_LOWER} PUBLIC ${INC_COMMON} ${INC_MP} ${INC_GF} ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${INC_PUBLIC} ../include ${INC_EC} .)
|
||||
target_link_libraries(curve-arith.bench_${SVARIANT_LOWER} ${LIB_EC_${SVARIANT_UPPER}} sqisign_common_sys)
|
||||
|
||||
add_executable(biextension.bench_${SVARIANT_LOWER} ${LVLX_DIR}/test/biextension-bench.c)
|
||||
target_include_directories(biextension.bench_${SVARIANT_LOWER} PUBLIC ${INC_COMMON} ${INC_MP} ${INC_GF} ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${INC_PUBLIC} ../include ${INC_EC} .)
|
||||
target_link_libraries(biextension.bench_${SVARIANT_LOWER} ${LIB_EC_${SVARIANT_UPPER}} sqisign_common_sys)
|
||||
|
||||
add_executable(basis-gen.bench_${SVARIANT_LOWER} ${LVLX_DIR}/test/basis-gen-bench.c)
|
||||
target_include_directories(basis-gen.bench_${SVARIANT_LOWER} PUBLIC ${INC_COMMON} ${INC_MP} ${LVLX_DIR}/test ${INC_GF} ${INC_GF_${SVARIANT_UPPER}} ${INC_PRECOMP_${SVARIANT_UPPER}} ${INC_PUBLIC} ../include ${INC_EC} .)
|
||||
target_link_libraries(basis-gen.bench_${SVARIANT_LOWER} ${LIB_EC_${SVARIANT_UPPER}})
|
||||
|
||||
set(BM_BINS ${BM_BINS}
|
||||
curve-arith.bench_${SVARIANT_LOWER} basis-gen.bench_${SVARIANT_LOWER} biextension.bench_${SVARIANT_LOWER}
|
||||
CACHE INTERNAL "List of benchmark executables")
|
||||
|
||||
Reference in New Issue
Block a user