зеркало из https://github.com/microsoft/FourQlib.git
160 строки
7.7 KiB
C
160 строки
7.7 KiB
C
/****************************************************************************************
|
|
* FourQlib: a high-performance crypto library based on the elliptic curve FourQ
|
|
*
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
*
|
|
*
|
|
* Abstract: ECC operations over GF(p^2) without exploiting endomorphisms
|
|
*
|
|
* This code is based on the papers:
|
|
* [1] "FourQ: four-dimensional decompositions on a Q-curve over the Mersenne prime"
|
|
* by Craig Costello and Patrick Longa, ASIACRYPT2015 (http://eprint.iacr.org/2015/565).
|
|
* [2] "FourQNEON: Faster Elliptic Curve Scalar Multiplications on ARM Processors"
|
|
* by Patrick Longa, SAC2016 (http://eprint.iacr.org/2016/645).
|
|
******************************************************************************************/
|
|
|
|
#include "FourQ_internal.h"
|
|
|
|
|
|
#if (USE_ENDO == false)
|
|
|
|
/***********************************************/
|
|
/********** CURVE/SCALAR FUNCTIONS ***********/
|
|
|
|
void fixed_window_recode(uint64_t* scalar, unsigned int* digits, unsigned int* sign_masks)
|
|
{ // Converting scalar to the fixed window representation used by the variable-base scalar multiplication
|
|
// Inputs: scalar in [0, order-1], where the order of FourQ's subgroup is 246 bits.
|
|
// Outputs: "digits" array with (t_VARBASE+1) nonzero entries. Each entry is in the range [0, 7], corresponding to one entry in the precomputed table.
|
|
// where t_VARBASE+1 = ((bitlength(order)+w-1)/(w-1))+1 represents the fixed length of the recoded scalar using window width w.
|
|
// The value of w is fixed to W_VARBASE = 5, which corresponds to a precomputed table with 2^(W_VARBASE-2) = 8 entries (see FourQ.h)
|
|
// used by the variable base scalar multiplication ecc_mul().
|
|
// "sign_masks" array with (t_VARBASE+1) entries storing the signs for their corresponding digits in "digits".
|
|
// Notation: if the corresponding digit > 0 then sign_mask = 0xFF...FF, else if digit < 0 then sign_mask = 0.
|
|
unsigned int val1, val2, i, j;
|
|
uint64_t res, borrow;
|
|
int64_t temp;
|
|
|
|
val1 = (1 << W_VARBASE) - 1;
|
|
val2 = (1 << (W_VARBASE-1));
|
|
|
|
for (i = 0; i < t_VARBASE; i++)
|
|
{
|
|
temp = (scalar[0] & val1) - val2; // ki = (k mod 2^w)/2^(w-1)
|
|
sign_masks[i] = ~((unsigned int)(temp >> (RADIX64-1)));
|
|
digits[i] = ((sign_masks[i] & (unsigned int)(temp ^ -temp)) ^ (unsigned int)-temp) >> 1;
|
|
|
|
res = scalar[0] - temp; // k = (k - ki) / 2^(w-1)
|
|
borrow = ((temp >> (RADIX64-1)) - 1) & (uint64_t)is_digit_lessthan_ct((digit_t)scalar[0], (digit_t)temp);
|
|
scalar[0] = res;
|
|
|
|
for (j = 1; j < NWORDS64_ORDER; j++)
|
|
{
|
|
res = scalar[j];
|
|
scalar[j] = res - borrow;
|
|
borrow = (uint64_t)is_digit_lessthan_ct((digit_t)res, (digit_t)borrow);
|
|
}
|
|
|
|
for (j = 0; j < (NWORDS64_ORDER-1); j++) {
|
|
SHIFTR(scalar[j+1], scalar[j], (W_VARBASE-1), scalar[j], RADIX64);
|
|
}
|
|
scalar[NWORDS64_ORDER-1] = scalar[NWORDS64_ORDER-1] >> (W_VARBASE-1);
|
|
|
|
}
|
|
sign_masks[t_VARBASE] = ~((unsigned int)(scalar[0] >> (RADIX64-1)));
|
|
digits[t_VARBASE] = ((sign_masks[t_VARBASE] & (unsigned int)(scalar[0] ^ (0-scalar[0]))) ^ (unsigned int)(0-scalar[0])) >> 1; // kt = k (t_VARBASE+1 digits)
|
|
}
|
|
|
|
|
|
void ecc_precomp(vpoint_extproj_t P, vpoint_extproj_precomp_t *T)
|
|
{ // Generation of the precomputation table used by the variable-base scalar multiplication ecc_mul().
|
|
// Input: P = (X1,Y1,Z1,Ta,Tb), where T1 = Ta*Tb, corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates.
|
|
// Output: table T containing NPOINTS_VARBASE points: P, 3P, 5P, ... , (2*NPOINTS_VARBASE-1)P. NPOINTS_VARBASE is fixed to 8 (see FourQ.h).
|
|
// Precomputed points use the representation (X+Y,Y-X,2Z,2dT) corresponding to (X:Y:Z:T) in extended twisted Edwards coordinates.
|
|
vpoint_extproj_precomp_t P2;
|
|
vpoint_extproj_t Q;
|
|
unsigned int i;
|
|
|
|
// Generating P2 = 2(X1,Y1,Z1,T1a,T1b) = (XP2+YP2,Y2P-X2P,ZP2,TP2) and T[0] = P = (X1+Y1,Y1-X1,2*Z1,2*d*T1)
|
|
ecccopy(P, Q);
|
|
R1_to_R2(P, T[0]);
|
|
eccdouble(Q);
|
|
R1_to_R3(Q, P2);
|
|
|
|
for (i = 1; i < NPOINTS_VARBASE; i++) {
|
|
// T[i] = 2P+T[i-1] = (2*i+1)P = (XP2+YP2,Y2P-X2P,ZP2,TP2) + (X_(2*i-1)+Y_(2*i-1), Y_(2*i-1)-X_(2*i-1), 2Z_(2*i-1), 2T_(2*i-1)) = (X_(2*i+1)+Y_(2*i+1), Y_(2*i+1)-X_(2*i+1), 2Z_(2*i+1), 2dT_(2*i+1))
|
|
eccadd_core(P2, T[i-1], Q);
|
|
R1_to_R2(Q, T[i]);
|
|
}
|
|
}
|
|
|
|
|
|
void cofactor_clearing(vpoint_extproj_t P)
|
|
{ // Co-factor clearing
|
|
// Input: P = (X1,Y1,Z1,Ta,Tb), where T1 = Ta*Tb, corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates
|
|
// Output: P = 392*P = (Xfinal,Yfinal,Zfinal,Tafinal,Tbfinal), where Tfinal = Tafinal*Tbfinal,
|
|
// corresponding to (Xfinal:Yfinal:Zfinal:Tfinal) in extended twisted Edwards coordinates
|
|
vpoint_extproj_precomp_t Q;
|
|
|
|
R1_to_R2(P, Q); // Converting from (X,Y,Z,Ta,Tb) to (X+Y,Y-X,2Z,2dT)
|
|
eccdouble(P); // P = 2*P using representations (X,Y,Z,Ta,Tb) <- 2*(X,Y,Z)
|
|
eccadd(Q, P); // P = P+Q using representations (X,Y,Z,Ta,Tb) <- (X,Y,Z,Ta,Tb) + (X+Y,Y-X,2Z,2dT)
|
|
eccdouble(P);
|
|
eccdouble(P);
|
|
eccdouble(P);
|
|
eccdouble(P);
|
|
eccadd(Q, P);
|
|
eccdouble(P);
|
|
eccdouble(P);
|
|
eccdouble(P);
|
|
}
|
|
|
|
|
|
bool ecc_mul(point_t P, digit_t* k, point_t Q, bool clear_cofactor)
|
|
{ // Scalar multiplication Q = k*P
|
|
// Inputs: scalar "k" in [0, 2^256-1],
|
|
// point P = (x,y) in affine coordinates,
|
|
// clear_cofactor = 1 (TRUE) or 0 (FALSE) whether cofactor clearing is required or not, respectively.
|
|
// Output: Q = k*P in affine coordinates (x,y).
|
|
// This function performs point validation and (if selected) cofactor clearing.
|
|
vpoint_t A;
|
|
vpoint_extproj_t R;
|
|
vpoint_extproj_precomp_t S, Table[NPOINTS_VARBASE];
|
|
unsigned int digits[t_VARBASE+1] = {0}, sign_masks[t_VARBASE+1] = {0};
|
|
digit_t k_odd[NWORDS_ORDER];
|
|
int i;
|
|
|
|
point_setup(P, R); // Convert to representation (X,Y,1,Ta,Tb)
|
|
|
|
if (ecc_point_validate(R) == false) { // Check if point lies on the curve
|
|
return false;
|
|
}
|
|
|
|
if (clear_cofactor == true) {
|
|
cofactor_clearing(R);
|
|
}
|
|
|
|
modulo_order(k, k_odd); // k_odd = k mod (order)
|
|
conversion_to_odd(k_odd, k_odd); // Converting scalar to odd using the prime subgroup order
|
|
ecc_precomp(R, Table); // Precomputation of points T[0],...,T[npoints-1]
|
|
fixed_window_recode((uint64_t*)k_odd, digits, sign_masks); // Scalar recoding
|
|
table_lookup_1x8(Table, S, digits[t_VARBASE], sign_masks[t_VARBASE]);
|
|
R2_to_R4(S, R); // Conversion to representation (2X,2Y,2Z)
|
|
|
|
for (i = (t_VARBASE-1); i >= 0; i--)
|
|
{
|
|
eccdouble(R);
|
|
table_lookup_1x8(Table, S, digits[i], sign_masks[i]); // Extract point in (X+Y,Y-X,2Z,2dT) representation
|
|
eccdouble(R);
|
|
eccdouble(R);
|
|
eccdouble(R); // P = 2*P using representations (X,Y,Z,Ta,Tb) <- 2*(X,Y,Z)
|
|
eccadd(S, R); // P = P+S using representations (X,Y,Z,Ta,Tb) <- (X,Y,Z,Ta,Tb) + (X+Y,Y-X,2Z,2dT)
|
|
}
|
|
eccnorm(R, A); // Conversion to affine coordinates (x,y) and modular correction.
|
|
from_ext_to_std(A->x, Q->x);
|
|
from_ext_to_std(A->y, Q->y);
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif
|