diff --git a/FourQ-Magma/Full-Routine-Affine.txt b/FourQ-Magma/Full-Routine-Affine.txt new file mode 100644 index 0000000..25ce57b --- /dev/null +++ b/FourQ-Magma/Full-Routine-Affine.txt @@ -0,0 +1,264 @@ +/************************************************************************************* +* FourQ: 4-dimensional decomposition on a Q-curve with CM in twisted Edwards form +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* +* Abstract: This MAGMA script is a condensed version of the script "FourQ-Extended-Theorem1". +* For simplicity and ease of readability, is not written in two-operand form, +* and works throughout in affine coordinates. It is intended to give a high- +* level overview of the algorithm. +* +* This code is based on the paper "FourQ: four-dimensional decompositions on a +* Q-curve over the Mersenne prime" by Craig Costello and Patrick Longa, in Advances +* in Cryptology - ASIACRYPT, 2015. +* Preprint available at http://eprint.iacr.org/2015/565. +**************************************************************************************/ + +clear; + +// Define twisted Edwards curves E, Ehat and the isogenous Weierstrass curve W +p:=2^127-1; Fp:=GF(p); Fp2:=ExtensionField; AS:=AffineSpace(Fp2,2); +d:=125317048443780598345676279555970305165*i + 4205857648805777768770; +E:=Curve(AS,[-x^2+y^2-(1+d*x^2*y^2)]); +dhat:=-1/(d+1); +Ehat:=Curve(AS,[-x^2+y^2-(1+dhat*x^2*y^2)]); +rt2:=2^64; +rt5:=87392807087336976318005368820707244464*i; +A:=-(30-8*rt5); B:=56-32*rt5; +W:=EllipticCurve([Fp2|A,B]); + +mu:=2^256; // Scalars allowed in [0,mu) + +DBL:=function(Q) // a=-1 twisted Edwards doubling + + x:=Q[1]; y:=Q[2]; + X:=2*x*y/(1+d*x^2*y^2); + Y:=(y^2+x^2)/(1-d*x^2*y^2); + return E![X,Y]; + +end function; + +ADD:=function(Q,R) // a=-1 twisted Edwards addition + + x1:=Q[1]; y1:=Q[2]; x2:=R[1]; y2:=R[2]; + X:=(x1*y2+y1*x2)/(1+d*x1*x2*y1*y2); + Y:=(y1*y2+x1*x2)/(1-d*x1*x2*y1*y2); + return E![X,Y]; + +end function; + +tau:=function(P) // Isogeny tau: E->Ehat + + x:=P[1]; y:=P[2]; + X:=2*x*y/((x^2+y^2)*Sqrt(dhat)); + Y:=(x^2-y^2+2)/(y^2-x^2); + return Ehat![X,Y]; + +end function; + +tau_dual:=function(P) // Isogeny tau_dual: Ehat->E + + x:=P[1]; y:=P[2]; + X:=2*x*y*Sqrt(dhat)/(x^2-y^2+2); + Y:=(y^2-x^2)/(y^2+x^2); + return E![X,Y]; + +end function; + +delta:=function(P) // Isomorphism delta: W->Ehat + + x:=P[1]; y:=P[2]; + X:=Sqrt(-12-4*rt2-2*rt5*rt2)*(x-4)/y; + Y:=(x-4-(2*rt2+rt2*rt5))/(x-4+(2*rt2+rt2*rt5)); + return Ehat![X,Y]; + +end function; + +delta_inv:=function(P) // Isomorphism delta_inv: Ehat->W + + x:=P[1]; y:=P[2]; + X:=(2*rt2+rt2*rt5)*(y+1)/(1-y)+4; + Y:=(2*rt2+rt2*rt5)*(y+1)/(1-y)*Sqrt(-12-4*rt2-2*rt5*rt2)/x; + return W![X,Y]; + +end function; + +phiW:=function(P) // Endomorphism phiW on the Weierstrass curve + + x:=P[1]; y:=P[2]; + X:=x^5+8*rt5*x^4+(40*rt5+260)*x^3+(720*rt5+640)*x^2+(656*rt5+4340)*x+(1920*rt5+960); + X:=X/(5*(x^2+4*rt5*x-1/5*(4*rt5-90))^2); + Y:=-y*(x^2+(4*rt5-8)*x-(12*rt5-26))*(x^4+(8*rt5+8)*x^3+28*x^2-(48*rt5+112)*x-32*rt5-124); + Y:=Y/(rt5*(x^2+4*rt5*x-1/5*(4*rt5-90)))^3; + return W![X^p,Y^p]; + +end function; + +psiW:=function(P) // Endomorphism psiW on the Weierstrass curve + + x:=P[1]; y:=P[2]; + X:=-x/2-(9+4*rt5)/(x-4); + Y:=-y/(i*rt2)*(-1/2+(9+4*rt5)/(x-4)^2); + return W![X^p,Y^p]; + +end function; + +phi:=function(P); // Endomorphism phi on E via composition + return tau_dual(delta(phiW(delta_inv(tau(P))))); +end function; + +psi:=function(P); // Endomorphism psi on E via composition + return tau_dual(delta(psiW(delta_inv(tau(P))))); +end function; + +decomposition:=function(m) // Scalar decomposition + + alpha1:=Floor(50127518246259276682880317011538934615153226543083896339791*m/mu); + alpha2:=Floor(22358026531042503310338016640572204942053343837521088510715*m/mu); + alpha3:=Floor(5105580562119000402467322500999592531749084507000101675068*m/mu); + alpha4:=Floor(19494034873545274265741574254707851381713530791194721254848*m/mu); + + a1:=m-alpha1*650487742939046294-alpha2*2110318963211420372-alpha3*1705647224544756482-alpha4*1400113754146392127+8234880650715616668; + + a2:=alpha1*1397215820276968864+alpha2-alpha3*199320682881407569-alpha4*3540637644719456050+6483313240794689388; + + a3:=-alpha1*523086274270593807-alpha2+alpha3*3336360048424633503+alpha4*471270406870313397+9066539331533273720; + + a4:=alpha1*598824378691085905-alpha2*2727991412926801872-alpha3*765171327772315031+alpha4*1789345740969872106+7765751599377320055; + + a1hat:=a1+1400113754146392127; + a2hat:=a2+3540637644719456050; + a3hat:=a3-471270406870313397; + a4hat:=a4-1789345740969872106; + + if IsEven(a1) then + a1:=a1hat; a2:=a2hat; a3:=a3hat; a4:=a4hat; + end if; + + a1:=IntegerToSequence(a1,2); + a2:=IntegerToSequence(a2,2); + a3:=IntegerToSequence(a3,2); + a4:=IntegerToSequence(a4,2); + + // Padding + while #a1 ne 65 do Append(~a1,0); end while; + while #a2 ne 65 do Append(~a2,0); end while; + while #a3 ne 65 do Append(~a3,0); end while; + while #a4 ne 65 do Append(~a4,0); end while; + + return a1,a2,a3,a4; + +end function; + +recode:=function(a1,a2,a3,a4) // Scalar recoding + + a:=[a1,a2,a3,a4]; + b:=[[0: i in [1..65]]: j in [1..4]]; + + b[1][65]:=1; + + for i:=1 to 65 do + if i ne 65 then + b[1][i]:=2*a[1][i+1]-1; + end if; + for j:=2 to 4 do + b[j][i]:=b[1][i]*a[j][1]; + aj:=SequenceToInteger(a[j],2); + aj:=Floor(aj div 2)-Floor(b[j][i] div 2); + if aj ne 0 then + a[j]:=IntegerToSequence(aj,2); + else + a[j]:=[0]; + end if; + end for; + end for; + + m:=b[1]; d:=[]; + for i:=1 to 65 do + Append(~d,SequenceToInteger([Abs(b[2][i]),Abs(b[3][i]),Abs(b[4][i])],2)+1); + end for; + + return m,d; + +end function; + +lookup_table:=function(P,phiP,psiP,psiphiP) // Building the lookup table + + T:=[]; + Append(~T,P); + Append(~T,ADD(phiP,T[1])); + Append(~T,ADD(psiP,T[1])); + Append(~T,ADD(psiP,T[2])); + Append(~T,ADD(psiphiP,T[1])); + Append(~T,ADD(psiphiP,T[2])); + Append(~T,ADD(psiphiP,T[3])); + Append(~T,ADD(psiphiP,T[4])); + + return T; + +end function; + +generic_scalar_multiplication:=function(P,k) // Generic scalar multiplication used for testing + + bits:=IntegerToSequence(k,2); + Q:=P; + + for i:=#bits-1 to 1 by -1 do + Q:=DBL(Q); + if bits[i] eq 1 then + Q:=ADD(Q,P); + end if; + end for; + + return Q; + +end function; + +fourQ_scalar_multiplication:=function(P,m) // Regular four-dimensional scalar multiplication + + // Step 1 - Compute endomorphisms: + phiP:=phi(P); psiP:=psi(P); psiphiP:=psi(phiP); + + // Step 2 - Precompute lookup table: + T:=lookup_table(P,phiP,psiP,psiphiP); + + // Step 3 - Scalar decomposition: + a1,a2,a3,a4:=decomposition(m); + + // Step 4 - Scalar recoding: + masks,indexes:=recode(a1,a2,a3,a4); + + // Step 5 - Initialize + Q:=T[indexes[65]]; + + // Steps 6,7,8 - Main loop: + for i:=64 to 1 by -1 do + Q:=DBL(Q); + Ti:=T[indexes[i]]; + if masks[i] eq -1 then + Ti:=E![-Ti[1],Ti[2]]; + end if; + Q:=ADD(Q,Ti); + end for; + + return Q; // no (Step 9) normalize here as Q is affine throughout + +end function; + +// Testing the full FourQ routine against a generic scalar multiplication + +while true do + + P:=generic_scalar_multiplication(tau_dual(delta(Random(W))),392); // Random N-torsion point + m:=Random(0,mu); // Random scalar + + if (fourQ_scalar_multiplication(P,m) ne generic_scalar_multiplication(P,m)) then; + break; + else + printf "passed\n"; + end if; + +end while; + +printf "failed"; diff --git a/FourQ-Magma/Full-Routine-Extended-Theorem 1.txt b/FourQ-Magma/Full-Routine-Extended-Theorem 1.txt new file mode 100644 index 0000000..5880413 --- /dev/null +++ b/FourQ-Magma/Full-Routine-Extended-Theorem 1.txt @@ -0,0 +1,684 @@ +/************************************************************************************* +* FourQ: 4-dimensional decomposition on a Q-curve with CM in twisted Edwards form +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* +* Abstract: This MAGMA script computes the full FourQ variable-based multiplication as +* detailed in Algorithm 2 of the paper. Inherently included in this script +* are the endomorphisms, the scalar decomposition and the scalar recoding +* routine in Algorithm 1. +* The code also verifies the operation counts and claims in Theorem 1. +* +* This code is based on the paper "FourQ: four-dimensional decompositions on a +* Q-curve over the Mersenne prime" by Craig Costello and Patrick Longa, in Advances +* in Cryptology - ASIACRYPT, 2015. +* Preprint available at http://eprint.iacr.org/2015/565. +**************************************************************************************/ + +clear; + +// Define curve +p:=2^127-1; Fp:=GF(p); Fp2:=ExtensionField; +AS:=AffineSpace(Fp2,2); + +// The complete twisted Edwards curve and prime subgroup order +d:=125317048443780598345676279555970305165*i + 4205857648805777768770; +E:=Curve(AS,[-x^2+y^2-(1+d*x^2*y^2)]); + +mu:=2^256; // Scalars allowed in [0,mu) + +// CONSTANTS FOR ENDOMORPHISMS + +// phi constants +cphi0:=49615650983565284830950896420241471514*i + 110680464442257309687; +cphi1:=131306912742858181648727312260439119609*i + 92233720368547758087; +cphi2:=160666015865631300014011952927357137809*i + 276701161105643274261; +cphi3:=107027644557995218531204623577807990436*i + 36893488147419103235; +cphi4:=24279268184862963117522688682631129173*i + 55340232221128654851; +cphi5:=92472642025247131565767320804994133491*i + 184467440737095516175; +cphi6:=14804100590025031399847337894104161255*i + 332041393326771929112; +cphi7:=76283848507754718862858058709728786458*i + 442721857769029238819; +cphi8:=41635071732389019719735756359456329456*i + 3135946492530623774960; +cphi9:=21045324596686230484035983431638590725*i + 39844967199212631493615; +// psi constants +cpsi1:=4095177184363520459066*i + 57123674603396429897431647433607300847; +cpsi2:=44824135016688633386011024159913800562*i + 4205857648805777768771; +cpsi3:=101947809620085063283442671593521101409*i + 110680464442257309705; +cpsi4:=68193373840384168448244632122363004318*i + 170141183460469231621006839273626796022; +// tau constant +ctau1:=221360928884514619410*i + 33754435779700894835198039471158097091; +// tau_dual constant +ctaudual1:=170141183460469231510326374831369486353*i + 99231301967130569661901792840482943028; + +// CONSTANTS FOR SCALAR DECOMPOSITION + +// The Babai-optimal basis +b11:=650487742939046294; +b12:=1397215820276968864; // negated +b13:=523086274270593807; +b14:=598824378691085905; // negated +b21:=2110318963211420372; +//b22:=1; // negated +//b23:=1; +b24:=2727991412926801872; +b31:=1705647224544756482; +b32:=199320682881407569; +b33:=3336360048424633503; // negated +b34:=765171327772315031; +b41:=1400113754146392127; +b42:=3540637644719456050; +b43:=471270406870313397; // negated +b44:=1789345740969872106; // negated + +// The offset vector +c1:=8234880650715616668; +c2:=6483313240794689388; +c3:=9066539331533273720; +c4:=7765751599377320055; + +// The precomputed fractions for the decomposition +ell1:=50127518246259276682880317011538934615153226543083896339791; +ell2:=22358026531042503310338016640572204942053343837521088510715; +ell3:=5105580562119000402467322500999592531749084507000101675068; +ell4:=19494034873545274265741574254707851381713530791194721254848; + +/* +Function converts Q from representation R1 to R2. See Tables 2 and 3. +*/ +R1toR2:=function(Q,Fp2_ops) + + mul:=0; sqr:=0; add:=0; + Q[4]:=Q[4]+Q[4]; add+:=1; + t1:=Q[1]+Q[2]; add+:=1; + Q[2]:=Q[2]-Q[1]; add+:=1; + Q[1]:=t1; + Q[4]:=Q[4]*Q[5]; mul+:=1; + Q[3]:=Q[3]+Q[3]; add+:=1; + Q[4]:=d*Q[4]; mul+:=1; + + Fp2_ops:=[Fp2_ops[1]+mul,Fp2_ops[2]+sqr,Fp2_ops[3]+add]; + Prune(~Q); + + return Q,Fp2_ops; + +end function; + +/* +Function converts Q from representation R1 to R3. See Tables 2 and 3. +*/ +R1toR3:=function(Q,Fp2_ops) + + mul:=0; sqr:=0; add:=0; + + t1:=Q[1]+Q[2]; add+:=1; + Q[2]:=Q[2]-Q[1]; add+:=1; + Q[1]:=t1; + Q[4]:=Q[4]*Q[5]; mul+:=1; + + Fp2_ops:=[Fp2_ops[1]+mul,Fp2_ops[2]+sqr,Fp2_ops[3]+add]; + Prune(~Q); + + return Q,Fp2_ops; + +end function; + +/* +Function converts Q from representation R2 to R4. See Tables 2 and 3. +*/ +R2toR4:=function(Q,Fp2_ops) + + mul:=0; sqr:=0; add:=0; + + t1:=Q[1]-Q[2]; add+:=1; + Q[2]:=Q[1]+Q[2]; add+:=1; + Q[1]:=t1; + + Fp2_ops:=[Fp2_ops[1]+mul,Fp2_ops[2]+sqr,Fp2_ops[3]+add]; + Prune(~Q); + + return Q,Fp2_ops; + +end function; + +/* +The DBL function on E. Only needs the (X,Y,Z) coordinates of input, +but outputs points in R1 as (X,Y,Z,Ta,Tb). See Section 5.3. +*/ +DBL:=function(Q,Fp2_ops) + + mul:=0; sqr:=0; add:=0; + + t1:=Q[1]^2; sqr+:=1; + t2:=Q[2]^2; sqr+:=1; + Q[1]:=Q[1]+Q[2]; add+:=1; + T1b:=t1+t2; add+:=1; + t1:=t2-t1; add+:=1; + t2:=Q[3]^2; sqr+:=1; + T1a:=Q[1]^2; sqr+:=1; + T1a:=T1a-T1b; add+:=1; + t2:=t2+t2; add+:=1; + t2:=t2-t1; add+:=1; + Q[2]:=t1*T1b; mul+:=1; + Q[1]:=t2*T1a; mul+:=1; + Q[3]:=t1*t2; mul+:=1; + + Fp2_ops:=[Fp2_ops[1]+mul,Fp2_ops[2]+sqr,Fp2_ops[3]+add]; + + return [Q[1],Q[2],Q[3],T1a,T1b],Fp2_ops; + +end function; + +/* +The ADD_core function on E. Takes Q in R3 and R in R2 and returns Q+R in R1. See Table 3. +*/ +ADD_core:=function(Q,R,Fp2_ops) + + mul:=0; sqr:=0; add:=0; + + Z3:=Q[4]*R[4]; mul+:=1; + t1:=Q[3]*R[3]; mul+:=1; + X3:=Q[1]*R[1]; mul+:=1; + Y3:=Q[2]*R[2]; mul+:=1; + t2:=t1-Z3; add+:=1; + t1:=t1+Z3; add+:=1; + T3b:=X3-Y3; add+:=1; + T3a:=X3+Y3; add+:=1; + X3:=T3b*t2; mul+:=1; + Z3:=t1*t2; mul+:=1; + Y3:=T3a*t1; mul+:=1; + + Fp2_ops:=[Fp2_ops[1]+mul,Fp2_ops[2]+sqr,Fp2_ops[3]+add]; + + return [X3,Y3,Z3,T3a,T3b],Fp2_ops; + +end function; + +/* +The ADD function on E. Takes Q in R1 and R in R2 and returns Q+R in R1. See Table 3. +*/ +ADD:=function(Q,R,Fp2_ops) + + Q,Fp2_ops:=R1toR3(Q,Fp2_ops); + return ADD_core(Q,R,Fp2_ops); + +end function; + +/* +This function is called every time an element from the lookup table is accessed. +In the actual C code we use masking to select between Q and -Q(=R), both in R2. +*/ +negate_and_select:=function(Q,mask,Fp2_ops) + + R:=[Q[2],Q[1],Q[3],-Q[4]]; + Fp2_ops:=[Fp2_ops[1],Fp2_ops[2],Fp2_ops[3]+1]; + + if mask eq -1 then + return R,Fp2_ops; + else + return Q,Fp2_ops; + end if; + +end function; + +/* +This is just the generic scalar multiplication used for testing, and for cofactor +killing to make sure the input point is of order N. +*/ +GenericScalarMult:=function(P,k) + + Fp2_ops:=[0,0,0]; // Just for synching input/output + + if k eq 0 then + return P; + else + + bits:=IntegerToSequence(k,2); + Q:=[P[1],P[2],1,P[1],P[2]]; + P:=R1toR2([P[1],P[2],1,P[1],P[2]],Fp2_ops); + + for i:=#bits-1 to 1 by -1 do + Q,Fp2_ops:=DBL(Q,Fp2_ops); + if bits[i] eq 1 then + Q,Fp2_ops:=ADD(Q,P,Fp2_ops); + end if; + end for; + + return Q; + + end if; + +end function; + +/* +Generate a random point T of order N on E. +*/ +RandomNTorstionPoint:=function() + + _:=PolynomialRing(Fp2); + repeat X:=Random(Fp2); + until HasRoot(-X^2+Y^2-(1+d*X^2*Y^2)); + _,Y:=HasRoot(-X^2+Y^2-(1+d*X^2*Y^2)); + + T:=GenericScalarMult(E![X,Y],392); + + return T; + +end function; + +/* +THE MAPS: The four maps needed for our endomorphisms: tau, tau_dual, delphidel + and delpsidel. +*/ + +/* +tau: E -> Ehat +Input: P on E in homogeneous coordinates +Output: tau(P) on Ehat in homogeneous coordinates +*/ + +tau:=function(P,Fp2_ops) + + Prune(~P); Prune(~P); + mul:=0; sqr:=0; add:=0; + + t0:=P[1]^2; sqr+:=1; + t1:=P[2]^2; sqr+:=1; + P[1]:=P[1]*P[2]; mul+:=1; + P[2]:=P[3]^2; sqr+:=1; + P[3]:=t0+t1; add+:=1; + P[2]:=2*P[2]; add+:=1; + t0:=t0-t1; add+:=1; + P[2]:=-P[2]; add+:=1; + P[1]:=P[1]*t0; mul+:=1; + P[2]:=P[2]-t0; add+:=1; + P[1]:=ctau1*P[1]; mul+:=1; + P[2]:=P[2]*P[3]; mul+:=1; + P[3]:=t0*P[3]; mul+:=1; + + Fp2_ops:=[Fp2_ops[1]+mul,Fp2_ops[2]+sqr,Fp2_ops[3]+add]; + + return P, Fp2_ops; + +end function; + + +/* +tau_dual: Ehat -> E +Input: P on Ehat in homogeneous coordinates +Output: tau_dual(P) on E in homogeneous coordinates +*/ + +tau_dual:=function(P,Fp2_ops) + + mul:=0; sqr:=0; add:=0; + + t0:=P[1]^2; sqr+:=1; + Append(~P,P[3]^2); sqr+:=1; + t1:=P[2]^2; sqr+:=1; + P[3]:=2*P[4]; add+:=1; + P[4]:=t1-t0; add+:=1; + t0:=t0+t1; add+:=1; + P[1]:=P[1]*P[2]; mul+:=1; + P[3]:=P[3]-P[4]; add+:=1; + Append(~P,ctaudual1*P[1]); mul+:=1; + P[2]:=P[4]*P[3]; mul+:=1; + P[1]:=P[5]*t0; mul+:=1; + P[3]:=t0*P[3]; mul+:=1; + + Fp2_ops:=[Fp2_ops[1]+mul,Fp2_ops[2]+sqr,Fp2_ops[3]+add]; + + return P, Fp2_ops; + +end function; + +/* +delphidel: Ehat -> Ehat +Input: P on Ehat +Output: delta(phi_W(delta_inv(P))) on Ehat, where delta: W->Ehat and +delta_inv: Ehat->W are isomorphisms and phi_W: W->W is the endomorphism on W. +*/ + +delphidel:=function(P,Fp2_ops) + + mul:=0; sqr:=0; add:=0; + + t4:=P[3]^2; sqr+:=1; + t3:=P[2]*P[3]; mul+:=1; + t0:=t4*cphi4; mul+:=1; + t2:=P[2]^2; sqr+:=1; + t0:=t0+t2; add+:=1; + t1:=t3*cphi3; mul+:=1; + t5:=t0-t1; add+:=1; + t0:=t1+t0; add+:=1; + t0:=t0*P[3]; mul+:=1; + t1:=t3*cphi1; mul+:=1; + t0:=t0*t5; mul+:=1; + t5:=t4*cphi2; mul+:=1; + t5:=t5+t2; add+:=1; + t6:=t1-t5; add+:=1; + t1:=t1+t5; add+:=1; + t6:=t6*t1; mul+:=1; + t6:=cphi0*t6; mul+:=1; + P[1]:=P[1]*t6; mul+:=1; + t6:=t2^2; sqr+:=1; + t2:=t3^2; sqr+:=1; + t3:=t4^2; sqr+:=1; + t1:=t2*cphi8; mul+:=1; + t5:=t3*cphi9; mul+:=1; + t1:=t1+t6; add+:=1; + t2:=t2*cphi6; mul+:=1; + t3:=t3*cphi7; mul+:=1; + t1:=t1+t5; add+:=1; + t2:=t2+t3; add+:=1; + t1:=P[2]*t1; mul+:=1; + P[2]:=t2+t6; add+:=1; + P[1]:=P[1]*t1; mul+:=1; + P[2]:=cphi5*P[2]; mul+:=1; + P[1]:=P[1]^p; add+:=1/2; + P[2]:=P[2]*P[3]; mul+:=1; + P[3]:=t0*t1; mul+:=1; + P[2]:=P[2]*t0; mul+:=1; + P[3]:=P[3]^p; add+:=1/2; + P[2]:=P[2]^p; add+:=1/2; + + Fp2_ops:=[Fp2_ops[1]+mul,Fp2_ops[2]+sqr,Fp2_ops[3]+add]; + + return P, Fp2_ops; + +end function; + +/* +delpsidel: Ehat -> Ehat +Input: P on Ehat +Output: delta(psi_W(delta_inv(P))) on Ehat, where delta: W->Ehat and +delta_inv: Ehat->W are isomorphisms and psi_W: W->W is the endomorphism on W. +*/ + +delpsidel:=function(P,Fp2_ops) + + mul:=0; sqr:=0; add:=0; + + P[1]:=P[1]^p; add+:=1/2; + P[3]:=P[3]^p; add+:=1/2; + P[2]:=P[2]^p; add+:=1/2; + t2:=P[3]^2; sqr+:=1; + t0:=P[1]^2; sqr+:=1; + P[1]:=P[1]*t2; mul+:=1; + P[3]:=t2*cpsi2; mul+:=1; + t1:=t2*cpsi3; mul+:=1; + t2:=t2*cpsi4; mul+:=1; + P[3]:=t0+P[3]; add+:=1; + t2:=t0+t2; add+:=1; + t1:=t0+t1; add+:=1; + t2:=-t2; add+:=1; + P[3]:=P[2]*P[3]; mul+:=1; + P[1]:=P[1]*t2; mul+:=1; + P[2]:=P[3]*t1; mul+:=1; + P[1]:=P[1]*cpsi1; mul+:=1; + P[3]:=P[3]*t2; mul+:=1; + + Fp2_ops:=[Fp2_ops[1]+mul,Fp2_ops[2]+sqr,Fp2_ops[3]+add]; + + return P, Fp2_ops; + +end function; + +/* +phi: E -> E +Input: P on E +Output: phi(P) on E +*/ + +phi:=function(P,Fp2_ops); + + P,Fp2_ops:=tau(P,Fp2_ops); + P,Fp2_ops:=delphidel(P,Fp2_ops); + P,Fp2_ops:=tau_dual(P,Fp2_ops); + + return P,Fp2_ops; + +end function; + +/* +psi: E -> E +Input: P on E +Output: psi(P) on E +*/ + +psi:=function(P,Fp2_ops); + + P,Fp2_ops:=tau(P,Fp2_ops); + P,Fp2_ops:=delpsidel(P,Fp2_ops); + P,Fp2_ops:=tau_dual(P,Fp2_ops); + + return P,Fp2_ops; + +end function; + + +/* +The decomposition described in Proposition 5. The "if" and "while" statements +at the end of the function are for simplicity in Magma. In the C code the "if" +statement is turned into a constant-time masking and the "while" statements +are not necessary. +Input: the integer scalar m in [0,2^256) +Output: the multiscalar (a1,a2,a3,a4) described in Proposition 5. +*/ + +decomposition:=function(m) + + alpha1:=Floor(ell1*m/mu); + alpha2:=Floor(ell2*m/mu); + alpha3:=Floor(ell3*m/mu); + alpha4:=Floor(ell4*m/mu); + + t0:=alpha1*b11; + a1:=m-t0; + t0:=alpha2*b21; + a1:=a1-t0; + t0:=alpha3*b31; + a1:=a1-t0; + t0:=alpha4*b41; + a1:=a1-t0; + + a2:=alpha1*b12; + a2:=a2+alpha2; + t0:=alpha3*b32; + a2:=a2-t0; + t0:=alpha4*b42; + a2:=a2-t0; + + a3:=alpha1*b13; + a3:=a3+alpha2; + t0:=alpha3*b33; + a3:=t0-a3; + t0:=alpha4*b43; + a3:=a3+t0; + + a4:=alpha1*b14; + t0:=alpha2*b24; + a4:=a4-t0; + t0:=alpha3*b34; + a4:=a4-t0; + t0:=alpha4*b44; + a4:=a4+t0; + + a1:=a1+c1; + a2:=a2+c2; + a3:=a3+c3; + a4:=a4+c4; + + a1hat:=a1+b41; + a2hat:=a2+b42; + a3hat:=a3-b43; + a4hat:=a4-b44; + + if IsEven(a1) then + a1:=a1hat; a2:=a2hat; a3:=a3hat; a4:=a4hat; + end if; + + a1:=IntegerToSequence(a1,2); + a2:=IntegerToSequence(a2,2); + a3:=IntegerToSequence(a3,2); + a4:=IntegerToSequence(a4,2); + + // Padding + while #a1 ne 65 do Append(~a1,0); end while; + while #a2 ne 65 do Append(~a2,0); end while; + while #a3 ne 65 do Append(~a3,0); end while; + while #a4 ne 65 do Append(~a4,0); end while; + + return a1,a2,a3,a4; + +end function; + +/* +The recoding described in Algorithm 1. The "if" statements are for + simplicity in Magma. In the C code the "if" statement are turned into constant-time maskings. +Input: the multiscalar (a1,a2,a3,a4) output from the decomposition function above. +Output: the indexes (d0,...,d64) and sign masks (m0,...,m64) +*/ +recode:=function(a1,a2,a3,a4) + + a:=[a1,a2,a3,a4]; + b:=[[0: i in [1..65]]: j in [1..4]]; + + b[1][65]:=1; + + for i:=1 to 65 do + if i ne 65 then + b[1][i]:=2*a[1][i+1]-1; + end if; + for j:=2 to 4 do + b[j][i]:=b[1][i]*a[j][1]; + aj:=SequenceToInteger(a[j],2); + aj:=Floor(aj div 2)-Floor(b[j][i] div 2); + if aj ne 0 then + a[j]:=IntegerToSequence(aj,2); + else + a[j]:=[0]; + end if; + end for; + end for; + + m:=b[1]; + d:=[]; + for i:=1 to 65 do + Append(~d,SequenceToInteger([Abs(b[2][i]),Abs(b[3][i]),Abs(b[4][i])],2)+1); + end for; + + return m,d; + +end function; + +/* +Building the lookup table as described in Section 5.2 and the proof of Theorem 1. +input: P, phi(P), psi(P) and psi(phi(P)) +output: the lookup table of size 8 +*/ +lookup_table:=function(P,phiP,psiP,psiphiP,Fp2_ops) + + T:=[]; + Append(~T,[P[1],P[2],P[3],P[4]]); //T[1] + + t0,Fp2_ops:=ADD_core(phiP,T[1],Fp2_ops); + t0,Fp2_ops:=R1toR2(t0,Fp2_ops); + Append(~T,t0); //T[2] + + t0,Fp2_ops:=ADD_core(psiP,T[1],Fp2_ops); + t0,Fp2_ops:=R1toR2(t0,Fp2_ops); + Append(~T,t0); //T[3] + + t0,Fp2_ops:=ADD_core(psiP,T[2],Fp2_ops); + t0,Fp2_ops:=R1toR2(t0,Fp2_ops); + Append(~T,t0); //T[4] + + t0,Fp2_ops:=ADD_core(psiphiP,T[1],Fp2_ops); + t0,Fp2_ops:=R1toR2(t0,Fp2_ops); + Append(~T,t0); //T[5] + + t0,Fp2_ops:=ADD_core(psiphiP,T[2],Fp2_ops); + t0,Fp2_ops:=R1toR2(t0,Fp2_ops); + Append(~T,t0); //T[6] + + t0,Fp2_ops:=ADD_core(psiphiP,T[3],Fp2_ops); + t0,Fp2_ops:=R1toR2(t0,Fp2_ops); + Append(~T,t0); //T[7] + + t0,Fp2_ops:=ADD_core(psiphiP,T[4],Fp2_ops); + t0,Fp2_ops:=R1toR2(t0,Fp2_ops); + Append(~T,t0); //T[8] + + return T,Fp2_ops; + +end function; + +/* +The regular four-dimensional scalar multiplication described in Algorithm 2. +*/ +scalar_multiplication:=function(P,m) + + Fp2_ops:=[0,0,0]; + + // Step 1 - Compute endomorphisms: + phiP,Fp2_ops:=phi(P,Fp2_ops); + psiP,Fp2_ops:=psi(P,Fp2_ops); + psiphiP,Fp2_ops:=psi(phiP,Fp2_ops); + + // Step 2 - Precompute lookup table: + P,Fp2_ops:=R1toR2(P,Fp2_ops); + phiP,Fp2_ops:=R1toR3(phiP,Fp2_ops); + psiP,Fp2_ops:=R1toR3(psiP,Fp2_ops); + psiphiP,Fp2_ops:=R1toR3(psiphiP,Fp2_ops); + T,Fp2_ops:=lookup_table(P,phiP,psiP,psiphiP,Fp2_ops); + + // Step 3 - Scalar decomposition: + a1,a2,a3,a4:=decomposition(m); + + // Step 4 - Scalar recoding: + masks,indexes:=recode(a1,a2,a3,a4); + + // Step 5 - Initialize + Q:=T[indexes[65]]; + Q,Fp2_ops:=negate_and_select(Q,masks[65],Fp2_ops); + Q,Fp2_ops:=R2toR4(Q,Fp2_ops); + + // Steps 6,7,8 - Main loop: + for i:=64 to 1 by -1 do + Q,Fp2_ops:=DBL(Q,Fp2_ops); + Ti:=T[indexes[i]]; + Ti,Fp2_ops:=negate_and_select(Ti,masks[i],Fp2_ops); + Q,Fp2_ops:=ADD(Q,Ti,Fp2_ops); + end for; + + // Step 9 - Normalize output: + Q[3]:=1/Q[3]; + Q[1]:=Q[1]*Q[3]; Fp2_ops[1]+:=1; + Q[2]:=Q[2]*Q[3]; Fp2_ops[1]+:=1; + + return E![Q[1],Q[2]],Fp2_ops; + +end function; + + +// Testing and illustrating the operation count in Theorem 1. + +while true do + + P:=RandomNTorstionPoint(); + m:=Random(0,mu-1); + + mP:=GenericScalarMult(E![P[1]/P[3],P[2]/P[3]],m); + compare:=E![mP[1]/mP[3],mP[2]/mP[3]]; + + Q,Fp2_ops:=scalar_multiplication(P,m); + + if (Q eq compare) then + "PASSED: ", 1, "Fp2 invs", Fp2_ops[1], "Fp2 muls", Fp2_ops[2], "Fp2 sqrs", Fp2_ops[3], "Fp2 add"; + else + "FAILED"; break; + end if; + +end while; + diff --git a/FourQ_ARM_NEON/ARM/fp2_1271_NEON.c b/FourQ_ARM_NEON/ARM/fp2_1271_NEON.c new file mode 100644 index 0000000..873b13f --- /dev/null +++ b/FourQ_ARM_NEON/ARM/fp2_1271_NEON.c @@ -0,0 +1,1746 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: arithmetic over GF(p) and GF(p^2) using ARM/NEON inlined assembly +************************************************************************************/ + +#include "../FourQ_internal.h" + + +void v2mul1271_a(uint32_t* a, uint32_t* b, uint32_t* c) +{ // Multiplication over GF((2^127-1)^2) using NEON instructions + // Operation: c [r3] = a [r1] * b [r2] + // Representation: 23/23/26/26/26/26/26/26/26/26-bit + +asm volatile( + // q0-q2[0] <- A0|A1, q3-q5[0] <- B0|B1 + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2,d3}, [%0]! \n\t" + "vld1.8 {d4}, [%0]! \n\t" +#if defined(INTERLEAVE) + "vshl.i32 q6, q0, #3 \n\t" // q6-q7 = 8*(a0->a8) + "vpush {q4-q7} \n\t" + "vld1.8 {d6,d7}, [%1]! \n\t" + "vshl.i32 d5, d4, #3 \n\t" // q2[1] = 8*(a4|a9) + "vld1.8 {d8,d9}, [%1]! \n\t" + "vshl.i32 q7, q1, #3 \n\t" + "vld1.8 {d10}, [%1]! \n\t" +#else + "vshl.i32 q6, q0, #3 \n\t" // q6-q7 = 8*(a0->a8) + "vld1.8 {d6,d7}, [%1]! \n\t" + "vpush {q4-q7} \n\t" + "vld1.8 {d8,d9}, [%1]! \n\t" + "vld1.8 {d10}, [%1]! \n\t" + "vshl.i32 d5, d4, #3 \n\t" // q2[1] = 8*(a4|a9) + "vshl.i32 q7, q1, #3 \n\t" +#endif + + // q11-q15 <- A0*B0|A0*B1, q8-q10 <- A1*B0|A1*B1 + "vmull.s32 q8, d6, d0[1] \n\t" // q8 = a5*b0 | a5*b5 + "vmlal.s32 q8, d10, d13[1] \n\t" // q8 = a5*b0 + 8*(a6*b4) | a5*b5 + 8*(a6*b9) + "vmlal.s32 q8, d7, d5[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1) | a5*b5 + 8*(a6*b9 + a9*b6) + "vmlal.s32 q8, d9, d14[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1 + a7*b3) | a5*b5 + 8*(a6*b9 + a9*b6 + a7*b8) + "vmlal.s32 q8, d8, d15[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1 + a7*b3 + a8*b2) | a5*b5 + 8*(a6*b9 + a9*b6 + a7*b8 + a8*b7) + "vmull.s32 q9, d7, d0[1] \n\t" // q9 = a5*b1 | a5*b6 + "vmlal.s32 q9, d6, d1[1] \n\t" // q9 = a5*b1 + a6*b0 | a5*b6 + a6*b5 + "vmlal.s32 q9, d10, d14[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4) | a5*b6 + a6*b5 + 8*(a7*b9) + "vmlal.s32 q9, d8, d5[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4 + a9*b2) | a5*b6 + a6*b5 + 8*(a7*b9 + a9*b7) + "vmlal.s32 q9, d9, d15[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4 + a9*b2 + a8*b3) | a5*b6 + a6*b5 + 8*(a7*b9 + a9*b7 + a8*b8) + "vmull.s32 q10, d8, d0[1] \n\t" // q10 = a5*b2 | a5*b7 + "vmlal.s32 q10, d6, d2[1] \n\t" // q10 = a5*b2 + a7*b0 | a5*b7 + a7*b5 + "vmlal.s32 q10, d7, d1[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 | a5*b7 + a7*b5 + a6*b6 + "vmlal.s32 q10, d10, d15[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 + 8*(a8*b4) | a5*b7 + a7*b5 + a6*b6 + 8*(a8*b9) + "vmlal.s32 q10, d9, d5[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 + 8*(a8*b4 + a9*b3) | a5*b7 + a7*b5 + a6*b6 + 8*(a8*b9 + a9*b8) + + "vmull.s32 q11, d6, d0[0] \n\t" // q11 = a0*b0 | a0*b5 + "vmlal.s32 q11, d10, d13[0] \n\t" // q11 = a0*b0 + 8*(a1*b4) | a0*b5 + 8*(a1*b9) + "vmlal.s32 q11, d7, d5[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1) | a0*b5 + 8*(a1*b9 + a4*b6) + "vmlal.s32 q11, d9, d14[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8) + "vmlal.s32 q11, d8, d15[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3 + a3*b2) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8 + a3*b7) + "vmull.s32 q12, d7, d0[0] \n\t" // q12 = a0*b1 | a0*b6 + "vmlal.s32 q12, d6, d1[0] \n\t" // q12 = a0*b1 + a1*b0 | a0*b6 + a1*b5 + "vmlal.s32 q12, d10, d14[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4) | a0*b6 + a1*b5 + 8*(a2*b9) + "vmlal.s32 q12, d8, d5[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7) + "vmlal.s32 q12, d9, d15[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2 + a3*b3) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7 + a3*b8) + "vmull.s32 q13, d8, d0[0] \n\t" // q13 = a0*b2 | a0*b7 + "vmlal.s32 q13, d6, d2[0] \n\t" // q13 = a0*b2 + a2*b0 | a0*b7 + a2*b5 + "vmlal.s32 q13, d7, d1[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 | a0*b7 + a2*b5 + a1*b6 + "vmlal.s32 q13, d10, d15[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9) + "vmlal.s32 q13, d9, d5[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4 + a4*b3) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9 + a4*b8) + "vmull.s32 q14, d9, d0[0] \n\t" // q14 = a0*b3 | a0*b8 + "vmlal.s32 q14, d6, d3[0] \n\t" // q14 = a0*b3 + a3*b0 | a0*b8 + a3*b5 + "vmlal.s32 q14, d8, d1[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 | a0*b8 + a3*b5 + a1*b7 + "vmlal.s32 q14, d7, d2[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 | a0*b8 + a3*b5 + a1*b7 + a2*b6 + "vmlal.s32 q14, d10, d5[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 + 8*(a4*b4) | a0*b8 + a3*b5 + a1*b7 + a2*b6 + 8*(a4*b9) + "vmull.s32 q15, d10, d0[0] \n\t" // q15 = a0*b4 | a0*b9 + "vmlal.s32 q15, d6, d4[0] \n\t" // q15 = a0*b4 + a4*b0 | a0*b9 + a4*b5 + "vmlal.s32 q15, d9, d1[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 | a0*b9 + a4*b5 + a1*b8 + "vmlal.s32 q15, d7, d3[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + "vmlal.s32 q15, d8, d2[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 + a2*b2 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + a2*b7 + + // q11[0]->q13[0] = A0*B0 - A1*B1, q11[1]->q13[1] = A0*B0 + A1*B1 + "vsub.s64 d22, d22, d17 \n\t" + "vsub.s64 d24, d24, d19 \n\t" + "vsub.s64 d26, d26, d21 \n\t" + "vadd.s64 d23, d23, d16 \n\t" + "vadd.s64 d25, d25, d18 \n\t" + "vadd.s64 d27, d27, d20 \n\t" + "vshr.s64 q10, q11, #26 \n\t" /// + + // Complete computation A1*B0|A1*B1, q8-q9 <- A1*B0|A1*B1 + "vmull.s32 q8, d9, d0[1] \n\t" // q8 = a5*b3 | a5*b8 + "vmlal.s32 q8, d6, d3[1] \n\t" // q8 = a5*b3 + a8*b0 | a5*b8 + a8*b5 + "vmlal.s32 q8, d8, d1[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 | a5*b8 + a8*b5 + a6*b7 + "vmlal.s32 q8, d7, d2[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 + a7*b1 | a5*b8 + a8*b5 + a6*b7 + a7*b6 + "vmlal.s32 q8, d10, d5[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 + a7*b1 + 8*(a9*b4) | a5*b8 + a8*b5 + a6*b7 + a7*b6 + 8*(a9*b9) + "vmull.s32 q9, d10, d0[1] \n\t" // q9 = a5*b4 | a5*b9 + "vmlal.s32 q9, d6, d4[1] \n\t" // q9 = a5*b4 + a9*b0 | a5*b9 + a9*b5 + "vmlal.s32 q9, d9, d1[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 | a5*b9 + a9*b5 + a6*b8 + "vmlal.s32 q9, d7, d3[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 + a8*b1 | a5*b9 + a9*b5 + a6*b8 + a8*b6 + "vmlal.s32 q9, d8, d2[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 + a8*b1 + a7*b2 | a5*b9 + a9*b5 + a6*b8 + a8*b6 + a7*b7 + "vadd.s64 q10, q12, q10 \n\t" /// + + // Complete q14[0]->q15[0] = A0*B0 - A1*B1, q14[1]->q15[0] = A0*B1 + A1*B0 + "vmov.i64 q7, 0xFFFFFFFF \n\t" // mask_26 + "vadd.s64 d29, d29, d16 \n\t" + "vsub.s64 d28, d28, d17 \n\t" + "vshr.s64 q8, q10, #26 \n\t" /// + "vadd.s64 d31, d31, d18 \n\t" + "vadd.s64 q8, q13, q8 \n\t" /// + "vsub.s64 d30, d30, d19 \n\t" + + // Reduction + "vshr.s64 q9, q8, #26 \n\t" + "vshr.u64 q7, q7, #6 \n\t" + "vadd.s64 q9, q14, q9 \n\t" + "vand.u64 q1, q10, q7 \n\t" + "vand.u64 q0, q11, q7 \n\t" + "vshr.s64 q10, q9, #26 \n\t" + "vand.u64 q2, q8, q7 \n\t" + "vadd.s64 q10, q15, q10 \n\t" + "vshr.u64 q6, q7, #3 \n\t" // mask_23 + "vand.u64 q3, q9, q7 \n\t" + "vshr.s64 q8, q10, #23 \n\t" + "vand.u64 q11, q10, q6 \n\t" + "vand.u64 q12, q8, q7 \n\t" + "vshr.s64 q6, q8, #26 \n\t" + "vadd.s64 q0, q0, q12 \n\t" + "vadd.s64 q1, q1, q6 \n\t" + "vst2.32 {d0[0],d1[0]}, [%2]! \n\t" + "vst2.32 {d2[0],d3[0]}, [%2]! \n\t" +#if defined(INTERLEAVE) + "vpop {q4-q7} \n\t" +#endif + "vst2.32 {d4[0],d5[0]}, [%2]! \n\t" + "vst2.32 {d6[0],d7[0]}, [%2]! \n\t" + "vst2.32 {d22[0],d23[0]}, [%2]! \n\t" +#if !defined(INTERLEAVE) + "vpop {q4-q7} \n\t" +#endif + : + :"r"(&a[0]), "r"(&b[0]), "r"(&c[0]) + ); + return; +} + + +void v2sqr1271_a(uint32_t* a, uint32_t* c) +{ // Squaring over GF((2^127-1)^2) using NEON instructions + // Operation: c = a^2 in GF((2^127-1)^2) + // Representation: 23/23/26/26/26/26/26/26/26/26-bit + +asm volatile( + // q0-q2[0] <- A0|A1 + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2,d3}, [%0]! \n\t" +#if defined(INTERLEAVE) + "vshr.u64 q3, q0, #32 \n\t" // q3-q5[0] = (0|a9->0|a5) + "vld1.8 {d4}, [%0]! \n\t" + "vpush {q4-q7} \n\t" + "vmov.i64 q8, 0xFFFFFFFF \n\t" // mask_26 +#else + "vld1.8 {d4}, [%0]! \n\t" + "vpush {q4-q7} \n\t" + "vmov.i64 q8, 0xFFFFFFFF \n\t" // mask_26 + "vshr.u64 q3, q0, #32 \n\t" // q3-q5[0] = (0|a9->0|a5) +#endif + "vshr.u64 q4, q1, #32 \n\t" + "vshr.u64 d10, d4, #32 \n\t" + "vsub.s32 q13, q0, q3 \n\t" // q13-q15[0] = (a9|a4-a9->a5|a0-a5) + "vsub.s32 q14, q1, q4 \n\t" + "vsub.s32 d30, d4, d10 \n\t" + "vadd.s32 q3, q0, q3 \n\t" // q3-q5[0] = (a9|a4+a9->a5|a0+a5) + "vadd.s32 q4, q1, q4 \n\t" + "vadd.s32 d10, d4, d10 \n\t" + "vshl.i64 q0, q0, #33 \n\t" // q0-q2[0] = (2*a4|0->2*a0|0) + "vshl.i64 q1, q1, #33 \n\t" + "vshl.i64 d4, d4, #33 \n\t" + "vbit q0, q13, q8 \n\t" // q0-q2[0] = (2*a4|a4-a9->2*a0|a0-a5) + "vbit q1, q14, q8 \n\t" + "vbit d4, d30, d16 \n\t" + "vshl.i32 q6, q0, #3 \n\t" // 8*(2*a4|a4-a9->2*a0|a0-a5) + "vshl.i32 q7, q1, #3 \n\t" + "vshl.i32 d5, d4, #3 \n\t" + + // q11-q15 <- 2*A0*B0|(A0+A1)*(A0-A1) + "vmull.s32 q11, d6, d0 \n\t" // q11 = a0*b0 | a0*b5 + "vmlal.s32 q11, d10, d13 \n\t" // q11 = a0*b0 + 8*(a1*b4) | a0*b5 + 8*(a1*b9) + "vmlal.s32 q11, d7, d5 \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1) | a0*b5 + 8*(a1*b9 + a4*b6) + "vmlal.s32 q11, d9, d14 \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8) + "vmlal.s32 q11, d8, d15 \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3 + a3*b2) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8 + a3*b7) + "vmull.s32 q12, d7, d0 \n\t" // q12 = a0*b1 | a0*b6 + "vmlal.s32 q12, d6, d1 \n\t" // q12 = a0*b1 + a1*b0 | a0*b6 + a1*b5 + "vmlal.s32 q12, d10, d14 \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4) | a0*b6 + a1*b5 + 8*(a2*b9) + "vmlal.s32 q12, d8, d5 \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7) + "vmlal.s32 q12, d9, d15 \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2 + a3*b3) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7 + a3*b8) + "vmull.s32 q13, d8, d0 \n\t" // q13 = a0*b2 | a0*b7 + "vmlal.s32 q13, d6, d2 \n\t" // q13 = a0*b2 + a2*b0 | a0*b7 + a2*b5 + "vmlal.s32 q13, d7, d1 \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 | a0*b7 + a2*b5 + a1*b6 + "vmlal.s32 q13, d10, d15 \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9) + "vmlal.s32 q13, d9, d5 \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4 + a4*b3) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9 + a4*b8) + "vshr.s64 q10, q11, #26 \n\t" /// + "vmull.s32 q14, d9, d0 \n\t" // q14 = a0*b3 | a0*b8 + "vadd.s64 q10, q12, q10 \n\t" /// + "vmlal.s32 q14, d6, d3 \n\t" // q14 = a0*b3 + a3*b0 | a0*b8 + a3*b5 + "vmlal.s32 q14, d8, d1 \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 | a0*b8 + a3*b5 + a1*b7 + "vmlal.s32 q14, d7, d2 \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 | a0*b8 + a3*b5 + a1*b7 + a2*b6 + "vmlal.s32 q14, d10, d5 \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 + 8*(a4*b4) | a0*b8 + a3*b5 + a1*b7 + a2*b6 + 8*(a4*b9) + "vmull.s32 q15, d10, d0 \n\t" // q15 = a0*b4 | a0*b9 + "vshr.s64 q5, q10, #26 \n\t" /// + "vmlal.s32 q15, d6, d4 \n\t" // q15 = a0*b4 + a4*b0 | a0*b9 + a4*b5 + "vadd.s64 q5, q13, q5 \n\t" /// + "vmlal.s32 q15, d9, d1 \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 | a0*b9 + a4*b5 + a1*b8 + "vmlal.s32 q15, d7, d3 \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + "vmlal.s32 q15, d8, d2 \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 + a2*b2 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + a2*b7 + + // Reduction + "vshr.s64 q9, q5, #26 \n\t" + "vshr.u64 q8, q8, #6 \n\t" + "vadd.s64 q9, q14, q9 \n\t" + "vand.u64 q1, q10, q8 \n\t" + "vand.u64 q0, q11, q8 \n\t" + "vshr.s64 q10, q9, #26 \n\t" + "vand.u64 q2, q5, q8 \n\t" + "vadd.s64 q10, q15, q10 \n\t" + "vshr.u64 q6, q8, #3 \n\t" // mask_23 + "vshr.s64 q5, q10, #23 \n\t" + "vand.u64 q3, q9, q8 \n\t" + "vand.u64 q11, q10, q6 \n\t" + "vand.u64 q12, q5, q8 \n\t" + "vshr.s64 q6, q5, #26 \n\t" + "vadd.s64 q0, q0, q12 \n\t" + "vadd.s64 q1, q1, q6 \n\t" + "vst2.32 {d0[0],d1[0]}, [%1]! \n\t" + "vst2.32 {d2[0],d3[0]}, [%1]! \n\t" +#if defined(INTERLEAVE) + "vpop {q4-q7} \n\t" +#endif + "vst2.32 {d4[0],d5[0]}, [%1]! \n\t" + "vst2.32 {d6[0],d7[0]}, [%1]! \n\t" + "vst2.32 {d22[0],d23[0]}, [%1]! \n\t" +#if !defined(INTERLEAVE) + "vpop {q4-q7} \n\t" +#endif + : + :"r"(&a[0]), "r"(&c[0]) + ); + return; +} + + +#if defined(MIX_ARM_NEON) + +void v2muladdsub1271_a(uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d, uint32_t* e, uint32_t* f, uint32_t* g) +{ // Multiplication/addition over GF((2^127-1)^2) combining ARM and NEON instructions + // Operation: c = a * b, f = d + e, g = d - e in GF((2^127-1)^2) + // Representation: 23/23/26/26/26/26/26/26/26/26-bit + +asm volatile( + // q0-q2[0] <- A0|A1, q3-q5[0] <- B0|B1 + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2,d3}, [%0]! \n\t" + "vld1.8 {d4}, [%0]! \n\t" + "vshl.i32 q6, q0, #3 \n\t" // q6-q7 = 8*(a0->a8) + "vpush {q4-q7} \n\t" + "vld1.8 {d6,d7}, [%1]! \n\t" + "vshl.i32 d5, d4, #3 \n\t" // q2[1] = 8*(a4|a9) + "vld1.8 {d8,d9}, [%1]! \n\t" + "vshl.i32 q7, q1, #3 \n\t" + "vld1.8 {d10}, [%1]! \n\t" + + // q11-q15 <- A0*B0|A0*B1, q8-q10 <- A1*B0|A1*B1 + "vmull.s32 q8, d6, d0[1] \n\t" // q8 = a5*b0 | a5*b5 + "vmlal.s32 q8, d10, d13[1] \n\t" // q8 = a5*b0 + 8*(a6*b4) | a5*b5 + 8*(a6*b9) + "vmlal.s32 q8, d7, d5[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1) | a5*b5 + 8*(a6*b9 + a9*b6) + "vmlal.s32 q8, d9, d14[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1 + a7*b3) | a5*b5 + 8*(a6*b9 + a9*b6 + a7*b8) + "vmlal.s32 q8, d8, d15[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1 + a7*b3 + a8*b2) | a5*b5 + 8*(a6*b9 + a9*b6 + a7*b8 + a8*b7) + "vmull.s32 q9, d7, d0[1] \n\t" // q9 = a5*b1 | a5*b6 + "vmlal.s32 q9, d6, d1[1] \n\t" // q9 = a5*b1 + a6*b0 | a5*b6 + a6*b5 + "vmlal.s32 q9, d10, d14[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4) | a5*b6 + a6*b5 + 8*(a7*b9) + "vmlal.s32 q9, d8, d5[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4 + a9*b2) | a5*b6 + a6*b5 + 8*(a7*b9 + a9*b7) + "vmlal.s32 q9, d9, d15[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4 + a9*b2 + a8*b3) | a5*b6 + a6*b5 + 8*(a7*b9 + a9*b7 + a8*b8) + "vmull.s32 q10, d8, d0[1] \n\t" // q10 = a5*b2 | a5*b7 + "vmlal.s32 q10, d6, d2[1] \n\t" // q10 = a5*b2 + a7*b0 | a5*b7 + a7*b5 + "vmlal.s32 q10, d7, d1[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 | a5*b7 + a7*b5 + a6*b6 + "vmlal.s32 q10, d10, d15[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 + 8*(a8*b4) | a5*b7 + a7*b5 + a6*b6 + 8*(a8*b9) + "vmlal.s32 q10, d9, d5[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 + 8*(a8*b4 + a9*b3) | a5*b7 + a7*b5 + a6*b6 + 8*(a8*b9 + a9*b8) + + "push {r7-r12} \n\t" + "ldm %3!, {r7,r8} \n\t" //***** + "ldm %4!, {r9,r10} \n\t" //***** + "add r11, r7, r9 \n\t" //***** + "add r12, r8, r10 \n\t" //***** + "sub r7, r9 \n\t" //***** + "sub r8, r10 \n\t" //***** + "stm %5!, {r11,r12} \n\t" //***** + "stm %6!, {r7,r8} \n\t" //***** + + "vmull.s32 q11, d6, d0[0] \n\t" // q11 = a0*b0 | a0*b5 + "vmlal.s32 q11, d10, d13[0] \n\t" // q11 = a0*b0 + 8*(a1*b4) | a0*b5 + 8*(a1*b9) + "vmlal.s32 q11, d7, d5[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1) | a0*b5 + 8*(a1*b9 + a4*b6) + "vmlal.s32 q11, d9, d14[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8) + "vmlal.s32 q11, d8, d15[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3 + a3*b2) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8 + a3*b7) + "vmull.s32 q12, d7, d0[0] \n\t" // q12 = a0*b1 | a0*b6 + "vmlal.s32 q12, d6, d1[0] \n\t" // q12 = a0*b1 + a1*b0 | a0*b6 + a1*b5 + "vmlal.s32 q12, d10, d14[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4) | a0*b6 + a1*b5 + 8*(a2*b9) + "vmlal.s32 q12, d8, d5[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7) + "vmlal.s32 q12, d9, d15[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2 + a3*b3) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7 + a3*b8) + "vmull.s32 q13, d8, d0[0] \n\t" // q13 = a0*b2 | a0*b7 + "vmlal.s32 q13, d6, d2[0] \n\t" // q13 = a0*b2 + a2*b0 | a0*b7 + a2*b5 + "vmlal.s32 q13, d7, d1[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 | a0*b7 + a2*b5 + a1*b6 + "vmlal.s32 q13, d10, d15[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9) + "vmlal.s32 q13, d9, d5[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4 + a4*b3) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9 + a4*b8) + "vmull.s32 q14, d9, d0[0] \n\t" // q14 = a0*b3 | a0*b8 + "vmlal.s32 q14, d6, d3[0] \n\t" // q14 = a0*b3 + a3*b0 | a0*b8 + a3*b5 + "vmlal.s32 q14, d8, d1[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 | a0*b8 + a3*b5 + a1*b7 + "vmlal.s32 q14, d7, d2[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 | a0*b8 + a3*b5 + a1*b7 + a2*b6 + "vmlal.s32 q14, d10, d5[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 + 8*(a4*b4) | a0*b8 + a3*b5 + a1*b7 + a2*b6 + 8*(a4*b9) + "vmull.s32 q15, d10, d0[0] \n\t" // q15 = a0*b4 | a0*b9 + "vmlal.s32 q15, d6, d4[0] \n\t" // q15 = a0*b4 + a4*b0 | a0*b9 + a4*b5 + "vmlal.s32 q15, d9, d1[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 | a0*b9 + a4*b5 + a1*b8 + "vmlal.s32 q15, d7, d3[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + "vmlal.s32 q15, d8, d2[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 + a2*b2 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + a2*b7 + + "ldm %3!, {r7,r8} \n\t" //***** + "ldm %4!, {r9,r10} \n\t" //***** + "add r11, r7, r9 \n\t" //***** + "add r12, r8, r10 \n\t" //***** + "sub r7, r9 \n\t" //***** + "sub r8, r10 \n\t" //***** + "stm %5!, {r11,r12} \n\t" //***** + "stm %6!, {r7,r8} \n\t" //***** + + // q11[0]->q13[0] = A0*B0 - A1*B1, q11[1]->q13[1] = A0*B0 + A1*B1 + "vsub.s64 d22, d22, d17 \n\t" + "vsub.s64 d24, d24, d19 \n\t" + "vsub.s64 d26, d26, d21 \n\t" + "vadd.s64 d23, d23, d16 \n\t" + "vadd.s64 d25, d25, d18 \n\t" + "vadd.s64 d27, d27, d20 \n\t" + + "ldm %3!, {r7,r8} \n\t" //***** + "ldm %4!, {r9,r10} \n\t" //***** + "add r11, r7, r9 \n\t" //***** + "add r12, r8, r10 \n\t" //***** + "sub r7, r9 \n\t" //***** + "sub r8, r10 \n\t" //***** + "stm %5!, {r11,r12} \n\t" //***** + "stm %6!, {r7,r8} \n\t" //***** + + // Complete computation A1*B0|A1*B1, q8-q9 <- A1*B0|A1*B1 + "vmull.s32 q8, d9, d0[1] \n\t" // q8 = a5*b3 | a5*b8 + "vmlal.s32 q8, d6, d3[1] \n\t" // q8 = a5*b3 + a8*b0 | a5*b8 + a8*b5 + "vmlal.s32 q8, d8, d1[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 | a5*b8 + a8*b5 + a6*b7 + "vmlal.s32 q8, d7, d2[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 + a7*b1 | a5*b8 + a8*b5 + a6*b7 + a7*b6 + "vmlal.s32 q8, d10, d5[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 + a7*b1 + 8*(a9*b4) | a5*b8 + a8*b5 + a6*b7 + a7*b6 + 8*(a9*b9) + "vmull.s32 q9, d10, d0[1] \n\t" // q9 = a5*b4 | a5*b9 + "vmlal.s32 q9, d6, d4[1] \n\t" // q9 = a5*b4 + a9*b0 | a5*b9 + a9*b5 + "vmlal.s32 q9, d9, d1[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 | a5*b9 + a9*b5 + a6*b8 + "vmlal.s32 q9, d7, d3[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 + a8*b1 | a5*b9 + a9*b5 + a6*b8 + a8*b6 + "vmlal.s32 q9, d8, d2[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 + a8*b1 + a7*b2 | a5*b9 + a9*b5 + a6*b8 + a8*b6 + a7*b7 + + "ldm %3!, {r7,r8} \n\t" //***** + "ldm %4!, {r9,r10} \n\t" //***** + "add r11, r7, r9 \n\t" //***** + "add r12, r8, r10 \n\t" //***** + "sub r7, r9 \n\t" //***** + "sub r8, r10 \n\t" //***** + "stm %5!, {r11,r12} \n\t" //***** + "stm %6!, {r7,r8} \n\t" //***** + + // Complete q14[0]->q15[0] = A0*B0 - A1*B1, q14[1]->q15[0] = A0*B1 + A1*B0 + "vmov.i64 q7, 0xFFFFFFFF \n\t" // mask_26 + "vadd.s64 d29, d29, d16 \n\t" + "vsub.s64 d28, d28, d17 \n\t" + "vshr.u64 q7, q7, #6 \n\t" + "vadd.s64 d31, d31, d18 \n\t" + "vsub.s64 d30, d30, d19 \n\t" + + "ldm %3!, {r7,r8} \n\t" //***** + "ldm %4!, {r9,r10} \n\t" //***** + "add r11, r7, r9 \n\t" //***** + "add r12, r8, r10 \n\t" //***** + "sub r7, r9 \n\t" //***** + "sub r8, r10 \n\t" //***** + "stm %5!, {r11,r12} \n\t" //***** + "stm %6!, {r7,r8} \n\t" //***** + "pop {r7-r12} \n\t" + + // Reduction + "vshr.u64 q6, q7, #3 \n\t" // mask_23 + "vshr.s64 q10, q11, #26 \n\t" + "vand.u64 q0, q11, q7 \n\t" + + "vshr.s64 q9, q14, #26 \n\t" + "vand.u64 q3, q14, q7 \n\t" + "vadd.s64 q10, q12, q10 \n\t" + "vadd.s64 q9, q15, q9 \n\t" + "vand.u64 q1, q10, q7 \n\t" + "vand.u64 q11, q9, q6 \n\t" + + "vshr.s64 q10, q10, #26 \n\t" + "vshr.s64 q9, q9, #23 \n\t" + "vadd.s64 q10, q13, q10 \n\t" + "vand.u64 q12, q9, q7 \n\t" + "vand.u64 q2, q10, q7 \n\t" + + "vshr.s64 q10, q10, #26 \n\t" + "vshr.s64 q6, q9, #26 \n\t" + "vadd.s64 q10, q3, q10 \n\t" + "vadd.s64 q0, q0, q12 \n\t" + "vadd.s64 q1, q1, q6 \n\t" + + "vst2.32 {d0[0],d1[0]}, [%2]! \n\t" + "vshr.s64 q9, q10, #26 \n\t" + "vst2.32 {d2[0],d3[0]}, [%2]! \n\t" + "vand.u64 q3, q10, q7 \n\t" + "vst2.32 {d4[0],d5[0]}, [%2]! \n\t" + "vpop {q4-q7} \n\t" + "vadd.s64 q11, q11, q9 \n\t" + "vst2.32 {d6[0],d7[0]}, [%2]! \n\t" + "vst2.32 {d22[0],d23[0]}, [%2]! \n\t" + : + :"r"(&a[0]), "r"(&b[0]), "r"(&c[0]), "r"(&d[0]), "r"(&e[0]), "r"(&f[0]), "r"(&g[0]) + :"memory","r7","r8","r9","r10","r11","r12" + ); + return; +} + + +void v2muladd1271_a(uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d, uint32_t* e, uint32_t* f) +{ // Multiplication/addition over GF((2^127-1)^2) combining ARM and NEON instructions + // Operation: c = a * b, f = d + e in GF((2^127-1)^2) + // Representation: 23/23/26/26/26/26/26/26/26/26-bit + +asm volatile( + // q0-q2[0] <- A0|A1, q3-q5[0] <- B0|B1 + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2,d3}, [%0]! \n\t" + "vld1.8 {d4}, [%0]! \n\t" + "vshl.i32 q6, q0, #3 \n\t" // q6-q7 = 8*(a0->a8) + "vpush {q4-q7} \n\t" + "vld1.8 {d6,d7}, [%1]! \n\t" + "vshl.i32 d5, d4, #3 \n\t" // q2[1] = 8*(a4|a9) + "vld1.8 {d8,d9}, [%1]! \n\t" + "vshl.i32 q7, q1, #3 \n\t" + "vld1.8 {d10}, [%1]! \n\t" + + // q11-q15 <- A0*B0|A0*B1, q8-q10 <- A1*B0|A1*B1 + "vmull.s32 q8, d6, d0[1] \n\t" // q8 = a5*b0 | a5*b5 + "vmlal.s32 q8, d10, d13[1] \n\t" // q8 = a5*b0 + 8*(a6*b4) | a5*b5 + 8*(a6*b9) + "vmlal.s32 q8, d7, d5[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1) | a5*b5 + 8*(a6*b9 + a9*b6) + "vmlal.s32 q8, d9, d14[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1 + a7*b3) | a5*b5 + 8*(a6*b9 + a9*b6 + a7*b8) + "vmlal.s32 q8, d8, d15[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1 + a7*b3 + a8*b2) | a5*b5 + 8*(a6*b9 + a9*b6 + a7*b8 + a8*b7) + "vmull.s32 q9, d7, d0[1] \n\t" // q9 = a5*b1 | a5*b6 + "vmlal.s32 q9, d6, d1[1] \n\t" // q9 = a5*b1 + a6*b0 | a5*b6 + a6*b5 + "vmlal.s32 q9, d10, d14[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4) | a5*b6 + a6*b5 + 8*(a7*b9) + "vmlal.s32 q9, d8, d5[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4 + a9*b2) | a5*b6 + a6*b5 + 8*(a7*b9 + a9*b7) + "vmlal.s32 q9, d9, d15[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4 + a9*b2 + a8*b3) | a5*b6 + a6*b5 + 8*(a7*b9 + a9*b7 + a8*b8) + "vmull.s32 q10, d8, d0[1] \n\t" // q10 = a5*b2 | a5*b7 + "vmlal.s32 q10, d6, d2[1] \n\t" // q10 = a5*b2 + a7*b0 | a5*b7 + a7*b5 + "vmlal.s32 q10, d7, d1[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 | a5*b7 + a7*b5 + a6*b6 + "vmlal.s32 q10, d10, d15[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 + 8*(a8*b4) | a5*b7 + a7*b5 + a6*b6 + 8*(a8*b9) + "vmlal.s32 q10, d9, d5[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 + 8*(a8*b4 + a9*b3) | a5*b7 + a7*b5 + a6*b6 + 8*(a8*b9 + a9*b8) + + "push {r6-r9} \n\t" + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "add r6, r8 \n\t" //***** + "add r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + "vmull.s32 q11, d6, d0[0] \n\t" // q11 = a0*b0 | a0*b5 + "vmlal.s32 q11, d10, d13[0] \n\t" // q11 = a0*b0 + 8*(a1*b4) | a0*b5 + 8*(a1*b9) + "vmlal.s32 q11, d7, d5[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1) | a0*b5 + 8*(a1*b9 + a4*b6) + "vmlal.s32 q11, d9, d14[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8) + "vmlal.s32 q11, d8, d15[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3 + a3*b2) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8 + a3*b7) + "vmull.s32 q12, d7, d0[0] \n\t" // q12 = a0*b1 | a0*b6 + "vmlal.s32 q12, d6, d1[0] \n\t" // q12 = a0*b1 + a1*b0 | a0*b6 + a1*b5 + "vmlal.s32 q12, d10, d14[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4) | a0*b6 + a1*b5 + 8*(a2*b9) + "vmlal.s32 q12, d8, d5[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7) + "vmlal.s32 q12, d9, d15[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2 + a3*b3) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7 + a3*b8) + "vmull.s32 q13, d8, d0[0] \n\t" // q13 = a0*b2 | a0*b7 + "vmlal.s32 q13, d6, d2[0] \n\t" // q13 = a0*b2 + a2*b0 | a0*b7 + a2*b5 + "vmlal.s32 q13, d7, d1[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 | a0*b7 + a2*b5 + a1*b6 + "vmlal.s32 q13, d10, d15[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9) + "vmlal.s32 q13, d9, d5[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4 + a4*b3) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9 + a4*b8) + "vmull.s32 q14, d9, d0[0] \n\t" // q14 = a0*b3 | a0*b8 + "vmlal.s32 q14, d6, d3[0] \n\t" // q14 = a0*b3 + a3*b0 | a0*b8 + a3*b5 + "vmlal.s32 q14, d8, d1[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 | a0*b8 + a3*b5 + a1*b7 + "vmlal.s32 q14, d7, d2[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 | a0*b8 + a3*b5 + a1*b7 + a2*b6 + "vmlal.s32 q14, d10, d5[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 + 8*(a4*b4) | a0*b8 + a3*b5 + a1*b7 + a2*b6 + 8*(a4*b9) + "vmull.s32 q15, d10, d0[0] \n\t" // q15 = a0*b4 | a0*b9 + "vmlal.s32 q15, d6, d4[0] \n\t" // q15 = a0*b4 + a4*b0 | a0*b9 + a4*b5 + "vmlal.s32 q15, d9, d1[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 | a0*b9 + a4*b5 + a1*b8 + "vmlal.s32 q15, d7, d3[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + "vmlal.s32 q15, d8, d2[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 + a2*b2 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + a2*b7 + + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "add r6, r8 \n\t" //***** + "add r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + // q11[0]->q13[0] = A0*B0 - A1*B1, q11[1]->q13[1] = A0*B0 + A1*B1 + "vsub.s64 d22, d22, d17 \n\t" + "vsub.s64 d24, d24, d19 \n\t" + "vsub.s64 d26, d26, d21 \n\t" + "vadd.s64 d23, d23, d16 \n\t" + "vadd.s64 d25, d25, d18 \n\t" + "vadd.s64 d27, d27, d20 \n\t" + + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "add r6, r8 \n\t" //***** + "add r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + // Complete computation A1*B0|A1*B1, q8-q9 <- A1*B0|A1*B1 + "vmull.s32 q8, d9, d0[1] \n\t" // q8 = a5*b3 | a5*b8 + "vmlal.s32 q8, d6, d3[1] \n\t" // q8 = a5*b3 + a8*b0 | a5*b8 + a8*b5 + "vmlal.s32 q8, d8, d1[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 | a5*b8 + a8*b5 + a6*b7 + "vmlal.s32 q8, d7, d2[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 + a7*b1 | a5*b8 + a8*b5 + a6*b7 + a7*b6 + "vmlal.s32 q8, d10, d5[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 + a7*b1 + 8*(a9*b4) | a5*b8 + a8*b5 + a6*b7 + a7*b6 + 8*(a9*b9) + "vmull.s32 q9, d10, d0[1] \n\t" // q9 = a5*b4 | a5*b9 + "vmlal.s32 q9, d6, d4[1] \n\t" // q9 = a5*b4 + a9*b0 | a5*b9 + a9*b5 + "vmlal.s32 q9, d9, d1[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 | a5*b9 + a9*b5 + a6*b8 + "vmlal.s32 q9, d7, d3[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 + a8*b1 | a5*b9 + a9*b5 + a6*b8 + a8*b6 + "vmlal.s32 q9, d8, d2[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 + a8*b1 + a7*b2 | a5*b9 + a9*b5 + a6*b8 + a8*b6 + a7*b7 + + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "add r6, r8 \n\t" //***** + "add r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + // Complete q14[0]->q15[0] = A0*B0 - A1*B1, q14[1]->q15[0] = A0*B1 + A1*B0 + "vmov.i64 q7, 0xFFFFFFFF \n\t" // mask_26 + "vadd.s64 d29, d29, d16 \n\t" + "vsub.s64 d28, d28, d17 \n\t" + "vshr.u64 q7, q7, #6 \n\t" + "vadd.s64 d31, d31, d18 \n\t" + "vsub.s64 d30, d30, d19 \n\t" + + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "add r6, r8 \n\t" //***** + "add r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + "pop {r6-r9} \n\t" + + // Reduction + "vshr.u64 q6, q7, #3 \n\t" // mask_23 + "vshr.s64 q10, q11, #26 \n\t" + "vand.u64 q0, q11, q7 \n\t" + + "vshr.s64 q9, q14, #26 \n\t" + "vand.u64 q3, q14, q7 \n\t" + "vadd.s64 q10, q12, q10 \n\t" + "vadd.s64 q9, q15, q9 \n\t" + "vand.u64 q1, q10, q7 \n\t" + "vand.u64 q11, q9, q6 \n\t" + + "vshr.s64 q10, q10, #26 \n\t" + "vshr.s64 q9, q9, #23 \n\t" + "vadd.s64 q10, q13, q10 \n\t" + "vand.u64 q12, q9, q7 \n\t" + "vand.u64 q2, q10, q7 \n\t" + + "vshr.s64 q10, q10, #26 \n\t" + "vshr.s64 q6, q9, #26 \n\t" + "vadd.s64 q10, q3, q10 \n\t" + "vadd.s64 q0, q0, q12 \n\t" + "vadd.s64 q1, q1, q6 \n\t" + + "vst2.32 {d0[0],d1[0]}, [%2]! \n\t" + "vshr.s64 q9, q10, #26 \n\t" + "vst2.32 {d2[0],d3[0]}, [%2]! \n\t" + "vand.u64 q3, q10, q7 \n\t" + "vst2.32 {d4[0],d5[0]}, [%2]! \n\t" + "vpop {q4-q7} \n\t" + "vadd.s64 q11, q11, q9 \n\t" + "vst2.32 {d6[0],d7[0]}, [%2]! \n\t" + "vst2.32 {d22[0],d23[0]}, [%2]! \n\t" + : + :"r"(&a[0]), "r"(&b[0]), "r"(&c[0]), "r"(&d[0]), "r"(&e[0]), "r"(&f[0]) + :"memory","r6","r7","r8","r9" + ); + return; +} + + +void v2mulsub1271_a(uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d, uint32_t* e, uint32_t* f) +{ // Multiplication/subtraction over GF((2^127-1)^2) combining ARM and NEON instructions + // Operation: c = a * b, f = d - e in GF((2^127-1)^2) + // Representation: 23/23/26/26/26/26/26/26/26/26-bit + +asm volatile( + // q0-q2[0] <- A0|A1, q3-q5[0] <- B0|B1 + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2,d3}, [%0]! \n\t" + "vld1.8 {d4}, [%0]! \n\t" + "vshl.i32 q6, q0, #3 \n\t" // q6-q7 = 8*(a0->a8) + "vpush {q4-q7} \n\t" + "vld1.8 {d6,d7}, [%1]! \n\t" + "vshl.i32 d5, d4, #3 \n\t" // q2[1] = 8*(a4|a9) + "vld1.8 {d8,d9}, [%1]! \n\t" + "vshl.i32 q7, q1, #3 \n\t" + "vld1.8 {d10}, [%1]! \n\t" + + // q11-q15 <- A0*B0|A0*B1, q8-q10 <- A1*B0|A1*B1 + "vmull.s32 q8, d6, d0[1] \n\t" // q8 = a5*b0 | a5*b5 + "vmlal.s32 q8, d10, d13[1] \n\t" // q8 = a5*b0 + 8*(a6*b4) | a5*b5 + 8*(a6*b9) + "vmlal.s32 q8, d7, d5[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1) | a5*b5 + 8*(a6*b9 + a9*b6) + "vmlal.s32 q8, d9, d14[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1 + a7*b3) | a5*b5 + 8*(a6*b9 + a9*b6 + a7*b8) + "vmlal.s32 q8, d8, d15[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1 + a7*b3 + a8*b2) | a5*b5 + 8*(a6*b9 + a9*b6 + a7*b8 + a8*b7) + "vmull.s32 q9, d7, d0[1] \n\t" // q9 = a5*b1 | a5*b6 + "vmlal.s32 q9, d6, d1[1] \n\t" // q9 = a5*b1 + a6*b0 | a5*b6 + a6*b5 + "vmlal.s32 q9, d10, d14[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4) | a5*b6 + a6*b5 + 8*(a7*b9) + "vmlal.s32 q9, d8, d5[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4 + a9*b2) | a5*b6 + a6*b5 + 8*(a7*b9 + a9*b7) + "vmlal.s32 q9, d9, d15[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4 + a9*b2 + a8*b3) | a5*b6 + a6*b5 + 8*(a7*b9 + a9*b7 + a8*b8) + "vmull.s32 q10, d8, d0[1] \n\t" // q10 = a5*b2 | a5*b7 + "vmlal.s32 q10, d6, d2[1] \n\t" // q10 = a5*b2 + a7*b0 | a5*b7 + a7*b5 + "vmlal.s32 q10, d7, d1[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 | a5*b7 + a7*b5 + a6*b6 + "vmlal.s32 q10, d10, d15[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 + 8*(a8*b4) | a5*b7 + a7*b5 + a6*b6 + 8*(a8*b9) + "vmlal.s32 q10, d9, d5[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 + 8*(a8*b4 + a9*b3) | a5*b7 + a7*b5 + a6*b6 + 8*(a8*b9 + a9*b8) + + "push {r6-r9} \n\t" + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + "vmull.s32 q11, d6, d0[0] \n\t" // q11 = a0*b0 | a0*b5 + "vmlal.s32 q11, d10, d13[0] \n\t" // q11 = a0*b0 + 8*(a1*b4) | a0*b5 + 8*(a1*b9) + "vmlal.s32 q11, d7, d5[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1) | a0*b5 + 8*(a1*b9 + a4*b6) + "vmlal.s32 q11, d9, d14[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8) + "vmlal.s32 q11, d8, d15[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3 + a3*b2) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8 + a3*b7) + "vmull.s32 q12, d7, d0[0] \n\t" // q12 = a0*b1 | a0*b6 + "vmlal.s32 q12, d6, d1[0] \n\t" // q12 = a0*b1 + a1*b0 | a0*b6 + a1*b5 + "vmlal.s32 q12, d10, d14[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4) | a0*b6 + a1*b5 + 8*(a2*b9) + "vmlal.s32 q12, d8, d5[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7) + "vmlal.s32 q12, d9, d15[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2 + a3*b3) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7 + a3*b8) + "vmull.s32 q13, d8, d0[0] \n\t" // q13 = a0*b2 | a0*b7 + "vmlal.s32 q13, d6, d2[0] \n\t" // q13 = a0*b2 + a2*b0 | a0*b7 + a2*b5 + "vmlal.s32 q13, d7, d1[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 | a0*b7 + a2*b5 + a1*b6 + "vmlal.s32 q13, d10, d15[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9) + "vmlal.s32 q13, d9, d5[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4 + a4*b3) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9 + a4*b8) + "vmull.s32 q14, d9, d0[0] \n\t" // q14 = a0*b3 | a0*b8 + "vmlal.s32 q14, d6, d3[0] \n\t" // q14 = a0*b3 + a3*b0 | a0*b8 + a3*b5 + "vmlal.s32 q14, d8, d1[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 | a0*b8 + a3*b5 + a1*b7 + "vmlal.s32 q14, d7, d2[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 | a0*b8 + a3*b5 + a1*b7 + a2*b6 + "vmlal.s32 q14, d10, d5[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 + 8*(a4*b4) | a0*b8 + a3*b5 + a1*b7 + a2*b6 + 8*(a4*b9) + "vmull.s32 q15, d10, d0[0] \n\t" // q15 = a0*b4 | a0*b9 + "vmlal.s32 q15, d6, d4[0] \n\t" // q15 = a0*b4 + a4*b0 | a0*b9 + a4*b5 + "vmlal.s32 q15, d9, d1[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 | a0*b9 + a4*b5 + a1*b8 + "vmlal.s32 q15, d7, d3[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + "vmlal.s32 q15, d8, d2[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 + a2*b2 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + a2*b7 + + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + // q11[0]->q13[0] = A0*B0 - A1*B1, q11[1]->q13[1] = A0*B0 + A1*B1 + "vsub.s64 d22, d22, d17 \n\t" + "vsub.s64 d24, d24, d19 \n\t" + "vsub.s64 d26, d26, d21 \n\t" + "vadd.s64 d23, d23, d16 \n\t" + "vadd.s64 d25, d25, d18 \n\t" + "vadd.s64 d27, d27, d20 \n\t" + + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + // Complete computation A1*B0|A1*B1, q8-q9 <- A1*B0|A1*B1 + "vmull.s32 q8, d9, d0[1] \n\t" // q8 = a5*b3 | a5*b8 + "vmlal.s32 q8, d6, d3[1] \n\t" // q8 = a5*b3 + a8*b0 | a5*b8 + a8*b5 + "vmlal.s32 q8, d8, d1[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 | a5*b8 + a8*b5 + a6*b7 + "vmlal.s32 q8, d7, d2[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 + a7*b1 | a5*b8 + a8*b5 + a6*b7 + a7*b6 + "vmlal.s32 q8, d10, d5[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 + a7*b1 + 8*(a9*b4) | a5*b8 + a8*b5 + a6*b7 + a7*b6 + 8*(a9*b9) + "vmull.s32 q9, d10, d0[1] \n\t" // q9 = a5*b4 | a5*b9 + "vmlal.s32 q9, d6, d4[1] \n\t" // q9 = a5*b4 + a9*b0 | a5*b9 + a9*b5 + "vmlal.s32 q9, d9, d1[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 | a5*b9 + a9*b5 + a6*b8 + "vmlal.s32 q9, d7, d3[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 + a8*b1 | a5*b9 + a9*b5 + a6*b8 + a8*b6 + "vmlal.s32 q9, d8, d2[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 + a8*b1 + a7*b2 | a5*b9 + a9*b5 + a6*b8 + a8*b6 + a7*b7 + + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + // Complete q14[0]->q15[0] = A0*B0 - A1*B1, q14[1]->q15[0] = A0*B1 + A1*B0 + "vmov.i64 q7, 0xFFFFFFFF \n\t" // mask_26 + "vadd.s64 d29, d29, d16 \n\t" + "vsub.s64 d28, d28, d17 \n\t" + "vshr.u64 q7, q7, #6 \n\t" + "vadd.s64 d31, d31, d18 \n\t" + "vsub.s64 d30, d30, d19 \n\t" + + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + "pop {r6-r9} \n\t" + + // Reduction + "vshr.u64 q6, q7, #3 \n\t" // mask_23 + "vshr.s64 q10, q11, #26 \n\t" + "vand.u64 q0, q11, q7 \n\t" + + "vshr.s64 q9, q14, #26 \n\t" + "vand.u64 q3, q14, q7 \n\t" + "vadd.s64 q10, q12, q10 \n\t" + "vadd.s64 q9, q15, q9 \n\t" + "vand.u64 q1, q10, q7 \n\t" + "vand.u64 q11, q9, q6 \n\t" + + "vshr.s64 q10, q10, #26 \n\t" + "vshr.s64 q9, q9, #23 \n\t" + "vadd.s64 q10, q13, q10 \n\t" + "vand.u64 q12, q9, q7 \n\t" + "vand.u64 q2, q10, q7 \n\t" + + "vshr.s64 q10, q10, #26 \n\t" + "vshr.s64 q6, q9, #26 \n\t" + "vadd.s64 q10, q3, q10 \n\t" + "vadd.s64 q0, q0, q12 \n\t" + "vadd.s64 q1, q1, q6 \n\t" + + "vst2.32 {d0[0],d1[0]}, [%2]! \n\t" + "vshr.s64 q9, q10, #26 \n\t" + "vst2.32 {d2[0],d3[0]}, [%2]! \n\t" + "vand.u64 q3, q10, q7 \n\t" + "vst2.32 {d4[0],d5[0]}, [%2]! \n\t" + "vpop {q4-q7} \n\t" + "vadd.s64 q11, q11, q9 \n\t" + "vst2.32 {d6[0],d7[0]}, [%2]! \n\t" + "vst2.32 {d22[0],d23[0]}, [%2]! \n\t" + : + :"r"(&a[0]), "r"(&b[0]), "r"(&c[0]), "r"(&d[0]), "r"(&e[0]), "r"(&f[0]) + :"memory","r6","r7","r8","r9" + ); + return; +} + + +void v2muldblsub1271_a(uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d, uint32_t* e, uint32_t* f) +{ // Multiplication/addition/subtraction over GF((2^127-1)^2) combining ARM and NEON instructions + // Operation: c = a * b, f = 2*d - e in GF((2^127-1)^2) + // Representation: 23/23/26/26/26/26/26/26/26/26-bit + +asm volatile( + // q0-q2[0] <- A0|A1, q3-q5[0] <- B0|B1 + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2,d3}, [%0]! \n\t" + "vld1.8 {d4}, [%0]! \n\t" + "vshl.i32 q6, q0, #3 \n\t" // q6-q7 = 8*(a0->a8) + "vpush {q4-q7} \n\t" + "vld1.8 {d6,d7}, [%1]! \n\t" + "vshl.i32 d5, d4, #3 \n\t" // q2[1] = 8*(a4|a9) + "vld1.8 {d8,d9}, [%1]! \n\t" + "vshl.i32 q7, q1, #3 \n\t" + "vld1.8 {d10}, [%1]! \n\t" + + // q11-q15 <- A0*B0|A0*B1, q8-q10 <- A1*B0|A1*B1 + "vmull.s32 q8, d6, d0[1] \n\t" // q8 = a5*b0 | a5*b5 + "vmlal.s32 q8, d10, d13[1] \n\t" // q8 = a5*b0 + 8*(a6*b4) | a5*b5 + 8*(a6*b9) + "vmlal.s32 q8, d7, d5[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1) | a5*b5 + 8*(a6*b9 + a9*b6) + "vmlal.s32 q8, d9, d14[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1 + a7*b3) | a5*b5 + 8*(a6*b9 + a9*b6 + a7*b8) + "vmlal.s32 q8, d8, d15[1] \n\t" // q8 = a5*b0 + 8*(a6*b4 + a9*b1 + a7*b3 + a8*b2) | a5*b5 + 8*(a6*b9 + a9*b6 + a7*b8 + a8*b7) + "vmull.s32 q9, d7, d0[1] \n\t" // q9 = a5*b1 | a5*b6 + "vmlal.s32 q9, d6, d1[1] \n\t" // q9 = a5*b1 + a6*b0 | a5*b6 + a6*b5 + "vmlal.s32 q9, d10, d14[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4) | a5*b6 + a6*b5 + 8*(a7*b9) + "vmlal.s32 q9, d8, d5[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4 + a9*b2) | a5*b6 + a6*b5 + 8*(a7*b9 + a9*b7) + "vmlal.s32 q9, d9, d15[1] \n\t" // q9 = a5*b1 + a6*b0 + 8*(a7*b4 + a9*b2 + a8*b3) | a5*b6 + a6*b5 + 8*(a7*b9 + a9*b7 + a8*b8) + "vmull.s32 q10, d8, d0[1] \n\t" // q10 = a5*b2 | a5*b7 + "vmlal.s32 q10, d6, d2[1] \n\t" // q10 = a5*b2 + a7*b0 | a5*b7 + a7*b5 + "vmlal.s32 q10, d7, d1[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 | a5*b7 + a7*b5 + a6*b6 + "vmlal.s32 q10, d10, d15[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 + 8*(a8*b4) | a5*b7 + a7*b5 + a6*b6 + 8*(a8*b9) + "vmlal.s32 q10, d9, d5[1] \n\t" // q10 = a5*b2 + a7*b0 + a6*b1 + 8*(a8*b4 + a9*b3) | a5*b7 + a7*b5 + a6*b6 + 8*(a8*b9 + a9*b8) + + "push {r6-r9} \n\t" + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "add r6, r6 \n\t" //***** + "add r7, r7 \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + "vmull.s32 q11, d6, d0[0] \n\t" // q11 = a0*b0 | a0*b5 + "vmlal.s32 q11, d10, d13[0] \n\t" // q11 = a0*b0 + 8*(a1*b4) | a0*b5 + 8*(a1*b9) + "vmlal.s32 q11, d7, d5[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1) | a0*b5 + 8*(a1*b9 + a4*b6) + "vmlal.s32 q11, d9, d14[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8) + "vmlal.s32 q11, d8, d15[0] \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3 + a3*b2) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8 + a3*b7) + "vmull.s32 q12, d7, d0[0] \n\t" // q12 = a0*b1 | a0*b6 + "vmlal.s32 q12, d6, d1[0] \n\t" // q12 = a0*b1 + a1*b0 | a0*b6 + a1*b5 + "vmlal.s32 q12, d10, d14[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4) | a0*b6 + a1*b5 + 8*(a2*b9) + "vmlal.s32 q12, d8, d5[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7) + "vmlal.s32 q12, d9, d15[0] \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2 + a3*b3) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7 + a3*b8) + "vmull.s32 q13, d8, d0[0] \n\t" // q13 = a0*b2 | a0*b7 + "vmlal.s32 q13, d6, d2[0] \n\t" // q13 = a0*b2 + a2*b0 | a0*b7 + a2*b5 + "vmlal.s32 q13, d7, d1[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 | a0*b7 + a2*b5 + a1*b6 + "vmlal.s32 q13, d10, d15[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9) + "vmlal.s32 q13, d9, d5[0] \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4 + a4*b3) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9 + a4*b8) + "vmull.s32 q14, d9, d0[0] \n\t" // q14 = a0*b3 | a0*b8 + "vmlal.s32 q14, d6, d3[0] \n\t" // q14 = a0*b3 + a3*b0 | a0*b8 + a3*b5 + "vmlal.s32 q14, d8, d1[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 | a0*b8 + a3*b5 + a1*b7 + "vmlal.s32 q14, d7, d2[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 | a0*b8 + a3*b5 + a1*b7 + a2*b6 + "vmlal.s32 q14, d10, d5[0] \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 + 8*(a4*b4) | a0*b8 + a3*b5 + a1*b7 + a2*b6 + 8*(a4*b9) + "vmull.s32 q15, d10, d0[0] \n\t" // q15 = a0*b4 | a0*b9 + "vmlal.s32 q15, d6, d4[0] \n\t" // q15 = a0*b4 + a4*b0 | a0*b9 + a4*b5 + "vmlal.s32 q15, d9, d1[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 | a0*b9 + a4*b5 + a1*b8 + "vmlal.s32 q15, d7, d3[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + "vmlal.s32 q15, d8, d2[0] \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 + a2*b2 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + a2*b7 + + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "add r6, r6 \n\t" //***** + "add r7, r7 \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + // q11[0]->q13[0] = A0*B0 - A1*B1, q11[1]->q13[1] = A0*B0 + A1*B1 + "vsub.s64 d22, d22, d17 \n\t" + "vsub.s64 d24, d24, d19 \n\t" + "vsub.s64 d26, d26, d21 \n\t" + "vadd.s64 d23, d23, d16 \n\t" + "vadd.s64 d25, d25, d18 \n\t" + "vadd.s64 d27, d27, d20 \n\t" + + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "add r6, r6 \n\t" //***** + "add r7, r7 \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + // Complete computation A1*B0|A1*B1, q8-q9 <- A1*B0|A1*B1 + "vmull.s32 q8, d9, d0[1] \n\t" // q8 = a5*b3 | a5*b8 + "vmlal.s32 q8, d6, d3[1] \n\t" // q8 = a5*b3 + a8*b0 | a5*b8 + a8*b5 + "vmlal.s32 q8, d8, d1[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 | a5*b8 + a8*b5 + a6*b7 + "vmlal.s32 q8, d7, d2[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 + a7*b1 | a5*b8 + a8*b5 + a6*b7 + a7*b6 + "vmlal.s32 q8, d10, d5[1] \n\t" // q8 = a5*b3 + a8*b0 + a6*b2 + a7*b1 + 8*(a9*b4) | a5*b8 + a8*b5 + a6*b7 + a7*b6 + 8*(a9*b9) + "vmull.s32 q9, d10, d0[1] \n\t" // q9 = a5*b4 | a5*b9 + "vmlal.s32 q9, d6, d4[1] \n\t" // q9 = a5*b4 + a9*b0 | a5*b9 + a9*b5 + "vmlal.s32 q9, d9, d1[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 | a5*b9 + a9*b5 + a6*b8 + "vmlal.s32 q9, d7, d3[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 + a8*b1 | a5*b9 + a9*b5 + a6*b8 + a8*b6 + "vmlal.s32 q9, d8, d2[1] \n\t" // q9 = a5*b4 + a9*b0 + a6*b3 + a8*b1 + a7*b2 | a5*b9 + a9*b5 + a6*b8 + a8*b6 + a7*b7 + + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "add r6, r6 \n\t" //***** + "add r7, r7 \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + // Complete q14[0]->q15[0] = A0*B0 - A1*B1, q14[1]->q15[0] = A0*B1 + A1*B0 + "vmov.i64 q7, 0xFFFFFFFF \n\t" // mask_26 + "vadd.s64 d29, d29, d16 \n\t" + "vsub.s64 d28, d28, d17 \n\t" + "vshr.u64 q7, q7, #6 \n\t" + "vadd.s64 d31, d31, d18 \n\t" + "vsub.s64 d30, d30, d19 \n\t" + + "ldm %3!, {r6,r7} \n\t" //***** + "ldm %4!, {r8,r9} \n\t" //***** + "add r6, r6 \n\t" //***** + "add r7, r7 \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + "pop {r6-r9} \n\t" + + // Reduction + "vshr.u64 q6, q7, #3 \n\t" // mask_23 + "vshr.s64 q10, q11, #26 \n\t" + "vand.u64 q0, q11, q7 \n\t" + + "vshr.s64 q9, q14, #26 \n\t" + "vand.u64 q3, q14, q7 \n\t" + "vadd.s64 q10, q12, q10 \n\t" + "vadd.s64 q9, q15, q9 \n\t" + "vand.u64 q1, q10, q7 \n\t" + "vand.u64 q11, q9, q6 \n\t" + + "vshr.s64 q10, q10, #26 \n\t" + "vshr.s64 q9, q9, #23 \n\t" + "vadd.s64 q10, q13, q10 \n\t" + "vand.u64 q12, q9, q7 \n\t" + "vand.u64 q2, q10, q7 \n\t" + + "vshr.s64 q10, q10, #26 \n\t" + "vshr.s64 q6, q9, #26 \n\t" + "vadd.s64 q10, q3, q10 \n\t" + "vadd.s64 q0, q0, q12 \n\t" + "vadd.s64 q1, q1, q6 \n\t" + + "vst2.32 {d0[0],d1[0]}, [%2]! \n\t" + "vshr.s64 q9, q10, #26 \n\t" + "vst2.32 {d2[0],d3[0]}, [%2]! \n\t" + "vand.u64 q3, q10, q7 \n\t" + "vst2.32 {d4[0],d5[0]}, [%2]! \n\t" + "vpop {q4-q7} \n\t" + "vadd.s64 q11, q11, q9 \n\t" + "vst2.32 {d6[0],d7[0]}, [%2]! \n\t" + "vst2.32 {d22[0],d23[0]}, [%2]! \n\t" + : + :"r"(&a[0]), "r"(&b[0]), "r"(&c[0]), "r"(&d[0]), "r"(&e[0]), "r"(&f[0]) + :"memory","r6","r7","r8","r9" + ); + return; +} + + +void v2sqradd1271_a(uint32_t* a, uint32_t* c, uint32_t* d, uint32_t* e, uint32_t* f) +{ // Squaring/addition over GF((2^127-1)^2) combining ARM and NEON instructions + // Operation: c = a^2, f = d + e in GF((2^127-1)^2) + // Representation: 23/23/26/26/26/26/26/26/26/26-bit + +asm volatile( + // q0-q2[0] <- A0|A1 + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2,d3}, [%0]! \n\t" + "vshr.u64 q3, q0, #32 \n\t" // q3-q5[0] = (0|a9->0|a5) + "vld1.8 {d4}, [%0]! \n\t" + "vpush {q4-q7} \n\t" + "vmov.i64 q8, 0xFFFFFFFF \n\t" // mask_26 + "vshr.u64 q4, q1, #32 \n\t" + "vshr.u64 d10, d4, #32 \n\t" + "vsub.s32 q13, q0, q3 \n\t" // q13-q15[0] = (a9|a4-a9->a5|a0-a5) + "vsub.s32 q14, q1, q4 \n\t" + "vsub.s32 d30, d4, d10 \n\t" + "vadd.s32 q3, q0, q3 \n\t" // q3-q5[0] = (a9|a4+a9->a5|a0+a5) + "vadd.s32 q4, q1, q4 \n\t" + "vadd.s32 d10, d4, d10 \n\t" + "vshl.i64 q0, q0, #33 \n\t" // q0-q2[0] = (2*a4|0->2*a0|0) + "vshl.i64 q1, q1, #33 \n\t" + "vshl.i64 d4, d4, #33 \n\t" + "vbit q0, q13, q8 \n\t" // q0-q2[0] = (2*a4|a4-a9->2*a0|a0-a5) + "vbit q1, q14, q8 \n\t" + "vbit d4, d30, d16 \n\t" + "vshl.i32 q6, q0, #3 \n\t" // 8*(2*a4|a4-a9->2*a0|a0-a5) + "vshl.i32 q7, q1, #3 \n\t" + "vshl.i32 d5, d4, #3 \n\t" + + "push {r5-r8} \n\t" + "ldm %2!, {r5,r6} \n\t" //***** + "ldm %3!, {r7,r8} \n\t" //***** + "add r5, r7 \n\t" //***** + "add r6, r8 \n\t" //***** + "stm %4!, {r5,r6} \n\t" //***** + + // q11-q15 <- 2*A0*B0|(A0+A1)*(A0-A1) + "vshr.u64 q8, q8, #6 \n\t" + "vmull.s32 q11, d6, d0 \n\t" // q11 = a0*b0 | a0*b5 + "vmlal.s32 q11, d10, d13 \n\t" // q11 = a0*b0 + 8*(a1*b4) | a0*b5 + 8*(a1*b9) + "vmlal.s32 q11, d7, d5 \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1) | a0*b5 + 8*(a1*b9 + a4*b6) + "vmlal.s32 q11, d9, d14 \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8) + "vmlal.s32 q11, d8, d15 \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3 + a3*b2) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8 + a3*b7) + "vmull.s32 q12, d7, d0 \n\t" // q12 = a0*b1 | a0*b6 + "ldm %2!, {r5,r6} \n\t" //***** + "ldm %3!, {r7,r8} \n\t" //***** + "add r5, r7 \n\t" //***** + "add r6, r8 \n\t" //***** + "stm %4!, {r5,r6} \n\t" //***** + "vmlal.s32 q12, d6, d1 \n\t" // q12 = a0*b1 + a1*b0 | a0*b6 + a1*b5 + "vmlal.s32 q12, d10, d14 \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4) | a0*b6 + a1*b5 + 8*(a2*b9) + "vmlal.s32 q12, d8, d5 \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7) + "vmlal.s32 q12, d9, d15 \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2 + a3*b3) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7 + a3*b8) + "vmull.s32 q13, d8, d0 \n\t" // q13 = a0*b2 | a0*b7 + "vmlal.s32 q13, d6, d2 \n\t" // q13 = a0*b2 + a2*b0 | a0*b7 + a2*b5 + "vmlal.s32 q13, d7, d1 \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 | a0*b7 + a2*b5 + a1*b6 + "vmlal.s32 q13, d10, d15 \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9) + "vmlal.s32 q13, d9, d5 \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4 + a4*b3) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9 + a4*b8) + "vmull.s32 q14, d9, d0 \n\t" // q14 = a0*b3 | a0*b8 + "ldm %2!, {r5,r6} \n\t" //***** + "ldm %3!, {r7,r8} \n\t" //***** + "add r5, r7 \n\t" //***** + "add r6, r8 \n\t" //***** + "stm %4!, {r5,r6} \n\t" //***** + "vmlal.s32 q14, d6, d3 \n\t" // q14 = a0*b3 + a3*b0 | a0*b8 + a3*b5 + "vmlal.s32 q14, d8, d1 \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 | a0*b8 + a3*b5 + a1*b7 + "vmlal.s32 q14, d7, d2 \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 | a0*b8 + a3*b5 + a1*b7 + a2*b6 + "vmlal.s32 q14, d10, d5 \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 + 8*(a4*b4) | a0*b8 + a3*b5 + a1*b7 + a2*b6 + 8*(a4*b9) + "vmull.s32 q15, d10, d0 \n\t" // q15 = a0*b4 | a0*b9 + "vmlal.s32 q15, d6, d4 \n\t" // q15 = a0*b4 + a4*b0 | a0*b9 + a4*b5 + "vmlal.s32 q15, d9, d1 \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 | a0*b9 + a4*b5 + a1*b8 + "vmlal.s32 q15, d7, d3 \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + "vmlal.s32 q15, d8, d2 \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 + a2*b2 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + a2*b7 + + "ldm %2!, {r5,r6} \n\t" //***** + "ldm %3!, {r7,r8} \n\t" //***** + "add r5, r7 \n\t" //***** + "add r6, r8 \n\t" //***** + "stm %4!, {r5,r6} \n\t" //***** + + // Reduction + "vshr.u64 q6, q8, #3 \n\t" // mask_23 + "vshr.s64 q10, q11, #26 \n\t" + "vand.u64 q0, q11, q8 \n\t" + + "vshr.s64 q9, q14, #26 \n\t" + "vand.u64 q3, q14, q8 \n\t" + "vadd.s64 q10, q12, q10 \n\t" + "vadd.s64 q9, q15, q9 \n\t" + "vand.u64 q1, q10, q8 \n\t" + "vand.u64 q11, q9, q6 \n\t" + + "ldm %2!, {r5,r6} \n\t" //***** + "ldm %3!, {r7,r8} \n\t" //***** + "add r5, r7 \n\t" //***** + "add r6, r8 \n\t" //***** + "stm %4!, {r5,r6} \n\t" //***** + "pop {r5-r8} \n\t" + + "vshr.s64 q10, q10, #26 \n\t" + "vshr.s64 q9, q9, #23 \n\t" + "vadd.s64 q10, q13, q10 \n\t" + "vand.u64 q12, q9, q8 \n\t" + "vand.u64 q2, q10, q8 \n\t" + + "vshr.s64 q10, q10, #26 \n\t" + "vshr.s64 q6, q9, #26 \n\t" + "vadd.s64 q10, q3, q10 \n\t" + "vadd.s64 q0, q0, q12 \n\t" + "vadd.s64 q1, q1, q6 \n\t" + + "vst2.32 {d0[0],d1[0]}, [%1]! \n\t" + "vshr.s64 q9, q10, #26 \n\t" + "vst2.32 {d2[0],d3[0]}, [%1]! \n\t" + "vand.u64 q3, q10, q8 \n\t" + "vst2.32 {d4[0],d5[0]}, [%1]! \n\t" + "vpop {q4-q7} \n\t" + "vadd.s64 q11, q11, q9 \n\t" + "vst2.32 {d6[0],d7[0]}, [%1]! \n\t" + "vst2.32 {d22[0],d23[0]}, [%1]! \n\t" + : + :"r"(&a[0]), "r"(&c[0]), "r"(&d[0]), "r"(&e[0]), "r"(&f[0]) + :"memory","r5","r6","r7","r8" + ); + return; +} + + +void v2sqraddsub1271_a(uint32_t* a, uint32_t* c, uint32_t* d, uint32_t* e, uint32_t* f, uint32_t* g) +{ // Squaring/addition/subtraction over GF((2^127-1)^2) combining ARM and NEON instructions + // Operation: c = a^2, f = d + e, g = d - e in GF((2^127-1)^2) + // Representation: 23/23/26/26/26/26/26/26/26/26-bit + +asm volatile( + // q0-q2[0] <- A0|A1 + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2,d3}, [%0]! \n\t" + "vshr.u64 q3, q0, #32 \n\t" // q3-q5[0] = (0|a9->0|a5) + "vld1.8 {d4}, [%0]! \n\t" + "vpush {q4-q7} \n\t" + "vmov.i64 q8, 0xFFFFFFFF \n\t" // mask_26 + "vshr.u64 q4, q1, #32 \n\t" + "vshr.u64 d10, d4, #32 \n\t" + "vsub.s32 q13, q0, q3 \n\t" // q13-q15[0] = (a9|a4-a9->a5|a0-a5) + "vsub.s32 q14, q1, q4 \n\t" + "vsub.s32 d30, d4, d10 \n\t" + "vadd.s32 q3, q0, q3 \n\t" // q3-q5[0] = (a9|a4+a9->a5|a0+a5) + "vadd.s32 q4, q1, q4 \n\t" + "vadd.s32 d10, d4, d10 \n\t" + "vshl.i64 q0, q0, #33 \n\t" // q0-q2[0] = (2*a4|0->2*a0|0) + "vshl.i64 q1, q1, #33 \n\t" + "vshl.i64 d4, d4, #33 \n\t" + "vbit q0, q13, q8 \n\t" // q0-q2[0] = (2*a4|a4-a9->2*a0|a0-a5) + "vbit q1, q14, q8 \n\t" + "vbit d4, d30, d16 \n\t" + "vshl.i32 q6, q0, #3 \n\t" // 8*(2*a4|a4-a9->2*a0|a0-a5) + "vshl.i32 q7, q1, #3 \n\t" + "vshl.i32 d5, d4, #3 \n\t" + + "push {r6-r11} \n\t" + "ldm %2!, {r6,r7} \n\t" //***** + "ldm %3!, {r8,r9} \n\t" //***** + "add r10, r6, r8 \n\t" //***** + "add r11, r7, r9 \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %4!, {r10,r11} \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + // q11-q15 <- 2*A0*B0|(A0+A1)*(A0-A1) + "vshr.u64 q8, q8, #6 \n\t" + "vmull.s32 q11, d6, d0 \n\t" // q11 = a0*b0 | a0*b5 + "vmlal.s32 q11, d10, d13 \n\t" // q11 = a0*b0 + 8*(a1*b4) | a0*b5 + 8*(a1*b9) + "vmlal.s32 q11, d7, d5 \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1) | a0*b5 + 8*(a1*b9 + a4*b6) + "vmlal.s32 q11, d9, d14 \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8) + "vmlal.s32 q11, d8, d15 \n\t" // q11 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3 + a3*b2) | a0*b5 + 8*(a1*b9 + a4*b6 + a2*b8 + a3*b7) + "vmull.s32 q12, d7, d0 \n\t" // q12 = a0*b1 | a0*b6 + "ldm %2!, {r6,r7} \n\t" //***** + "ldm %3!, {r8,r9} \n\t" //***** + "add r10, r6, r8 \n\t" //***** + "add r11, r7, r9 \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %4!, {r10,r11} \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + "vmlal.s32 q12, d6, d1 \n\t" // q12 = a0*b1 + a1*b0 | a0*b6 + a1*b5 + "vmlal.s32 q12, d10, d14 \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4) | a0*b6 + a1*b5 + 8*(a2*b9) + "vmlal.s32 q12, d8, d5 \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7) + "vmlal.s32 q12, d9, d15 \n\t" // q12 = a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2 + a3*b3) | a0*b6 + a1*b5 + 8*(a2*b9 + a4*b7 + a3*b8) + "vmull.s32 q13, d8, d0 \n\t" // q13 = a0*b2 | a0*b7 + "vmlal.s32 q13, d6, d2 \n\t" // q13 = a0*b2 + a2*b0 | a0*b7 + a2*b5 + "vmlal.s32 q13, d7, d1 \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 | a0*b7 + a2*b5 + a1*b6 + "vmlal.s32 q13, d10, d15 \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9) + "vmlal.s32 q13, d9, d5 \n\t" // q13 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4 + a4*b3) | a0*b7 + a2*b5 + a1*b6 + 8*(a3*b9 + a4*b8) + "vmull.s32 q14, d9, d0 \n\t" // q14 = a0*b3 | a0*b8 + "ldm %2!, {r6,r7} \n\t" //***** + "ldm %3!, {r8,r9} \n\t" //***** + "add r10, r6, r8 \n\t" //***** + "add r11, r7, r9 \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %4!, {r10,r11} \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + "vmlal.s32 q14, d6, d3 \n\t" // q14 = a0*b3 + a3*b0 | a0*b8 + a3*b5 + "vmlal.s32 q14, d8, d1 \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 | a0*b8 + a3*b5 + a1*b7 + "vmlal.s32 q14, d7, d2 \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 | a0*b8 + a3*b5 + a1*b7 + a2*b6 + "vmlal.s32 q14, d10, d5 \n\t" // q14 = a0*b3 + a3*b0 + a1*b2 + a2*b1 + 8*(a4*b4) | a0*b8 + a3*b5 + a1*b7 + a2*b6 + 8*(a4*b9) + "vmull.s32 q15, d10, d0 \n\t" // q15 = a0*b4 | a0*b9 + "vmlal.s32 q15, d6, d4 \n\t" // q15 = a0*b4 + a4*b0 | a0*b9 + a4*b5 + "vmlal.s32 q15, d9, d1 \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 | a0*b9 + a4*b5 + a1*b8 + "vmlal.s32 q15, d7, d3 \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + "vmlal.s32 q15, d8, d2 \n\t" // q15 = a0*b4 + a4*b0 + a1*b3 + a3*b1 + a2*b2 | a0*b9 + a4*b5 + a1*b8 + a3*b6 + a2*b7 + + "ldm %2!, {r6,r7} \n\t" //***** + "ldm %3!, {r8,r9} \n\t" //***** + "add r10, r6, r8 \n\t" //***** + "add r11, r7, r9 \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %4!, {r10,r11} \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + + // Reduction + "vshr.u64 q6, q8, #3 \n\t" // mask_23 + "vshr.s64 q10, q11, #26 \n\t" + "vand.u64 q0, q11, q8 \n\t" + + "vshr.s64 q9, q14, #26 \n\t" + "vand.u64 q3, q14, q8 \n\t" + "vadd.s64 q10, q12, q10 \n\t" + "vadd.s64 q9, q15, q9 \n\t" + "vand.u64 q1, q10, q8 \n\t" + "vand.u64 q11, q9, q6 \n\t" + + "ldm %2!, {r6,r7} \n\t" //***** + "ldm %3!, {r8,r9} \n\t" //***** + "add r10, r6, r8 \n\t" //***** + "add r11, r7, r9 \n\t" //***** + "sub r6, r8 \n\t" //***** + "sub r7, r9 \n\t" //***** + "stm %4!, {r10,r11} \n\t" //***** + "stm %5!, {r6,r7} \n\t" //***** + "pop {r6-r11} \n\t" + + "vshr.s64 q10, q10, #26 \n\t" + "vshr.s64 q9, q9, #23 \n\t" + "vadd.s64 q10, q13, q10 \n\t" + "vand.u64 q12, q9, q8 \n\t" + "vand.u64 q2, q10, q8 \n\t" + + "vshr.s64 q10, q10, #26 \n\t" + "vshr.s64 q6, q9, #26 \n\t" + "vadd.s64 q10, q3, q10 \n\t" + "vadd.s64 q0, q0, q12 \n\t" + "vadd.s64 q1, q1, q6 \n\t" + + "vst2.32 {d0[0],d1[0]}, [%1]! \n\t" + "vshr.s64 q9, q10, #26 \n\t" + "vst2.32 {d2[0],d3[0]}, [%1]! \n\t" + "vand.u64 q3, q10, q8 \n\t" + "vst2.32 {d4[0],d5[0]}, [%1]! \n\t" + "vpop {q4-q7} \n\t" + "vadd.s64 q11, q11, q9 \n\t" + "vst2.32 {d6[0],d7[0]}, [%1]! \n\t" + "vst2.32 {d22[0],d23[0]}, [%1]! \n\t" + : + :"r"(&a[0]), "r"(&c[0]), "r"(&d[0]), "r"(&e[0]), "r"(&f[0]), "r"(&g[0]) + :"memory","r6","r7","r8","r9","r10","r11" + ); + return; +} + +#endif + + +void v2add1271_a(uint32_t* a, uint32_t* b, uint32_t* c) +{ // GF(p^2) addition, c = a+b in GF((2^127-1)^2) + // Representation: 23/23/26/26/26/26/26/26/26/26-bit + +asm volatile( + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2,d3}, [%1]! \n\t" + "vadd.s32 q0, q1 \n\t" + + "vld1.8 {d2,d3}, [%0]! \n\t" + "vld1.8 {d4,d5}, [%1]! \n\t" + "vadd.s32 q1, q2 \n\t" + "vst1.64 {d0,d1}, [%2]! \n\t" + + "vld1.8 {d0}, [%0]! \n\t" + "vld1.8 {d1}, [%1]! \n\t" + "vadd.s32 d0, d1 \n\t" + "vst1.64 {d2,d3}, [%2]! \n\t" + "vst1.64 {d0}, [%2]! \n\t" + : + :"r"(&a[0]), "r"(&b[0]), "r"(&c[0]) + ); + return; +} + + +void v2sub1271_a(uint32_t* a, uint32_t* b, uint32_t* c) +{ // GF(p^2) subtraction, c = a-b in GF((2^127-1)^2) + // Representation: 23/23/26/26/26/26/26/26/26/26-bit + +asm volatile( + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2,d3}, [%1]! \n\t" + "vsub.s32 q0, q1 \n\t" + + "vld1.8 {d2,d3}, [%0]! \n\t" + "vld1.8 {d4,d5}, [%1]! \n\t" + "vsub.s32 q1, q2 \n\t" + "vst1.64 {d0,d1}, [%2]! \n\t" + + "vld1.8 {d0}, [%0]! \n\t" + "vld1.8 {d1}, [%1]! \n\t" + "vsub.s32 d0, d1 \n\t" + "vst1.64 {d2,d3}, [%2]! \n\t" + "vst1.64 {d0}, [%2]! \n\t" + : + :"r"(&a[0]), "r"(&b[0]), "r"(&c[0]) + ); + return; +} + + +void v2dblsub1271_a(uint32_t* a, uint32_t* b, uint32_t* c) +{ // GF(p^2) addition followed by subtraction, c = 2a-c in GF((2^127-1)^2) + // Representation: 23/23/26/26/26/26/26/26/26/26-bit + +asm volatile( + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2,d3}, [%1]! \n\t" + "vadd.s32 q0, q0 \n\t" + + "vld1.8 {d4,d5}, [%0]! \n\t" + "vsub.s32 q0, q1 \n\t" + "vld1.8 {d6,d7}, [%1]! \n\t" + "vadd.s32 q2, q2 \n\t" + "vst1.64 {d0,d1}, [%2]! \n\t" + "vsub.s32 q2, q3 \n\t" + + "vld1.8 {d0}, [%0]! \n\t" + "vld1.8 {d1}, [%1]! \n\t" + "vadd.s32 d0, d0 \n\t" + "vst1.64 {d4,d5}, [%2]! \n\t" + "vsub.s32 d0, d1 \n\t" + "vst1.64 {d0}, [%2]! \n\t" + : + :"r"(&a[0]), "r"(&b[0]), "r"(&c[0]) + ); + return; +} + + +void v2addsub1271_a(uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d) +{ // GF(p^2) addition and subtraction, c = a+b and d = a-b in GF((2^127-1)^2) + // Representation: 23/23/26/26/26/26/26/26/26/26-bit + +asm volatile( + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2,d3}, [%1]! \n\t" + "vsub.s32 q2, q0, q1 \n\t" + "vadd.s32 q0, q1 \n\t" + "vld1.8 {d2,d3}, [%0]! \n\t" + "vst1.64 {d4,d5}, [%3]! \n\t" + "vld1.8 {d4,d5}, [%1]! \n\t" + "vst1.64 {d0,d1}, [%2]! \n\t" + "vsub.s32 q3, q1, q2 \n\t" + "vadd.s32 q1, q2 \n\t" + "vld1.8 {d0}, [%0]! \n\t" + "vst1.64 {d6,d7}, [%3]! \n\t" + "vld1.8 {d1}, [%1]! \n\t" + "vst1.64 {d2,d3}, [%2]! \n\t" + "vsub.s32 d4, d0, d1 \n\t" + "vadd.s32 d0, d1 \n\t" + "vst1.64 {d4}, [%3]! \n\t" + "vst1.64 {d0}, [%2]! \n\t" + : + :"r"(&a[0]), "r"(&b[0]), "r"(&c[0]), "r"(&d[0]) + ); + return; +} + + +void table_lookup_1x8(vpoint_extproj_precomp_t* Table, vpoint_extproj_precomp_t point, unsigned int digit, unsigned int sign_mask) +{ // Constant-time table lookup to extract a point represented as (X+Y,Y-X,2Z,2dT) corresponding to extended twisted Edwards coordinates (X:Y:Z:T) + // Inputs: sign_mask, digit, table containing 8 points + // Output: P = sign*table[digit], where sign=1 if sign_mask=0xFF...FF and sign=-1 if sign_mask=0 + uint32_t* table = (uint32_t*)Table; + uint32_t* P = (uint32_t*)point; + +asm volatile( + // q0-q11 <- table[0] + "vpush {q4-q7} \n\t" + "vldm %0!, {q0-q4} \n\t" + "push {r4-r6} \n\t" + "vldm %0!, {q5-q9} \n\t" + "sub %2, %2, #1 \n\t" + "mov r4, #6 \n\t" + +"loop0: \n\t" + // If digit>=0 then mask = 0x00...0 else mask = 0xFF...F + "asr r5, %2, #31 \n\t" + "vdup.32 q13, r5 \n\t" + + "vld1.8 {d24,d25}, [%0]! \n\t" + "vbif q0, q12, q13 \n\t" + "vld1.8 {d24,d25}, [%0]! \n\t" + "vbif q1, q12, q13 \n\t" + "vld1.8 {d24,d25}, [%0]! \n\t" + "vbif q2, q12, q13 \n\t" + "vld1.8 {d24,d25}, [%0]! \n\t" + "vbif q3, q12, q13 \n\t" + "vld1.8 {d24,d25}, [%0]! \n\t" + "vbif q4, q12, q13 \n\t" + "vld1.8 {d24,d25}, [%0]! \n\t" + "vbif q5, q12, q13 \n\t" + "vld1.8 {d24,d25}, [%0]! \n\t" + "vbif q6, q12, q13 \n\t" + "vld1.8 {d24,d25}, [%0]! \n\t" + "vbif q7, q12, q13 \n\t" + "vld1.8 {d24,d25}, [%0]! \n\t" + "vbif q8, q12, q13 \n\t" + "vld1.8 {d24,d25}, [%0]! \n\t" + "vbif q9, q12, q13 \n\t" + "sub %2, %2, #1 \n\t" + + "subs r4, r4, #1 \n\t" + "bpl loop0 \n\t" + + // If sign_mask = 0 then choose negative of the point + "vdup.32 q15, %3 \n\t" + "vmov d28, d5 \n\t" + "vmov q12, q3 \n\t" + "vmov q13, q4 \n\t" + "vmov.i32 d20, 0xFFFFFFFF \n\t" // mask_26 + "vbif d5, d0, d30 \n\t" + "vbif d6, d1, d30 \n\t" + "vbif d7, d2, d30 \n\t" + "vbif d8, d3, d30 \n\t" + "vbif d9, d4, d30 \n\t" + "vshr.u32 d20, d20, #6 \n\t" + "vbif d0, d28, d30 \n\t" + "vbif d1, d24, d30 \n\t" + "vbif d2, d25, d30 \n\t" + "vbif d3, d26, d30 \n\t" + "vbif d4, d27, d30 \n\t" + "vstmia %1!, {d0-d14} \n\t" + "vshr.u32 d21, d20, #3 \n\t" // mask_23 + "vsub.s32 d24, d20, d15 \n\t" // Negate t2 coordinate + "vsub.s32 d25, d20, d16 \n\t" + "vsub.s32 d26, d20, d17 \n\t" + "vsub.s32 d27, d20, d18 \n\t" + "vsub.s32 d28, d21, d19 \n\t" + "vbif d15, d24, d30 \n\t" + "vbif d16, d25, d30 \n\t" + "vbif d17, d26, d30 \n\t" + "vbif d18, d27, d30 \n\t" + "vbif d19, d28, d30 \n\t" + "vstmia %1!, {d15-d19} \n\t" + "pop {r4-r6} \n\t" + "vpop {q4-q7} \n\t" + : + :"r"(&table[0]), "r"(&P[0]), "r"(digit), "r"(sign_mask) + :"memory","r4","r5","r6" + ); + return; +} + + +void vmul1271_a(uint32_t* a, uint32_t* b, uint32_t* c) +{ // Vectorized field multiplication over GF(2^127-1) + // Operation: c [r3] = a [r1] * b [r2] + +asm volatile( + // q0-q1[0] <- a, q3-q4[0] <- b + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2}, [%0]! \n\t" + "vpush {q4-q7} \n\t" + "vshl.i32 q6, q0, #3 \n\t" // q6-q7[0] = 8*(a0-a4) + "vshl.i32 d14, d2, #3 \n\t" + "vld1.8 {d6,d7}, [%1]! \n\t" + "vld1.8 {d8}, [%1]! \n\t" + + // q13-q15[0] <- a*b + "vmull.s32 q15, d12, d8[0] \n\t" // q15 = 8*(a0*b4 | a1*b4) + "vmlal.s32 q15, d6, d14[0] \n\t" // q15 = 8*(a0*b4 + a4*b0 | a1*b4 + a4*b1) + "vmlal.s32 q15, d7, d13[0] \n\t" // q15 = 8*(a0*b4 + a4*b0 + a2*b2 | a1*b4 + a4*b1 + a2*b3) + "vmull.s32 q13, d13, d8[0] \n\t" // q13 = 8*(a2*b4 | a3*b4) + "vmlal.s32 q13, d7, d14[0] \n\t" // q13 = 8*(a2*b4 + a4*b2 | a3*b4 + a4*b3) + "vmlal.s32 q13, d6, d0[1] \n\t" // q13 = a1*b0 + 8*(a2*b4 + a4*b2) | a1*b1 + 8*(a3*b4 + a4*b3) + "vmull.s32 q14, d8, d14[0] \n\t" // q14 = 8*a4*b4 | x + "vshr.s64 d30, d30, #3 \n\t" // q15 = a0*b4 + a4*b0 + a2*b2 | 8*(a1*b4 + a4*b1 + a2*b3) + "vmov d29, d30 \n\t" + "vmlal.s32 q14, d7, d0[1] \n\t" // q14 = a1*b2 + 8*(a4*b4) | a1*b3 + "vmlal.s32 q14, d1, d6[1] \n\t" // q14 = a1*b2 + a2*b1 + 8*(a4*b4) | a0*b4 + a4*b0 + a1*b3 + a3*b1 + a2*b2 + "vmov d30, d29 \n\t" + "vext.s32 q14, q13, q14, #2 \n\t" + "vext.s32 q13, q15, q13, #2 \n\t" // result: q13-q15[0] + "vmlal.s32 q13, d6, d0[0] \n\t" // q13 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3) | a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2) + "vmlal.s32 q13, d7, d13[1] \n\t" // q13 = a0*b0 + 8*(a1*b4 + a4*b1 + a2*b3 + a3*b2) | a0*b1 + a1*b0 + 8*(a2*b4 + a4*b2 + a3*b3) + "vmlal.s32 q14, d7, d0[0] \n\t" // q14 = a0*b2 + a1*b1 + 8*(a3*b4 + a4*b3) | a0*b3 + a1*b2 + a2*b1 + 8*(a4*b4) + "vmlal.s32 q14, d1, d6[0] \n\t" // q14 = a0*b2 + a2*b0 + a1*b1 + 8*(a3*b4 + a4*b3) | a0*b3 + a3*b0 + a1*b2 + a2*b1 + 8*(a4*b4) + + // Reduction + "vmov.i64 q9, 0xFFFFFFFF \n\t" // mask_26 + "vshr.u64 q9, q9, #6 \n\t" + "vmov.i64 d31, #0 \n\t" + "vswp d29, d27 \n\t" + "vswp d29, d28 \n\t" + "vshr.s64 q10, q13, #26 \n\t" + "vswp d30, d29 \n\t" + "vadd.s64 q10, q14, q10 \n\t" + "vand.u64 q0, q13, q9 \n\t" + "vshr.s64 q8, q10, #26 \n\t" + "vand.u64 q1, q10, q9 \n\t" + "vadd.s64 q8, q15, q8 \n\t" + "vand.u64 q2, q8, q9 \n\t" + "vshl.i64 d22, d17, #3 \n\t" + "vshr.s64 d23, d16, #26 \n\t" + "vand.u64 q5, q11, q9 \n\t" + "vshr.s64 q6, q11, #26 \n\t" + "vadd.s64 q0, q0, q5 \n\t" + "vadd.s64 q1, q1, q6 \n\t" + + "vst2.32 {d0[0],d2[0]}, [%2]! \n\t" + "vst1.32 {d4[0]}, [%2]! \n\t" + "vst2.32 {d1[0],d3[0]}, [%2]! \n\t" + "vpop {q4-q7} \n\t" + : + :"r"(&a[0]), "r"(&b[0]), "r"(&c[0]) + ); + return; +} + + +void vsqr1271_a(uint32_t* a, uint32_t* c) +{ // Vectorized field squaring over GF(2^127-1) + // Operation: c [r2] = a^2 [r1] + +asm volatile( + // q0-q1[0] <- a + "vld1.8 {d0,d1}, [%0]! \n\t" + "vld1.8 {d2}, [%0]! \n\t" + "vext.s32 q2, q0, q1, #1 \n\t" // q2: a1|a2|a3|a4 + "vpush {q4-q7} \n\t" + + // q13-q15[0] <- a^2 + "vqdmull.s32 q14, d4, d0[1] \n\t" // q14 = 2*(a1^2 | a1*a2) + "vext.s32 d6, d5, d5, #1 \n\t" + "vqdmull.s32 q15, d6, d0 \n\t" // q15 = 2*(a0*a4 | a1*a3) + "vshl.i32 d2, d2, #1 \n\t" // d2: 2*a4|x + "vshr.s64 d28, d28, #1 \n\t" // q14 = a1^2 | 2*a1*a2 + "vadd.s64 d30, d30, d31 \n\t" // q15 = 2*(a0*a4 + a1*a3) | x + "vtrn.32 d2, d6 \n\t" // d2: 2*a4|a4 + "vqdmull.s32 q13, d0, d0[0] \n\t" // q13 = 2*(a0^2 | a0*a1) + "vshl.i32 q2, q2, #3 \n\t" // q2: 8*(a1|a2|a3|a4) + "vmlal.s32 q15, d1, d1 \n\t" // q15 = 2*(a0*a4 + a1*a3) + a2^2 | x + "vmov.i64 q9, 0xFFFFFFFF \n\t" // mask_26 + "vshr.s64 d26, d26, #1 \n\t" // q13 = a0^2 | 2*a0*a1 + "vmlal.s32 q13, d4, d2[0] \n\t" // q13 = a0^2 + 16*a1*a4 | 2*a0*a1 +16*a2*a4 + "vshr.s32 d4, d4, #2 \n\t" // q2: 2*(a1|a2)|8*(a3|a4) + "vmlal.s32 q14, d5, d2 \n\t" // q14 = a1^2 + 16*a3*a4 | 2*a1*a2 + 8*a4^2 + "vqdmlal.s32 q14, d1, d0[0] \n\t" // q14 = 2*a0*a2 + a1^2 + 16*a3*a4 | 2*a0*a3 + 2*a1*a2 + 8*a4^2 + "vtrn.32 d4, d1 \n\t" // d1: 2*a2|a3 + "vmlal.s32 q13, d1, d5[0] \n\t" // q13 = a0^2 + 16*a1*a4 + 16*a2*a3 | 2*a0*a1 + 16*a2*a4 + 8*a3^2 + + // Reduction + "vshr.u64 q9, q9, #6 \n\t" + "vmov.i64 d31, #0 \n\t" + "vswp d29, d27 \n\t" + "vswp d29, d28 \n\t" + "vshr.s64 q10, q13, #26 \n\t" + "vswp d30, d29 \n\t" + "vadd.s64 q10, q14, q10 \n\t" + "vand.u64 q0, q13, q9 \n\t" + "vshr.s64 q8, q10, #26 \n\t" + "vand.u64 q1, q10, q9 \n\t" + "vadd.s64 q8, q15, q8 \n\t" + "vand.u64 q2, q8, q9 \n\t" + "vshl.i64 d22, d17, #3 \n\t" + "vshr.s64 d23, d16, #26 \n\t" + "vand.u64 q5, q11, q9 \n\t" + "vshr.s64 q6, q11, #26 \n\t" + "vadd.s64 q0, q0, q5 \n\t" + "vadd.s64 q1, q1, q6 \n\t" + + "vst2.32 {d0[0],d2[0]}, [%1]! \n\t" + "vst1.32 {d4[0]}, [%1]! \n\t" + "vst2.32 {d1[0],d3[0]}, [%1]! \n\t" + "vpop {q4-q7} \n\t" + : + :"r"(&a[0]), "r"(&c[0]) + ); + return; +} + + +void mul_truncate_a(uint32_t* a, uint32_t* b, uint32_t* c) +{ // 256-bit multiplication with truncation for the scalar decomposition + // Outputs 64-bit value c = (uint64_t)((a * b) >> 256). + +asm volatile( + "push {r4-r12} \n\t" + + "ldm %0!, {r3-r4} \n\t" + "ldr r5, [%1, #0] \n\t" + "mov r8, #0 \n\t" + "sub r13, r13, #12 \n\t" // Allocating space in the stack + "umull r7, r6, r5, r3 \n\t" + "umlal r6, r8, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "mov r9, #0 \n\t" + "mov r10, #0 \n\t" + "str r6, [r13], #4 \n\t" // Store in stack + "umlal r8, r9, r5, r3 \n\t" + "umlal r9, r10, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "mov r11, #0 \n\t" + "mov r12, #0 \n\t" + "umlal r10, r11, r5, r3 \n\t" + "umlal r11, r12, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "mov r6, #0 \n\t" + "mov r7, #0 \n\t" + "sub %0, %0, #32 \n\t" + "umlal r12, r6, r5, r3 \n\t" + "umlal r6, r7, r5, r4 \n\t" + "stm r13, {r6-r7} \n\t" // Store in stack + + "sub r13, r13, #4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "ldr r5, [%1, #4] \n\t" + "ldr r6, [r13] \n\t" + "mov r7, #0 \n\t" + "umlal r6, r7, r5, r3 \n\t" + "umaal r7, r8, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "str r7, [r13], #4 \n\t" // Store in stack + "umaal r8, r9, r5, r3 \n\t" + "umaal r9, r10, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "umaal r10, r11, r5, r3 \n\t" + "umaal r11, r12, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "ldm r13, {r6-r7} \n\t" + "sub %0, %0, #32 \n\t" + "umaal r12, r6, r5, r3 \n\t" + "umaal r6, r7, r5, r4 \n\t" + "stm r13, {r6-r7} \n\t" // Store in stack + + "sub r13, r13, #4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "ldr r5, [%1, #8] \n\t" + "ldr r7, [r13] \n\t" + "mov r6, #0 \n\t" + "umlal r7, r6, r5, r3 \n\t" + "umaal r6, r8, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "str r6, [r13], #4 \n\t" // Store in stack + "umaal r8, r9, r5, r3 \n\t" + "umaal r9, r10, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "umaal r10, r11, r5, r3 \n\t" + "umaal r11, r12, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "ldm r13, {r6-r7} \n\t" + "sub %0, %0, #32 \n\t" + "umaal r12, r6, r5, r3 \n\t" + "umaal r6, r7, r5, r4 \n\t" + "stm r13, {r6-r7} \n\t" // Store in stack + + "sub r13, r13, #4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "ldr r5, [%1, #12] \n\t" + "ldr r6, [r13] \n\t" + "mov r7, #0 \n\t" + "umlal r6, r7, r5, r3 \n\t" + "umaal r7, r8, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "str r7, [r13], #4 \n\t" // Store in stack + "umaal r8, r9, r5, r3 \n\t" + "umaal r9, r10, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "umaal r10, r11, r5, r3 \n\t" + "umaal r11, r12, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "ldm r13, {r6-r7} \n\t" + "sub %0, %0, #32 \n\t" + "umaal r12, r6, r5, r3 \n\t" + + "sub r13, r13, #4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "ldr r5, [%1, #16] \n\t" + "ldr r7, [r13] \n\t" + "mov r6, #0 \n\t" + "umlal r7, r6, r5, r3 \n\t" + "umaal r6, r8, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "str r6, [r13] \n\t" // Store in stack + "umaal r8, r9, r5, r3 \n\t" + "umaal r9, r10, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "sub %0, %0, #24 \n\t" + "umaal r10, r11, r5, r3 \n\t" + "umaal r11, r12, r5, r4 \n\t" + + "ldm %0!, {r3-r4} \n\t" + "ldr r5, [%1, #20] \n\t" + "ldr r6, [r13], #12 \n\t" + "mov r7, #0 \n\t" + "umlal r6, r7, r5, r3 \n\t" + "umaal r7, r8, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "umaal r8, r9, r5, r3 \n\t" + "umaal r9, r10, r5, r4 \n\t" + "ldm %0!, {r3-r4} \n\t" + "sub %0, %0, #24 \n\t" + "umaal r10, r11, r5, r3 \n\t" + + "ldm %0!, {r3-r4} \n\t" + "ldr r5, [%1, #24] \n\t" + "ldm %0!, {r11-r12} \n\t" + "mov r6, #0 \n\t" + "umlal r7, r6, r5, r3 \n\t" + "umaal r6, r8, r5, r4 \n\t" + "umaal r8, r9, r5, r11 \n\t" + "umaal r9, r10, r5, r12 \n\t" + "stm %2!, {r8-r9} \n\t" + "pop {r4-r12} \n\t" + : + :"r"(&a[0]), "r"(&b[0]), "r"(&c[0]) + :"memory","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12" + ); + return; +} + + +void table_lookup_fixed_base(vpoint_precomp_t* Table, vpoint_precomp_t point, unsigned int digit, unsigned int sign) +{ // Constant-time table lookup to extract a point represented as (x+y,y-x,2t) corresponding to extended twisted Edwards coordinates (X:Y:Z:T) with Z=1 + // Inputs: sign, digit, table containing VPOINTS_FIXEDBASE = 2^(W_FIXEDBASE-1) points + // Output: if sign=0 then P = table[digit], else if (sign=-1) then P = -table[digit] + uint32_t* table = (uint32_t*)Table; + uint32_t* P = (uint32_t*)point; + uint32_t npoints = VPOINTS_FIXEDBASE; + +asm volatile( + // q0-q8 <- table[0] + "vpush {q4-q7} \n\t" + "vldm %0!, {q0-q4} \n\t" + "push {r5-r6} \n\t" + "vldm %0!, {q5-q6} \n\t" + "vld1.8 {d14}, [%0]! \n\t" + "sub %4, %4, #2 \n\t" + +"loop1: \n\t" + // If digit>=0 then mask = 0x00...0 else mask = 0xFF...F + "sub %2, %2, #1 \n\t" + "asr r5, %2, #31 \n\t" + "vdup.32 q14, r5 \n\t" + + "vld1.8 {d30,d31}, [%0]! \n\t" + "vbif q0, q15, q14 \n\t" + "vld1.8 {d30,d31}, [%0]! \n\t" + "vbif q1, q15, q14 \n\t" + "vld1.8 {d30,d31}, [%0]! \n\t" + "vbif q2, q15, q14 \n\t" + "vld1.8 {d30,d31}, [%0]! \n\t" + "vbif q3, q15, q14 \n\t" + "vld1.8 {d30,d31}, [%0]! \n\t" + "vbif q4, q15, q14 \n\t" + "vld1.8 {d30,d31}, [%0]! \n\t" + "vbif q5, q15, q14 \n\t" + "vld1.8 {d30,d31}, [%0]! \n\t" + "vbif q6, q15, q14 \n\t" + "vld1.8 {d30}, [%0]! \n\t" + "vbif d14, d30, d28 \n\t" + + "subs %4, %4, #1 \n\t" + "bpl loop1 \n\t" + + // If sign = 0 then choose positive of the point + "vdup.32 q15, %3 \n\t" + "vmov d28, d5 \n\t" + "vmov q12, q3 \n\t" + "vmov q13, q4 \n\t" + "vbit d5, d0, d30 \n\t" + "vbit d6, d1, d30 \n\t" + "vbit d7, d2, d30 \n\t" + "vbit d8, d3, d30 \n\t" + "vbit d9, d4, d30 \n\t" + "vbit d0, d28, d30 \n\t" + "vbit d1, d24, d30 \n\t" + "vbit d2, d25, d30 \n\t" + "vbit d3, d26, d30 \n\t" + "vbit d4, d27, d30 \n\t" + "vstmia %1!, {d0-d9} \n\t" + "vmov.i32 q0, 0xFFFFFFFF \n\t" // mask_26 + "vshr.u32 q0, q0, #6 \n\t" + "vsub.s32 q12, q0, q5 \n\t" // Negate t2 coordinate + "vsub.s32 q13, q0, q6 \n\t" + "vshr.u32 q0, q0, #3 \n\t" // mask_23 + "vsub.s32 d28, d0, d14 \n\t" + "vbit q5, q12, q15 \n\t" + "vbit q6, q13, q15 \n\t" + "vbit d14, d28, d30 \n\t" + "vstmia %1!, {d10-d14} \n\t" + "pop {r5-r6} \n\t" + "vpop {q4-q7} \n\t" + : + :"r"(&table[0]), "r"(&P[0]), "r"(digit), "r"(sign), "r"(npoints) + :"memory","r5","r6" + ); + return; +} \ No newline at end of file diff --git a/FourQ_ARM_NEON/FourQ.h b/FourQ_ARM_NEON/FourQ.h new file mode 100644 index 0000000..40297dd --- /dev/null +++ b/FourQ_ARM_NEON/FourQ.h @@ -0,0 +1,164 @@ +/***************************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: main header file +* +* 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). +******************************************************************************************/ + +#ifndef __FOURQ_H__ +#define __FOURQ_H__ + + +// For C++ +#ifdef __cplusplus +extern "C" { +#endif + + +#include +#include + + +// Definition of operating system + +#define OS_LINUX 1 + +#if defined(__LINUX__) // Linux OS + #define OS_TARGET OS_LINUX +#else + #error -- "Unsupported OS" +#endif + + +// Definition of compiler + +#define COMPILER_GCC 1 +#define COMPILER_CLANG 2 + +#if defined(__GNUC__) // GNU GCC compiler + #define COMPILER COMPILER_GCC +#elif defined(__clang__) // Clang compiler + #define COMPILER COMPILER_CLANG +#else + #error -- "Unsupported COMPILER" +#endif + + +// Definition of the targeted architecture and basic data types + +#define TARGET_ARM 1 + +#if defined(_ARM_) + #define TARGET TARGET_ARM + #define RADIX 32 + typedef uint32_t digit_t; // Unsigned 32-bit digit + typedef int32_t sdigit_t; // Signed 32-bit digit + #define NWORDS_FIELD 4 + #define NWORDS_ORDER 8 +#else + #error -- "Unsupported ARCHITECTURE" +#endif + + +// Constants + +#define RADIX64 64 +#define NWORDS64_FIELD 2 // Number of 64-bit words of a field element +#define NWORDS64_ORDER 4 // Number of 64-bit words of an element in Z_r + + +// Definition of complementary cryptographic functions + +#define RandomBytesFunction random_bytes +#define CryptoHashFunction crypto_sha512 // Use SHA-512 by default + + +// Detect if additional optimizationes are enabled + +#if defined(_INTERLEAVE_) + #define INTERLEAVE // Interleaving of instructions +#endif + +#if defined(_MIX_ARM_NEON_) + #define MIX_ARM_NEON // Mix ARM/NEON instructions +#endif + + +// Basic parameters for variable-base scalar multiplication (without using endomorphisms) +#define W_VARBASE 5 +#define NBITS_ORDER_PLUS_ONE 246+1 + + +// Basic parameters for fixed-base scalar multiplication +#define W_FIXEDBASE 5 // Memory requirement: 7.5KB (storage for 80 points). +#define V_FIXEDBASE 5 + +// Basic parameters for double scalar multiplication +#define WP_DOUBLEBASE 8 // Memory requirement: 24KB (storage for 256 points). +#define WQ_DOUBLEBASE 4 + + +// FourQ's basic element definitions and point representations + +typedef digit_t felm_t[NWORDS_FIELD]; // Datatype for representing 128-bit field elements +typedef felm_t f2elm_t[2]; // Datatype for representing quadratic extension field elements + +typedef struct { f2elm_t x; f2elm_t y; } point_affine; // Point representation in affine coordinates. +typedef point_affine point_t[1]; + + +// FourQ's vectorized element definitions and point representations + +#define VWORDS_FIELD 5 // Number of 32-bit words of a vectorized field element + +typedef uint32_t velm_t[VWORDS_FIELD]; // Datatype for representing 128-bit vectorized field elements +typedef uint32_t v2elm_t[2*VWORDS_FIELD]; // Datatype for representing vectorized quadratic extension field elements + +typedef struct { v2elm_t x; v2elm_t y; } vpoint_affine; // Point representation in affine coordinates. +typedef vpoint_affine vpoint_t[1]; + + +// Definitions of the error-handling type and error codes + +typedef enum { + ECCRYPTO_ERROR, // 0x00 + ECCRYPTO_SUCCESS, // 0x01 + ECCRYPTO_ERROR_DURING_TEST, // 0x02 + ECCRYPTO_ERROR_UNKNOWN, // 0x03 + ECCRYPTO_ERROR_NOT_IMPLEMENTED, // 0x04 + ECCRYPTO_ERROR_NO_MEMORY, // 0x05 + ECCRYPTO_ERROR_INVALID_PARAMETER, // 0x06 + ECCRYPTO_ERROR_SHARED_KEY, // 0x07 + ECCRYPTO_ERROR_SIGNATURE_VERIFICATION, // 0x08 + ECCRYPTO_ERROR_END_OF_LIST +} ECCRYPTO_STATUS; + +#define ECCRYPTO_STATUS_TYPE_SIZE (ECCRYPTO_ERROR_END_OF_LIST) + + +// Error message definitions + +#define ECCRYPTO_MSG_ERROR "ECCRYPTO_ERROR" +#define ECCRYPTO_MSG_SUCCESS "ECCRYPTO_SUCCESS" +#define ECCRYPTO_MSG_ERROR_DURING_TEST "ECCRYPTO_ERROR_DURING_TEST" +#define ECCRYPTO_MSG_ERROR_UNKNOWN "ECCRYPTO_ERROR_UNKNOWN" +#define ECCRYPTO_MSG_ERROR_NOT_IMPLEMENTED "ECCRYPTO_ERROR_NOT_IMPLEMENTED" +#define ECCRYPTO_MSG_ERROR_NO_MEMORY "ECCRYPTO_ERROR_NO_MEMORY" +#define ECCRYPTO_MSG_ERROR_INVALID_PARAMETER "ECCRYPTO_ERROR_INVALID_PARAMETER" +#define ECCRYPTO_MSG_ERROR_SHARED_KEY "ECCRYPTO_ERROR_SHARED_KEY" +#define ECCRYPTO_MSG_ERROR_SIGNATURE_VERIFICATION "ECCRYPTO_ERROR_SIGNATURE_VERIFICATION" + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/FourQ_ARM_NEON/FourQ_api.h b/FourQ_ARM_NEON/FourQ_api.h new file mode 100644 index 0000000..77d5d74 --- /dev/null +++ b/FourQ_ARM_NEON/FourQ_api.h @@ -0,0 +1,116 @@ +/***************************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: API header file +* +* 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). +******************************************************************************************/ + +#ifndef __FOURQ_API_H__ +#define __FOURQ_API_H__ + + +// For C++ +#ifdef __cplusplus +extern "C" { +#endif + + +#include "FourQ.h" + + +/**************** Public ECC API ****************/ + +// Set generator G = (x,y) +void eccset(point_t G); + +// Variable-base scalar multiplication Q = k*P +bool ecc_mul(point_t P, digit_t* k, point_t Q, bool clear_cofactor); + +// Fixed-base scalar multiplication Q = k*G, where G is the generator +bool ecc_mul_fixed(digit_t* k, point_t Q); + +// Double scalar multiplication R = k*G + l*Q, where G is the generator +bool ecc_mul_double(digit_t* k, point_t Q, digit_t* l, point_t R); + + +/**************** Public API for SchnorrQ ****************/ + +// SchnorrQ public key generation +// It produces a public key PublicKey, which is the encoding of P = s*G, where G is the generator and +// s is the output of hashing SecretKey and taking the least significant 32 bytes of the result. +// Input: 32-byte SecretKey +// Output: 32-byte PublicKey +ECCRYPTO_STATUS SchnorrQ_KeyGeneration(const unsigned char* SecretKey, unsigned char* PublicKey); + +// SchnorrQ keypair generation +// It produces a private key SecretKey and computes the public key PublicKey, which is the encoding of P = s*G, +// where G is the generator and s is the output of hashing SecretKey and taking the least significant 32 bytes of the result. +// Outputs: 32-byte SecretKey and 32-byte PublicKey +ECCRYPTO_STATUS SchnorrQ_FullKeyGeneration(unsigned char* SecretKey, unsigned char* PublicKey); + +// SchnorrQ signature generation +// It produces the signature Signature of a message Message of size SizeMessage in bytes +// Inputs: 32-byte SecretKey, 32-byte PublicKey, and Message of size SizeMessage in bytes +// Output: 64-byte Signature +ECCRYPTO_STATUS SchnorrQ_Sign(const unsigned char* SecretKey, const unsigned char* PublicKey, const unsigned char* Message, const unsigned int SizeMessage, unsigned char* Signature); + +// SchnorrQ signature verification +// It verifies the signature Signature of a message Message of size SizeMessage in bytes +// Inputs: 32-byte PublicKey, 64-byte Signature, and Message of size SizeMessage in bytes +// Output: true (valid signature) or false (invalid signature) +ECCRYPTO_STATUS SchnorrQ_Verify(const unsigned char* PublicKey, const unsigned char* Message, const unsigned int SizeMessage, const unsigned char* Signature, unsigned int* valid); + + +/**************** Public API for co-factor ECDH key exchange with compressed, 32-byte public keys ****************/ + +// Compressed public key generation for key exchange +// It produces a public key PublicKey, which is the encoding of P = SecretKey*G (G is the generator). +// Input: 32-byte SecretKey +// Output: 32-byte PublicKey +ECCRYPTO_STATUS CompressedPublicKeyGeneration(const unsigned char* SecretKey, unsigned char* PublicKey); + +// Keypair generation for key exchange. Public key is compressed to 32 bytes +// It produces a private key SecretKey and a public key PublicKey, which is the encoding of P = SecretKey*G (G is the generator). +// Outputs: 32-byte SecretKey and 32-byte PublicKey +ECCRYPTO_STATUS CompressedKeyGeneration(unsigned char* SecretKey, unsigned char* PublicKey); + +// Secret agreement computation for key exchange using a compressed, 32-byte public key +// The output is the y-coordinate of SecretKey*A, where A is the decoding of the public key PublicKey. +// Inputs: 32-byte SecretKey and 32-byte PublicKey +// Output: 32-byte SharedSecret +ECCRYPTO_STATUS CompressedSecretAgreement(const unsigned char* SecretKey, const unsigned char* PublicKey, unsigned char* SharedSecret); + + +/**************** Public API for co-factor ECDH key exchange with uncompressed, 64-byte public keys ****************/ + +// Public key generation for key exchange +// It produces the public key PublicKey = SecretKey*G, where G is the generator. +// Input: 32-byte SecretKey +// Output: 64-byte PublicKey +ECCRYPTO_STATUS PublicKeyGeneration(const unsigned char* SecretKey, unsigned char* PublicKey); + +// Keypair generation for key exchange +// It produces a private key SecretKey and computes the public key PublicKey = SecretKey*G, where G is the generator. +// Outputs: 32-byte SecretKey and 64-byte PublicKey +ECCRYPTO_STATUS KeyGeneration(unsigned char* SecretKey, unsigned char* PublicKey); + +// Secret agreement computation for key exchange +// The output is the y-coordinate of SecretKey*PublicKey. +// Inputs: 32-byte SecretKey and 64-byte PublicKey +// Output: 32-byte SharedSecret +ECCRYPTO_STATUS SecretAgreement(const unsigned char* SecretKey, const unsigned char* PublicKey, unsigned char* SharedSecret); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/FourQ_ARM_NEON/FourQ_internal.h b/FourQ_ARM_NEON/FourQ_internal.h new file mode 100644 index 0000000..1d9cfbe --- /dev/null +++ b/FourQ_ARM_NEON/FourQ_internal.h @@ -0,0 +1,360 @@ +/***************************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: internal header file +* +* 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). +******************************************************************************************/ + +#ifndef __FOURQ_INTERNAL_H__ +#define __FOURQ_INTERNAL_H__ + + +// For C++ +#ifdef __cplusplus +extern "C" { +#endif + + +#include "FourQ_api.h" + + +// Basic parameters for variable-base scalar multiplication (without using endomorphisms) +#define NPOINTS_VARBASE (1 << (W_VARBASE-2)) +#define t_VARBASE ((NBITS_ORDER_PLUS_ONE+W_VARBASE-2)/(W_VARBASE-1)) + + +// Basic parameters for fixed-base scalar multiplication +#define E_FIXEDBASE (NBITS_ORDER_PLUS_ONE + W_FIXEDBASE*V_FIXEDBASE - 1)/(W_FIXEDBASE*V_FIXEDBASE) +#define D_FIXEDBASE E_FIXEDBASE*V_FIXEDBASE +#define L_FIXEDBASE D_FIXEDBASE*W_FIXEDBASE +#define NPOINTS_FIXEDBASE V_FIXEDBASE*(1 << (W_FIXEDBASE-1)) +#define VPOINTS_FIXEDBASE (1 << (W_FIXEDBASE-1)) +#if (NBITS_ORDER_PLUS_ONE-L_FIXEDBASE == 0) // This parameter selection is not supported + #error -- "Unsupported parameter selection for fixed-base scalar multiplication" +#endif + + +// Basic parameters for double scalar multiplication +#define NPOINTS_DOUBLEMUL_WP (1 << (WP_DOUBLEBASE-2)) +#define NPOINTS_DOUBLEMUL_WQ (1 << (WQ_DOUBLEBASE-2)) + + +// FourQ's point representations + +typedef struct { f2elm_t x; f2elm_t y; f2elm_t z; f2elm_t ta; f2elm_t tb; } point_extproj; // Point representation in extended coordinates. +typedef point_extproj point_extproj_t[1]; +typedef struct { f2elm_t xy; f2elm_t yx; f2elm_t z2; f2elm_t t2; } point_extproj_precomp; // Point representation in extended coordinates (for precomputed points). +typedef point_extproj_precomp point_extproj_precomp_t[1]; +typedef struct { f2elm_t xy; f2elm_t yx; f2elm_t t2; } point_precomp; // Point representation in extended affine coordinates (for precomputed points). +typedef point_precomp point_precomp_t[1]; + + +// FourQ's vectorized point representations + +typedef struct { v2elm_t x; v2elm_t y; v2elm_t z; v2elm_t ta; v2elm_t tb; } vpoint_extproj; // Point representation in extended coordinates. +typedef vpoint_extproj vpoint_extproj_t[1]; +typedef struct { v2elm_t xy; v2elm_t yx; v2elm_t z2; v2elm_t t2; } vpoint_extproj_precomp; // Point representation in extended coordinates (for precomputed points). +typedef vpoint_extproj_precomp vpoint_extproj_precomp_t[1]; +typedef struct { v2elm_t xy; v2elm_t yx; v2elm_t t2; } vpoint_precomp; // Point representation in extended affine coordinates (for precomputed points). +typedef vpoint_precomp vpoint_precomp_t[1]; + + +/********************** Constant-time unsigned comparisons ***********************/ + +// The following functions return 1 (TRUE) if condition is true, 0 (FALSE) otherwise + +static __inline unsigned int is_digit_nonzero_ct(digit_t x) +{ // Is x != 0? + return (unsigned int)((x | (0-x)) >> (RADIX-1)); +} + +static __inline unsigned int is_digit_zero_ct(digit_t x) +{ // Is x = 0? + return (unsigned int)(1 ^ is_digit_nonzero_ct(x)); +} + +static __inline unsigned int is_digit_lessthan_ct(digit_t x, digit_t y) +{ // Is x < y? + return (unsigned int)((x ^ ((x ^ y) | ((x - y) ^ y))) >> (RADIX-1)); +} + + +/********************** Macros for digit operations **********************/ + +// Digit addition with carry +#define ADDC(carryIn, addend1, addend2, carryOut, sumOut) \ + { digit_t tempReg = (addend1) + (digit_t)(carryIn); \ + (sumOut) = (addend2) + tempReg; \ + (carryOut) = (is_digit_lessthan_ct(tempReg, (digit_t)(carryIn)) | is_digit_lessthan_ct((sumOut), tempReg)); } + +// Digit subtraction with borrow +#define SUBC(borrowIn, minuend, subtrahend, borrowOut, differenceOut) \ + { digit_t tempReg = (minuend) - (subtrahend); \ + unsigned int borrowReg = (is_digit_lessthan_ct((minuend), (subtrahend)) | ((borrowIn) & is_digit_zero_ct(tempReg))); \ + (differenceOut) = tempReg - (digit_t)(borrowIn); \ + (borrowOut) = borrowReg; } + +// Shift right with flexible datatype +#define SHIFTR(highIn, lowIn, shift, shiftOut, DigitSize) \ + (shiftOut) = ((lowIn) >> (shift)) ^ ((highIn) << (DigitSize - (shift))); + + +/**************** Function prototypes ****************/ + +/************* Arithmetic functions modulo the curve order **************/ + +// Converting to Montgomery representation +void to_Montgomery(const digit_t* ma, digit_t* c); + +// Converting from Montgomery to standard representation +void from_Montgomery(const digit_t* a, digit_t* mc); + +// 256-bit Montgomery multiplication modulo the curve order +void Montgomery_multiply_mod_order(const digit_t* ma, const digit_t* mb, digit_t* mc); + +// Addition modulo the curve order, c = a+b mod order +void add_mod_order(const digit_t* a, const digit_t* b, digit_t* c); + +// Subtraction modulo the curve order, c = a-b mod order +void subtract_mod_order(const digit_t* a, const digit_t* b, digit_t* c); + +// Reduction modulo the order using Montgomery arithmetic internally +void modulo_order(digit_t* a, digit_t* c); + +/************* Multiprecision functions **************/ + +// Check if multiprecision element is zero +bool is_zero_ct(digit_t* a, unsigned int nwords); + +// Multiprecision subtraction, c = a-b. Returns the borrow bit +unsigned int subtract(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords); + +// Clear "nwords" integer-size digits from memory +extern void clear_words(void* mem, unsigned int nwords); + +/************ Field arithmetic functions *************/ + +// Field negation, a = -a mod p +void vneg1271(velm_t a); + +// Field negation over GF(2^127-1) of second element of a GF(p^2) element +void v2neg1271_felm(v2elm_t a); + +// Modular correction, a = a mod p +void vmod1271(velm_t a, velm_t c); + +// Field addition, c = a+b mod p +void vadd1271(velm_t a, velm_t b, velm_t c); + +// Field subtraction, c = a-b mod p +void vsub1271(velm_t a, velm_t b, velm_t c); + +// Field division by two, c = a/2 mod p +void vdiv1271(uint32_t* a); + +// Field squaring, c = a^2 mod p +void vsqr1271(velm_t a, velm_t c); +void vsqr1271_a(uint32_t* a, uint32_t* c); + +// Field multiplication, c = a*b mod p +void vmul1271(velm_t a, velm_t b, velm_t c); +void vmul1271_a(uint32_t* a, uint32_t* b, uint32_t* c); + +// Field inversion, af = a^-1 = a^(p-2) mod p +void vinv1271(velm_t a); + +// Exponentiation over GF(p), af = a^(125-1) +void vexp1251(velm_t a, velm_t af); + +// Conversion functions +void from_std_to_ext(f2elm_t a, v2elm_t c); +void from_ext_to_std(v2elm_t a, f2elm_t c); + +/************ Quadratic extension field arithmetic functions *************/ + +// Convert GF(p^2) element in 23/23/26/26/26/26/26/26/26/26-bit vector representation to +// two field elements in 23/26/26/26/26-bit vector representation +void from_v2_to_v(v2elm_t a, velm_t c0, velm_t c1); + +// Convert two field elements in 23/26/26/26/26-bit vector representation to GF(p^2) element in +// 23/23/26/26/26/26/26/26/26/26-bit vector representation +void from_v_to_v2(velm_t a0, velm_t a1, v2elm_t c); + +// Zeroing a quadratic extension field element, a=0 +void v2zero1271(v2elm_t a); + +// Copy quadratic extension field element, c = a +void fp2copy1271(f2elm_t a, f2elm_t c); +void v2copy1271(v2elm_t a, v2elm_t c); + +// Quadratic extension field negation, a = -a in GF((2^127-1)^2) +void v2neg1271(v2elm_t a); + +// Quadratic extension field addition, c = a+b in GF((2^127-1)^2) +void v2add1271(v2elm_t a, v2elm_t b, v2elm_t c); +void v2add1271_a(uint32_t* a, uint32_t* b, uint32_t* c); + +// Quadratic extension field subtraction, c = a-b in GF((2^127-1)^2) +void v2sub1271(v2elm_t a, v2elm_t b, v2elm_t c); +void v2sub1271_a(uint32_t* a, uint32_t* b, uint32_t* c); + +// Quadratic extension field addition followed by subtraction over GF(2^127-1) +void v2dblsub1271(v2elm_t a, v2elm_t b, v2elm_t c); +void v2dblsub1271_a(uint32_t* a, uint32_t* b, uint32_t* c); + +// Quadratic extension field addition and subtraction over GF(2^127-1) +void v2addsub1271(v2elm_t a, v2elm_t b, v2elm_t c, v2elm_t d); +void v2addsub1271_a(uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d); + +// Modular correction over GF(p^2) +void v2mod1271(v2elm_t a, v2elm_t c); + +// Quadratic extension field multiplication, c = a*b in GF((2^127-1)^2) +void v2mul1271(v2elm_t a, v2elm_t b, v2elm_t c); +void v2mul1271_a(uint32_t* a, uint32_t* b, uint32_t* c); + +// Quadratic extension field squaring, c = a^2 in GF((2^127-1)^2) +void v2sqr1271(v2elm_t a, v2elm_t c); +void v2sqr1271_a(uint32_t* a, uint32_t* c); + +// Vectorized GF(p^2) squaring/addition in GF((2^127-1)^2) +void v2sqradd1271(v2elm_t a, v2elm_t c, v2elm_t d, v2elm_t e, v2elm_t f); +void v2sqradd1271_a(uint32_t* a, uint32_t* c, uint32_t* d, uint32_t* e, uint32_t* f); + +// Vectorized GF(p^2) squaring/addition/subtraction in GF((2^127-1)^2) +void v2sqraddsub1271(v2elm_t a, v2elm_t c, v2elm_t d, v2elm_t e, v2elm_t f, v2elm_t g); +void v2sqraddsub1271_a(uint32_t* a, uint32_t* c, uint32_t* d, uint32_t* e, uint32_t* f, uint32_t* g); + +// Vectorized GF(p^2) multiplication/addition in GF((2^127-1)^2) +void v2muladd1271(v2elm_t a, v2elm_t b, v2elm_t c, v2elm_t d, v2elm_t e, v2elm_t f); +void v2muladd1271_a(uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d, uint32_t* e, uint32_t* f); + +// Vectorized GF(p^2) multiplication/subtraction in GF((2^127-1)^2) +void v2mulsub1271(v2elm_t a, v2elm_t b, v2elm_t c, v2elm_t d, v2elm_t e, v2elm_t f); +void v2mulsub1271_a(uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d, uint32_t* e, uint32_t* f); + +// Vectorized GF(p^2) multiplication/addition/subtraction in GF((2^127-1)^2) +void v2muladdsub1271(v2elm_t a, v2elm_t b, v2elm_t c, v2elm_t d, v2elm_t e, v2elm_t f, v2elm_t g); +void v2muladdsub1271_a(uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d, uint32_t* e, uint32_t* f, uint32_t* g); + +// Vectorized GF(p^2) multiplication/addition/subtraction in GF((2^127-1)^2) +void v2muldlbsub1271(v2elm_t a, v2elm_t b, v2elm_t c, v2elm_t d, v2elm_t e, v2elm_t f); +void v2muldblsub1271_a(uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d, uint32_t* e, uint32_t* f); + +// Vectorized GF(p^2) inversion, af = a^-1 = a^(p-2) in GF((2^127-1)^2) +void v2inv1271(v2elm_t a); + +/************ Curve and recoding functions *************/ + +// Normalize projective twisted Edwards point Q = (X,Y,Z) -> P = (x,y) +void eccnorm(vpoint_extproj_t P, vpoint_t Q); + +// Conversion from representation (X,Y,Z,Ta,Tb) to (X+Y,Y-X,2Z,2dT), where T = Ta*Tb +void R1_to_R2(vpoint_extproj_t P, vpoint_extproj_precomp_t Q); + +// Conversion from representation (X,Y,Z,Ta,Tb) to (X+Y,Y-X,Z,T), where T = Ta*Tb +void R1_to_R3(vpoint_extproj_t P, vpoint_extproj_precomp_t Q); + +// Conversion from representation (X+Y,Y-X,2Z,2dT) to (2X,2Y,2Z,2dT) +void R2_to_R4(vpoint_extproj_precomp_t P, vpoint_extproj_t Q); + +// Point doubling 2P +void eccdouble(vpoint_extproj_t P); + +// Complete point addition P = P+Q or P = P+P +void eccadd(vpoint_extproj_precomp_t Q, vpoint_extproj_t P); +void eccadd_core(vpoint_extproj_precomp_t P, vpoint_extproj_precomp_t Q, vpoint_extproj_t R); + +// Psi mapping of a point, P = psi(P) +void ecc_psi(vpoint_extproj_t P); + +// Phi mapping of a point, P = phi(P) +void ecc_phi(vpoint_extproj_t P); + +// Scalar decomposition +void decompose(uint64_t* k, uint64_t* scalars); + +// 256-bit multiplication with truncation for the scalar decomposition +// Outputs 64-bit value c = (uint64_t)((a * b) >> 256) +void mul_truncate_a(uint32_t* a, uint32_t* b, uint32_t* c); + +// Recoding sub-scalars for use in the variable-base scalar multiplication +void recode(uint64_t* scalars, unsigned int* digits, unsigned int* sign_masks); + +// Convert scalar to odd if even using the prime subgroup order r +void conversion_to_odd(digit_t* k, digit_t* k_odd); + +// Co-factor clearing +void cofactor_clearing(vpoint_extproj_t P); + +// Reduction modulo the order using Montgomery arithmetic +void modulo_order(digit_t* a, digit_t* c); + +// Precomputation function +void ecc_precomp(vpoint_extproj_t P, vpoint_extproj_precomp_t *T); + +// Constant-time table lookup to extract an extended twisted Edwards point (X+Y:Y-X:2Z:2T) from the precomputed table +void table_lookup_1x8(vpoint_extproj_precomp_t* table, vpoint_extproj_precomp_t P, unsigned int digit, unsigned int sign_mask); + +// Modular correction of input coordinates and conversion to representation (X,Y,Z,Ta,Tb) +void point_setup(point_t P, vpoint_extproj_t Q); + +// Point validation: check if point lies on the curve +bool ecc_point_validate(vpoint_extproj_t P); + +// Output error/success message for a given ECCRYPTO_STATUS +const char* FourQ_get_error_message(ECCRYPTO_STATUS Status); + +// Constant-time table lookup to extract a point represented as (x+y,y-x,2t) +void table_lookup_fixed_base(vpoint_precomp_t* table, vpoint_precomp_t P, unsigned int digit, unsigned int sign); + +// Computes the modified LSB-set representation of scalar +void mLSB_set_recode(uint64_t* scalar, unsigned int *digits); + +// Generation of the precomputation table used internally by the double scalar multiplication function ecc_mul_double() +void ecc_precomp_double(vpoint_extproj_t P, vpoint_extproj_precomp_t* Table, unsigned int npoints); + +// Computes wNAF recoding of a scalar +void wNAF_recode(uint64_t scalar, unsigned int w, int* digits); + +// Encode point P +void encode(point_t P, unsigned char* Pencoded); + +// Decode point P +ECCRYPTO_STATUS decode(const unsigned char* Pencoded, point_t P); + + +/************ Functions based on macros *************/ + +// Copy extended projective point Q = (X:Y:Z:Ta:Tb) to P +#define ecccopy(Q, P); v2copy1271((Q)->x, (P)->x); \ + v2copy1271((Q)->y, (P)->y); \ + v2copy1271((Q)->z, (P)->z); \ + v2copy1271((Q)->ta, (P)->ta); \ + v2copy1271((Q)->tb, (P)->tb); + +// Copy extended affine point Q = (x+y,y-x,2dt) to P +#define ecccopy_precomp_fixed_base(Q, P); v2copy1271((Q)->xy, (P)->xy); \ + v2copy1271((Q)->yx, (P)->yx); \ + v2copy1271((Q)->t2, (P)->t2); + +// Vectorize extended projective point Q = (X:Y:Z:Ta:Tb) +#define point_from_std_to_ext(Q, P); from_std_to_ext(Q->x, P->x); \ + from_std_to_ext(Q->y, P->y); \ + from_std_to_ext(Q->z, P->z); \ + from_std_to_ext(Q->ta, P->ta); \ + from_std_to_ext(Q->tb, P->tb); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/FourQ_ARM_NEON/FourQ_params.h b/FourQ_ARM_NEON/FourQ_params.h new file mode 100644 index 0000000..db41fbb --- /dev/null +++ b/FourQ_ARM_NEON/FourQ_params.h @@ -0,0 +1,36 @@ +/****************************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: FourQ's curve parameters +* +* 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). +*******************************************************************************************/ + +#ifndef __FOURQ_PARAMS_H__ +#define __FOURQ_PARAMS_H__ + +#include "FourQ_internal.h" + + +// Encoding of field elements, elements over Z_r and elements over GF(p^2): +// ----------------------------------------------------------------------- +// Elements over GF(p) and Z_r are encoded with the least significant digit located in the leftmost position (i.e., little endian format). +// Elements (a+b*i) over GF(p^2), where a and b are defined over GF(p), are encoded as a||b, with a in the least significant position. +// Parameter "d" is encoded as an interleaved vector using the representation b_4|a_4|...|b_0|a_0 <- 23|23|26|26|26|26|26|26|26|26-bit, +// where the 23-bit digits are the most significant digits. Digits are stored in 32-bit words. + +static const uint32_t PARAMETER_d[10] = { 0x00000142, 0x01FC0C8D, 0x00000000, 0x0085223C, 0x000E4000, 0x020FCB38, 0x00000000, 0x0211995F, 0x00000000, 0x005E472F }; +static const uint64_t GENERATOR_x[4] = { 0x286592AD7B3833AA, 0x1A3472237C2FB305, 0x96869FB360AC77F6, 0x1E1F553F2878AA9C }; +static const uint64_t GENERATOR_y[4] = { 0xB924A2462BCBB287, 0x0E3FEE9BA120785A, 0x49A7C344844C8B5C, 0x6E1C4AF8630E0242 }; +static const uint64_t curve_order[4] = { 0x2FB2540EC7768CE7, 0xDFBD004DFE0F7999, 0xF05397829CBC14E5, 0x0029CBC14E5E0A72 }; +static const uint64_t Montgomery_Rprime[4] = { 0xC81DB8795FF3D621, 0x173EA5AAEA6B387D, 0x3D01B7C72136F61C, 0x0006A5F16AC8F9D3 }; +static const uint64_t Montgomery_rprime[4] = { 0xE12FE5F079BC3929, 0xD75E78B8D1FCDCF3, 0xBCE409ED76B5DB21, 0xF32702FDAFC1C074 }; + + +#endif \ No newline at end of file diff --git a/FourQ_ARM_NEON/FourQ_tables.h b/FourQ_ARM_NEON/FourQ_tables.h new file mode 100644 index 0000000..1769e41 --- /dev/null +++ b/FourQ_ARM_NEON/FourQ_tables.h @@ -0,0 +1,369 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: precomputation tables +************************************************************************************/ + +#ifndef __TABLES_H__ +#define __TABLES_H__ + +#include + + +// The table below was generated using window width W = 5 and table parameter V = 5 (see http://eprint.iacr.org/2013/158). +// Number of point entries = 5 * 2^4 = 80 points, where each point (x,y) is represented using coordinates (x+y,y-x,2*d*t). +// Each coordinate a+b*i in GF(p^2) is encoded as an interleaved vector using the representation b_4|a_4|...|b_0|a_0 <- 23|23| +// 26|26|26|26|26|26|26|26-bit, where the 23-bit digits are the most significant digits. Digits are stored in 32-bit words. +// Table size = 80 * 3 * 320 = 9.375KB + +static const uint32_t FIXED_BASE_TABLE[2400] = { +0x303E631, 0xF90353, 0x28D3CE9, 0x398BDF9, 0x2B5FE18, 0x2CDEE02, 0x2FC7540, 0xDE2E1A, 0x287460, 0xC3BA0, 0x937EDC, 0x3A01366, 0x3C3E62C, 0x48E448, 0x55590B, 0x17A5B32, 0x1E093C3, 0x2E4EA55, 0x740B7C, 0x4FFCF5, 0x3DA42BB, 0x330684C, 0x2BF32EA, 0x2268E4C, 0x17C6297, 0x1F27A81, 0xDD55B2, 0x1C828D0, 0x5948D1, 0xCAF2B, +0x1188787, 0x9F9B77, 0x2E8063F, 0xF30CF0, 0x12A83A8, 0x2049B0B, 0x2062374, 0x3E2E134, 0x554612, 0x1BAEEA, 0x1FAF900, 0x2556066, 0x1096984, 0x33C2684, 0x3789006, 0x36EB6DC, 0x4B869B, 0x3BAB39E, 0x18F7CD, 0x448E05, 0x12829B0, 0x3C03EE, 0x3CCDA27, 0xD4F6F7, 0x3DB4BF2, 0x25019F2, 0x32CA55E, 0x16EAFB, 0x6D911D, 0x6C543, +0x1AFA125, 0x1313EF2, 0x3D15C4F, 0x1DDC7E7, 0x364D2EA, 0x306961B, 0x1619228, 0x3E2FF8A, 0x729630, 0x4F41C7, 0x19790AC, 0xDD7487, 0x188EB96, 0x1A59927, 0xA42408, 0x2114FC5, 0x21910CC, 0x3839663, 0x4D3385, 0x74DF72, 0x13C110B, 0x2BFF3D9, 0x18C964, 0x679975, 0x30D8C9A, 0x3A08766, 0x457F92, 0x51F3B8, 0x76BD4, 0x249240, +0x965A73, 0x1F7A57B, 0x16E5852, 0x7014CA, 0x3706D69, 0x200E41F, 0x28A20A7, 0x3A27C0F, 0x28AAC8, 0x441CA9, 0x3F7241E, 0x25400C6, 0x28E2AE2, 0x2BE2E3E, 0x37F4E1A, 0x63ECAD, 0x2BF20CA, 0x18A13A, 0x58F28C, 0x34B6D1, 0x2F15097, 0x48E8BC, 0x2632ACE, 0x3DDAA05, 0x1C49F54, 0x200663B, 0x24005F6, 0x16FC8EB, 0x6DBE77, 0x637192, +0x1ED81FA, 0x975810, 0xB1C86F, 0x3366D6D, 0x16ABC5E, 0x1AA88F3, 0x3BB5A01, 0x64BC2A, 0x4EDE70, 0x4752FD, 0x3734414, 0x2B1A34E, 0x1E53AC7, 0xEC1BDC, 0x662318, 0x2770261, 0x34B211A, 0x2CDEAC1, 0x11DDF7, 0x465575, 0x2638D2B, 0x1B4F131, 0x26117E0, 0x2E4E940, 0x18CE40B, 0x32FBBED, 0x141E40A, 0x34A226, 0x488940, 0x4F356, +0x15B278B, 0x20C977E, 0x3761D44, 0x1307373, 0x58A457, 0x99692D, 0x395364A, 0x1061F5D, 0x56F25E, 0x78FCA, 0x2CC22A1, 0x1C2BAA2, 0x2CB7B5D, 0xDD9F2E, 0x2BF63BB, 0xA8F43F, 0x214F770, 0x9783AA, 0x117B28, 0x73079E, 0x215796D, 0x3372916, 0x1E64AD6, 0x2620D59, 0x2F92017, 0x176DBE0, 0x520367, 0x1ADEBDD, 0x2E7772, 0x258F17, +0x168391B, 0x3E85114, 0xCE3F58, 0x303F413, 0x13A4308, 0x2B51862, 0x17E69CD, 0x39D08EB, 0x728592, 0x53259E, 0x33B1A68, 0x1C928A7, 0xC6A12, 0x35505A3, 0x31FCFE0, 0x2A6A2DD, 0x1987E81, 0x6B7C65, 0x1A4F1D, 0x60185C, 0x6DA9B4, 0x1FA7E8D, 0x25C5F7, 0x3A9BE81, 0x3C03498, 0x8A0A41, 0x12D373F, 0x1BC9DC5, 0x606209, 0x4A4FE0, +0x29E80F0, 0x29A039E, 0x94EA7B, 0x8EF99A, 0x17337BB, 0x14BB843, 0x22F32C4, 0x2BA5CA0, 0x419A92, 0x1B2D1, 0x3051231, 0x22F22DD, 0x2216134, 0x241BF8F, 0x1DD7A75, 0x1A0F91D, 0x83325E, 0x25D7F7C, 0x54DF1E, 0x4E36E9, 0x3747634, 0x173BAA3, 0x21C5D1A, 0x2A025E5, 0x3433D81, 0x37C6E4D, 0x2EBBB84, 0x365F3F9, 0x3E5E31, 0x4B852A, +0x418B9E, 0x5C180B, 0x2CD19C5, 0xE74B79, 0x2F88E08, 0x15C8B73, 0x26CBF9B, 0x3BC474B, 0x283D71, 0x75ACFC, 0x561876, 0x2BAEE08, 0x1DDEA3, 0x38A1F59, 0xC4B8F4, 0x8BFB92, 0x1029C4D, 0x1401A86, 0xC54AC, 0x6F357E, 0x11E6971, 0x12F816E, 0xCC67B, 0x21AA47, 0x3D40C59, 0x2F7DDE4, 0x3BE476B, 0x3B6CECF, 0x747C45, 0x5DCB27, +0x21DD2EE, 0x1ED9BDC, 0x3711B3E, 0x14D3DD8, 0x249843F, 0x307FB54, 0x27DC259, 0x2CC1CFE, 0x51551F, 0x453455, 0x3CAB70B, 0x3EEE29, 0x1DCF8E0, 0x1FB7CA5, 0x34DFF24, 0xF66DA1, 0x179D633, 0x2E35B70, 0x679BE2, 0x3DC9E5, 0x13FB75B, 0x2C7213, 0x1432E90, 0x24090A0, 0x137F56A, 0x252E5FF, 0x16F16A1, 0x323D094, 0x1E6531, 0x73C9D8, +0x3198C8F, 0x2DD6902, 0xDEE18C, 0x4F9CB7, 0xF333C6, 0x33AFAD3, 0x2CFB505, 0x250737C, 0x534F84, 0x5ED57E, 0x257306E, 0x31C2BF3, 0x3F8074A, 0x2DC15C3, 0x13F95A6, 0x18DB39C, 0x3A8D11C, 0x3927C68, 0x73B63D, 0x2DF8C6, 0x37797E4, 0x959643, 0x2F0D259, 0xAA237A, 0x1062661, 0x1D515B5, 0x32EFAFA, 0xA04700, 0x501AE7, 0x37275, +0x1BB928, 0x1A02CF1, 0x315E88C, 0xFE908A, 0xFC6010, 0x1B29F88, 0x1C55555, 0x2E1435F, 0x378B31, 0x5F0047, 0x402DAA, 0xA443F5, 0x11EB8CA, 0x19766A2, 0x22BC4D2, 0x3089B4E, 0x9EA142, 0x1ACB5B6, 0xD0306, 0x6EC968, 0x2A1D987, 0x261BFB7, 0xB823F, 0x345EFBD, 0x3600DE2, 0x334C157, 0x34FCA35, 0xDB75D4, 0x5C64E1, 0x56392D, +0x119155C, 0x14E15E8, 0x11E362F, 0x2F802FE, 0x2AFDE25, 0x10C09BF, 0xB4F4CD, 0x269AB7C, 0x146D4F, 0x2B185A, 0x152AB7B, 0x7CC541, 0x149ECFB, 0x3D3FD25, 0x1E80926, 0x1A7AB58, 0x51CC40, 0x31FEB26, 0x67997E, 0x36F800, 0x456D9, 0x350D898, 0xB8C90, 0x132AED1, 0x297BD03, 0x3CBF914, 0xD902F1, 0x3EB2688, 0x4372E4, 0x75D25A, +0x255CBFE, 0x166D0C9, 0x1645D9D, 0x1EC8909, 0xB07794, 0x3B23705, 0x1985FF1, 0x1642105, 0x74DB21, 0x1D543B, 0x428783, 0x68AE72, 0xA02D11, 0xCF5AB0, 0x3EF19C, 0x19F4378, 0x3F62DB3, 0x688F00, 0x352309, 0x4EC067, 0x3D05BB5, 0x17EFB4A, 0x20DB868, 0x1AF0F39, 0x2FE39D9, 0x150A29, 0x37FC893, 0x1A0D685, 0x44FE1A, 0x2EFEC8, +0x3194BCA, 0x1C0B9E0, 0x67027E, 0x3FC85F2, 0x12062FE, 0x3CEE5BD, 0x34E54F3, 0x159606A, 0x18CC07, 0x671AA7, 0xF7D1A2, 0x1BABB83, 0x30CEB8A, 0xF4599, 0x23FEE1C, 0x1211515, 0x124DE82, 0xDB5622, 0x1B6F25, 0x74B956, 0x296F869, 0x2B93B13, 0x25EB93A, 0x393553E, 0x10BDBDB, 0x929796, 0x627894, 0x17C1658, 0x1507CE, 0x6A8176, +0x1A833ED, 0x3D52693, 0x1014879, 0x1DA5D7F, 0x36442E9, 0xED6BEA, 0xCAC917, 0x122E9B5, 0x3BDEA5, 0x64B948, 0xE33EC7, 0x35A8138, 0x14B4065, 0x1CEC7F6, 0x1F259DB, 0x1C22EDE, 0x369558E, 0xEDB18B, 0x71CF65, 0x12E4D1, 0x1185517, 0x2CD84E4, 0x26C3099, 0x37172AB, 0x3DD09D1, 0x12D11FE, 0x3495ED7, 0x5478D2, 0x77A011, 0x46844E, +0x4220DF, 0x335E22E, 0x8E8C64, 0x197BAB7, 0x30997A4, 0x195B1C6, 0x31D1FA3, 0x15BF115, 0x5B3165, 0x7802B5, 0x15BD2DE, 0x60C1E5, 0xB7BD00, 0x3DB4D48, 0x26AD85A, 0xE6A19C, 0x21E55C5, 0x346F902, 0x17F2AB, 0x122A7A, 0x5BF766, 0x3A28538, 0x26EF219, 0x9A89CA, 0x1ACF5B7, 0xBDE975, 0x275342B, 0x3A43508, 0x20FB00, 0x7041B4, +0xDAB057, 0x3CD4708, 0x44CD6, 0x1666680, 0x2433B3, 0x9691A, 0x19BC349, 0x27364E, 0x3D398B, 0x1EAE24, 0x36108C, 0x125DCFD, 0x35AD813, 0x2B5A45C, 0x196866D, 0x31CA57C, 0xDE2420, 0x2E25C13, 0x171308, 0x34B06C, 0x335ABF2, 0x3AF075B, 0x3FA39C7, 0x1D9D990, 0xDB9DCA, 0x2B6D628, 0x663551, 0x3955674, 0x698331, 0x200950, +0xDD9074, 0x1319356, 0x18FF0FB, 0xC201, 0x13A2D4F, 0x38BA96B, 0x1C50AB0, 0x380910D, 0x747331, 0x2C20FF, 0x26AC01A, 0x30BF8EA, 0x25446B4, 0x3F9B9C3, 0x3CF6488, 0x26D715F, 0x86665F, 0x2D29B42, 0x4EE327, 0x6B617F, 0x12F7324, 0x37E04B, 0x1B72871, 0x843132, 0x277491, 0x142CC24, 0x3C2191A, 0x13E4569, 0x3C8269, 0x4E480B, +0x27FE35E, 0xA407B9, 0x3BCEC26, 0xA79250, 0x4B2C5F, 0x25AB79F, 0x37913F6, 0xF29733, 0x31A501, 0xBA7E0, 0x274D8EA, 0xA1128A, 0x22C8162, 0x1C6B3A5, 0x1ADCA7A, 0x2811461, 0x204389B, 0x95256, 0x46F4C7, 0x44DB55, 0x3F18D5C, 0x31CFFAD, 0x2278692, 0x265D9AE, 0x6B27F8, 0x1ACA33A, 0xA90FCC, 0x164934E, 0x4D4F17, 0x625477, +0x225136E, 0x23F63BA, 0x148C3B0, 0x3A65A7D, 0x211DD85, 0x138212F, 0x341E364, 0x3725277, 0x1C544D, 0x69AF1, 0x3E5C256, 0x3B7DE06, 0x2F3D033, 0x425DE4, 0x3595305, 0x43EE45, 0x2492EEE, 0x3CE7F00, 0x63AE90, 0x9780C, 0x3798871, 0x2E055BA, 0x2BE39FA, 0x3C184CC, 0x3A37827, 0x292B79D, 0x1B1DD5D, 0x1EAAB3A, 0x3ACE8A, 0x561DC0, +0x20D2673, 0x2D8526B, 0x108B660, 0x146B077, 0x13487E4, 0x2BD1F1, 0x20F82BD, 0x39455C5, 0x6B85DF, 0x35EAD8, 0x3C79DD4, 0x27D5FA, 0x1BBDB0C, 0xDF4330, 0x3DE46DA, 0x331B910, 0x1349653, 0x401EC0, 0x5F2EA0, 0x53B540, 0x14BA5A3, 0x2ACF9E, 0x3C6628F, 0x2252B3B, 0x195810, 0x9CE32B, 0x966EA5, 0x187590D, 0x4463BD, 0x787117, +0x11FE211, 0x25E49DE, 0x2B86CFD, 0xDB4436, 0x2463253, 0x336A3A2, 0xFD4D6D, 0xA7084, 0x409E4B, 0x19D2B1, 0x2AADD90, 0x2828279, 0x17D010D, 0x244C61D, 0xB19283, 0x1F9CC18, 0x541464, 0x30F2A38, 0x942A3, 0x3AFE96, 0x1230693, 0x1D44C8E, 0x2006D24, 0x2D40D57, 0x10919F1, 0x280D9FA, 0x2E1897F, 0x369CA6C, 0x39E28D, 0x145155, +0x14D76D5, 0x354EA8A, 0x33E0407, 0x19B2132, 0x2C68D3C, 0x7733CC, 0x6A30AD, 0x38FD59B, 0x5A0FAA, 0x51052C, 0x1AE9FF5, 0x16BF15E, 0x3853799, 0x39E4722, 0x30243BE, 0x13D6089, 0x2280733, 0xB49876, 0x758611, 0x35FF02, 0x37D1CF9, 0x2DC41B4, 0x3384F63, 0x1A28918, 0x38F6CD3, 0x1D2951E, 0x23E56DE, 0xF08FDB, 0x4F1DE9, 0x61AD9E, +0xEBDB51, 0x1F336D5, 0x3FA9920, 0x3920FAB, 0x2CF3584, 0x296A9AF, 0x1CFE77, 0x32602C5, 0x5D52FE, 0x1DFA03, 0x3819A19, 0x2399419, 0x1CF51FF, 0x1201111, 0xED55F, 0x259FDED, 0x174D844, 0x119FF38, 0x697BF5, 0x618C94, 0x8EF50C, 0xDED5F6, 0x25FFC7C, 0x1632F1E, 0x33C0F25, 0x148FBB7, 0x2E63764, 0x1ABC4C, 0x7C935, 0x1E9A0D, +0x34CD4DB, 0x17605C3, 0x338515F, 0x2568F71, 0x994879, 0x27B1F50, 0x28658B5, 0xF69314, 0x28396C, 0x1E570F, 0x935787, 0xBC8633, 0x1A68E41, 0x2D637E2, 0x1CCE2AF, 0x15D1F77, 0x1DBF740, 0x146CBCE, 0x591EE3, 0x5464D6, 0x29A86AE, 0x29D3E08, 0x3025AC7, 0x2A0A34B, 0x2B28AFB, 0x26D03B3, 0x12FD96D, 0x7634B5, 0x6CE2DF, 0x638201, +0x13D193D, 0xAD15A9, 0x21F2993, 0x37D9F32, 0x16AF949, 0x1F928D5, 0x34EDB5, 0x262F16C, 0x50DDF7, 0x392080, 0x3D5A4FB, 0x3C789, 0x27D4837, 0x3E22A36, 0x3BA9CE9, 0x55E13, 0x21EE1A9, 0x2F7C880, 0x323BBC, 0x56FFDC, 0x324C72D, 0x2C46A13, 0x3C368C6, 0x1EDFD4E, 0xC163AF, 0x3BC276F, 0x1991830, 0x3FADC1D, 0x700115, 0x1C069B, +0x14A3C36, 0x17D6634, 0x1C64F28, 0x2CAF64C, 0x1E3D8F4, 0x1EC8634, 0x12BC223, 0xE2DDFC, 0x6D73E3, 0x5B4047, 0xA1CB1D, 0xEDA660, 0x3EAEDC7, 0x372B742, 0x2A46F34, 0x1EF1E8C, 0x32B2951, 0x2FE562F, 0x54ABB, 0x6971AB, 0x1DB4EAF, 0x3A26068, 0xE155F7, 0x1C11D33, 0x367C413, 0x2469D22, 0x216C1E6, 0xCACF3A, 0x1E1585, 0x53B36D, +0x543D08, 0x117ACD1, 0x148F05B, 0x3CFAF90, 0x314E011, 0x131ABAE, 0xB17DCC, 0x6A9C4E, 0x4668E9, 0x4037D, 0x390C68D, 0x329C032, 0x463938, 0x1FAA295, 0x157568E, 0x1AB2730, 0x1569130, 0x17FBBA6, 0x6B80CD, 0x5CC547, 0x14AC75, 0x588052, 0x1439093, 0x38AC6D4, 0x1CD8344, 0x2F8F62C, 0x1F976CF, 0x3153994, 0x3F0915, 0x27A899, +0x3C2A5ED, 0xA75958, 0x340E7CB, 0x34627A4, 0x3EEC0AC, 0x33A1C04, 0x3775604, 0x2F39C74, 0x4B4044, 0x242551, 0x1F87F05, 0x39483C5, 0x2BE5AD4, 0x3D97DCE, 0x1815D95, 0xB43B27, 0x83E027, 0x117D0D9, 0x29888, 0x2EF607, 0x34FB8B9, 0x39867A1, 0x1AF724F, 0x2F6B826, 0x3B8ACB6, 0x29AAF8E, 0x2D21D5A, 0x6139BF, 0x2B86C9, 0x441E70, +0xCC1289, 0xAE74BE, 0x94C0CC, 0xEDBE8C, 0x2992FDC, 0x19D58C0, 0x16A2D35, 0xF30EF6, 0x47D8D6, 0x1CA869, 0x18F2A6, 0x13AAB59, 0x3AC5444, 0x1C810CF, 0x3FF5699, 0x17FF361, 0x19367D3, 0x184B2E1, 0x3DA047, 0x2FA911, 0x2F1CAC, 0x15F0BC5, 0x15F6843, 0x1040834, 0x619A40, 0x1DAD423, 0x2E4CE97, 0x1411A82, 0x48A219, 0x73F889, +0x27421B8, 0x4E0DFF, 0x354C4B1, 0x1C69E79, 0x222E1BA, 0x31C28CC, 0x6CDA39, 0x391519F, 0x419477, 0x4B4564, 0x3E52093, 0x34EF798, 0x27C5AAB, 0x301A52A, 0x3EA9775, 0x130D2A1, 0x3735D7E, 0x1515110, 0x391B71, 0x23087, 0x3AA1AA1, 0x10B54B9, 0x2B87FF3, 0x11C0E2F, 0x21E74B7, 0x2E158DA, 0xCB5CCD, 0x1BFABB3, 0x64E26F, 0x148CFA, +0x1C2CC3D, 0x2BB2C43, 0x1B5351E, 0x322FBC9, 0x3DE375, 0x337FD82, 0x2A34C55, 0xCF49F, 0x25D44E, 0x2C2047, 0x3DAD260, 0x2A583F2, 0xCF660D, 0x1C75A5F, 0x3B7D5BD, 0x1BF2120, 0x5E8CE0, 0x9CA889, 0x779431, 0x3C7C41, 0x1F03AD3, 0x2EE75D1, 0x2EF7EBC, 0x38A14EE, 0x370492E, 0x3636CA6, 0x31A2D8, 0xD1DC68, 0x5D6103, 0x12404B, +0x2667E4F, 0x1C80F89, 0xF118C9, 0xFE32EB, 0x23B0BE1, 0xB4886E, 0x245BE6F, 0x2285E53, 0x2BD261, 0x74520D, 0x24CF97E, 0x399CDA1, 0x171D140, 0x223782B, 0x2B021E1, 0x62C8D0, 0x78794F, 0x2587302, 0x5CEE74, 0x625812, 0x1C0E934, 0x10E143, 0xD0DCC8, 0x1C7EFCF, 0x37A4431, 0x15B8ABA, 0x1A31093, 0x27C52A4, 0x60BBC7, 0x37B8EA, +0x213FF, 0x2F607A3, 0x1BB1971, 0x2DC6536, 0x45C8D9, 0x706BED, 0xA3FDDE, 0x1C45872, 0x74A088, 0x17E866, 0x24059CF, 0x31B3C47, 0x2E63814, 0xA5C6EB, 0x2F09ACE, 0x1B704CD, 0x3125245, 0x2F37788, 0x68552A, 0x68442E, 0x2867595, 0x2E393AD, 0xA6E303, 0x2D1783C, 0x247A196, 0x10C46FA, 0x34D8D7E, 0x3D3F3C1, 0x6A6955, 0x66DD3E, +0x1DC7DF1, 0x2FD411D, 0x2DEAF3F, 0x1E7E728, 0xF9CBB0, 0x200A1CF, 0x1D46C2F, 0x1CFFFC1, 0x14EB5B, 0x5C496F, 0x1426D70, 0x19B6D4F, 0x1236155, 0x3F6E1C3, 0x18A9496, 0x3633B57, 0x1A88C8B, 0x1482776, 0x46C101, 0x609EB6, 0x2DC82C5, 0x227A20, 0x3E459AF, 0xA5366C, 0x2F27E70, 0x3C8D79A, 0x2D722BE, 0x10444B6, 0x772FB5, 0x7F75B1, +0x2070020, 0x15F33FF, 0x71FE23, 0x94FAF8, 0x17B198D, 0xC45E28, 0x2AB1208, 0x3047985, 0x5953D0, 0x267D1D, 0x19E2246, 0x260BED0, 0x13D42AE, 0x356B01F, 0x1495BE6, 0x1B4D927, 0x1720BF9, 0x1B79AA8, 0x4EAAAB, 0x67D378, 0x36E2945, 0x26640AC, 0x258AFC3, 0x8A31F4, 0x2A9BA71, 0x35A1B34, 0x1128D7B, 0x34BACA3, 0x63D938, 0x169C38, +0x39DC22, 0x1D58C7, 0x25CACCD, 0x1B8497B, 0x1E144B7, 0x14F1522, 0x15F36A8, 0x25B9E3F, 0x714784, 0x669D87, 0x244A07F, 0x14FBD25, 0x3746AAA, 0x2E3A56D, 0x3ECF750, 0x364E006, 0x2D56BAE, 0x17407AC, 0x327C62, 0x2AB3F9, 0xD5E196, 0x139B5D, 0x3942030, 0x2CAD9D6, 0x2725FCB, 0x3A731D2, 0x35D695F, 0x2BE126D, 0x2A1B9B, 0x751CF4, +0x37D00A5, 0x1BE28F9, 0x29F4B8C, 0x2380D9B, 0x24BC164, 0x502349, 0x2932E0E, 0x245234A, 0xCEE3, 0x53D89, 0x2B0FB69, 0x13F915D, 0x1975932, 0x12EF52F, 0xE74016, 0x22BBBA4, 0x88235A, 0x3E45C84, 0x4A9913, 0x1D34B0, 0x1E8A9F3, 0x2F0F3E8, 0x5371CA, 0x2E3A48C, 0xB605D1, 0xF6228D, 0xF754CD, 0x6E0099, 0x8E7A4, 0x5CB7BE, +0x2508F23, 0x1D194BE, 0xB1E1E0, 0xB53B8B, 0x21B29AF, 0x28727FE, 0x333DF8E, 0x6CAE29, 0x336AE7, 0x573D2E, 0x3B2EA36, 0x2B3260D, 0xBA8CD8, 0x11F2301, 0x243333, 0x1C5E65C, 0xDD6C7D, 0x3294E65, 0x200BC1, 0x42021F, 0x3B19946, 0x3E0D70D, 0x39B3D26, 0x304ED8A, 0x2D2C2F7, 0x30DCC30, 0x1A88C65, 0x509C46, 0x311FBA, 0x61EEAC, +0x17D35D4, 0x129A510, 0x9A6596, 0x6CB42B, 0x21D7885, 0x394DA0F, 0x32F9AF4, 0x51CB06, 0x70169B, 0x2ADE53, 0x9873E7, 0x2F621E3, 0xC83706, 0x23114E9, 0x1B3811E, 0x36F7A0A, 0x253A173, 0x2D51497, 0x2D2A17, 0x4B06D5, 0x48EC1C, 0x10A5B4E, 0x2459A46, 0x18369CA, 0x730F42, 0x165FF8C, 0x155755E, 0xE687CD, 0x1D4216, 0x66DD9F, +0x3B474A0, 0x2E6BC89, 0x30A764D, 0x36B2A84, 0x1EE455A, 0x310918, 0x1E928DA, 0x2401947, 0x429196, 0x3D46E8, 0xE90B1, 0x8C51E6, 0x1550C28, 0x870CD2, 0xA39AF0, 0x3CD51A0, 0x3D5B697, 0x37D8FEE, 0x16F62B, 0xD64DA, 0x1BFEA7C, 0x39FA90C, 0x23B3967, 0x21516E2, 0x203A091, 0x19E61D8, 0x35F75D0, 0x3724231, 0x3B3319, 0x13B792, +0x3D0979, 0x26D8470, 0x364E6A7, 0x251FFFD, 0x31270A2, 0x3C995E5, 0x2FADD2F, 0x32BF49A, 0x321A5D, 0x22EC9E, 0x3B10536, 0x1485023, 0x1F2A0A4, 0x20DCCDD, 0x1846DE1, 0xB1C114, 0x3015677, 0x3F7DD12, 0x593F56, 0x23C6B0, 0x227804F, 0x235AC70, 0x2411162, 0x6C93CC, 0x2A70377, 0x385E35E, 0x2589C9B, 0x8127D3, 0x573E91, 0x51BA08, +0xD47194, 0x26E4E33, 0x1246058, 0x16252CF, 0x21DD4BC, 0x10FB7E1, 0x78CC23, 0xBD3CC7, 0x5D29A2, 0x50DBBD, 0x1A9C9DE, 0x2363BD2, 0x122F48D, 0x1C8CE94, 0x710EF2, 0x99F96C, 0x3486D8D, 0x2B66823, 0x3418AD, 0x7C8414, 0xE6C05C, 0x308FA1C, 0x2B2D295, 0x1F0F802, 0x179ABC6, 0x2A73062, 0x68464D, 0x3E785F0, 0x572902, 0x3D0B4F, +0x190317F, 0xE651F5, 0x1FA1D56, 0x203CB1B, 0x3E48D50, 0x2E4644A, 0x2CEF1EF, 0x3F06DC1, 0x75B27B, 0x7B9795, 0x1F9A640, 0x30889A0, 0x1D6F7BF, 0x2AC45A1, 0x3AA89DE, 0x2C6CCE0, 0x2AEAFF, 0x3F37567, 0x75ADE5, 0x6F3DDC, 0xDE0674, 0x884D61, 0x1A0CD62, 0x2394E19, 0x20736E3, 0xD76F8B, 0xA7A8A2, 0x3C6BA15, 0x291D11, 0x706EF8, +0x3753069, 0x376C7BA, 0x2A31960, 0x387FE0B, 0x3966137, 0x1C54E28, 0x731883, 0x2B38FA2, 0x1E45F, 0x36D29E, 0x30B49CB, 0x30CDA3E, 0x1E7C55F, 0x8F1141, 0x3937833, 0x2DE59B3, 0x278AEB2, 0xC6ADF8, 0x65E9C3, 0x16E02F, 0x35122B7, 0x21E57AC, 0x33CD198, 0x3D7E53A, 0x1E0953B, 0x34DF3A5, 0x1F5B0B, 0x3A343C2, 0x1FD7E2, 0xCBA06, +0x3A9C392, 0x239912B, 0x11030E1, 0x22E9B5C, 0x180070B, 0x2D14549, 0x10F7B87, 0x2805C60, 0x1E7DC1, 0x332870, 0x32D794C, 0x12BA79F, 0xC1BF19, 0x2DC8B23, 0x2B4E6BE, 0x327A109, 0x44916C, 0x3EA717D, 0x2C2CE2, 0x268520, 0xFE78EE, 0x210BF78, 0x2CC0149, 0x22B044C, 0x2698515, 0x1843460, 0x3B32EBA, 0x2467110, 0x736201, 0x32D8FD, +0xB8F2D8, 0x3A417F5, 0x15F86C1, 0x3D5616, 0x3459C95, 0x1304120, 0x3DE6371, 0x17CF9EB, 0x775437, 0x2E00EC, 0x3446288, 0x789B22, 0x1CF57CA, 0x1A91F02, 0x36E4FC8, 0x16BEC64, 0x24D8921, 0x3FA4958, 0x32270A, 0x2370D9, 0x1E671C4, 0x2417635, 0x2BE8D86, 0x137B0BC, 0x1FB2430, 0x258F3B8, 0x33AB07D, 0x2405F03, 0x156468, 0x31140E, +0x37443FA, 0x1B0FB84, 0x17E2332, 0x3FD121C, 0x24AC5C8, 0x36C3295, 0x1759361, 0x2EB4CC, 0xDA75F, 0x1B79E1, 0x12977B3, 0x112864E, 0x3E650B7, 0x1E28930, 0x1A23FFD, 0x8D0BA7, 0x2343E68, 0x25FC9B5, 0x4C1B19, 0x74F668, 0x27AB611, 0x1CB9165, 0x1701BA1, 0x2D3739D, 0x38B93FD, 0x1163F7D, 0xCFFDE1, 0x28267B1, 0x4B98CE, 0x11665A, +0x27118B9, 0xCE2C86, 0x263C5AB, 0x108C19A, 0x109A2A4, 0x33853DA, 0x36ED3AD, 0x2AACB8C, 0x265EC3, 0x36E62B, 0x1AB4478, 0x3022CE1, 0x1F529E, 0x307B24C, 0x875995, 0x466D7A, 0x3F1047A, 0x2B80CF4, 0x25BFB2, 0x23D341, 0x162BC00, 0x3922D4D, 0x16D197A, 0x3335EBF, 0x3180D29, 0x1514A03, 0x6E8B5C, 0x12378C0, 0x23D021, 0x1E7671, +0x94EFAB, 0x3D27A87, 0x6ACDAA, 0x2E5958A, 0x1E58C24, 0x3015CA3, 0x3CD0FF0, 0x8A1775, 0x1C9FC2, 0x53623E, 0x219420, 0x323592F, 0x1047C07, 0x4B6506, 0x2F9557, 0x1C06D33, 0x1DC25AD, 0x2870F14, 0x192655, 0x30A9A9, 0x26E8F79, 0x2DF6E36, 0x26C2CFA, 0x26C61B9, 0x3CB23D8, 0x1694C0A, 0x77171D, 0x160FC55, 0x7EAB75, 0x4F844D, +0x393DFFA, 0x1DF6E32, 0x608C9, 0x1203C4C, 0x54D419, 0x2417D55, 0x2DAF4E, 0x211AB8F, 0x2ADD44, 0x318CE3, 0x20984F4, 0x1E79790, 0x1418B46, 0x1D7F9CA, 0x39F6056, 0x24E7770, 0x18F4AFF, 0x1189322, 0x6EBAEC, 0xDD943, 0x3A9B062, 0x32C6344, 0x3C478B7, 0x85433D, 0x3364BF8, 0x28DC62C, 0x957BA2, 0x2034207, 0x1B17D8, 0x281068, +0x3EC91C1, 0xB9316F, 0x12BC377, 0x1E8E9CE, 0x1F2EF4A, 0x22EC72A, 0x1B25DF8, 0x1CA3138, 0x1A8F0E, 0x323716, 0x3A4AF3B, 0xB6C337, 0x1A4196, 0x352BEAA, 0x1367C14, 0xE751B, 0x922447, 0x26D44D0, 0x81514, 0x50E77A, 0x2822548, 0x1CAC17F, 0x146CA, 0x2C3BE90, 0x1CFC46C, 0x1675A06, 0x390697B, 0x2C06E71, 0x24886, 0x336A30, +0x2097626, 0x1A17B74, 0x2CB0432, 0xB254AE, 0x98174F, 0x303B690, 0x2A923A4, 0x2DAE488, 0x2B204C, 0x39C2E9, 0x597419, 0x2AE1427, 0x5AE6CF, 0xA5F57B, 0x1F76B92, 0x13077B1, 0x993C5, 0x2B7F86F, 0x6D9293, 0xF0744, 0x3E6A89D, 0x1DC772C, 0x15F8996, 0xE65718, 0x2C1033B, 0xFF53A0, 0x394CCD5, 0x17A24F7, 0x282FA2, 0x4F5D8F, +0x48023F, 0x29B8A2, 0x3249FBF, 0xF82BFB, 0x5AE4BF, 0x38423CB, 0x1075A9A, 0x344194, 0x596F22, 0x31018E, 0x575626, 0x26781A7, 0x3FA51, 0x3559993, 0x20112FD, 0x22CE970, 0x1C1260B, 0x2743CF7, 0x1241D8, 0x1B05F4, 0x3717E66, 0x3F1579A, 0x13FF7D8, 0x20B3B54, 0xE98A99, 0x2A4B8B0, 0x29DAEA2, 0x3EAD74A, 0x416374, 0x56781D, +0x65B318, 0x338E14E, 0x77BF46, 0x1BD2ED7, 0x1F7815, 0xB40E43, 0x2103582, 0x1042A5D, 0x64669B, 0x43D438, 0x266BE02, 0x1E3EA86, 0xB3ACF5, 0x251C6CE, 0x28E583, 0x1AE4697, 0x2786B86, 0x1872D2D, 0x6347D, 0x2CF2CF, 0x25A6EE4, 0x30D1FFC, 0x2CA7AB6, 0x2C44274, 0x1768B7A, 0xE5AE65, 0x2CA6B29, 0x335ACC8, 0x12E75C, 0x71F9BE, +0x247EED9, 0x254C1E5, 0xA24099, 0x2EFD48E, 0x58FDC8, 0x1491EA2, 0x143295, 0x2E78FB9, 0x31D62D, 0x602BF0, 0x380AD4B, 0x2A0470D, 0x29CD888, 0x17BF61A, 0x1F5825A, 0x354BDBC, 0xC9C77D, 0x92E310, 0x2B6B1E, 0x5353C, 0x1E06BCA, 0x2CE7CA1, 0x1F6CF3D, 0x14BD784, 0x25F7A3C, 0x3C7DD61, 0x23CAD3A, 0x2D0D99C, 0x288A1C, 0x59D4C1, +0x21FCB95, 0x1A4D9D1, 0x955394, 0x5BDACE, 0x14401E0, 0x2F62ABF, 0x3C902B, 0x72A530, 0x66D398, 0x7FEA35, 0x9163BA, 0x1A7C669, 0xADBCCE, 0x19100F3, 0x15EA3D6, 0x3193D5C, 0x13CB9E2, 0x243980, 0xFC6B4, 0x2E4099, 0x1FA4C2F, 0x25B331B, 0x303EBC5, 0x12B758E, 0x36399B5, 0x18795CE, 0x276384A, 0x1CDB131, 0x46295C, 0x5FA7BD, +0x3D1AEF2, 0x23C5299, 0xD1C511, 0x210DF66, 0x173947B, 0x27E8D58, 0x7088C9, 0x604B34, 0x28004C, 0x2AB19C, 0x37802, 0x2BC2139, 0x1C03DA0, 0x1FBCDBE, 0x2B363AE, 0x3D1D45B, 0x2002D08, 0x3FC8772, 0x1AD163, 0x44BCDE, 0x1E11C7B, 0x1C13849, 0x1B6885C, 0xA509D6, 0xC1441C, 0x50A485, 0x1E7DF13, 0x1BC42F8, 0x2C35EE, 0x6492D2, +0x50F0D9, 0x25E57A3, 0x153A623, 0x2601ACA, 0x181BA6F, 0x3D20F7D, 0x2DB7588, 0x36CEE94, 0x6A2DB2, 0x57526B, 0x100E650, 0x18DE970, 0x39B2C7D, 0x29B1A, 0x334517C, 0xB8EAA8, 0x2C10BE3, 0x166AF8B, 0x5D841, 0x4F4B5, 0x19CE49D, 0x1306204, 0x37F5C9, 0x496195, 0x3935C05, 0x305AB37, 0x2F7E536, 0x22C67E5, 0x213839, 0x7D323B, +0x2B6C618, 0x1B41872, 0x1140AC5, 0x1F038DB, 0x195B26D, 0x21D0F86, 0x1A6AA25, 0x361B1DB, 0x797170, 0x13D601, 0x31B7383, 0x310EBA0, 0x322C34C, 0x344F9CA, 0x752DF, 0x1B9505B, 0x3CF90BA, 0x1D243DE, 0x185472, 0x519A38, 0x3AD2500, 0x62426C, 0x2706CB4, 0x60655A, 0x37338D0, 0x1B09640, 0x174B3C3, 0x3D66FF8, 0x45DA4, 0x728D57, +0x1A2C585, 0x394FE0, 0x267E1E3, 0x180B315, 0xE10F9A, 0x28AE6DC, 0x798771, 0x1AD9FA7, 0x4FC483, 0x48456, 0x293809B, 0x2FE6C43, 0x33C11D2, 0x3EAF8D, 0x22BBC5F, 0xA7B40, 0xE963CF, 0xFABB93, 0x71C0C2, 0x614C2F, 0xE1C6C1, 0x2C2CB2B, 0x2A6034, 0x38727CE, 0x1DCC761, 0x341EEAD, 0x1F22221, 0x1EEBCBC, 0x1CE819, 0x471AD0, +0x301121B, 0x33262CA, 0x2A0DF1A, 0x1C0790B, 0xB59D67, 0x58052E, 0xA07D67, 0x1F7B394, 0x2A8E64, 0x19E0A2, 0x3BDA6AC, 0x3AE49EA, 0x24705E9, 0x555526, 0x31F2B56, 0x3AE5A68, 0xC46E77, 0x3768897, 0x43484C, 0x43A2C5, 0x1700EEF, 0x8C4DA9, 0x3A64ABB, 0x2E06879, 0x856FA5, 0x3BD648, 0x1588E46, 0x32F743, 0x58911F, 0x66E6E3, +0x29D266B, 0x20C3D2E, 0x2882705, 0x2D6AA86, 0x3685F3B, 0x11F1D1B, 0x188C111, 0x210F444, 0x20F7A8, 0x366C29, 0x1CC9013, 0x677464, 0x1E2D90B, 0x3AB2F29, 0x23FB06C, 0xCC18F8, 0x1938427, 0x6C7709, 0x27484A, 0xB6CB3, 0x18F0FA0, 0x14C5C69, 0x27213E2, 0x4A865F, 0x32A2DF6, 0x18D6C09, 0x1D12483, 0x1FDAA63, 0x2DD426, 0x489ADE, +0x3203E28, 0x16D7D67, 0x1DA7D1F, 0x24DBD2B, 0x2C97458, 0xFF83BB, 0x8FF016, 0x3FB53C0, 0x124F41, 0x330954, 0x2F90EAF, 0x6DFB83, 0x3994011, 0xC5CA96, 0x1EBDC2C, 0x3D962E9, 0x18B53E7, 0x18AD044, 0x7BF947, 0x3C7A60, 0x7F0D93, 0x3639BFA, 0x2C0E5C5, 0x399FFD9, 0x10345DD, 0x232374, 0x1BF1A0E, 0x846622, 0x8E359, 0x19021C, +0x1D55EFA, 0x174C84C, 0x3D7413F, 0x1E3A8EB, 0x3AA3002, 0x277DE56, 0x381E786, 0x209A962, 0x5B4C6, 0x1C42F7, 0x2CAFACD, 0xAEBB32, 0x119A2F4, 0x11A98DD, 0x261CE05, 0xEF4EDF, 0x34FB790, 0x164C73C, 0x237668, 0x31EC8C, 0x35B5825, 0x27D1EC0, 0x30BA570, 0x225DB90, 0x1603955, 0x3D13B7A, 0x3A9A096, 0x301C54A, 0x27D8B0, 0x6B6CC5, +0xB244CD, 0x293A7FD, 0x223C328, 0x12CE87D, 0x189703D, 0x2C96A84, 0x26A33FB, 0x32DEAF7, 0x1CAE, 0x676C9A, 0xCDBD33, 0x2FB2EFF, 0x2DAF578, 0x1F55D4D, 0x19B8631, 0x3059094, 0x3703377, 0x19438FA, 0x29F289, 0x1EB2CE, 0x28BF405, 0x270D6A6, 0x26CE903, 0x7B699E, 0x2E8D213, 0x4F6E06, 0x3ECE7D2, 0xCA3242, 0x4165ED, 0x2E3CC0, +0x56063F, 0x256D34B, 0x20CA7B4, 0x324BC5, 0x33D51EF, 0x29E0011, 0x33927A2, 0x1385C20, 0x6D4D01, 0x6DAD1C, 0xB477BE, 0x2B7D36D, 0x315B164, 0x2099363, 0x2935584, 0x29E600, 0x2B5497, 0x1526672, 0x597E5F, 0x3F5867, 0x1546A1D, 0x2F879A7, 0x3AA277D, 0x1E5A08B, 0x3643D7, 0x28723B0, 0x1F668FD, 0x2566098, 0x41754F, 0x1AB277, +0x3EF7923, 0x1DD5846, 0x1F27C2E, 0xB69702, 0x2097DC3, 0x145C4A7, 0x63B0D6, 0x187B72B, 0x256EC8, 0x51DF6C, 0x35CE819, 0x17B3A9E, 0x93F373, 0x1EF5969, 0x9F1AEF, 0xE4AE66, 0x2566B9A, 0x2468A2A, 0xBA6BB, 0x71FFD5, 0x3A7FADF, 0x12A09E4, 0xC97E94, 0x1D469B5, 0xF1306C, 0x74A3EF, 0x261ACB7, 0x10902E3, 0x6667F2, 0x517A10, +0x8183F5, 0x395933, 0x3377F63, 0x253F462, 0x7F1D08, 0x2F67FFF, 0x31C6E05, 0x164B443, 0x59237C, 0x538ACC, 0x3F0EB1D, 0x1BFE8B9, 0x738E1B, 0x3B68E65, 0x3E65AC5, 0x2341A17, 0x2045317, 0x23F7C16, 0x69D42B, 0x5DC6D9, 0xE8BE78, 0x380222A, 0x134DD7, 0xB60501, 0x3CAF23, 0x15C904D, 0x87B312, 0xAF8FB6, 0x31B585, 0x3DC18B, +0x2D70D2B, 0x2B7143B, 0x3858E7C, 0xF196E9, 0x38D0A48, 0x3A9D8AE, 0x29AF03C, 0x7E45E3, 0x4FFD54, 0x482EB4, 0x3AD4F1D, 0x275132, 0x2E2D3A1, 0x17DDF91, 0x2B40240, 0x2349C13, 0x1080167, 0x1A836AB, 0x6D8532, 0x626107, 0x42765C, 0x1177A75, 0x5AF6CE, 0x35DD2F5, 0x3D92353, 0x23B61C2, 0x2E8EA2F, 0x264591F, 0x246165, 0x45A2F, +0x14671A8, 0xA0F50F, 0x2D648D6, 0x25FF0D6, 0xDB5ED3, 0x2A91E82, 0x3696B35, 0x373CA54, 0x514FA, 0x7CD2BA, 0x29AC266, 0x293A390, 0x1144C3A, 0xADCA7F, 0x9790DA, 0x3CCBBB6, 0xF07853, 0x2BFDFD9, 0x26A0D4, 0x360357, 0x7C59E8, 0x3A3BD96, 0x120D747, 0x12F9A63, 0x70B3AD, 0x2FFCD7C, 0x3F61BE9, 0x3B0AB5D, 0x570DAF, 0x17E4BD, +0x2D7DC51, 0x680555, 0x393AA7A, 0x1331F99, 0x118E43C, 0x30B8E01, 0x3835929, 0x14F3898, 0x58BA7A, 0x3ABC9, 0x399BE57, 0x23B2FFD, 0x218831D, 0x23F7141, 0x2952A31, 0x2556DD8, 0x28BA136, 0x35E68EA, 0x2B258F, 0x17371D, 0x981299, 0xE54BD0, 0x2E0DD5E, 0xC18863, 0x2B2D927, 0x2235B45, 0x407642, 0x197FF6D, 0x554552, 0x59109B, +0x180A515, 0xB73878, 0xF83128, 0x306A937, 0x4F4866, 0x3517AE2, 0x3907198, 0xB1B01, 0x41467F, 0x19D3CB, 0x26745F1, 0x2F87DFA, 0x11F25FA, 0x4FB09A, 0x43CAA1, 0x3B25B92, 0x68C72B, 0x3A7D839, 0x70DAC7, 0x67F228, 0x38DF3DF, 0x3177544, 0x166E33D, 0x39707C8, 0x2FA3BFB, 0x1C90E1B, 0x24A9095, 0x6D912C, 0x366877, 0x786A9E, +0x3CA7F5B, 0x2631B6F, 0xBD1CE4, 0x2710C7E, 0x2B59417, 0xC6DBCD, 0x2D2E2AB, 0x2CBB727, 0x62AE5B, 0x1FBE20, 0xEE085, 0x1F7DBB6, 0x360A7EF, 0x1A23589, 0x1D595FD, 0x12D4B4B, 0x56B717, 0x3FB96FB, 0x241DD3, 0x595A82, 0x11880D, 0x3770A81, 0x14EB833, 0x1256D41, 0x2F76696, 0x731BB2, 0x3FBF100, 0x15D7ECD, 0x2B9E85, 0x5D20C, +0x2485AB2, 0xC04FF7, 0x3988D0D, 0x33FBD21, 0x3EBB9D9, 0x3FBE586, 0x25997CF, 0x3303AA, 0x27012A, 0x44A586, 0x3532E80, 0x3809678, 0x3F9B8BC, 0x3487CB2, 0x20FE6FB, 0x3ED21BE, 0x2EABCC8, 0x4ADFAB, 0x5ABEA, 0x2AA621, 0x210190B, 0xF96F6B, 0x220DF3D, 0x3A6CEA9, 0x18F8E29, 0xEF31EF, 0x2F3BE45, 0xA81A2C, 0x1EC8FB, 0x6A3B84, +0x3F827F7, 0x1F6D98, 0x352DF35, 0x2ED9067, 0x1C9792D, 0x3310139, 0x2EFCFF4, 0x3A65E36, 0x605175, 0x3A3AB2, 0x1D5DD0B, 0x1BB8126, 0x2565072, 0x1045692, 0x3CE0C5C, 0x36190D4, 0x18096CA, 0x3AC476B, 0x34C6C7, 0x7622CB, 0x24EF5AD, 0xCE6E5C, 0x2FFE4C5, 0x3C95713, 0x345D785, 0x2E3E117, 0x1F4D572, 0x22C3A6A, 0x719164, 0x581B44, +0x2225414, 0x3C6B96F, 0x13CF2CD, 0x19010ED, 0x68554A, 0x10B470, 0x314E6F1, 0x16CE8B0, 0x790180, 0x43CCCF, 0x14C3731, 0x1070B5A, 0x2FCEBF0, 0x30BB4ED, 0x25741DF, 0x3F6000B, 0xC6555C, 0x3758ECD, 0x1C368F, 0x332D8, 0x9BD8F0, 0x1C61E14, 0x12C6423, 0x16D2F6E, 0x39CE074, 0x2996BBA, 0x18A36B2, 0xA568D3, 0x2D258E, 0xBCA12, +0x32175D4, 0x1ABB5B0, 0x321319B, 0x253D5DF, 0x3E78059, 0x33E4DF3, 0x10E1E42, 0x398ECF0, 0x1A3BED, 0x304777, 0x2C5A6A, 0x3312959, 0xA753FA, 0x188C0C4, 0x37A459A, 0x3BB869E, 0x347A239, 0x2B633CA, 0x72E421, 0x2DA03A, 0x3ECB0B6, 0x29A8F63, 0x2361823, 0x26D9D74, 0x3A6285, 0x1886BA2, 0x39E9009, 0x293DBC5, 0x343099, 0x3D2028, +0x2047D0A, 0x385DA79, 0x238B4A1, 0x1D29648, 0xE20F06, 0x1CD9D18, 0x175B1DC, 0x14B0568, 0x14999B, 0x78AEB5, 0x3E9C06E, 0x29A7A06, 0x3733308, 0x3225BBF, 0x1745482, 0x1C13036, 0x27ED52D, 0x383461C, 0x7B18A1, 0x2F2C2C, 0x25492C7, 0x365E3CB, 0x366E7B5, 0x2D9BA9E, 0x10773B2, 0x303FCDA, 0x3942067, 0x10312AB, 0x649C7, 0x49B15B }; + + +// The table below consists of four mini-tables each generated using window width W = 8. +// Number of point entries = 4 * 2^6 = 256 points, where each point (x,y) is represented using coordinates (x+y,y-x,2*d*t). +// Each coordinate a+b*i in GF(p^2) is encoded as an interleaved vector using the representation b_4|a_4|...|b_0|a_0 <- 23|23| +// 26|26|26|26|26|26|26|26-bit, where the 23-bit digits are the most significant digits. Digits are stored in 32-bit words. +// Table size = 256 * 3 * 320 = 30KB + +static const uint32_t DOUBLE_SCALAR_TABLE[7680] = { +0x303E631, 0xF90353, 0x28D3CE9, 0x398BDF9, 0x2B5FE18, 0x2CDEE02, 0x2FC7540, 0xDE2E1A, 0x287460, 0xC3BA0, 0x937EDC, 0x3A01366, 0x3C3E62C, 0x48E448, 0x55590B, 0x17A5B32, 0x1E093C3, 0x2E4EA55, 0x740B7C, 0x4FFCF5, 0x3DA42BB, 0x330684C, 0x2BF32EA, 0x2268E4C, 0x17C6297, 0x1F27A81, 0xDD55B2, 0x1C828D0, 0x5948D1, 0xCAF2B, +0x3CF68C4, 0x1F89F9B, 0x1D5AC56, 0x296877A, 0x26BA892, 0x10F7340, 0x1F26294, 0x2BB9D7, 0x5742F7, 0x14EF68, 0x43A41F, 0x24DC0E2, 0x1DC3850, 0x1E479B7, 0x3C9584E, 0x1D2835B, 0x445B0C, 0x214635, 0x212C4, 0x5949DF, 0xED10DB, 0x2FDBA50, 0x38481D1, 0x62C562, 0x11D36A0, 0x20886F6, 0x33A110E, 0x1F91C38, 0x5A5183, 0x2CE203, +0x264BA3C, 0x355586B, 0x27E8526, 0x41415B, 0x4511F4, 0x1726030, 0x354659C, 0x155F63F, 0x5F9876, 0x20F1A, 0x6D86C8, 0x16A1B67, 0x32C5D6C, 0xCA529D, 0x390DF4, 0x38EC793, 0x2F9FF96, 0x2492D63, 0x694FBC, 0x9DBE9, 0x1F197B6, 0x2252367, 0x3D100F3, 0x191DDC4, 0xBA7590, 0x3096C49, 0x27F21E8, 0x1808BC6, 0x1C0796, 0x550897, +0x12E1775, 0x3E5DC5F, 0x28D8791, 0x39E4702, 0x38FBEFD, 0xB93B07, 0x332B320, 0x2D0632F, 0x7A0A0C, 0x24D9B6, 0x2117E03, 0x292612B, 0x25C3CF1, 0x161B39, 0x1595497, 0x39D68F8, 0x1632E5B, 0x369F937, 0x3986A1, 0x305CAF, 0x52914A, 0x364B099, 0x70B819, 0x196C7DC, 0x3079C1A, 0x1C6B3A7, 0x303AD60, 0x1B560A6, 0x7EF989, 0x4FEE23, +0x30E8419, 0x32B4210, 0x4257DD, 0xAE9C9A, 0x3C096F8, 0x78B2B7, 0x1ADCE5A, 0x74A407, 0x53BBD8, 0x625DDA, 0xCD2B3E, 0xFF50D7, 0x16F1EC6, 0x4917C8, 0x13320FF, 0x297E099, 0x231CD63, 0x397A466, 0x55659, 0xE7F58, 0x3758756, 0x34C7520, 0x1584DCE, 0xC18130, 0x198A5A0, 0x1BFAF92, 0x24FE1F0, 0x951D70, 0x6447BC, 0x6B2144, +0x27F9497, 0x64CFE4, 0x3798B5A, 0xE531F1, 0x93CE93, 0x21B3456, 0x2761BD1, 0x3FB0FD2, 0x212945, 0x612434, 0x4261F3, 0xA7E4E3, 0x247B77D, 0x3454C62, 0x23FF1ED, 0x110CD3F, 0x153E782, 0x2F7285A, 0xC6D38, 0x24691F, 0x3625C9D, 0x326D62B, 0x1D19735, 0x355D8E8, 0x19F4BE9, 0x20BA824, 0x34DCFDD, 0x2794368, 0x2AA61C, 0x1A0AE3, +0x2E4C3B9, 0x3BF95DA, 0x321207, 0x1C5C50B, 0x18C632D, 0x29C6E52, 0x427374, 0x7ED4B3, 0x6C3687, 0x67BFA4, 0xA01474, 0x103191E, 0x135A822, 0x3E3EAA4, 0x26264E2, 0x3062D67, 0x2B8FED, 0x3D6A9B4, 0x49A6CA, 0x674888, 0x2E85A99, 0x2728AC1, 0x1CE0930, 0x21EC6FA, 0x33144BA, 0x160EA70, 0x34634D6, 0x88C5EC, 0x406B2F, 0x11D2F2, +0x223A469, 0x1216BA, 0x11B801F, 0x27B86F7, 0x31A2F89, 0x2324530, 0x3EAEF38, 0x254E09E, 0x22A196, 0x240FE9, 0x3AEB5C7, 0x2CF61FB, 0x32E26D8, 0x61DB00, 0x31B0F9F, 0x148BB1F, 0x127B45A, 0x2BD84BE, 0x603B81, 0x4A5E32, 0x29A8813, 0x1E6C123, 0x246BB79, 0x1436C75, 0x3AA5FC4, 0x12CA5DA, 0x244DB94, 0x3DFF8B0, 0x1AD937, 0x2F4014, +0x285C3F5, 0x555F97, 0x19E475D, 0x1486BE6, 0x1A9BE4F, 0x1A7B0C0, 0x870DD1, 0xA54F2B, 0x4C2185, 0x1462A1, 0x2452C1B, 0x5DBC9C, 0xAAD8F5, 0x37BD4D8, 0x3B870BB, 0x2719737, 0xC7B262, 0x2E4C3A1, 0x5783C5, 0x49F982, 0x35211E3, 0x2EC9851, 0x59E432, 0xADCB7F, 0x299E75B, 0xC88106, 0x1D336EB, 0x27311A, 0x45AD65, 0x45029A, +0x3F3A1F2, 0x2F8A0A0, 0x90379D, 0xB5FBF0, 0x10EA532, 0x378EE0A, 0x7AAA6B, 0x148085, 0x17BD29, 0x3A7412, 0x2CC90DF, 0x300D6C6, 0x3EC25DA, 0x95E732, 0x31F3B0D, 0x9A3115, 0x2DA269E, 0xED8C61, 0x7FD603, 0x634074, 0x20CDA01, 0x181E75A, 0x291CA43, 0x975BF6, 0x2F0BEBA, 0x2F2A453, 0x29B54FF, 0x330E561, 0x143265, 0xE9780, +0x28628DD, 0x3B504B6, 0x1A3481E, 0x35DA692, 0x2841A4F, 0x292EF3B, 0x2D4624F, 0x18E5A4, 0x50D230, 0x55975C, 0x3B8756F, 0x35A1F0, 0x9EE897, 0x1FE9033, 0x31FD077, 0x18FCEF5, 0x33E3B5C, 0x1C21D08, 0x7FF86, 0x70753A, 0x2B973C, 0x1E44468, 0x255388D, 0x3A7A7FD, 0x1F86615, 0x3D233B8, 0x23C6967, 0x535828, 0x5AA9D6, 0x2E7491, +0x176DB4B, 0x31B6D27, 0x6E47B0, 0xE08C9E, 0x2E6D14A, 0x2AFDF42, 0x18F5A6A, 0x11D7EB2, 0x55F91A, 0x2ACF1F, 0x1B58968, 0x27AAAB6, 0x1A6D1E, 0x326AE62, 0x1F77FD9, 0x981A2A, 0x3971291, 0x14063D4, 0x3BAAF4, 0x5466CB, 0x1BA3205, 0x557393, 0x2E89DDC, 0x105AD7, 0x3BE43E6, 0xD7D000, 0x337A86E, 0x1056944, 0x31EA90, 0x464CB0, +0x2FF2BBF, 0x2CAAB0D, 0x21F481, 0x15B4E10, 0x2736D02, 0xA7B2B, 0x335FEAF, 0x2DDD9DC, 0x2B9C8E, 0x46EA0, 0x2317310, 0x10388BD, 0x29EA227, 0x36A53B5, 0x10CA113, 0x11543ED, 0x152FBDF, 0x3DD9E0E, 0x5992A3, 0x52661, 0x19E28E0, 0x335AB3D, 0x23B7DB8, 0xC85236, 0x4E54C2, 0xF55D7, 0x3CB4BD9, 0x52E0D6, 0x1D19C2, 0x680C47, +0x380CCEC, 0x19B45F2, 0x13CA0AE, 0x95DF56, 0x211CA37, 0x21B110D, 0x26F1DEB, 0x16E15DC, 0x789E60, 0x1C548B, 0x543FDF, 0x3E82082, 0x3A9C9AD, 0x18880ED, 0xED27BA, 0x2900D63, 0x244B46D, 0x8F4F1E, 0x3C1562, 0x1414E5, 0x1D23A9, 0xA9EF36, 0xD26547, 0x7AEF2B, 0xFB47CA, 0x180B798, 0x178F3A0, 0x396D6FE, 0x4DA426, 0x4EBAC9, +0x9CB5A4, 0x3D11CBD, 0xB0773D, 0x3BBFEAE, 0x340FABD, 0x1E8C202, 0x3F09718, 0x1F2CDA5, 0x3F54AC, 0x67216B, 0x23FC9F1, 0x111F85E, 0x32F3E6C, 0x15AFBE8, 0x3AFBFF7, 0x102C711, 0x37FDFE9, 0x237D48A, 0x2EEBEB, 0x1B8FD9, 0x2519791, 0x6967D5, 0x23AEB58, 0x5EF080, 0x18ED6B2, 0x30ADB46, 0x2583807, 0x1972CF7, 0x6CF0EA, 0x323DA0, +0x1E24D9C, 0x320527, 0x21F41D0, 0xFE1649, 0x3CC2316, 0x2D2B924, 0xAD4269, 0x3C075B9, 0x2DB8F, 0x68C360, 0x3D5306A, 0x3C4928F, 0x717A1D, 0x2594A0D, 0x33A9235, 0x39711B0, 0x3F21717, 0x155320F, 0x6F56CC, 0xB3337, 0xC783EC, 0xE2C6AC, 0xC6F8B3, 0x178D8D6, 0x64FE29, 0x11709F3, 0x252E823, 0xCEC003, 0x468296, 0x1474B3, +0x3C96640, 0x2FD9375, 0x1E49D5B, 0x3D6C496, 0xC5E24D, 0x258B7F, 0x27FBE1A, 0x1F81103, 0x618FDA, 0x778DD9, 0x2219627, 0x37B7BDC, 0x3CC5221, 0x2566A23, 0x2811FBF, 0x67221E, 0x3878A9F, 0x3AE30F2, 0x3417E1, 0x3508C2, 0x11C430F, 0x32F5746, 0x3B37784, 0x7E942A, 0x2134827, 0x18FAE0C, 0x27EC1EA, 0x2D3999, 0x21BCB1, 0x401E68, +0x13693CC, 0x381C3CC, 0x92EACC, 0x25D6DBE, 0x47A2CC, 0x17F7374, 0x4AE591, 0x3ECD138, 0x20541C, 0x52905E, 0x18B5F9E, 0x15BF4E4, 0x1726D5B, 0xE01F62, 0x23EC79C, 0x2B517EF, 0x1D74AE6, 0x1690811, 0x3390BF, 0x281416, 0x26FE158, 0x194D25, 0x33F424C, 0x235B6B3, 0x22EC7F8, 0x5E8567, 0x13D325D, 0x3EC29D5, 0x3232FB, 0x6F7CAF, +0x23E7963, 0x2062914, 0x2058DEC, 0x28C66B8, 0xEF5BD9, 0x285B10B, 0x1F2E228, 0x13E0A56, 0x691D7B, 0x6FB14, 0x3F62F8F, 0x1D10B1C, 0x18825DA, 0x2AA79D0, 0x16B480E, 0x69B800, 0x1C7B1CF, 0x22F4681, 0x2A4259, 0x230D7D, 0x28DFE8C, 0x3AF7B8, 0x2B38DD0, 0x3A549A5, 0x366765A, 0x1AE7CF0, 0xA5FD62, 0x16DD753, 0xFCAB5, 0x7D9091, +0x2259D6B, 0x287AEFD, 0x1691855, 0x2C3B4EA, 0x21B5745, 0x1D58F2F, 0x18DD333, 0x2BC3953, 0x29BCC0, 0x211A06, 0x23DE9BC, 0x14DFB18, 0x325715C, 0x18F9E13, 0xCA76C0, 0x1B307FD, 0x3B49402, 0x1366F07, 0x6299B6, 0x2CC93B, 0x5D13EA, 0x2215F79, 0x1F8B513, 0x38F7496, 0x11A0EBC, 0x16D349, 0x23534F4, 0x542CC1, 0x3278E1, 0x7EB2A7, +0x2A094CB, 0x96F009, 0xF5F57D, 0x3CE7A77, 0x140505F, 0x99208E, 0x35238CC, 0xDCE8D9, 0x2A3771, 0x12248, 0x1FD4D33, 0x22673B4, 0x23E4BF2, 0x25965, 0xA6CF75, 0x10548B0, 0x31B7F4F, 0xFAE676, 0x2339D8, 0x746FF4, 0x2422EFF, 0x21A42AE, 0x3370152, 0x3802B24, 0x3F0C47E, 0x18E622F, 0x32099ED, 0xF4C7F3, 0x33D8F7, 0x31E57F, +0x1C50869, 0x973EDF, 0x48C568, 0x75D298, 0x3BAFBB9, 0x5D7054, 0x2C3E9FA, 0xCD2CB, 0x4AC8CD, 0x723490, 0xADFA33, 0x6FDEB9, 0x1517DCC, 0x28F4017, 0x2C96F2E, 0x36B5FCB, 0x398F6D6, 0x3995664, 0x224E44, 0x2C93A4, 0x188D758, 0x32C0254, 0x1E835EB, 0x3BE26BA, 0x1CDD772, 0x2FB47B2, 0x859C6, 0x2DD1D62, 0x2E3310, 0x1F6DE5, +0x14FB321, 0x3A874D8, 0x22411C4, 0x24571C9, 0x180D6AE, 0x112F18E, 0x269BB1B, 0x2D7A742, 0x3D605E, 0x699088, 0x2056F10, 0xF4C891, 0xD11863, 0x230CF5C, 0x20B3AF9, 0x13C35EB, 0x37E0917, 0x3EC88AC, 0x1B9169, 0x1609DD, 0x1B366ED, 0x3C93968, 0x722174, 0x1D1E34B, 0x27B0813, 0x27F5D29, 0x27672C6, 0x15CE93A, 0x7BC3CF, 0x13CBB4, +0xD5986B, 0x3973C9E, 0x1ED7319, 0xD217C8, 0x35DCDD3, 0x11D7AC5, 0x35F606A, 0x174CCEE, 0x7ED3D1, 0x70567, 0x3186C1, 0x2717963, 0x17484F1, 0x3E22877, 0x1F14ADE, 0x3CE2A87, 0x15ED2FF, 0x82D466, 0x6A8BDF, 0x17F292, 0x395C610, 0x32813E1, 0xB5FEC3, 0xF0F625, 0xA7C7AF, 0x32C18E7, 0x248EC51, 0x10318B9, 0x28D1D3, 0x100B, +0x21F50DA, 0x34B285, 0x39EA07E, 0xD65BC2, 0x24484D, 0x29CEBCC, 0x3596276, 0x3582893, 0x4FA391, 0x4D4ACB, 0x1835A0D, 0x1B3D082, 0x2A62E30, 0x1CF465D, 0x1D0B97F, 0x148D60A, 0x238A640, 0x290C96E, 0x33ABCF, 0x60666A, 0x1284A39, 0x26A3872, 0x12B6DDA, 0x387FF2B, 0x1B28AD5, 0x18C4A1, 0x3444D82, 0x12F59FE, 0x227A98, 0x1E4EE4, +0x387D315, 0xBBB055, 0x131AED0, 0x54F89C, 0x7955A7, 0xA615CC, 0x302C6C6, 0x37C0371, 0x19428, 0x2B3CAB, 0x2924B57, 0x33389F5, 0x443009, 0x5A5E4C, 0x3217834, 0x2417471, 0x217CB67, 0x1A86080, 0x2D30E9, 0x53E3FD, 0x2E5864, 0x305B6D, 0x24F35E7, 0x2269FB2, 0x2E82B13, 0x337A869, 0xD79044, 0x13BB8A3, 0x58D929, 0x42A8FE, +0x1591901, 0x1687544, 0x84BBC0, 0x32F9B8F, 0x31B974E, 0x2FB67BB, 0x1E80E5E, 0x1C07426, 0x327791, 0xB8957, 0x503668, 0x22D0F4E, 0x2F23B9D, 0x115D4EE, 0x3486CF, 0x3D66570, 0x16B6A7E, 0xE19888, 0x48A992, 0x7D69CA, 0x117271F, 0x1EC35E, 0x153388A, 0x2B90B7E, 0x11DEC70, 0x3CC33A3, 0x3844CED, 0x3D0B51, 0x41BCE1, 0x7EAADA, +0x8A57CC, 0x2A0C732, 0x4E3C41, 0x657AC5, 0x1A8F13B, 0x34D27AF, 0x2F5FA45, 0x29E4758, 0x64F98A, 0x11BE81, 0x30F61B8, 0x3940AA6, 0x237D1D0, 0x1244DBE, 0x100497D, 0x2DBA3E9, 0x2CE049C, 0x1033655, 0x767C7, 0x3BDEE3, 0x11D2602, 0xD978CB, 0x3B13FE, 0x39D254C, 0x19DBB25, 0x1835AF5, 0x15351FD, 0x846753, 0x4CDE24, 0x5A8E2F, +0x20744DF, 0x1E4719C, 0x32D5096, 0xD7A0CB, 0x1055DF1, 0xD42C63, 0x29EFCD7, 0x1F82455, 0x3D3B08, 0x6EB8D9, 0x3D20DD9, 0xFA41C, 0x28FE378, 0x1AE037F, 0x33DA2F6, 0x17D7B4A, 0x3F49D88, 0x100EB3F, 0x13F23C, 0x58D876, 0x38E139B, 0x1ECA3C8, 0x10881E2, 0x9D6224, 0x94D2AD, 0x93809A, 0xAAEEBD, 0x3C45E2C, 0x73DBEE, 0x6EF9A9, +0xC637DA, 0x2F9FF1F, 0x3A7B2E4, 0x13A72D8, 0x1A7CFC7, 0x33D8C02, 0x17F042C, 0xEA92A8, 0x3A0434, 0x6C4F9C, 0x15AC1F0, 0xAC276, 0x35A656E, 0x19A8C5C, 0x3A1B049, 0x1905A14, 0x14655D8, 0x48E8C9, 0x224384, 0x600FB7, 0xD35A24, 0x12E221F, 0x2469928, 0x17796FF, 0x31089D3, 0x1B1E227, 0x1541907, 0x119658F, 0x3B093B, 0x25F5E7, +0x3E7FB84, 0x2EB0E48, 0x8041FD, 0x263467D, 0x1A8E3E2, 0x1FDAB41, 0xEF06E1, 0x1876B51, 0x6F06A2, 0x5DC117, 0x2B52A0D, 0x2C790BE, 0xF924A, 0x16DC33D, 0x3528BA3, 0x1A5CD3A, 0x31CF6A7, 0x3142067, 0x127C69, 0xD72B0, 0x2C2CDF7, 0x2F380EA, 0x3E4358B, 0x3020F54, 0x2DAF193, 0x3F4D7AE, 0x33F13D1, 0x36928A2, 0x67F7D0, 0x7C0A1D, +0x8CBA7, 0xF45F78, 0x3483F98, 0x74F6BB, 0x159546F, 0x30368FB, 0x2450457, 0x302539E, 0x7A588C, 0x851DA, 0x232A892, 0x21F9006, 0x29DB8A, 0x360791B, 0x1B2FCAE, 0x912B79, 0x4C8B77, 0x35E8926, 0x104F86, 0x1E4D28, 0x34B89BF, 0x265226F, 0x5D74E5, 0x1A20FA3, 0x15C2AF3, 0x2F0523F, 0x3E69A71, 0x35971B7, 0x613D00, 0x72F7E, +0x338E243, 0x24749AE, 0x3990EE, 0x1B459A7, 0x1B15669, 0x190C105, 0x29F2462, 0x29D063C, 0x1A81C4, 0x137F2, 0x2699D16, 0x1A88243, 0x649E5B, 0x21B451D, 0x237CED3, 0x316E78E, 0x2D170E2, 0x2B31256, 0x3ED76D, 0x45985A, 0x28F1030, 0xF7F26B, 0x1720823, 0xF4060B, 0x278247D, 0x2DBD08D, 0x1A2D343, 0x3385CBE, 0x6DBE5F, 0x64C375, +0x20C2875, 0x1F8E63E, 0x3DB6CE8, 0x150CFF7, 0x1250BA0, 0x2D9B031, 0x294C90, 0x1438DF6, 0x57E1D9, 0x333447, 0x269B016, 0x29D3DF5, 0x3034A2B, 0x12BAA19, 0x154762C, 0x14A9587, 0x3D8403, 0xFE0993, 0x435FE8, 0x3B9691, 0x31314B0, 0xB777AF, 0x19F5AE, 0x38AEF5A, 0xCCF738, 0x1D666F5, 0x9331BD, 0x1EEA58D, 0x48CCCF, 0x34C2C3, +0xFDBE5B, 0x11B73D7, 0x54D240, 0x104850D, 0x1D43D73, 0x25AE81B, 0x25EBF84, 0x2B446, 0x4E4F9D, 0x1D48D1, 0xE2B151, 0x3D45394, 0x3B9D98A, 0x2158683, 0x2FB82A4, 0x1AC0B5A, 0x24061DF, 0x3DB5735, 0x34902E, 0x44317A, 0x1068BAD, 0x12D0F2B, 0x3091A7A, 0x1DBBA08, 0x1022354, 0x1495FDA, 0x9D872B, 0x31B510D, 0x771FE, 0x76CDEE, +0x3E825FD, 0x3F466E7, 0x2615D6C, 0x31313EC, 0x3A1B55C, 0xBB0563, 0x17B575C, 0x2904CCE, 0x298332, 0x731B0F, 0x3A05240, 0x12AB28E, 0x1467295, 0x1F054F7, 0x3351DEB, 0x30B3EFB, 0x26D713D, 0x21977B8, 0x7A7E90, 0x11CA1C, 0x19D7DE1, 0x83AF7F, 0x32A0D23, 0x3262884, 0xF9A013, 0x2EE3464, 0x36BBBA3, 0x3617084, 0x575E0B, 0x683DDC, +0xD02019, 0x32E2ED3, 0x7C2AD3, 0x3B03BCF, 0x24C8117, 0x76C972, 0x71FD35, 0x3098469, 0x22C7E0, 0x623F83, 0x1AA25A1, 0x2A4D5F2, 0xFC5AFA, 0x3EEA151, 0xE0B99B, 0x6E35D5, 0x151A264, 0x24674A6, 0x2D3EBC, 0x4716E6, 0x3F5D6C, 0xF94F2B, 0xBCAF06, 0x31BCA9E, 0x14BE3AB, 0x24F5341, 0x34E4433, 0x2E2941, 0x5F6257, 0x6EE839, +0x3CA8E7, 0x30DFD59, 0x1902E6E, 0x335A36C, 0x3E3D9D8, 0x33F66F6, 0x349119A, 0x703E43, 0x33C5A, 0x52AA6B, 0x3403646, 0x35896DA, 0x2F35325, 0x212DDD5, 0x1FB0FE7, 0x2137245, 0x32582C1, 0x3AE4CB6, 0x11AB3F, 0x427F8D, 0x5306F0, 0x1B9CD3F, 0x28A32D4, 0x2AA6244, 0x20E928, 0x1145AAB, 0x1BFA18E, 0x2EA6536, 0x4AE91, 0x59E588, +0x2EE9E9F, 0x137B146, 0x3C6BEAF, 0x3D4F3A6, 0x3F8E9B8, 0x448E9C, 0x3BCD1DB, 0x2A00549, 0x4FFC7, 0x73FE42, 0x3BBAAAD, 0x345726B, 0x2F68F3C, 0x3BAB520, 0x4A4224, 0x36D28E6, 0x15B5662, 0xDB505C, 0x5FA850, 0x92309, 0x1AD6BE7, 0x60E24B, 0x27AD634, 0x23AD49E, 0x1EAFE67, 0x3278968, 0x26D4C2C, 0xB6BE6B, 0x8BB75, 0x13704D, +0x3906F14, 0x29E61EB, 0x1CEB1C6, 0x223866E, 0x1EB5D92, 0x1699B77, 0x3EEF503, 0x3707176, 0x57EE05, 0x7967B6, 0x30127C0, 0x14D1B07, 0x10FF08, 0x1ECA103, 0x119C36E, 0x2A3FC01, 0x262ECB5, 0x1227DD5, 0x2A7165, 0x1D3BFA, 0x318D36, 0x1F89084, 0x1CEAFC9, 0x269F250, 0x225D4AD, 0x22FCB21, 0x3D4F849, 0x1EA3D1D, 0x1915E6, 0x228008, +0x3D1B4E7, 0x22CE2E1, 0xA00D17, 0x18E9E1F, 0x3D798EB, 0x3885C9E, 0x3B95DCB, 0x2B6F6A4, 0x55B8D4, 0x685741, 0x1A3B491, 0x2629078, 0x20C2AC4, 0x2BA89C6, 0x2428FFB, 0x2639C03, 0x87E4D5, 0xCA4C28, 0x7E8911, 0x71C459, 0x3F81795, 0x27A63D7, 0x3C64A9A, 0x36D56A2, 0x2DF1E7D, 0x33C06D, 0x23C60EA, 0x21D8FCC, 0x704AEE, 0x52556D, +0x30C33A7, 0xC27B9B, 0x2D1631B, 0x2B95D69, 0x395AB76, 0x2DFD365, 0x21F0D8A, 0x44158A, 0x28666B, 0x36EF35, 0x127F9C7, 0x3F988C1, 0x1577636, 0x382F13B, 0x2C9E899, 0x946762, 0x1F5A961, 0x2D2D6B9, 0x526E78, 0x6C9523, 0xCFE95F, 0x258520F, 0x2A425A2, 0x522E9E, 0x2DA3E90, 0x11CFBEE, 0x322CFFE, 0x1F615CF, 0x658A7D, 0x681900, +0x1BE9C5, 0x330E894, 0xED7B05, 0xBEA6E2, 0x3C2775D, 0x2CBF119, 0x2B98D3C, 0xF87424, 0x4BC236, 0x4129D4, 0xBBEA45, 0x155ECD4, 0x301A156, 0x1E85E68, 0x2534FCA, 0x172F537, 0x21EE045, 0x795515, 0x513E8D, 0x6C9353, 0x9AAD91, 0xBA172A, 0x37E06E8, 0xC82C76, 0x2250727, 0x9B150, 0xE76F25, 0x17D8286, 0x75271, 0x2281E8, +0xEBA6AF, 0x2AEBE78, 0x12DF549, 0x3785F58, 0xCA8716, 0x10DE90, 0x58FFA9, 0x2E8A301, 0x50D387, 0x6AB369, 0x295D138, 0x101B92, 0x1F8C56, 0x28136EF, 0x3EFD17D, 0x1B0EB87, 0xD4914F, 0x3EDD5FA, 0x58B496, 0x40A8F0, 0x16E64D1, 0x6B563E, 0x22D229A, 0x9FA7CE, 0x17D7214, 0x23C5179, 0xE8D430, 0x351078F, 0x4E004A, 0x29DA9C, +0x3417213, 0x453DF1, 0x34B70D5, 0xDEBD52, 0x2644883, 0x393B53A, 0xFFDE18, 0x2CF0C02, 0x2E9465, 0x4475D, 0x15E7204, 0x34D97CD, 0x17E9360, 0x1CD3033, 0x3CCD2D6, 0x11221FD, 0x2DD30B0, 0x30417DB, 0x231A2D, 0x32D255, 0x1EB07B0, 0x2A97072, 0x13F6480, 0x2990E6F, 0x2F60BB7, 0xBC1FB9, 0x7206B1, 0x1F6E737, 0x12E33F, 0x52E14B, +0x2E374CB, 0x24B7D33, 0x2B06A46, 0x21B1429, 0x224637, 0x1893EB7, 0x30D6B72, 0x29C8CA9, 0x1C8622, 0x362823, 0x8D472A, 0x3F4BCF1, 0x36BF29A, 0x2125EFF, 0x37C4F22, 0x1B7F97B, 0x3808DF, 0x2C9EA71, 0x18598F, 0x7ABF4C, 0x33D95D3, 0x1F902C8, 0x1F1138E, 0xDA069B, 0x3A43EA4, 0x1E797FD, 0x38F8609, 0x2F7104F, 0x58728F, 0x6DB1DB, +0x2C3007F, 0x3D2519A, 0x3BFFB46, 0x166D3E2, 0x3CABBC4, 0x1DBE65, 0x11D1221, 0x316C309, 0x7F31A5, 0x18A78E, 0x15D2030, 0x1116B47, 0x40A16C, 0x2DBC837, 0xFF4F6E, 0x733134, 0x3A8866A, 0x36F2266, 0x5C1323, 0x5D0ABD, 0x302E151, 0x21815E6, 0x264E4E1, 0xED2FB6, 0x2D5DA3C, 0x2FDC8CF, 0x2D253DA, 0x8C0230, 0xAB6AE, 0x546CE3, +0x38DBE39, 0x117D806, 0x3AD69A9, 0x332F8C5, 0x3DA4A10, 0x162C026, 0x2A2E115, 0x12E04BD, 0x26D2E8, 0x2A3517, 0x17A374D, 0x101062C, 0x1C12677, 0x2C9457E, 0x5E557D, 0x377490, 0x146B34F, 0x39F0C57, 0x3368F9, 0x316109, 0x29535CF, 0x4D5E0F, 0x83AE95, 0x2025B71, 0x170932E, 0x3B0557, 0xE7599F, 0xB39CE4, 0x496A8C, 0x608A16, +0xB37CAB, 0x2602455, 0x399614B, 0x212CC20, 0x9A96B2, 0xB947AC, 0xB9BB58, 0x2D653A1, 0x75B09A, 0x7690CB, 0x11973FB, 0x1D5883E, 0x176B654, 0xCFF24E, 0x6D0FC8, 0x9F4832, 0x2C23240, 0x22D76CF, 0x738A74, 0x7FBFC0, 0x35F7749, 0x1CC656F, 0x3924FE, 0x3C0B982, 0x37C181A, 0x3CEC234, 0x3DF9A69, 0x2E587C, 0x2C255E, 0x5960CF, +0x3B1F17A, 0xD8B0C6, 0xA5008D, 0x2824380, 0x6ACAC7, 0x73ECA6, 0x228A751, 0x900079, 0x434E03, 0x1F1AAD, 0x33399FE, 0x1BBF5DF, 0x12DB704, 0x242CFC9, 0x6076D6, 0xE11CA5, 0x107A775, 0x1E2C363, 0x899BA, 0x572179, 0x26DE9AC, 0x1A7757F, 0x132C4F6, 0x3EF541D, 0x375DD6B, 0x2161649, 0x33D593, 0x2E43F9C, 0x3C8852, 0x3F2593, +0x1DCC9A8, 0xAA855C, 0x3B94FA4, 0xE5A25E, 0xA92E1B, 0x3D73EF8, 0x373931D, 0x2060ED4, 0x10069, 0x6CD884, 0xE403EB, 0x19850E2, 0x37D6584, 0xC44B31, 0xA7F0B3, 0x330CCC2, 0x3511860, 0x2D9C28D, 0x713225, 0x105796, 0x22FA4CF, 0x285F560, 0x1FD3B1E, 0x1D157, 0x3253A14, 0x1D604E7, 0x1CB5D6, 0x1A9DC7F, 0x32DA1F, 0x76A537, +0xC699F7, 0x372546F, 0x2D3EAF7, 0x19BCAEA, 0x2D9647E, 0xDEC360, 0x18CD31B, 0x19564FB, 0x4E45DB, 0x4F480, 0x3BB5601, 0x3B4DBD, 0x3009E4F, 0x3D9BFE, 0x25263FE, 0x3F1C21D, 0x189AD92, 0x3B7991, 0x122F74, 0x137061, 0x8172C9, 0x5C93F5, 0x20890AE, 0x326810E, 0x1ADE57B, 0xA6C5E9, 0x2B7F719, 0x2794952, 0x527DCB, 0x64D1CF, +0x65C994, 0x251095, 0x1CCCDE, 0x8A3B1, 0x1615BA0, 0x308DF84, 0x13942F3, 0x204AA63, 0x633EE1, 0x49BB96, 0x2F96678, 0x12AE863, 0x15F4108, 0x43329D, 0x20E182F, 0x3E38339, 0xEFFF9F, 0x1F19821, 0x6D7E4, 0x4D46E, 0x27017C3, 0x2CD6164, 0x24D7105, 0x258913C, 0x9ACF14, 0x24DBA61, 0x3D1340F, 0x339453E, 0x3F22E2, 0x15A2B4, +0x2BBD0C4, 0xA673C0, 0x681312, 0x160F061, 0x219D519, 0x33E7FEF, 0x183B322, 0x29F1D0, 0xE7633, 0x75C2F3, 0x3C7C099, 0x2BEC2D4, 0x1E95551, 0x199BE79, 0x3A83E94, 0x1AC867A, 0x3913DB9, 0x8BE991, 0x245C7A, 0x5DE0B9, 0xB72E22, 0x23AC231, 0x2CF9297, 0x3ADA3A1, 0x3A8EDD9, 0x2DA0A7F, 0x3215EB6, 0x3BE23B0, 0x139C2, 0x501381, +0xF40B01, 0x2D65714, 0x231A91C, 0x2410529, 0x3062B2B, 0x1F0C4CE, 0x2F6E0D8, 0x1497467, 0x51D65, 0x1E510B, 0x1374CF6, 0x10F9AA2, 0x39C8FD7, 0x1167AF1, 0x21F0569, 0x1E32AE7, 0x3F4E3F7, 0x2C5C37F, 0x4BFE02, 0xF7E2C, 0x27407CB, 0x285C3C8, 0x3688C9A, 0x2CD3217, 0x18423C3, 0x333362A, 0x2A17FF4, 0x1912ECD, 0xCFC50, 0x22B4D9, +0x7C2D98, 0xBEFC0C, 0xC4ECF6, 0xF447E9, 0x133F57D, 0x312E616, 0x72E924, 0x48BF77, 0x4F432C, 0x1AB94E, 0x2FC85A8, 0x145C810, 0x324D62B, 0x3B5BFC8, 0x9B1FB7, 0x2D00CF8, 0x23E0765, 0x300864C, 0x5B2006, 0x5794AF, 0x36E35D5, 0x23EA1D7, 0x261EB66, 0x3C7FB52, 0x203E5C8, 0x27BF794, 0x2E0DBF6, 0xA37AC3, 0x6BB1F4, 0xCF6D1, +0x1878CF5, 0x1E77B71, 0x30F8719, 0x3645C14, 0x200E54E, 0x1E7F382, 0x1D8EE88, 0x2F404EA, 0x2811, 0x49E00C, 0xCF019C, 0x1EDFC1F, 0x15DBA69, 0x85A245, 0x333ACCF, 0x1685F77, 0xA1E5C0, 0x3B2991E, 0x4B4A66, 0x278EB5, 0x341CF06, 0x1F2FE75, 0x1722E73, 0x3846622, 0x39DB8A9, 0x18D4478, 0x31E09B4, 0x6646F6, 0x6E58C9, 0x73ECD2, +0x3BB9502, 0x38BB5C5, 0x1D47FA7, 0x1A3E5BB, 0x2E9526E, 0x2004216, 0x1C6C18C, 0x2794F26, 0x29825B, 0x2F2A89, 0x345CE8, 0x36FE9A5, 0xCA4BB5, 0x2B2A712, 0x1DEC280, 0x16713AA, 0x1571F19, 0x33B6A2F, 0x727310, 0x6228D3, 0x3C48EAF, 0x2C8D766, 0x38B17BF, 0x2784125, 0x1AC9773, 0x30F960, 0x2783FAA, 0x3E6CC0B, 0x17AB1, 0x121E89, +0x3E96480, 0x2CD4E52, 0x1F40282, 0x15BE51F, 0x1BAB4E8, 0xF5BC67, 0x5C2EA7, 0x2EEF334, 0x9BD8D, 0x2C9E40, 0x1FD812E, 0x16E77C1, 0x16DDD9A, 0x177E674, 0xD9E42A, 0x2509EE5, 0x160EC20, 0x1717BFC, 0x66ABA9, 0x4CC00C, 0x2B7C16B, 0x2DCEF54, 0x1357882, 0x17A40D1, 0x3EFB8C8, 0x3B72B29, 0x258613F, 0x28E770, 0xAE5C, 0x5D1BDA, +0x9B5EF2, 0x2C433C1, 0x24B5CAA, 0x33EDCA9, 0x2C0E75F, 0x36048A1, 0x2327FE6, 0x752759, 0x259D99, 0x23F5B7, 0x14F62EF, 0x2488C4A, 0x363CC24, 0xB3A6F1, 0x2CA9478, 0x3E2E4DA, 0x4D4863, 0x3F4D4A0, 0x8FE61, 0x15F1EA, 0x42EA0F, 0x3BDEEB2, 0xAF8FAF, 0x26414B9, 0x2902C2D, 0x290CA1E, 0x14E75BB, 0xC7B1E0, 0x2A5216, 0x3A8F26, +0x2BFBFE4, 0x2221F75, 0x1462A0B, 0x14B5646, 0x3DDCB71, 0x3D926EF, 0x1C711BA, 0x136DA99, 0x247006, 0x479461, 0xBAB607, 0xDB3B29, 0x3D723B9, 0x1564EFA, 0x35D5761, 0x22601A4, 0x23C8D86, 0x197AC45, 0x31D9DD, 0x7F06C3, 0x12EB65B, 0x14ADB75, 0x1699B9, 0x13F4A05, 0x2C189D3, 0x1742EF3, 0x2D584FA, 0x15D4EE7, 0x5EDCFC, 0x790F80, +0x1DFB797, 0x2815528, 0x356B095, 0x21B17BE, 0x8DB6EC, 0x1887C1C, 0x36D766A, 0xCEE967, 0xCBE14, 0x2C6361, 0x1F52297, 0xDE6903, 0x350B0B6, 0x1F37DE4, 0x2BD3C75, 0x230A32E, 0x30878B, 0x260DF4F, 0x4BD354, 0x1AAE3C, 0x1436F09, 0x19797A5, 0xA3927, 0x51561F, 0x2D1CEED, 0x7B6E0, 0x8D47BF, 0x133BA69, 0x779AE1, 0x25156E, +0x2C57119, 0x3241611, 0x3F60BCA, 0x30363EC, 0x2ED2AC2, 0x145AEAC, 0x1BC7460, 0x1974B5D, 0x7F8C02, 0x5968DB, 0x1121DBE, 0x1B66C01, 0x9611AC, 0x3FA6FB2, 0x39CF7D5, 0xEFA471, 0x35EE00C, 0x15FC49A, 0x57949F, 0x5C2700, 0x3F656E, 0x206B312, 0x24918C2, 0x2CAEF2A, 0x2CF9CE0, 0x3416B7C, 0x737218, 0x1AF6218, 0x16E824, 0x3C2593, +0x4A3827, 0x1A6AC6A, 0x232A59B, 0x3400AE5, 0x263E19B, 0x29971DF, 0x2B7F487, 0x1FDB663, 0x1AE43B, 0x4708E2, 0x31AC7D, 0x63960C, 0x358C8B7, 0x2A8BA95, 0x1550B5F, 0x254F025, 0x36685B7, 0x31E8F3E, 0x53BAF4, 0x5B5B33, 0x2E96B90, 0xC154B, 0xA1E19B, 0xFB016A, 0x1C4FDBA, 0x3B96233, 0x3CFCE9B, 0x1756E67, 0x4748C1, 0x4A4774, +0x26ECDED, 0x12FC35A, 0x156C18A, 0x2FD80F4, 0x3170449, 0x26736, 0x3AA4057, 0x2F294E2, 0x7791FE, 0x2632AD, 0x1697C4F, 0x1A56406, 0x3931238, 0x1010A83, 0x232D956, 0x3353A58, 0x3FA1803, 0x3D2FD15, 0x4EE9AD, 0x34A3D7, 0x176FAB, 0x1F340A4, 0x3F53F80, 0x1C07BE0, 0x1F4E8D4, 0xBA8670, 0x3A15650, 0x1862BB4, 0x15321E, 0xC7D7C, +0x1BFD9D6, 0x2E8B991, 0x20C4C76, 0x33EEF2A, 0x2C65732, 0xAC6466, 0xE78C6E, 0x138611E, 0x34935A, 0x250DD5, 0x240DE4F, 0xB877C, 0x391B147, 0x13620C2, 0xE04659, 0x4F7FE6, 0x53FB14, 0x2ED9A23, 0x618EA0, 0x572CAB, 0x2834146, 0x336A849, 0x205D24E, 0x382DC5C, 0x120A2C, 0x13C4E3D, 0x121D8DE, 0x146476D, 0x6CD73, 0x36942F, +0x2BF4D88, 0x38A5B4F, 0x26B7D9A, 0x27FBF2D, 0x3A96A3F, 0xBABFE4, 0x12E021F, 0x2185A4A, 0x2A9A14, 0x1BE40A, 0x121F7AA, 0x242380E, 0x24065D5, 0x3C0212E, 0x351007A, 0x7374DB, 0x29A0DA4, 0x256E463, 0x1FC66E, 0x1F3744, 0x380A00A, 0x6312C1, 0x11A55A8, 0x2D5A275, 0x2A07B83, 0x1316B4D, 0x1D9BF36, 0xC9D370, 0x1346F4, 0x775E7F, +0x32341C0, 0x1E9C5E4, 0x2620A3C, 0x3181338, 0x6DF078, 0x87370B, 0x28CECFA, 0x3780088, 0x144390, 0x127652, 0x1F50D45, 0x18214E2, 0x12F19A7, 0x293FF4C, 0x21F4287, 0x17453BF, 0x2145405, 0x1859416, 0x236F45, 0x7CC92A, 0x10EF72A, 0xD1D447, 0x383A482, 0x300C25D, 0xC3B2FA, 0x6E7220, 0x356713F, 0x21FA61A, 0x26676B, 0x664558, +0x760DDC, 0x371CADE, 0x12E3936, 0x10B1B24, 0x2B63416, 0x20B9D9B, 0x1BE103F, 0x33BB305, 0x5517A8, 0x3A7F03, 0xAE366C, 0x3A0E82B, 0x21B593, 0x3BF34A9, 0x2533DD4, 0x131E144, 0x30C9E10, 0x972843, 0x1B6290, 0x166219, 0xE208F1, 0x749D99, 0x3344C46, 0x11CCC72, 0x54EA9D, 0xB5580C, 0x1FB72C7, 0xD5A6A0, 0x5A90F9, 0x6F061A, +0x22A15C5, 0x1C9B47F, 0x2AFD867, 0x2C4261, 0x5F40F6, 0x3410586, 0x2604889, 0xDE7857, 0x29106C, 0x4F379A, 0x28E1678, 0x12A6A3A, 0x1BD177D, 0x1EA8025, 0x283C2DD, 0x136523B, 0x19EB66C, 0x9A9031, 0x2C4751, 0x5532BC, 0x196CE22, 0x173E67F, 0x2A2F8D, 0x3A10EAA, 0x256FA5C, 0x3854944, 0x1EA6BBE, 0x3516BA1, 0x4FA312, 0x3C7727, +0x1117EA4, 0x26F88E5, 0x28B399D, 0x10E791C, 0x3B9C48F, 0x2286D57, 0x12B4EE, 0x29A80EC, 0x7BCA8E, 0x3337D3, 0x2005953, 0x2D7C6B4, 0x185CA40, 0x3E24D3B, 0xA1B0B, 0x375EF97, 0x19CD39B, 0x33B9FC6, 0x514BD7, 0xABE13, 0x20E54A7, 0x1B94097, 0x2041E84, 0x1314C42, 0x11DF6C8, 0x373A504, 0x1B5E9B8, 0x319548A, 0x634F96, 0x68D49F, +0x444666, 0x35DA76F, 0xA57363, 0x3E25062, 0x222469E, 0x2CB413F, 0x17F6666, 0x1E1AA1F, 0x542C4C, 0x7133FA, 0x16402B4, 0xC71590, 0x2024991, 0x3C3484C, 0xDCC2F1, 0x18266EA, 0x29E4C71, 0x28BB08C, 0x52DDAD, 0x14EC2, 0x3B34DD6, 0x2D01099, 0x16D8510, 0xBD2E12, 0x3219AC0, 0xEB8E4E, 0x3EAC462, 0x1368A68, 0x157ACB, 0xABF4A, +0x19EAB1F, 0x3790A15, 0x14AE16D, 0x19764A1, 0x29ED5F8, 0xA00CE5, 0x311C9A1, 0x10AF3D6, 0x1BD259, 0x17A484, 0x381363B, 0x714CB2, 0x1465488, 0x2FCBEF7, 0x207A01E, 0x38A9CFE, 0x1E9C436, 0x11D308E, 0x2336D0, 0x2F7A51, 0xE3716C, 0x1401AE4, 0x2CA81F5, 0xD8F39B, 0x180677D, 0x32FD644, 0x34B4282, 0x3811C05, 0x40E8D8, 0x53F9CA, +0x1DADC53, 0x439CE2, 0x25BB363, 0x282485, 0x169658D, 0x3E566F4, 0x13CF5B, 0x1C48DB0, 0x150282, 0x738C53, 0x28BF9FC, 0x321E376, 0x21FB9E8, 0x2A57D2F, 0xFEE64F, 0x16BCD0A, 0x1126A04, 0x90A0E1, 0x4F1899, 0x6170CC, 0x364FF75, 0x22CE087, 0x31249F5, 0x34D9958, 0x20129DF, 0x285EADD, 0x158FE8B, 0x3A81E94, 0x227EA1, 0x473D3B, +0x12B0EB2, 0x4FD508, 0x261BB83, 0x36FCC28, 0x18EDC0B, 0x2DBBD5A, 0x31D0374, 0x16AD66F, 0x78E584, 0x1C6AED, 0x1DB5BA1, 0x18144FA, 0x17F32F, 0x3D8D0FF, 0x231925D, 0x7E5DB2, 0x1ACFE25, 0x379B56C, 0x4A58FB, 0x46A445, 0x3E9E1DA, 0x20A2A0C, 0x2819A13, 0xE65020, 0x1C9FF67, 0x1AB5504, 0x1648EC5, 0x2C9BC13, 0x57B251, 0x62F4B9, +0x1B033D, 0x7ED39A, 0x3A98074, 0x2FFCBE4, 0x3FFBE79, 0x1400333, 0x5DBC43, 0x27989B7, 0x9BC6, 0x253D0A, 0xBEF06A, 0x124CC9A, 0x2EFB73F, 0x3ED18A8, 0x342D7A9, 0x1CB0BAD, 0x1E96CE4, 0x2760B05, 0x2D1B6A, 0x2E8CDE, 0x2F1B2A1, 0xCBD304, 0x3E06F35, 0x1B4F6CE, 0x12947C3, 0x3553FA3, 0x23E901D, 0xD10A20, 0x4CB0B, 0x59FEF9, +0xB9342E, 0x2293ECE, 0x20A9D07, 0x2D3B096, 0x1982919, 0x30A4530, 0x2B05EC0, 0x2B67E83, 0x7B9D63, 0x611069, 0x256A79D, 0x25D4E50, 0x18A966D, 0x3F5D906, 0x15B07A2, 0x111C2C2, 0x3D35B40, 0x1C1632, 0x6FE6F8, 0x24B0C5, 0x2FE45AE, 0x178B8C, 0x220B924, 0x32AABE5, 0x2761834, 0x3D010EA, 0x6C4D0C, 0x24C01B5, 0x68D0B0, 0x123E3A, +0x37FF33C, 0x2E45654, 0xBF9A4D, 0x31116C7, 0x184BECF, 0x1A932AD, 0x2AD1021, 0x734742, 0x4FC960, 0x498968, 0x3E9E3B6, 0x2391B25, 0x25666B, 0xA167F5, 0x1C15795, 0x2D272ED, 0x2FBBA18, 0x8A26DA, 0x7F6FFB, 0x5E8BD5, 0x3CE7C79, 0x27D373B, 0x24A02B6, 0x15CC533, 0xD54C94, 0xEF27F9, 0x3A197C3, 0x292EAC2, 0x510999, 0x4B2C0E, +0x5A8DB, 0x2C55B8, 0x33022D7, 0x12E8D46, 0x36972D7, 0x21E6E20, 0x3A88D41, 0xFF7BD, 0x4609A0, 0x5E4D59, 0x26598B, 0x1E5A0F3, 0xE10BCA, 0x6865E, 0x2179FE6, 0x3BA2D2F, 0x34EAD8A, 0x2F758DF, 0x782A3F, 0xFB4C6, 0x20C350, 0x1A2E55, 0x3D30648, 0x35EA227, 0x23C0FBF, 0x12CB65E, 0x230F48, 0x3D20FE8, 0x148590, 0x1D78DA, +0x1BC09CA, 0x5B63A7, 0x13446C0, 0x948C44, 0x25155B5, 0x1A99897, 0x15CDCC1, 0xE52B73, 0x54FDE7, 0x712D1F, 0x1ABEFAB, 0x1995549, 0x1001BBA, 0x8ACE8C, 0x1381B55, 0x122F98D, 0x1EEF531, 0x379AD5C, 0x4DD8F, 0x637A53, 0x92DA63, 0x23D7B7C, 0x1F5A6D3, 0x15426BD, 0xDF6836, 0x25F8B26, 0x2545094, 0xDAF12D, 0x236F2A, 0x8522E, +0x2CE8301, 0x30E5F0A, 0x39C9404, 0x2160E15, 0xCE9ABA, 0x2B6C331, 0x1C65EA6, 0x1EB1053, 0x493B25, 0x65F547, 0x699753, 0x1BDC53D, 0xA8DA15, 0x921046, 0x3DB3D00, 0x2E1E3B3, 0x2D365BB, 0x3026A3E, 0x2BE693, 0x55691A, 0x14C047F, 0xD6AB37, 0x278E514, 0x1BD918E, 0x171F024, 0x118F116, 0x3242DE0, 0x2932D4B, 0x765674, 0x746ADB, +0x1DA6CDA, 0x2D96CC2, 0xA4D94F, 0x1F10B42, 0xB6893E, 0xA7465C, 0x354BAFC, 0x38472BF, 0x5D004E, 0x3350DB, 0x2FEF67, 0x9AA471, 0x233EA25, 0x2D89799, 0x1164C63, 0x386D9E1, 0x3FF16B0, 0x340F4BA, 0xFF2DF, 0x13A219, 0x2F9F7F9, 0x1F7E5C6, 0xA167AE, 0x433FA6, 0x1ABCDB9, 0x170D25C, 0x2463DF5, 0x2D4FE40, 0x645C50, 0x13D858, +0x2B1E7A6, 0x111CDA8, 0x962C4E, 0x21FEA15, 0x3FC4DDB, 0x2F7A9EF, 0x127D384, 0x134ED34, 0x4849FF, 0x48C50D, 0x7C9AC, 0x1B4EC3B, 0x2108B20, 0x632C59, 0x34916C9, 0x3DAA56B, 0x39968F4, 0x3E78FF0, 0x3FDD72, 0x6E2C6D, 0x1DC97A4, 0x24D0A0, 0x2D6AA63, 0x23D7B7D, 0x3795F6D, 0x193642F, 0x20BCFE, 0x9A584E, 0x423FD4, 0x1A091C, +0x3B2D58A, 0x2FAB685, 0x70AEEC, 0x3DF447D, 0x1099316, 0x1A4B45E, 0x27AC3EE, 0x1A36CF, 0x2E8D33, 0x7F222A, 0x2549A7C, 0x31AF02E, 0x25BE5D0, 0x23A06C4, 0x81C9AF, 0x2CEEDE9, 0x3CC773B, 0x8A91D2, 0x55370D, 0x58BD06, 0x2882E0D, 0x2DA77FD, 0x103E9F2, 0x13AD1E6, 0x24108AB, 0xA7D475, 0x255957C, 0xDF5BF2, 0x5B4DB1, 0x67A8A4, +0x30C9D58, 0x7B57D9, 0x2095293, 0x2C37808, 0x618988, 0x2AA7587, 0x20EFB43, 0x2FB2C25, 0x3232BA, 0x20DF6, 0x229A8AB, 0x23EE086, 0x390414A, 0x33A5524, 0x1A69EF9, 0x2887167, 0x3B9C285, 0x265B077, 0x4AE671, 0x6878C3, 0xAC097E, 0x6D8D29, 0x31C4524, 0x1E5AE9, 0x1144B29, 0x3B65059, 0x27095DF, 0x32352BA, 0x1CF41A, 0x1C2E6D, +0x9B4CB9, 0x1BE57D, 0x2413E2B, 0x8BD210, 0x29E7BFB, 0x132F5A4, 0xB1E191, 0x371DF5B, 0x4EA174, 0xBE0AF, 0x2C738D3, 0xDF7DF6, 0x1D972E8, 0x22B8310, 0x89D5E8, 0x16D5928, 0x1D41668, 0x25DC568, 0x7DAD04, 0x51C65F, 0x6FF9D4, 0x204E41F, 0x57531E, 0x3D19A11, 0x9EFA96, 0xEFC1C1, 0xFB006, 0x3559F6C, 0x507FFE, 0x282FE9, +0x1FB8178, 0x39ED71, 0x39FE0E0, 0x1A51D0D, 0xD57EBE, 0x5ECF35, 0x117082, 0x28DCFAF, 0x5BD4B6, 0x7CDDD5, 0x28E3B5F, 0x1489131, 0x37CCF31, 0x20752FF, 0xDF3A58, 0x28C1EA8, 0x13D7172, 0x2D2470, 0x40E671, 0x6B3640, 0xB6303B, 0x394CE3, 0x1D73D65, 0x161EB4D, 0x254AD44, 0x2275A0B, 0x3771CB9, 0x18053E1, 0x5B630C, 0x3EA3BA, +0x120EEEE, 0x1D7EC00, 0x3AB0497, 0x2E8FEB1, 0x33BBC3D, 0x223CEE6, 0x210428A, 0xCCDEAA, 0x2EF356, 0x5FABCB, 0x17889A, 0x362BF51, 0x84B9EE, 0x32950F5, 0x11D16B1, 0x1D0617, 0x216A6F9, 0x329A52C, 0xB37D2, 0x896B4, 0x277A1FB, 0x36CF430, 0x3765C60, 0x2E3DFA4, 0x865E3A, 0xB90904, 0x1F751E1, 0x3C82C91, 0x553DEE, 0x5B6A78, +0x14B9BFA, 0x37E7654, 0x21DB0A4, 0x3A86D52, 0x29F4A2B, 0x3660B04, 0x14BA765, 0x2CE5273, 0x704DE9, 0x5D307B, 0x1049D17, 0x286F656, 0x1308FAF, 0x210CAE0, 0x1063CEE, 0x16E500B, 0xEEC40C, 0x21A8588, 0x7A8829, 0x260A9C, 0x29D8686, 0x19B2928, 0x39B998, 0x3C3DDB3, 0x2000D14, 0x3DD4536, 0x3FD5806, 0x308EA08, 0x296011, 0x267409, +0x17F8423, 0x2098EA, 0x10410DE, 0x277FBA8, 0x2CA90F0, 0x20C52E6, 0x981658, 0x3BBB34E, 0x3DA610, 0x427E7E, 0x190793D, 0x1F3C326, 0x3E97A29, 0x786E2E, 0x3C9175E, 0x2E911AA, 0x37DB7F7, 0x260FF3, 0x1F5841, 0x7BD5B, 0x1C48939, 0x113764F, 0x25082FA, 0xCC3FFC, 0x23DD16, 0x6C79BB, 0x13C2EE4, 0x2C33F89, 0x794033, 0x674FF1, +0x129CBAB, 0x1E883A3, 0x20FE35C, 0x10469F5, 0x904E20, 0x15909BE, 0x38F6701, 0x1939F09, 0x7E6223, 0x726426, 0x412322, 0x3FDE271, 0x3DE0ED7, 0x18FBABB, 0x280BBB1, 0x3B9FA3, 0x23F5CDC, 0x4C7F0B, 0x46716E, 0x6C256C, 0x32CE1D8, 0x119DA19, 0x166AFF2, 0x1F23494, 0x2708132, 0x995FAA, 0x15BA5AA, 0x10E3A7E, 0x53B965, 0x5019F, +0x24F1EE, 0x3A10158, 0x7556A5, 0x2113A65, 0x3F0905E, 0xCA5E9D, 0x139B0BC, 0x347A528, 0x63E8E1, 0x51904E, 0x36BC6CC, 0x147187A, 0x118B537, 0x10E1211, 0x2691B09, 0x1DD43F8, 0x239885C, 0x2365CE7, 0x2EE530, 0x62B92B, 0x39F083C, 0x2296979, 0x152AD74, 0x2C3F59F, 0x8D43CA, 0xBB77CA, 0x181228A, 0x1E0E58B, 0x25B333, 0x58BA2E, +0x38F3515, 0x1128F01, 0x23C686, 0x11107DE, 0x3BDD778, 0x35E3758, 0x27B9C54, 0x101BD44, 0x290C21, 0x442DB, 0x30A9D, 0x33ADDE0, 0x7794BB, 0x130A9C5, 0x36B2E74, 0xD0CBD6, 0x159619D, 0x1B48222, 0x374697, 0x2280B6, 0x2DB0FB2, 0x7FDD97, 0x2D4F2D2, 0x1AA579F, 0x5BEDD1, 0x2D9553B, 0x10E5311, 0x1BD4125, 0x397496, 0x6EACDC, +0x38A5BB3, 0x104962E, 0x3413015, 0x3405C71, 0x9C8178, 0x95EFE0, 0x17D4857, 0x152C881, 0xD171A, 0x4EECE, 0x1DB67AA, 0x1686AD7, 0x3451400, 0x2B98B66, 0x20AFAC4, 0xD89CDD, 0x19A5885, 0x12348C, 0x6577C4, 0x7A053A, 0x205A880, 0x13AAB89, 0x26A839, 0x2BDEC2D, 0x232F1FF, 0x378CFBD, 0x9BCD54, 0x2E7AC37, 0x5D2604, 0x5EEF31, +0x3276288, 0xA44B01, 0x21F95AD, 0x39292F0, 0xD06FB7, 0x2E33415, 0x2A1F58C, 0x7DC762, 0x4DCCCB, 0xF0A98, 0x18A1502, 0x3EBE037, 0x2EDE1BE, 0x1890185, 0x628E0E, 0x2B5B8D3, 0xF39C37, 0x3874800, 0xEA4AA, 0x2D20C0, 0x1A30282, 0x26B63B, 0x3E2A904, 0x237FE2B, 0x2C4C336, 0x9BCE46, 0x1F605E3, 0x2F5FC47, 0x1D87C6, 0x266086, +0xD829F8, 0x68394, 0x3FBB720, 0x36E4C9F, 0x335505C, 0xC38413, 0x280A774, 0xDE47D9, 0x146902, 0x55FA41, 0x21BF9D, 0x1CC21BF, 0xE57040, 0x2B9A163, 0xE45E06, 0x18F79E7, 0x1A33DE7, 0x2FA5ED5, 0x18D662, 0x3AD51D, 0x2EEF43C, 0x223E935, 0x24B1D1E, 0x3F28E52, 0x2BB7067, 0x1126AA, 0x1E085C2, 0x36636D9, 0x27EC9B, 0x18F7CB, +0x36EDBFA, 0x1B35467, 0x11B39AC, 0x26387D1, 0x2A23341, 0x1412684, 0x3AADF33, 0x68EDC7, 0x1DCFB4, 0x1B20D7, 0x2602E3E, 0xCAFE8A, 0x1D7F253, 0xC9B407, 0x2C2B7A8, 0x666B52, 0x291255D, 0x1CC935C, 0x78C15F, 0x3F53F5, 0x1BCEBAA, 0x1F2306F, 0x20DB8E, 0x3B5CF7B, 0x884383, 0xF745DF, 0x1CF740B, 0x22DB3D5, 0x27A30C, 0x75EE4A, +0x11A8E3E, 0x1169E7D, 0x3327161, 0x2E87F8B, 0x1F2D97E, 0x3BD3F7B, 0x5A430F, 0x120429D, 0x496B58, 0x4B0618, 0x103C7BD, 0x11F1EC6, 0x1B590EE, 0x11F86B1, 0x106D40E, 0xDCF92F, 0xED45DA, 0x1314F30, 0x3C90F6, 0x70C245, 0x653B4E, 0x1D0F4A3, 0x1D7491B, 0x2D1311C, 0x30DFB5A, 0x1977CAF, 0x29082A2, 0x3A4AEF9, 0x7E5173, 0x69A3A4, +0x1FEB424, 0x2FE9979, 0x24C60F3, 0x2FBE99C, 0x213026E, 0x1BF9669, 0x2D5BE9F, 0x1A9FBD9, 0x1E0489, 0xF8AEA, 0x16B51FF, 0x301C9BE, 0x2E20FAA, 0x1E800A5, 0x867FF0, 0x3D63688, 0x1D8F0F2, 0x335C321, 0x31A668, 0x545644, 0x39410E0, 0x3F22468, 0x2DBEDF6, 0x6D35C7, 0x33B9537, 0x29F9C7D, 0x3C408A6, 0x34EC815, 0x6CA227, 0x522058, +0x251FB62, 0x25857B, 0x2FF604E, 0x3F6DA16, 0x24A15F4, 0xBF96D, 0x28E9090, 0x2205514, 0x105B94, 0x14D985, 0x7A9404, 0x1BC821C, 0x2E0D453, 0x275FA57, 0x2F37B4D, 0x2BD3122, 0x26215BE, 0x5E8BDC, 0x67AAF9, 0x7E617A, 0x222695A, 0xDF7538, 0x1336E9C, 0xB0266A, 0x3EAFE96, 0x21AD7F8, 0x3310281, 0x1D7B256, 0x677619, 0x2A2191, +0x11FF3DC, 0x350278D, 0x2B051ED, 0x352A48F, 0x23EC755, 0x120A6D8, 0x14BE1A0, 0x2B26300, 0x4A87F6, 0x4BB952, 0x31E482C, 0x208D16D, 0x315E9A8, 0x176DAB1, 0x1653968, 0x39C63F0, 0x5207F5, 0x1D1B841, 0x855A1, 0x33F9E5, 0x51F53A, 0x1875DDF, 0x11638FB, 0x2CB8B6D, 0xF811F3, 0x35E03C0, 0x20DB3B3, 0x498B2E, 0x4AE3FC, 0x42336A, +0x2DC3868, 0x72E53A, 0x14514F2, 0x2CC424A, 0x22DEE36, 0x1C37D4C, 0x3F5BA02, 0x126846A, 0x25081C, 0x16CA93, 0x11CB675, 0x3D0CA1, 0xEB9103, 0x39AA113, 0x16A4B1D, 0x3023475, 0x3B2F32F, 0x37B6FC1, 0x41B2D6, 0x2CD0E0, 0x3002A6E, 0x1A3276C, 0x3511B76, 0x1E4E1FA, 0x60985A, 0xB109E7, 0x1506699, 0x18EA502, 0x72A06E, 0x414A81, +0x391333E, 0x94F121, 0x1ED4F05, 0x2CD1AC, 0x183825C, 0x2C9DBF2, 0x242D0B3, 0x2EA66C1, 0x3EA571, 0x47570C, 0x6CB5F2, 0x2243975, 0x340721D, 0x25A43, 0x28EFE6B, 0x3DA2B22, 0x2313025, 0x3929590, 0x3C0B0B, 0x251737, 0x2B89DEA, 0x2FFEA7B, 0x352448E, 0x1D19A17, 0x5A63CD, 0x3A29563, 0x3478F31, 0x721BAC, 0x68748C, 0x4E4C5B, +0x2D32070, 0x1E30288, 0x2805D45, 0x19A831F, 0x13A3E1B, 0xF1DBC, 0x28312EA, 0x15A83DC, 0x5CDD35, 0x221071, 0x2C0F647, 0x178CCED, 0x1A4116A, 0x36CE7DB, 0xBC00FB, 0x3892266, 0x25D8F42, 0x21F1C0C, 0x111DCB, 0x2A325, 0x22A4B19, 0x377AC7, 0x325339A, 0x1161302, 0x296F76F, 0x34C00C4, 0x3C4BF3E, 0x3D0C503, 0x474DB0, 0x5F435B, +0xEEF7A3, 0x2A39450, 0x1070C05, 0x3D5AEDB, 0x3F04B97, 0x2B10EAD, 0x8ED4DB, 0x1B86995, 0x54596C, 0x32F24F, 0x1F54E3F, 0xBF9928, 0x8B9375, 0x18BFF74, 0x607214, 0xAA7F6F, 0x1E14D98, 0x24C0057, 0xD6AD5, 0x72569C, 0x31B9216, 0xBE0E05, 0x24D5E64, 0xF88018, 0x27EF42, 0x29A4622, 0x1015F9A, 0x3A5A77E, 0x49D6A, 0x20D91A, +0x56D47A, 0x3BC9BF8, 0x46CD15, 0x5EC9A, 0x2A0F026, 0x2359E6B, 0x4F46F7, 0x3CF5950, 0x601DD4, 0x63399F, 0x5A9764, 0x20535CE, 0x3F88941, 0xB56943, 0x1BEBDBD, 0xAF1C65, 0xCD1992, 0x158E713, 0x10ACD9, 0x49EFBD, 0x304DE65, 0x2715261, 0x176F628, 0x20CDF57, 0x1BE865A, 0x7E25DB, 0x3B43A19, 0x1D525A0, 0x8DDEB, 0x34CF4C, +0x244B56A, 0x1C9568, 0x31D05B, 0x3F9B7CB, 0x3151D84, 0x22B136F, 0x34A0B62, 0x22DB4C6, 0x10FD30, 0x66D8A3, 0x1984774, 0xF0EC9E, 0x2B4EA98, 0x2517B8, 0x3D9001F, 0xF37272, 0x361ECC0, 0x31FAA13, 0x412A9F, 0xC91B4, 0x15832F0, 0x1ED3342, 0x18BC97F, 0x1F4930C, 0x1842984, 0x1FD8ECC, 0x1E31243, 0x1A65145, 0x6F4CD5, 0x580AB9, +0x465B3E, 0x15B774A, 0x2A5FB66, 0x9A9395, 0xAE36D8, 0x3568506, 0x3004242, 0x396A2A6, 0x16995D, 0x82636, 0x23B413, 0x2F9F9DD, 0x10D7312, 0x8DB739, 0x34E7A99, 0x2ADC114, 0xF443BF, 0x312EF82, 0x41FC42, 0x6C3995, 0x135753D, 0xCC292E, 0x8B25D6, 0x36AB0CB, 0x2A78F3F, 0x15AADBA, 0x9FB7B0, 0x1BE28DE, 0x6B1B3F, 0x385603, +0x2C01D73, 0x1C184A3, 0x5532AB, 0x32527CE, 0x349B947, 0x10C8C50, 0x1CF8FC3, 0x21A14D7, 0xA22E5, 0x2AADD0, 0x3992446, 0x26308F9, 0x316EF97, 0x438DE, 0xE9022B, 0x307038, 0x37F28EB, 0x3635C60, 0x15D36A, 0x161B06, 0x2F8D056, 0x18EF392, 0x3D38EAF, 0x1751338, 0x16BACFB, 0x1E646A1, 0x3FA71DA, 0x2700DA7, 0x2A1765, 0x540523, +0xF58E29, 0x1322520, 0x2F68484, 0x3F7CA1D, 0x30355FA, 0x547A29, 0xE5D2CD, 0x3A17B6B, 0x40CBB0, 0x3B32AC, 0x1679DF8, 0x2CCC95A, 0x324AD07, 0x3197016, 0x2F0C0F0, 0x3221B5F, 0x351E9F4, 0x29C18DB, 0x7F07EC, 0xE8B1D, 0xE8A846, 0x2F689ED, 0x2F44C7D, 0x3CF503F, 0x3391B2E, 0x1582AA2, 0x12AE95F, 0x57F797, 0x7DF51E, 0xEE1E1, +0x2240AE6, 0x205E565, 0x96D0B, 0x3FF2BFC, 0x2AF2F7D, 0x2E1E7C5, 0x3BFAD49, 0x3621038, 0x29FC1B, 0x4CF4D0, 0xAD0FF6, 0x2A8D08C, 0x34604, 0x23F47BB, 0x15FFB8B, 0x1C4F86A, 0x1A1AEA4, 0x2B73DBB, 0x44D3AF, 0x3EB300, 0x3588186, 0xCCC170, 0xF099A, 0xEE8983, 0x28818DB, 0xC77BA8, 0x34C07A5, 0x151B3AC, 0x289D0F, 0x26EE69, +0x2C4EA05, 0x2664A0B, 0x2762FE4, 0x2640B96, 0x37D1110, 0x3B714BD, 0xD99C64, 0x3B513F6, 0x33AA0, 0x42BD48, 0x3A9622D, 0x3643859, 0x27864D5, 0x37AECC8, 0x222F735, 0x366EC24, 0xA1576B, 0x3878645, 0xD6EE9, 0x4C60FE, 0x1FAA328, 0x2710909, 0x2BB03A6, 0x2278318, 0x1B0A3BE, 0x2CE17FE, 0x385C271, 0x34EB139, 0x56C2A, 0x7E3B5C, +0x7370A4, 0x3C3197F, 0x1921AB, 0x2943882, 0x1429E9D, 0x300B11, 0x18BA67E, 0xF0976B, 0x4B1A8C, 0x75EC51, 0x1466DCA, 0x1B99943, 0x3F4192C, 0x3B8FEDF, 0x308CFB9, 0x2A44CA3, 0x33F3964, 0x3A4C3EB, 0x290379, 0x2AF7A3, 0x105E35B, 0x31D4CFE, 0x2539B45, 0x215C020, 0x1F0D2, 0x90E902, 0x2146078, 0x41741B, 0x7D5345, 0x419F25, +0x3828172, 0x4D4A6A, 0x79E7D7, 0x20554FA, 0x27985F7, 0x173DA09, 0xA90CC9, 0x1064E1, 0x2921E, 0x220C82, 0x320C927, 0x1ED2828, 0x2D6DE3B, 0x91FF66, 0x2DDBFD2, 0x90CFB1, 0x3718472, 0xE7DC92, 0x3C99A2, 0x4B3A37, 0x12D1017, 0xA6B5C3, 0x17A8B5F, 0x1448E88, 0x987777, 0x161F82E, 0x2D6EA2B, 0x262AA08, 0x3AB07C, 0x449650, +0x1AC4C0C, 0x1FFEDAB, 0x1231DFA, 0x13D014B, 0x157D209, 0x327FC8F, 0x12AC850, 0x30BBD1B, 0x521E93, 0x1DA963, 0x12FA2E0, 0x1DE4BAE, 0x1D8C788, 0x20FB4E1, 0x184E3BE, 0x30D9B44, 0x2234690, 0x37A0F4A, 0xD188E, 0x4FFADF, 0x2938608, 0x6F3A5D, 0x2F66946, 0x110134, 0x30E8ACE, 0x2D37857, 0x324C0A, 0x1E98689, 0x40968C, 0x3E9F47, +0x3D18D12, 0x35C8CAF, 0x7BF1F2, 0x1A917A2, 0xB041DA, 0x35CC755, 0x11EE7CB, 0x2DDC8EC, 0x4FB87A, 0x7F6991, 0x132635F, 0x667C21, 0x4285A5, 0x11770ED, 0x152F3FA, 0x1BAFE6B, 0x735CAF, 0x352EFCE, 0x15E61B, 0x45CF3B, 0x29D63F9, 0x3CEC018, 0xEC18DA, 0x398468F, 0x1567734, 0x392D331, 0x3126B12, 0x1611D5A, 0x457551, 0x7D19E2, +0x59655, 0x1458870, 0x1477C5D, 0xDC487F, 0x3337789, 0x3C3CB3E, 0x225A9E4, 0x2C686FA, 0x573CD, 0x3CC032, 0x24D5A41, 0x1A224ED, 0x7741B4, 0x2A14305, 0x1FFA257, 0x6D46CD, 0x3B12A8A, 0x3B8B5D6, 0x17382, 0x6AF59B, 0x3F80EE9, 0x20490D5, 0x34F1009, 0x3CC9F17, 0xF25287, 0x2DFBF29, 0x2E79475, 0x3E4FD0F, 0x6AA570, 0xFB62, +0x313277, 0x1A589A, 0x1B980B7, 0x18604C1, 0x39E7B0, 0x31EC5BB, 0x239C8EC, 0x4FBBDF, 0x5D8DC9, 0x2A4C9F, 0x3BABA6F, 0x16BBC8D, 0x27B72D2, 0x2B8A8BF, 0x4AD943, 0x2FF087, 0x12539DE, 0x2E906BB, 0x27F4D, 0x230F37, 0x2AAC09C, 0x982A, 0x1DB90F6, 0x135433C, 0x1BE3638, 0x2A75D35, 0x2B9B85F, 0x2849CEB, 0x28ABD7, 0x1DD774, +0x14B0902, 0x9628C5, 0x19624C3, 0x301EE6B, 0x23D7243, 0x39CC22B, 0x8E8B69, 0x35A2AA4, 0xDF507, 0x134123, 0xD450E2, 0x1610565, 0x13B8B3C, 0x39D0711, 0x1ED14E8, 0x3E19D06, 0x36F52AA, 0x3E5BCBD, 0x53A8C6, 0x608DA7, 0x2A0243C, 0x2914182, 0x1FF27F9, 0x477A0D, 0x2B3D59B, 0x31E409A, 0x2D1BF47, 0x3302E5B, 0xDA36B, 0x3BECC1, +0x171C17F, 0x1523C28, 0x2E2932B, 0x1FF6AB8, 0x43C820, 0x2FB1F6F, 0x340812A, 0x325879, 0x2A425D, 0x5FB74C, 0x37845A2, 0x2A5934F, 0x1B83DCA, 0xB4D737, 0x27780C7, 0x1D5D7A2, 0x5E51B3, 0x6C9099, 0x273DB1, 0x73AEEB, 0x2E4392D, 0x1EFBF2F, 0x2986154, 0x3DAADE0, 0x1923938, 0x1354F32, 0x16FADB0, 0x1711DB8, 0x605021, 0x2E4ECE, +0x3812356, 0x23BCE54, 0x1296584, 0x3EFE561, 0x33FDF2A, 0x27A62FF, 0x3680624, 0x270C607, 0x555185, 0x72644F, 0x1E3D624, 0x150FBAD, 0x1AC7542, 0x25D84F5, 0x17D098C, 0x3923DD1, 0x1CC24E7, 0x3E87EB2, 0x5BDDD5, 0x7671FA, 0xC5B802, 0x2FD8871, 0x2ED8452, 0x1D6D311, 0x3BD13D, 0x38700B1, 0x31CF337, 0x3AC002A, 0x616BC5, 0x498A1E, +0x3802521, 0x3DD52B0, 0x3C728B5, 0x30CF1C9, 0x3E5AA49, 0x1749F1B, 0x1B33802, 0x3CC48BF, 0x690634, 0x5D005F, 0x3C622E7, 0x3FFF3B9, 0x62B575, 0x3E8848F, 0x2E82513, 0x6E588D, 0x1B45791, 0x3F38F2B, 0x50F93D, 0x3848E6, 0x3EA4F5E, 0x259A7E2, 0x3F0C68C, 0x2500B, 0x144F6CE, 0x712EE2, 0x3713978, 0x3F6E1BD, 0xCC5E7, 0x257679, +0xB17E83, 0x11E6AAD, 0x1A254F6, 0x2E3A79, 0x20704CF, 0x24F6400, 0x305B38, 0x2B3407C, 0x710F97, 0x5AF48D, 0x3FCC916, 0xD990D2, 0x19E7574, 0x35EAE91, 0x232209, 0x1A62D6, 0x375F2FA, 0x3CB52CB, 0xA3538, 0x46C718, 0x378233C, 0x3B77EEE, 0xF5E668, 0xBC12B2, 0x27A0995, 0x1B2D991, 0x3D29A0B, 0x1E6865, 0x4F4E80, 0x317432, +0x1C11E3B, 0x3F750EA, 0x33369A8, 0x36C5D9C, 0x3BE2ACC, 0x9B6016, 0x205F43C, 0x668900, 0x3FD895, 0x635FC6, 0x30DA1E7, 0x18508D0, 0x11EACCD, 0x16B1C0F, 0x221B84, 0x1CB55F3, 0x2866AFD, 0xC9352B, 0x6C893A, 0x13533D, 0x2CE8512, 0x3BF6A04, 0x40DC37, 0x3583C, 0xF4B846, 0x54318F, 0x9BE69C, 0x22C83BE, 0x2223F1, 0x174BD7, +0x1698189, 0xE4BC6, 0x1E6F1A8, 0x148D0AF, 0x1302EB1, 0x1E85983, 0x1298805, 0x1030552, 0x732BF4, 0x53F66, 0x17C7CE8, 0x6CDB97, 0x3BA2C0E, 0x3E832CA, 0x227B65E, 0x3BF236F, 0x3CE7CBE, 0x3B13259, 0x790451, 0x46D07C, 0x868412, 0x273E57F, 0x126B38C, 0x1E1523C, 0x34997C8, 0x1EF08AB, 0x274CE7B, 0x2F62DFD, 0x6DEE23, 0x1C5BE, +0x2EAE93B, 0xA565C9, 0x397C10, 0x1749B09, 0x3DB6E44, 0x302FE6D, 0x15FF815, 0x2829AB5, 0x65583F, 0x6B3B87, 0x17B8E64, 0x20F9BFA, 0x1754CC4, 0x3546643, 0x1F89D3F, 0x10A4F1B, 0x3436A4B, 0x3B076F3, 0x4ADDB9, 0x30C624, 0x27023A0, 0x13DD8C7, 0x3CBC036, 0x36F52FF, 0x34E4AFA, 0x92E93B, 0xCAD515, 0x3B84CB2, 0x3086E1, 0x690976, +0x124D198, 0x164F568, 0x30471E5, 0x22ECE15, 0x73486F, 0x116B5B7, 0x198B80B, 0x3D575F3, 0xF6B95, 0x55C9B3, 0x2D1C07F, 0x257B3D6, 0xC590D2, 0x34895FA, 0x12DEDF1, 0x439A1F, 0x34FF7CC, 0x2AF92D5, 0x93D67, 0x4B5B18, 0x1D796B2, 0x1E68AE4, 0xA3D6D6, 0xDD4C99, 0x1EA466C, 0x2D6FB9D, 0x1B990BF, 0x35B7EC0, 0x7BAFFE, 0x40903B, +0x32D6BC8, 0x721AEF, 0x2563535, 0x32A16F2, 0x1DD3357, 0x32255A9, 0x37A9196, 0x2780F26, 0x179330, 0x209F0, 0x933495, 0x2A6B951, 0x3CBA5CE, 0xF25AD9, 0x10C5C0B, 0x1358274, 0x135C579, 0x222835B, 0x5E0DDE, 0x6AF961, 0xF2A709, 0x12177, 0xF1CA08, 0x4FD4C9, 0x19A0B2F, 0x3ACEF0B, 0x350CC9F, 0x3D3DD06, 0x5E9B8F, 0x7ABDEA, +0x11471F7, 0x13AFA2, 0x18924D, 0x2BC720F, 0x2D6C6F0, 0x135BE09, 0x2473FA7, 0x2235779, 0x3204EB, 0x6D70ED, 0x22FAA1F, 0x3A1CE1D, 0x221CF46, 0x2ED01E8, 0x33DA207, 0x2A8541B, 0x36E365B, 0xBED53B, 0x5C73BE, 0x7A40EC, 0x1D722E3, 0xC0EA05, 0x15A72E7, 0x1876063, 0x3B6AD6D, 0x4E227C, 0x1E01649, 0x327D664, 0x10ACF6, 0x57B175, +0x2B5A60D, 0x2A720E, 0x2D02F24, 0x1375573, 0x389A4F7, 0x1A1CCD8, 0x191ED1A, 0x25C0202, 0x51431F, 0x6B3605, 0x20E9A0F, 0x28FEE2B, 0xF97741, 0x96C37A, 0x37D478E, 0x206DC99, 0x6851B1, 0x1812C5A, 0x630C0C, 0x4728F0, 0x35B2318, 0x23211DB, 0x41418, 0x3B4A894, 0x309BB46, 0x3A5BBE2, 0xA06191, 0x3FC8F74, 0x2484F7, 0x6425D4, +0x17AEF5E, 0x17F87E9, 0x1A30240, 0x76D27C, 0x15EEF08, 0x1727A63, 0x386B71B, 0x33B5535, 0x2733D1, 0x36D753, 0x4AF537, 0x13E549B, 0x345FEDB, 0x2378323, 0x1B04451, 0x2C3D0BB, 0x1847755, 0x49C564, 0x1DCC4D, 0x2FB2CA, 0x3C31CED, 0x30277E3, 0x1E453FE, 0x37596A5, 0xD10D87, 0x1FA44B, 0x2865941, 0x19E2D2C, 0x190809, 0x13195C, +0x384D41F, 0x30E1C9B, 0x2906953, 0xB4BF1B, 0x508E69, 0x152AECA, 0x1C15979, 0x203895C, 0x61C7C8, 0x7F0654, 0x28873B0, 0x29DA7A2, 0x2A7DF0E, 0x29E409B, 0x324AFAA, 0x39D9969, 0x236D628, 0x16BCCA2, 0x43FCDB, 0x4EAB13, 0x3F85F7C, 0xD27CBC, 0x2AABFA1, 0x1FDB1AD, 0x2F32B38, 0x39E7560, 0x3F869AD, 0x2FA9DD3, 0x69EBA4, 0x273072, +0xD51DB0, 0xFE70DA, 0x5278F2, 0x2987C86, 0xBFA3C1, 0x36BB765, 0x350CF0A, 0x1017C80, 0x161F8C, 0x442B5D, 0x564CC1, 0x2AF395C, 0x1E409C7, 0x28E2D11, 0x95696F, 0xCE6621, 0xCD4173, 0x2D16EDC, 0x3D5DBB, 0x2DA978, 0x1A49388, 0xB7BE24, 0x2B29C47, 0x2D15357, 0x2DF8755, 0x2D12FC5, 0xF957A1, 0x35A363D, 0x46F2E3, 0x67DF47, +0x3898AAD, 0x3D460D9, 0x3889224, 0x1A79358, 0x113E7A1, 0xAD26C9, 0x272270B, 0x177E2D8, 0x40021, 0x4DF64D, 0x1FF89ED, 0x96ADB6, 0x3B41691, 0x3EF0F7C, 0x34EF1FE, 0x1C9697F, 0x1679A12, 0x1F9D958, 0x290C4B, 0x4AC603, 0x15E51B1, 0x3AC596C, 0x100A644, 0x157E2DA, 0x21BE1BC, 0x217843F, 0x28765AA, 0x180C206, 0x7169E0, 0x1CC6A0, +0x3C925D0, 0x20AF1B5, 0x34B6DA6, 0x7AC90B, 0x29318E1, 0x2D7C3AD, 0x3BB5474, 0x54BF35, 0x6FFB86, 0x338198, 0x1F13943, 0x27EEC81, 0xE0525B, 0x5D4437, 0xB02C1F, 0x12B8396, 0xBF8718, 0x16B1DAC, 0x5D924, 0x24D8BA, 0x2548483, 0x1BD1235, 0x3ACB6E7, 0x27E424E, 0x13F0280, 0x1AA6B2A, 0x1ECEA2A, 0x21B0E7E, 0x6C5131, 0x2DA9DE, +0x3127B97, 0x31E9DA7, 0x1245C40, 0x275C0F4, 0x21697F5, 0xA4EC96, 0x16B4C9D, 0xEEEC7E, 0x7BE2BE, 0x500DF, 0x1795917, 0x1AABE35, 0x171DDA1, 0x1FE378B, 0x1345EA0, 0x35CBD56, 0x2A64B42, 0xD6A380, 0x49575, 0x383FAD, 0x3D43D56, 0x1BEC03E, 0x14FACAE, 0x12F351B, 0xC5AB93, 0x279CF9E, 0xC88618, 0x2D29ECC, 0x52B395, 0x4B0DB0, +0x1FF80C0, 0x39C4236, 0x17DADB8, 0x23AC96C, 0x22158CC, 0x29FCD00, 0x1192D54, 0x2ECBD0A, 0x1BD2CE, 0x3B4CE5, 0x1153D9D, 0xED5A53, 0x925A07, 0x740872, 0x5B9E1F, 0x4958A1, 0x2C52F13, 0x2C962FB, 0x3E022C, 0x560D3F, 0x5A6012, 0x27CE0C3, 0x16149C, 0x303D8EE, 0x2FD3F44, 0x1BBAD93, 0x34AC6CF, 0x32CFA4F, 0x5C8BCC, 0x337798, +0xC8E88, 0x3BDB4A9, 0x3DA33E0, 0x1075B37, 0x3CCE7A9, 0x274E7DD, 0x1A27CFA, 0x31386C, 0x579AFE, 0x380241, 0xF0DB02, 0x2D1952E, 0x1075DC3, 0xFF60D7, 0x1E23642, 0x237BF3C, 0xCF1D2F, 0x2228F3B, 0x2F7C81, 0x741B1D, 0x283C68F, 0x3E47C24, 0x6B9911, 0x135D07C, 0x11E174E, 0x1252398, 0x2783DEA, 0x1EDA8E7, 0xC80DD, 0x4B3EB9, +0x1A9A195, 0xDDEA30, 0x26E5043, 0x3F5794F, 0x3B4132E, 0xE05F92, 0x37013B0, 0x1562783, 0x11D09F, 0x296E09, 0x283B696, 0xAD0033, 0x8030E8, 0x300E5E4, 0x332C4E3, 0x84ED3, 0x2E913B2, 0x982D7B, 0x7E33FB, 0x5C8EBB, 0x39D2E9D, 0x10D8D49, 0x1D156ED, 0x17DAED3, 0x3155A66, 0x180B3AA, 0x2753D6E, 0x3B5C197, 0x12FBEC, 0xCA652, +0x11C6F83, 0x3C38F7D, 0xE1D4F5, 0x8F5358, 0x39F2B79, 0x1282842, 0x306980B, 0x12E2E4C, 0x41644A, 0x71057B, 0x25F47B5, 0x26C2DAD, 0x3E80545, 0x4F2905, 0x201D39, 0x511BE7, 0x28670CF, 0x30AD066, 0x7536C8, 0x456C98, 0xB44658, 0x1A27957, 0xFC9787, 0x3B5B878, 0x1BA7479, 0x2BDB9F9, 0x73F868, 0x380A109, 0x1D002F, 0x95DEC, +0x1001D6, 0x1C02AA5, 0x34D04BF, 0x1ADAE83, 0x1E99E57, 0x683C75, 0x28366C9, 0x1F5E7B5, 0x481C63, 0x24AF04, 0x3B68275, 0x3900CE, 0x2B0404C, 0x1E37BC3, 0x2012E37, 0x1740875, 0x395C200, 0x248EE32, 0x418B45, 0x7C5661, 0x1DA7366, 0x9E4D32, 0x2AC29BF, 0x14A390B, 0x2B3C5F4, 0x1DE8308, 0x209793, 0x1E64CF7, 0xAC610, 0x436E59, +0x3352222, 0x38C9273, 0x1BAF848, 0x31577FC, 0x3DC70CD, 0x11D96C, 0x2291BCC, 0x369C501, 0x63D176, 0x474438, 0x1CF6402, 0x3391F0E, 0x12E26E0, 0x11C8105, 0x1050A18, 0xCBA3BD, 0x28EA99D, 0x2166A38, 0x6BF820, 0x3F2B8F, 0x125DA29, 0x1B0A9FD, 0x149586C, 0x1C3431F, 0x97DED9, 0xA6CC3F, 0x31D0594, 0x29224A5, 0x7EB1A, 0x5AB896, +0x20018D, 0x24C7464, 0x18225D7, 0x1BA63F0, 0x456D4B, 0x1E42F76, 0xE7C974, 0x2748A4, 0x6243B0, 0x20035C, 0x3462524, 0xFA9BF6, 0x396D7BA, 0x2636639, 0x657CC0, 0x24D443A, 0x15417E4, 0x3106209, 0x24BCBA, 0x3B621E, 0x35C812C, 0x3F5D0BD, 0x11CBF88, 0x2036DF5, 0x2D23633, 0xF947B, 0x1128CC5, 0x3D598DE, 0x31A208, 0x22D482, +0x2142020, 0x2657645, 0x89F714, 0x29BB8C2, 0x137E4DF, 0x2433CB4, 0x1892FC, 0x36ED6B6, 0x25076D, 0xCE469, 0x25B9C5B, 0x1EC4B97, 0x18947D, 0x2932073, 0x3538FDB, 0x1D0D98F, 0x1D2A3A3, 0x346AED8, 0x44F822, 0xCCD61, 0xC5AB54, 0x1BA5722, 0x30DC4D1, 0x3207CDA, 0x3919B9D, 0x24DA67F, 0x333E397, 0x286BD80, 0x35DCD9, 0x121B5A, +0x3B1F1FA, 0xE40104, 0x6C5AC3, 0x61F3C4, 0x5BE0B, 0x2CD905C, 0x35B4EC6, 0x31D0F6A, 0x4DC688, 0x71AF39, 0x2ACF4B3, 0x3DE616B, 0x7A5FE0, 0xEBC4DF, 0x3F5BE69, 0x27F6B06, 0x16E490E, 0xA87781, 0xC4630, 0x4E26E7, 0x2221004, 0x2EFFEFC, 0x399B406, 0x1434DEC, 0x10B161F, 0x2A5D4FF, 0x9033A9, 0x2AC2E26, 0x172FE9, 0x6BE02, +0x17AF213, 0x89326D, 0x2AAE59C, 0xAAA596, 0x3FFCDD4, 0x17A4781, 0x156D629, 0x3D83591, 0x323225, 0x1BD608, 0x199E141, 0x3814855, 0x2DAD13A, 0x11A7F0C, 0x28A82C7, 0x1586D95, 0x2A1E15A, 0xDBDAFF, 0x113A86, 0x4A18DC, 0x3854FD3, 0x1F8DCC, 0x1AD82F6, 0x3DF3F39, 0x3A90070, 0x2AE824E, 0x1A15943, 0xF98CB7, 0x4DC356, 0x19049C, +0x3138A89, 0x2A362D2, 0x2938A2D, 0x1273719, 0x7E25C9, 0x2C85EBF, 0x2F07942, 0x57995D, 0xF0B7D, 0x19E4B8, 0x3B6063D, 0x3986795, 0x18147B8, 0x240D37B, 0x28E4189, 0x35E8400, 0x10614A9, 0x3FCE6D2, 0x9ECC7, 0x36B440, 0x28AF1CB, 0x3AE5F2D, 0x991FB8, 0x62B977, 0x33A89BC, 0x855C20, 0x277454A, 0x3CC0027, 0x62613C, 0x29CE5E, +0x21D2B1C, 0x553D3, 0x14D562C, 0x10DCC9, 0x9360B6, 0x2310483, 0x1747DD, 0x26216A0, 0x45E2C5, 0x52856, 0x3924181, 0x7D28A, 0x3500B8C, 0x242B9F8, 0x1555A90, 0x2E37288, 0x3708F2E, 0x2DAC7AE, 0x5E610E, 0x7E5132, 0x94CB1B, 0x1730534, 0x94BADF, 0x2B02D0C, 0x36720D5, 0x25B999F, 0x3A87F6E, 0x358EE4C, 0x308DDA, 0x77D54E, +0x2C6EC3F, 0xB08A35, 0x11EF2DD, 0xAD7B0C, 0x2D864D6, 0x2B5C4B2, 0x8BB0B2, 0xED48C9, 0xE968B, 0x3B31DF, 0x2C3105D, 0x2F2CF2A, 0x13D8E36, 0x2DA5165, 0x3ED3BE8, 0x20AA7A8, 0x3C4CFB2, 0x305745B, 0x7DB085, 0x67B2E6, 0x173011D, 0x1743987, 0x22C82FC, 0x3CFCF36, 0x3864480, 0x1DF3F67, 0x2FEF99B, 0x3A2585F, 0x25D5FB, 0x654250, +0x20A88C0, 0x1256902, 0x69F82E, 0x2709E8B, 0x350AF5A, 0x17DD266, 0x205E66A, 0x20384BF, 0x3616C7, 0x3A8EC3, 0x2418E30, 0x35A4133, 0xD87D12, 0x74EDD4, 0x3645A25, 0x3BDF60F, 0x748C, 0x284B971, 0x2942F3, 0x14DEAA, 0x10C8D6F, 0x370567D, 0x27EFB38, 0x28C2FEE, 0x3D008, 0x3FB365A, 0x4DD5F2, 0x2BD0268, 0x4BF7C3, 0x4FED47, +0x1D3DAF5, 0x29AE02F, 0x15F761D, 0x3D90F4C, 0x9BB075, 0x3CB0A21, 0x8E038F, 0x11D0CE2, 0x36C49C, 0x6CF6F7, 0x20F3012, 0x35E79CD, 0x3DE04DA, 0x1BF32F9, 0x29D4B5D, 0x3B7D4D8, 0x37CB803, 0x3820B40, 0x31FB2, 0x23F890, 0x10A8262, 0x6090D5, 0x1A87FED, 0x2F8D47E, 0x3302571, 0x13646A1, 0x2A9B3C, 0x3F04CD2, 0x199B5, 0x36095E, +0xE46920, 0x3156A6, 0x1D4AFA3, 0x3B957F4, 0x2F65FFE, 0x9F6320, 0xD02D94, 0x1149E10, 0x65047A, 0x5AF6AA, 0x1CF3850, 0x318F680, 0x2BCA0EC, 0x3D9E49A, 0x2F96A6C, 0x1A4A750, 0x23D841C, 0xA49F48, 0x4E3A98, 0x9FC3F, 0x2CE1169, 0x23774F2, 0x224F0BC, 0x49565C, 0x3E75914, 0x54A6CB, 0x19C486C, 0x30A9C38, 0x4D15B3, 0x3EE5B8, +0x184D2D7, 0x1842A05, 0x26CD463, 0x342412B, 0x3A587DD, 0x1845E1B, 0x1694FD5, 0xA7269, 0x147D5A, 0x3A0F3B, 0x1410074, 0x1F28AF9, 0xF00C98, 0x33D72DE, 0xC17715, 0x39F4EBE, 0x19CDC16, 0x261C309, 0x4E203D, 0x574B88, 0x1F444A4, 0x6275B2, 0xC5EC01, 0x3C87371, 0xB1E326, 0x24E07C5, 0x112CD3D, 0x2E7B893, 0x7480DA, 0x210494, +0xAA4EAD, 0x3A566CA, 0x3DB287D, 0x22A119C, 0x19403CB, 0x1A219E, 0xB32FFB, 0x5A6410, 0x6BF387, 0x61A80E, 0x39B3824, 0x29F9AF0, 0x380A79F, 0x38DB525, 0x2BD3EA2, 0x799F60, 0x21197C3, 0x6014C7, 0x576229, 0xB826, 0xF3C61D, 0x2A5CBA3, 0x83B257, 0x11F3FD1, 0x7D0171, 0x226BB0D, 0x35B7A17, 0x35FB7, 0x47196C, 0x292714, +0x116B894, 0x1C0DB5F, 0x2420D4D, 0x177BB79, 0x2C8E835, 0x9FB2EC, 0x2307BB7, 0x22B129A, 0x4BC57F, 0x7B9FC4, 0xFC10E5, 0x2A531F9, 0x339B7A2, 0x847F13, 0x23D6F82, 0x203E88A, 0x29C380E, 0x396462A, 0x6C5D84, 0x7D5583, 0x2FB8F39, 0xCACB4, 0xB5C1D9, 0x261CAE0, 0x318ABDF, 0x22D6D6A, 0x1F9CD2A, 0x35487F4, 0x592649, 0x757C1C, +0x3EC4BC0, 0x2D3D4EB, 0x142C304, 0x239E3F3, 0x299A22D, 0x216995C, 0x34D2857, 0x27056F, 0x288A77, 0x45ECE1, 0x132128, 0x2E7741E, 0x3BC98B4, 0x3150974, 0x39D6878, 0x1C65E3F, 0x27F6624, 0x39C7D66, 0x48110E, 0x50CA6, 0x19FE375, 0x3229A54, 0x3E5D817, 0x1287041, 0x10E4E02, 0x1FEFD3, 0x26FFB90, 0x3372F5, 0x2AF48B, 0x43DC6F, +0x1CC562B, 0x1D32810, 0x13ADF59, 0x21D847B, 0x124815B, 0x1D7F2B0, 0x374FA4, 0x1377382, 0x369A7B, 0x116B23, 0x290D2B0, 0x242B600, 0xF2BA3, 0x1E4DCE4, 0x2038CDB, 0x12A1081, 0x561D59, 0x398CF35, 0x4017D5, 0x5086E8, 0x1CB8087, 0x2DF2068, 0x36BB855, 0x16A82B2, 0x27E9F5D, 0x288236E, 0x2D83566, 0xA06C64, 0x773311, 0x7126A4, +0x37ECEF8, 0x2740C25, 0x437D53, 0x7ADB0F, 0x3F6754A, 0x32DEAC3, 0x3EEDB8C, 0x12103FA, 0x3CD7D2, 0x517DB5, 0x3CE27A2, 0x385A2DA, 0x32C9A6C, 0x21F07CB, 0x19E7F17, 0x1B01FC8, 0x3347732, 0x1096ED5, 0x4A8FE, 0x280DA7, 0x16A5A53, 0x2587F71, 0x3DCBD49, 0xFF9EE9, 0x3465A1A, 0x3335C20, 0x27F1167, 0x7DDE93, 0x71DA83, 0x8A420, +0x3014D96, 0x3E3997F, 0x27A95A0, 0x2B05A30, 0x1AE26CB, 0xF7AB55, 0x1DADAD4, 0x8DCF5E, 0x5DA170, 0x41B9A3, 0x600A50, 0x3D66D0C, 0x1600CEE, 0x2220DC1, 0x16CC96F, 0x226F0FF, 0xFB2765, 0xD5114, 0x6EBFBA, 0x2F562B, 0x3D368C7, 0x24083A6, 0x23F0056, 0x3C0DA70, 0x227E238, 0x1AAA301, 0xB389FD, 0x3DB6A35, 0x2B7D80, 0x77E139, +0x3FCE43C, 0xE26585, 0x215D1A5, 0x1801CCE, 0x21B69F7, 0x2FF1AD, 0x2515950, 0x17ACD70, 0x2726C, 0x6134CC, 0xDCD1E1, 0x1ED2E10, 0x39CE727, 0xE49B73, 0x3A1377A, 0x3B7397D, 0x10C8CF1, 0x1F8533A, 0x4E965, 0x6BCDFF, 0x2489774, 0xD9784E, 0x1AB8ACC, 0x142F644, 0x2F8D9C4, 0xAD7B03, 0x26811CE, 0x34F8859, 0x4A97B, 0x448212, +0x1F5E995, 0x2AF20, 0x19380D4, 0x15354D0, 0x28D6F34, 0x2AEB868, 0x92CEB7, 0x3F977A4, 0x68AB4D, 0x613F7F, 0x8A370A, 0x2BD3680, 0x16D3D18, 0x3B14E12, 0x2688B38, 0xFD8C31, 0x3B2F1BC, 0x1068800, 0x220DCC, 0x25A828, 0x694236, 0xD99176, 0x3908941, 0x21947B7, 0x1F5D19, 0x1C76080, 0x135505E, 0x88F50A, 0xBC112, 0x41B81F, +0x2CC80C6, 0x327119, 0x372C998, 0xABB63E, 0x1F741A6, 0x23406F0, 0x2C3BC34, 0x1DB3312, 0xB101F, 0x5B4C51, 0x16EE8ED, 0x2DD1341, 0x3BF4803, 0x3FB287E, 0x7498FC, 0x16CE1E, 0x1CA1FD1, 0x627724, 0x54812, 0xE74BC, 0x346CB12, 0x32497D1, 0x11C0D4F, 0xDA1BC7, 0x90CE90, 0x1086950, 0xD156F2, 0x2DDCCFC, 0x69513D, 0x280A0B, +0xA91DEA, 0x3DBCEB1, 0x17E664C, 0xCB1953, 0x387814E, 0xECF46E, 0x212C0F0, 0x208AECB, 0x7840AD, 0x7E88D2, 0x3F8661D, 0x474A10, 0x22A2BB5, 0x1BC5CCF, 0x1804D7, 0x4EF97B, 0x105BBD0, 0x3F131C2, 0x70EB17, 0x3D0D27, 0x1EE0D71, 0x2F1611, 0x3D83DA8, 0x22BCCDD, 0x1302730, 0x22EDA1E, 0x22174F6, 0x3B04A60, 0x7BF6E3, 0x73B798, +0x642A70, 0x298CBD7, 0x1A6EC25, 0x63807E, 0x4A40F6, 0x14510DB, 0x379E27F, 0x1D9D2F8, 0x142927, 0x6AE4D3, 0x38B4B74, 0x4DB879, 0x17A63C5, 0x47494B, 0x2C6C717, 0x1AAEB72, 0xC66F14, 0x3E3CFB4, 0x40534E, 0x1A7651, 0x150CC97, 0x35B3839, 0x290E4CB, 0x35DD5D7, 0x3599C9, 0x64A327, 0xADC807, 0x39E10C6, 0x630B23, 0x5F0E19, +0x30A3BB6, 0x4BD764, 0x2C02D94, 0x1DE779D, 0x3857BFB, 0x11E1759, 0x18365FD, 0x18C5DDE, 0x19BA9D, 0x5FACBE, 0x16A3B61, 0x7AF492, 0x3A94471, 0x252D4, 0x31DC74, 0x2B37CD2, 0x3A1020F, 0x301F24A, 0x1D8909, 0x2EF1B9, 0x494FC9, 0x3175D73, 0x3B67BE, 0x236F20D, 0x1FA1843, 0x10221FB, 0x39B7D6C, 0x2D60023, 0x3F9170, 0x65B961, +0x2864B6F, 0x161EF84, 0x2BEDA05, 0x773583, 0x31E97E1, 0x1298C0A, 0xB14D21, 0x3A64B10, 0x54C4B9, 0x4390F0, 0x3C27348, 0x4A89FC, 0x138B22D, 0xBEF643, 0x308C1E5, 0x209DEE4, 0x68BB0, 0x1FE35F1, 0x7A987E, 0x1ED8C7, 0x19A3346, 0x39FD03C, 0x37B6B2A, 0x1548A8E, 0x34ED569, 0x2BFBC91, 0x39827FB, 0x2C919D1, 0xEB471, 0x726453, +0x1C5FA4B, 0x1FAC3, 0xF2B94F, 0x37E7C1, 0x2EF64ED, 0x2E2F085, 0x2CD2E7F, 0xF2C908, 0x1BF1E4, 0xA58D3, 0x3ECFC29, 0xD9BCAF, 0x25FE580, 0x324CC4, 0x32E3D1, 0x33F96C, 0x36E8731, 0x1162F8B, 0x45E46E, 0x18DE3A, 0x12A49A, 0x5710B3, 0x19796F3, 0xECBC07, 0x3187C9E, 0x2C4A53B, 0x17C08E6, 0x3D5F38B, 0x71A534, 0x438350, +0x20391DB, 0x33117FD, 0x34DA29D, 0x2B5D7B5, 0x1FE2DBB, 0x2E8C297, 0x237FB0A, 0x3552C41, 0x403363, 0x269C08, 0x38B4218, 0x1CF5FA7, 0xF93F48, 0x1454C45, 0xAAAA4E, 0x374A957, 0x32C2482, 0x3C21DBE, 0x1F48A1, 0x59FEEF, 0x3368710, 0x707C39, 0x36D2BDB, 0x35AEED3, 0x34D4FDE, 0x3BB1689, 0x39E7E99, 0x526415, 0x79BE1F, 0x394A45, +0x1FC43B3, 0x334BD13, 0x1F53EC8, 0x2DDA512, 0x23BF588, 0xB36C66, 0x3F12D70, 0x2A2916F, 0x37628D, 0x6E97F0, 0x1EDBBDD, 0x3CD9037, 0x1AC404E, 0x16365DD, 0x18333AC, 0x2537F87, 0x11AD9D1, 0x23C09A4, 0x313F48, 0x2FDC9, 0x3F833A5, 0x2D8C9EE, 0x27CE07F, 0x3D2281D, 0x105C9E7, 0x3B31E9, 0x1A3126C, 0x327FA55, 0x25AC5D, 0x788C85, +0x3B3B778, 0x2FDDD25, 0x3A9476C, 0x24B0AA0, 0xDB2776, 0x29763C3, 0x10156D9, 0xEFA3B, 0x7C4, 0x650002, 0x37C50AB, 0x18B8282, 0x6599AA, 0x2BDE5C4, 0x2D39EA1, 0xD3AC4A, 0x3A3E0, 0x354E0B8, 0x528B27, 0x55E5A7, 0x9F1039, 0x1622435, 0x202C8BA, 0x18C1D43, 0x7A015A, 0x35B28D5, 0x1652C49, 0x2331B7B, 0x199F68, 0x2687F4, +0x1EAFAEE, 0x2679D9F, 0x2C30096, 0x2F3CD33, 0x195AA16, 0x3C87E31, 0x20D3A4D, 0x20A7BB8, 0x7AEB10, 0x4E2C19, 0xA35C9D, 0x298389C, 0x21A72E3, 0x23B299B, 0x4EBA46, 0x2740A08, 0x4F0214, 0x3C3DC98, 0x3CD353, 0x44C562, 0x47523A, 0xF2E0AD, 0x2E28A3D, 0xB175B4, 0x3576D3E, 0xC61031, 0x166FF8D, 0x3C34585, 0x43A0E0, 0x5F30AA, +0x182B0AA, 0x27925E6, 0x269E9B8, 0x26ED7BB, 0x296B6F0, 0x2FE3659, 0x3486A08, 0x1163730, 0x575DB3, 0x93F89, 0x151FC84, 0x75A4F6, 0x12BDE14, 0x1BE3E4C, 0x148070C, 0x1C6D0E6, 0x3146779, 0x898CE9, 0x1230C0, 0x5DE4A1, 0x1ECE1B6, 0x359C447, 0x273E0FE, 0x39A79A3, 0x1617DB9, 0x3C164DF, 0x1284F7B, 0x3DDC568, 0x1C3ACD, 0x482BA1, +0x1EA8FD, 0x3DF322B, 0x3B4A9F2, 0x31D2B3E, 0x172FEFE, 0x2FBF78B, 0x3ADC4E9, 0x33A3AE1, 0x4E089E, 0x4B4951, 0x2C6714D, 0x1E9E3A2, 0x3EDAD1A, 0x22FDBF3, 0x14040EA, 0x2D62B49, 0x34427DF, 0x20FBD77, 0x72913E, 0x3C08A2, 0x248B346, 0x1DF44AC, 0x27D64E, 0x3A10FB9, 0x9809AF, 0x2151A78, 0x1074035, 0x35082A1, 0x7ED524, 0x25DB12, +0x1D049E0, 0x1DA882C, 0x1039FA2, 0x1771549, 0x16CCEC8, 0x27DD87, 0x3A4A2FE, 0xBF095A, 0x5A34CB, 0x2AF444, 0x2EF5A5D, 0xC240DA, 0x3ED0A30, 0x1CA0955, 0x3D9C089, 0x2BC96F5, 0x3382028, 0x299C1ED, 0xB573A, 0x425CED, 0x1E824FB, 0x5C1EB7, 0x16A30F7, 0xA48647, 0x1DA994B, 0x1533ADF, 0x1A9116D, 0x20BE939, 0x264F6F, 0x5E302E, +0x237F35, 0x1C71B75, 0x1C4BF11, 0x24B2D36, 0x2E66F51, 0x295B103, 0xB10B95, 0x3FA115E, 0x2B0AF6, 0x4D7E08, 0x4534BF, 0xBA79E9, 0x2E7B3AC, 0x290FF6D, 0x21E5210, 0x1E87667, 0x71F623, 0x109DBB, 0x73329D, 0x3435EC, 0x278B098, 0x2754041, 0x2150286, 0x3A8D45C, 0x3B7838B, 0x3DAC447, 0x1B99E4E, 0x1D0B630, 0x4F6C26, 0x109D7B, +0x2A4F6F7, 0x245BAB5, 0x32AD174, 0x2CE7595, 0x3D2AE3C, 0x2AA730, 0x2DCFCEE, 0x34BE0CE, 0x59040B, 0x5C61AE, 0x3CF83E1, 0x310E2F7, 0x850F78, 0x1208A2C, 0xF9A99, 0x333A546, 0x2E226DC, 0x14BB83D, 0x13455C, 0x5B8377, 0x1EA0DD9, 0x3D94258, 0xE9B039, 0x30816E3, 0x29A2392, 0x2CD5A34, 0x7F272, 0xA682D, 0x5EBEBD, 0x7D1A10, +0x1A46527, 0x27240B6, 0xF00890, 0x21BFD72, 0x3C626C8, 0x1CD926F, 0x175AF87, 0x79F765, 0x4127C8, 0x216739, 0x78CAEF, 0x5CF574, 0x9D41AB, 0x1149990, 0x2A0F792, 0x3AE1077, 0x66E20C, 0x1FD5C4, 0x1A2CF9, 0x38095A, 0xA3E7E7, 0x4A4822, 0x3AAE617, 0x9FAF9, 0x1639E5E, 0x1F0991, 0x3BADCD3, 0x3ED37A7, 0x6A5DD9, 0x311085, +0x66C3B5, 0x32BAC13, 0xD87884, 0xD17154, 0x288F33F, 0x31B5376, 0x34B7F21, 0x23E6424, 0x550091, 0xAA089, 0x1D3226E, 0x33850C, 0x3CCD1B9, 0x30AB98D, 0x2AFCEA2, 0x2F52AC7, 0x2ADE1DD, 0xEB6843, 0x208790, 0x3C5C37, 0x34CDE6A, 0x536294, 0x6D000F, 0x187F4FA, 0x178196C, 0x10666C9, 0x311D702, 0x18FF035, 0x4546A9, 0x43F36E, +0x2167F4, 0x1CE9617, 0x1807631, 0x289F84, 0x71B296, 0x24EEDB0, 0x30E1595, 0x206DF9F, 0x241C1F, 0x603811, 0x1AC4D52, 0xC43E0B, 0x1DADD8D, 0x23DA6FB, 0x1A38C10, 0xB17523, 0x3FEE37, 0x8055C2, 0x16601, 0x63303A, 0x3B22591, 0x3F1A7B3, 0x2B6CB96, 0x2AC06AA, 0x131DE8B, 0x126F236, 0x38862D8, 0x69A290, 0x3A10A4, 0x1CE8A5, +0x2A87928, 0x36BF79B, 0x1DD78A8, 0xF0AF85, 0x30159E, 0x6600B4, 0x3AD2DCE, 0x3ED909, 0x770B48, 0x195785, 0xB0AB2A, 0x2183F6B, 0x157B87B, 0x23D8B2D, 0x34F0444, 0x15DB019, 0x2845BBB, 0x23ABCB5, 0x620CEA, 0x3274F7, 0xF7ED5F, 0x1942722, 0x2939183, 0x39BD16C, 0x2F43D2B, 0x3B58CBA, 0x1EF02D9, 0x11CE451, 0x19CFC1, 0x5D93E4, +0x28FC597, 0x3083464, 0x602E74, 0x19CD1DF, 0x1A46D07, 0x26C2ED2, 0x86CBA9, 0x3BB315F, 0x35372B, 0x7A9EBE, 0x1A6B314, 0x110DD05, 0x36646A0, 0x878825, 0x1E58B51, 0x138045F, 0x3D3B5B, 0x9C5723, 0x35E7D9, 0x446FFD, 0x36D3E76, 0x1508738, 0x2D71EA6, 0x72122F, 0x12E6E69, 0x3FF6C16, 0x27EE5A4, 0x127633, 0x1379E7, 0x22264A, +0x37EF7B3, 0x1D764E7, 0x869A3F, 0x23196EA, 0x3333323, 0xF51C0, 0x331616, 0x24FE4BC, 0x57B0E5, 0x5534C7, 0x2FE6FE4, 0x2DD3FF2, 0x33B65FA, 0x317E3F2, 0x199C7A1, 0x653618, 0x1CE4809, 0x2CF9952, 0x6B8933, 0x2A8719, 0x200F0C, 0x21ACCD, 0x2A7B171, 0x2C8ADD4, 0x1A58346, 0x2465844, 0x340343B, 0x167F17, 0x7A36B8, 0x769737, +0x19F266, 0x24B6FF3, 0x2E9A6D4, 0x3446B49, 0x1AC1DB1, 0x3053491, 0x8C176E, 0x37F15E8, 0x177724, 0x136198, 0x1EB7176, 0x1BE386D, 0x33191D0, 0x1199FDC, 0x36504A6, 0x2B5E6B6, 0x325FF25, 0x2B7C067, 0x14E811, 0x3286FC, 0x18E10A0, 0x100DCF2, 0x1647D12, 0x23B1FB8, 0x67B3F2, 0x32A4BAE, 0x30CB7DE, 0x288298D, 0x674FA7, 0x3B2C0, +0x1E24474, 0x28F514D, 0x35DAD1C, 0xAF6CBF, 0x216B4C8, 0x33F5C67, 0x29EE28C, 0x14F66BF, 0x421FB6, 0x202AF6, 0x226953E, 0xF70479, 0x17E03E5, 0x2392070, 0x2FFC05E, 0x362B99D, 0x28F3350, 0x1D1B48C, 0x7B721F, 0x54C31, 0x30E8025, 0x2B347E3, 0x3CB8810, 0x1C061D3, 0x20C2FBE, 0x37A6161, 0x3C0B9DC, 0x3A432ED, 0x60E1E3, 0x363924, +0x23A1A6A, 0x35447F0, 0x3D7B861, 0x1E619B8, 0x1FE2180, 0x1636446, 0x11BFDE, 0x375CF83, 0x2F79C0, 0x1C64C6, 0x341469D, 0x36952A5, 0x5D5598, 0x21D13E5, 0x1E871D8, 0xC8A8F4, 0x2596E2E, 0x348F6E5, 0x5BA634, 0x744F28, 0x232DA34, 0x66EF89, 0x3A12C7C, 0x24F15BA, 0x2E8CD15, 0x2B03146, 0x1EA8E2F, 0x2683E07, 0x556F3D, 0x1564FB, +0x22B483F, 0x23B3E45, 0x3BB55BE, 0x3C4A2B2, 0x1957E97, 0x13A9AE8, 0x6BAF4, 0x16E8ABF, 0x6D3F7E, 0x3D41E8, 0x36D8328, 0xD6E91A, 0x3921792, 0x2803815, 0x98EE4F, 0x1006E96, 0x130FA60, 0x89CE33, 0x65C49B, 0x394A21, 0x3D90785, 0x3A148AC, 0x3328F7F, 0x3711E8C, 0x965715, 0x3D556DC, 0x3785624, 0x35B6F86, 0x7BC3DC, 0x435DB9, +0x3D89C27, 0x2C5189A, 0x3535B83, 0x1049EE9, 0x553D74, 0x139CBE5, 0x3DA94E0, 0xF0F986, 0x25E727, 0x65C87D, 0x2809E2E, 0x1758661, 0x29B448A, 0x22DB9C0, 0x2AFAC34, 0x2046B8F, 0x21FC25F, 0x2FE5C10, 0x7DE6B7, 0x10705F, 0x1A2D44F, 0x249C60, 0x58539B, 0x2630694, 0x70F159, 0x23029AD, 0x1BB1BAC, 0x113592C, 0x7C74F2, 0x6E1BBD, +0x7790F9, 0x1AE0DAE, 0x33B9D81, 0x39E6B9D, 0x3690937, 0x3556332, 0x31C2FAB, 0x587424, 0x5B4CCB, 0x2E6394, 0x36849F0, 0x273F2A4, 0x1E2FDA3, 0x10C7878, 0x272D4B3, 0x24FD8BB, 0x2833AEE, 0x202EF80, 0x6C419F, 0x357CEC, 0x22F11A9, 0x3C49E13, 0x1BA44E5, 0x242D76A, 0x371883A, 0x172AB66, 0xB8948, 0x964DD6, 0x7808DF, 0x6CEF23, +0x1E551FC, 0x19E3E1F, 0x2B1D9ED, 0x248F788, 0x3D36D18, 0x1CFE6F7, 0x3776C56, 0x2236E6D, 0x5A0BA1, 0x3EC235, 0x83BBE0, 0x110218E, 0x308F50B, 0x16DB95C, 0x18CDA4F, 0x77FA29, 0x1DA19, 0x2C7457D, 0x21581A, 0x3E7BBA, 0x30D0635, 0x38CBEB8, 0x1B00F4F, 0x299D2AE, 0x3B5226, 0x3390AA1, 0x22A56F8, 0x2954EB8, 0x4174F0, 0x6BDF6B, +0x38545E2, 0x3A69F65, 0x7E0918, 0x294F632, 0x1E538A3, 0x2316148, 0x283C3BB, 0x3A05B65, 0x2A9E37, 0x64C587, 0x3E97E93, 0x22FA665, 0x280A291, 0xE2D121, 0x2E0E777, 0x35F6131, 0x11AFBEC, 0xE2A1DD, 0x13728E, 0xFCA8C, 0x1D067FA, 0xC2F728, 0x12F5603, 0x2E9B6E0, 0x102ECC4, 0x37F9AB3, 0x190B88B, 0xB8B496, 0x40F2F7, 0x5068AA, +0x22923FF, 0x1460A84, 0x2A10B02, 0x32E7FD5, 0x1965A8, 0x25188F5, 0x228401B, 0x829066, 0x67C39E, 0x2E735C, 0x3DC2DA4, 0xE1608F, 0x3B8FF2F, 0x3384C3A, 0x12BD0C6, 0x28E85E4, 0x182A1EE, 0x2CF9400, 0x5BF6ED, 0x932CE, 0x38CBFB8, 0x35060DE, 0x33E2814, 0x29E590B, 0x37BD793, 0x16CAA, 0x30062FA, 0x29344FC, 0x4E89E2, 0x542A38, +0x663E55, 0x24119FE, 0x3F66AB, 0x3A0BD96, 0xE4A1B, 0x1FC4060, 0x7DECCF, 0x1A6854A, 0x5158BF, 0x323470, 0x27480D5, 0x36C7013, 0x1BBDA44, 0x230E4BA, 0x2FFE5C9, 0xA79DBE, 0x84D37D, 0x22C38ED, 0x409A90, 0x73F2C4, 0x37E2DFF, 0xFD49A7, 0x14182E4, 0x3F8A6B9, 0x11D9DDF, 0x1F29F47, 0x49E18, 0x3F9D54E, 0x1534F9, 0x7A2C0B, +0x30FE7FB, 0x1DF4AC3, 0x1346CA, 0x25C3092, 0x350E19E, 0x36855C8, 0x2F60606, 0x33A3B79, 0x56381E, 0x8ACAE, 0xA0D20B, 0x5A0C95, 0x3C69C6B, 0x1A9F962, 0x2C3AC44, 0x116E549, 0x2364B92, 0xDCC56C, 0x623EDC, 0x20A9BA, 0x1F5B55D, 0x3724573, 0x161CE02, 0x25B6487, 0x2FF5376, 0x29EB56A, 0x10BAFBC, 0x16DCAE2, 0x23C44C, 0x321781, +0x350A489, 0x12CE34D, 0x6D0BD4, 0x2972313, 0x70B2CC, 0x2EAC504, 0x1BA16E3, 0x9ACDE1, 0x31F0B3, 0x1AF8EA, 0x3AFD62F, 0x8EFB27, 0x31789B5, 0x3599DAA, 0x3F9A69B, 0x2FD46E6, 0x341091E, 0x2E7FA69, 0x21E399, 0x476212, 0x4168DE, 0x1D81C29, 0x3ED94A, 0x1B0C9E7, 0x1408074, 0x2D6D016, 0x2F9979A, 0x2401F13, 0x5F7570, 0x656548, +0x35219C9, 0x1C1198B, 0x2D6F4DE, 0x98E6D4, 0x10F7BAF, 0x28110D2, 0x27CB88, 0x3CEF8F7, 0x2517, 0xF3C0D, 0x3374EEF, 0x157A00C, 0x984AF8, 0x3C7078D, 0x20AA355, 0x2614CB9, 0x10C63FE, 0x3D77A2D, 0x83474, 0x20C359, 0xD05268, 0xD911A6, 0x2520A8D, 0xDB08BA, 0x35D7D31, 0x7E1CA3, 0x1C6D1AD, 0x1C019E9, 0x421657, 0x4D072F, +0x1555E9E, 0x44817, 0xB1BC40, 0x2042CB6, 0x1697902, 0x9C1629, 0x2BDF30B, 0x3006C1B, 0x4C8C7E, 0x25110B, 0x39EAFF7, 0xB62068, 0x2701AFC, 0x1CE9A85, 0x34E81BF, 0x382176B, 0x547D4A, 0x372276C, 0x6CC36F, 0x47DCB0, 0x3670F41, 0x133C1A, 0x37FAB0B, 0x3245E4C, 0x417FE9, 0x3B2B5F8, 0x24EE5CF, 0xF8264A, 0x625B5C, 0x6BD35F, +0x1409E5E, 0x2A23CB6, 0x14E46A1, 0x172028C, 0x276703B, 0x2DC3DB4, 0x3F458D8, 0x1FBD22C, 0x7981D8, 0x67356A, 0x301ADAF, 0x69727E, 0x248DBA7, 0x189C667, 0x2BD6618, 0x1453D, 0x153940C, 0x1058F3B, 0x7A1E9, 0x25D67E, 0x3A80738, 0x1643F04, 0x1EEDA98, 0x2B5B4E0, 0x3C7418E, 0x334DAD9, 0x132D772, 0x32FAAED, 0x3112BE, 0x116112, +0x166FF07, 0x497808, 0x8EAF8B, 0x3419B01, 0x36DE326, 0x27009BE, 0x20890, 0x2CE73A1, 0x4D7803, 0x40DB29, 0x5602A5, 0x3A18394, 0x397ACE0, 0xB13065, 0x340D6E5, 0x30BC51C, 0x3CAC6E6, 0x108FB89, 0x52F227, 0x6D8BCA, 0x3B07F72, 0x20B17CC, 0x1833FA3, 0x3A9ED66, 0xC6D6E, 0x172966A, 0xE5C3E5, 0x2C00583, 0x7DD66C, 0x75FCF8, +0x32402B5, 0x31B6631, 0x317A8E6, 0x777CB2, 0x2DD5BED, 0x176AADC, 0x1097FB, 0xF8EABA, 0xDC360, 0x205EE9, 0x3C98498, 0x1599FE, 0x32D38CC, 0xE6F06D, 0x72C7A2, 0x14278E3, 0x1DDB55A, 0x294FEB2, 0x7D12EB, 0x4600F0, 0x2F14304, 0x2A35739, 0x274E8DC, 0x1E5889C, 0x3742104, 0x30C4D56, 0x82C8B6, 0x22C4457, 0x7B54E0, 0x27A117, +0x1C35E1B, 0x34FFFEA, 0x2CE7586, 0x173BDFE, 0x14866CF, 0x21D1AF4, 0x346A767, 0x2CAEA4C, 0x5CB96F, 0x4A73D7, 0xBE86AC, 0x72F372, 0x11AD2A0, 0x344279D, 0x373444B, 0x15B6AB5, 0x15E7A3, 0x2872FA6, 0x2769B5, 0x2BCCFB, 0x332F6A3, 0xD90DD9, 0x98454, 0x1571823, 0x1C53C00, 0x2E13215, 0x1F68558, 0x2CA1E36, 0x7ACB28, 0x7731D1, +0x1A0649, 0x19CE66F, 0x8AFD7B, 0x2F86D6B, 0x467321, 0x19D876, 0x28603B2, 0x316ECD2, 0x592B5F, 0x484C1C, 0x330B06C, 0x187AEFF, 0x1331096, 0x2095912, 0x22CE08E, 0x16A6D90, 0x17C3934, 0x331FF11, 0x276606, 0x3A835F, 0x806D69, 0x1F1E74F, 0x20074B3, 0x3AA7F40, 0x3839F4D, 0x11CBF2D, 0x3B32957, 0x25D1888, 0x41D767, 0x74D01B, +0x29F80CC, 0x862CD9, 0x38A02B4, 0x195680F, 0x3231E43, 0xC79E8D, 0x29A40A6, 0x2D6343A, 0x5CDF66, 0x388E38, 0xFF83A2, 0x12109EA, 0x2AA9212, 0x1B736A4, 0x3E745D9, 0x3541042, 0x3B935B2, 0x335D752, 0x14D6FB, 0x1BB7B9, 0x39B8505, 0x1A6473A, 0x301412C, 0x1E4F58D, 0x367A3A3, 0x2034678, 0x220ACC4, 0x1F88080, 0x35A3C5, 0x66ABCA, +0x1300021, 0x369095D, 0x3FC76B, 0x1B4E6E3, 0x26844A9, 0xCC8203, 0xD95134, 0x1591746, 0x18F290, 0x36490F, 0x2D3562E, 0x253E40B, 0x135CDA2, 0x2C395B5, 0x87E941, 0x37BB93D, 0x2811561, 0x3AA5814, 0x7F8108, 0x3F413, 0x37267EF, 0x2060A49, 0x1C5EDDF, 0xC6370D, 0x3305984, 0x239E725, 0x29297B9, 0x3E39E68, 0x6C5D9D, 0x274397, +0x95BAB0, 0x32D6733, 0x1E596D0, 0x3EDA819, 0x26E3BDA, 0x2859451, 0x14171E1, 0x3D0090A, 0x6292B2, 0x37C560, 0x18F1423, 0x25C75E1, 0x395BAE0, 0x17FE1CE, 0x2EE1151, 0x396A927, 0x21BC308, 0x1CD28CA, 0x634519, 0x178CDC, 0x244AACC, 0x1071219, 0x2B6EC90, 0x3072320, 0x2DDCFF7, 0x26DC161, 0x2837F65, 0x130428F, 0x76518A, 0x584D4, +0x1E9ACAB, 0x21C0E6D, 0x1CA0A82, 0xF41672, 0xEBD272, 0x2BC6032, 0x270D145, 0x2E1F749, 0x1298E4, 0x6072C8, 0xD36F26, 0x39546A7, 0x328AACA, 0x1F50E82, 0x2A2A36E, 0x1D29F15, 0x2D6AB93, 0x3C3B598, 0x2A977C, 0x4D60A, 0x26E4402, 0xF07A40, 0x3042004, 0xDE5C9E, 0x117134B, 0x20ACBD1, 0x2688562, 0x3C2D5FC, 0x7677EF, 0x32C0DA, +0x366DC2E, 0x339DC8A, 0xFF46E0, 0x12168FC, 0x30ECBC8, 0x3E8BF35, 0x21B1399, 0x217C891, 0x6CD072, 0x6E7E92, 0x1943BAE, 0x3242FE, 0x674E82, 0x4E6281, 0x12A6A9D, 0xBE9F91, 0x25FBB61, 0x32C4C4B, 0x43FA51, 0x4A100D, 0x110A692, 0x12D578F, 0x3F61AFA, 0x2A62C6A, 0x3937BE2, 0xA7EDB5, 0xA4DA35, 0xF86C37, 0x614FD8, 0x46F1D2, +0x2813F36, 0x28F5C7F, 0x1319C97, 0x1940EB8, 0xE918BF, 0xCE5FF5, 0x1E04A7, 0x139085E, 0x68BC89, 0x2B6E0F, 0x65895B, 0x158A0A0, 0x33651FB, 0x2BCCB7C, 0x36C9A97, 0x3713EBB, 0x198A03F, 0x2B00AE, 0x7AA90B, 0x6A748D, 0x1E83397, 0x2B32881, 0x26D7586, 0x615486, 0x1B69DF7, 0x20C9E75, 0x11FD921, 0x9DA9D1, 0x169349, 0x20791E, +0x2C70BC9, 0x13711DE, 0x3100F88, 0x35725C7, 0x21D3D25, 0x232C45D, 0x146399B, 0x1A8C2F8, 0xBF079, 0x66BD2C, 0x29E53CA, 0x20F1D39, 0x20A796C, 0xE1627A, 0x8A2607, 0x3C5C3FD, 0x139C770, 0x487CDF, 0x30ED41, 0x5A881A, 0x987A4F, 0xF33EA0, 0x24E50DA, 0x3ADD420, 0x2E2D27B, 0x2BBDC6F, 0x1784EBE, 0x14BD17B, 0x321FE4, 0x2166D, +0xCD2FC9, 0x3C676C9, 0x9A86C3, 0x37D81B, 0x3D6D150, 0x38C4FD2, 0x24F56F0, 0x1AC02B5, 0x1141BE, 0x4059E2, 0x2C6B505, 0x1DF0CFC, 0x26D0273, 0x35DF47D, 0x38E5070, 0x2FF1875, 0x3A2B3D1, 0x1DCD458, 0x68F020, 0x66EB37, 0x17A32AE, 0x99ECDB, 0x120AAD0, 0x3FC3368, 0x3935860, 0x38E7A07, 0x11F6884, 0x5DEB8A, 0x21175F, 0x26AE5F, +0x120EAF7, 0x1FA2A7A, 0x1C3A94, 0x3C4DFC, 0x3F81A9A, 0x2C6249E, 0x3AE9CE0, 0x1473F47, 0x2581FE, 0x7FE93C, 0x3777F7E, 0x1D77A2E, 0x136F729, 0x2D3E182, 0x23FF2D7, 0xEC8543, 0x2E9D3A0, 0x84BC8D, 0x562DA2, 0x3A0F65, 0x270EBC6, 0x26A8576, 0xB8FFA8, 0x5621EA, 0x1E11F84, 0x29A3808, 0xB1A8A2, 0x14F0FF8, 0x452432, 0x46F49D, +0x1B0D388, 0x3654AD9, 0x24F3B7F, 0x33558DC, 0x2D2BBCC, 0x115F1F2, 0x1DBBC2, 0x25C00D3, 0x4DB312, 0x4C6446, 0x1D7130C, 0x3AF1B1A, 0xB36FF5, 0x252DCB, 0x2AE534D, 0x8F7736, 0x340F6C, 0x1AA7C96, 0x619895, 0x1F6CA4, 0x259772A, 0x14F6D6F, 0x2C0F58, 0x38D032, 0x23A8CBA, 0x466709, 0xF635AF, 0x1FB953A, 0x24E5A2, 0x287BA2, +0x2D607F0, 0x3F6BA4A, 0x832208, 0x3026182, 0x3171873, 0xC0AF35, 0x94277, 0xC3BDDF, 0x44FD58, 0x6CF531, 0xB48CE4, 0x298D33D, 0x459E80, 0x95A0FB, 0xB48AA8, 0x21A659A, 0x1DD6C36, 0x1F441, 0x649F4C, 0x651479, 0x36E16DA, 0x162458A, 0x121D047, 0x7C4D10, 0xBF2155, 0x1368C23, 0x191D501, 0x18CFDF7, 0x411D03, 0x4F36B7, +0x27A89A4, 0x1ED45, 0x3770293, 0x3ED22C4, 0x1542A98, 0x2B95C3, 0x369BAB3, 0x332BE9C, 0x55D8A5, 0x5C7785, 0x16AFB79, 0x327B6F, 0xDA7F48, 0x3D20C6F, 0x669A64, 0x82D755, 0x3C43A50, 0x1F5C7C6, 0x1F405E, 0x2BC1B6, 0x17777D0, 0x1C9DB39, 0x2C573FB, 0x6DD5C0, 0x13268EA, 0x3621081, 0x3560366, 0x32D4BDE, 0x517370, 0x234D84, +0x1DAE49C, 0x35E7008, 0x313EF77, 0x83DAB5, 0x1E1970, 0x3345B07, 0x1091D79, 0x314612F, 0x3BA8D8, 0x275CD5, 0xD3796A, 0x12B5F4D, 0x260CE22, 0x1523F82, 0x2F35EB, 0x3CC9946, 0x37F7847, 0x2D43C98, 0x1B3A42, 0x119917, 0x20A3F82, 0x150372A, 0x37A5568, 0x8C04E0, 0x3FF4622, 0x36A7C79, 0x28E9831, 0x2546379, 0x6A552E, 0x18083B, +0x13B5455, 0x2356271, 0x2DD375F, 0x129CCD7, 0x33455F, 0x31D2599, 0x269C3FE, 0x3D810C3, 0x523EEA, 0x3BB011, 0x1D6EA7C, 0x1EBF07, 0x10D32E8, 0x14105D5, 0x17801EC, 0x383046C, 0x2583FAD, 0x3EFE748, 0x69B632, 0x1470B, 0x9BC5CC, 0x1E83A38, 0x147D301, 0x28EA450, 0x28EDE95, 0x127B09C, 0xE3CD7B, 0xF9D044, 0x1C1246, 0x44DAAF, +0x2FCD10, 0x341E833, 0x11C5EDB, 0x2B1B208, 0x114B0E5, 0x672528, 0x1AC9B56, 0x267507D, 0x518AB4, 0x2247FA, 0xF327A2, 0xE86B3, 0xC31970, 0x3BF5A53, 0x21B4ABE, 0xE4E35D, 0x4ADDF, 0x42FF98, 0x3AC74E, 0x7C382E, 0x2B8461C, 0xF7B7B1, 0x38E0A65, 0x3C59E21, 0x1E1AF37, 0x643AC8, 0x714D8C, 0x1AAC693, 0x4D4748, 0x5AE1BB, +0x29DF80, 0xE09807, 0x2C09642, 0x3890BC7, 0x3FA163E, 0x3D2B6E1, 0x218A9E4, 0xC2ABB3, 0x623126, 0x7BF961, 0xBFF70A, 0x14D30AB, 0x17A7A84, 0x1C3B916, 0x126EEDC, 0x353E70C, 0x8CEE53, 0x1B22044, 0x66B548, 0x79B000, 0x1710C1F, 0x1E3779C, 0x9E4B24, 0x257B9DA, 0x3539435, 0x2DCDFC9, 0x14606A7, 0x1B2E773, 0xC7BF1, 0x44871C, +0x9A046B, 0x75FB94, 0x202EFCB, 0x2CC8E1A, 0xCD90D1, 0xF35DEF, 0x2631174, 0x14D5598, 0x5445C5, 0x5B0D23, 0x33A7973, 0x2D77504, 0x37AA096, 0x3D7A1FE, 0x2147BE1, 0x169448A, 0x31386EF, 0x32529F7, 0x10658E, 0x55F5D3, 0xAD6BA2, 0x10AEBC, 0xF9C18B, 0x359485C, 0x2A31A9A, 0x3598C4B, 0x38FE783, 0x3F22E7E, 0x36C0A7, 0x1D031D, +0x113889E, 0x3785FD7, 0x870410, 0x316E281, 0x2477E36, 0xADA124, 0x3B879A9, 0x3C60623, 0x774B77, 0x5A6C0D, 0x272D7BE, 0x3E4A4D0, 0x3735517, 0x32F8D7, 0x2966F4A, 0x175210, 0x3FED9AE, 0xB7C14B, 0x38100F, 0x4489BE, 0x326899F, 0x2795EAA, 0x288900E, 0x3EFEE00, 0x3928A03, 0x253289D, 0x283FB04, 0x2713B3C, 0x5AE4A0, 0x34917E, +0x20CBBB3, 0x1EE34E1, 0x24D9D31, 0x8FD9BC, 0x71D64B, 0x1E48A7, 0x1418CD3, 0x37D23C5, 0x25C098, 0x3A960A, 0x1E440BB, 0xB25496, 0x3CE19A5, 0x1066C3D, 0x15E6659, 0x65B8EF, 0x2FDBA02, 0x28C2E79, 0x577A0F, 0x44176, 0x2013E6F, 0x38EFFD7, 0x21C177C, 0x3A45EE5, 0x1CE77A9, 0x2C7F309, 0x120EAA5, 0x16FFA50, 0x77D0B2, 0x8F1E5, +0xD613C8, 0x2E4F9FA, 0x1058A6E, 0x267DA8F, 0x149FFC2, 0x33B5388, 0xD735A2, 0x3374C03, 0x140F2E, 0x7ABC8E, 0x1D23EAF, 0x20EC5C4, 0x2B48D41, 0x12998ED, 0x2C7CD3D, 0x2EC9564, 0x24DDAC, 0x22BF87A, 0x75E73F, 0x511ADE, 0x1ABCA89, 0xD28C8, 0x17F938, 0x299962E, 0x1F6CBB0, 0x1EC800, 0x1CEC328, 0x1872459, 0x2838DE, 0x48AABA, +0x304D4E2, 0x1F69D03, 0x1D672AD, 0x38738D0, 0x3ECA222, 0x2E10A1C, 0x3033A16, 0x43A393, 0x106DD3, 0x1651B2, 0x133E136, 0x7B02AF, 0xA6979C, 0x32E95A5, 0x27B9473, 0x1B4809D, 0x11F724D, 0x45E049, 0x58C02F, 0x435C25, 0xCD9315, 0x331F32D, 0x25E68FC, 0x83D401, 0x3DDBD56, 0xB5D239, 0x29908AB, 0x8E08CB, 0x2F02B0, 0xAB833, +0xBB60DB, 0xD5282E, 0xF46FEC, 0x39B9685, 0x2EC2A7B, 0x224BAC5, 0x280F1BA, 0x77710A, 0x2342C2, 0x5B9A42, 0x143E056, 0x3DB1CED, 0x1419051, 0x2FDC7B4, 0x14E6018, 0x9794F8, 0x1F02125, 0x3056AC4, 0x6D7C37, 0x5150DB, 0x33A7FBF, 0x25B7911, 0x14286CD, 0x16FFA5B, 0x70500B, 0x3F3E500, 0x30F4C91, 0x156EC4C, 0x140BE5, 0x77CEA5, +0x3A973C6, 0x323C9C3, 0x786A75, 0x3DD1D92, 0x28D32AB, 0x17CD9E0, 0x260C525, 0x2EB9066, 0x3897AC, 0x2E5ECB, 0xF12433, 0x36BB343, 0xBA9592, 0xDB00F0, 0x269C43E, 0xE4317D, 0x392023, 0x14D207, 0x3A515A, 0x44CEBD, 0x21B0D76, 0x8A0E83, 0x2195B0, 0x8FE408, 0x1BE6890, 0x2A732E2, 0x3F2E402, 0x353BF4D, 0x2F8513, 0x3828C2, +0x1A8527D, 0x7DC5EF, 0x1F593E2, 0x2F1C917, 0x151DBF1, 0x15EC7D7, 0xAE5958, 0xA832DA, 0x59EBB4, 0x191B68, 0x19F9ADD, 0x3002DD1, 0x45CBEB, 0xCBE729, 0x3DCF893, 0x18B5769, 0x2EEACBA, 0x123E163, 0x239B6C, 0xC1405, 0x3741EA5, 0x7436FE, 0x2B7F773, 0xD6897E, 0x25676C7, 0xAE0C51, 0x2E78B86, 0x3B2DF74, 0x3B39C4, 0x690D8F, +0xDA10C2, 0x3C955A4, 0xA9863B, 0x207DC6E, 0x3832D78, 0x239835A, 0x2CC4D33, 0x3B592B9, 0x4F2A84, 0x457F88, 0x1479985, 0x275EB11, 0x3ADC70C, 0xBA5E16, 0x2B32C27, 0x2D36A5F, 0x215A6A, 0x266E0DF, 0x4AE918, 0x619CB1, 0x1484E40, 0x12B039D, 0x39644AE, 0x9DE70B, 0xAF00E7, 0x61A49A, 0x3A1FF6F, 0x381FD24, 0x3B5831, 0x3D4B81, +0x222B55C, 0x1DD7637, 0x66C3E8, 0x34A3946, 0x14E2AA1, 0x24B26B4, 0x46D0BF, 0x2403796, 0x265C1B, 0x3D2DA7, 0x1F21D63, 0x32F8C92, 0x1961AD, 0x79D4E4, 0x2E1899B, 0x3834B67, 0x3679A87, 0x874261, 0x4CE62B, 0x390B78, 0x3F1FC2F, 0x11E7533, 0x3DF1CF0, 0xECD7F8, 0x3AF91AD, 0x3FD7AEE, 0x2A14529, 0x249E3DB, 0x78C636, 0x7FBD19, +0x23D77DE, 0x39A981C, 0x2AEFD0D, 0x192877F, 0x3F6A41A, 0x3F9ADA2, 0x3C62E5A, 0x214C302, 0x1B27FD, 0x36EFC0, 0x1830854, 0x364FDCF, 0x2218A97, 0xCC9316, 0x26CB5BD, 0x265F452, 0x17995B, 0xDD88E1, 0x23D7C9, 0x36627F, 0x6D5EA4, 0x3B009B, 0x3D4E497, 0x36D4A95, 0x3022564, 0x194BF90, 0x21A8644, 0x3247E2E, 0x17C7CC, 0x15192D, +0x39EC6E2, 0xF1824, 0x3E8F069, 0x1A8EE63, 0x2ECC80B, 0x1E22FEE, 0x3AA65DC, 0x15806E0, 0x48FCA8, 0x46A8C7, 0x895FCC, 0x5971D7, 0xF100AA, 0x3BF9E3A, 0x1CE22CB, 0xB2C1A, 0x27010C1, 0x20EAD6A, 0x1D1DFF, 0x79C6A0, 0x1BF2518, 0x25F470E, 0x31EF297, 0x10B273E, 0xA02379, 0x459C9C, 0x22626CF, 0x33A46C5, 0x241935, 0x4481C2, +0x226DECA, 0xFA4F26, 0x137A87A, 0x331AF36, 0x21016B0, 0xFBDE36, 0x3BB8342, 0x25C65D9, 0x26EE3C, 0x4D1470, 0x31FEF52, 0x64CF3B, 0x1CA9C1B, 0x392C12A, 0x2EC1E05, 0x77332A, 0x1A688FC, 0x2A46E51, 0xF75FB, 0xB6373, 0x3D088AF, 0x3C51433, 0x3CAF082, 0x1AC2528, 0x17471A8, 0x1C7A0E, 0x16B3900, 0x8F09A3, 0x586B0D, 0x1752A1, +0x1770EA1, 0xCC6B3F, 0x30AA4ED, 0x2C14974, 0x2B43643, 0x2FC36BF, 0x346DC7B, 0x3BB0EB7, 0x536CB9, 0x1F4DCF, 0xBF57F0, 0x3AD7A1, 0x5A774, 0x3681A1C, 0x144928A, 0x203DBBC, 0x2A8828D, 0x20A0F07, 0x1336C9, 0x5E3347, 0x18FDAF2, 0x1695613, 0x25DCCF4, 0x1C30535, 0x3867F19, 0x256F799, 0x1E85EE, 0x10BA114, 0x789AF5, 0x794523, +0x226A018, 0xB30929, 0xBE4D9E, 0x39B77C9, 0x1FBE6C1, 0x755720, 0x723E73, 0x78F951, 0x11BEDA, 0x7706E9, 0x26C9059, 0x1D2BB07, 0xE074E, 0x10D5698, 0x424446, 0x29E2602, 0x1B0D9E3, 0x75E721, 0x7E0191, 0x68BAE0, 0x5DF659, 0x3266467, 0x32F3FCA, 0x3C1E305, 0x933F21, 0x2103CE0, 0x1ABAD5F, 0x36D45C2, 0x2F7EE, 0x39B4F, +0x1A4AE1B, 0x210DED9, 0x383FB18, 0x139039A, 0x695D5D, 0x3213EA6, 0x54A9DE, 0x10DCEF6, 0x33D37A, 0x1F1D39, 0x359FD14, 0x376F4A1, 0x1662DBB, 0x2A43862, 0x2283F63, 0x1DAEE39, 0x370EB94, 0x3AF662A, 0x57922A, 0x27F3DB, 0x3804B3, 0x32F3225, 0x1E77670, 0x7DB492, 0x2D73181, 0x197F88E, 0x30644B8, 0x267370A, 0x511D72, 0x560099, +0x3D82FE4, 0x3F13BD7, 0x37E5DED, 0x3EB3F0E, 0x2226DA6, 0xE180B5, 0x2EE98F6, 0x13D9BC, 0x76F746, 0x4A31EB, 0x3CFE28F, 0x3400317, 0x39CF579, 0x25E7F9C, 0x20B18AC, 0x3C9FA91, 0x6F0C30, 0x1C68271, 0x19AA73, 0x6795CE, 0x33700BA, 0x1EDCA71, 0x1554064, 0x316AF22, 0x114D93D, 0x25EF450, 0x3C22C7F, 0x2122F7E, 0x3850EA, 0x1BE5DB, +0x3CF082B, 0x3E0ED6D, 0x19F4FD3, 0xB04A97, 0x3C45776, 0x3ED16F2, 0x1B12092, 0x1C8AD77, 0x673B6E, 0x6EE6, 0x28D0C62, 0x1D3AB58, 0x284F051, 0x1AD54EA, 0x26E4B47, 0x3CFD0BC, 0x1E68DE3, 0x1E79137, 0x405648, 0x21761C, 0x31050FB, 0xDBF2AD, 0xDBB4FA, 0x113129A, 0x1D366F, 0x39C487, 0x4C4B74, 0xADB5B8, 0x2E67DF, 0x784496, +0x378B65F, 0x38C2E2B, 0x2D59D74, 0x29599F5, 0x1DF0E07, 0x1E2A320, 0x2A8F4B0, 0x365B769, 0x336262, 0x4F668D, 0x7B8470, 0x32206B6, 0x1559E57, 0x14C8451, 0x2BB1E21, 0x3A39AEE, 0x16CBBE0, 0x1FFB835, 0x306190, 0x1F8737, 0x3B1A0C7, 0xA3990F, 0x16314A8, 0x3FB1175, 0x3FFDDAC, 0x22C2FDF, 0x3813C35, 0x3DE78AB, 0x6E3C4C, 0x4B5340, +0x3D1F332, 0x1057F1E, 0x1F22DEC, 0xDB439B, 0x2E1A053, 0x33D7423, 0x112B8D7, 0x2799172, 0x552927, 0x5AC40E, 0x5E46C7, 0x3AF4F35, 0x3DEDFE1, 0x2B3D88A, 0x3150848, 0x27BB891, 0x19CDBBF, 0x273CE59, 0x74BDA8, 0x14BCEF, 0x331B9B3, 0x662ED0, 0x4D5365, 0xA6A384, 0x259F9AA, 0x37A71A8, 0x2864A57, 0x3E7B110, 0x27E855, 0x3BBC43, +0x1DE5341, 0x1F25A48, 0x2A2C72C, 0x201F690, 0x15498BF, 0x2552E3D, 0x201A34D, 0x738BBF, 0x343277, 0x1BB6EE, 0x3D3AFFC, 0x22F8939, 0x26F7B42, 0x37F5E55, 0x17A808D, 0x211FDA8, 0x14A66A4, 0x39A1A18, 0x290F1C, 0x1BF7AA, 0x860765, 0x439B94, 0x1B6BE6F, 0x1BEAADF, 0xA0B2AB, 0xBDA874, 0xBC3AD6, 0x1DD42EE, 0x7BEF6E, 0x17EA8, +0x39C9A7C, 0x1F1606, 0x3FAC888, 0x2A52B18, 0x3A13F8D, 0x176768A, 0x34A21EC, 0xFE2E98, 0x35CEC0, 0x747055, 0x1EAC410, 0x1A2FE94, 0x253E472, 0x23643CA, 0x3732378, 0x23A53F, 0x3AE0CDF, 0x22BB1A4, 0x55B22A, 0xAEC06, 0x16182EE, 0x12DF3C8, 0x1858AB, 0x35C2552, 0x1475405, 0x3521968, 0x3C6B079, 0x18657D9, 0x6A327F, 0x3F93F4, +0x170D546, 0x2B6F8B3, 0xEF28A2, 0x2C04C99, 0x13C2498, 0x369FF42, 0xC4A5AD, 0x212DA8, 0x2716B9, 0x76F29B, 0x2216249, 0x2B8F954, 0x21D2488, 0x199A5FA, 0x2CFD8E2, 0xCE50EE, 0x34E9B06, 0xA3FB03, 0x4F2FA1, 0x37C33E, 0x2FD1DD1, 0x1E5C7E6, 0x10678AE, 0x1AAEF0, 0xDAA7D0, 0x32A95EC, 0x10A66E5, 0x18183B5, 0x1F04D, 0x3A24C6, +0x3960F26, 0x6D9149, 0x1D93857, 0x3098237, 0x1C3A0DB, 0x3518F3D, 0x357567E, 0x1186DCB, 0x1D5973, 0x1D80E0, 0x1C8B09C, 0x31FC2AD, 0x1373352, 0x38E21C6, 0xD5E226, 0xBD32D6, 0x28918CD, 0x2B93CA1, 0x1F03E7, 0x418588, 0x3E1AFA2, 0x1CC4A76, 0x2C1C6EB, 0x9CC88B, 0x18DC3EF, 0xB23A6B, 0x3202F7, 0x22B229, 0x799BA, 0x13859F, +0x23C5ACB, 0x6F8CC1, 0x12B3099, 0x155543C, 0x2DF6019, 0x2A751B0, 0x16F42EF, 0x3519667, 0x459FA5, 0x9E5FA, 0x32958A3, 0x210F594, 0x245BBDD, 0x140F8D9, 0x24316B3, 0x23B98E1, 0x306024E, 0x1412289, 0x4AAAA5, 0x620EF5, 0xB8ECBC, 0x19CFEA9, 0x2258F23, 0xE581BD, 0x15A5A2, 0x28B167E, 0x2C6DD03, 0x38DDDF2, 0x6AEE46, 0x13A579, +0xBB8DE3, 0x2379578, 0x364BD87, 0x18D51B7, 0xEAB45A, 0x8609B1, 0x690918, 0x29F3B35, 0x53068A, 0x7BF38, 0x1282DE1, 0x15F6D45, 0x31DC0C7, 0xF7480A, 0xFFCF84, 0x2ECDFB8, 0x18E67DE, 0x15CD034, 0x402AED, 0x3702E2, 0x39B97C8, 0x13017DB, 0x2CB62E5, 0x3D89E0C, 0xC51B8D, 0x1D92D86, 0x34A942C, 0x37B157E, 0x617526, 0x2F35EE, +0x117973B, 0x39F63D, 0x2DA524D, 0x31B6A3B, 0x309AEEC, 0x3746B82, 0x1D382EB, 0x18C4A0C, 0x7A111A, 0x421707, 0x1DA88D9, 0x13D6CBB, 0x1B447CF, 0x26D8B42, 0x28875D3, 0x28FD982, 0x2CD83CA, 0xBDBB7C, 0x7BAEBC, 0x10F17A, 0x3F40626, 0x3960895, 0x3BE90D4, 0x159E209, 0xE34FE3, 0x355C618, 0x197046, 0x293D318, 0x731CA3, 0x7F906, +0x2657142, 0x104B69A, 0x3673443, 0x77C17, 0x21CE361, 0xDBA3E, 0x114B761, 0x2F133F3, 0x2B5F5D, 0x533723, 0x1BBCCB5, 0x1E13646, 0xE12BE8, 0x369420E, 0xDFD820, 0x29680F8, 0x1056576, 0x15CE965, 0x4E67E9, 0x6887A0, 0x2CE7343, 0x8074C1, 0x37477D6, 0xBE1526, 0x16C8E93, 0xB60BA, 0x3CA3B3E, 0x529069, 0xD4076, 0x5EB2A3, +0x276B27E, 0xD7DA95, 0x3DB49E9, 0x7E69D4, 0x114E49F, 0x2B5CC17, 0x102B354, 0x2247DE7, 0x15F7CA, 0x3BEDBE, 0x3F74FF, 0x260C4A9, 0x10EF3AE, 0x2531F82, 0x1A4C5B6, 0x3151DE2, 0x3CEA8CC, 0x3F20482, 0x88B1A, 0xA0770, 0x7C1937, 0x28CC49, 0x2DD5E83, 0x38FB6CB, 0x1C88F09, 0x122C051, 0x300FBF6, 0x3B16B14, 0x34B797, 0x66DB34, +0x3DC8CBF, 0x310F89D, 0x37834F4, 0x11B465D, 0x18CF95F, 0x9C51FD, 0x3204860, 0x1600FE0, 0x797897, 0x533A50, 0x9FD211, 0x8CF5A5, 0x3C70243, 0x30FFE93, 0x1D82B60, 0x21F4BF, 0x1E6BD72, 0x2984C1A, 0x4A7C34, 0x6949F4, 0x27ABCDC, 0x10895E0, 0x1325271, 0x191BDAF, 0x23C4D81, 0x145A9DE, 0xCC59A1, 0x1126951, 0x419A5E, 0x497CC1, +0x3E126F2, 0x178127D, 0x2CC491F, 0x36D34F, 0x347769E, 0x380C52E, 0x8CE59F, 0x2239EE4, 0x323C83, 0x42A0E1, 0x2E34E7E, 0x308FA4D, 0x2C04711, 0x1C28975, 0x34AA3A6, 0xDC8942, 0x22AA682, 0x632F27, 0x79F416, 0x2BB286, 0x606819, 0x2D0AF10, 0x391AEC1, 0x2E4B431, 0x2982741, 0x14126DB, 0x14BECB3, 0x2B8187A, 0x2790C, 0x32AA96, +0xD98EAA, 0x9AFF20, 0x19C0324, 0x1FE3BBE, 0x3136137, 0x2E37B39, 0x1943029, 0x128106E, 0x4D1DFE, 0x4836AC, 0xA02B8, 0x16B7E7B, 0x3041DAA, 0x3C985ED, 0x3A37F37, 0x1A5D498, 0x28919EC, 0x2536E16, 0xD063F, 0x65EF11, 0x28FFCB6, 0x9B15B, 0x3897574, 0x3A0ACEC, 0x83D1F, 0xBFC6B7, 0x3D25167, 0x17BC7F3, 0x228EE6, 0x713B18, +0x360C298, 0x30816C2, 0x11A3C7F, 0x1AB643F, 0x1614552, 0x2E58A8, 0x1740946, 0x24A12F4, 0x2B7BA6, 0x7BF924, 0x34C2D10, 0x3DEA766, 0x2315B91, 0x2DE741E, 0x540300, 0x151F15F, 0x2DDFE01, 0x31EE6C2, 0x171473, 0x66AC67, 0x2D2F652, 0x315C19C, 0x32856ED, 0x16B88DD, 0x217B34B, 0x3EF2C51, 0x349A1F5, 0x19D97EF, 0x13C63D, 0xE543C, +0x156FB5E, 0x394E113, 0x3203EBC, 0x2EA8990, 0x22B8668, 0x19CF89E, 0xECF665, 0x873C59, 0x1E2E9E, 0x322ADD, 0x3619F8E, 0x17E092F, 0x1B899CC, 0x3BCA0DF, 0x7F0F9E, 0x101179A, 0x22DE485, 0x164A42D, 0x723BFC, 0x1AA61C, 0x2499CD3, 0x1A8676B, 0x16B95DA, 0x133E866, 0x20DA995, 0x285FB86, 0x1A96873, 0x7C4200, 0x2C3D6E, 0x4961A2, +0x39D997B, 0x14CFCC5, 0x38612B7, 0x1D19DC2, 0x2725828, 0x105BE69, 0x2A5F9F3, 0x1DCE518, 0xC84BD, 0x4EC8CD, 0x15FB5C6, 0x139C03D, 0x1A06F32, 0x1D8A3F7, 0x3269A48, 0x18429B9, 0x3E3DE97, 0x387C67C, 0x6ADE87, 0x3BDE0E, 0x17C0CA1, 0x38A57E5, 0x2323EC4, 0x17D0D6D, 0x29BF4EF, 0xF9CC8F, 0x3E341F7, 0x2A186EF, 0x769BF8, 0x79987A, +0xB02022, 0x33EB70B, 0x3155C81, 0x187BC02, 0x29D17F6, 0x3B39F0C, 0x644471, 0x1446FED, 0x119BD8, 0x4317F0, 0x4D608E, 0x5F1775, 0xAE513A, 0x2FD1C42, 0x29CB36A, 0x19AD37D, 0x18B68CD, 0x7841D0, 0x1C1A38, 0x383575, 0x307A3FE, 0x154F23E, 0x2C3212E, 0x3F4832D, 0x13A004A, 0x15B715F, 0x3EF1F7C, 0x110AC54, 0x63758B, 0x1FF11C, +0x3937186, 0x352A761, 0xDDFC6F, 0x39F3EB8, 0x38F8171, 0x1502321, 0x20AE0D4, 0x9F5C90, 0x615EFE, 0x7AF024, 0x2CC559F, 0xBFDAC9, 0x11B91FC, 0x362A96E, 0x1D75865, 0x623C95, 0x2805D96, 0x32DA264, 0x65A1D8, 0x1E887, 0x26BCC3D, 0xC16B35, 0x23BA311, 0x2068D20, 0x108FF1F, 0x8CDD2B, 0x13CAE8E, 0xFAAFDC, 0x40CE5E, 0x51625D, +0x105739, 0x1E8F732, 0x1DC2884, 0x13246F4, 0x18A044D, 0x2460FBE, 0x12808A5, 0x32C4D61, 0x7F1DE7, 0x204FBA, 0x22E3CF8, 0x141909, 0x1E425F5, 0x2D1E467, 0x311497D, 0x1ECFFDF, 0x16464D2, 0x394913F, 0x541AD5, 0x354926, 0x2E994B0, 0x2371E7, 0x6C2838, 0x26F950C, 0x3D1629, 0x1CD818, 0x1A74E9B, 0x177C6A2, 0x2B9A9A, 0x3645C6, +0x1E3877B, 0x146B6B0, 0x1183D11, 0x397DDA3, 0x126EDF0, 0x14E60C2, 0x3714B43, 0x36A9F17, 0x7EA384, 0x1F6E62, 0x32343EE, 0x2731517, 0x9ACCE, 0x1746DAD, 0x372CF8B, 0xD60BD4, 0x321D9F4, 0xA1F11C, 0x2B7183, 0x4DDB3D, 0x263ECE2, 0x109B455, 0x76E900, 0x326341F, 0x45F103, 0x37F58CB, 0x2835964, 0xA28AF2, 0x4E737F, 0x34A351 }; + + +#endif \ No newline at end of file diff --git a/FourQ_ARM_NEON/README.txt b/FourQ_ARM_NEON/README.txt new file mode 100644 index 0000000..d2e92fa --- /dev/null +++ b/FourQ_ARM_NEON/README.txt @@ -0,0 +1,73 @@ + + FourQlib v3.0 (C Edition) + ========================= + Optimized implementation for 32-bit ARM using NEON + ================================================== + +1. CONTENTS: + -------- + +The "FourQ_ARM_NEON" folder contains: + +makefile - Makefile for compilation on ARM processors with NEON support using + GNU GCC or clang on Linux. +*.c, *.h - Library and header files. Public API for ECC scalar multiplication, key + exchange and signatures is located in FourQ_api.h +ARM/ - Folder with library files implementing low-level arithmetic for ARM. +tests/ - Test files. +README.txt - This readme file. + + +2. SUPPORTED PLATFORMS: + ------------------- + +This implementation is supported on 32-bit ARM platforms that contain the SIMD engine called NEON and run Linux. +For example, platforms with a NEON engine include many cores with the ARMv7 architecture. The implementation +has been optimized for ARM Cortex-A7, Cortex-A8, Cortex-A9 and Cortex-A15 based processors. + +See instructions below to choose an implementation option and compile on one of the supported platforms. + + +3. COMPLEMENTARY CRYPTO FUNCTIONS: + ------------------------------ + +Random values are generated with /dev/urandom. + +The library includes an implementation of SHA-512 which is used by default by SchnorrQ signatures. + +Users can experiment with different options by replacing functions in the folders "random" and "sha512" and +applying the corresponding changes to the settings in FourQ.h. + + +4. INSTRUCTIONS TO BUILD THE LIBRARY AND EXECUTE THE TESTS WITH GNU GCC OR CLANG: + --------------------------------------------------------------------------- + +To compile on Linux using the GNU GCC compiler or the clang compiler, execute the following command from the +command prompt: + +make CC=[gcc/clang] USE_ENDO=[TRUE/FALSE] EXTENDED_SET=[TRUE/FALSE] INTERLEAVE=[TRUE/FALSE] + MIX_ARM_NEON=[TRUE/FALSE] + +After compilation, run fp_tests, ecc_tests or crypto_tests. + +By default GNU GCC is used, as well as endomorphisms and extended settings. + +There are two special optimizations that can be exploited. INTERLEAVE improves performance on some platforms +by interleaving load/store instructions with other non-memory instructions. This optimization is recommended +for Cortex-A7, Cortex-A8 and Cortex-A9. MIX_ARM_NEON improves performance on some platforms by mixing ARM and +NEON instructions. This optimization is recommended for Cortex-A7, Cortex-A9 and Cortex-A15. + +By default, INTERLEAVE is turned off and MIX_ARM_NEON is turned on. + +For example, to compile using GNU GCC with the efficient endomorphisms on an ARM Cortex-A15 device, execute: + +make + +As another example, to compile using clang with the efficient endomorphisms on an ARM Cortex-A8 device, +execute: + +make CC=clang INTERLEAVE=TRUE MIX_ARM_NEON=FALSE + +By default EXTENDED_SET is enabled, which sets the following compilation flags: -fwrapv -fomit-frame-pointer +-funroll-loops. To disable this, use EXTENDED_SET=FALSE. +Users are encouraged to experiment with the different flag options. \ No newline at end of file diff --git a/FourQ_ARM_NEON/crypto_util.c b/FourQ_ARM_NEON/crypto_util.c new file mode 100644 index 0000000..bae9b8c --- /dev/null +++ b/FourQ_ARM_NEON/crypto_util.c @@ -0,0 +1,177 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: crypto utility functions +************************************************************************************/ + +#include "FourQ_internal.h" +#include "FourQ_params.h" +#include + +static digit_t mask4000 = (digit_t)1 << (sizeof(digit_t)*8 - 2); +static digit_t mask7fff = (digit_t)(-1) >> 1; + + +bool is_zero_ct(digit_t* a, unsigned int nwords) +{ // Check if multiprecision element is zero + digit_t x; + unsigned int i; + + x = a[0]; + for (i = 1; i < nwords; i++) { + x |= a[i]; + } + + return (bool)(1 ^ ((x | (0-x)) >> (RADIX-1))); +} + + +void encode(point_t P, unsigned char* Pencoded) +{ // Encode point P + // SECURITY NOTE: this function does not run in constant time. + digit_t temp1 = (P->x[1][NWORDS_FIELD-1] & mask4000) << 1; + digit_t temp2 = (P->x[0][NWORDS_FIELD-1] & mask4000) << 1; + + memmove(Pencoded, P->y, 32); + if (is_zero_ct((digit_t*)P->x, NWORDS_FIELD) == true) { + ((digit_t*)Pencoded)[2*NWORDS_FIELD-1] |= temp1; + } else { + ((digit_t*)Pencoded)[2*NWORDS_FIELD-1] |= temp2; + } +} + + +ECCRYPTO_STATUS decode(const unsigned char* Pencoded, point_t P) +{ // Decode point P + // SECURITY NOTE: this function does not run in constant time. + velm_t r, t, t0, t1, t2, t3, t4, VPx0, VPx1; + v2elm_t u, v, u2, v2, one = {0}; + digit_t sign_dec; + vpoint_extproj_t R; + vpoint_t VP; + unsigned int i, sign; + + one[0] = 1; + memmove((unsigned char*)P->y, Pencoded, 32); // Decoding y-coordinate and sign + sign = (unsigned int)(Pencoded[31] >> 7); + P->y[1][NWORDS_FIELD-1] &= mask7fff; + from_std_to_ext(P->y, VP->y); + + v2sqr1271(VP->y, u2); + v2mul1271(u2, (uint32_t*)&PARAMETER_d, v2); + v2sub1271(u2, one, u2); + v2add1271(v2, one, v2); + from_v2_to_v(u2, &u[0], &u[VWORDS_FIELD]); + from_v2_to_v(v2, &v[0], &v[VWORDS_FIELD]); + + vsqr1271(&v[0], t0); // t0 = v0^2 + vsqr1271(&v[VWORDS_FIELD], t1); // t1 = v1^2 + vadd1271(t0, t1, t0); // t0 = t0+t1 + vmul1271(&u[0], &v[0], t1); // t1 = u0*v0 + vmul1271(&u[VWORDS_FIELD], &v[VWORDS_FIELD], t2); // t2 = u1*v1 + vadd1271(t1, t2, t1); // t1 = t1+t2 + vmul1271(&u[VWORDS_FIELD], &v[0], t2); // t2 = u1*v0 + vmul1271(&u[0], &v[VWORDS_FIELD], t3); // t3 = u0*v1 + vsub1271(t2, t3, t2); // t2 = t2-t3 + vsqr1271(t1, t3); // t3 = t1^2 + vsqr1271(t2, t4); // t4 = t2^2 + vadd1271(t3, t4, t3); // t3 = t3+t4 + for (i = 0; i < 125; i++) { // t3 = t3^(2^125) + vsqr1271(t3, t3); + } + + vadd1271(t1, t3, t); // t = t1+t3 + vmod1271(t, t); + if (is_zero_ct(t, VWORDS_FIELD) == true) { + vsub1271(t1, t3, t); // t = t1-t3 + } + vadd1271(t, t, t); // t = 2*t + vsqr1271(t0, t3); // t3 = t0^2 + vmul1271(t0, t3, t3); // t3 = t3*t0 + vmul1271(t, t3, t3); // t3 = t3*t + vexp1251(t3, r); // r = t3^(2^125-1) + vmul1271(t0, r, t3); // t3 = t0*r + vmul1271(t, t3, VPx0); // x0 = t*t3 + vsqr1271(VPx0, t1); + vmul1271(t0, t1, t1); // t1 = t0*x0^2 + vdiv1271(VPx0); // x0 = x0/2 + vmul1271(t2, t3, VPx1); // x1 = t3*t2 + + vsub1271(t, t1, t); + vmod1271(t, t); + if (is_zero_ct(t, VWORDS_FIELD) == false) { // If t != t1 then swap x0 and x1 + memmove((unsigned char*)t0, (unsigned char*)VPx0, 20); + memmove((unsigned char*)VPx0, (unsigned char*)VPx1, 20); + memmove((unsigned char*)VPx1, t0, 20); + } + + from_v_to_v2(VPx0, VPx1, VP->x); + v2mod1271(VP->x, VP->x); + if (is_zero_ct(VP->x, VWORDS_FIELD) == true) { + sign_dec = VP->x[2*VWORDS_FIELD-1] >> 22; + } else { + sign_dec = VP->x[2*VWORDS_FIELD-2] >> 22; + } + + if (sign != (unsigned int)sign_dec) { // If sign of x-coordinate decoded != input sign bit, then negate x-coordinate + v2neg1271(VP->x); + } + + v2mod1271(VP->x, R->x); + v2mod1271(VP->y, R->y); + if (ecc_point_validate(R) == false) { + v2neg1271_felm(R->x); + if (ecc_point_validate(R) == false) { // Final point validation + return ECCRYPTO_ERROR; + } + } + + v2mod1271(R->x, R->x); + from_ext_to_std(R->x, P->x); + from_ext_to_std(R->y, P->y); + + return ECCRYPTO_SUCCESS; +} + + +void to_Montgomery(const digit_t* ma, digit_t* c) +{ // Converting to Montgomery representation + + Montgomery_multiply_mod_order(ma, (digit_t*)&Montgomery_Rprime, c); +} + + +void from_Montgomery(const digit_t* a, digit_t* mc) +{ // Converting from Montgomery to standard representation + digit_t one[NWORDS_ORDER] = {0}; + one[0] = 1; + + Montgomery_multiply_mod_order(a, one, mc); +} + + +const char* FourQ_get_error_message(ECCRYPTO_STATUS Status) +{ // Output error/success message for a given ECCRYPTO_STATUS + struct error_mapping { + unsigned int index; + char* string; + } mapping[ECCRYPTO_STATUS_TYPE_SIZE] = { + {ECCRYPTO_ERROR, ECCRYPTO_MSG_ERROR}, + {ECCRYPTO_SUCCESS, ECCRYPTO_MSG_SUCCESS}, + {ECCRYPTO_ERROR_DURING_TEST, ECCRYPTO_MSG_ERROR_DURING_TEST}, + {ECCRYPTO_ERROR_UNKNOWN, ECCRYPTO_MSG_ERROR_UNKNOWN}, + {ECCRYPTO_ERROR_NOT_IMPLEMENTED, ECCRYPTO_MSG_ERROR_NOT_IMPLEMENTED}, + {ECCRYPTO_ERROR_NO_MEMORY, ECCRYPTO_MSG_ERROR_NO_MEMORY}, + {ECCRYPTO_ERROR_INVALID_PARAMETER, ECCRYPTO_MSG_ERROR_INVALID_PARAMETER}, + {ECCRYPTO_ERROR_SHARED_KEY, ECCRYPTO_MSG_ERROR_SHARED_KEY}, + {ECCRYPTO_ERROR_SIGNATURE_VERIFICATION, ECCRYPTO_MSG_ERROR_SIGNATURE_VERIFICATION}, + }; + + if (Status >= ECCRYPTO_STATUS_TYPE_SIZE || mapping[Status].string == NULL) { + return "Unrecognized ECCRYPTO_STATUS"; + } else { + return mapping[Status].string; + } +}; \ No newline at end of file diff --git a/FourQ_ARM_NEON/eccp2.c b/FourQ_ARM_NEON/eccp2.c new file mode 100644 index 0000000..af47aef --- /dev/null +++ b/FourQ_ARM_NEON/eccp2.c @@ -0,0 +1,1117 @@ +/**************************************************************************************** +* 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) 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" +#include "FourQ_params.h" +#include "FourQ_tables.h" +#include "ARM/fp_arm.h" +#include + + +/***********************************************/ +/************* GF(p^2) FUNCTIONS ***************/ + +void fp2copy1271(f2elm_t a, f2elm_t c) +{ // Copy of a GF(p^2) element, c = a + fpcopy1271(a[0], c[0]); + fpcopy1271(a[1], c[1]); +} + + +void v2copy1271(v2elm_t a, v2elm_t c) +{ // Copy vectorized GF(p^2) element, c <- a + + c[0] = a[0]; c[1] = a[1]; c[2] = a[2]; c[3] = a[3]; c[4] = a[4]; + c[5] = a[5]; c[6] = a[6]; c[7] = a[7]; c[8] = a[8]; c[9] = a[9]; +} + + +void v2zero1271(v2elm_t a) +{ // Zeroing vectorized GF(p^2) element, a = 0 + + a[0] = 0; a[1] = 0; a[2] = 0; a[3] = 0; a[4] = 0; + a[5] = 0; a[6] = 0; a[7] = 0; a[8] = 0; a[9] = 0; +} + + +__inline void v2add1271(v2elm_t a, v2elm_t b, v2elm_t c) +{ // Vectorized GF(p^2) addition, c = a+b in GF((2^127-1)^2) + v2add1271_a((uint32_t*)a, (uint32_t*)b, (uint32_t*)c); +} + + +__inline void v2sub1271(v2elm_t a, v2elm_t b, v2elm_t c) +{ // Vectorized GF(p^2) subtraction, c = a-b in GF((2^127-1)^2) + v2sub1271_a((uint32_t*)a, (uint32_t*)b, (uint32_t*)c); +} + + +void v2dblsub1271(v2elm_t a, v2elm_t b, v2elm_t c) +{ // Vectorized GF(p^2) addition followed by subtraction, c = 2a-b in GF((2^127-1)^2) + v2dblsub1271_a((uint32_t*)a, (uint32_t*)b, (uint32_t*)c); +} + + +void v2addsub1271(v2elm_t a, v2elm_t b, v2elm_t c, v2elm_t d) +{ // Vectorized GF(p^2) addition and subtraction, c = a+b, d = a-b in GF((2^127-1)^2) + v2addsub1271_a((uint32_t*)a, (uint32_t*)b, (uint32_t*)c, (uint32_t*)d); +} + + +void v2neg1271(v2elm_t a) +{ // Vectorized GF(p^2) negation + // Representation: 23/23/26/26/26/26/26/26/26/26-bit + + a[0] = mask_26 - a[0]; + a[1] = mask_26 - a[1]; + a[2] = mask_26 - a[2]; + a[3] = mask_26 - a[3]; + a[4] = mask_26 - a[4]; + a[5] = mask_26 - a[5]; + a[6] = mask_26 - a[6]; + a[7] = mask_26 - a[7]; + a[8] = mask_23 - a[8]; + a[9] = mask_23 - a[9]; +} + + +void v2mul1271(v2elm_t a, v2elm_t b, v2elm_t c) +{ // Vectorized GF(p^2) multiplication, c = a*b in GF((2^127-1)^2) + v2mul1271_a((uint32_t*)a, (uint32_t*)b, (uint32_t*)c); +} + + +void v2sqr1271(v2elm_t a, v2elm_t c) +{ // Vectorized GF(p^2) squaring, c = a^2 in GF((2^127-1)^2) + v2sqr1271_a((uint32_t*)a, (uint32_t*)c); +} + + +#if defined(MIX_ARM_NEON) + +void v2muladd1271(v2elm_t a, v2elm_t b, v2elm_t c, v2elm_t d, v2elm_t e, v2elm_t f) +{ // Vectorized GF(p^2) multiplication/addition in GF((2^127-1)^2) + v2muladd1271_a((uint32_t*)a, (uint32_t*)b, (uint32_t*)c, (uint32_t*)d, (uint32_t*)e, (uint32_t*)f); +} + + +void v2mulsub1271(v2elm_t a, v2elm_t b, v2elm_t c, v2elm_t d, v2elm_t e, v2elm_t f) +{ // Vectorized GF(p^2) multiplication/subtraction in GF((2^127-1)^2) + v2mulsub1271_a((uint32_t*)a, (uint32_t*)b, (uint32_t*)c, (uint32_t*)d, (uint32_t*)e, (uint32_t*)f); +} + +void v2muladdsub1271(v2elm_t a, v2elm_t b, v2elm_t c, v2elm_t d, v2elm_t e, v2elm_t f, v2elm_t g) +{ // Vectorized GF(p^2) multiplication/addition/subtraction in GF((2^127-1)^2) + v2muladdsub1271_a((uint32_t*)a, (uint32_t*)b, (uint32_t*)c, (uint32_t*)d, (uint32_t*)e, (uint32_t*)f, (uint32_t*)g); +} + + +void v2muldblsub1271(v2elm_t a, v2elm_t b, v2elm_t c, v2elm_t d, v2elm_t e, v2elm_t f) +{ // Vectorized GF(p^2) multiplication/addition/subtraction in GF((2^127-1)^2) + v2muldblsub1271_a((uint32_t*)a, (uint32_t*)b, (uint32_t*)c, (uint32_t*)d, (uint32_t*)e, (uint32_t*)f); +} + + +void v2sqradd1271(v2elm_t a, v2elm_t c, v2elm_t d, v2elm_t e, v2elm_t f) +{ // Vectorized GF(p^2) squaring/addition in GF((2^127-1)^2) + v2sqradd1271_a((uint32_t*)a, (uint32_t*)c, (uint32_t*)d, (uint32_t*)e, (uint32_t*)f); +} + + +void v2sqraddsub1271(v2elm_t a, v2elm_t c, v2elm_t d, v2elm_t e, v2elm_t f, v2elm_t g) +{ // Vectorized GF(p^2) squaring/addition/subtraction in GF((2^127-1)^2) + v2sqraddsub1271_a((uint32_t*)a, (uint32_t*)c, (uint32_t*)d, (uint32_t*)e, (uint32_t*)f, (uint32_t*)g); +} + +#endif + + +void v2inv1271(v2elm_t a) +{ // Vectorized GF(p^2) inversion, a = (a0-i*a1)/(a0^2+a1^2) + velm_t a0, a1, t0, t1; + + from_v2_to_v(a, a0, a1); + vsqr1271(a0, t0); // t0 = a0^2 + vsqr1271(a1, t1); // t1 = a1^2 + vadd1271(t0, t1, t0); // t0 = a0^2+a1^2 + vinv1271(t0); // t0 = (a0^2+a1^2)^-1 + vneg1271(a1); // a = a0-i*a1 + vmul1271(a0, t0, a0); + vmul1271(a1, t0, a1); // a = (a0-i*a1)*(a0^2+a1^2)^-1 + from_v_to_v2(a0, a1, a); +} + + +__inline void clear_words(void* mem, unsigned int nwords) +{ // Clear integer-size digits from memory. "nwords" indicates the number of integer digits to be zeroed. + // This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing. + // It has been tested with MSVS 2013 and GNU GCC 4.6.3, 4.7.3, 4.8.2 and 4.8.4. Users are responsible for verifying correctness with different compilers. + // See "Compliant Solution (C99)" at https://www.securecoding.cert.org/confluence/display/c/MSC06-C.+Beware+of+compiler+optimizations + unsigned int i; + volatile unsigned int *v = mem; + + for (i = 0; i < nwords; i++) + v[i] = 0; +} + + +#if (USE_ENDO == true) + +// Fixed GF(p^2) constants for the endomorphisms +static v2elm_t ctau1 = {0x3ce74c3, 0x12, 0x3355f3a, 0x0, 0x120c74d, 0xc000, 0xb0ebeb, 0x0, 0x1964de, 0x0}; +static v2elm_t ctaudual1 = {0x2cdf034, 0x11, 0x2a9b677, 0x0, 0x6529ec, 0x3ff4000, 0x3ac8c16, 0x3ffffff, 0x4aa740, 0x7fffff}; +static v2elm_t cphi0 = {0x3fffff7,0x366f81a, 0x3ffffff, 0x154db3b, 0x5fff, 0x3294f6, 0x0, 0x1d6460b, 0x0, 0x2553a0}; +static v2elm_t cphi1 = {0x7, 0x28296f9, 0x0, 0x3643a78, 0x5000, 0x22cf334, 0x0, 0x2831431, 0x0, 0x62c8ca}; +static v2elm_t cphi2 = {0x15, 0x31df391, 0x0, 0x32dc553, 0xf000, 0x1c982c2, 0x0, 0xadb26d, 0x0, 0x78df26}; +static v2elm_t cphi3 = {0x3,0x3962ea4, 0x0, 0x10115e9, 0x2000, 0x342a924, 0x0, 0x12475d8, 0x0, 0x5084c6}; +static v2elm_t cphi4 = {0x3, 0x2ec6855, 0x0, 0x263248e, 0x3000, 0x2ea4a10, 0x0, 0x15e9e58, 0x0, 0x124404}; +static v2elm_t cphi5 = {0xf, 0x1052df3, 0x0, 0x2c874f1, 0xa000, 0x59e669, 0x0, 0x1062863, 0x0, 0x459195}; +static v2elm_t cphi6 = {0x18, 0x20a5be7, 0x0, 0x190e9e2, 0x12000, 0xb3ccd3, 0x0, 0x20c50c6, 0x0, 0xb232a}; +static v2elm_t cphi7 = {0x23, 0x348781a, 0x0, 0x60c0d7, 0x18000, 0x2a1a66c, 0x0, 0x72678b, 0x0, 0x3963bc}; +static v2elm_t cphi8 = {0xf0, 0x35d0ef0, 0x0, 0x94560a, 0xaa000, 0xbe544e, 0x0, 0x2180c5b, 0x0, 0x1f529f}; +static v2elm_t cphi9 = {0xbef, 0x36e2505, 0x0, 0x34f9225, 0x870000, 0x375b014, 0x0, 0x273f800, 0x0, 0xfd52e}; +static v2elm_t cpsi1 = {0x3e346ef, 0x13a, 0x1fd1d9, 0x0, 0xa02edf, 0xde000, 0x26a0f55, 0x0, 0x2af99e, 0x0}; +static v2elm_t cpsi2 = {0x143, 0x203f372, 0x0, 0x37addc3, 0xe4000, 0x1f034c7, 0x0, 0x1ee66a0, 0x0, 0x21b8d0}; +static v2elm_t cpsi3 = {0x9, 0x1e73a61, 0x0, 0x39aaf9d, 0x6000, 0x29063a6, 0x0, 0x5875f5, 0x0, 0x4cb26f}; +static v2elm_t cpsi4 = {0x3fffff6, 0x218c59e, 0x3ffffff, 0x655062, 0x3ff9fff, 0x16f9c59, 0x3ffffff, 0x3a78a0a, 0x7fffff, 0x334d90}; + +// Fixed integer constants for the decomposition +// Close "offset" vector +static uint64_t c1 = {0x72482C5251A4559C}; +static uint64_t c2 = {0x59F95B0ADD276F6C}; +static uint64_t c3 = {0x7DD2D17C4625FA78}; +static uint64_t c4 = {0x6BC57DEF56CE8877}; +// Optimal basis vectors +static uint64_t b11 = {0x0906FF27E0A0A196}; +static uint64_t b12 = {0x1363E862C22A2DA0}; +static uint64_t b13 = {0x07426031ECC8030F}; +static uint64_t b14 = {0x084F739986B9E651}; +static uint64_t b21 = {0x1D495BEA84FCC2D4}; +static uint64_t b24 = {0x25DBC5BC8DD167D0}; +static uint64_t b31 = {0x17ABAD1D231F0302}; +static uint64_t b32 = {0x02C4211AE388DA51}; +static uint64_t b33 = {0x2E4D21C98927C49F}; +static uint64_t b34 = {0x0A9E6F44C02ECD97}; +static uint64_t b41 = {0x136E340A9108C83F}; +static uint64_t b42 = {0x3122DF2DC3E0FF32}; +static uint64_t b43 = {0x068A49F02AA8A9B5}; +static uint64_t b44 = {0x18D5087896DE0AEA}; +// Precomputed integers for fast-Babai rounding +static uint64_t ell1[4] = {0x259686E09D1A7D4F, 0xF75682ACE6A6BD66, 0xFC5BB5C5EA2BE5DF, 0x07}; +static uint64_t ell2[4] = {0xD1BA1D84DD627AFB, 0x2BD235580F468D8D, 0x8FD4B04CAA6C0F8A, 0x03}; +static uint64_t ell3[4] = {0x9B291A33678C203C, 0xC42BD6C965DCA902, 0xD038BF8D0BFFBAF6, 0x00}; +static uint64_t ell4[4] = {0x12E5666B77E7FDC0, 0x81CBDC3714983D82, 0x1B073877A22D8410, 0x03}; + + +/***********************************************/ +/********** CURVE/SCALAR FUNCTIONS ***********/ + +static __inline void ecc_tau(vpoint_extproj_t P) +{ // Apply tau mapping to a point, P = tau(P) + // Input: P = (X1:Y1:Z1) on E in twisted Edwards coordinates + // Output: P = (Xfinal:Yfinal:Zfinal) on Ehat in twisted Edwards coordinates + v2elm_t t0, t1; + + v2sqr1271(P->x, t0); // t0 = X1^2 + v2sqr1271(P->y, t1); // t1 = Y1^2 + v2mul1271(P->x, P->y, P->x); // X = X1*Y1 + v2sqr1271(P->z, P->y); // Y = Z1^2 + v2addsub1271(t1, t0, P->z, t0); // Z = X1^2+Y1^2, t0 = Y1^2-X1^2 + v2mul1271(P->x, t0, P->x); // X = X1*Y1*(Y1^2-X1^2) + v2dblsub1271(P->y, t0, P->y); // Y = 2*Z1^2-(Y1^2-X1^2) + v2mul1271(P->x, ctau1, P->x); // Xfinal = X*ctau1 + v2mul1271(P->y, P->z, P->y); // Yfinal = Y*Z + v2mul1271(P->z, t0, P->z); // Zfinal = t0*Z +} + + +static __inline void ecc_tau_dual(vpoint_extproj_t P) +{ // Apply tau_dual mapping to a point, P = tau_dual(P) + // Input: P = (X1:Y1:Z1) on Ehat in twisted Edwards coordinates + // Output: P = (Xfinal,Yfinal,Zfinal,Tafinal,Tbfinal) on E, where Tfinal = Tafinal*Tbfinal, + // corresponding to (Xfinal:Yfinal:Zfinal:Tfinal) in extended twisted Edwards coordinates + v2elm_t t0, t1, t2; + + v2sqr1271(P->x, t0); // t0 = X1^2 + v2sqr1271(P->z, t2); // t2 = Z1^2 + v2sqr1271(P->y, t1); // t1 = Y1^2 + v2addsub1271(t1, t0, t0, P->ta); // t0 = X1^2+Y1^2, Tafinal = Y1^2-X1^2 + v2mul1271(P->x, P->y, P->x); // X = X1*Y1 + v2dblsub1271(t2, P->ta, P->z); // Z = 2*Z1^2-(Y1^2-X1^2) + v2mul1271(P->x, ctaudual1, P->tb); // Tbfinal = ctaudual1*X1*X1 + v2mul1271(P->z, P->ta, P->y); // Yfinal = Z*Tafinal + v2mul1271(P->tb, t0, P->x); // Xfinal = Tbfinal*t0 + v2mul1271(P->z, t0, P->z); // Zfinal = Z*t0 +} + + +static __inline void ecc_delphidel(vpoint_extproj_t P) +{ // Apply delta_phi_delta mapping to a point, P = delta(phi_W(delta_inv(P))), + // where phi_W is the endomorphism on the Weierstrass form. + // Input: P = (X1:Y1:Z1) on Ehat in twisted Edwards coordinates + // Output: P = (Xfinal:Yfinal:Zfinal) on Ehat in twisted Edwards coordinates + v2elm_t t0, t1, t2, t3, t4, t5, t6; + + v2sqr1271(P->z, t4); // t4 = Z1^2 + v2mul1271(P->y, P->z, t3); // t3 = Y1*Z1 + v2mul1271(t4, cphi4, t0); // t0 = cphi4*t4 + v2sqr1271(P->y, t2); // t2 = Y1^2 + v2add1271(t0, t2, t0); // t0 = t0+t2 + v2mul1271(t3, cphi3, t1); // t1 = cphi3*t3 + v2addsub1271(t0, t1, t0, t5); // t0 = t0+t1, t5 = t0-t1 + v2mul1271(t0, P->z, t0); // t0 = t0*Z1 + v2mul1271(t3, cphi1, t1); // t1 = cphi1*t3 + v2mul1271(t0, t5, t0); // t0 = t0*t5 + v2mul1271(t4, cphi2, t5); // t5 = cphi2*t4 + v2add1271(t2, t5, t5); // t5 = t2+t5 + v2addsub1271(t1, t5, t1, t6); // t1 = t1+t5, t6 = t1-t5 + v2mul1271(t6, t1, t6); // t6 = t1*t6 + v2mul1271(t6, cphi0, t6); // t6 = cphi0*t6 + v2mul1271(P->x, t6, P->x); // X = X1*t6 + v2sqr1271(t2, t6); // t6 = t2^2 + v2sqr1271(t3, t2); // t2 = t3^2 + v2sqr1271(t4, t3); // t3 = t4^2 + v2mul1271(t2, cphi8, t1); // t1 = cphi8*t2 + v2mul1271(t3, cphi9, t5); // t5 = cphi9*t3 + v2add1271(t1, t6, t1); // t1 = t1+t6 + v2mul1271(t2, cphi6, t2); // t2 = cphi6*t2 + v2mul1271(t3, cphi7, t3); // t3 = cphi7*t3 + v2add1271(t1, t5, t1); // t1 = t1+t5 + v2add1271(t2, t3, t2); // t2 = t2+t3 + v2mul1271(t1, P->y, t1); // t1 = Y1*t1 + v2add1271(t6, t2, P->y); // Y = t6+t2 + v2mul1271(P->x, t1, P->x); // X = X*t1 + v2mul1271(P->y, cphi5, P->y); // Y = cphi5*Y + v2neg1271_felm(P->x); // Xfinal = X^p + v2mul1271(P->y, P->z, P->y); // Y = Y*Z1 + v2mul1271(t0, t1, P->z); // Z = t0*t1 + v2mul1271(P->y, t0, P->y); // Y = Y*t0 + v2neg1271_felm(P->z); // Zfinal = Z^p + v2neg1271_felm(P->y); // Yfinal = Y^p +} + + +static __inline void ecc_delpsidel(vpoint_extproj_t P) +{ // Apply delta_psi_delta mapping to a point, P = delta(psi_W(delta_inv(P))), + // where psi_W is the endomorphism on the Weierstrass form. + // Input: P = (X1:Y1:Z1) on Ehat in twisted Edwards coordinates + // Output: P = (Xfinal:Yfinal:Zfinal) on Ehat in twisted Edwards coordinates + v2elm_t t0, t1, t2; + + v2neg1271_felm(P->x); // X = X1^p + v2neg1271_felm(P->z); // Z = Z1^p + v2neg1271_felm(P->y); // Y = Y1^p + v2sqr1271(P->z, t2); // t2 = Z1^p^2 + v2sqr1271(P->x, t0); // t0 = X1^p^2 + v2mul1271(P->x, t2, P->x); // X = X1^p*Z1^p^2 + v2mul1271(t2, cpsi2, P->z); // Z = cpsi2*Z1^p^2 + v2mul1271(t2, cpsi3, t1); // t1 = cpsi3*Z1^p^2 + v2mul1271(t2, cpsi4, t2); // t2 = cpsi4*Z1^p^2 + v2add1271(t0, P->z, P->z); // Z = X1^p^2 + cpsi2*Z1^p^2 + v2add1271(t0, t2, t2); // t2 = X1^p^2 + cpsi4*Z1^p^2 + v2add1271(t0, t1, t1); // t1 = X1^p^2 + cpsi3*Z1^p^2 + v2neg1271(t2); // t2 = -(X1^p^2 + cpsi4*Z1^p^2) + v2mul1271(P->z, P->y, P->z); // Z = Y1^p*(X1^p^2 + cpsi2*Z1^p^2) + v2mul1271(P->x, t2, P->x); // X = -X1^p*Z1^p^2*(X1^p^2 + cpsi4*Z1^p^2) + v2mul1271(t1, P->z, P->y); // Yfinal = t1*Z + v2mul1271(P->x, cpsi1, P->x); // Xfinal = cpsi1*X + v2mul1271(P->z, t2, P->z); // Zfinal = Z*t2 +} + + +void ecc_psi(vpoint_extproj_t P) +{ // Apply psi mapping to a point, P = psi(P) + // Input: P = (X1:Y1:Z1) on E in twisted Edwards coordinates + // Output: P = (Xfinal,Yfinal,Zfinal,Tafinal,Tbfinal) on E, where Tfinal = Tafinal*Tbfinal, + // corresponding to (Xfinal:Yfinal:Zfinal:Tfinal) in extended twisted Edwards coordinates + + ecc_tau(P); + ecc_delpsidel(P); + ecc_tau_dual(P); +} + + +void ecc_phi(vpoint_extproj_t P) +{ // Apply phi mapping to a point, P = phi(P) + // Input: P = (X1:Y1:Z1) on E in twisted Edwards coordinates + // Output: P = (Xfinal,Yfinal,Zfinal,Tafinal,Tbfinal) on E, where Tfinal = Tafinal*Tbfinal, + // corresponding to (Xfinal:Yfinal:Zfinal:Tfinal) in extended twisted Edwards coordinates + + ecc_tau(P); + ecc_delphidel(P); + ecc_tau_dual(P); +} + + +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 8 points: P, P+phi(P), P+psi(P), P+phi(P)+psi(P), P+psi(phi(P)), P+phi(P)+psi(phi(P)), P+psi(P)+psi(phi(P)), P+phi(P)+psi(P)+psi(phi(P)) + // 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 Q, R, S; + vpoint_extproj_t PP; + + // Generating Q = phi(P) = (XQ+YQ,YQ-XQ,ZQ,TQ) + ecccopy(P, PP); + ecc_phi(PP); + R1_to_R3(PP, Q); // Converting from (X,Y,Z,Ta,Tb) to (X+Y,Y-X,Z,T) + + // Generating S = psi(Q) = (XS+YS,YS-XS,ZS,TS) + ecc_psi(PP); + R1_to_R3(PP, S); // Converting from (X,Y,Z,Ta,Tb) to (X+Y,Y-X,Z,T) + + // Generating T[0] = P = (XP+YP,YP-XP,2ZP,2dTP) + R1_to_R2(P, T[0]); // Converting from (X,Y,Z,Ta,Tb) to (X+Y,Y-X,2Z,2dT) + + // Generating R = psi(P) = (XR+YR,YR-XR,ZR,TR) + ecc_psi(P); + R1_to_R3(P, R); // Converting from (X,Y,Z,Ta,Tb) to (X+Y,Y-X,Z,T) + + eccadd_core(T[0], Q, PP); // T[1] = P+Q using the representations (X,Y,Z,Ta,Tb) <- (X+Y,Y-X,2Z,2dT) + (X+Y,Y-X,Z,T) + R1_to_R2(PP, T[1]); // Converting from (X,Y,Z,Ta,Tb) to (X+Y,Y-X,2Z,2dT) + eccadd_core(T[0], R, PP); // T[2] = P+R + R1_to_R2(PP, T[2]); + eccadd_core(T[1], R, PP); // T[3] = P+Q+R + R1_to_R2(PP, T[3]); + eccadd_core(T[0], S, PP); // T[4] = P+S + R1_to_R2(PP, T[4]); + eccadd_core(T[1], S, PP); // T[5] = P+Q+S + R1_to_R2(PP, T[5]); + eccadd_core(T[2], S, PP); // T[6] = P+R+S + R1_to_R2(PP, T[6]); + eccadd_core(T[3], S, PP); // T[7] = P+Q+R+S + R1_to_R2(PP, T[7]); +} + + +static __inline void mul_truncate(uint32_t* s, uint32_t* C, uint32_t* out) +{ // 256-bit multiplication with truncation for the scalar decomposition + // Outputs 64-bit value "out" = (uint64_t)((s * C) >> 256). + + mul_truncate_a(s, C, out); +} + + +void decompose(uint64_t* k, uint64_t* scalars) +{ // Scalar decomposition for the variable-base scalar multiplication + // Input: scalar in the range [0, 2^256-1]. + // Output: 4 64-bit sub-scalars. + uint64_t a1, a2, a3, a4, temp, mask; + + mul_truncate_a((uint32_t*)k, (uint32_t*)ell1, (uint32_t*)&a1); + mul_truncate_a((uint32_t*)k, (uint32_t*)ell2, (uint32_t*)&a2); + mul_truncate_a((uint32_t*)k, (uint32_t*)ell3, (uint32_t*)&a3); + mul_truncate_a((uint32_t*)k, (uint32_t*)ell4, (uint32_t*)&a4); + + temp = k[0] - (uint64_t)a1*b11 - (uint64_t)a2*b21 - (uint64_t)a3*b31 - (uint64_t)a4*b41 + c1; + mask = ~(0 - (temp & 1)); // If temp is even then mask = 0xFF...FF, else mask = 0 + + scalars[0] = temp + (mask & b41); + scalars[1] = (uint64_t)a1*b12 + (uint64_t)a2 - (uint64_t)a3*b32 - (uint64_t)a4*b42 + c2 + (mask & b42); + scalars[2] = (uint64_t)a3*b33 - (uint64_t)a1*b13 - (uint64_t)a2 + (uint64_t)a4*b43 + c3 - (mask & b43); + scalars[3] = (uint64_t)a1*b14 - (uint64_t)a2*b24 - (uint64_t)a3*b34 + (uint64_t)a4*b44 + c4 - (mask & b44); +} + + +void recode(uint64_t* scalars, unsigned int* digits, unsigned int* sign_masks) +{ // Recoding sub-scalars for use in the variable-base scalar multiplication. See Algorithm 1 in "Efficient and Secure Methods for GLV-Based Scalar + // Multiplication and their Implementation on GLV-GLS Curves (Extended Version)", A. Faz-Hernandez, P. Longa, and A.H. Sanchez, in Journal + // of Cryptographic Engineering, Vol. 5(1), 2015. + // Input: 4 64-bit sub-scalars passed through "scalars", which are obtained after calling decompose(). + // Outputs: "digits" array with 65 nonzero entries. Each entry is in the range [0, 7], corresponding to one entry in the precomputed table. + // "sign_masks" array with 65 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 i, bit, bit0, carry; + sign_masks[64] = (unsigned int)-1; + + for (i = 0; i < 64; i++) + { + scalars[0] >>= 1; + bit0 = (unsigned int)scalars[0] & 1; + sign_masks[i] = 0 - bit0; + + bit = (unsigned int)scalars[1] & 1; + carry = (bit0 | bit) ^ bit0; + scalars[1] = (scalars[1] >> 1) + (uint64_t)carry; + digits[i] = bit; + + bit = (unsigned int)scalars[2] & 1; + carry = (bit0 | bit) ^ bit0; + scalars[2] = (scalars[2] >> 1) + (uint64_t)carry; + digits[i] += (bit << 1); + + bit = (unsigned int)scalars[3] & 1; + carry = (bit0 | bit) ^ bit0; + scalars[3] = (scalars[3] >> 1) + (uint64_t)carry; + digits[i] += (bit << 2); + } + digits[64] = (unsigned int)(scalars[1] + (scalars[2] << 1) + (scalars[3] << 2)); +} + + +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) +{ // Variable-base scalar multiplication Q = k*P using a 4-dimensional decomposition + // 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[8]; + uint64_t scalars[NWORDS64_ORDER]; + unsigned int digits[65], sign_masks[65]; + int i; + + point_setup(P, R); // Convert to vectorized representation (X,Y,1,Ta,Tb) + + if (ecc_point_validate(R) == false) { // Check if point lies on the curve + return false; + } + + decompose((uint64_t*)k, scalars); // Scalar decomposition + if (clear_cofactor == true) { + cofactor_clearing(R); + } + recode(scalars, digits, sign_masks); // Scalar recoding + ecc_precomp(R, Table); // Precomputation + table_lookup_1x8(Table, S, digits[64], sign_masks[64]); // Extract initial point in (X+Y,Y-X,2Z,2dT) representation + R2_to_R4(S, R); // Conversion to representation (2X,2Y,2Z) + + for (i = 63; i >= 0; i--) + { + table_lookup_1x8(Table, S, digits[i], sign_masks[i]); // Extract point S in (X+Y,Y-X,2Z,2dT) representation + 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 + + +void eccset(point_t P) +{ // Set generator + // Output: P = (x,y) + + fp2copy1271((felm_t*)&GENERATOR_x, P->x); // X1 + fp2copy1271((felm_t*)&GENERATOR_y, P->y); // Y1 +} + + +__inline void eccnorm(vpoint_extproj_t P, vpoint_t Q) +{ // Normalize a projective point (X1:Y1:Z1), including full reduction + // Input: P = (X1:Y1:Z1) in twisted Edwards coordinates + // Output: Q = (X1/Z1,Y1/Z1), corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates + + v2inv1271(P->z); // Z1 = Z1^-1 + v2mul1271(P->x, P->z, Q->x); // X1 = X1/Z1 + v2mul1271(P->y, P->z, Q->y); // Y1 = Y1/Z1 + v2mod1271(Q->x, Q->x); + v2mod1271(Q->y, Q->y); +} + + +void R1_to_R2(vpoint_extproj_t P, vpoint_extproj_precomp_t Q) +{ // Conversion from representation (X,Y,Z,Ta,Tb) to (X+Y,Y-X,2Z,2dT), where T = Ta*Tb + // Input: P = (X1,Y1,Z1,Ta,Tb), where T1 = Ta*Tb, corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates + // Output: Q = (X1+Y1,Y1-X1,2Z1,2dT1) corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates + + v2add1271(P->ta, P->ta, Q->t2); // T = 2*Ta + v2add1271(P->x, P->y, Q->xy); // QX = X+Y + v2sub1271(P->y, P->x, Q->yx); // QY = Y-X + v2mul1271(Q->t2, P->tb, Q->t2); // T = 2*T + v2add1271(P->z, P->z, Q->z2); // QZ = 2*Z + v2mul1271(Q->t2, (digit_t*)&PARAMETER_d, Q->t2); // QT = 2d*T +} + + +void R1_to_R3(vpoint_extproj_t P, vpoint_extproj_precomp_t Q) +{ // Conversion from representation (X,Y,Z,Ta,Tb) to (X+Y,Y-X,Z,T), where T = Ta*Tb + // Input: P = (X1,Y1,Z1,Ta,Tb), where T1 = Ta*Tb, corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates + // Output: Q = (X1+Y1,Y1-X1,Z1,T1) corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates + + v2addsub1271(P->y, P->x, Q->xy, Q->yx); // XQ = (X1+Y1), YQ = (Y1-X1) + v2mul1271(P->ta, P->tb, Q->t2); // TQ = T1 + v2copy1271(P->z, Q->z2); // ZQ = Z1 +} + + +void R2_to_R4(vpoint_extproj_precomp_t P, vpoint_extproj_t Q) +{ // Conversion from representation (X+Y,Y-X,2Z,2dT) to (2X,2Y,2Z,2dT) + // Input: P = (X1+Y1,Y1-X1,2Z1,2dT1) corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates + // Output: Q = (2X1,2Y1,2Z1) corresponding to (X1:Y1:Z1) in twisted Edwards coordinates + + v2addsub1271(P->xy, P->yx, Q->y, Q->x); // YQ = 2*Y1, XQ = 2*X1 + v2copy1271(P->z2, Q->z); // ZQ = 2*Z1 + v2mod1271_incomplete(Q->x, Q->x); + v2mod1271_incomplete(Q->y, Q->y); +} + + +void eccdouble(vpoint_extproj_t P) +{ // Point doubling 2P + // Input: P = (X1:Y1:Z1) in twisted Edwards coordinates + // Output: 2P = (Xfinal,Yfinal,Zfinal,Tafinal,Tbfinal), where Tfinal = Tafinal*Tbfinal, + // corresponding to (Xfinal:Yfinal:Zfinal:Tfinal) in extended twisted Edwards coordinates + v2elm_t t1, t2; + +#if !defined(MIX_ARM_NEON) + v2sqr1271(P->x, t1); // t1 = X1^2 + v2sqr1271(P->y, t2); // t2 = Y1^2 + v2add1271(P->x, P->y, P->x); // X = X1+Y1 + v2addsub1271(t2, t1, P->tb, t1); // Tbfinal = X1^2+Y1^2, t1 = Y1^2-X1^2 + v2sqr1271(P->z, t2); // t2 = Z1^2 + v2sqr1271(P->x, P->ta); // Ta = (X1+Y1)^2 + v2dblsub1271(t2, t1, t2); // t2 = 2Z1^2-(Y1^2-X1^2) + v2sub1271(P->ta, P->tb, P->ta); // Tafinal = 2X1*Y1 = (X1+Y1)^2-(X1^2+Y1^2) + v2mul1271(t1, P->tb, P->y); // Yfinal = (X1^2+Y1^2)(Y1^2-X1^2) + v2mul1271(t2, P->ta, P->x); // Xfinal = 2X1*Y1*[2Z1^2-(Y1^2-X1^2)] + v2mul1271(t1, t2, P->z); // Zfinal = (Y1^2-X1^2)[2Z1^2-(Y1^2-X1^2)] +#else + v2sqradd1271(P->x, t1, P->x, P->y, P->x); // t1 = X1^2, X = X1+Y1 + v2sqr1271(P->y, t2); // t2 = Y1^2 + v2sqraddsub1271(P->z, P->z, t2, t1, P->tb, t1); // Z = Z1^2, Tbfinal = X1^2+Y1^2, t1 = Y1^2-X1^2 + v2sqr1271(P->x, P->ta); // Ta = (X1+Y1)^2 + v2muldblsub1271(t1, P->tb, P->y, P->z, t1, t2); // Yfinal = (X1^2+Y1^2)(Y1^2-X1^2), t2 = 2Z1^2-(Y1^2-X1^2) + v2mulsub1271(t1, t2, P->z, P->ta, P->tb, P->ta); // Zfinal = (Y1^2-X1^2)[2Z1^2-(Y1^2-X1^2)], Tafinal = 2X1*Y1 = (X1+Y1)^2-(X1^2+Y1^2) + v2mul1271(t2, P->ta, P->x); // Xfinal = 2X1*Y1*[2Z1^2-(Y1^2-X1^2)] +#endif +} + + +__inline void eccadd_core(vpoint_extproj_precomp_t P, vpoint_extproj_precomp_t Q, vpoint_extproj_t R) +{ // Basic point addition R = P+Q or R = P+P + // Inputs: P = (X1+Y1,Y1-X1,2Z1,2dT1) corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates + // Q = (X2+Y2,Y2-X2,Z2,T2) corresponding to (X2:Y2:Z2:T2) in extended twisted Edwards coordinates + // Output: R = (Xfinal,Yfinal,Zfinal,Tafinal,Tbfinal), where Tfinal = Tafinal*Tbfinal, + // corresponding to (Xfinal:Yfinal:Zfinal:Tfinal) in extended twisted Edwards coordinates + v2elm_t t1, t2; + +#if !defined(MIX_ARM_NEON) + v2mul1271(P->t2, Q->t2, R->z); // Z = 2dT1*T2 + v2mul1271(P->z2, Q->z2, t1); // t1 = 2Z1*Z2 + v2mul1271(P->xy, Q->xy, R->x); // X = (X1+Y1)(X2+Y2) + v2mul1271(P->yx, Q->yx, R->y); // Y = (Y1-X1)(Y2-X2) + v2addsub1271(R->x, R->y, R->ta, R->tb); // Tafinal = omega, Tbfinal = beta + v2addsub1271(t1, R->z, t1, t2); // t1 = alpha, t2 = theta + v2mul1271(R->tb, t2, R->x); // Xfinal = beta*theta + v2mul1271(t1, t2, R->z); // Zfinal = theta*alpha + v2mul1271(R->ta, t1, R->y); // Yfinal = alpha*omega +#else + v2mul1271(P->t2, Q->t2, R->z); // Z = 2dT1*T2 + v2mul1271(P->z2, Q->z2, t1); // t1 = 2Z1*Z2 + v2mul1271(P->xy, Q->xy, R->x); // X = (X1+Y1)(X2+Y2) + v2muladdsub1271(P->yx, Q->yx, R->y, t1, R->z, t1, t2); // Y = (Y1-X1)(Y2-X2), t1 = alpha, t2 = theta + v2muladdsub1271(t1, t2, R->z, R->x, R->y, R->ta, R->tb); // Zfinal = theta*alpha, Tafinal = omega, Tbfinal = beta + v2mul1271(t2, R->tb, R->x); // Xfinal = beta*theta + v2mul1271(t1, R->ta, R->y); // Yfinal = alpha*omega +#endif +} + + +void eccadd(vpoint_extproj_precomp_t Q, vpoint_extproj_t P) +{ // Complete point addition P = P+Q or P = P+P + // Inputs: P = (X1,Y1,Z1,Ta,Tb), where T1 = Ta*Tb, corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates + // Q = (X2+Y2,Y2-X2,2Z2,2dT2) corresponding to (X2:Y2:Z2:T2) in extended twisted Edwards coordinates + // Output: P = (Xfinal,Yfinal,Zfinal,Tafinal,Tbfinal), where Tfinal = Tafinal*Tbfinal, + // corresponding to (Xfinal:Yfinal:Zfinal:Tfinal) in extended twisted Edwards coordinates + +#if !defined(MIX_ARM_NEON) + vpoint_precomp_t R; + v2elm_t t1; + + v2addsub1271(P->y, P->x, R->xy, R->yx); // XR = (X1+Y1), YR = (Y1-X1) + v2mul1271(P->ta, P->tb, R->t2); // TR = T1 + v2mul1271(Q->z2, P->z, t1); // t1 = 2Z1*Z2 + v2mul1271(Q->t2, R->t2, P->z); // Z = 2dT1*T2 + v2mul1271(Q->xy, R->xy, P->x); // X = (X1+Y1)(X2+Y2) + v2mul1271(Q->yx, R->yx, P->y); // Y = (Y1-X1)(Y2-X2) + v2addsub1271(P->x, P->y, P->ta, P->tb); // Tafinal = omega, Tbfinal = beta + v2addsub1271(t1, P->z, t1, R->t2); // t1 = alpha, TR = theta + v2mul1271(P->tb, R->t2, P->x); // Xfinal = beta*theta + v2mul1271(t1, R->t2, P->z); // Zfinal = theta*alpha + v2mul1271(P->ta, t1, P->y); // Yfinal = alpha*omega +#else + v2elm_t t1, t2; + + v2muladdsub1271(P->ta, P->tb, P->ta, P->y, P->x, P->tb, P->y); // Ta = T1, Tb = (X1+Y1), Y = (Y1-X1) + v2mul1271(P->z, Q->z2, t1); // t1 = 2Z1*Z2 + v2mul1271(P->ta, Q->t2, P->z); // Z = 2dT1*T2 + v2muladdsub1271(P->tb, Q->xy, P->x, t1, P->z, t1, t2); // X = (X1+Y1)(X2+Y2), t1 = alpha, t2 = theta + v2mul1271(P->y, Q->yx, P->y); // Y = (Y1-X1)(Y2-X2) + v2muladdsub1271(t2, t1, P->z, P->x, P->y, P->ta, P->tb); // Zfinal = theta*alpha, Tafinal = omega, Tbfinal = beta + v2mul1271(t2, P->tb, P->x); // Xfinal = beta*theta + v2mul1271(t1, P->ta, P->y); // Yfinal = alpha*omega +#endif +} + + +void point_setup(point_t P, vpoint_extproj_t Q) +{ // Point conversion to vectorized representation (X,Y,Z,Ta,Tb) + // Input: P = (x,y) in affine coordinates + // Output: P = (X,Y,1,Ta,Tb), where Ta=X, Tb=Y and T=Ta*Tb, corresponding to (X:Y:Z:T) in extended twisted Edwards coordinates + + from_std_to_ext(P->x, Q->x); + from_std_to_ext(P->y, Q->y); + v2copy1271(Q->x, Q->ta); // Ta = X1 + v2copy1271(Q->y, Q->tb); // Tb = Y1 + v2zero1271(Q->z); Q->z[0]=1; // Z1 = 1 +} + + +bool ecc_point_validate(vpoint_extproj_t P) +{ // Point validation: check if point lies on the curve + // Input: P = (x,y) in affine coordinates, where x, y in [0, 2^127-1]. + // Output: TRUE (1) if point lies on the curve E: -x^2+y^2-1-dx^2*y^2 = 0, FALSE (0) otherwise. + // SECURITY NOTE: this function does not run in constant time (input point P is assumed to be public). + v2elm_t t1, t2, t3; + unsigned int i; + + v2sqr1271(P->y, t1); + v2sqr1271(P->x, t2); + v2sub1271(t1, t2, t3); // -x^2 + y^2 + v2mul1271(t1, t2, t1); // x^2*y^2 + v2mul1271((digit_t*)&PARAMETER_d, t1, t2); // dx^2*y^2 + v2zero1271(t1); t1[0] = 1; // t1 = 1 + v2add1271(t2, t1, t2); // 1 + dx^2*y^2 + v2sub1271(t3, t2, t1); // -x^2 + y^2 - 1 - dx^2*y^2 + v2mod1271(t1, t1); + + for (i = 0; i < 2*VWORDS_FIELD-1; i++) { + if (t1[i] != 0) return false; + } + return true; +} + + +static __inline void R5_to_R1(vpoint_precomp_t P, vpoint_extproj_t Q) +{ // Conversion from representation (x+y,y-x,2dt) to (X,Y,Z,Ta,Tb) + // Input: P = (x1+y1,y1-x1,2dt1) corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates, where Z1=1 + // Output: Q = (x1,y1,z1,x1,y1), where z1=1, corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates + + v2addsub1271(P->xy, P->yx, Q->y, Q->x); // 2*y1, 2*x1 + v2zero1271(Q->z); Q->z[0]=1; // ZQ = 1 + v2div1271(Q->x); // XQ = x1 + v2div1271(Q->y); // YQ = y1 + v2copy1271(Q->x, Q->ta); // TaQ = x1 + v2copy1271(Q->y, Q->tb); // TbQ = y1 +} + + +static __inline void eccmadd(vpoint_precomp_t Q, vpoint_extproj_t P) +{ // Mixed point addition P = P+Q or P = P+P + // Inputs: P = (X1,Y1,Z1,Ta,Tb), where T1 = Ta*Tb, corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates + // Q = (x2+y2,y2-x2,2dt2) corresponding to (X2:Y2:Z2:T2) in extended twisted Edwards coordinates, where Z2=1 + // Output: P = (Xfinal,Yfinal,Zfinal,Tafinal,Tbfinal), where Tfinal = Tafinal*Tbfinal, + // corresponding to (Xfinal:Yfinal:Zfinal:Tfinal) in extended twisted Edwards coordinates + v2elm_t t1, t2; + +#if !defined(MIX_ARM_NEON) + v2mul1271(P->ta, P->tb, P->ta); // Ta = T1 + v2add1271(P->z, P->z, t1); // t1 = 2Z1 + v2mul1271(P->ta, Q->t2, P->ta); // Ta = 2dT1*t2 + v2addsub1271(P->y, P->x, P->z, P->tb); // Z = (X1+Y1), Tb = (Y1-X1) + v2addsub1271(t1, P->ta, t1, t2); // t1 = alpha, t2 = theta + v2mul1271(Q->xy, P->z, P->ta); // Ta = (X1+Y1)(x2+y2) + v2mul1271(Q->yx, P->tb, P->x); // X = (Y1-X1)(y2-x2) + v2addsub1271(P->ta, P->x, P->ta, P->tb); // Tafinal = omega, Tbfinal = beta + v2mul1271(t1, t2, P->z); // Zfinal = theta*alpha + v2mul1271(P->tb, t2, P->x); // Xfinal = beta*theta + v2mul1271(P->ta, t1, P->y); // Yfinal = alpha*omega +#else + v2muladd1271(P->ta, P->tb, P->ta, P->z, P->z, t1); // Ta = T1, t1 = 2Z1 + v2muladdsub1271(P->ta, Q->t2, P->ta, P->y, P->x, P->z, P->tb); // Ta = 2dT1*t2, Z = (X1+Y1), Tb = (Y1-X1) + v2muladdsub1271(Q->xy, P->z, P->y, t1, P->ta, t1, t2); // Y = (X1+Y1)(x2+y2), t1 = alpha, t2 = theta + v2mul1271(Q->yx, P->tb, P->x); // X = (Y1-X1)(y2-x2) + v2muladdsub1271(t1, t2, P->z, P->y, P->x, P->ta, P->tb); // Zfinal = theta*alpha, Tafinal = omega, Tbfinal = beta + v2mul1271(P->tb, t2, P->x); // Xfinal = beta*theta + v2mul1271(P->ta, t1, P->y); // Yfinal = alpha*omega +#endif +} + + +bool ecc_mul_fixed(digit_t* k, point_t Q) +{ // Fixed-base scalar multiplication Q = k*G, where G is the generator. FIXED_BASE_TABLE stores v*2^(w-1) = 80 multiples of G. + // Inputs: scalar "k" in [0, 2^256-1]. + // Output: Q = k*G in affine coordinates (x,y). + // The function is based on the modified LSB-set comb method, which converts the scalar to an odd signed representation + // with (bitlength(order)+w*v) digits. + unsigned int j, w = W_FIXEDBASE, v = V_FIXEDBASE, d = D_FIXEDBASE, e = E_FIXEDBASE; + unsigned int digit = 0, digits[NBITS_ORDER_PLUS_ONE+(W_FIXEDBASE*V_FIXEDBASE)-1] = {0}; + digit_t temp[NWORDS_ORDER]; + vpoint_t A; + vpoint_extproj_t R; + vpoint_precomp_t S; + int i, ii; + + modulo_order(k, temp); // temp = k mod (order) + conversion_to_odd(temp, temp); // Converting scalar to odd using the prime subgroup order + mLSB_set_recode((uint64_t*)temp, digits); // Scalar recoding + + // Extracting initial digit + digit = digits[w*d-1]; + for (i = (int)((w-1)*d-1); i >= (int)(2*d-1); i = i-d) + { + digit = 2*digit + digits[i]; + } + // Initialize R = (x+y,y-x,2dt) with a point from the table + table_lookup_fixed_base(((vpoint_precomp_t*)&FIXED_BASE_TABLE)+(v-1)*(1 << (w-1)), S, digit, digits[d-1]); + R5_to_R1(S, R); // Converting to representation (X:Y:1:Ta:Tb) + + for (j = 0; j < (v-1); j++) + { + digit = digits[w*d-(j+1)*e-1]; + for (i = (int)((w-1)*d-(j+1)*e-1); i >= (int)(2*d-(j+1)*e-1); i = i-d) + { + digit = 2*digit + digits[i]; + } + // Extract point in (x+y,y-x,2dt) representation + table_lookup_fixed_base(((vpoint_precomp_t*)&FIXED_BASE_TABLE)+(v-j-2)*(1 << (w-1)), S, digit, digits[d-(j+1)*e-1]); + eccmadd(S, R); // R = R+S using representations (X,Y,Z,Ta,Tb) <- (X,Y,Z,Ta,Tb) + (x+y,y-x,2dt) + } + + for (ii = (e-2); ii >= 0; ii--) + { + eccdouble(R); // R = 2*R using representations (X,Y,Z,Ta,Tb) <- 2*(X,Y,Z) + for (j = 0; j < v; j++) + { + digit = digits[w*d-j*e+ii-e]; + for (i = (int)((w-1)*d-j*e+ii-e); i >= (int)(2*d-j*e+ii-e); i = i-d) + { + digit = 2*digit + digits[i]; + } + // Extract point in (x+y,y-x,2dt) representation + table_lookup_fixed_base(((vpoint_precomp_t*)&FIXED_BASE_TABLE)+(v-j-1)*(1 << (w-1)), S, digit, digits[d-j*e+ii-e]); + eccmadd(S, R); // R = R+S using representations (X,Y,Z,Ta,Tb) <- (X,Y,Z,Ta,Tb) + (x+y,y-x,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; +} + + +void mLSB_set_recode(uint64_t* scalar, unsigned int *digits) +{ // Computes the modified LSB-set representation of a scalar + // Inputs: scalar in [0, order-1], where the order of FourQ's subgroup is 246 bits. + // Output: digits, where the first "d" values (from index 0 to (d-1)) store the signs for the recoded values using the convention: -1 (negative), 0 (positive), and + // the remaining values (from index d to (l-1)) store the recoded values in mLSB-set representation, excluding their sign, + // where l = d*w and d = ceil(bitlength(order)/(w*v))*v. The values v and w are fixed and must be in the range [1, 10] (see FourQ.h); they determine the size + // of the precomputed table "FIXED_BASE_TABLE" used by ecc_mul_fixed(). + unsigned int i, j, d = D_FIXEDBASE, l = L_FIXEDBASE; + uint64_t temp, carry; + + digits[d-1] = 0; + + // Shift scalar to the right by 1 + for (j = 0; j < (NWORDS64_ORDER-1); j++) { + SHIFTR(scalar[j+1], scalar[j], 1, scalar[j], RADIX64); + } + scalar[NWORDS64_ORDER-1] >>= 1; + + for (i = 0; i < (d-1); i++) + { + digits[i] = (unsigned int)((scalar[0] & 1) - 1); // Convention for the "sign" row: + // if scalar_(i+1) = 0 then digit_i = -1 (negative), else if scalar_(i+1) = 1 then digit_i = 0 (positive) + // Shift scalar to the right by 1 + for (j = 0; j < (NWORDS64_ORDER-1); j++) { + SHIFTR(scalar[j+1], scalar[j], 1, scalar[j], RADIX64); + } + scalar[NWORDS64_ORDER-1] >>= 1; + } + + for (i = d; i < l; i++) + { + digits[i] = (unsigned int)(scalar[0] & 1); // digits_i = k mod 2. Sign is determined by the "sign" row + + // Shift scalar to the right by 1 + for (j = 0; j < (NWORDS64_ORDER-1); j++) { + SHIFTR(scalar[j+1], scalar[j], 1, scalar[j], RADIX64); + } + scalar[NWORDS64_ORDER-1] >>= 1; + + temp = (0 - digits[i-(i/d)*d]) & digits[i]; // if (digits_i=0 \/ 1) then temp = 0, else if (digits_i=-1) then temp = 1 + + // floor(scalar/2) + temp + scalar[0] = scalar[0] + temp; + carry = (temp & (uint64_t)is_digit_zero_ct((digit_t)scalar[0])); // carry = (scalar[0] < temp); + for (j = 1; j < NWORDS64_ORDER; j++) + { + scalar[j] = scalar[j] + carry; + carry = (carry & (uint64_t)is_digit_zero_ct((digit_t)scalar[j])); // carry = (scalar[j] < temp); + } + } + return; +} + + +static __inline void eccneg_extproj_precomp(vpoint_extproj_precomp_t P, vpoint_extproj_precomp_t Q) +{ // Point negation + // Input : point P in coordinates (X+Y,Y-X,2Z,2dT) + // Output: point Q = -P = (Y-X,X+Y,2Z,-2dT) + v2copy1271(P->t2, Q->t2); + v2copy1271(P->xy, Q->yx); + v2copy1271(P->yx, Q->xy); + v2copy1271(P->z2, Q->z2); + v2neg1271(Q->t2); +} + + +static __inline void eccneg_precomp(vpoint_precomp_t P, vpoint_precomp_t Q) +{ // Point negation + // Input : point P in coordinates (x+y,y-x,2dt) + // Output: point Q = -P = (y-x,x+y,-2dt) + v2copy1271(P->t2, Q->t2); + v2copy1271(P->xy, Q->yx); + v2copy1271(P->yx, Q->xy); + v2neg1271(Q->t2); +} + + +bool ecc_mul_double(digit_t* k, point_t Q, digit_t* l, point_t R) +{ // Double scalar multiplication R = k*G + l*Q, where the G is the generator. Uses DOUBLE_SCALAR_TABLE, which contains multiples of G, Phi(G), Psi(G) and Phi(Psi(G)). + // Inputs: point Q in affine coordinates, + // Scalars "k" and "l" in [0, 2^256-1]. + // Output: R = k*G + l*Q in affine coordinates (x,y). + // The function uses wNAF with interleaving. + vpoint_t A; + + // SECURITY NOTE: this function is intended for a non-constant-time operation such as signature verification. + +#if (USE_ENDO == true) + unsigned int position; + int i, digits_k1[65] = {0}, digits_k2[65] = {0}, digits_k3[65] = {0}, digits_k4[65] = {0}; + int digits_l1[65] = {0}, digits_l2[65] = {0}, digits_l3[65] = {0}, digits_l4[65] = {0}; + vpoint_precomp_t V; + vpoint_extproj_t Q1, Q2, Q3, Q4, T; + vpoint_extproj_precomp_t U, Q_table1[NPOINTS_DOUBLEMUL_WQ], Q_table2[NPOINTS_DOUBLEMUL_WQ], Q_table3[NPOINTS_DOUBLEMUL_WQ], Q_table4[NPOINTS_DOUBLEMUL_WQ]; + uint64_t k_scalars[4], l_scalars[4]; + + point_setup(Q, Q1); // Convert to representation (X,Y,1,Ta,Tb) + + if (ecc_point_validate(Q1) == false) { // Check if point lies on the curve + return false; + } + + // Computing endomorphisms over point Q + ecccopy(Q1, Q2); + ecc_phi(Q2); + ecccopy(Q1, Q3); + ecc_psi(Q3); + ecccopy(Q2, Q4); + ecc_psi(Q4); + + decompose((uint64_t*)k, k_scalars); // Scalar decomposition + decompose((uint64_t*)l, l_scalars); + wNAF_recode(k_scalars[0], WP_DOUBLEBASE, digits_k1); // Scalar recoding + wNAF_recode(k_scalars[1], WP_DOUBLEBASE, digits_k2); + wNAF_recode(k_scalars[2], WP_DOUBLEBASE, digits_k3); + wNAF_recode(k_scalars[3], WP_DOUBLEBASE, digits_k4); + wNAF_recode(l_scalars[0], WQ_DOUBLEBASE, digits_l1); + wNAF_recode(l_scalars[1], WQ_DOUBLEBASE, digits_l2); + wNAF_recode(l_scalars[2], WQ_DOUBLEBASE, digits_l3); + wNAF_recode(l_scalars[3], WQ_DOUBLEBASE, digits_l4); + ecc_precomp_double(Q1, Q_table1, NPOINTS_DOUBLEMUL_WQ); // Precomputation + ecc_precomp_double(Q2, Q_table2, NPOINTS_DOUBLEMUL_WQ); + ecc_precomp_double(Q3, Q_table3, NPOINTS_DOUBLEMUL_WQ); + ecc_precomp_double(Q4, Q_table4, NPOINTS_DOUBLEMUL_WQ); + + v2zero1271(T->x); // Initialize T as the neutral point (0:1:1) + v2zero1271(T->y); T->y[0] = 1; + v2zero1271(T->z); T->z[0] = 1; + + for (i = 64; i >= 0; i--) + { + eccdouble(T); // Double (X_T,Y_T,Z_T,Ta_T,Tb_T) = 2(X_T,Y_T,Z_T,Ta_T,Tb_T) + if (digits_l1[i] < 0) { + position = (-digits_l1[i])/2; + eccneg_extproj_precomp(Q_table1[position], U); // Load and negate U = (X_U,Y_U,Z_U,Td_U) <- -(X+Y,Y-X,2Z,2dT) from a point in the precomputed table + eccadd(U, T); // T = T+U = (X_T,Y_T,Z_T,Ta_T,Tb_T) = (X_T,Y_T,Z_T,Ta_T,Tb_T) + (X_U,Y_U,Z_U,Td_U) + } else if (digits_l1[i] > 0) { + position = (digits_l1[i])/2; // Take U = (X_U,Y_U,Z_U,Td_U) <- (X+Y,Y-X,2Z,2dT) from a point in the precomputed table + eccadd(Q_table1[position], T); // T = T+U = (X_T,Y_T,Z_T,Ta_T,Tb_T) = (X_T,Y_T,Z_T,Ta_T,Tb_T) + (X_U,Y_U,Z_U,Td_U) + } + if (digits_l2[i] < 0) { + position = (-digits_l2[i])/2; + eccneg_extproj_precomp(Q_table2[position], U); + eccadd(U, T); + } else if (digits_l2[i] > 0) { + position = (digits_l2[i])/2; + eccadd(Q_table2[position], T); + } + if (digits_l3[i] < 0) { + position = (-digits_l3[i])/2; + eccneg_extproj_precomp(Q_table3[position], U); + eccadd(U, T); + } else if (digits_l3[i] > 0) { + position = (digits_l3[i])/2; + eccadd(Q_table3[position], T); + } + if (digits_l4[i] < 0) { + position = (-digits_l4[i])/2; + eccneg_extproj_precomp(Q_table4[position], U); + eccadd(U, T); + } else if (digits_l4[i] > 0) { + position = (digits_l4[i])/2; + eccadd(Q_table4[position], T); + } + + if (digits_k1[i] < 0) { + position = (-digits_k1[i])/2; + eccneg_precomp(((vpoint_precomp_t*)&DOUBLE_SCALAR_TABLE)[position], V); // Load and negate V = (X_V,Y_V,Z_V,Td_V) <- -(x+y,y-x,2dt) from a point in the precomputed table + eccmadd(V, T); // T = T+V = (X_T,Y_T,Z_T,Ta_T,Tb_T) = (X_T,Y_T,Z_T,Ta_T,Tb_T) + (X_V,Y_V,Z_V,Td_V) + } else if (digits_k1[i] > 0) { + position = (digits_k1[i])/2; // Take V = (X_V,Y_V,Z_V,Td_V) <- (x+y,y-x,2dt) from a point in the precomputed table + eccmadd(((vpoint_precomp_t*)&DOUBLE_SCALAR_TABLE)[position], T); // T = T+V = (X_T,Y_T,Z_T,Ta_T,Tb_T) = (X_T,Y_T,Z_T,Ta_T,Tb_T) + (X_V,Y_V,Z_V,Td_V) + } + if (digits_k2[i] < 0) { + position = (-digits_k2[i])/2; + eccneg_precomp(((vpoint_precomp_t*)&DOUBLE_SCALAR_TABLE)[NPOINTS_DOUBLEMUL_WP+position], V); + eccmadd(V, T); + } else if (digits_k2[i] > 0) { + position = (digits_k2[i])/2; + eccmadd(((vpoint_precomp_t*)&DOUBLE_SCALAR_TABLE)[NPOINTS_DOUBLEMUL_WP+position], T); + } + if (digits_k3[i] < 0) { + position = (-digits_k3[i])/2; + eccneg_precomp(((vpoint_precomp_t*)&DOUBLE_SCALAR_TABLE)[2*NPOINTS_DOUBLEMUL_WP+position], V); + eccmadd(V, T); + } else if (digits_k3[i] > 0) { + position = (digits_k3[i])/2; + eccmadd(((vpoint_precomp_t*)&DOUBLE_SCALAR_TABLE)[2*NPOINTS_DOUBLEMUL_WP+position], T); + } + if (digits_k4[i] < 0) { + position = (-digits_k4[i])/2; + eccneg_precomp(((vpoint_precomp_t*)&DOUBLE_SCALAR_TABLE)[3*NPOINTS_DOUBLEMUL_WP+position], V); + eccmadd(V, T); + } else if (digits_k4[i] > 0) { + position = (digits_k4[i])/2; + eccmadd(((vpoint_precomp_t*)&DOUBLE_SCALAR_TABLE)[3*NPOINTS_DOUBLEMUL_WP+position], T); + } + } + +#else + point_t B; + vpoint_extproj_t T; + vpoint_extproj_precomp_t S; + + if (ecc_mul(Q, l, B, false) == false) { + return false; + } + point_setup(B, T); + R1_to_R2(T, S); + + ecc_mul_fixed(k, B); + point_setup(B, T); + eccadd(S, T); +#endif + eccnorm(T, A); // Conversion to affine coordinates (x,y) and modular correction. + from_ext_to_std(A->x, R->x); + from_ext_to_std(A->y, R->y); + + return true; +} + + +void ecc_precomp_double(vpoint_extproj_t P, vpoint_extproj_precomp_t* Table, unsigned int npoints) +{ // Generation of the precomputation table used internally by the double scalar multiplication function ecc_mul_double(). + // Inputs: point P in representation (X,Y,Z,Ta,Tb), + // Table with storage for npoints, + // number of points "npoints". + // Output: Table containing multiples of the base point P using representation (X+Y,Y-X,2Z,2dT). + vpoint_extproj_t Q; + vpoint_extproj_precomp_t PP; + unsigned int i; + + R1_to_R2(P, Table[0]); // Precomputed point Table[0] = P in coordinates (X+Y,Y-X,2Z,2dT) + eccdouble(P); // A = 2*P in (X,Y,Z,Ta,Tb) + R1_to_R3(P, PP); // Converting from (X,Y,Z,Ta,Tb) to (X+Y,Y-X,Z,T) + + for (i = 1; i < npoints; i++) { + eccadd_core(Table[i-1], PP, Q); // Table[i] = Table[i-1]+2P using the representations (X,Y,Z,Ta,Tb) <- (X+Y,Y-X,2Z,2dT) + (X+Y,Y-X,Z,T) + R1_to_R2(Q, Table[i]); // Converting from (X,Y,Z,Ta,Tb) to (X+Y,Y-X,2Z,2dT) + } + + return; +} + + +void wNAF_recode(uint64_t scalar, unsigned int w, int* digits) +{ // Computes wNAF recoding of a scalar, where digits are in set {0,+-1,+-3,...,+-(2^(w-1)-1)} + unsigned int i; + int digit, index = 0; + int val1 = (int)(1 << (w-1)) - 1; // 2^(w-1) - 1 + int val2 = (int)(1 << w); // 2^w; + uint64_t k = scalar, mask = (uint64_t)val2 - 1; // 2^w - 1 + + while (k != 0) + { + digit = (int)(k & 1); + + if (digit == 0) { + k >>= 1; // Shift scalar to the right by 1 + digits[index] = 0; + } else { + digit = (int)(k & mask); + k >>= w; // Shift scalar to the right by w + + if (digit > val1) { + digit -= val2; + } + if (digit < 0) { // scalar + 1 + k += 1; + } + digits[index] = digit; + + if (k != 0) { // Check if scalar != 0 + for (i = 0; i < (w-1); i++) + { + index++; + digits[index] = 0; + } + } + } + index++; + } + return; +} + diff --git a/FourQ_ARM_NEON/eccp2_no_endo.c b/FourQ_ARM_NEON/eccp2_no_endo.c new file mode 100644 index 0000000..2520a70 --- /dev/null +++ b/FourQ_ARM_NEON/eccp2_no_endo.c @@ -0,0 +1,159 @@ +/**************************************************************************************** +* 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 diff --git a/FourQ_ARM_NEON/kex.c b/FourQ_ARM_NEON/kex.c new file mode 100644 index 0000000..c0d51f7 --- /dev/null +++ b/FourQ_ARM_NEON/kex.c @@ -0,0 +1,181 @@ +/******************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: Diffie-Hellman key exchange based on FourQ +* option 1: co-factor ecdh using compressed 32-byte public keys, +* (see https://datatracker.ietf.org/doc/draft-ladd-cfrg-4q/). +* option 2: co-factor ecdh using uncompressed, 64-byte public keys. +*********************************************************************************/ + +#include "FourQ_internal.h" +#include "FourQ_params.h" +#include "../random/random.h" +#include + + +static __inline bool is_neutral_point(point_t P) +{ // Is P the neutral point (0,1)? + // SECURITY NOTE: this function does not run in constant time (input point P is assumed to be public). + + if (is_zero_ct((digit_t*)P->x, 2*NWORDS_FIELD) && is_zero_ct(&((digit_t*)P->y)[1], 2*NWORDS_FIELD-1) && is_digit_zero_ct(P->y[0][0] - 1)) { + return true; + } + return false; +} + + +/*************** ECDH USING COMPRESSED, 32-BYTE PUBLIC KEYS ***************/ + +ECCRYPTO_STATUS CompressedPublicKeyGeneration(const unsigned char* SecretKey, unsigned char* PublicKey) +{ // Compressed public key generation for key exchange + // It produces a public key PublicKey, which is the encoding of P = SecretKey*G (G is the generator). + // Input: 32-byte SecretKey + // Output: 32-byte PublicKey + point_t P; + + ecc_mul_fixed((digit_t*)SecretKey, P); // Compute public key + encode(P, PublicKey); // Encode public key + + return ECCRYPTO_SUCCESS; +} + + +ECCRYPTO_STATUS CompressedKeyGeneration(unsigned char* SecretKey, unsigned char* PublicKey) +{ // Keypair generation for key exchange. Public key is compressed to 32 bytes + // It produces a private key SecretKey and a public key PublicKey, which is the encoding of P = SecretKey*G (G is the generator). + // Outputs: 32-byte SecretKey and 32-byte PublicKey + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + Status = RandomBytesFunction(SecretKey, 32); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + Status = CompressedPublicKeyGeneration(SecretKey, PublicKey); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)SecretKey, 256/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)PublicKey, 256/(sizeof(unsigned int)*8)); + + return Status; +} + + +ECCRYPTO_STATUS CompressedSecretAgreement(const unsigned char* SecretKey, const unsigned char* PublicKey, unsigned char* SharedSecret) +{ // Secret agreement computation for key exchange using a compressed, 32-byte public key + // The output is the y-coordinate of SecretKey*A, where A is the decoding of the public key PublicKey. + // Inputs: 32-byte SecretKey and 32-byte PublicKey + // Output: 32-byte SharedSecret + point_t A; + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + if ((PublicKey[15] & 0x80) != 0) { // Is bit128(PublicKey) = 0? + Status = ECCRYPTO_ERROR_INVALID_PARAMETER; + goto cleanup; + } + + Status = decode(PublicKey, A); // Also verifies that A is on the curve. If it is not, it fails + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + Status = ecc_mul(A, (digit_t*)SecretKey, A, true); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + if (is_neutral_point(A)) { // Is output = neutral point (0,1)? + Status = ECCRYPTO_ERROR_SHARED_KEY; + goto cleanup; + } + + memmove(SharedSecret, (unsigned char*)A->y, 32); + + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)SharedSecret, 256/(sizeof(unsigned int)*8)); + + return Status; +} + + +/*************** ECDH USING UNCOMPRESSED PUBLIC KEYS ***************/ + +ECCRYPTO_STATUS PublicKeyGeneration(const unsigned char* SecretKey, unsigned char* PublicKey) +{ // Public key generation for key exchange + // It produces the public key PublicKey = SecretKey*G, where G is the generator. + // Input: 32-byte SecretKey + // Output: 64-byte PublicKey + + ecc_mul_fixed((digit_t*)SecretKey, (point_affine*)PublicKey); // Compute public key + + return ECCRYPTO_SUCCESS; +} + + +ECCRYPTO_STATUS KeyGeneration(unsigned char* SecretKey, unsigned char* PublicKey) +{ // Keypair generation for key exchange + // It produces a private key SecretKey and computes the public key PublicKey = SecretKey*G, where G is the generator. + // Outputs: 32-byte SecretKey and 64-byte PublicKey + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + Status = RandomBytesFunction(SecretKey, 32); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + Status = PublicKeyGeneration(SecretKey, PublicKey); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)SecretKey, 256/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)PublicKey, 512/(sizeof(unsigned int)*8)); + + return Status; +} + + +ECCRYPTO_STATUS SecretAgreement(const unsigned char* SecretKey, const unsigned char* PublicKey, unsigned char* SharedSecret) +{ // Secret agreement computation for key exchange + // The output is the y-coordinate of SecretKey*PublicKey. + // Inputs: 32-byte SecretKey and 64-byte PublicKey + // Output: 32-byte SharedSecret + point_t A; + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + if (((PublicKey[15] & 0x80) != 0) || ((PublicKey[31] & 0x80) != 0) || ((PublicKey[47] & 0x80) != 0) || ((PublicKey[63] & 0x80) != 0)) { // Are PublicKey_x[i] and PublicKey_y[i] < 2^127? + Status = ECCRYPTO_ERROR_INVALID_PARAMETER; + goto cleanup; + } + + Status = ecc_mul((point_affine*)PublicKey, (digit_t*)SecretKey, A, true); // Also verifies that PublicKey is a point on the curve. If it is not, it fails + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + if (is_neutral_point(A)) { // Is output = neutral point (0,1)? + Status = ECCRYPTO_ERROR_SHARED_KEY; + goto cleanup; + } + + memmove(SharedSecret, (unsigned char*)A->y, 32); + + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)SharedSecret, 256/(sizeof(unsigned int)*8)); + + return Status; +} \ No newline at end of file diff --git a/FourQ_ARM_NEON/makefile b/FourQ_ARM_NEON/makefile new file mode 100644 index 0000000..cbc3547 --- /dev/null +++ b/FourQ_ARM_NEON/makefile @@ -0,0 +1,95 @@ +#### Makefile for compilation using GNU GCC or clang on ARM-based processors with NEON support #### + +OPT=-O3 # Optimization option by default + +CC=gcc +ifeq "$(CC)" "gcc" + COMPILER=gcc +else ifeq "$(CC)" "clang" + COMPILER=clang +endif + +ADDITIONAL_SETTINGS=-fwrapv -fomit-frame-pointer -funroll-loops +ifeq "$(EXTENDED_SET)" "FALSE" + ADDITIONAL_SETTINGS= +endif + +USE_ENDOMORPHISMS=-D USE_ENDO +ifeq "$(USE_ENDO)" "FALSE" + USE_ENDOMORPHISMS= +endif + +INLINING_SETTINGS= +ifeq "$(CC)" "gcc" + INLINING_SETTINGS=-finline-functions -finline-limit=300 +endif + +ifeq "$(INTERLEAVE)" "TRUE" + USE_INTERLEAVING=-D _INTERLEAVE_ +endif + +USE_ARM_NEON_MIX=-D _MIX_ARM_NEON_ +ifeq "$(MIX_ARM_NEON)" "FALSE" + USE_ARM_NEON_MIX= +endif + +CFLAGS=-c $(OPT) $(ADDITIONAL_SETTINGS) -D _ARM_ -D __LINUX__ -mfloat-abi=hard -mfpu=neon $(USE_ENDOMORPHISMS) $(USE_INTERLEAVING) $(USE_ARM_NEON_MIX) $(INLINING_SETTINGS) +LDFLAGS= +OBJECTS=eccp2.o fp2_1271_NEON.o eccp2_no_endo.o crypto_util.o schnorrq.o kex.o sha512.o random.o +OBJECTS_ECC_TEST=ecc_tests.o test_extras.o $(OBJECTS) +OBJECTS_FP_TEST=$(OBJECTS) fp_tests.o test_extras.o +OBJECTS_CRYPTO_TEST=crypto_tests.o $(OBJECTS) test_extras.o +OBJECTS_ALL=$(OBJECTS) $(OBJECTS_ECC_TEST) $(OBJECTS_FP_TEST) $(OBJECTS_CRYPTO_TEST) + +all: crypto_test ecc_test fp_test + +crypto_test: $(OBJECTS_CRYPTO_TEST) + $(CC) -o crypto_test $(OBJECTS_CRYPTO_TEST) -lrt + +ecc_test: $(OBJECTS_ECC_TEST) + $(CC) -o ecc_test $(OBJECTS_ECC_TEST) -lrt + +fp_test: $(OBJECTS_FP_TEST) + $(CC) -o fp_test $(OBJECTS_FP_TEST) -lrt + +eccp2.o: eccp2.c + $(CC) $(CFLAGS) eccp2.c + +eccp2_no_endo.o: eccp2_no_endo.c + $(CC) $(CFLAGS) eccp2_no_endo.c + +fp2_1271_NEON.o: ARM/fp2_1271_NEON.c + $(CC) $(CFLAGS) ARM/fp2_1271_NEON.c + +schnorrq.o: schnorrq.c + $(CC) $(CFLAGS) schnorrq.c + +kex.o: kex.c + $(CC) $(CFLAGS) kex.c + +crypto_util.o: crypto_util.c + $(CC) $(CFLAGS) crypto_util.c + +sha512.o: ../sha512/sha512.c + $(CC) $(CFLAGS) ../sha512/sha512.c + +random.o: ../random/random.c + $(CC) $(CFLAGS) ../random/random.c + +test_extras.o: tests/test_extras.c + $(CC) $(CFLAGS) tests/test_extras.c + +crypto_tests.o: tests/crypto_tests.c + $(CC) $(CFLAGS) tests/crypto_tests.c + +ecc_tests.o: tests/ecc_tests.c + $(CC) $(CFLAGS) tests/ecc_tests.c + +fp_tests.o: tests/fp_tests.c + $(CC) $(CFLAGS) tests/fp_tests.c + +.PHONY: clean + +clean: + rm -f crypto_test ecc_test fp_test fp2_1271_NEON.o $(OBJECTS_ALL) + diff --git a/FourQ_ARM_NEON/schnorrq.c b/FourQ_ARM_NEON/schnorrq.c new file mode 100644 index 0000000..da89f86 --- /dev/null +++ b/FourQ_ARM_NEON/schnorrq.c @@ -0,0 +1,190 @@ +/********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: digital signature SchnorrQ +* +* See "SchnorrQ: Schnorr signatures on FourQ" by Craig Costello and Patrick Longa, +* MSR Technical Report, 2016. Available at: +* https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/SchnorrQ.pdf. +***********************************************************************************/ + +#include "FourQ_internal.h" +#include "FourQ_params.h" +#include "../random/random.h" +#include "../sha512/sha512.h" +#include +#include + + +ECCRYPTO_STATUS SchnorrQ_KeyGeneration(const unsigned char* SecretKey, unsigned char* PublicKey) +{ // SchnorrQ public key generation + // It produces a public key PublicKey, which is the encoding of P = s*G, where G is the generator and + // s is the output of hashing SecretKey and taking the least significant 32 bytes of the result. + // Input: 32-byte SecretKey + // Output: 32-byte PublicKey + point_t P; + unsigned char k[64]; + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + if (CryptoHashFunction(SecretKey, 32, k) != 0) { + Status = ECCRYPTO_ERROR; + goto cleanup; + } + + ecc_mul_fixed((digit_t*)k, P); // Compute public key + encode(P, PublicKey); // Encode public key + + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)k, 512/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)PublicKey, 256/(sizeof(unsigned int)*8)); + + return Status; +} + + +ECCRYPTO_STATUS SchnorrQ_FullKeyGeneration(unsigned char* SecretKey, unsigned char* PublicKey) +{ // SchnorrQ keypair generation + // It produces a private key SecretKey and computes the public key PublicKey, which is the encoding of P = s*G, + // where G is the generator and s is the output of hashing SecretKey and taking the least significant 32 bytes of the result. + // Outputs: 32-byte SecretKey and 32-byte PublicKey + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + Status = RandomBytesFunction(SecretKey, 32); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + Status = SchnorrQ_KeyGeneration(SecretKey, PublicKey); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)SecretKey, 256/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)PublicKey, 256/(sizeof(unsigned int)*8)); + + return Status; +} + + +ECCRYPTO_STATUS SchnorrQ_Sign(const unsigned char* SecretKey, const unsigned char* PublicKey, const unsigned char* Message, const unsigned int SizeMessage, unsigned char* Signature) +{ // SchnorrQ signature generation + // It produces the signature Signature of a message Message of size SizeMessage in bytes + // Inputs: 32-byte SecretKey, 32-byte PublicKey, and Message of size SizeMessage in bytes + // Output: 64-byte Signature + point_t R; + unsigned char k[64], r[64], h[64], *temp = NULL; + digit_t* H = (digit_t*)h; + digit_t* S = (digit_t*)(Signature+32); + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + if (CryptoHashFunction(SecretKey, 32, k) != 0) { + Status = ECCRYPTO_ERROR; + goto cleanup; + } + + temp = (unsigned char*)calloc(1, SizeMessage+64); + if (temp == NULL) { + Status = ECCRYPTO_ERROR_NO_MEMORY; + goto cleanup; + } + + memmove(temp+32, k+32, 32); + memmove(temp+64, Message, SizeMessage); + + if (CryptoHashFunction(temp+32, SizeMessage+32, r) != 0) { + Status = ECCRYPTO_ERROR; + goto cleanup; + } + + ecc_mul_fixed((digit_t*)r, R); + encode(R, Signature); // Encode lowest 32 bytes of signature + memmove(temp, Signature, 32); + memmove(temp+32, PublicKey, 32); + + if (CryptoHashFunction(temp, SizeMessage+64, h) != 0) { + Status = ECCRYPTO_ERROR; + goto cleanup; + } + modulo_order((digit_t*)r, (digit_t*)r); + modulo_order(H, H); + to_Montgomery((digit_t*)k, S); // Converting to Montgomery representation + to_Montgomery(H, H); // Converting to Montgomery representation + Montgomery_multiply_mod_order(S, H, S); + from_Montgomery(S, S); // Converting back to standard representation + subtract_mod_order((digit_t*)r, S, S); + Status = ECCRYPTO_SUCCESS; + +cleanup: + if (temp != NULL) + free(temp); + clear_words((unsigned int*)k, 512/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)r, 512/(sizeof(unsigned int)*8)); + + return Status; +} + + +ECCRYPTO_STATUS SchnorrQ_Verify(const unsigned char* PublicKey, const unsigned char* Message, const unsigned int SizeMessage, const unsigned char* Signature, unsigned int* valid) +{ // SchnorrQ signature verification + // It verifies the signature Signature of a message Message of size SizeMessage in bytes + // Inputs: 32-byte PublicKey, 64-byte Signature, and Message of size SizeMessage in bytes + // Output: true (valid signature) or false (invalid signature) + point_t A; + unsigned char *temp, h[64]; + unsigned int i; + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + *valid = false; + + temp = (unsigned char*)calloc(1, SizeMessage+64); + if (temp == NULL) { + Status = ECCRYPTO_ERROR_NO_MEMORY; + goto cleanup; + } + + if (((PublicKey[15] & 0x80) != 0) || ((Signature[15] & 0x80) != 0) || (Signature[63] != 0) || ((Signature[62] & 0xC0) != 0)) { // Are bit128(PublicKey) = bit128(Signature) = 0 and Signature+32 < 2^246? + Status = ECCRYPTO_ERROR_INVALID_PARAMETER; + goto cleanup; + } + + Status = decode(PublicKey, A); // Also verifies that A is on the curve. If it is not, it fails + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + memmove(temp, Signature, 32); + memmove(temp+32, PublicKey, 32); + memmove(temp+64, Message, SizeMessage); + + if (CryptoHashFunction(temp, SizeMessage+64, h) != 0) { + Status = ECCRYPTO_ERROR; + goto cleanup; + } + + Status = ecc_mul_double((digit_t*)(Signature+32), A, (digit_t*)h, A); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + encode(A, (unsigned char*)A); + + for (i = 0; i < NWORDS_ORDER; i++) { + if (((digit_t*)A)[i] != ((digit_t*)Signature)[i]) { + goto cleanup; + } + } + *valid = true; + +cleanup: + if (temp != NULL) + free(temp); + + return Status; +} \ No newline at end of file diff --git a/FourQ_ARM_NEON/tests/ecc_tests.c b/FourQ_ARM_NEON/tests/ecc_tests.c new file mode 100644 index 0000000..147ab1a --- /dev/null +++ b/FourQ_ARM_NEON/tests/ecc_tests.c @@ -0,0 +1,657 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: testing code for FourQ's curve arithmetic +************************************************************************************/ + +#include "../FourQ_api.h" +#include "../FourQ_params.h" +#include "../FourQ_tables.h" +#include "test_extras.h" +#include + + +// Benchmark and test parameters +#define BENCH_LOOPS 1000 // Number of iterations per bench +#define SHORT_BENCH_LOOPS 100 // Number of iterations per bench (for expensive operations) +#define TEST_LOOPS 1000 // Number of iterations per test + + +bool ecc_test() +{ + bool clear_cofactor, OK = true; + unsigned int n; + int passed; + point_t A; + vpoint_t VA; + vpoint_extproj_t VP; + vpoint_extproj_precomp_t VQ; + v2elm_t t1; + uint64_t scalar[4], res_x[4], res_y[4]; + + printf("\n--------------------------------------------------------------------------------------------------------\n\n"); + printf("Testing FourQ's curve arithmetic: \n\n"); + + // Point doubling + passed = 1; + eccset(A); + point_setup(A, VP); + + for (n=0; nx, A->x); + from_ext_to_std(VA->y, A->y); + + // Result + res_x[0] = 0xC9099C54855859D6; res_x[1] = 0x2C3FD8822C82270F; res_x[2] = 0xA7B3F6E2043E8E68; res_x[3] = 0x4DA5B9E83AA7A1B2; + res_y[0] = 0x3EE089F0EB49AA14; res_y[1] = 0x2001EB3A57688396; res_y[2] = 0x1FEE5617A7E954CD; res_y[3] = 0x0FFDB0D761421F50; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + if (passed==1) printf(" Point doubling tests .................................................................... PASSED"); + else { printf(" Point doubling tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + + // Point addition + eccset(A); + point_setup(A, VP); + + for (n=0; nta, t1); // d*ta + v2add1271(t1, t1, t1); // 2*d*ta + v2mul1271(t1, VP->tb, VQ->t2); // 2*d*t + v2add1271(VP->x, VP->y, VQ->xy); // x+y + v2sub1271(VP->y, VP->x, VQ->yx); // y-x + v2copy1271(VP->z, VQ->z2); + v2add1271(VQ->z2, VQ->z2, VQ->z2); // 2*z + eccadd(VQ, VP); // 2*P + } + eccnorm(VP, VA); + from_ext_to_std(VA->x, A->x); + from_ext_to_std(VA->y, A->y); + + // Result + res_x[0] = 0xC9099C54855859D6; res_x[1] = 0x2C3FD8822C82270F; res_x[2] = 0xA7B3F6E2043E8E68; res_x[3] = 0x4DA5B9E83AA7A1B2; + res_y[0] = 0x3EE089F0EB49AA14; res_y[1] = 0x2001EB3A57688396; res_y[2] = 0x1FEE5617A7E954CD; res_y[3] = 0x0FFDB0D761421F50; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + eccset(A); + point_setup(A, VP); + v2mul1271((uint32_t*)&PARAMETER_d, VP->x, t1); // d*x + v2add1271(t1, t1, t1); // 2*d*x + v2mul1271(t1, VP->y, VQ->t2); // 2*d*t + v2add1271(VP->x, VP->y, VQ->xy); // x+y + v2sub1271(VP->y, VP->x, VQ->yx); // y-x + v2zero1271(VQ->z2); VQ->z2[0] = 2; // 2*z + eccdouble(VP); // P = 2P + + for (n=0; nx, A->x); + from_ext_to_std(VA->y, A->y); + + // Result + res_x[0] = 0x6480B1EF0A151DB0; res_x[1] = 0x3E243958590C4D90; res_x[2] = 0xAA270F644A65D473; res_x[3] = 0x5327AF7D84238CD0; + res_y[0] = 0x5E06003D73C43EB1; res_y[1] = 0x3EF69A49CB7E0237; res_y[2] = 0x4E752648AC2EF0AB; res_y[3] = 0x293EB1E26DD23B4E; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + if (passed==1) printf(" Point addition tests .................................................................... PASSED"); + else { printf(" Point addition tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + +#if (USE_ENDO == true) + // Psi endomorphism + eccset(A); + point_setup(A, VP); + + for (n=0; nx, A->x); + from_ext_to_std(VA->y, A->y); + + // Result + res_x[0] = 0xD8F3C8C24A2BC7E2; res_x[1] = 0x75AF54EDB41A2B93; res_x[2] = 0x4DE2466701F009A9; res_x[3] = 0x065249F9EDE0C798; + res_y[0] = 0x1C6E119ADD608104; res_y[1] = 0x06DBB85BFFB7C21E; res_y[2] = 0xFD234D6C4CFA3EC1; res_y[3] = 0x060A30903424BF13; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + if (passed==1) printf(" Psi endomorphism tests .................................................................. PASSED"); + else { printf(" Psi endomorphism tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + + // Phi endomorphism + eccset(A); + point_setup(A, VP); + + for (n=0; nx, A->x); + from_ext_to_std(VA->y, A->y); + point_setup(A, VP); + } + + // Result + res_x[0] = 0xD5B5A3061287DB16; res_x[1] = 0x5550AAB9E7A620EE; res_x[2] = 0xEC321E6CF33610FC; res_x[3] = 0x3E61EBB9A1CB0210; + res_y[0] = 0x7E2851D5A8E83FB9; res_y[1] = 0x5474BF8EC55603AE; res_y[2] = 0xA5077613491788D5; res_y[3] = 0x5476093DBF8BF6BF; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + if (passed==1) printf(" Phi endomorphism tests .................................................................. PASSED"); + else { printf(" Phi endomorphism tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + + // Scalar decomposition and recoding + { + uint64_t acc1, acc2, acc3, acc4, scalars[4]; + unsigned int digits[65], sign_masks[65]; + uint64_t k[4]; + int i; + + for (n=0; n= 0; i--) + { + acc1 = 2*acc1; acc2 = 2*acc2; acc3 = 2*acc3; acc4 = 2*acc4; + if (sign_masks[i] == (unsigned int)-1) { + acc1 += 1; + acc2 += (digits[i] & 1); + acc3 += ((digits[i] >> 1) & 1); + acc4 += ((digits[i] >> 2) & 1); + } else if (sign_masks[i] == 0) { + acc1 -= 1; + acc2 -= (digits[i] & 1); + acc3 -= ((digits[i] >> 1) & 1); + acc4 -= ((digits[i] >> 2) & 1); + } + } + if (scalar[0] != acc1 || scalar[1] != acc2 || scalar[2] != acc3 || scalar[3] != acc4) { passed=0; break; } + } + + if (passed==1) printf(" Recoding and decomposition tests ........................................................ PASSED"); + else { printf(" Recoding and decomposition tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + } +#endif + + // Scalar multiplication + eccset(A); + clear_cofactor = false; + scalar[0] = 0x3AD457AB55456230; scalar[1] = 0x3A8B3C2C6FD86E0C; scalar[2] = 0x7E38F7C9CFBB9166; scalar[3] = 0x0028FD6CBDA458F0; + + for (n=0; nx, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + eccset(A); + clear_cofactor = true; + scalar[0] = 0x3AD457AB55456230; scalar[1] = 0x3A8B3C2C6FD86E0C; scalar[2] = 0x7E38F7C9CFBB9166; scalar[3] = 0x0028FD6CBDA458F0; + + for (n=0; nx, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + if (passed==1) printf(" Scalar multiplication tests ............................................................. PASSED"); + else { printf(" Scalar multiplication tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + + { + point_t A, B, C; + vpoint_extproj_t VS; + unsigned int i, j, w, v, e, d; + uint64_t k[4]; + unsigned int digits_fixed[NBITS_ORDER_PLUS_ONE+(W_FIXEDBASE*V_FIXEDBASE)-1] = {0}; + + // Scalar recoding using the mLSB-set representation + w = W_FIXEDBASE; + v = V_FIXEDBASE; + e = E_FIXEDBASE; + d = D_FIXEDBASE; + + for (n=0; nx,(uint64_t*)C->x)!=0 || fp2compare64((uint64_t*)B->y,(uint64_t*)C->y)!=0) { passed=0; break; } + } + + if (passed==1) printf(" Fixed-base scalar multiplication tests .................................................. PASSED"); + else { printf(" Fixed-base scalar multiplication tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + } + + { + point_t PP, QQ, RR, UU, TT; + vpoint_extproj_t VS, VT; + vpoint_extproj_precomp_t VR; + uint64_t k[4], l[4], scalar[4]; + + // Double scalar multiplication + eccset(QQ); + eccset(PP); + + for (n=0; nx, VT->x); + from_std_to_ext(TT->y, VT->y); + v2add1271(VT->x, VT->y, VR->xy); + v2sub1271(VT->y, VT->x, VR->yx); + v2zero1271(VR->z2); VR->z2[0] = 2; + v2mul1271(VT->x, VT->y, VR->t2); + v2add1271(VR->t2, VR->t2, VR->t2); + v2mul1271(VR->t2, (digit_t*)&PARAMETER_d, VR->t2); + + eccadd(VR, VS); + eccnorm(VS, VA); + from_ext_to_std(VA->x, A->x); + from_ext_to_std(VA->y, A->y); + + if (fp2compare64((uint64_t*)A->x,(uint64_t*)RR->x)!=0 || fp2compare64((uint64_t*)A->y,(uint64_t*)RR->y)!=0) { passed=0; break; } + } + + if (passed==1) printf(" Double scalar multiplication tests ...................................................... PASSED"); + else { printf(" Double scalar multiplication tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + } + + return OK; +} + + +bool ecc_run() +{ + bool OK = true; + unsigned int n, i, sign_mask=-1, digit=1; + unsigned long long nsec, nsec1, nsec2; + point_t A, B; + vpoint_extproj_t VP; + vpoint_extproj_precomp_t VQ, Table[8]; + v2elm_t t1; + uint64_t scalar[4]; + + printf("\n--------------------------------------------------------------------------------------------------------\n\n"); + printf("Benchmarking FourQ's curve arithmetic \n\n"); + + // Point doubling + eccset(A); + point_setup(A, VP); + + nsec = 0; + for (n=0; nx, t1); // d*x + v2add1271(t1, t1, t1); // 2*d*x + v2mul1271(t1, VP->y, VQ->t2); // 2*d*t + v2add1271(VP->x, VP->y, VQ->xy); // x+y + v2sub1271(VP->y, VP->x, VQ->yx); // y-x + v2zero1271(VQ->z2); VQ->z2[0] = 2; // 2*z + eccdouble(VP); // P = 2P + + nsec = 0; + for (n=0; n +#endif +#include +#include +#include + + +int64_t cpu_nseconds(void) +{ // Access system counter for benchmarking + struct timespec time; + + clock_gettime(CLOCK_REALTIME, &time); + return (int64_t)(time.tv_sec*1e9 + time.tv_nsec); +} + + +int fpcompare64(uint64_t* a, uint64_t* b) +{ // Comparing uint64_t digits of two field elements, a=b? : (0) equal, (1) unequal + // NOTE: this function does not have constant-time execution. TO BE USED FOR TESTING ONLY. + unsigned int i; + + for (i = 0; i < (NWORDS64_FIELD); i++) { + if (a[i] != b[i]) return 1; + } + + return 0; +} + + +int fp2compare64(uint64_t* a, uint64_t* b) +{ // Comparing uint64_t digits of two quadratic extension field elements, ai=bi? : (0) equal, (1) unequal + // NOTE: this function does not have constant-time execution. TO BE USED FOR TESTING ONLY. + unsigned int i; + + for (i = 0; i < (2*NWORDS64_FIELD); i++) { + if (a[i] != b[i]) return 1; + } + + return 0; +} + + +void random_scalar_test(uint64_t* a) +{ // Generating a pseudo-random scalar value in [0, 2^256-1] + // NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY. + unsigned char* string = (unsigned char*)&a[0]; + unsigned int i; + + for (i = 0; i < (sizeof(uint64_t)*NWORDS64_ORDER); i++) { + string[i] = (unsigned char)rand(); + } +} + + +void fp2random1271_test(f2elm_t a) +{ // Generating a pseudo-random GF(p^2) element a+b*i, where a,b in [0, 2^127-1] + // NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY. + digit_t mask_7fff = (digit_t)-1 >> 1; + + random_scalar_test((uint64_t*)&a[0]); + a[0][NWORDS_FIELD-1] &= mask_7fff; + a[1][NWORDS_FIELD-1] &= mask_7fff; +} + + +void vrandom1271_test(velm_t a) +{ // Generating a vectorized pseudo-random GF(p) element in [0, 2^127-1] + // NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY. + v2elm_t temp; + velm_t b; + + v2random1271_test(temp); + from_v2_to_v(temp, a, b); +} + + +void v2random1271_test(v2elm_t a) +{ // Generating a vectorized pseudo-random GF(p^2) element a+b*i, where a,b in [0, 2^127-1] + // NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY. + digit_t mask_7fff = (digit_t)-1 >> 1; + f2elm_t temp; + + random_scalar_test((uint64_t*)&temp[0]); + temp[0][NWORDS_FIELD-1] &= mask_7fff; + temp[1][NWORDS_FIELD-1] &= mask_7fff; + from_std_to_ext(temp, a); +} + + +bool verify_mLSB_recoding(uint64_t* scalar, int* digits) +{ // Verification of the mLSB-set's recoding algorithm used in fixed-base scalar multiplication + unsigned int j, l = L_FIXEDBASE, d = D_FIXEDBASE; + uint64_t temp, temp2, carry, borrow, generated_scalar[NWORDS64_ORDER] = {0}; + int i, digit; + + for (i = (l-1); i >= 0; i--) + { + // Shift generated scalar to the left by 1 (multiply by 2) + temp = ((generated_scalar[0] >> (RADIX64-1)) & 1) ; + generated_scalar[0] = generated_scalar[0] << 1; + + for (j = 1; j < NWORDS64_ORDER; j++) { + temp2 = ((generated_scalar[j] >> (RADIX64-1)) & 1) ; + generated_scalar[j] = (generated_scalar[j] << 1) | temp; + temp = temp2; + } + + // generated scalar + digit_i + if (i < (int)d) { + digit = digits[i] | 1; + if (digit >= 0) { + generated_scalar[0] = generated_scalar[0] + digit; + carry = (generated_scalar[0] < (unsigned int)digit); + for (j = 1; j < NWORDS64_ORDER; j++) + { + generated_scalar[j] = generated_scalar[j] + carry; + carry = (generated_scalar[j] < carry); + } + } else { + borrow = 0; + temp = (uint64_t)(-digit); + for (j = 0; j < NWORDS64_ORDER; j++) + { + temp2 = generated_scalar[j] - temp; + carry = (generated_scalar[j] < temp); + generated_scalar[j] = temp2 - borrow; + borrow = carry || (temp2 < borrow); + temp = 0; + } + } + } else { + digit = digits[i]*(digits[i-(i/d)*d] | 1); + if (digit >= 0) { + generated_scalar[0] = generated_scalar[0] + digit; + carry = (generated_scalar[0] < (unsigned int)digit); + for (j = 1; j < NWORDS64_ORDER; j++) + { + generated_scalar[j] = generated_scalar[j] + carry; + carry = (generated_scalar[j] < carry); + } + } else { + borrow = 0; + temp = (uint64_t)(-digit); + for (j = 0; j < NWORDS64_ORDER; j++) + { + temp2 = generated_scalar[j] - temp; + carry = (generated_scalar[j] < temp); + generated_scalar[j] = temp2 - borrow; + borrow = carry || (temp2 < borrow); + temp = 0; + } + } + } + } + + for (j = 0; j < NWORDS64_ORDER; j++) + { + if (scalar[j] != generated_scalar[j]) + return false; + } + + return true; +} diff --git a/FourQ_ARM_NEON/tests/test_extras.h b/FourQ_ARM_NEON/tests/test_extras.h new file mode 100644 index 0000000..c348572 --- /dev/null +++ b/FourQ_ARM_NEON/tests/test_extras.h @@ -0,0 +1,49 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: utility header file for tests +************************************************************************************/ + +#ifndef __TEST_EXTRAS_H__ +#define __TEST_EXTRAS_H__ + + +// For C++ +#ifdef __cplusplus +extern "C" { +#endif + + +// Access system counter for benchmarking +int64_t cpu_nseconds(void); + +// Comparing uint64_t digits of two field elements, a=b? : (0) equal, (1) unequal +int fpcompare64(uint64_t* a, uint64_t* b); + +// Comparing uint64_t digits of two quadratic extension field elements, ai=bi? : (0) equal, (1) unequal +int fp2compare64(uint64_t* a, uint64_t* b); + +// Generating a pseudo-random scalar value in [0, 2^256-1] +void random_scalar_test(uint64_t* a); + +// Generating a vectorized pseudo-random GF(p) element in [0, 2^127-1] +void vrandom1271_test(velm_t a); + +// Generating a pseudo-random GF(p^2) element a+b*i, where a,b in [0, 2^127-1] +void fp2random1271_test(f2elm_t a); + +// Generating a vectorized pseudo-random GF(p^2) element a+b*i, where a,b in [0, 2^127-1] +void v2random1271_test(v2elm_t a); + +// Verification of the mLSB-set's recoding algorithm used in fixed-base scalar multiplication +bool verify_mLSB_recoding(uint64_t* scalar, int* digits); + + +#ifdef __cplusplus +} +#endif + + +#endif \ No newline at end of file diff --git a/FourQ_ARM_side_channel/ARM/fp2_1271_arm.S b/FourQ_ARM_side_channel/ARM/fp2_1271_arm.S new file mode 100644 index 0000000..e7e69f0 --- /dev/null +++ b/FourQ_ARM_side_channel/ARM/fp2_1271_arm.S @@ -0,0 +1,644 @@ +//*********************************************************************************** +// FourQlib: a high-performance crypto library based on the elliptic curve FourQ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Abstract: arithmetic over GF(p^2) using ARM assembly for Linux +//*********************************************************************************** + + +.text +.align 4 +//*********************************************************************** +// Multiplication over GF(p^2) +// Operation: c [reg_p3] = a [reg_p1] * b [reg_p2] +// Restriction : b != c +//*********************************************************************** +.global fp2mul1271_a +.type fp2mul1271_a, %function +fp2mul1271_a: + push {r4-r12} + sub r13, r13, #44 // Allocating space in the stack + + // T0 = a0 * b0 + ldm r0!, {r3-r6} + ldr r7, [r1] + mov r10, #0 + mov r11, #0 + mov r12, #0 + umull r9, r8, r7, r3 + umlal r8, r10, r7, r4 + umlal r10, r11, r7, r5 + umlal r11, r12, r7, r6 + ldr r7, [r1, #4] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #8] + str r8, [r13], #4 // Store in stack + mov r8, #0 + + umlal r9, r8, r7, r3 + umaal r8, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #12] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + + // T1 = a1 * b1 + ldm r0!, {r3-r6} + ldr r7, [r1, #16] + stmia r13!, {r8-r12} // Store in stack + mov r10, #0 + mov r11, #0 + mov r12, #0 + umull r9, r8, r7, r3 + umlal r8, r10, r7, r4 + umlal r10, r11, r7, r5 + umlal r11, r12, r7, r6 + ldr r7, [r1, #20] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #24] + str r8, [r13], #4 // Store in stack + mov r8, #0 + + umlal r9, r8, r7, r3 + umaal r8, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #28] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + sub r13, r13, #52 + stmia r13!, {r0-r1} + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + + // c0 = T0 - T1 = a0*b0 - a1*b1 + ldmia r13!, {r3-r6} + ldr r0, [r13, #16] + ldr r1, [r13, #20] + ldr r7, [r13, #24] + subs r3, r3, r0 + sbcs r4, r4, r1 + sbcs r5, r5, r7 + sbcs r6, r6, r8 + ldmia r13!, {r7-r8} + ldmia r13!, {r0-r1} + sbcs r7, r7, r9 + sbcs r8, r8, r10 + sbcs r9, r0, r11 + sbcs r10, r1, r12 + sub r13, #40 + pop {r0-r1} + + // Reducing and storing c0 + lsl r10, r10, #1 + orr r10, r10, r9, lsr #31 + lsl r9, r9, #1 + orr r9, r9, r8, lsr #31 + lsl r8, r8, #1 + orr r8, r8, r7, lsr #31 + lsl r7, r7, #1 + orr r7, r7, r6, lsr #31 + and r6, r6, #0x7FFFFFFF + + subs r7, r7, r10, lsr #31 + sbcs r8, r8, #0 + sbcs r9, r9, #0 + sbcs r10, r10, #0 + and r10, r10, #0x7FFFFFFF + + adds r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10 + + and r7, r6, #0x7FFFFFFF + adds r3, r3, r6, lsr #31 + adcs r4, r4, #0 + adcs r5, r5, #0 + adcs r6, r7, #0 + stmia r13!, {r3-r6} + + // T2 = a0 * b1 + sub r0, r0, #32 + ldm r0!, {r3-r6} + ldr r7, [r1, #16] + mov r10, #0 + mov r11, #0 + mov r12, #0 + umull r9, r8, r7, r3 + umlal r8, r10, r7, r4 + umlal r10, r11, r7, r5 + umlal r11, r12, r7, r6 + ldr r7, [r1, #20] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #24] + str r8, [r13], #4 // Store in stack + mov r8, #0 + + umlal r9, r8, r7, r3 + umaal r8, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #28] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + str r8, [r13], #4 + + sub r13, r13, #32 + ldm r13, {r3-r6} + stmia r13!, {r9-r12} // Store in stack + ldr r7, [r1] + stmia r2!, {r3-r6} // Storing c0 + + // T3 = a1 * b0 + add r13, r13, #16 + ldm r0!, {r3-r6} + mov r10, #0 + mov r11, #0 + mov r12, #0 + umull r9, r8, r7, r3 + umlal r8, r10, r7, r4 + umlal r10, r11, r7, r5 + umlal r11, r12, r7, r6 + ldr r7, [r1, #4] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #8] + str r8, [r13], #4 // Store in stack + mov r8, #0 + + umlal r9, r8, r7, r3 + umaal r8, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #12] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + + // c1 = T2 + T3 = a0*b1 + a1*b0 + sub r13, r13, #28 + ldmia r13!, {r3-r6} + ldmia r13, {r0-r1,r7} + sub r13, r13, #32 + adds r3, r3, r0 + adcs r4, r4, r1 + adcs r5, r5, r7 + adcs r6, r6, r8 + ldmia r13!, {r7-r8} + ldmia r13!, {r0-r1} + adcs r7, r7, r9 + adcs r8, r8, r10 + adcs r9, r0, r11 + adcs r10, r1, r12 + + // Reducing and storing c1 + lsl r10, r10, #1 + orr r10, r10, r9, lsr #31 + lsl r9, r9, #1 + orr r9, r9, r8, lsr #31 + lsl r8, r8, #1 + orr r8, r8, r7, lsr #31 + lsl r7, r7, #1 + orr r7, r7, r6, lsr #31 + and r6, r6, #0x7FFFFFFF + + lsls r10, r10, #1 + adcs r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10, lsr #1 + + and r7, r6, #0x7FFFFFFF + adds r3, r3, r6, lsr #31 + adcs r4, r4, #0 + adcs r5, r5, #0 + adcs r6, r7, #0 + stmia r2!, {r3-r6} // Storing c1 + + add r13, r13, #28 // Restoring stack + pop {r4-r12} + bx lr + + +//*********************************************************************** +// Squaring over GF(p^2) +// Operation: c [reg_p2] = a^2 [reg_p1] +//*********************************************************************** +.global fp2sqr1271_a +.type fp2sqr1271_a, %function +fp2sqr1271_a: + push {r4-r12} + sub r13, r13, #16 // Allocating space in the stack + + // t0 = a0 + a1 + ldm r0, {r2-r9} + adds r2, r2, r6 + adcs r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + stm r13, {r2-r5} // Store in stack + + // t1 = a0 - a1 + ldm r0, {r2-r5} + subs r2, r2, r6 + sbcs r3, r3, r7 + sbcs r4, r4, r8 + sbcs r5, r5, r9 + + and r6, r5, #0x7FFFFFFF + subs r2, r2, r5, lsr #31 + sbcs r3, r3, #0 + sbcs r4, r4, #0 + sbcs r5, r6, #0 + + // T0 = t0 * t1 = (a0 + a1)*(a0 - a1) + ldr r12, [r13] + mov r9, #0 + mov r10, #0 + mov r11, #0 + umull r6, r7, r12, r2 + umlal r7, r9, r12, r3 + umlal r9, r10, r12, r4 + umlal r10, r11, r12, r5 + ldr r12, [r13, #4] + str r6, [r13] // Store in stack + mov r6, #0 + + umlal r7, r6, r12, r2 + umaal r6, r9, r12, r3 + umaal r9, r10, r12, r4 + umaal r10, r11, r12, r5 + ldr r12, [r13, #8] + str r7, [r13, #4] // Store in stack + mov r7, #0 + + umlal r6, r7, r12, r2 + umaal r7, r9, r12, r3 + umaal r9, r10, r12, r4 + umaal r10, r11, r12, r5 + ldr r12, [r13, #12] + mov r8, #0 + + umlal r7, r8, r12, r2 + umaal r8, r9, r12, r3 + umaal r9, r10, r12, r4 + umaal r10, r11, r12, r5 + + // Reduction + lsl r11, r11, #1 + orr r11, r11, r10, lsr #31 + lsl r10, r10, #1 + orr r10, r10, r9, lsr #31 + lsl r9, r9, #1 + orr r9, r9, r8, lsr #31 + lsl r8, r8, #1 + orr r8, r8, r7, lsr #31 + ldm r13, {r4,r5} + and r7, r7, #0x7FFFFFFF + + lsls r11, r11, #1 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10 + adcs r7, r7, r11, lsr #1 + + and r8, r7, #0x7FFFFFFF + adds r9, r4, r7, lsr #31 + adcs r10, r5, #0 + ldm r0, {r2-r5} + adcs r11, r6, #0 + adcs r12, r8, #0 + + // t0 = 2*a0 + adds r2, r2, r2 + adcs r3, r3, r3 + adcs r4, r4, r4 + adcs r5, r5, r5 + + stmia r1!, {r9-r12} // Storing c0 + + // T1 = 2a0 * a1 + ldr r12, [r0, #16] + mov r9, #0 + mov r10, #0 + mov r11, #0 + umull r6, r7, r12, r2 + umlal r7, r9, r12, r3 + umlal r9, r10, r12, r4 + umlal r10, r11, r12, r5 + ldr r12, [r0, #20] + str r6, [r13] // Store in stack + mov r6, #0 + + umlal r7, r6, r12, r2 + umaal r6, r9, r12, r3 + umaal r9, r10, r12, r4 + umaal r10, r11, r12, r5 + ldr r12, [r0, #24] + str r7, [r13, #4] // Store in stack + mov r7, #0 + + umlal r6, r7, r12, r2 + umaal r7, r9, r12, r3 + umaal r9, r10, r12, r4 + umaal r10, r11, r12, r5 + ldr r12, [r0, #28] + mov r8, #0 + + umlal r7, r8, r12, r2 + umaal r8, r9, r12, r3 + umaal r9, r10, r12, r4 + umaal r10, r11, r12, r5 + + // Reduction + lsl r11, r11, #1 + orr r11, r11, r10, lsr #31 + lsl r10, r10, #1 + orr r10, r10, r9, lsr #31 + lsl r9, r9, #1 + orr r9, r9, r8, lsr #31 + lsl r8, r8, #1 + orr r8, r8, r7, lsr #31 + ldm r13, {r4,r5} + and r7, r7, #0x7FFFFFFF + + lsls r11, r11, #1 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10 + adcs r7, r7, r11, lsr #1 + + and r8, r7, #0x7FFFFFFF + adds r4, r4, r7, lsr #31 + adcs r5, r5, #0 + adcs r6, r6, #0 + adcs r7, r8, #0 + stmia r1!, {r4-r7} // Storing c1 + + add r13, r13, #16 // Restoring stack + pop {r4-r12} + bx lr + + +//*********************************************************************** +// Addition over GF(p^2) +// Operation: c [reg_p3] = a [reg_p1] + b [reg_p2] mod p, p = 2^127-1 +//*********************************************************************** +.global fp2add1271_a +.type fp2add1271_a, %function +fp2add1271_a: + push {r4-r10} + ldm r0!, {r3-r4} + ldm r1!, {r7-r8} + ldm r0!, {r5-r6} + ldm r1!, {r9-r10} + adds r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10 + + ldm r1!, {r7-r10} + adds r3, r3, r6, lsr #31 + adcs r4, r4, #0 + adcs r5, r5, #0 + adcs r6, r6, #0 + and r6, r6, #0x7FFFFFFF + + stmia r2!, {r3-r4} + ldm r0!, {r3-r4} + stmia r2!, {r5-r6} + ldm r0!, {r5-r6} + adds r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10 + + and r7, r6, #0x7FFFFFFF + adds r3, r3, r6, lsr #31 + adcs r4, r4, #0 + adcs r5, r5, #0 + adcs r6, r7, #0 + stmia r2!, {r3-r6} + pop {r4-r10} + bx lr + + +//*********************************************************************** +// Subtraction over GF(p^2) +// Operation: c [reg_p3] = a [reg_p1] - b [reg_p2] mod p, p = 2^127-1 +//*********************************************************************** +.global fp2sub1271_a +.type fp2sub1271_a, %function +fp2sub1271_a: + push {r4-r10} + ldm r0!, {r3-r4} + ldm r1!, {r7-r8} + ldm r0!, {r5-r6} + ldm r1!, {r9-r10} + subs r3, r3, r7 + sbcs r4, r4, r8 + sbcs r5, r5, r9 + sbcs r6, r6, r10 + + ldm r1!, {r7-r10} + subs r3, r3, r6, lsr #31 + sbcs r4, r4, #0 + sbcs r5, r5, #0 + sbcs r6, r6, #0 + and r6, r6, #0x7FFFFFFF + + stmia r2!, {r3-r4} + ldm r0!, {r3-r4} + stmia r2!, {r5-r6} + ldm r0!, {r5-r6} + subs r3, r3, r7 + sbcs r4, r4, r8 + sbcs r5, r5, r9 + sbcs r6, r6, r10 + + and r7, r6, #0x7FFFFFFF + subs r3, r3, r6, lsr #31 + sbcs r4, r4, #0 + sbcs r5, r5, #0 + sbcs r6, r7, #0 + stmia r2!, {r3-r6} + pop {r4-r10} + bx lr + + +//*********************************************************************** +// Integer multiplication +// Operation: c [reg_p3] = a [reg_p1] * b [reg_p2] +// Restriction : b != c +//*********************************************************************** +.global mul1271_a +.type mul1271_a, %function +mul1271_a: + push {r4-r12} + ldm r0!, {r3-r6} + ldr r7, [r1] + mov r10, #0 + mov r11, #0 + mov r12, #0 + umull r9, r8, r7, r3 + umlal r8, r10, r7, r4 + umlal r10, r11, r7, r5 + umlal r11, r12, r7, r6 + ldr r7, [r1, #4] + str r9, [r2], #4 + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #8] + str r8, [r2], #4 + mov r8, #0 + + umlal r9, r8, r7, r3 + umaal r8, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #12] + str r9, [r2], #4 + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + stmia r2!, {r8-r12} + pop {r4-r12} + bx lr + + +//*********************************************************************** +// Modular reduction +// Operation: c [reg_p3] = a [reg_p1] mod p, p = 2^127-1 +//*********************************************************************** +.global mod1271_a +.type mod1271_a, %function +mod1271_a: + push {r4-r9} + ldm r0!, {r2-r9} + lsl r9, r9, #1 + orr r9, r9, r8, lsr #31 + lsl r8, r8, #1 + orr r8, r8, r7, lsr #31 + lsl r7, r7, #1 + orr r7, r7, r6, lsr #31 + lsl r6, r6, #1 + orr r6, r6, r5, lsr #31 + + and r5, r5, #0x7FFFFFFF + adds r2, r2, r6 + adcs r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + + and r6, r5, #0x7FFFFFFF + adds r2, r2, r5, lsr #31 + adcs r3, r3, #0 + adcs r4, r4, #0 + adcs r5, r6, #0 + stmia r1!, {r2-r5} + pop {r4-r9} + bx lr + + +//*********************************************************************** +// Field addition +// Operation: c [reg_p3] = a [reg_p1] + b [reg_p2] mod p, p = 2^127-1 +//*********************************************************************** +.global fpadd1271_a +.type fpadd1271_a, %function +fpadd1271_a: + push {r4-r10} + ldm r0!, {r3-r4} + ldm r1!, {r7-r8} + ldm r0!, {r5-r6} + ldm r1!, {r9-r10} + adds r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10 + + and r7, r6, #0x7FFFFFFF + adds r3, r3, r6, lsr #31 + adcs r4, r4, #0 + adcs r5, r5, #0 + adcs r6, r7, #0 + stmia r2!, {r3-r6} + pop {r4-r10} + bx lr + + +//*********************************************************************** +// Field subtraction +// Operation: c [reg_p3] = a [reg_p1] - b [reg_p2] mod p, p = 2^127-1 +//*********************************************************************** +.global fpsub1271_a +.type fpsub1271_a, %function +fpsub1271_a: + push {r4-r10} + ldm r0!, {r3-r4} + ldm r1!, {r7-r8} + ldm r0!, {r5-r6} + ldm r1!, {r9-r10} + subs r3, r3, r7 + sbcs r4, r4, r8 + sbcs r5, r5, r9 + sbcs r6, r6, r10 + + and r7, r6, #0x7FFFFFFF + subs r3, r3, r6, lsr #31 + sbcs r4, r4, #0 + sbcs r5, r5, #0 + sbcs r6, r7, #0 + stmia r2!, {r3-r6} + pop {r4-r10} + bx lr \ No newline at end of file diff --git a/FourQ_ARM_side_channel/ARM/fp2_1271_arm_Cortex-M4.S b/FourQ_ARM_side_channel/ARM/fp2_1271_arm_Cortex-M4.S new file mode 100644 index 0000000..1f27e55 --- /dev/null +++ b/FourQ_ARM_side_channel/ARM/fp2_1271_arm_Cortex-M4.S @@ -0,0 +1,637 @@ +//*********************************************************************************** +// FourQlib: a high-performance crypto library based on the elliptic curve FourQ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Abstract: arithmetic over GF(p^2) using ARMv7-M assembly (Cortex-M4) for Linux +//*********************************************************************************** + +.syntax unified +.cpu cortex-m4 +.thumb + +.text +.align 4 +//*********************************************************************** +// Multiplication over GF(p^2) +// Operation: c [reg_p3] = a [reg_p1] * b [reg_p2] +// Restriction : b != c +//*********************************************************************** +.global fp2mul1271_a +.type fp2mul1271_a, %function +fp2mul1271_a: + push {r4-r12} + sub r13, r13, #44 // Allocating space in the stack + + // T0 = a0 * b0 + ldm r0!, {r3-r6} + ldr r7, [r1] + mov r10, #0 + mov r11, #0 + mov r12, #0 + umull r9, r8, r7, r3 + umlal r8, r10, r7, r4 + umlal r10, r11, r7, r5 + umlal r11, r12, r7, r6 + ldr r7, [r1, #4] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #8] + str r8, [r13], #4 // Store in stack + mov r8, #0 + + umlal r9, r8, r7, r3 + umaal r8, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #12] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + + // T1 = a1 * b1 + ldm r0!, {r3-r6} + ldr r7, [r1, #16] + stmia r13!, {r8-r12} // Store in stack + mov r10, #0 + mov r11, #0 + mov r12, #0 + umull r9, r8, r7, r3 + umlal r8, r10, r7, r4 + umlal r10, r11, r7, r5 + umlal r11, r12, r7, r6 + ldr r7, [r1, #20] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #24] + str r8, [r13], #4 // Store in stack + mov r8, #0 + + umlal r9, r8, r7, r3 + umaal r8, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #28] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + sub r13, r13, #52 + str r0, [r13], #4 + str r1, [r13], #4 + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + + // c0 = T0 - T1 = a0*b0 - a1*b1 + ldmia r13!, {r3-r6} + ldr r0, [r13, #16] + ldr r1, [r13, #20] + ldr r7, [r13, #24] + subs r3, r3, r0 + sbcs r4, r4, r1 + sbcs r5, r5, r7 + sbcs r6, r6, r8 + ldmia r13!, {r7-r8} + ldmia r13!, {r0-r1} + sbcs r7, r7, r9 + sbcs r8, r8, r10 + sbcs r9, r0, r11 + sbcs r10, r1, r12 + sub r13, #40 + pop {r0-r1} + + // Reducing and storing c0 + lsl r10, r10, #1 + orr r10, r10, r9, lsr #31 + lsl r9, r9, #1 + orr r9, r9, r8, lsr #31 + lsl r8, r8, #1 + orr r8, r8, r7, lsr #31 + lsl r7, r7, #1 + orr r7, r7, r6, lsr #31 + and r6, r6, #0x7FFFFFFF + + subs r7, r7, r10, lsr #31 + sbcs r8, r8, #0 + sbcs r9, r9, #0 + sbcs r10, r10, #0 + and r10, r10, #0x7FFFFFFF + + adds r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10 + + and r7, r6, #0x7FFFFFFF + adds r3, r3, r6, lsr #31 + adcs r4, r4, #0 + adcs r5, r5, #0 + adcs r6, r7, #0 + stm r13, {r3-r6} + add r13, r13, #16 + + // T2 = a0 * b1 + sub r0, r0, #32 + ldm r0!, {r3-r6} + ldr r7, [r1, #16] + mov r10, #0 + mov r11, #0 + mov r12, #0 + umull r9, r8, r7, r3 + umlal r8, r10, r7, r4 + umlal r10, r11, r7, r5 + umlal r11, r12, r7, r6 + ldr r7, [r1, #20] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #24] + str r8, [r13], #4 // Store in stack + mov r8, #0 + + umlal r9, r8, r7, r3 + umaal r8, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #28] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + str r8, [r13], #4 + + sub r13, r13, #32 + ldm r13, {r3-r6} + stmia r13!, {r9-r12} // Store in stack + ldr r7, [r1] + stmia r2!, {r3-r6} // Storing c0 + + // T3 = a1 * b0 + add r13, r13, #16 + ldm r0!, {r3-r6} + mov r10, #0 + mov r11, #0 + mov r12, #0 + umull r9, r8, r7, r3 + umlal r8, r10, r7, r4 + umlal r10, r11, r7, r5 + umlal r11, r12, r7, r6 + ldr r7, [r1, #4] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #8] + str r8, [r13], #4 // Store in stack + mov r8, #0 + + umlal r9, r8, r7, r3 + umaal r8, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #12] + str r9, [r13], #4 // Store in stack + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + + // c1 = T2 + T3 = a0*b1 + a1*b0 + sub r13, r13, #28 + ldmia r13!, {r3-r6} + ldm r13, {r0-r1,r7} + sub r13, r13, #32 + adds r3, r3, r0 + adcs r4, r4, r1 + adcs r5, r5, r7 + adcs r6, r6, r8 + ldmia r13!, {r7-r8} + ldmia r13!, {r0-r1} + adcs r7, r7, r9 + adcs r8, r8, r10 + adcs r9, r0, r11 + adcs r10, r1, r12 + + // Reducing and storing c1 + lsl r10, r10, #1 + orr r10, r10, r9, lsr #31 + lsl r9, r9, #1 + orr r9, r9, r8, lsr #31 + lsl r8, r8, #1 + orr r8, r8, r7, lsr #31 + lsl r7, r7, #1 + orr r7, r7, r6, lsr #31 + and r6, r6, #0x7FFFFFFF + + lsls r10, r10, #1 + adcs r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10, lsr #1 + + and r7, r6, #0x7FFFFFFF + adds r3, r3, r6, lsr #31 + adcs r4, r4, #0 + adcs r5, r5, #0 + adcs r6, r7, #0 + stmia r2!, {r3-r6} // Storing c1 + + add r13, r13, #28 // Restoring stack + pop {r4-r12} + bx lr + + +//*********************************************************************** +// Squaring over GF(p^2) +// Operation: c [reg_p2] = a^2 [reg_p1] +//*********************************************************************** +.global fp2sqr1271_a +.type fp2sqr1271_a, %function +fp2sqr1271_a: + push {r4-r12} + sub r13, r13, #16 // Allocating space in the stack + + // t0 = a0 + a1 + ldm r0, {r2-r9} + adds r2, r2, r6 + adcs r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + stm r13, {r2-r5} // Store in stack + + // t1 = a0 - a1 + ldm r0, {r2-r5} + subs r2, r2, r6 + sbcs r3, r3, r7 + sbcs r4, r4, r8 + sbcs r5, r5, r9 + + and r6, r5, #0x7FFFFFFF + subs r2, r2, r5, lsr #31 + sbcs r3, r3, #0 + sbcs r4, r4, #0 + sbcs r5, r6, #0 + + // T0 = t0 * t1 = (a0 + a1)*(a0 - a1) + ldr r12, [r13] + mov r9, #0 + mov r10, #0 + mov r11, #0 + umull r6, r7, r12, r2 + umlal r7, r9, r12, r3 + umlal r9, r10, r12, r4 + umlal r10, r11, r12, r5 + ldr r12, [r13, #4] + str r6, [r13] // Store in stack + mov r6, #0 + + umlal r7, r6, r12, r2 + umaal r6, r9, r12, r3 + umaal r9, r10, r12, r4 + umaal r10, r11, r12, r5 + ldr r12, [r13, #8] + str r7, [r13, #4] // Store in stack + mov r7, #0 + + umlal r6, r7, r12, r2 + umaal r7, r9, r12, r3 + umaal r9, r10, r12, r4 + umaal r10, r11, r12, r5 + ldr r12, [r13, #12] + mov r8, #0 + + umlal r7, r8, r12, r2 + umaal r8, r9, r12, r3 + umaal r9, r10, r12, r4 + umaal r10, r11, r12, r5 + + // Reduction + lsl r11, r11, #1 + orr r11, r11, r10, lsr #31 + lsl r10, r10, #1 + orr r10, r10, r9, lsr #31 + lsl r9, r9, #1 + orr r9, r9, r8, lsr #31 + lsl r8, r8, #1 + orr r8, r8, r7, lsr #31 + ldm r13, {r4,r5} + and r7, r7, #0x7FFFFFFF + + lsls r11, r11, #1 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10 + adcs r7, r7, r11, lsr #1 + + and r8, r7, #0x7FFFFFFF + adds r9, r4, r7, lsr #31 + adcs r10, r5, #0 + ldm r0, {r2-r5} + adcs r11, r6, #0 + adcs r12, r8, #0 + + // t0 = 2*a0 + adds r2, r2, r2 + adcs r3, r3, r3 + adcs r4, r4, r4 + adcs r5, r5, r5 + + stmia r1!, {r9-r12} // Storing c0 + + // T1 = 2a0 * a1 + ldr r12, [r0, #16] + mov r9, #0 + mov r10, #0 + mov r11, #0 + umull r6, r7, r12, r2 + umlal r7, r9, r12, r3 + umlal r9, r10, r12, r4 + umlal r10, r11, r12, r5 + ldr r12, [r0, #20] + str r6, [r13] // Store in stack + mov r6, #0 + + umlal r7, r6, r12, r2 + umaal r6, r9, r12, r3 + umaal r9, r10, r12, r4 + umaal r10, r11, r12, r5 + ldr r12, [r0, #24] + str r7, [r13, #4] // Store in stack + mov r7, #0 + + umlal r6, r7, r12, r2 + umaal r7, r9, r12, r3 + umaal r9, r10, r12, r4 + umaal r10, r11, r12, r5 + ldr r12, [r0, #28] + mov r8, #0 + + umlal r7, r8, r12, r2 + umaal r8, r9, r12, r3 + umaal r9, r10, r12, r4 + umaal r10, r11, r12, r5 + + // Reduction + lsl r11, r11, #1 + orr r11, r11, r10, lsr #31 + lsl r10, r10, #1 + orr r10, r10, r9, lsr #31 + lsl r9, r9, #1 + orr r9, r9, r8, lsr #31 + lsl r8, r8, #1 + orr r8, r8, r7, lsr #31 + ldm r13, {r4,r5} + and r7, r7, #0x7FFFFFFF + + lsls r11, r11, #1 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10 + adcs r7, r7, r11, lsr #1 + + and r8, r7, #0x7FFFFFFF + adds r4, r4, r7, lsr #31 + adcs r5, r5, #0 + adcs r6, r6, #0 + adcs r7, r8, #0 + stmia r1!, {r4-r7} // Storing c1 + + add r13, r13, #16 // Restoring stack + pop {r4-r12} + bx lr + + +//*********************************************************************** +// Addition over GF(p^2) +// Operation: c [reg_p3] = a [reg_p1] + b [reg_p2] mod p, p = 2^127-1 +//*********************************************************************** +.global fp2add1271_a +.type fp2add1271_a, %function +fp2add1271_a: + push {r4-r10} + ldm r0!, {r3-r6} + ldm r1!, {r7-r10} + adds r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10 + + ldm r1!, {r7-r10} + adds r3, r3, r6, lsr #31 + adcs r4, r4, #0 + adcs r5, r5, #0 + adcs r6, r6, #0 + and r6, r6, #0x7FFFFFFF + + stmia r2!, {r3-r6} + ldm r0!, {r3-r6} + adds r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10 + + and r7, r6, #0x7FFFFFFF + adds r3, r3, r6, lsr #31 + adcs r4, r4, #0 + adcs r5, r5, #0 + adcs r6, r7, #0 + stmia r2!, {r3-r6} + pop {r4-r10} + bx lr + + +//*********************************************************************** +// Subtraction over GF(p^2) +// Operation: c [reg_p3] = a [reg_p1] - b [reg_p2] mod p, p = 2^127-1 +//*********************************************************************** +.global fp2sub1271_a +.type fp2sub1271_a, %function +fp2sub1271_a: + push {r4-r10} + ldm r0!, {r3-r6} + ldm r1!, {r7-r10} + subs r3, r3, r7 + sbcs r4, r4, r8 + sbcs r5, r5, r9 + sbcs r6, r6, r10 + + ldm r1!, {r7-r10} + subs r3, r3, r6, lsr #31 + sbcs r4, r4, #0 + sbcs r5, r5, #0 + sbcs r6, r6, #0 + and r6, r6, #0x7FFFFFFF + + stmia r2!, {r3-r6} + ldm r0!, {r3-r6} + subs r3, r3, r7 + sbcs r4, r4, r8 + sbcs r5, r5, r9 + sbcs r6, r6, r10 + + and r7, r6, #0x7FFFFFFF + subs r3, r3, r6, lsr #31 + sbcs r4, r4, #0 + sbcs r5, r5, #0 + sbcs r6, r7, #0 + stmia r2!, {r3-r6} + pop {r4-r10} + bx lr + + +//*********************************************************************** +// Integer multiplication +// Operation: c [reg_p3] = a [reg_p1] * b [reg_p2] +// Restriction : b != c +//*********************************************************************** +.global mul1271_a +.type mul1271_a, %function +mul1271_a: + push {r4-r12} + ldm r0!, {r3-r6} + ldr r7, [r1] + mov r10, #0 + mov r11, #0 + mov r12, #0 + umull r9, r8, r7, r3 + umlal r8, r10, r7, r4 + umlal r10, r11, r7, r5 + umlal r11, r12, r7, r6 + ldr r7, [r1, #4] + str r9, [r2], #4 + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #8] + str r8, [r2], #4 + mov r8, #0 + + umlal r9, r8, r7, r3 + umaal r8, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + ldr r7, [r1, #12] + str r9, [r2], #4 + mov r9, #0 + + umlal r8, r9, r7, r3 + umaal r9, r10, r7, r4 + umaal r10, r11, r7, r5 + umaal r11, r12, r7, r6 + stmia r2!, {r8-r12} + pop {r4-r12} + bx lr + + +//*********************************************************************** +// Modular reduction +// Operation: c [reg_p3] = a [reg_p1] mod p, p = 2^127-1 +//*********************************************************************** +.global mod1271_a +.type mod1271_a, %function +mod1271_a: + push {r4-r9} + ldm r0!, {r2-r9} + lsl r9, r9, #1 + orr r9, r9, r8, lsr #31 + lsl r8, r8, #1 + orr r8, r8, r7, lsr #31 + lsl r7, r7, #1 + orr r7, r7, r6, lsr #31 + lsl r6, r6, #1 + orr r6, r6, r5, lsr #31 + + and r5, r5, #0x7FFFFFFF + adds r2, r2, r6 + adcs r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + + and r6, r5, #0x7FFFFFFF + adds r2, r2, r5, lsr #31 + adcs r3, r3, #0 + adcs r4, r4, #0 + adcs r5, r6, #0 + stmia r1!, {r2-r5} + pop {r4-r9} + bx lr + + +//*********************************************************************** +// Field addition +// Operation: c [reg_p3] = a [reg_p1] + b [reg_p2] mod p, p = 2^127-1 +//*********************************************************************** +.global fpadd1271_a +.type fpadd1271_a, %function +fpadd1271_a: + push {r4-r10} + ldm r0!, {r3-r6} + ldm r1!, {r7-r10} + adds r3, r3, r7 + adcs r4, r4, r8 + adcs r5, r5, r9 + adcs r6, r6, r10 + + and r7, r6, #0x7FFFFFFF + adds r3, r3, r6, lsr #31 + adcs r4, r4, #0 + adcs r5, r5, #0 + adcs r6, r7, #0 + stmia r2!, {r3-r6} + pop {r4-r10} + bx lr + + +//*********************************************************************** +// Field subtraction +// Operation: c [reg_p3] = a [reg_p1] - b [reg_p2] mod p, p = 2^127-1 +//*********************************************************************** +.global fpsub1271_a +.type fpsub1271_a, %function +fpsub1271_a: + push {r4-r10} + ldm r0!, {r3-r6} + ldm r1!, {r7-r10} + subs r3, r3, r7 + sbcs r4, r4, r8 + sbcs r5, r5, r9 + sbcs r6, r6, r10 + + and r7, r6, #0x7FFFFFFF + subs r3, r3, r6, lsr #31 + sbcs r4, r4, #0 + sbcs r5, r5, #0 + sbcs r6, r7, #0 + stmia r2!, {r3-r6} + pop {r4-r10} + bx lr \ No newline at end of file diff --git a/FourQ_ARM_side_channel/ARM/fp_arm.h b/FourQ_ARM_side_channel/ARM/fp_arm.h new file mode 100644 index 0000000..28c2777 --- /dev/null +++ b/FourQ_ARM_side_channel/ARM/fp_arm.h @@ -0,0 +1,363 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: modular arithmetic and other low-level operations for ARM processors +************************************************************************************/ + +#ifndef __FP_ARM_H__ +#define __FP_ARM_H__ + + +// For C++ +#ifdef __cplusplus +extern "C" { +#endif + + +#include "../table_lookup.h" + +const digit_t mask_7fff = (digit_t)(-1) >> 1; +const digit_t prime1271_0 = (digit_t)(-1); +#define prime1271_1 mask_7fff + + +void digit_x_digit(digit_t a, digit_t b, digit_t* c) +{ // Digit multiplication, digit * digit -> 2-digit result + register digit_t al, ah, bl, bh, temp; + digit_t albl, albh, ahbl, ahbh, res1, res2, res3, carry; + digit_t mask_low = (digit_t)(-1) >> (sizeof(digit_t)*4), mask_high = (digit_t)(-1) << (sizeof(digit_t)*4); + + al = a & mask_low; // Low part + ah = a >> (sizeof(digit_t) * 4); // High part + bl = b & mask_low; + bh = b >> (sizeof(digit_t) * 4); + + albl = al*bl; + albh = al*bh; + ahbl = ah*bl; + ahbh = ah*bh; + c[0] = albl & mask_low; // C00 + + res1 = albl >> (sizeof(digit_t) * 4); + res2 = ahbl & mask_low; + res3 = albh & mask_low; + temp = res1 + res2 + res3; + carry = temp >> (sizeof(digit_t) * 4); + c[0] ^= temp << (sizeof(digit_t) * 4); // C01 + + res1 = ahbl >> (sizeof(digit_t) * 4); + res2 = albh >> (sizeof(digit_t) * 4); + res3 = ahbh & mask_low; + temp = res1 + res2 + res3 + carry; + c[1] = temp & mask_low; // C10 + carry = temp & mask_high; + c[1] ^= (ahbh & mask_high) + carry; // C11 +} + + +__inline void fpcopy1271(felm_t a, felm_t c) +{ // Copy of a field element, c = a + unsigned int i; + + for (i = 0; i < NWORDS_FIELD; i++) + c[i] = a[i]; +} + + +static __inline void fpzero1271(felm_t a) +{ // Zeroing a field element, a = 0 + unsigned int i; + + for (i = 0; i < NWORDS_FIELD; i++) + a[i] = 0; +} + + +__inline void fpadd1271(felm_t a, felm_t b, felm_t c) +{ // Field addition, c = a+b mod p + + fpadd1271_a(a, b, c); +} + + +__inline void fpsub1271(felm_t a, felm_t b, felm_t c) +{ // Field subtraction, c = a-b mod p + + fpsub1271_a(a, b, c); +} + + +__inline void fpneg1271(felm_t a) +{ // Field negation, a = -a mod p + unsigned int i; + unsigned int borrow = 0; + + for (i = 0; i < (NWORDS_FIELD-1); i++) { + SUBC(borrow, prime1271_0, a[i], borrow, a[i]); + } + a[NWORDS_FIELD-1] = prime1271_1 - a[NWORDS_FIELD-1]; +} + + +void fpmul1271(felm_t a, felm_t b, felm_t c) +{ // Field multiplication using schoolbook method, c = a*b mod p + digit_t t[2*NWORDS_FIELD] = {0}; + + mul1271_a(a, b, t); + mod1271_a(t, c); +} + + +void fpsqr1271(felm_t a, felm_t c) +{ // Field squaring using schoolbook method, c = a^2 mod p + + fpmul1271(a, a, c); +} + + +void mod1271(felm_t a) +{ // Modular correction, a = a mod (2^127-1) + digit_t mask; + unsigned int i; + unsigned int borrow = 0; + + for (i = 0; i < (NWORDS_FIELD-1); i++) { + SUBC(borrow, a[i], prime1271_0, borrow, a[i]); + } + SUBC(borrow, a[NWORDS_FIELD-1], prime1271_1, borrow, a[NWORDS_FIELD-1]); + + mask = 0 - (digit_t)borrow; // If result < 0 then mask = 0xFF...F else sign = 0x00...0 + borrow = 0; + for (i = 0; i < (NWORDS_FIELD-1); i++) { + ADDC(borrow, a[i], mask, borrow, a[i]); + } + ADDC(borrow, a[NWORDS_FIELD-1], (mask >> 1), borrow, a[NWORDS_FIELD-1]); +} + + +void mp_mul(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords) +{ // Schoolbook multiprecision multiply, c = a*b + unsigned int i, j; + digit_t u, v, UV[2]; + unsigned int carry = 0; + + for (i = 0; i < (2*nwords); i++) c[i] = 0; + + for (i = 0; i < nwords; i++) { + u = 0; + for (j = 0; j < nwords; j++) { + MUL(a[i], b[j], UV+1, UV[0]); + ADDC(0, UV[0], u, carry, v); + u = UV[1] + carry; + ADDC(0, c[i+j], v, carry, v); + u = u + carry; + c[i+j] = v; + } + c[nwords+i] = u; + } +} + + +unsigned int mp_add(digit_t* a, digit_t* b, digit_t* c, unsigned int nwords) +{ // Multiprecision addition, c = a+b, where lng(a) = lng(b) = nwords. Returns the carry bit + unsigned int i, carry = 0; + + for (i = 0; i < nwords; i++) { + ADDC(carry, a[i], b[i], carry, c[i]); + } + + return carry; +} + + +__inline void fpexp1251(felm_t a, felm_t af) +{ // Exponentiation over GF(p), af = a^(125-1) + int i; + felm_t t1, t2, t3, t4, t5; + + fpsqr1271(a, t2); + fpmul1271(a, t2, t2); + fpsqr1271(t2, t3); + fpsqr1271(t3, t3); + fpmul1271(t2, t3, t3); + fpsqr1271(t3, t4); + fpsqr1271(t4, t4); + fpsqr1271(t4, t4); + fpsqr1271(t4, t4); + fpmul1271(t3, t4, t4); + fpsqr1271(t4, t5); + for (i = 0; i<7; i++) fpsqr1271(t5, t5); + fpmul1271(t4, t5, t5); + fpsqr1271(t5, t2); + for (i = 0; i<15; i++) fpsqr1271(t2, t2); + fpmul1271(t5, t2, t2); + fpsqr1271(t2, t1); + for (i = 0; i<31; i++) fpsqr1271(t1, t1); + fpmul1271(t2, t1, t1); + for (i = 0; i<32; i++) fpsqr1271(t1, t1); + fpmul1271(t1, t2, t1); + for (i = 0; i<16; i++) fpsqr1271(t1, t1); + fpmul1271(t5, t1, t1); + for (i = 0; i<8; i++) fpsqr1271(t1, t1); + fpmul1271(t4, t1, t1); + for (i = 0; i<4; i++) fpsqr1271(t1, t1); + fpmul1271(t3, t1, t1); + fpsqr1271(t1, t1); + fpmul1271(a, t1, af); +} + + +void fpinv1271(felm_t a) +{ // Field inversion, af = a^-1 = a^(p-2) mod p + // Hardcoded for p = 2^127-1 + felm_t t; + + fpexp1251(a, t); + fpsqr1271(t, t); + fpsqr1271(t, t); + fpmul1271(a, t, a); +} + + +static __inline void multiply(const digit_t* a, const digit_t* b, digit_t* c) +{ // Schoolbook multiprecision multiply, c = a*b + + mp_mul(a, b, c, NWORDS_ORDER); +} + + +static __inline unsigned int add(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords) +{ // Multiprecision addition, c = a+b, where lng(a) = lng(b) = nwords. Returns the carry bit + + return mp_add((digit_t*)a, (digit_t*)b, c, (unsigned int)nwords); +} + + +unsigned int subtract(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords) +{ // Multiprecision subtraction, c = a-b, where lng(a) = lng(b) = nwords. Returns the borrow bit + unsigned int i; + unsigned int borrow = 0; + + for (i = 0; i < nwords; i++) { + SUBC(borrow, a[i], b[i], borrow, c[i]); + } + + return borrow; +} + + +void subtract_mod_order(const digit_t* a, const digit_t* b, digit_t* c) +{ // Subtraction modulo the curve order, c = a-b mod order + digit_t mask, carry = 0; + digit_t* order = (digit_t*)curve_order; + unsigned int i, bout; + + bout = subtract(a, b, c, NWORDS_ORDER); // (bout, c) = a - b + mask = 0 - (digit_t)bout; // if bout = 0 then mask = 0x00..0, else if bout = 1 then mask = 0xFF..F + + for (i = 0; i < NWORDS_ORDER; i++) { // c = c + (mask & order) + ADDC(carry, c[i], mask & order[i], carry, c[i]); + } +} + + +void add_mod_order(const digit_t* a, const digit_t* b, digit_t* c) +{ // Addition modulo the curve order, c = a+b mod order + + add(a, b, c, NWORDS_ORDER); // c = a + b + subtract_mod_order(c, (digit_t*)&curve_order, c); // if c >= order then c = c - order +} + + +void Montgomery_multiply_mod_order(const digit_t* ma, const digit_t* mb, digit_t* mc) +{ // 256-bit Montgomery multiplication modulo the curve order, mc = ma*mb*r' mod order, where ma,mb,mc in [0, order-1] + // ma, mb and mc are assumed to be in Montgomery representation + // The Montgomery constant r' = -r^(-1) mod 2^(log_2(r)) is the global value "Montgomery_rprime", where r is the order + unsigned int i; + digit_t mask, P[2*NWORDS_ORDER], Q[2*NWORDS_ORDER], temp[2*NWORDS_ORDER]; + digit_t* order = (digit_t*)curve_order; + unsigned int cout = 0, bout = 0; + + multiply(ma, mb, P); // P = ma * mb + multiply(P, (digit_t*)&Montgomery_rprime, Q); // Q = P * r' mod 2^(log_2(r)) + multiply(Q, (digit_t*)&curve_order, temp); // temp = Q * r + cout = add(P, temp, temp, 2*NWORDS_ORDER); // (cout, temp) = P + Q * r + + for (i = 0; i < NWORDS_ORDER; i++) { // (cout, mc) = (P + Q * r)/2^(log_2(r)) + mc[i] = temp[NWORDS_ORDER + i]; + } + + // Final, constant-time subtraction + bout = subtract(mc, (digit_t*)&curve_order, mc, NWORDS_ORDER); // (cout, mc) = (cout, mc) - r + mask = (digit_t)cout - (digit_t)bout; // if (cout, mc) >= 0 then mask = 0x00..0, else if (cout, mc) < 0 then mask = 0xFF..F + + for (i = 0; i < NWORDS_ORDER; i++) { // temp = mask & r + temp[i] = (order[i] & mask); + } + add(mc, temp, mc, NWORDS_ORDER); // mc = mc + (mask & r) + + return; +} + + +void modulo_order(digit_t* a, digit_t* c) +{ // Reduction modulo the order using Montgomery arithmetic + // ma = a*Montgomery_Rprime mod r, where a,ma in [0, r-1], a,ma,r < 2^256 + // c = ma*1*Montgomery_Rprime^(-1) mod r, where ma,c in [0, r-1], ma,c,r < 2^256 + digit_t ma[NWORDS_ORDER], one[NWORDS_ORDER] = {0}; + + one[0] = 1; + Montgomery_multiply_mod_order(a, (digit_t*)&Montgomery_Rprime, ma); + Montgomery_multiply_mod_order(ma, one, c); +} + + +void conversion_to_odd(digit_t* k, digit_t* k_odd) +{// Convert scalar to odd if even using the prime subgroup order r + digit_t i, mask; + digit_t* order = (digit_t*)curve_order; + unsigned int carry = 0; + + mask = ~(0 - (k[0] & 1)); + + for (i = 0; i < NWORDS_ORDER; i++) { // If (k is odd) then k_odd = k else k_odd = k + r + ADDC(carry, order[i] & mask, k[i], carry, k_odd[i]); + } +} + + +__inline void fpdiv1271(felm_t a) +{ // Field division by two, c = a/2 mod p + digit_t mask; + unsigned int carry = 0; + unsigned int i; + + mask = 0 - (a[0] & 1); // if a is odd then mask = 0xFF...FF, else mask = 0 + + for (i = 0; i < (NWORDS_FIELD-1); i++) { + ADDC(carry, mask, a[i], carry, a[i]); + } + ADDC(carry, (mask >> 1), a[NWORDS_FIELD-1], carry, a[NWORDS_FIELD-1]); + + for (i = 0; i < (NWORDS_FIELD-1); i++) { + SHIFTR(a[i+1], a[i], 1, a[i], RADIX); + } + a[NWORDS_FIELD-1] = (a[NWORDS_FIELD-1] >> 1); +} + + +void fp2div1271(f2elm_t a) +{ // GF(p^2) division by two c = a/2 mod p + fpdiv1271(a[0]); + fpdiv1271(a[1]); +} + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/FourQ_ARM_side_channel/FourQ.h b/FourQ_ARM_side_channel/FourQ.h new file mode 100644 index 0000000..20d74d4 --- /dev/null +++ b/FourQ_ARM_side_channel/FourQ.h @@ -0,0 +1,140 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: main header file +* +* This code is based on the paper "FourQ: four-dimensional decompositions on a +* Q-curve over the Mersenne prime" by Craig Costello and Patrick Longa, in Advances +* in Cryptology - ASIACRYPT, 2015. +* Preprint available at http://eprint.iacr.org/2015/565. +************************************************************************************/ + +#ifndef __FOURQ_H__ +#define __FOURQ_H__ + + +// For C++ +#ifdef __cplusplus +extern "C" { +#endif + + +#include +#include + + +// Definition of operating system + +#define OS_LINUX 1 + +#if defined(__LINUX__) // Linux OS + #define OS_TARGET OS_LINUX +#else + #error -- "Unsupported OS" +#endif + + +// Definition of compiler + +#define COMPILER_GCC 1 +#define COMPILER_CLANG 2 + +#if defined(__GNUC__) // GNU GCC compiler + #define COMPILER COMPILER_GCC +#elif defined(__clang__) // Clang compiler + #define COMPILER COMPILER_CLANG +#else + #error -- "Unsupported COMPILER" +#endif + + +// Definition of the targeted architecture and basic data types + +#define TARGET_ARM 1 + +#if defined(_ARM_) + #define TARGET TARGET_ARM + #define RADIX 32 + typedef uint32_t digit_t; // Unsigned 32-bit digit + typedef int32_t sdigit_t; // Signed 32-bit digit + #define NWORDS_FIELD 4 + #define NWORDS_ORDER 8 +#else + #error -- "Unsupported ARCHITECTURE" +#endif + + +// Constants + +#define RADIX64 64 +#define NWORDS64_FIELD 2 // Number of 64-bit words of a field element +#define NWORDS64_ORDER 4 // Number of 64-bit words of an element in Z_r + + +// Definition of complementary cryptographic functions + +#define RandomBytesFunction random_bytes +#define CryptoHashFunction crypto_sha512 // Use SHA-512 by default + + +// Basic parameters for fixed-base scalar multiplication +#define W_FIXEDBASE 5 // Memory requirement: 7.5KB (storage for 80 points). +#define V_FIXEDBASE 5 + +// Basic parameters for double scalar multiplication +#define WP_DOUBLEBASE 8 // Memory requirement: 24KB (storage for 256 points). +#define WQ_DOUBLEBASE 4 + + +// Full table randomization selection for additional protection against side-channel attacks +//#define FULL_TABLE_RANDOMIZATION + + +// FourQ's basic element definitions and point representations + +typedef digit_t felm_t[NWORDS_FIELD]; // Datatype for representing 128-bit field elements +typedef felm_t f2elm_t[2]; // Datatype for representing quadratic extension field elements + +typedef struct { f2elm_t x; f2elm_t y; } point_affine; // Point representation in affine coordinates. +typedef point_affine point_t[1]; + + +// Definitions of the error-handling type and error codes + +typedef enum { + ECCRYPTO_ERROR, // 0x00 + ECCRYPTO_SUCCESS, // 0x01 + ECCRYPTO_ERROR_DURING_TEST, // 0x02 + ECCRYPTO_ERROR_UNKNOWN, // 0x03 + ECCRYPTO_ERROR_NOT_IMPLEMENTED, // 0x04 + ECCRYPTO_ERROR_NO_MEMORY, // 0x05 + ECCRYPTO_ERROR_INVALID_PARAMETER, // 0x06 + ECCRYPTO_ERROR_SHARED_KEY, // 0x07 + ECCRYPTO_ERROR_SIGNATURE_VERIFICATION, // 0x08 + ECCRYPTO_ERROR_END_OF_LIST +} ECCRYPTO_STATUS; + +#define ECCRYPTO_STATUS_TYPE_SIZE (ECCRYPTO_ERROR_END_OF_LIST) + + +// Error message definitions + +#define ECCRYPTO_MSG_ERROR "ECCRYPTO_ERROR" +#define ECCRYPTO_MSG_SUCCESS "ECCRYPTO_SUCCESS" +#define ECCRYPTO_MSG_ERROR_DURING_TEST "ECCRYPTO_ERROR_DURING_TEST" +#define ECCRYPTO_MSG_ERROR_UNKNOWN "ECCRYPTO_ERROR_UNKNOWN" +#define ECCRYPTO_MSG_ERROR_NOT_IMPLEMENTED "ECCRYPTO_ERROR_NOT_IMPLEMENTED" +#define ECCRYPTO_MSG_ERROR_NO_MEMORY "ECCRYPTO_ERROR_NO_MEMORY" +#define ECCRYPTO_MSG_ERROR_INVALID_PARAMETER "ECCRYPTO_ERROR_INVALID_PARAMETER" +#define ECCRYPTO_MSG_ERROR_SHARED_KEY "ECCRYPTO_ERROR_SHARED_KEY" +#define ECCRYPTO_MSG_ERROR_SIGNATURE_VERIFICATION "ECCRYPTO_ERROR_SIGNATURE_VERIFICATION" + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/FourQ_ARM_side_channel/FourQ_api.h b/FourQ_ARM_side_channel/FourQ_api.h new file mode 100644 index 0000000..1fbe404 --- /dev/null +++ b/FourQ_ARM_side_channel/FourQ_api.h @@ -0,0 +1,112 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: API header file +* +* This code is based on the paper "FourQ: four-dimensional decompositions on a +* Q-curve over the Mersenne prime" by Craig Costello and Patrick Longa, in Advances +* in Cryptology - ASIACRYPT, 2015. +* Preprint available at http://eprint.iacr.org/2015/565. +************************************************************************************/ + +#ifndef __FOURQ_API_H__ +#define __FOURQ_API_H__ + + +// For C++ +#ifdef __cplusplus +extern "C" { +#endif + + +#include "FourQ.h" + + +/**************** Public ECC API ****************/ + +// Set generator G = (x,y) +void eccset(point_t G); + +// Variable-base scalar multiplication Q = k*P using a 4-dimensional decomposition and protected against side-channel attacks +bool ecc_mul_SCA_secure(point_t P, point_t R, digit_t* k, point_t Q, bool clear_cofactor); + +// Double scalar multiplication R = k*G + l*Q, where G is the generator +bool ecc_mul_double(digit_t* k, point_t Q, digit_t* l, point_t R); + + +/**************** Public API for SchnorrQ ****************/ + +// SchnorrQ public key generation +// It produces a blinding point BlindingPoint and a public key PublicKey, which is the encoding of P = s*G, where G is the generator and +// s is the output of hashing SecretKey and taking the least significant 32 bytes of the result. +// Input: 32-byte SecretKey +// Output: 32-byte PublicKey and 64-byte BlindingPoint +ECCRYPTO_STATUS SchnorrQ_KeyGeneration_SCA_secure(const unsigned char* SecretKey, unsigned char* PublicKey, unsigned char* BlindingPoint); + +// SchnorrQ keypair generation +// It produces a blinding point BlindingPoint, a private key SecretKey and computes the public key PublicKey, which is the encoding of P = s*G, +// where G is the generator and s is the output of hashing SecretKey and taking the least significant 32 bytes of the result. +// Outputs: 32-byte SecretKey, 32-byte PublicKey and 64-byte BlindingPoint +ECCRYPTO_STATUS SchnorrQ_FullKeyGeneration_SCA_secure(unsigned char* SecretKey, unsigned char* PublicKey, unsigned char* BlindingPoint); + +// SchnorrQ signature generation +// It produces the signature Signature of a message Message of size SizeMessage in bytes +// Inputs: 32-byte SecretKey, 32-byte PublicKey, Message of size SizeMessage in bytes, and 64-byte BlindingPoint +// Output: 64-byte Signature +ECCRYPTO_STATUS SchnorrQ_Sign_SCA_secure(const unsigned char* SecretKey, const unsigned char* PublicKey, const unsigned char* Message, const unsigned int SizeMessage, unsigned char* Signature, unsigned char* BlindingPoint); + +// SchnorrQ signature verification +// It verifies the signature Signature of a message Message of size SizeMessage in bytes +// Inputs: 32-byte PublicKey, 64-byte Signature, and Message of size SizeMessage in bytes +// Output: true (valid signature) or false (invalid signature) +ECCRYPTO_STATUS SchnorrQ_Verify(const unsigned char* PublicKey, const unsigned char* Message, const unsigned int SizeMessage, const unsigned char* Signature, unsigned int* valid); + + +/**************** Public API for co-factor ECDH key exchange with compressed, 32-byte public keys ****************/ + +// Compressed public key generation for key exchange +// It produces a public key PublicKey, which is the encoding of P = SecretKey*G (G is the generator), and a blinding point BlindingPoint. +// Input: 32-byte SecretKey +// Output: 32-byte PublicKey and 64-byte BlindingPoint +ECCRYPTO_STATUS CompressedPublicKeyGeneration_SCA_secure(const unsigned char* SecretKey, unsigned char* PublicKey, unsigned char* BlindingPoint); + +// Keypair generation for key exchange. Public key is compressed to 32 bytes +// It produces a private key SecretKey, a public key PublicKey, which is the encoding of P = SecretKey*G (G is the generator), and a blinding point BlindingPoint. +// Outputs: 32-byte SecretKey, 32-byte PublicKey and 64-byte BlindingPoint +ECCRYPTO_STATUS CompressedKeyGeneration_SCA_secure(unsigned char* SecretKey, unsigned char* PublicKey, unsigned char* BlindingPoint); + +// Secret agreement computation for key exchange using a compressed, 32-byte public key +// The output is the y-coordinate of SecretKey*A, where A is the decoding of the public key PublicKey. +// Inputs: 32-byte SecretKey, 32-byte PublicKey and 64-byte BlindingPoint +// Output: 32-byte SharedSecret +ECCRYPTO_STATUS CompressedSecretAgreement_SCA_secure(const unsigned char* SecretKey, const unsigned char* PublicKey, unsigned char* SharedSecret, unsigned char* BlindingPoint); + + +/**************** Public API for co-factor ECDH key exchange with uncompressed, 64-byte public keys ****************/ + +// Public key generation for key exchange +// It produces the public key PublicKey = SecretKey*G, where G is the generator, and a blinding point BlindingPoint. +// Input: 32-byte SecretKey +// Output: 64-byte PublicKey and 64-byte BlindingPoint +ECCRYPTO_STATUS PublicKeyGeneration_SCA_secure(const unsigned char* SecretKey, unsigned char* PublicKey, unsigned char* BlindingPoint); + +// Keypair generation for key exchange +// It produces a private key SecretKey, the public key PublicKey = SecretKey*G, where G is the generator, and a blinding point BlindingPoint. +// Outputs: 32-byte SecretKey, 64-byte PublicKey and 64-byte BlindingPoint +ECCRYPTO_STATUS KeyGeneration_SCA_secure(unsigned char* SecretKey, unsigned char* PublicKey, unsigned char* BlindingPoint); + +// Secret agreement computation for key exchange +// The output is the y-coordinate of SecretKey*PublicKey. +// Inputs: 32-byte SecretKey, 64-byte PublicKey and 64-byte BlindingPoint +// Output: 32-byte SharedSecret +ECCRYPTO_STATUS SecretAgreement_SCA_secure(const unsigned char* SecretKey, const unsigned char* PublicKey, unsigned char* SharedSecret, unsigned char* BlindingPoint); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/FourQ_ARM_side_channel/FourQ_internal.h b/FourQ_ARM_side_channel/FourQ_internal.h new file mode 100644 index 0000000..4728f15 --- /dev/null +++ b/FourQ_ARM_side_channel/FourQ_internal.h @@ -0,0 +1,331 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: internal header file +* +* This code is based on the paper "FourQ: four-dimensional decompositions on a +* Q-curve over the Mersenne prime" by Craig Costello and Patrick Longa, in Advances +* in Cryptology - ASIACRYPT, 2015. +* Preprint available at http://eprint.iacr.org/2015/565. +************************************************************************************/ + +#ifndef __FOURQ_INTERNAL_H__ +#define __FOURQ_INTERNAL_H__ + + +// For C++ +#ifdef __cplusplus +extern "C" { +#endif + + +#include "FourQ_api.h" + + +// Extended datatype definition + +typedef uint64_t uint128_t[2]; + + +// Basic parameters for fixed-base scalar multiplication +#define NBITS_ORDER_PLUS_ONE 246+1 +#define E_FIXEDBASE (NBITS_ORDER_PLUS_ONE + W_FIXEDBASE*V_FIXEDBASE - 1)/(W_FIXEDBASE*V_FIXEDBASE) +#define D_FIXEDBASE E_FIXEDBASE*V_FIXEDBASE +#define L_FIXEDBASE D_FIXEDBASE*W_FIXEDBASE +#define NPOINTS_FIXEDBASE V_FIXEDBASE*(1 << (W_FIXEDBASE-1)) +#define VPOINTS_FIXEDBASE (1 << (W_FIXEDBASE-1)) +#if (NBITS_ORDER_PLUS_ONE-L_FIXEDBASE == 0) // This parameter selection is not supported + #error -- "Unsupported parameter selection for fixed-base scalar multiplication" +#endif + + +// Basic parameters for double scalar multiplication +#define NPOINTS_DOUBLEMUL_WP (1 << (WP_DOUBLEBASE-2)) +#define NPOINTS_DOUBLEMUL_WQ (1 << (WQ_DOUBLEBASE-2)) + + +// FourQ's point representations + +typedef struct { f2elm_t x; f2elm_t y; f2elm_t z; f2elm_t t; } point_extedwards; // Point representation in extended twisted Edwards coordinates. +typedef point_extedwards point_extedwards_t[1]; +typedef struct { f2elm_t x; f2elm_t y; f2elm_t z; f2elm_t ta; f2elm_t tb; } point_extproj; // Point representation in extended coordinates. +typedef point_extproj point_extproj_t[1]; +typedef struct { f2elm_t xy; f2elm_t yx; f2elm_t z2; f2elm_t t2; } point_extproj_precomp; // Point representation in extended coordinates (for precomputed points). +typedef point_extproj_precomp point_extproj_precomp_t[1]; +typedef struct { f2elm_t xy; f2elm_t yx; f2elm_t t2; } point_precomp; // Point representation in extended affine coordinates (for precomputed points). +typedef point_precomp point_precomp_t[1]; + + +/********************** Constant-time unsigned comparisons ***********************/ + +// The following functions return 1 (TRUE) if condition is true, 0 (FALSE) otherwise + +static __inline unsigned int is_digit_nonzero_ct(digit_t x) +{ // Is x != 0? + return (unsigned int)((x | (0-x)) >> (RADIX-1)); +} + +static __inline unsigned int is_digit_zero_ct(digit_t x) +{ // Is x = 0? + return (unsigned int)(1 ^ is_digit_nonzero_ct(x)); +} + +static __inline unsigned int is_digit_lessthan_ct(digit_t x, digit_t y) +{ // Is x < y? + return (unsigned int)((x ^ ((x ^ y) | ((x - y) ^ y))) >> (RADIX-1)); +} + + +/********************** Macros for digit operations **********************/ + +// Digit multiplication +#define MUL(multiplier, multiplicand, hi, lo) \ + digit_x_digit((multiplier), (multiplicand), &(lo)); + +// Digit addition with carry +#define ADDC(carryIn, addend1, addend2, carryOut, sumOut) \ + { digit_t tempReg = (addend1) + (digit_t)(carryIn); \ + (sumOut) = (addend2) + tempReg; \ + (carryOut) = (is_digit_lessthan_ct(tempReg, (digit_t)(carryIn)) | is_digit_lessthan_ct((sumOut), tempReg)); } + +// Digit subtraction with borrow +#define SUBC(borrowIn, minuend, subtrahend, borrowOut, differenceOut) \ + { digit_t tempReg = (minuend) - (subtrahend); \ + unsigned int borrowReg = (is_digit_lessthan_ct((minuend), (subtrahend)) | ((borrowIn) & is_digit_zero_ct(tempReg))); \ + (differenceOut) = tempReg - (digit_t)(borrowIn); \ + (borrowOut) = borrowReg; } + +// Shift right with flexible datatype +#define SHIFTR(highIn, lowIn, shift, shiftOut, DigitSize) \ + (shiftOut) = ((lowIn) >> (shift)) ^ ((highIn) << (DigitSize - (shift))); + +// 64x64-bit multiplication +#define MUL128(multiplier, multiplicand, product) \ + mp_mul((digit_t*)&(multiplier), (digit_t*)&(multiplicand), (digit_t*)&(product), NWORDS_FIELD/2); + +// 128-bit addition, inputs < 2^127 +#define ADD128(addend1, addend2, addition) \ + mp_add((digit_t*)(addend1), (digit_t*)(addend2), (digit_t*)(addition), NWORDS_FIELD); + +// 128-bit addition with output carry +#define ADC128(addend1, addend2, carry, addition) \ + (carry) = mp_add((digit_t*)(addend1), (digit_t*)(addend2), (digit_t*)(addition), NWORDS_FIELD); + + +/**************** Function prototypes ****************/ + +/************* Arithmetic functions modulo the curve order **************/ + +// Converting to Montgomery representation +void to_Montgomery(const digit_t* ma, digit_t* c); + +// Converting from Montgomery to standard representation +void from_Montgomery(const digit_t* a, digit_t* mc); + +// 256-bit Montgomery multiplication modulo the curve order +void Montgomery_multiply_mod_order(const digit_t* ma, const digit_t* mb, digit_t* mc); + +// Addition modulo the curve order, c = a+b mod order +void add_mod_order(const digit_t* a, const digit_t* b, digit_t* c); + +// Subtraction modulo the curve order, c = a-b mod order +void subtract_mod_order(const digit_t* a, const digit_t* b, digit_t* c); + +// Reduction modulo the order using Montgomery arithmetic internally +void modulo_order(digit_t* a, digit_t* c); + +/************* Multiprecision functions **************/ + +// Check if multiprecision element is zero +bool is_zero_ct(digit_t* a, unsigned int nwords); + +// Multiprecision addition, c = a+b. Returns the carry bit +unsigned int mp_add(digit_t* a, digit_t* b, digit_t* c, unsigned int nwords); + +// Schoolbook multiprecision multiply, c = a*b +void mp_mul(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords); + +// Multiprecision subtraction, c = a-b. Returns the borrow bit +unsigned int subtract(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords); + +// Clear "nwords" integer-size digits from memory +extern void clear_words(void* mem, unsigned int nwords); + +/************ Field arithmetic functions *************/ + +// Copy of a field element, c = a +void fpcopy1271(felm_t a, felm_t c); + +// Field negation, a = -a mod p +void fpneg1271(felm_t a); + +// Integer multiplication, c = a*b +void mul1271_a(felm_t a, felm_t b, felm_t c); + +// Modular correction, a = a mod p +void mod1271(felm_t a); +void mod1271_a(felm_t a, felm_t c); + +// Field addition, c = a+b mod p +void fpadd1271(felm_t a, felm_t b, felm_t c); +void fpadd1271_a(felm_t a, felm_t b, felm_t c); + +// Field subtraction, c = a-b mod p +void fpsub1271(felm_t a, felm_t b, felm_t c); +void fpsub1271_a(felm_t a, felm_t b, felm_t c); + +// Field division by two, c = a/2 mod p +void fpdiv1271(felm_t a); + +// Field multiplication, c = a*b mod p +void fpmul1271(felm_t a, felm_t b, felm_t c); + +// Field squaring, c = a^2 mod p +void fpsqr1271(felm_t a, felm_t c); + +// Field inversion, af = a^-1 = a^(p-2) mod p +void fpinv1271(felm_t a); + +// Exponentiation over GF(p), af = a^(125-1) +void fpexp1251(felm_t a, felm_t af); + +/************ Quadratic extension field arithmetic functions *************/ + +// Zeroing a quadratic extension field element, a=0 +void fp2zero1271(f2elm_t a); + +// Copy quadratic extension field element, c = a +void fp2copy1271(f2elm_t a, f2elm_t c); + +// Quadratic extension field negation, a = -a in GF((2^127-1)^2) +void fp2neg1271(f2elm_t a); + +// Quadratic extension field addition, c = a+b in GF((2^127-1)^2) +void fp2add1271(f2elm_t a, f2elm_t b, f2elm_t c); +void fp2add1271_a(f2elm_t a, f2elm_t b, f2elm_t c); + +// Quadratic extension field subtraction, c = a-b in GF((2^127-1)^2) +void fp2sub1271(f2elm_t a, f2elm_t b, f2elm_t c); +void fp2sub1271_a(f2elm_t a, f2elm_t b, f2elm_t c); + +// Quadratic extension field multiplication, c = a*b in GF((2^127-1)^2) +void fp2mul1271(f2elm_t a, f2elm_t b, f2elm_t c); +void fp2mul1271_a(f2elm_t a, f2elm_t b, f2elm_t c); + +// Quadratic extension field squaring, c = a^2 in GF((2^127-1)^2) +void fp2sqr1271(f2elm_t a, f2elm_t c); +void fp2sqr1271_a(f2elm_t a, f2elm_t c); + +// Quadratic extension field inversion, af = a^-1 = a^(p-2) in GF((2^127-1)^2) +void fp2inv1271(f2elm_t a); + +/************ Curve and recoding functions *************/ + +// Normalize projective twisted Edwards point Q = (X,Y,Z) -> P = (x,y) +void eccnorm(point_extedwards_t P, point_t Q); + +// Normalize two projective points, including full reduction +void eccnorm2(point_extedwards_t P, point_t Q, point_extedwards_t R, point_t S); + +// Conversion from representation (X,Y,Z,Ta,Tb) to (X+Y,Y-X,2Z,2dT), where T = Ta*Tb +void R1_to_R2(point_extproj_t P, point_extproj_precomp_t Q); + +// Point doubling 2P +void eccdouble(point_extedwards_t P); + +// Complete point addition P = P+Q or P = P+P +void eccadd(point_extedwards_t P, point_extedwards_t Q, point_extedwards_t R); +void eccadd_core(point_extedwards_t P, point_extedwards_t Q, point_extedwards_t R, f2elm_t Ta, f2elm_t Tb); + +// Psi mapping of a point, P = psi(P) +void ecc_psi(point_extedwards_t P); + +// Phi mapping of a point, P = phi(P) +void ecc_phi(point_extedwards_t P); + +// Scalar decomposition +void decompose(uint64_t* k, uint64_t* scalars); + +// Generate random field element in [0, 2^127-1] +void random_felmt(felm_t random); + +// Scalar randomization for variable-base scalar multiplication +void randomize(uint64_t* scalars, unsigned char* r, uint128_t* random_scalars); + +// Randomization of point coordinates using a random field element +void felmt_randomize_point(point_extedwards_t P, felm_t random); + +// Randomization of all the point coordinates in the precomputed table using a random element in GF(p^2) +void randomize_table(point_extedwards_t* Table, felm_t random); + +// Recoding sub-scalars for use in the variable-base scalar multiplication +void recode(uint128_t* scalars, unsigned int* digits); + +// Computes the fixed window representation of scalar +void fixed_window_recode(uint64_t* scalar, unsigned int* digits, unsigned int* sign_masks); + +// Convert scalar to odd if even using the prime subgroup order r +void conversion_to_odd(digit_t* k, digit_t* k_odd); + +// Co-factor clearing +void cofactor_clearing(point_extedwards_t P); + +// Reduction modulo the order using Montgomery arithmetic +void modulo_order(digit_t* a, digit_t* c); + +// Generation of the precomputation table used by the variable-base scalar multiplication ecc_mul_SCA_secure() +void ecc_precomp(point_extedwards_t P, point_extedwards_t R, point_extedwards_t *Table); + +// Constant-time table lookup to extract an extended twisted Edwards point (X:Y:Z:T) from the precomputed table +void table_lookup_1x16(point_extedwards_t* table, point_extedwards_t P, unsigned int digit); + +// Modular correction of input coordinates and conversion to representation (X,Y,Z,Ta,Tb) +void point_setup(point_t P, point_extedwards_t Q); + +// Point validation: check if point lies on the curve +bool ecc_point_validate(point_extedwards_t P); + +// Output error/success message for a given ECCRYPTO_STATUS +const char* FourQ_get_error_message(ECCRYPTO_STATUS Status); + +// Generation of the precomputation table used internally by the double scalar multiplication function ecc_mul_double() +void ecc_precomp_double(point_extedwards_t P, point_extedwards_t* Table, unsigned int npoints); + +// Computes wNAF recoding of a scalar +void wNAF_recode(uint64_t scalar, unsigned int w, int* digits); + +// Encode point P +void encode(point_t P, unsigned char* Pencoded); + +// Decode point P +ECCRYPTO_STATUS decode(const unsigned char* Pencoded, point_t P); + + +/************ Functions based on macros *************/ + +// Copy extended projective point Q = (X:Y:Z:T) to P +#define ecccopy(Q, P); fp2copy1271((Q)->x, (P)->x); \ + fp2copy1271((Q)->y, (P)->y); \ + fp2copy1271((Q)->z, (P)->z); \ + fp2copy1271((Q)->t, (P)->t); + +// Copy extended projective point Q = (X+Y,Y-X,2Z,2dT) to P +#define ecccopy_precomp(Q, P); fp2copy1271((Q)->xy, (P)->xy); \ + fp2copy1271((Q)->yx, (P)->yx); \ + fp2copy1271((Q)->z2, (P)->z2); \ + fp2copy1271((Q)->t2, (P)->t2); + +// Copy extended affine point Q = (x+y,y-x,2dt) to P +#define ecccopy_precomp_fixed_base(Q, P); fp2copy1271((Q)->xy, (P)->xy); \ + fp2copy1271((Q)->yx, (P)->yx); \ + fp2copy1271((Q)->t2, (P)->t2); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/FourQ_ARM_side_channel/FourQ_params.h b/FourQ_ARM_side_channel/FourQ_params.h new file mode 100644 index 0000000..7e30121 --- /dev/null +++ b/FourQ_ARM_side_channel/FourQ_params.h @@ -0,0 +1,33 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: FourQ's curve parameters +* +* This code is based on the paper "FourQ: four-dimensional decompositions on a +* Q-curve over the Mersenne prime" by Craig Costello and Patrick Longa, in Advances +* in Cryptology - ASIACRYPT, 2015. +* Preprint available at http://eprint.iacr.org/2015/565. +************************************************************************************/ + +#ifndef __FOURQ_PARAMS_H__ +#define __FOURQ_PARAMS_H__ + +#include "FourQ_internal.h" + + +// Encoding of field elements, elements over Z_r and elements over GF(p^2): +// ----------------------------------------------------------------------- +// Elements over GF(p) and Z_r are encoded with the least significant digit located in the leftmost position (i.e., little endian format). +// Elements (a+b*i) over GF(p^2), where a and b are defined over GF(p), are encoded as a||b, with a in the least significant position. + +static const uint64_t PARAMETER_d[4] = { 0x0000000000000142, 0x00000000000000E4, 0xB3821488F1FC0C8D, 0x5E472F846657E0FC }; +static const uint64_t GENERATOR_x[4] = { 0x286592AD7B3833AA, 0x1A3472237C2FB305, 0x96869FB360AC77F6, 0x1E1F553F2878AA9C }; +static const uint64_t GENERATOR_y[4] = { 0xB924A2462BCBB287, 0x0E3FEE9BA120785A, 0x49A7C344844C8B5C, 0x6E1C4AF8630E0242 }; +static const uint64_t curve_order[4] = { 0x2FB2540EC7768CE7, 0xDFBD004DFE0F7999, 0xF05397829CBC14E5, 0x0029CBC14E5E0A72 }; +static const uint64_t Montgomery_Rprime[4] = { 0xC81DB8795FF3D621, 0x173EA5AAEA6B387D, 0x3D01B7C72136F61C, 0x0006A5F16AC8F9D3 }; +static const uint64_t Montgomery_rprime[4] = { 0xE12FE5F079BC3929, 0xD75E78B8D1FCDCF3, 0xBCE409ED76B5DB21, 0xF32702FDAFC1C074 }; + + +#endif \ No newline at end of file diff --git a/FourQ_ARM_side_channel/FourQ_tables.h b/FourQ_ARM_side_channel/FourQ_tables.h new file mode 100644 index 0000000..e59ff4e --- /dev/null +++ b/FourQ_ARM_side_channel/FourQ_tables.h @@ -0,0 +1,278 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: precomputation tables +************************************************************************************/ + +#ifndef __TABLES_H__ +#define __TABLES_H__ + +#include + + +// The table below consists of four mini-tables each generated using window width W = 8. +// Number of point entries = 4 * 2^6 = 256 points, where each point (x,y) is represented using coordinates (x+y,y-x,2*d*t). +// Table size = 256 * 3 * 256 = 24KB + +static const uint64_t DOUBLE_SCALAR_TABLE[3072] = { + 0xe18a34f3a703e631, 0x287460bf1d502b5f, 0xe02e62f7e4f90353, 0x0c3ba0378b86acde, 0x90bf0f98b0937edc, 0x740b7c7824f0c555, 0xb321239123a01366, 0x4ffcf5b93a9557a5, 0x297afccbabda42bb, 0x5948d137556c97c6, 0xa8189a393330684c, 0x0caf2b720a341f27 +, 0x892756b15bcf68c4, 0x5742f77c98a526ba, 0x340a5a1de9f89f9b, 0x14ef680aee75d0f7, 0x84e770e14043a41f, 0x0212c41116c33c95, 0x35b791e6de4dc0e2, 0x5949df08518d5d28, 0x6a0e120744ed10db, 0x5a5183ce844391d3, 0x6f618b158afdba50, 0x2ce2037e470e2088 +, 0x1f49fa149a64ba3c, 0x5f9876d519670451, 0x030105056f55586b, 0x020f1a557d8fd726, 0xdf4cb175b06d86c8, 0x694fbcbe7fe58390, 0x7933294a756a1b67, 0x09dbe9924b58f8ec, 0x590f4403cdf197b6, 0x1c07969fc87a0ba7, 0xc496477712252367, 0x5508976022f1b096 +, 0xefda361e452e1775, 0x7a0a0cccacc838fb, 0xb07e791c0be5dc5f, 0x24d9b6b418cbcb93, 0x497970f3c6117e03, 0x3986a158cb96d595, 0x8f80586ce692612b, 0x305cafda7e4df9d6, 0xc1a1c2e06452914a, 0x7ef989c0eb583079, 0x3a765b1f7364b099, 0x4fee236d58299c6b +, 0x6f81095f770e8419, 0x53bbd86b7396bc09, 0x2b72ba726b2b4210, 0x625dda1d2901c78b, 0x0ff5bc7b18cd2b3e, 0x0556598c7358d332, 0x0991245f20ff50d7, 0x0e7f58e5e919a97e, 0x5a0561373b758756, 0x6447bc93f87c198a, 0xf9230604c34c7520, 0x6b214425475c1bfa +, 0xe93de62d6a7f9497, 0x2129459d86f4493c, 0x456394c7c464cfe4, 0x612434fec3f4a1b3, 0x1ed91eddf44261f3, 0x0c6d3854f9e0a3ff, 0xd3fd153188a7e4e3, 0x24691fbdca16910c, 0xbe97465cd7625c9d, 0x2aa61cd373f759f4, 0x824d5763a326d62b, 0x1a0ae39e50da20ba +, 0x32d0c8481ee4c3b9, 0x6c3687109cdd18c6, 0xe52717142fbf95da, 0x67bfa41fb52ce9c6, 0x4e24d6a088a01474, 0x49a6ca0ae3fb6626, 0xd67f8faa9103191e, 0x674888f5aa6d3062, 0x4ba73824c2e85a99, 0x406b2fd18d35b314, 0xa7087b1bea728ac1, 0x11d2f222317b160e +, 0xf8946e007e23a469, 0x22a196fabbce31a2, 0x5309ee1bdc1216ba, 0x240fe9953827a324, 0xf9fcb89b63aeb5c7, 0x603b8149ed16b1b0, 0xb1f1876c02cf61fb, 0x4a5e32af612f948b, 0xfc491aede69a8813, 0x1ad9379136e53aa5, 0x5da50db1d5e6c123, 0x2f4014f7fe2c12ca +, 0xe4f6791d7685c3f5, 0x4c218521c3745a9b, 0x0c0521af98555f97, 0x1462a12953cada7b, 0x0bb2ab63d6452c1b, 0x5783c531ec98bb87, 0x737def53605dbc9c, 0x49f982b930e86719, 0x75b16790cb5211e3, 0x45ad6574cdbae99e, 0x1062b72dfeec9851, 0x45029a09cc468c88 +, 0x532240de77f3a1f2, 0x17bd291eaa9ad0ea, 0xe0a2d7efc2f8a0a0, 0x3a7412052021778e, 0xb0dfb0976acc90df, 0x7fd603b689a7b1f3, 0x1152579ccb00d6c6, 0x6340743b631849a3, 0xebaa47290e0cda01, 0x143265a6d53fef0b, 0x45325d6fd981e75a, 0x0e9780cc39586f2a +, 0xa4f68d207a8628dd, 0x50d230b51893e841, 0xf3bd769a4bb504b6, 0x55975c063969292e, 0x07727ba25fb8756f, 0x07ff86cf8ed731fd, 0xef57fa40cc35a1f0, 0x70753a70874218fc, 0x615954e2342b973c, 0x5aa9d68f1a59df86, 0x3b8e9e9ff5e44468, 0x2e749114d60a3d23 +, 0x14a1b91ec176db4b, 0x55f91a63d69aae6d, 0xf42382327b1b6d27, 0x2acf1f475facaafd, 0xfd9069b479b58968, 0x3baaf4e5c4a45f77, 0xa2ac9ab98a7aaab6, 0x5466cb5018f50981, 0x3e6ba27771ba3205, 0x31ea90cdea1bbbe4, 0x0000416b5c557393, 0x464cb0415a510d7d +, 0xd02087d206ff2bbf, 0x2b9c8ecd7fabe736, 0xb2b56d3842caab0d, 0x046ea0b7767700a7, 0x113a7a889e317310, 0x5992a354bef7d0ca, 0x3edda94ed50388bd, 0x052661f767839154, 0x4c28edf6e19e28e0, 0x1d19c2f2d2f644e5, 0x5d732148db35ab3d, 0x680c4714b83580f5 +, 0xa374f282bb80ccec, 0x789e609bc77ae11c, 0x10d2577d599b45f2, 0x1c548b5b857721b1, 0x7baea726b4543fdf, 0x3c1562912d1b4ed2, 0xd6362203b7e82082, 0x1414e523d3c7a900, 0x7ca349951c1d23a9, 0x4da4265e3ce80fb4, 0x7981ebbcaca9ef36, 0x4ebac9e5b5bf980b +, 0xabd2c1dcf49cb5a4, 0x3f54acfc25c6340f, 0x202eeffabbd11cbd, 0x67216b7cb3695e8c, 0xff7cbcf9b23fc9f1, 0x2eebebdff7fa7afb, 0x71156befa111f85e, 0x1b8fd98df522902c, 0x6b28ebad62519791, 0x6cf0ea960e01d8ed, 0xb4617bc2006967d5, 0x323da065cb3df0ad +, 0x31687d0741e24d9c, 0x02db8f2b509a7cc2, 0x9243f85924320527, 0x68c360f01d6e6d2b, 0x2351c5e877d5306a, 0x6f56ccfc85c5f3a9, 0x1b09652837c4928f, 0x0b3337554c83f971, 0xe2931be2ccc783ec, 0x46829694ba08c64f, 0x9f35e36358e2c6ac, 0x1474b333b000d170 +, 0x24d792756fc96640, 0x618fda9fef868c5e, 0xb7ff5b125afd9375, 0x778dd97e0440c258, 0xfbff314886219627, 0x3417e1e1e2a7e811, 0x21e959a88f7b7bdc, 0x3508c2eb8c3c8672, 0x827ecdde111c430f, 0x21bcb19fb07aa134, 0xe0c1fa50ab2f5746, 0x401e680b4e6658fa +, 0x2cc24bab313693cc, 0x20541c12b964447a, 0x374975b6fb81c3cc, 0x52905efb344e17f7, 0x79c5c9b56d8b5f9e, 0x3390bf75d2b9a3ec, 0x7ef3807d895bf4e4, 0x2814165a42046b51, 0x7f8cfd09326fe158, 0x3232fb4f4c9762ec, 0x5678d6dacc194d25, 0x6f7caffb0a7545e8 +, 0xbd981637b23e7963, 0x691d7b7cb88a0ef5, 0x10ba319ae2062914, 0x06fb144f8295a85b, 0x80e620976bf62f8f, 0x2a425971ec73d6b4, 0x800aa9e741d10b1c, 0x230d7d8bd1a0469b, 0x65aace37428dfe8c, 0x0fcab5297f58b667, 0xcf0e9526943af7b8, 0x7d90915b75d4dae7 +, 0x7455a46156259d6b, 0x29bcc06374cce1b5, 0xf2fb0ed3aa87aefd, 0x211a06af0e54dd58, 0x6c0c95c5723de9bc, 0x6299b6ed25008ca7, 0x7fd63e784d4dfb18, 0x2cc93b4d9bc1db30, 0xebc7e2d44c5d13ea, 0x3278e18d4d3d11a0, 0x349e3dd25a215f79, 0x7eb2a7150b30416d +, 0x05f3d7d5f6a094cb, 0x2a3771d48e331405, 0x08ef39e9dc96f009, 0x012248373a364992, 0xf758f92fc9fd4d33, 0x2339d8c6dfd3ca6c, 0x8b000965962673b4, 0x746ff43eb99d9054, 0x47ecdc054a422eff, 0x33d8f7c8267b7f0c, 0x22fe00ac921a42ae, 0x31e57f3d31fcd8e6 +, 0xbb912315a1c50869, 0x4ac8cdb0fa7ebbaf, 0x0541d74a60973edf, 0x7234900334b2c5d7, 0xf2e545f730adfa33, 0x224e44e63db5ac96, 0xfcba3d005c6fdeb9, 0x2c93a4e6559936b5, 0x7727a0d7ad88d758, 0x2e33100216719cdd, 0x7b2ef89aeb2c0254, 0x1f6de5b74758afb4 +, 0x6ae89047114fb321, 0x3d605e9a6ec6d80d, 0x18e915c727a874d8, 0x699088b5e9d0912f, 0xaf9344618e056f10, 0x1b9169df8245e0b3, 0x5eb8c33d70f4c891, 0x1609ddfb222b13c3, 0x8131c885d1b366ed, 0x7bc3cf9d9cb1a7b0, 0xd297478d2fc93968, 0x13cbb4573a4ea7f5 +, 0xdd37b5cc64d5986b, 0x7ed3d1d7d81ab5dc, 0xac53485f23973c9e, 0x0705675d333b91d7, 0xade5d213c43186c1, 0x6a8bdf57b4bfdf14, 0xa87f88a1de717963, 0x17f29220b519bce2, 0x7af2d7fb0f95c610, 0x28d1d3923b144a7c, 0x8e73c3d8972813e1, 0x00100b40c62e72c1 +, 0x84de7a81fa1f50da, 0x4fa391d6589d8244, 0xbcc3596f0834b285, 0x4d4acbd60a24e9ce, 0x97fa98b8c1835a0d, 0x33abcf8e29901d0b, 0x60a73d1975b3d082, 0x60666aa4325b948d, 0xad54adb769284a39, 0x227a98d113609b28, 0x4a1e1ffcae6a3872, 0x1e4ee44bd67f818c +, 0x5a74c6bb4387d315, 0x019428c0b1b18795, 0x5cc153e270bbb055, 0x2b3cabdf00dc4a61, 0x834110c026924b57, 0x2d30e985f2d9f217, 0x47116979333389f5, 0x53e3fd6a18202417, 0xb1393cd79c2e5864, 0x58d92935e4112e82, 0x86989a7ec8305b6d, 0x42a8fe4eee28f37a +, 0x74e212ef01591901, 0x3277917a0397b1b9, 0x7bbcbe6e3d687544, 0x0b8957701d09afb6, 0x6cfbc8ee74503668, 0x48a9925ada9f8348, 0x57045753ba2d0f4e, 0x7d69ca3866223d66, 0xc7054ce22917271f, 0x41bce1e1133b51de, 0x3a3ae42df81ec35e, 0x7eaada0f42d47cc3 +, 0x13b138f1048a57cc, 0x64f98abd7e915a8f, 0x7af195eb16a0c732, 0x11be81a791d634d2, 0x97d8df47430f61b8, 0x0767c7b381271004, 0x3e949136fb940aa6, 0x3bdee340cd956dba, 0xb250ec4ff91d2602, 0x4cde2454d47f59db, 0xaf5e749530d978cb, 0x5a8e2f2119d4d835 +, 0xdf1cb5425a0744df, 0x3d3b08a7bf35d055, 0xc6335e832de4719c, 0x6eb8d97e09154d42, 0x2f6a3f8de3d20dd9, 0x13f23cfd276233da, 0xb4a6b80dfc0fa41c, 0x58d876403acfd7d7, 0x2ad422078b8e139b, 0x73dbee2abbaf494d, 0x09a2758891eca3c8, 0x6ef9a9f1178b0938 +, 0xfc7e9ecb90c637da, 0x3a04345fc10b1a7c, 0xc024e9cb62f9ff1f, 0x6c4f9c3aa4aa33d8, 0x049d6995b95ac1f0, 0x2243845195763a1b, 0xa1466a31700ac276, 0x600fb7123a325905, 0x9d391a64a0d35a24, 0x3b093b550641f108, 0x2275de5bfd2e221f, 0x25f5e7465963db1e +, 0x3e220107f7e7fb84, 0x6f06a23bc1b85a8e, 0xb4198d19f6eb0e48, 0x5dc11761dad45fda, 0xba303e492ab52a0d, 0x127c69c73da9f528, 0xd3a5b70cf6c790be, 0x0d72b0c50819da5c, 0x193f90d62ec2cdf7, 0x67f7d0cfc4f46daf, 0x7aec083d52f380ea, 0x7c0a1dda4a28bf4d +, 0x46fd20fe6008cba7, 0x7a588c914115d595, 0x8fb1d3daecf45f78, 0x0851dac094e7b036, 0xcae0a76e2a32a892, 0x104f861322dddb2f, 0xb79d81e46e1f9006, 0x1e4d28d7a2498912, 0xaf3175d3974b89bf, 0x613d00f9a69c55c2, 0x23f6883e8e65226f, 0x072f7ed65c6def05 +, 0x6690e643bb38e243, 0x1a81c4a7c9189b15, 0x1056d1669e4749ae, 0x0137f2a7418f190c, 0xed3192796e699d16, 0x3ed76db45c38a37c, 0x78e86d1475a88243, 0x45985aacc495b16e, 0x47d5c8208e8f1030, 0x6dbe5f68b4d0e782, 0x08d3d0182cf7f26b, 0x64c375ce172fadbd +, 0xba0f6db3a20c2875, 0x57e1d90a53241250, 0x0315433fddf8e63e, 0x33344750e37dad9b, 0x62cc0d28ae69b016, 0x435fe80f6100d547, 0x5874aea8669d3df5, 0x3b96913f8264d4a9, 0x738067d6bb1314b0, 0x48cccf24cc6f4ccf, 0x6f5e2bbd68b777af, 0x34c2c37ba9635d66 +, 0xd731534900fdbe5b, 0x4e4f9d97afe11d43, 0x81b41214351b73d7, 0x1d48d100ad11a5ae, 0x2a4ee76628e2b151, 0x34902e901877efb8, 0xb5a8561a0fd45394, 0x44317af6d5cd5ac0, 0x354c2469e9068bad, 0x0771fe2761cad022, 0xfda76ee8212d0f2b, 0x76cdeec6d4435495 +, 0x55c98575b3e825fd, 0x2983325ed5d73a1b, 0x563c4c4fb3f466e7, 0x731b0fa413338bb0, 0xdeb519ca57a05240, 0x7a7e909b5c4f7351, 0xefb7c153dd2ab28e, 0x11ca1c865dee30b3, 0x013ca8348d9d7de1, 0x575e0bdaeee8cf9a, 0x464c98a21083af7f, 0x683ddcd85c212ee3 +, 0x1171f0ab4cd02019, 0x22c7e01c7f4d64c8, 0x972ec0ef3f2e2ed3, 0x623f83c2611a476c, 0x99b3f16be9aa25a1, 0x2d3ebc5468990e0b, 0x5d5fba8546a4d5f2, 0x4716e6919d2986e3, 0x3ab2f2bc183f5d6c, 0x5f6257d3910cd4be, 0x341c6f2a78f94f2b, 0x6ee8390b8a5064f5 +, 0x9d8640b9b83ca8e7, 0x033c5ad24466be3d, 0x6f6cd68db30dfd59, 0x52aa6b1c0f90f3f6, 0xfe7bcd4c97403646, 0x11ab3fc960b05fb0, 0x24584b77575896da, 0x427f8deb932da137, 0x928a28cb505306f0, 0x04ae916fe863820e, 0xaabaa98911b9cd3f, 0x59e588ba994d9145 +, 0x9b8f1afabeee9e9f, 0x04ffc7ef3476ff8e, 0xe9cf53ce9937b146, 0x73fe42a801524448, 0x224bda3cf3bbaaad, 0x5fa85056d59884a4, 0x8e6eead48345726b, 0x09230936d41736d2, 0xe679eb58d1ad6be7, 0x08bb759b530b1eaf, 0x9688eb527860e24b, 0x13704d2daf9af278 +, 0xd9273ac71b906f14, 0x57ee05fbbd40deb5, 0xb7788e19ba9e61eb, 0x7967b6dc1c5d9699, 0x36e043fc230127c0, 0x2a716598bb2d519c, 0xc017b2840d4d1b07, 0x1d3bfa489f756a3f, 0x4ad73abf24318d36, 0x1915e6f53e12625d, 0xb219a7c941f89084, 0x2280087a8f4762fc +, 0x8eb280345fd1b4e7, 0x55b8d4ee5772fd79, 0xc9e63a787e2ce2e1, 0x685741adbda93885, 0xffb830ab11a3b491, 0x7e891121f9356428, 0xc03aea271a629078, 0x71c45932930a2639, 0xe7df192a6bf81795, 0x704aee8f183aadf1, 0x06ddb55a8a7a63d7, 0x52556d8763f3033c +, 0xb76b458c6f0c33a7, 0x28666b87c362b95a, 0x365ae575a4c27b9b, 0x36ef35110562adfd, 0x89955dd8d927f9c7, 0x526e787d6a586c9e, 0x762e0bc4eff988c1, 0x6c9523b4b5ae4946, 0xe90a909688cfe95f, 0x658a7dc8b3ffada3, 0xbee148ba7a58520f, 0x6819007d8573d1cf +, 0x75d3b5ec141be9c5, 0x4bc236ae634f3c27, 0x1192fa9b8b30e894, 0x4129d43e1d092cbf, 0xfcac068558bbea45, 0x513e8d87b8116534, 0x5377a179a155ecd4, 0x6c93531e5545572f, 0x727df81ba09aad91, 0x07527139dbc96250, 0x150320b1d8ba172a, 0x2281e85f60a1809b +, 0x7164b7d524eba6af, 0x50d387163fea4ca8, 0xe90de17d62aebe78, 0x6ab369ba28c0410d, 0x17d07e315a95d138, 0x58b496352453fefd, 0xb87a04dbbc101b92, 0x40a8f0fb757e9b0e, 0x2148b48a696e64d1, 0x4e004a3a350c17d7, 0x17927e9f386b563e, 0x29da9cd441e3e3c5 +, 0x883d2dc357417213, 0x2e94653ff7862644, 0x53a37af548453df1, 0x04475db3c300b93b, 0x2d65fa4d815e7204, 0x231a2db74c2c3ccd, 0x1fd734c0cf4d97cd, 0x32d255c105f6d122, 0xbb74fd9201eb07b0, 0x12e33f1c81ac6f60, 0xfb9a6439bea97072, 0x52e14b7db9cdcbc1 +, 0x637ac1a91ae374cb, 0x1c8622c35adc8224, 0xeb786c50a64b7d33, 0x362823a7232a5893, 0xf22dafca688d472a, 0x18598f0e0237f7c4, 0x97b8497bfff4bcf1, 0x7abf4cb27a9c5b7f, 0xea47c44e3b3d95d3, 0x58728fe3e1827a43, 0x7fd3681a6df902c8, 0x6db1dbbdc413de79 +, 0xbc4effed1ac3007f, 0x7f31a54744887cab, 0xe6559b4f8bd2519a, 0x18a78ec5b0c241db, 0xf6e10285b15d2030, 0x5c1323ea219a8ff4, 0x134b6f20dd116b47, 0x5d0abddbc8998733, 0xa3c993938702e151, 0x0ab6aeb494f6ad5d, 0x8cf3b4beda1815e6, 0x546ce323008c2fdc +, 0xa10eb5a6a78dbe39, 0x26d2e8a8b8457da4, 0x026ccbe31517d806, 0x2a35174b812f562c, 0x57d70499dd7a374d, 0x3368f951acd3c5e5, 0x490b2515f901062c, 0x316109e7c315c377, 0x32e20eba569535cf, 0x496a8c39d667d709, 0x5578096dc44d5e0f, 0x608a162ce73903b0 +, 0x6b2e65852cb37cab, 0x75b09a2e6ed609a9, 0x7ac84b3082602455, 0x7690cbb594e84b94, 0xfc85dad9511973fb, 0x738a74b08c9006d0, 0x83233fc939d5883e, 0x7fbfc08b5db3c9f4, 0x81a0e493fb5f7749, 0x2c255ef7e69a77c1, 0x234f02e609cc656f, 0x5960cf0b961f3cec +, 0xac72940237b1f17a, 0x434e038a29d446ac, 0xca6a090e00d8b0c6, 0x1f1aad24001e473e, 0x6d64b6dc133399fe, 0x0899ba41e9dd4607, 0xca590b3f25bbf5df, 0x57217978b0d8ce11, 0xd6b4cb13da6de9ac, 0x3c88520cf564f75d, 0x649fbd5075a7757f, 0x3f2593b90fe72161 +, 0xe1bee53e91dcc9a8, 0x010069dce4c74a92, 0xef83968978aa855c, 0x6cd8848183b53d73, 0x0b3df59610e403eb, 0x713225d446180a7f, 0xcc23112cc59850e2, 0x105796b670a3730c, 0xa147f4ec7a2fa4cf, 0x32da1f072d75b253, 0x4e7007455e85f560, 0x76a5376a771fdd60 +, 0x47eb4fabdcc699f7, 0x4e45db6334c6ed96, 0x36066f2bab72546f, 0x04f48065593ecdec, 0x3fec02793fbb5601, 0x122f74626b64a526, 0x21d0f66ff83b4dbd, 0x1370610ede647f1c, 0x57b82242b88172c9, 0x527dcbadfdc65ade, 0x5e9c9a04385c93f5, 0x64d1cf9e52548a6c +, 0xba0073337865c994, 0x633ee14e50bcd615, 0xf840228ec4251095, 0x49bb96812a98f08d, 0x82f57d0422f96678, 0x06d7e43bffe7e0e1, 0x33910cca752ae863, 0x04d46e7c66087e38, 0xf14935c4167017c3, 0x3f22e2f44d03c9ac, 0xa6196244f2cd6164, 0x15a2b4ce514fa4db +, 0x5191a04c4abbd0c4, 0x0e763360ecc8a19d, 0xfef583c184a673c0, 0x75c2f30a7c7433e7, 0xe947a55547c7c099, 0x245c7ae44f6e7a83, 0x67a666f9e6bec2d4, 0x5de0b922fa645ac8, 0xdd9b3e4a5cb72e22, 0x0139c2c857adba8e, 0xa7feb68e863ac231, 0x501381ef88ec2da0 +, 0xb2b8c6a470f40b01, 0x051d65bdb8363062, 0x4ce90414a6d65714, 0x1e510b525d19df0c, 0x569e723f5d374cf6, 0x4bfe02fd38fde1f0, 0xae7459ebc50f9aa2, 0x0f7e2cb170dfde32, 0x3c3da2326a7407cb, 0x0cfc50a85ffd1842, 0x62ab34c85e85c3c8, 0x22b4d9644bb37333 +, 0x57d313b3d87c2d98, 0x4f432c1cba49133f, 0x6163d11fa4befc0c, 0x1ab94e122fddf12e, 0xfb7c9358aefc85a8, 0x5b20068f81d949b1, 0xcf8ed6ff2145c810, 0x5794afc021932d00, 0x5c8987ad9b6e35d5, 0x6bb1f4b836fda03e, 0x794f1fed4a3ea1d7, 0x0cf6d128deb0e7bf +, 0x54ec3e1c65878cf5, 0x002811763ba2200e, 0x382d917051e77b71, 0x49e00cbd013a9e7f, 0xccf576e9a4cf019c, 0x4b4a66287970333a, 0xf772168915edfc1f, 0x278eb5eca6479685, 0x8a95c8b9cf41cf06, 0x6e58c9c7826d39db, 0x478e119889f2fe75, 0x73ecd21991bd98d4 +, 0x26e751fe9fbb9502, 0x29825b71b0632e95, 0x21668f96ef8bb5c5, 0x2f2a899e53c9a004, 0x2803292ed4345ce8, 0x72731055c7c65dec, 0x3aaaca9c4b6fe9a5, 0x6228d3ceda8bd671, 0x773e2c5effc48eaf, 0x017ab19e0fea9ac9, 0x9609e10496c8d766, 0x121e89f9b302c30f +, 0x4e87d00a0be96480, 0x09bd8d170ba9dbab, 0xc6756f947ecd4e52, 0x2c9e40bbbccd0f5b, 0x42a5b77669fd812e, 0x66aba9583b080d9e, 0xee55df99d16e77c1, 0x4cc00c5c5eff2509, 0x8c84d5e20ab7c16b, 0x00ae5c96184ffefb, 0xb295e90346dcef54, 0x5d1bda0a39dc3b72 +, 0x75f92d72a89b5ef2, 0x259d998c9ff9ac0e, 0x8a1cfb72a6c433c1, 0x23f5b71d49d67604, 0x478d8f30914f62ef, 0x08fe61135218eca9, 0x4da2ce9bc6488c4a, 0x15f1eafd35283e2e, 0xc2d2be3ebc42ea0f, 0x2a5216539d6ee902, 0xa1e99052e7bdeeb2, 0x3a8f2631ec78290c +, 0xb71518a82ebfbfe4, 0x24700671c46ebddc, 0x6ef52d591a221f75, 0x4794614db6a67d92, 0x761f5c8ee4bab607, 0x31d9dd8f2361b5d5, 0x1a45593be8db3b29, 0x7f06c365eb116260, 0x9d305a66e52eb65b, 0x5edcfcb5613eac18, 0xef34fd28154adb75, 0x790f805753b9d742 +, 0x6ecd5ac255dfb797, 0x0cbe14db5d9a88db, 0xc1c86c5efa815528, 0x2c636133ba59d887, 0xc75d42c2d9f52297, 0x4bd3540c21e2ebd3, 0x32e7cdf790de6903, 0x1aae3c9837d3e30a, 0xeed028e49d436f09, 0x779ae12351efed1c, 0x6e0145587d9797a5, 0x25156e4cee9a407b +, 0xac2fd82f2ac57119, 0x7f8c026f1d182ed2, 0xeacc0d8fb3241611, 0x5968db65d2d7545a, 0x7d525846b1121dbe, 0x57949fd7b80339cf, 0x471fe9bec9b66c01, 0x5c270057f1268efa, 0xce092463083f656e, 0x16e8241cdc862cf9, 0xb7cb2bbcaa06b312, 0x3c25936bd8863416 +, 0x19b8ca966c4a3827, 0x1ae43badfd21e63e, 0x1dfd002b95a6ac6a, 0x4708e27f6d98e997, 0xb5fd6322dc31ac7d, 0x53baf4d9a16dd550, 0x025aa2ea5463960c, 0x5b5b33c7a3cfa54f, 0xdba287866ee96b90, 0x4748c1f3f3a6dc4f, 0x2333ec05a80c154b, 0x4a47745d5b99fb96 +, 0x44955b062a6ecded, 0x7791feea9015f170, 0x736bf603d12fc35a, 0x2632adbca5388026, 0x956e4c48e1697c4f, 0x4ee9adfe8600e32d, 0xa584042a0da56406, 0x34a3d7f4bf457353, 0x8d4fd4fe00176fab, 0x15321ee855941f4e, 0x670701ef81f340a4, 0x0c7d7c618aed0ba8 +, 0x73283131d9bfd9d6, 0x34935a39e31bac65, 0x466cfbbcaae8b991, 0x250dd54e18478ac6, 0x659e46c51e40de4f, 0x618ea014fec50e04, 0xfe64d883080b877c, 0x572cabbb6688c4f7, 0xa2c817493a834146, 0x06cd734876378120, 0xe3de0b717336a849, 0x36942f5191db53c4 +, 0xa3f9adf66abf4d88, 0x2a9a144b8087fa96, 0xfe49fefcb78a5b4f, 0x1be40a8616928bab, 0x07a901975521f7aa, 0x1fc66ea683693510, 0x4dbf0084ba42380e, 0x1f374495b918c737, 0xb8346956a380a00a, 0x1346f4766fcdaa07, 0xb4db5689d46312c1, 0x775e7f3274dc1316 +, 0x07898828f32341c0, 0x144390a33b3e86df, 0x70bc604ce1e9c5e4, 0x127652de00220873, 0x2874bc669df50d45, 0x236f4585150161f4, 0x3bfa4ffd318214e2, 0x7cc92a6165059745, 0x2fae0e92090ef72a, 0x26676bd59c4fcc3b, 0x220c030974d1d447, 0x66455887e98686e7 +, 0x4164b8e4d8760ddc, 0x5517a86f840feb63, 0xd9b42c6c9371cade, 0x3a7f03ceecc160b9, 0xdd4086d64cae366c, 0x1b6290c327842533, 0x144efcd2a7a0e82b, 0x16621925ca10d31e, 0xa9dcd13118e208f1, 0x5a90f97edcb1c54e, 0x80c47331c8749d99, 0x6f061a3569a80b55 +, 0x0f6abf619e2a15c5, 0x29106c98122245f4, 0x5860b10985c9b47f, 0x4f379a379e15f410, 0x2dd6f45df68e1678, 0x2c475167ad9b283c, 0x23b7aa00952a6a3a, 0x5532bc26a40c5365, 0xa5c0a8be3596ce22, 0x4fa3127a9aefa56f, 0x944e843aa973e67f, 0x3c7727d45ae87854 +, 0x48fa2ce675117ea4, 0x7bca8e04ad3bbb9c, 0xd57439e4726f88e5, 0x3337d3a6a03b2286, 0xb0b6172902005953, 0x514bd76734e6c0a1, 0xf97f8934eed7c6b4, 0x0abe13cee7f1b75e, 0x6c88107a120e54a7, 0x634f966d7a6e11df, 0x5044c53109b94097, 0x68d49fc65522b73a +, 0x69e295cd8c444666, 0x542c4c5fd999a224, 0x13ff89418b5da76f, 0x7133fa786a87ecb4, 0x2f180926456402b4, 0x52ddada7931c4dcc, 0x6eaf0d2130c71590, 0x014ec2a2ec231826, 0xac05b61443b34dd6, 0x157acbfab118b219, 0xe4e2f4b84ad01099, 0x0abf4a4da29a0eb8 +, 0x5f852b85b59eab1f, 0x1bd259c4726869ed, 0xce565d9287790a15, 0x17a48442bcf58a00, 0x01e519522381363b, 0x2336d07a710da07a, 0xcfebf2fbdc714cb2, 0x2f7a51474c23b8a9, 0x77db2a07d4e3716c, 0x40e8d8d2d0a09806, 0x644363ce6d401ae4, 0x53f9cae0470172fd +, 0x58d96ecd8ddadc53, 0x15028204f3d6d696, 0x6f40a09214439ce2, 0x738c5371236c3e56, 0x64f87ee7a28bf9fc, 0x4f1899449a810fee, 0xd0aa95f4bf21e376, 0x6170cc24283856bc, 0x9dfc4927d764ff75, 0x227ea1563fa2e012, 0xaddd3665622ce087, 0x473d3bea07a5285e +, 0xc0b986ee0d2b0eb2, 0x78e584c740dd18ed, 0xd5adbf30a04fd508, 0x1c6aed5ab59bedbb, 0x25d05fccbddb5ba1, 0x4a58fb6b3f896319, 0xdb2f6343fd8144fa, 0x46a445de6d5b07e5, 0xf67a06684fe9e1da, 0x57b2515923b15c9f, 0x50439940820a2a0c, 0x62f4b9b26f04dab5 +, 0xe79ea601d01b033d, 0x009bc6176f10fffb, 0x333bff2f907ed39a, 0x253d0a9e626dd400, 0x7a9bbedcfcbef06a, 0x2d1b6a7a5b39342d, 0xbadfb462a124cc9a, 0x2e8cde9d82c15cb0, 0x7c3f81bcd6f1b2a1, 0x04cb0b8fa4075294, 0xfa36d3db38cbd304, 0x59fef93442883553 +, 0x91982a741cb9342e, 0x7b9d63ac17b01982, 0x530b4ec25a293ece, 0x611069ad9fa0f0a4, 0x7a262a59b656a79d, 0x6fe6f8f4d6d015b0, 0x2c2fd7641a5d4e50, 0x24b0c507058c911c, 0x834882e492fe45ae, 0x68d0b01b13432761, 0x0eacaaaf94178b8c, 0x123e3a93006d7d01 +, 0xecf2fe69377ff33c, 0x4fc960ab4408584b, 0x2adc445b1ee45654, 0x4989681cd1d09a93, 0x79509599afe9e3b6, 0x7f6ffbbeee861c15, 0x2ed2859fd6391b25, 0x5e8bd52289b6ad27, 0xc949280adbce7c79, 0x510999e865f0cd54, 0x7f957314ce7d373b, 0x4b2c0ea4bab08ef2 +, 0x2d7cc08b5c05a8db, 0x4609a0ea23507697, 0xe204ba35182c55b8, 0x5e4d5903fdef61e6, 0xfe63842f2826598b, 0x782a3fd3ab62a179, 0xd2f01a1979e5a0f3, 0x0fb4c6bdd637fba2, 0xfbff4c192020c350, 0x14859008c3d223c0, 0x65ed7a889c1a2e55, 0x1d78daf483fa12cb +, 0x5b54d11b01bc09ca, 0x54fde75737306515, 0x89725231105b63a7, 0x712d1f394adcda99, 0xb554006ee9abefab, 0x04dd8f7bbd4c5381, 0x98d22b3a31995549, 0x637a53de6b57122f, 0x8367d69b4c92da63, 0x236f2a9514250df6, 0xb265509af63d7b7c, 0x08522e36bc4b65f8 +, 0xabae725012ce8301, 0x493b257197a98ce9, 0x33185838570e5f0a, 0x65f5477ac414eb6c, 0xd002a36854699753, 0x2be693b4d96efdb3, 0x3b32484119bdc53d, 0x55691ac09a8fae1e, 0x0249e394514c047f, 0x765674c90b78171f, 0x1166f64638d6ab37, 0x746adba4cb52d18f +, 0x93e293653dda6cda, 0x5d004ed52ebf0b68, 0x65c7c42d0ad96cc2, 0x3350dbe11cafca74, 0xc638cfa8942fef67, 0x0ff2dfffc5ac1164, 0x9e1b625e649aa471, 0x13a219d03d2eb86d, 0xdb92859ebaf9f7f9, 0x645c50918f7d5abc, 0x25c10cfe99f7e5c6, 0x13d858b53f90170d +, 0xddb258b13ab1e7a6, 0x4849ff49f4e13fc4, 0x9ef87fa85511cda8, 0x48c50d4d3b4d2f7a, 0x6c98422c8007c9ac, 0x3fdd72e65a3d3491, 0x56b18cb165b4ec3b, 0x6e2c6df9e3fc3daa, 0xf6db5aa98ddc97a4, 0x423fd4082f3fb795, 0x42f8f5edf424d0a0, 0x1a091c2696139936 +, 0x3161c2bbb3b2d58a, 0x2e8d339eb0fb9099, 0x45ef7d11f6fab685, 0x7f222a068db3da4b, 0x9af96f9742549a7c, 0x55370df31dcec81c, 0xde98e81b131af02e, 0x58bd0622a474acee, 0x8ab40fa7ca882e0d, 0x5b4db195655f2410, 0x4754eb479ada77fd, 0x67a8a437d6fc8a7d +, 0x9888254a4f0c9d58, 0x3232ba83bed0c618, 0x587b0de0207b57d9, 0x020df6becb096aa7, 0xef9e41052a29a8ab, 0x4ae671ee70a15a69, 0x167ce954923ee086, 0x6878c3996c1de887, 0xb29c711490ac097e, 0x1cf41a9c2577d144, 0x0590796ba46d8d29, 0x1c2e6dc8d4aebb65 +, 0xbfb904f8ac9b4cb9, 0x4ea1742c786469e7, 0x5a422f48401be57d, 0x0be0afdc77d6d32f, 0x5e8765cba2c738d3, 0x7dad0475059a089d, 0x9288ae0c40df7df6, 0x51c65f97715a16d5, 0xa9615d4c786ff9d4, 0x507ffe03ec0189ef, 0x1c1f46684604e41f, 0x282fe9d567db0efc +, 0xebee7f8381fb8178, 0x5bd4b6045c208d57, 0xf35694743439ed71, 0x7cddd5a373ebc5ec, 0xa58df33cc68e3b5f, 0x40e6714f5c5c8df3, 0xea881d4bfd489131, 0x6b36400b491c28c1, 0xd4475cf594b6303b, 0x5b630cddc72e654a, 0xa0b587ad34394ce3, 0x3ea3ba6014f86275 +, 0xc3deac125d20eeee, 0x2ef3568410a2b3bb, 0xee6ba3fac5d7ec00, 0x5fabcb3337aaa23c, 0x6b1212e7b817889a, 0x0b37d285a9be51d1, 0x617ca543d762bf51, 0x0896b4ca694b01d0, 0xe3add9718277a1fb, 0x553dee7dd4784865, 0x904b8f7e936cf430, 0x5b6a78f20b244b90 +, 0xa2b876c2914b9bfa, 0x704de952e9d969f4, 0xb04ea1b54b7e7654, 0x5d307bb3949cf660, 0xcee4c23ebd049d17, 0x7a88293bb1031063, 0x00b8432b8286f656, 0x260a9c86a16216e5, 0xd140e6e6629d8686, 0x296011ff5601a000, 0x536f0f76cd9b2928, 0x267409c23a823dd4 +, 0x0f041043797f8423, 0x3da6102605962ca9, 0x2e69dfeea02098ea, 0x427e7eeeecd3a0c5, 0x75efa5e8a590793d, 0x1f5841df6dfdfc91, 0x1aa1e1b8b9f3c326, 0x07bd5b0983fcee91, 0xd169420be9c48939, 0x7940334f0bb9023d, 0x9bb330fff113764f, 0x674ff1b0cfe246c7 +, 0xe2083f8d7129cbab, 0x7e6223e3d9c04904, 0x9be411a7d5e883a3, 0x72642664e7c25590, 0xbb1f783b5c412322, 0x46716e8fd737280b, 0xfa363eeaeffde271, 0x6c256c131fc2c3b9, 0x13259abfcb2ce1d8, 0x53b96556e96aa708, 0xfaa7c8d25119da19, 0x05019f438e9f8995 +, 0x05e1d55a9424f1ee, 0x63e8e14e6c2f3f09, 0xe9d844e997a10158, 0x51904ed1e94a0ca5, 0xb09462d4df6bc6cc, 0x2ee5308e62172691, 0x3f8438484547187a, 0x62b92b8d9739ddd4, 0x3ca54ab5d39f083c, 0x25b3336048a288d4, 0x7cab0fd67e296979, 0x58ba2e783962cbb7 +, 0x77808f1a1b8f3515, 0x290c219ee7153bdd, 0x7584441f79128f01, 0x0442db406f5135e3, 0xe741de52ec030a9d, 0x37469756586776b2, 0xbd64c2a7173adde0, 0x2280b66d20888d0c, 0xdd1b53cb4adb0fb2, 0x3974964394c445be, 0x53b6a95e7c7fdd97, 0x6eacdc6f50496d95 +, 0x178d04c0578a5bb3, 0x0d171a5f5215c9c8, 0xfe0d0171c504962e, 0x04eece54b220495e, 0xac4d145001db67aa, 0x6577c466962160af, 0xcddae62d99686ad7, 0x7a053a048d230d89, 0x1ff09aa0e605a880, 0x5d260426f355232f, 0xfbdaf7b0b53aab89, 0x5eef31b9eb0df78c +, 0xfb787e56b7276288, 0x4dcccba87d630d06, 0x415e4a4bc0a44b01, 0x0f0a981f71d8ae33, 0xe0ebb786f98a1502, 0x0ea4aa3ce70dc628, 0x8d36240617ebe037, 0x2d20c0e1d2002b5b, 0x336f8aa411a30282, 0x1d87c67d8178ec4c, 0xe468dff8ac26b63b, 0x266086bd7f11c9bc +, 0x05cfeedc80d829f8, 0x146902a029dd3355, 0x413db9327c068394, 0x55fa413791f64c38, 0xe06395c10021bf9d, 0x18d66268cf79ce45, 0x9e7ae6858dcc21bf, 0x3ad51dbe97b558f7, 0x06792c747aeef43c, 0x27ec9b782170abb7, 0x6aafca394a23e935, 0x18f7cbd98db64112 +, 0x34146ce6b36edbfa, 0x1dcfb4eab7ccea23, 0x68498e1f45b35467, 0x1b20d71a3b71d412, 0x7a875fc94e602e3e, 0x78c15fa449576c2b, 0xb52326d01ccafe8a, 0x3f53f57324d70666, 0x3830836e39bcebaa, 0x27a30c73dd02c884, 0x5dfed73dedf2306f, 0x75ee4a8b6cf54f74 +, 0x97ecc9c5851a8e3e, 0x496b581690c3df2d, 0xf7bba1fe2d169e7d, 0x4b06184810a77bd3, 0x40e6d643b903c7bd, 0x3c90f63b5176906d, 0x92f47e1ac51f1ec6, 0x70c2454c53cc0dcf, 0xb5a75d246c653b4e, 0x7e5173a420a8b0df, 0xcafb44c471d0f4a3, 0x69a3a4e92bbe5977 +, 0x26e93183cdfeb424, 0x1e0489b56fa7e130, 0x669befa672fe9979, 0x0f8aea6a7ef65bf9, 0xff0b883ea96b51ff, 0x31a668763c3c8867, 0x6887a0029701c9be, 0x545644cd70c87d63, 0x537b6fb7db9410e0, 0x6ca227f10229b3b9, 0xc7d1b4d71ff22468, 0x522058d3b20569f9 +, 0x5f4bfd813a51fb62, 0x105b94a3a42424a1, 0x96dfdb685825857b, 0x14d98588154500bf, 0xb4db83514c7a9404, 0x67aaf998856faf37, 0x1229d7e95dbc821c, 0x7e617a17a2f72bd3, 0xe964cdba7222695a, 0x677619cc40a07eaf, 0x7f82c099a8df7538, 0x2a219175ec95a1ad +, 0x755ac147b51ff3dc, 0x4a87f652f86823ec, 0x6d8d4a923f50278d, 0x4bb952ac98c0120a, 0x968c57a6a31e482c, 0x0855a11481fd5653, 0x3f05db6ac608d16d, 0x33f9e5746e1079c6, 0x1f3458e3ec51f53a, 0x4ae3fc836ceccf81, 0x3c0b2e2db5875ddf, 0x42336a1262cbb5e0 +, 0xe3651453cadc3868, 0x25081cfd6e80a2de, 0xd4cb31092872e53a, 0x16ca9349a11a9c37, 0xb1d3ae440d1cb675, 0x41b2d6ecbccbd6a4, 0x475e6a844c3d0ca1, 0x2cd0e0dedbf07023, 0x85ad446ddb002a6e, 0x72a06e5419a64609, 0x9e779387e9a3276c, 0x414a8163a9408b10 +, 0x25c7b53c1791333e, 0x3ea57190b42cd838, 0xbf20b346b094f121, 0x47570cba99b06c9d, 0xe6bd01c8746cb5f2, 0x3c0b0b8c4c0968ef, 0xb22009690e243975, 0x251737e4a5643da2, 0x3cdd49123ab89dea, 0x68748cd1e3cc45a6, 0x563746685effea7b, 0x4e4c5b1c86eb3a29 +, 0xe1ba017516d32070, 0x5cdd35a0c4ba93a3, 0xdbc66a0c7de30288, 0x22107156a0f700f1, 0x0fb69045aac0f647, 0x111dcb9763d08bc0, 0x266db39f6d78cced, 0x02a32587c7033892, 0x76fc94ce6a2a4b19, 0x474db0f12fcfa96f, 0x0c44584c08377ac7, 0x5f435bf43140f4c0 +, 0xb9741c3014eef7a3, 0x54596c23b536ff04, 0xeadf56bb6ea39450, 0x32f24f6e1a656b10, 0x21422e4dd5f54e3f, 0x0d6ad57853660607, 0xf6f62ffdd0bf9928, 0x72569c930015caa7, 0xf4293579931b9216, 0x049d6a4057e6827e, 0x6223e20060be0e05, 0x20d91ae969dfa9a4 +, 0x02611b345456d47a, 0x601dd413d1bdea0f, 0xe6b017b26bbc9bf8, 0x63399ff3d6542359, 0xdbdfe225045a9764, 0x10acd93346649beb, 0xc652d5a50e0535ce, 0x49efbd5639c4caf1, 0x65a5dbd8a304de65, 0x08ddebed0e865be8, 0x5db8337d5e715261, 0x34cf4c75496807e2 +, 0xd840c7416e44b56a, 0x10fd30d282d8b151, 0x36ffe6df2c1c9568, 0x66d8a38b6d31a2b1, 0x01fad3aa61984774, 0x412a9fd87b303d90, 0x2720945ee0f0ec9e, 0x0c91b4c7ea84cf37, 0x98462f25fd5832f0, 0x6f4cd578c490d842, 0xecc7d24c31ed3342, 0x580ab96994515fd8 +, 0x6d8a97ed98465b3e, 0x16995dc010908ae3, 0x50626a4e555b774a, 0x082636e5a8a9b568, 0xa99435cc4823b413, 0x41fc423d10eff4e7, 0x114236dce6f9f9dd, 0x6c3995c4bbe0aadc, 0xf3f22c975935753d, 0x6b1b3f27edec2a78, 0xdbadaac32ccc292e, 0x3856036f8a3795aa +, 0x947154caaec01d73, 0x0a22e573e3f0f49b, 0xc50c949f39c184a3, 0x2aadd0868535d0c8, 0x22bc5bbe5f992446, 0x15d36adfca3ace90, 0x038010e37a6308f9, 0x161b06d8d7180307, 0xcfbf4e3abef8d056, 0x2a1765fe9c7696ba, 0x6a15d44ce18ef392, 0x5405239c0369de64 +, 0x5fabda1210f58e29, 0x40cbb03974b37035, 0xa29fdf2875322520, 0x3b32ace85edac547, 0x0f0c92b41d679df8, 0x7f07ecd47a7d2f0c, 0xb5fc65c05accc95a, 0x0e8b1da70636f221, 0xb2ebd131f4e8a846, 0x7df51e4aba57f391, 0xaa2f3d40fef689ed, 0x0ee1e115fde5d582 +, 0xf7d025b42e240ae6, 0x29fc1befeb526af2, 0x7c5ffcaff205e565, 0x4cf4d0d8840e2e1e, 0xb8b00d1810ad0ff6, 0x44d3af686ba915ff, 0x86a8fd1eeea8d08c, 0x3eb300adcf6edc4f, 0x8db03c266b588186, 0x289d0fd301e96881, 0xba83ba260cccc170, 0x26ee69546ceb0c77 +, 0x1109d8bf92c4ea05, 0x033aa036671937d1, 0x4bd9902e5a664a0b, 0x42bd48ed44fdbb71, 0x7359e19357a9622d, 0x0d6ee92855dae22f, 0xc24debb323643859, 0x4c60fee1e191766e, 0x3beaec0e99faa328, 0x056c2ae1709c5b0a, 0x7fe89e0c62710909, 0x7e3b5cd3ac4e6ce1 +, 0xe9d06486ac7370a4, 0x4b1a8c62e99f9429, 0xb11a50e20bc3197f, 0x75ec513c25dac300, 0xfb9fd064b1466dca, 0x290379cfce59308c, 0xca3ee3fb7db99943, 0x2af7a3e930faea44, 0x0d294e6d1505e35b, 0x7d534585181e001f, 0x90285700831d4cfe, 0x419f25105d06c90e +, 0x5f71e79f5f828172, 0x02921e2a43326798, 0xa0981553e84d4a6a, 0x220c82041938573d, 0xfd2b5b78ef20c927, 0x3c99a2dc611caddb, 0xfb1247fd99ed2828, 0x4b3a3739f724890c, 0x7775ea2d7d2d1017, 0x3ab07cb5ba8ac987, 0x82e5123a20a6b5c3, 0x44965098aa82161f +, 0x20948c77e9ac4c0c, 0x521e934ab214157d, 0xc8f4f4052dffedab, 0x1da963c2ef46f27f, 0x3be7631e212fa2e0, 0x0d188e88d1a4184e, 0xb4483ed385de4bae, 0x4ffadfde83d2b0d9, 0xacebd9a51a938608, 0x40968c0c9302b0e8, 0x85704404d06f3a5d, 0x3e9f477a61a26d37 +, 0x1da1efc7cbd18d12, 0x4fb87a47b9f2cb04, 0x7556a45e8b5c8caf, 0x7f6991b7723b35cc, 0x3fa10a169532635f, 0x15e61b1cd72bd52f, 0xe6b45dc3b4667c21, 0x45cf3bd4bbf39baf, 0x7343b0636a9d63f9, 0x457551c49ac49567, 0x331e611a3fcec018, 0x7d19e2584756b92d +, 0x78951df174059655, 0x0573cd896a793337, 0xb3e37121fd458870, 0x3cc032b1a1bebc3c, 0x2571dd06d24d5a41, 0x017382ec4aa29ffa, 0x6cda850c15a224ed, 0x6af59bee2d7586d4, 0x287d3c4027f80ee9, 0x6aa570b9e51d4f25, 0xf29f327c5e0490d5, 0x00fb62f93f43edfb +, 0x7b06e602dc313277, 0x5d8dc98e723b039e, 0x5bb61813041a589a, 0x2a4c9f13eef7f1ec, 0x9439edcb4bbaba6f, 0x027f4d494e7784ad, 0x087ae2a2fd6bbc8d, 0x230f37ba41aec2ff, 0x63876e43daaac09c, 0x28abd7ae6e17dbe3, 0xd354d50cf000982a, 0x1dd774a1273aea75 +, 0x243658930d4b0902, 0x0df50723a2da63d7, 0x22bc07b9ac9628c5, 0x134123d68aa939cc, 0x4e84ee2cf0d450e2, 0x53a8c6dbd4aa9ed1, 0xd06e741c45610565, 0x608da7f96f2f7e19, 0x59b7fc9fe6a0243c, 0x0da36bb46fd1eb3d, 0x09a11de836914182, 0x3becc1cc0b96f1e4 +, 0x820b8a4cad71c17f, 0x2a425dd0204a843c, 0xf6f7fdaae1523c28, 0x5fb74c0c961e6fb1, 0x0c76e0f72b7845a2, 0x273db117946ce778, 0x7a22d35cdea5934f, 0x73aeeb1b24265d5d, 0x938a618552e4392d, 0x6050215beb6c1923, 0xf32f6ab781efbf2f, 0x2e4ece5c476e1354 +, 0xf2a4a59613812356, 0x555185da018933fd, 0x2fffbf95863bce54, 0x72644f9c3181e7a6, 0x98c6b1d509e3d624, 0x5bddd5730939d7d0, 0xdd197613d550fbad, 0x7671fafa1facb923, 0x13dbb61148c5b802, 0x616bc5c73ccdc3bd, 0x0b175b4c46fd8871, 0x498a1eeb000ab870 +, 0xa49f1ca2d7802521, 0x6906346cce00be5a, 0xf1bc33c727dd52b0, 0x5d005ff3122fd749, 0x51318ad5d7c622e7, 0x50f93d6d15e46e82, 0x88dfa2123ffff3b9, 0x3848e6fce3cac6e5, 0x6cefc31a33ea4f5e, 0x0cc5e7dc4e5e144f, 0xee2009402e59a7e2, 0x257679fdb86f4712 +, 0x4cf68953d8b17e83, 0x710f970c16ce2070, 0x4000b8e9e51e6aad, 0x5af48dacd01f24f6, 0x209679d5d3fcc916, 0x0a3538dd7cbe8232, 0x2d6d7aba44d990d2, 0x46c718f2d4b2c1a6, 0x9953d799a378233c, 0x4f4e80f4a682e7a0, 0x9912f04acbb77eee, 0x317432079a195b2d +, 0xaccccda6a1c11e3b, 0x3fd895817d0f3be2, 0x016db17673f750ea, 0x635fc619a24009b6, 0xb8447ab3370da1e7, 0x6c893aa19abf4221, 0x5f35ac703d8508d0, 0x13533d324d4adcb5, 0x84610370dece8512, 0x2223f126f9a70f4b, 0x18f00d60f3bf6a04, 0x174bd78b20ef8543 +, 0xeb179bc6a1698189, 0x732bf44a62015302, 0x98352342bc0e4bc6, 0x053f6640c1549e85, 0x65eee8b0397c7ce8, 0x790451f39f2fa27b, 0x36ffa0cb286cdb97, 0x46d07cec4c967bf2, 0x7c849ace30868412, 0x6dee239d339ef499, 0x8ab78548f273e57f, 0x01c5bebd8b7f5ef0 +, 0xe440e5f042eae93b, 0x65583f57fe057db6, 0xe6d5d26c24a565c9, 0x6b3b87a0a6ad702f, 0xd3f5d533117b8e64, 0x4addb9d0da92df89, 0xf1bd51990e0f9bfa, 0x30c624ec1dbcd0a4, 0xafaf2f00da7023a0, 0x3086e132b54574e4, 0x93bdbd4bfd3dd8c7, 0x690976ee132c892e +, 0x86fc11c79524d198, 0x0f6b95662e02c734, 0x5b78bb385564f568, 0x55c9b3f55d7cd16b, 0xdf1316434ad1c07f, 0x093d67d3fdf312de, 0xa1fd2257ea57b3d6, 0x4b5b18abe4b54439, 0x66c28f5b59d796b2, 0x7baffe6e642fdea4, 0xb9d3753265e68ae4, 0x40903bd6dfb02d6f +, 0x357958d4d72d6bc8, 0x179330dea4659dd3, 0x5a9ca85bc8721aef, 0x0209f09e03c9b225, 0xc0bf2e9738933495, 0x5e0dde4d715e50c5, 0x2743c96b66a6b951, 0x6af96188a0d6d358, 0xb2f3c72820f2a709, 0x5e9b8fd43327d9a0, 0xf0b13f5324012177, 0x7abdeaf4f741bace +, 0x6f006249351471f7, 0x3204eb91cfe9ed6c, 0xe09af1c83c13afa2, 0x6d70ed88d5de535b, 0x2078873d1a2faa1f, 0x5c73bedb8d96f3da, 0x41bbb407a3a1ce1d, 0x7a40ec2fb54eea85, 0xd6d569cb9dd722e3, 0x10acf67805927b6a, 0x27c61d818cc0ea05, 0x57b175c9f59904e2 +, 0x4f7b40bc92b5a60d, 0x51431f647b46b89a, 0xcd84dd55cc2a720e, 0x6b36059700809a1c, 0x78e3e5dd060e9a0f, 0x630c0c1a146c77d4, 0xc9925b0dea8fee2b, 0x4728f0604b16a06d, 0xb4601050635b2318, 0x2484f7281864709b, 0xbe2ed2a2523211db, 0x6425d4ff23dd3a5b +, 0xf0868c09017aef5e, 0x2733d1e1adc6d5ee, 0xa631db49f17f87e9, 0x36d753ced54d5727, 0x451d17fb6c4af537, 0x1dcc4d611dd55b04, 0x0bb8de0c8d3e549b, 0x2fb2ca1271592c3d, 0xd877914ffbc31ced, 0x190809a196504d10, 0x44bdd65a970277e3, 0x13195c678b4b01fa +, 0xe69a41a54f84d41f, 0x61c7c870565e4508, 0xeca2d2fc6f0e1c9b, 0x7f065480e257152a, 0xfaaa9f7c3a8873b0, 0x43fcdb8db58a324a, 0x969a79026e9da7a2, 0x4eab135af328b9d9, 0xb38aaafe87f85f7c, 0x69eba4fe1a6b6f32, 0x5607f6c6b4d27cbc, 0x273072bea774f9e7 +, 0x3c1149e3c8d51db0, 0x161f8cd433c28bfa, 0x765a61f218fe70da, 0x442b5d405f2036bb, 0x96f790271c564cc1, 0x3d5dbb33505cc956, 0x621a38b446af395c, 0x2da978b45bb70ce6, 0x755aca711da49388, 0x46f2e33e55e86df8, 0xfc5b454d5cb7be24, 0x67df47d68d8f6d12 +, 0x7a1e224893898aad, 0x0400219c89c2d13e, 0x6c969e4d63d460d9, 0x4df64d5df8b60ad2, 0x1feed05a45ff89ed, 0x290c4b59e684b4ef, 0x97ffbc3df096adb6, 0x4ac6037e76561c96, 0x1bc40299115e51b1, 0x7169e0a1d96aa1be, 0x43f55f8b6bac596c, 0x1cc6a0603081a178 +, 0x8e1d2db69bc925d0, 0x6ffb86eed51d2931, 0x3ad1eb242e0af1b5, 0x338198152fcd6d7c, 0xc1f381496df13943, 0x05d9242fe1c60b02, 0x39617510de7eec81, 0x24d8ba5ac76b12b8, 0x280eb2db9e548483, 0x6c51317b3a8a93f0, 0xb2a9f90939bd1235, 0x2da9de86c39f9aa6 +, 0x7f54917103127b97, 0x7be2be5ad3276169, 0xc969d703d31e9da7, 0x0500df3bbb1f8a4e, 0xea05c77685795917, 0x049575a992d09345, 0xd567f8de2daabe35, 0x383fad35a8e035cb, 0xb9353eb2bbd43d56, 0x52b3953221860c5a, 0xf9e4bcd46dbec03e, 0x4b0db0b4a7b3279c +, 0x8cc5f6b6e1ff80c0, 0x1bd2ce464b552215, 0xd008eb25b39c4236, 0x3b4ce5bb2f42a9fc, 0xe1f249681d153d9d, 0x3e022cb14bc4c5b9, 0x8a11d021c8ed5a53, 0x560d3fb258bec495, 0xf4405852705a6012, 0x5c8bccd2b1b3efd3, 0xd93c0f63ba7ce0c3, 0x337798cb3e93dbba +, 0x7a9f68cf800c8e88, 0x579afe689f3ebcce, 0x7dd41d6cdfbdb4a9, 0x3802410c4e1b274e, 0x64241d770cf0db02, 0x2f7c8133c74bde23, 0xf3c3fd835ed1952e, 0x741b1d88a3cee37b, 0x74e1ae644683c68f, 0x0c80dd9e0f7a91e1, 0x3984d741f3e47c24, 0x4b3eb97b6a39d252 +, 0x32e9b9410da9a195, 0x11d09fdc04ec3b41, 0xf92fd5e53cddea30, 0x296e095589e0ce05, 0x4e3200c3a283b696, 0x7e33fbba44ecb32c, 0xed3c039790ad0033, 0x5c8ebb260b5ec084, 0xa667455bb79d2e9d, 0x12fbec9d4f5bb155, 0x3aa5f6bb4d0d8d49, 0x0ca652ed7065d80b +, 0xb7938753d51c6f83, 0x41644ac1a602f9f2, 0x84223d4d63c38f7d, 0x71057b4b8b931282, 0xd39fa015165f47b5, 0x7536c8a19c33c201, 0xbe713ca4166c2dad, 0x456c98c2b4198511, 0x4793f25e1cb44658, 0x1d002f1cfe1a1ba7, 0x9f9ed6e1e1a27957, 0x095dece028426bdb +, 0xe57d3412fc1001d6, 0x481c63a0d9b25e99, 0xc756b6ba0dc02aa5, 0x24af047d79ed4683, 0xe37ac10133b68275, 0x418b45e570802012, 0x87578def0c3900ce, 0x7c5661923b8c9740, 0x5f4ab0a6fdda7366, 0x0ac6100825e4eb3c, 0x308528e42c9e4d32, 0x436e5979933ddde8 +, 0x0cd6ebe123352222, 0x63d1768a46f33dc7, 0x96cc55dff38c9273, 0x474438da7140411d, 0xa184b89b81cf6402, 0x6bf820a3aa675050, 0x3bd4720417391f0e, 0x3f2b8f859a8e0cba, 0xed952561b125da29, 0x07eb1ac74165097d, 0xc3f70d0c7db0a9fd, 0x5ab896a489294a6c +, 0xd4b608975c20018d, 0x6243b039f25d0456, 0xf766e98fc24c7464, 0x20035c09d2291e42, 0xcc0e5b5eeb462524, 0x24bcba5505f90657, 0x43a98d98e4fa9bf6, 0x3b621ec4188264d4, 0x633472fe235c812c, 0x31a20844a3316d23, 0x47b80db7d7f5d0bd, 0x22d482f5663780f9 +, 0x4df227dc52142020, 0x25076d0624bf137e, 0xcb4a6ee30a657645, 0x0ce469dbb5ada433, 0xfdb06251f65b9c5b, 0x44f82274a8e8f538, 0x98fa4c81cdec4b97, 0x0ccd61d1abb61d0d, 0xb9dc371344c5ab54, 0x35dcd9ccf8e5f919, 0x67fc81f369ba5722, 0x121b5aa1af6024da +, 0xe0b1b16b0fb1f1fa, 0x4dc688d6d3b1805b, 0x05c187cf10e40104, 0x71af39c743daacd9, 0xe691e97f82acf4b3, 0x0c46305b9243bf5b, 0xb063af137fde616b, 0x4e26e72a1de067f6, 0x61fe66d01a221004, 0x172fe9240cea50b1, 0x4ff50d37b2effefc, 0x06be02ab0b89aa5d +, 0xdd4aab96717af213, 0x32322555b58a7ffc, 0x7812aa965889326d, 0x1bd608f60d6457a4, 0x2c7b6b44e999e141, 0x113a86a87856a8a8, 0xd95469fc33814855, 0x4a18dc36f6bfd586, 0x0706b60bdb854fd3, 0x4dc356685650fa90, 0x24ef7cfce41f8dcc, 0x19049c3e632deae8 +, 0x5c9a4e28b7138a89, 0x0f0b7dbc1e5087e2, 0xebf49cdc66a362d2, 0x19e4b815e6576c85, 0x1896051ee3b6063d, 0x09ecc741852a68e4, 0x4009034def986795, 0x36b440ff39b4b5e8, 0x9bc2647ee28af1cb, 0x62613c9dd152b3a8, 0xc2018ae5dfae5f2d, 0x29ce5ef30009c855 +, 0x0b653558b21d2b1c, 0x45e2c505d1f74936, 0x48304373240553d3, 0x0528569885a82310, 0xa90d402e33924181, 0x5e610edc23cb9555, 0x28890ae7e007d28a, 0x7e5132b6b1ebae37, 0x0d5252eb7c94cb1b, 0x308ddaea1fdbb672, 0x99fac0b431730534, 0x77d54ed63b9325b9 +, 0x4d647bcb76c6ec3f, 0x0e968b22ec2cad86, 0x4b22b5ec30b08a35, 0x3b31df3b52326b5c, 0xbe84f638dac3105d, 0x7db085f133ecbed3, 0x7a8b694596f2cf2a, 0x67b2e6c15d16e0aa, 0x4808b20bf173011d, 0x25d5fbbfbe66f864, 0xf67f3f3cd9743987, 0x654250e89617ddf3 +, 0xf5a1a7e0ba0a88c0, 0x3616c781799ab50a, 0x2669c27a2d256902, 0x3a8ec380e12fd7dd, 0xa25361f44a418e30, 0x2942f3001d233645, 0x60f1d3b7535a4133, 0x14deaaa12e5c7bdf, 0x0089fbece10c8d6f, 0x4bf7c313757c803d, 0x65aa30bfbb70567d, 0x4fed47af409a3fb3 +, 0x07557dd875d3daf5, 0x36c49c2380e3c9bb, 0xa21f643d329ae02f, 0x6cf6f7474338bcb0, 0xb5df78136a0f3012, 0x031fb2df2e00e9d4, 0x4d86fccbe75e79cd, 0x23f890e082d03b7d, 0x5716a1ffb50a8262, 0x0199b50aa6cf3302, 0x6a1be351f86090d5, 0x36095efc13349364 +, 0xffe752be8ce46920, 0x65047a340b652f65, 0x320ee55fd03156a6, 0x5af6aa45278409f6, 0xa6caf283b1cf3850, 0x4e3a988f61072f96, 0x750f67926b18f680, 0x09fc3f2927d21a4a, 0x914893c2f2ce1169, 0x4d15b367121b3e75, 0x6cb12559723774f2, 0x3ee5b8c2a70e054a +, 0x7dd9b3518d84d2d7, 0x147d5a5a53f57a58, 0xe1bd0904ad842a05, 0x3a0f3b029c9a5845, 0x7153c03261410074, 0x4e203d6737058c17, 0xebecf5cb79f28af9, 0x574b889870c279f4, 0x326317b005f444a4, 0x7480da44b34f4b1e, 0x7c5f21cdc46275b2, 0x210494b9ee24e4e0 +, 0x3cbf6ca1f4aa4ead, 0x6bf3872ccbfed940, 0x19e8a84673a566ca, 0x61a80e16990401a2, 0xea2e029e7f9b3824, 0x5762298465f0ebd3, 0xf60e36d4969f9af0, 0x00b826180531c799, 0x17120ec95cf3c61d, 0x47196cd6de85c7d0, 0xb0d47cff46a5cba3, 0x29271400d7ede26b +, 0x835908353516b894, 0x4bc57f8c1eedec8e, 0x2ec5deede5c0db5f, 0x7b9fc48ac4a689fb, 0xf82ce6de88fc10e5, 0x6c5d84a70e03a3d6, 0x88a211fc4ea531f9, 0x7d5583e5918aa03e, 0xbdf2d70766fb8f39, 0x5926497e734ab18a, 0xd6a9872b800cacb4, 0x757c1cd521fd22d6 +, 0x22d50b0c13ec4bc0, 0x288a77d34a15e99a, 0x95c8e78fced3d4eb, 0x45ece109c15be169, 0x878ef262d0132128, 0x48110e9fd98939d6, 0xe3fc5425d2e7741e, 0x050ca6e71f599c65, 0xe02f97605d9fe375, 0x2af48b9bfee410e4, 0xfd34a1c107229a54, 0x43dc6f0cdcbd41fe +, 0x15b4eb7d65cc562b, 0x369a7b0dd3e91248, 0x2b087611edd32810, 0x116b234ddce09d7f, 0xcdb03cae8e90d2b0, 0x4017d51587566038, 0x081793739242b600, 0x5086e8e633cd52a1, 0xf5ddaee155cb8087, 0x773311b60d59a7e9, 0x36e5aa0acadf2068, 0x7126a4281b192882 +, 0x54a10df54f7ecef8, 0x3cd7d2fbb6e33f67, 0xac31eb6c3e740c25, 0x517db54840feb2de, 0xf17cb269b3ce27a2, 0x04a8fecd1dcc99e7, 0xfc887c1f2f85a2da, 0x280da7425bb55b01, 0xa1af72f5256a5a53, 0x71da839fc459f465, 0xc203fe7ba6587f71, 0x08a4201f77a4f335 +, 0x6cb9ea5683014d96, 0x5da17076b6b51ae2, 0xb55ac168c3e3997f, 0x41b9a32373d78f7a, 0x96f58033b8600a50, 0x6ebfba3ec9d956cc, 0x0ff8883707d66d0c, 0x2f562b035445226f, 0x2388fc015bd368c7, 0x2b7d802ce27f627e, 0x301f0369c24083a6, 0x77e139f6da8d5aaa +, 0x9f78574697fce43c, 0x02726c94565421b6, 0x1ad6007338e26585, 0x6134cc5eb35c02ff, 0x77ae739c9cdcd1e1, 0x04e96543233c7a13, 0x97d3926dcded2e10, 0x6bcdff7e14cebb73, 0x9c46ae2b32489774, 0x04a97b9a0473af8d, 0xb0350bd910d9784e, 0x448212d3e2164ad7 +, 0xf3464e0351f5e995, 0x68ab4d24b3ade8d6, 0x86854d534002af20, 0x613f7ffe5de92aeb, 0xb385b4f4608a370a, 0x220dccecbc6f2688, 0xc31ec5384abd3680, 0x25a82841a2000fd8, 0xd19e422504694236, 0x0bc1124d541781f5, 0x0808651edcd99176, 0x41b81f223d429c76 +, 0x1a6dcb2662cc80c6, 0x0b101fb0ef0d1f74, 0x6f02aed8f8327119, 0x5b4c5176ccc4a340, 0x8fcefd200d6ee8ed, 0x0548127287f44749, 0xe1efeca1fadd1341, 0x0e74bc189dc9016c, 0xe90470353f46cb12, 0x69513d3455bc890c, 0x9503686f1f2497d1, 0x280a0bb7733f1086 +, 0x14e5f99930a91dea, 0x7840ad84b03c3878, 0x46e32c654fdbceb1, 0x7e88d2822bb2cecf, 0x4d78a8aed7f8661d, 0x70eb17416ef40180, 0x97b6f1733c474a10, 0x3d0d27fc4c7084ef, 0x730f60f6a1ee0d71, 0x7bf6e3885d3d9302, 0xa1e8af33742f1611, 0x73b798ec129822ed +, 0x0f669bb094642a70, 0x142927de789fc4a4, 0x0db18e01fa98cbd7, 0x6ae4d37674be1451, 0x7175e98f178b4b74, 0x40534e319bc52c6c, 0xb7211d252c4db879, 0x1a7651f8f3ed1aae, 0x9c9a43932d50cc97, 0x630b232b7201c359, 0x327d77575f5b3839, 0x5f0e19e78431864a +, 0xbfbb00b6530a3bb6, 0x19ba9d60d97f7857, 0x759779de744bd764, 0x5facbe63177791e1, 0xc74ea511c56a3b61, 0x1d8909e84083c31d, 0xcd20094b507af492, 0x2ef1b9c07c92ab37, 0x8430ed9ef8494fc9, 0x3f9170e6df5b1fa1, 0x1fb8dbc837175d73, 0x65b961b58008d022 +, 0x7e1afb6816864b6f, 0x54c4b92c534871e9, 0xc0a1dcd60d61ef84, 0x4390f0e992c41298, 0x1e54e2c8b7c27348, 0x7a987e01a2ec308c, 0xee42fbd90c4a89fc, 0x1ed8c77f8d7c609d, 0x569dedaca99a3346, 0x0eb471e609fef4ed, 0xc915522a3b9fd03c, 0x726453b246746bfb +, 0x4ed3cae53dc5fa4b, 0x1bf1e4b34b9feef6, 0x0850df9f0401fac3, 0x0a58d33cb2422e2f, 0x3d197f9603ecfc29, 0x45e46edba1cc432e, 0x96c0c93310d9bcaf, 0x18de3a458be2c33f, 0xc9e65e5bcc12a49a, 0x71a5345f0239b187, 0x53b3b2f01c5710b3, 0x438350f57ce2ec4a +, 0xdbbd368a760391db, 0x4033638dfec29fe2, 0x297ad75ed73117fd, 0x269c08d54b106e8c, 0xa4e3e4fd238b4218, 0x1f48a1cb09208aaa, 0x9575153115cf5fa7, 0x59feeff0876fb74a, 0xfdedb4af6f368710, 0x79be1fe79fa674d4, 0x689d6bbb4c707c39, 0x394a451499057bb1 +, 0x5887d4fb21fc43b3, 0x37628dfc4b5c23bf, 0xc66b76944b34bd13, 0x6e97f0a8a45bcb36, 0x3ac6b10139edbbdd, 0x313f4846b6745833, 0xf8758d9777cd9037, 0x02fdc98f02692537, 0x9e79f381fff833a5, 0x25ac5d68c49b105c, 0x1e9f48a076d8c9ee, 0x788c85c9fe9543b3 +, 0x776ea51db3b3b778, 0x0007c44055b64db2, 0x3c392c2a82fddd25, 0x65000203be8ee976, 0xea119666ab7c50ab, 0x528b2700e8f82d39, 0xc4aaf797118b8282, 0x55e5a7d5382e0d3a, 0x15a80b22e89f1039, 0x199f68594b1247a0, 0x8d5630750d622435, 0x2687f48cc6def5b2 +, 0xa16b0c0259eafaee, 0x7aeb10834e93595a, 0xe31bcf34ce679d9f, 0x4e2c19829eee3c87, 0xa46869cb8ca35c9d, 0x3cd35313c08504eb, 0xa088eca66e98389c, 0x44c562f0f7262740, 0xd3eb8a28f447523a, 0x43a0e059bfe37576, 0x0312c5d6d0f2e0ad, 0x5f30aaf0d1614c61 +, 0x6f09a7a6e182b0aa, 0x575db3d21a82296b, 0x6599bb5eee7925e6, 0x093f89458dcc2fe3, 0x70c4af785151fc84, 0x1230c0c519de5480, 0x0e66f8f93075a4f6, 0x5de4a122633a5c6d, 0xdb99cf83f9ece1b6, 0x1c3acd4a13ded617, 0x4dfe69e68f59c447, 0x482ba1f7715a3c16 +, 0xefeed2a7c81ea8fd, 0x4e089eeb713a572f, 0x78bc74acfbdf322b, 0x4b4951ce8eb86fbf, 0x0eafb6b46ac6714d, 0x72913ed109f7d404, 0xb498bf6fcde9e3a2, 0x3c08a283ef5ded62, 0x9af09f593a48b346, 0x7ed52441d00d4980, 0xa78e843ee5df44ac, 0x25db12d420a86151 +, 0xec840e7e89d049e0, 0x5a34cbe928bf96cc, 0xd875dc5525da882c, 0x2af4442fc256827d, 0x089fb428c2ef5a5d, 0x0b573ace080a3d9c, 0x6f57282554c240da, 0x425ceda6707b6bc9, 0x94b5a8c3dde824fb, 0x264f6f6a445b5da9, 0xadf292191c5c1eb7, 0x5e302e82fa4e5533 +, 0xf51712fc44237f35, 0x2b0af62c42e56e66, 0x10392cb4d9c71b75, 0x4d7e08fe8457a95b, 0x210b9eceb04534bf, 0x73329d1c7d88e1e5, 0x667a43fdb4ba79e9, 0x3435ec04276ede87, 0x38b8540a1a78b098, 0x4f6c266e6793bb78, 0x447ea35172754041, 0x109d7b742d8c3dac +, 0xe3ccab45d2a4f6f7, 0x59040bb73f3bbd2a, 0x730b39d65645bab5, 0x5c61aed2f83382aa, 0xa992143de3cf83e1, 0x13455cb889b700f9, 0x54648228b310e2f7, 0x5b837752ee0f733a, 0x3923a6c0e5ea0dd9, 0x5ebebd01fc9ca9a2, 0xa34c205b8fd94258, 0x7d1a10029a0b6cd5 +, 0x6c83c02241a46527, 0x4127c85d6be1fc62, 0x26f86ff5ca7240b6, 0x2167391e7dd95cd9, 0x79227506ac78caef, 0x1a2cf919b8832a0f, 0x07745266405cf574, 0x38095a07f5713ae1, 0xe5eeab985ca3e7e7, 0x6a5dd9eeb734d639, 0x991027ebe44a4822, 0x311085fb4de9c1f0 +, 0x33f361e21066c3b5, 0x550091d2dfc8688f, 0x376345c5532bac13, 0x0aa0898f990931b5, 0xea2f3346e5d3226e, 0x208790ab78776afc, 0xac7c2ae63433850c, 0x3c5c373ada10ef52, 0x96c1b4003f4cde6a, 0x4546a9c475c09781, 0x6c961fd3e8536294, 0x43f36e63fc0d5066 +, 0x296601d8c42167f4, 0x241c1fc38565471b, 0xdb00a27e11ce9617, 0x60381181b7e7e4ee, 0xc1076b7635ac4d52, 0x0166010ffb8dda38, 0x5238f69becc43e0b, 0x63303a2015708b17, 0xe8badb2e5bb22591, 0x3a10a4e218b6131d, 0x236ab01aabf1a7b3, 0x1ce8a51a68a4126f +, 0x59e775e2a2a87928, 0x770b48eb4b738301, 0x0b43c2be176bf79b, 0x1957850fb6424660, 0x44455ee1ecb0ab2a, 0x620ceaa116eef4f0, 0x0198f62cb6183f6b, 0x3274f78eaf2d55db, 0xd2ba4e460cf7ed5f, 0x19cfc17bc0b66f43, 0xcbae6f45b1942722, 0x5d93e44739147b58 +, 0xd07180b9d28fc597, 0x35372b21b2ea5a46, 0xed2673477f083464, 0x7a9ebeeecc57e6c2, 0xb51d991a81a6b314, 0x35e7d90f4ed6de58, 0x45f21e209510dd05, 0x446ffd2715c8d380, 0xe69b5c7a9b6d3e76, 0x1379e79fb96912e6, 0xc161c848bd508738, 0x22264a049d8cfff6 +, 0x32321a68ff7ef7b3, 0x57b0e50cc585b333, 0x1c08c65ba9d764e7, 0x5534c793f92f00f5, 0x7a1ced97eafe6fe4, 0x6b8933739202599c, 0x618c5f8fcadd3ff2, 0x2a8719b3e6548653, 0x346a9ec5c4200f0c, 0x7a36b8d00d0eda58, 0x844b22b75021accd, 0x769737059fc5e465 +, 0xdb1ba69b5019f266, 0x1777242305db9ac1, 0x491d11ad264b6ff3, 0x136198dfc57a3053, 0x4a6cc64741eb7176, 0x14e811c97fc97650, 0x6b64667f71be386d, 0x3286fcadf019eb5e, 0x3f2591f4498e10a0, 0x674fa7c32df7867b, 0xbae8ec7ee100dcf2, 0x03b2c0a20a6372a4 +, 0x4c8d76b471e24474, 0x421fb6a7b8a3216b, 0xc672bdb2fe8f514d, 0x202af653d9aff3f5, 0x05e5f80f9626953e, 0x7b721fa3ccd42ffc, 0x99d8e481c0f70479, 0x054c31746d23362b, 0xfbef2e20430e8025, 0x60e1e3f02e7720c2, 0x161701874eb347e3, 0x363924e90cbb77a6 +, 0x180f5ee1863a1a6a, 0x2f79c0046ff79fe2, 0x44679866e35447f0, 0x1c64c6dd73e0d636, 0x1d8175566341469d, 0x5ba634965b8b9e87, 0x8f48744f976952a5, 0x744f28d23db94c8a, 0xd15e84b1f232da34, 0x556f3d7aa38bee8c, 0x14693c56e866ef89, 0x1564fb9a0f81eb03 +, 0xe97eed56fa2b483f, 0x6d3f7e01aebd1957, 0xae8f128aca3b3e45, 0x3d41e85ba2afd3a9, 0xe4fe485e4b6d8328, 0x65c49b4c3e98098e, 0xe96a00e054d6e91a, 0x394a2122738cd006, 0x715cca3dffd90785, 0x7bc3dcde15890965, 0x6dcdc47a33a148ac, 0x435db9d6dbe1bd55 +, 0xd74d4d6e0fd89c27, 0x25e727f6a5380553, 0xbe54127ba6c5189a, 0x65c87d3c3e61939c, 0xc34a6d122a809e2e, 0x7de6b787f097eafa, 0xb8f8b6e701758661, 0x10705fbf97042046, 0x1591614e6da2d44f, 0x7c74f26ec6eb070f, 0x9ad98c1a50249c60, 0x6e1bbd44d64b2302 +, 0x937cee76047790f9, 0x5b4ccbc70beaf690, 0x332e79ae75ae0dae, 0x2e6394161d093556, 0x4b378bf68f6849f0, 0x6c419fa0cebba72d, 0x8bb431e1e273f2a4, 0x357cec80bbe024fd, 0x83a6e913962f11a9, 0x7808df02e2523718, 0xb6690b5dabc49e13, 0x6cef23259375972a +, 0xd18ac767b5e551fc, 0x5a0ba1dddb15bd36, 0x6f7923de219e3e1f, 0x3ec23588db9b5cfe, 0xa4fc23d42c83bbe0, 0x21581a00768658cd, 0xa295b6e57110218e, 0x3e7bbab1d15f477f, 0x2266c03d3f0d0635, 0x4174f08a95be03b5, 0xaa1a674abb8cbeb8, 0x6bdf6ba553ae3390 +, 0x8a31f824638545e2, 0x2a9e37a0f0eede53, 0x148a53d8cba69f65, 0x64c587e816d96316, 0x777a028a47e97e93, 0x13728e46befb2e0e, 0x13138b44862fa665, 0x0fca8c38a87775f6, 0xcc44bd580dd067fa, 0x40f2f7642e22d02e, 0xab3ba6db80c2f728, 0x5068aa2e2d25b7f9 +, 0x5a8a842c0a2923ff, 0x67c39e8a1006c196, 0x8f5cb9ff55460a84, 0x2e735c20a419a518, 0x0c6ee3fcbfdc2da4, 0x5bf6ed60a87b92bd, 0x5e4ce130e8e1608f, 0x0932ceb3e50028e8, 0x793cf8a0538cbfb8, 0x4e89e2c018beb7bd, 0xcaaa79642f5060de, 0x542a38a4d13f0016 +, 0xa1b0fd9aac663e55, 0x5158bf1f7b33c0e4, 0x060e82f65a4119fe, 0x32347069a1529fc4, 0x5c96ef69127480d5, 0x409a902134df6ffe, 0xdbe8c392eb6c7013, 0x73f2c48b0e3b4a79, 0xddf5060b937e2dff, 0x1534f901278611d9, 0xf47fe29ae4fd49a7, 0x7a2c0bfe75539f29 +, 0x19e04d1b2b0fe7fb, 0x56381ebd8181b50e, 0x5c8970c249df4ac3, 0x08acaece8ede7685, 0xc44f1a71aca0d20b, 0x623edc8d92e4ac3a, 0x5496a7e5885a0c95, 0x20a9ba37315b116e, 0x3765873809f5b55d, 0x23c44c42ebef2ff5, 0x56a96d921f724573, 0x3217815b72b8a9eb +, 0x2cc1b42f5350a489, 0x31f0b36e85b8c70b, 0x504a5c8c4d2ce34d, 0x1af8ea26b3786eac, 0x69bc5e26d7afd62f, 0x21e399d04247bf9a, 0x6e6d6676a88efb27, 0x476212b9fe9a6fd4, 0x0740fb65284168de, 0x5f7570be65e69408, 0x0166c3279dd81c29, 0x6565489007c4ed6d +, 0xbafb5bd37b5219c9, 0x00251709f2e210f7, 0x0d22639b51c1198b, 0x0f3c0df3be3de811, 0x3552612be3374eef, 0x0834744318ffa0aa, 0xcb9f1c1e3557a00c, 0x20c359f5de8b6614, 0xd319482a34d05268, 0x42165771b46b75d7, 0xca336c22e8d911a6, 0x4d072f70067a47e1 +, 0x9022c6f101555e9e, 0x4c8c7eaf7cc2d697, 0x629810b2d8044817, 0x25110bc01b06c9c1, 0x1bf9c06bf39eaff7, 0x6cc36f151f52b4e8, 0x76b73a6a14b62068, 0x47dcb0dc89db3821, 0xfe9dfeac2f670f41, 0x625b5c93b973c417, 0x5f8c917930133c1a, 0x6bd35f3e0992bb2b +, 0x03b5391a85409e5e, 0x7981d8fd16362767, 0xdb45c80a32a23cb6, 0x67356a7ef48b2dc3, 0x6189236e9f01adaf, 0x07a1e954e5032bd6, 0x53d627199c69727e, 0x25d67e4163cec014, 0x18e7bb6a63a80738, 0x3112be4cb5dcbc74, 0xad9ad6d381643f04, 0x116112cbeabb734d +, 0x32623abe2d66ff07, 0x4d780300822436de, 0x9bed066c04497808, 0x40db29b39ce86700, 0x6e5e5eb3805602a5, 0x52f227f2b1b9b40d, 0x51c2c4c197a18394, 0x6d8bca423ee270bc, 0xd6e60cfe8fb07f72, 0x7dd66c3970f940c6, 0x66aea7b59a0b17cc, 0x75fcf8b00160d729 +, 0xbedc5ea39b2402b5, 0x0dc3600425feedd5, 0xadc1ddf2cb1b6631, 0x205ee93e3aae976a, 0x7a2cb4e333c98498, 0x7d12eb776d56872c, 0x8e339bc1b41599fe, 0x4600f0a53fac9427, 0x1049d3a372f14304, 0x7b54e020b22db742, 0xd567962272a35739, 0x27a1178b1115f0c4 +, 0x6cfb39d619c35e1b, 0x5cb96fd1a9d9d486, 0xaf45cef7fb4fffea, 0x4a73d7b2ba9321d1, 0x44b46b4a80be86ac, 0x2769b50579e8f734, 0xab5d109e7472f372, 0x2bccfba1cbe995b6, 0xc00026115332f6a3, 0x7acb287da1561c53, 0x21555c608cd90dd9, 0x7731d1b2878dae13 +, 0x32122bf5ec1a0649, 0x592b5fa180ec8467, 0x876be1b5ad9ce66f, 0x484c1cc5bb34819d, 0x08e4cc425b30b06c, 0x2766065f0e4d22ce, 0xd90825644987aeff, 0x3a835fcc7fc456a6, 0xf4d801d2cc806d69, 0x41d767ecca55f839, 0xf2dea9fd01f1e74f, 0x74d01b97462211cb +, 0xe43e280ad29f80cc, 0x5cdf66a69029b231, 0xe8d655a03c862cd9, 0x388e38b58d0e8c79, 0x5d9aaa4848ff83a2, 0x14d6fbee4d6cbe74, 0x0426dcda912109ea, 0x1bb7b9cd75d4b541, 0x3a3c0504b39b8505, 0x35a3c5882b31367a, 0x678793d635a6473a, 0x66abca7e20202034 +, 0x4a90ff1dad300021, 0x18f29036544d2684, 0x2036d39b8f69095d, 0x36490f5645d18cc8, 0x9414d7368ad3562e, 0x7f8108a04558487e, 0x93db0e56d653e40b, 0x03f413ea960537bb, 0x984717b77f7267ef, 0x6c5d9da4a5ee7305, 0x725318dc36060a49, 0x274397f8e79a239e +, 0xbda7965b4095bab0, 0x6292b2505c7866e3, 0x451fb6a0672d6733, 0x37c560f40242a859, 0x151e56eb818f1423, 0x63451986f0c22ee1, 0x9275ff873a5c75e1, 0x178cdc734a32b96a, 0xff7adbb24244aacc, 0x76518aa0dfd96ddc, 0x161c1c8c81071219, 0x0584d44c10a3e6dc +, 0x2727282a09e9acab, 0x1298e49c34514ebd, 0x0323d059ca1c0e6d, 0x6072c8b87dd26bc6, 0x36eca2ab28d36f26, 0x2a977cb5aae4ea2a, 0xf157d43a0b9546a7, 0x04d60af0ed661d29, 0x34bc1080126e4402, 0x7677ef9a21589171, 0xbd13797278f07a40, 0x32c0daf0b57f20ac +, 0xbc83fd1b8366dc2e, 0x6cd07286c4e670ec, 0xf35485a3f339dc8a, 0x6e7e9285f2247e8b, 0xa9d19d3a09943bae, 0x43fa5197eed852a6, 0xf911398a043242fe, 0x4a100dcb1312cbe9, 0xbe2fd86be910a692, 0x614fd829368d7937, 0xdb5a98b1a92d578f, 0x46f1d23e1b0dca7e +, 0x8bf4c6725e813f36, 0x68bc89078129ce91, 0xff56503ae28f5c7f, 0x2b6e0f4e42178ce5, 0xa97cd947ec65895b, 0x7aa90b66280ff6c9, 0xebbaf32df158a0a0, 0x6a748d0ac02bb713, 0xdf79b5d619e83397, 0x16934947f6485b69, 0xe75185521ab32881, 0x20791e276a7460c9 +, 0xd25c403e22c70bc9, 0x0bf079518e66e1d3, 0x45dd5c971d3711de, 0x66bd2c6a30be232c, 0x607829e5b29e53ca, 0x30ed414e71dc08a2, 0x3fd38589ea0f1d39, 0x5a881a121f37fc5c, 0x27b9394368987a4f, 0x321fe45e13afae2d, 0xc6feb75080f33ea0, 0x02166d52f45eebbd +, 0x15026a1b0ccd2fc9, 0x1141be93d5bc3d6d, 0xfd20df606fc676c9, 0x4059e26b00ad78c4, 0x0709b409cec6b505, 0x68f020e8acf478e5, 0x875d77d1f5df0cfc, 0x66eb377735162ff1, 0x860482ab417a32ae, 0x21175f47da213935, 0xa07ff0cda099ecdb, 0x26ae5f177ae2b8e7 +, 0xa9a070ea5120eaf7, 0x2581feeba7383f81, 0x49e0f137f1fa2a7a, 0x7fe93c51cfd1ec62, 0x2d74dbdca7777f7e, 0x562da2ba74e823ff, 0x543b4f8609d77a2e, 0x3a0f65212f234ec8, 0xf842e3fea270ebc6, 0x4524322c6a289e11, 0x80815887aa6a8576, 0x46f49d53c3fe29a3 +, 0xbcc93cedfdb0d388, 0x4db312076ef0ad2b, 0x1f2cd56373654ad9, 0x4c6446970034d15f, 0x34d2cdbfd5d7130c, 0x6198950d03db2ae5, 0x736094b72faf1b1a, 0x1f6ca46a9f2588f7, 0xcba0b03d6259772a, 0x24e5a23d8d6be3a8, 0x7090e340c94f6d6f, 0x287ba27ee54e8466 +, 0x87320c8822d607f0, 0x44fd5802509df171, 0xf35c09860bf6ba4a, 0x6cf53130ef77cc0a, 0xaa81167a00b48ce4, 0x649f4c775b0d8b48, 0x59a25683ee98d33d, 0x651479007d1061a6, 0x155487411f6e16da, 0x411d036475404bf2, 0xc231f1344162458a, 0x4f36b7633f7dd368 +, 0xa98ddc0a4e7a89a4, 0x55d8a5da6eacd542, 0x5c3fb48b1001ed45, 0x5c7785ccafa702b9, 0xa64369fd216afb79, 0x1f405ef10e940669, 0x755f4831bc327b6f, 0x2bc1b67d71f1882d, 0x8eab15cfed7777d0, 0x517370d580d99326, 0x0811b75701c9db39, 0x234d84cb52f7b621 +, 0x970c4fbddddae49c, 0x3ba8d842475e41e1, 0xb0720f6ad75e7008, 0x275cd5c5184bf345, 0x5eb9833888d3796a, 0x1b3a42dfde11c2f3, 0x946548fe092b5f4d, 0x119917b50f263cc9, 0x622de955a20a3f82, 0x6a552ea3a60c7ff4, 0xc79230138150372a, 0x18083b9518de76a7 +, 0x55fb74dd7d3b5455, 0x523eea9a70ff8334, 0x5994a7335e356271, 0x3bb011f60430f1d2, 0x1ec434cba1d6ea7c, 0x69b632960feb5780, 0x46c50417541ebf07, 0x01470bfbf9d23830, 0xe9551f4c049bc5cc, 0x1c124638f35ee8ed, 0x09ca3a9141e83a38, 0x44daaf3e7411127b +, 0x0e54717b6c2fcd10, 0x518ab46b26d5914b, 0x528ac6c82341e833, 0x2247fa99d41f4672, 0xabe30c65c0f327a2, 0x3ac74e012b77e1b4, 0x35defd694c0e86b3, 0x7c382e10bfe60e4e, 0xf37e382996b8461c, 0x4d47481c53631e1a, 0xac8f167884f7b7b1, 0x5ae1bb6ab1a4c643 +, 0x63eb02590829df80, 0x623126862a793fa1, 0x6e1e242f1ce09807, 0x7bf96130aaecfd2b, 0xedc5e9ea10bff70a, 0x66b548233b94d26e, 0x70c70ee4594d30ab, 0x79b0006c8811353e, 0x4352792c91710c1f, 0x0c7bf15181a9f539, 0xfc995ee769e3779c, 0x44871c6cb9dcedcd +, 0x0d180bbf2c9a046b, 0x5445c598c45d0cd9, 0xdefb32386875fb94, 0x5b0d235355660f35, 0xbe1dea825b3a7973, 0x10658ec4e1bbe147, 0x48af5e87fad77504, 0x55f5d3c94a7dd694, 0xa9a3e7062cad6ba2, 0x36c0a7e3f9e0ea31, 0xc4bd65217010aebc, 0x1d031dfc8b9fb598 +, 0xe3621c104113889e, 0x774b77ee1e6a6477, 0x124c5b8a07785fd7, 0x5a6c0df18188cada, 0xf4adcd545e72d7be, 0x38100fffb66ba966, 0x2100cbe35fe4a4d0, 0x4489be2df052c175, 0xa03a22403b26899f, 0x5ae4a0a0fec13928, 0x89dfbfb802795eaa, 0x34917e9c4ecf2532 +, 0x64b93674c60cbbb3, 0x25c098506334c71d, 0x8a723f66f1ee34e1, 0x3a960adf48f141e4, 0x659f386695e440bb, 0x577a0fbf6e8095e6, 0x8ef419b0f4b25496, 0x044176a30b9e465b, 0x7a98705df2013e6f, 0x77d0b2483aa95ce7, 0x309e917b978effd7, 0x08f1e55bfe942c7f +, 0xfc241629b8d613c8, 0x140f2e35cd68949f, 0x38899f6a3ee4f9fa, 0x7abc8ecdd300f3b5, 0xd3dad23505d23eaf, 0x75e73f09376b2c7c, 0x5644a663b60ec5c4, 0x511ade8afe1eaec9, 0xbb005fe4e1abca89, 0x2838de73b0ca1f6c, 0x800a6658b80d28c8, 0x48aaba61c91641ec +, 0x222759cab704d4e2, 0x106dd3c0ce85beca, 0xa1ce1ce341f69d03, 0x1651b210e8e4ee10, 0x47329a5e7133e136, 0x58c02f47dc9367b9, 0x09dcba56947b02af, 0x435c251178125b48, 0xd56979a3f0cd9315, 0x2f02b0a6422afddb, 0x23920f500731f32d, 0x0ab833238232cb5d +, 0xa7b3d1bfb0bb60db, 0x2342c2a03c6eaec2, 0xac5e6e5a14d5282e, 0x5b9a421ddc42a24b, 0x018506414543e056, 0x6d7c377c084954e6, 0x4f8bf71ed3db1ced, 0x5150dbc15ab10979, 0x00b50a1b373a7fbf, 0x140be5c3d3244705, 0x5005bfe96e5b7911, 0x77cea555bb133f3e +, 0x2ab1e1a9d7a973c6, 0x3897ac98314968d3, 0x9e0f74764b23c9c3, 0x2e5ecbbae41997cd, 0x43e2ea5648f12433, 0x3a515a0e4808e69c, 0x17d36c03c36bb343, 0x44cebd053481ce43, 0x89008656c21b0d76, 0x2f8513fcb9009be6, 0x2e223f90208a0e83, 0x3828c2d4efd36a73 +, 0xbf17d64f89a8527d, 0x59ebb42b9656151d, 0x7d7bc7245c7dc5ef, 0x191b682a0cb695ec, 0x8931172fad9f9add, 0x239b6cbbab2ebdcf, 0x76932f9ca7002dd1, 0x0c140548f858d8b5, 0x6c7adfddcf741ea5, 0x3b39c4b9e2e1a567, 0xc5135a25f87436fe, 0x690d8fecb7dd0ae0 +, 0xd782a618ecda10c2, 0x4f2a84b3134cf832, 0x35a81f71bbc955a4, 0x457f88ed64ae6398, 0xc27eb71c31479985, 0x4ae91808569aab32, 0xa5f2e9785a75eb11, 0x619cb199b837ed36, 0x0e7e5912b9484e40, 0x3b5831e87fdbcaf0, 0x49a2779c2d2b039d, 0x3d4b81e07f49061a +, 0xaa119b0fa222b55c, 0x265c1b11b42fd4e2, 0x6b4d28e519dd7637, 0x3d2da7900de5a4b2, 0x99b06586b5f21d63, 0x4ce62bd9e6a1ee18, 0xb671e753932f8c92, 0x390b7821d0987834, 0x1adf7c73c3f1fc2f, 0x78c636a8514a7af9, 0xaee3b35fe11e7533, 0x7fbd199278f6ffd7 +, 0x41aabbf4363d77de, 0x1b27fdf18b96bf6a, 0xda264a1dff9a981c, 0x36efc08530c0bf9a, 0x5bd8862a5d830854, 0x23d7c905e656e6cb, 0x4523324c5b64fdcf, 0x36627f376238665f, 0x564f53925c6d5ea4, 0x17c7cc86a1913022, 0xf90db52a543b009b, 0x15192dc91f8b994b +, 0x80bfa3c1a79ec6e2, 0x48fca8ea99772ecc, 0xfee6a3b98c0f1824, 0x46a8c75601b81e22, 0x2cb3c402a8895fcc, 0x1d1dff9c04305ce2, 0xc1aefe78e85971d7, 0x79c6a083ab5a80b2, 0x379c7bca5dbf2518, 0x2419358989b3ca02, 0xc9c42c9cfa5f470e, 0x4481c2ce91b14459 +, 0x6b04dea1ea26deca, 0x26ee3ceee0d0a101, 0xe36cc6bcd8fa4f26, 0x4d14709719764fbd, 0xe0572a706f1fef52, 0x0f75fb69a23f2ec1, 0x32ae4b04a864cf3b, 0x0b6373a91b944773, 0x1a8f2bc20bd088af, 0x586b0d5ace401747, 0xa0e6b094a3c51433, 0x1752a123c268c1c7 +, 0x643c2a93b5770ea1, 0x536cb9d1b71eeb43, 0x6bfb0525d0cc6b3f, 0x1f4dcfeec3adefc3, 0x28a0169dd0bf57f0, 0x1336c9aa20a35449, 0xbbcda068703ad7a1, 0x5e33478283c1e03d, 0xf1997733d18fdaf2, 0x789af507a17bb867, 0x79970c14d5695613, 0x79452342e845256f +, 0x6c12f9367a26a018, 0x11beda1c8f9cdfbe, 0x720e6ddf24b30929, 0x7706e91e3e544755, 0x4460381d3a6c9059, 0x7e01916c3678c424, 0x6024355a61d2bb07, 0x68bae01d79c869e2, 0xf21cbcff285df659, 0x02f7ee6aeb57c933, 0xce0f078c17266467, 0x039b4fdb5170a103 +, 0xd5de0fec61a4ae1b, 0x33d37a152a778695, 0xea64e40e6a10ded9, 0x1f1d394373bdb213, 0xf63598b6ef59fd14, 0x57922adc3ae52283, 0xe39a90e18b76f4a1, 0x27f3dbebd98a9dae, 0x18179dd9c03804b3, 0x511d72c1912e2d73, 0x88e1f6d24b2f3225, 0x56009999cdc2997f +, 0xda6df977b7d82fe4, 0x76f746bba63da226, 0x0b5facfc3bf13bd7, 0x4a31eb04f66f0e18, 0x8ace73d5e7cfe28f, 0x19aa731bc30c20b1, 0xa91979fe73400317, 0x6795ce71a09c7c9f, 0x93d55501933700ba, 0x3850eaf08b1fd14d, 0x450c5abc89edca71, 0x1be5db848bdfa5ef +, 0x77667d3f4fcf082b, 0x673b6e6c4824bc45, 0x6f22c12a5fe0ed6d, 0x006ee6722b5dfed1, 0xb47a13c1468d0c62, 0x40564879a378e6e4, 0x0bc6b553a9d3ab58, 0x21761c79e44dfcfd, 0x66f36ed3eb1050fb, 0x2e67df1312dd01d3, 0x48744c4a68dbf2ad, 0x7844962b6d6e039c +, 0xe07b5675d378b65f, 0x336262aa3d2c1df0, 0x320a5667d78c2e2b, 0x4f668dd96dda5e2a, 0xe21556795c7b8470, 0x3061905b2ef82bb1, 0xaee53211472206b6, 0x1f87377fee0d7a39, 0xdac58c52a3b1a0c7, 0x6e3c4ce04f0d7ffd, 0xfdffec45d4a3990f, 0x4b5340f79e2ae2c2 +, 0x0537c8b7b3d1f332, 0x55292744ae35ee1a, 0x42336d0e6d057f1e, 0x5ac40e9e645cb3d7, 0x848f7b7f845e46c7, 0x74bda86736eff150, 0x891acf622baf4f35, 0x14bcef9cf39667bb, 0x9aa1354d9731b9b3, 0x27e855a19295e59f, 0x1a829a8e10662ed0, 0x3bbc43f9ec4437a7 +, 0x8bfa8b1cb1de5341, 0x3432778068d35549, 0xe3d807da41f25a48, 0x1bb6ee1ce2efe552, 0x08d9bded0bd3affc, 0x290f1c5299a917a8, 0xda8dfd79562f8939, 0x1bf7aae68686211f, 0x2ab6daf9bc860765, 0x7bef6e2f0eb58a0b, 0x8746faab7c439b94, 0x017ea87750bb8bda +, 0xf8dfeb22239c9a7c, 0x35cec0d2887b3a13, 0x68aa94ac601f1606, 0x7470553f8ba61767, 0x37894f91c9eac410, 0x55b22aeb8337f732, 0x53f8d90f29a2fe94, 0x0aec068aec69023a, 0x40506162ad6182ee, 0x6a327ff1ac1e5475, 0x968d7095492df3c8, 0x3f93f46195f67521 +, 0x4983bca28970d546, 0x2716b931296b53c2, 0xf42b013266b6f8b3, 0x76f29b084b6a369f, 0x8e28749222216249, 0x4f2fa1d3a6c1acfd, 0x0ee66697eab8f954, 0x37c33e28fec0cce5, 0x7d0419e2bafd1dd1, 0x01f04d4299b94daa, 0x5ec06abbc1e5c7e6, 0x3a24c66060ed72a9 +, 0x0db764e15f960f26, 0x1d5973d5d59f9c3a, 0xf3dc2608dc6d9149, 0x1d80e0461b72f518, 0x2264dccd49c8b09c, 0x1f03e7a246334d5e, 0x2d6e38871b1fc2ad, 0x418588ae4f284bd3, 0x3efb071bafe1afa2, 0x0799ba0c80bdd8dc, 0xa6b273222dcc4a76, 0x13859f08ac8a4b23 +, 0x0194acc2663c5acb, 0x459fa55bd0bbedf6, 0x1b055550f06f8cc1, 0x09e5fad46599ea75, 0x6b3916ef772958a3, 0x4aaaa5c18093a431, 0x8e1503e36610f594, 0x620ef55048a263b9, 0x5a28963c8cb8ecbc, 0x6aee46b1b740c15a, 0x67e39606f59cfea9, 0x13a579e3777ca8b1 +, 0x45ad92f61cbb8de3, 0x53068a1a42460eab, 0x9b163546de379578, 0x07bf38a7cecd4860, 0xf84c77031d282de1, 0x402aed6399f78ffc, 0xfb83dd20295f6d45, 0x3702e257340d2ecd, 0xb8db2d8b979b97c8, 0x617526d2a50b0c51, 0xd86f6278313017db, 0x2f35eedec55f9d92 +, 0xeecb69493517973b, 0x7a111a74e0baf09a, 0xb82c6da8ec39f63d, 0x4217076312833746, 0x5d36d11f3dda88d9, 0x7baebcb360f2a887, 0x9829b62d093d6cbb, 0x10f17a2f6edf28fd, 0xfe3efa4353f40626, 0x731ca3065c118e34, 0x6185678827960895, 0x07f906a4f4c6355c +, 0x361d9cd10e657142, 0x2b5f5d452dd861ce, 0xa3e01df05d04b69a, 0x533723bc4cfcc0db, 0x820384afa1bbccb5, 0x4e67e941595d8dfd, 0x0f8da50839e13646, 0x6887a0573a596968, 0xe93dd1df5ace7343, 0x0d4076f28ecf96c8, 0x0ba2f854988074c1, 0x5eb2a314a41a40b6 +, 0x49ff6d27a676b27e, 0x15f7ca40acd5114e, 0xc171f9a750d7da95, 0x3bedbe891f79eb5c, 0x5b643bceb83f74ff, 0x088b1af3aa331a4c, 0xde294c7e0a60c4a9, 0x0a0770fc8120b151, 0xf09b757a0c7c1937, 0x34b797c03efd9c88, 0x051e3edb2c28cc49, 0x66db34ec5ac5122c +, 0x95fde0d3d3dc8cbf, 0x797897c8121818cf, 0x1fd46d197710f89d, 0x533a505803f809c5, 0xb60f1c090c9fd211, 0x4a7c3479af5c9d82, 0x4bfc3ffa4c8cf5a5, 0x6949f4a61306821f, 0xd814c949c67abcdc, 0x419a5e33166863c4, 0x9de646f6bd0895e0, 0x497cc1449a54545a +, 0x69eb31247fe126f2, 0x323c83233967f477, 0x52e0db4d3d78127d, 0x42a0e188e7b9380c, 0x3a6b011c46e34e7e, 0x79f4168aa9a0b4aa, 0x94270a25d708fa4d, 0x2bb28618cbc9cdc8, 0x741e46bb04606819, 0x02790c52fb2ce982, 0x6dbb92d0c6d0af10, 0x32aa96ae061e9412 +, 0x1376700c90d98eaa, 0x4d1dfe650c0a7136, 0xb397f8eef89aff20, 0x4836ac4a041bae37, 0xf37c1076a80a02b8, 0x0d063fa2467b3a37, 0x498f2617b56b7e7b, 0x65ef1194db859a5d, 0xd1fe25d5d28ffcb6, 0x228ee6f49459c083, 0x6b7e82b3b009b15b, 0x713b185ef1fccbfc +, 0x552468f1ff60c298, 0x2b7ba65d02519614, 0x8a86ad90ff0816c2, 0x7bf9249284bd02e5, 0x3008c56e474c2d10, 0x171473b77f804540, 0x15fb79d07bdea766, 0x66ac67c7b9b0951f, 0x34bca15bb6d2f652, 0x13c63dd2687d617b, 0xc515ae237715c19c, 0x0e543c6765fbfef2 +, 0x668c80faf156fb5e, 0x1e2e9e3b3d9962b8, 0x89ebaa264394e113, 0x322add21cf1659cf, 0xf9e6e26733619f8e, 0x723bfc8b792147f0, 0x79aef2837d7e092f, 0x1aa61c59290b5011, 0x9955ae576a499cd3, 0x2c3d6e6a5a1ce0da, 0xb864cfa199a8676b, 0x4961a21f1080285f +, 0x828e184adf9d997b, 0x0c84bda97e7ce725, 0xe6974677094cfcc5, 0x4ec8cd773946105b, 0xa48681bcc95fb5c6, 0x6ade87f8f7a5f269, 0x9b97628fdd39c03d, 0x3bde0ee1f19f1842, 0x4ef8c8fb117c0ca1, 0x769bf8f8d07de9bf, 0xc8f5f435b78a57e5, 0x79987aa861bbcf9c +, 0x7f6c557204b02022, 0x119bd819111c69d1, 0xf0c61ef00b3eb70b, 0x4317f0511bfb7b39, 0x36a2b944e84d608e, 0x1c1a3862da3369cb, 0x37dbf471085f1775, 0x3835751e107419ad, 0x04ab0c84bb07a3fe, 0x63758bfbc7df13a0, 0x15ffd20cb554f23e, 0x1ff11c442b1515b7 +, 0x171377f1bf937186, 0x615efe82b83538f8, 0x321e7cfae352a761, 0x7af02427d7241502, 0x86546e47f2cc559f, 0x65a1d8a017659d75, 0xc95d8aa5b8bfdac9, 0x01e887cb68990623, 0xf1f8ee8c466bcc3d, 0x40ce5e4f2ba3908f, 0xd2b81a3480c16b35, 0x51625d3eabf708cd +, 0x44d770a210105739, 0x7f1de74a022958a0, 0xfbe4c91bd1e8f732, 0x204fbacb13586460, 0x97d79097d62e3cf8, 0x541ad5591934b114, 0xfdfb47919c141909, 0x354926e5244fdecf, 0x6291b0a0e2e994b0, 0x2b9a9a69d3a6c3d1, 0x8189be54302371e7, 0x3645c65df1a881cd +, 0xdf0460f445e3877b, 0x7ea384dc52d0d26e, 0x0c2e5f768d46b6b0, 0x1f6e62daa7c5d4e6, 0xf8b026b33b2343ee, 0x2b7183c8767d372c, 0xbd45d1b6b6731517, 0x4ddb3d287c470d60, 0x1031dba40263ece2, 0x4e737fa0d659045f, 0x8cbc98d07d09b455, 0x34a35128a2bcb7f5 }; + + +#endif \ No newline at end of file diff --git a/FourQ_ARM_side_channel/README.txt b/FourQ_ARM_side_channel/README.txt new file mode 100644 index 0000000..748690b --- /dev/null +++ b/FourQ_ARM_side_channel/README.txt @@ -0,0 +1,125 @@ + + FourQlib v3.0 (C Edition) + ========================= + Optimized implementation for 32-bit ARM and ARM Cortex-M4 with side-channel countermeasures + =========================================================================================== + +1. CONTENTS: + -------- + +The "FourQ_ARM_side_channel" folder contains: + +makefile - Makefile for compilation on ARM processors (ARMv6 and ARMv7) using GNU GCC + on Linux. +makefile_Cortex-M4 - Makefile for compilation on ARM Cortex-M4 (STM32F4xx series) using GNU GCC + on Linux. +*.c, *.h - Library and header files. Public API for ECC scalar multiplication, key + exchange and signatures is located in FourQ_api.h +ARM/ - Folder with library files implementing low-level arithmetic for ARM. +libopencm3/ - Folder with firmware library files for ARM Cortex-M microcontrollers +random/ - Folder with pseudo-random generation function for ARM Cortex-M4. +tests/ - Test files for 32-bit ARM. +tests_Cortex-M4/ - Test files for ARM Cortex-M4. +README.txt - This readme file. + +stm32f4_wrapper.c and stm32f4_wrapper.h are by Joost Rijneveld and can be found at: +https://github.com/joostrijneveld/STM32-getting-started + +Files in the folder libopencm3 are from the libopencm3 project (http://libopencm3.org/): +https://github.com/libopencm3/libopencm3 + + +2. SUPPORTED PLATFORMS: + ------------------- + +This implementation is supported on ARM platforms and includes two variants: +(i) Implementation for ARM processors based on ARMv6 and ARMv7 architectures. This implementation was optimized + for a first generation Raspberry Pi using a 700 MHz ARM1176JZF-S processor (ARMv6 architecture). +(ii) Implementation for ARM Cortex-M4 processors based on the ARMv7-M architecture. This implementation was + developed and optimized on a STM32F4Discovery development board containing a Cortex-M4 STM32F407VG micro- + controller (ARMv7-M architecture). It should be possible to extend the support to Cortex-M3 and Cortex-M7 + based devices with small modifications. + +See instructions below to choose an implementation option and compile on one of the supported platforms. + + +3. COMPLEMENTARY CRYPTO FUNCTIONS: + ------------------------------ + +Random values are generated with /dev/urandom in the case of the 32-bit ARM implementation, and with the function +random_int() in the case of the ARM Cortex-M4 implementation. + +The library includes an implementation of SHA-512 which is used by default by SchnorrQ signatures. + +Users can experiment with different options by replacing functions in the folders "random" and "sha512" and +applying the corresponding changes to the settings in FourQ.h. + + +4. INSTRUCTIONS: + ------------ + +4.1. BUILDING THE LIBRARY FOR ARMv6 or ARMv7: + --------------------------------------- + +To compile on Linux using the GNU GCC compiler or the clang compiler, execute the following command from the +command prompt: + +make CC=[gcc/clang] EXTENDED_SET=[TRUE/FALSE] + +After compilation, run fp_tests, ecc_tests or crypto_tests. + +By default GNU GCC is used, as well as the extended settings. + +For example, to compile using GNU GCC, execute: + +make + +As another example, to compile using clang, execute: + +make CC=clang + +By default EXTENDED_SET is enabled, which sets the following compilation flags: -fwrapv -fomit-frame-pointer +-funroll-loops. To disable this, use EXTENDED_SET=FALSE. +Users are encouraged to experiment with the different flag options. + +4.2. BUILDING THE LIBRARY FOR CORTEX-M4 ON THE STM32F4DISCOVERY BOARD: + ---------------------------------------------------------------- + +The following instructions have been tested on a Ubuntu 16.04 Linux machine. + +First, install the ARM GNU GCC cross-compiler on the server machine: + +sudo apt-get install gcc-arm-none-eabi libc6-dev-i386 + +Then, download, build and install stlink: https://github.com/texane/stlink + +sudo apt-get install libusb-1.0-0-dev +git clone https://github.com/texane/stlink.git +cd stlink +make +cd build/Release/ && sudo make install + +To compile the code, execute the following command from the FourQ_ARM_side_channel folder on the server machine: + +make -f makefile_Cortex-M4 + +Power the STM32F4DISCOVERY board (with a USB to mini-USB cable) and connect it to the server machine via a +USB-TTL converter as follows: + +VDD -> VDD +GND -> GND +TX -> PA3 +RX -> PA2 + +Then, run from the server machine: + +sudo ./tests_Cortex-M4/monitor.sh + +From a different terminal window on the server machine, program the device with one of the following commands +from the FourQ_ARM_side_channel folder: + +st-flash write tests_Cortex-M4/fp_tests.bin 0x8000000 +st-flash write tests_Cortex-M4/ecc_tests.bin 0x8000000 +st-flash write tests_Cortex-M4/crypto_tests.bin 0x8000000 + +The tests should begin to run on the first terminal window. \ No newline at end of file diff --git a/FourQ_ARM_side_channel/crypto_util.c b/FourQ_ARM_side_channel/crypto_util.c new file mode 100644 index 0000000..47352a2 --- /dev/null +++ b/FourQ_ARM_side_channel/crypto_util.c @@ -0,0 +1,168 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: crypto utility functions +************************************************************************************/ + +#include "FourQ_internal.h" +#include "FourQ_params.h" +#include + +static digit_t mask4000 = (digit_t)1 << (sizeof(digit_t)*8 - 2); +static digit_t mask7fff = (digit_t)(-1) >> 1; + + +bool is_zero_ct(digit_t* a, unsigned int nwords) +{ // Check if multiprecision element is zero + digit_t x; + unsigned int i; + + x = a[0]; + for (i = 1; i < nwords; i++) { + x |= a[i]; + } + + return (bool)(1 ^ ((x | (0-x)) >> (RADIX-1))); +} + + +void encode(point_t P, unsigned char* Pencoded) +{ // Encode point P + // SECURITY NOTE: this function does not run in constant time. + digit_t temp1 = (P->x[1][NWORDS_FIELD-1] & mask4000) << 1; + digit_t temp2 = (P->x[0][NWORDS_FIELD-1] & mask4000) << 1; + + memmove(Pencoded, P->y, 32); + if (is_zero_ct((digit_t*)P->x, NWORDS_FIELD) == true) { + ((digit_t*)Pencoded)[2*NWORDS_FIELD-1] |= temp1; + } else { + ((digit_t*)Pencoded)[2*NWORDS_FIELD-1] |= temp2; + } +} + + +ECCRYPTO_STATUS decode(const unsigned char* Pencoded, point_t P) +{ // Decode point P + // SECURITY NOTE: this function does not run in constant time. + felm_t r, t, t0, t1, t2, t3, t4; + f2elm_t u, v, one = {0}; + digit_t sign_dec; + point_extedwards_t R; + unsigned int i, sign; + + one[0][0] = 1; + memmove((unsigned char*)P->y, Pencoded, 32); // Decoding y-coordinate and sign + sign = (unsigned int)(Pencoded[31] >> 7); + P->y[1][NWORDS_FIELD-1] &= mask7fff; + + fp2sqr1271(P->y, u); + fp2mul1271(u, (felm_t*)&PARAMETER_d, v); + fp2sub1271(u, one, u); + fp2add1271(v, one, v); + + fpsqr1271(v[0], t0); // t0 = v0^2 + fpsqr1271(v[1], t1); // t1 = v1^2 + fpadd1271(t0, t1, t0); // t0 = t0+t1 + fpmul1271(u[0], v[0], t1); // t1 = u0*v0 + fpmul1271(u[1], v[1], t2); // t2 = u1*v1 + fpadd1271(t1, t2, t1); // t1 = t1+t2 + fpmul1271(u[1], v[0], t2); // t2 = u1*v0 + fpmul1271(u[0], v[1], t3); // t3 = u0*v1 + fpsub1271(t2, t3, t2); // t2 = t2-t3 + fpsqr1271(t1, t3); // t3 = t1^2 + fpsqr1271(t2, t4); // t4 = t2^2 + fpadd1271(t3, t4, t3); // t3 = t3+t4 + for (i = 0; i < 125; i++) { // t3 = t3^(2^125) + fpsqr1271(t3, t3); + } + + fpadd1271(t1, t3, t); // t = t1+t3 + mod1271(t); + if (is_zero_ct(t, NWORDS_FIELD) == true) { + fpsub1271(t1, t3, t); // t = t1-t3 + } + fpadd1271(t, t, t); // t = 2*t + fpsqr1271(t0, t3); // t3 = t0^2 + fpmul1271(t0, t3, t3); // t3 = t3*t0 + fpmul1271(t, t3, t3); // t3 = t3*t + fpexp1251(t3, r); // r = t3^(2^125-1) + fpmul1271(t0, r, t3); // t3 = t0*r + fpmul1271(t, t3, P->x[0]); // x0 = t*t3 + fpsqr1271(P->x[0], t1); + fpmul1271(t0, t1, t1); // t1 = t0*x0^2 + fpdiv1271(P->x[0]); // x0 = x0/2 + fpmul1271(t2, t3, P->x[1]); // x1 = t3*t2 + + fpsub1271(t, t1, t); + mod1271(t); + if (is_zero_ct(t, NWORDS_FIELD) == false) { // If t != t1 then swap x0 and x1 + fpcopy1271(P->x[0], t0); + fpcopy1271(P->x[1], P->x[0]); + fpcopy1271(t0, P->x[1]); + } + + mod1271(P->x[0]); + if (is_zero_ct((digit_t*)P->x, NWORDS_FIELD) == true) { + sign_dec = ((digit_t*)&P->x[1])[NWORDS_FIELD-1] >> (sizeof(digit_t)*8 - 2); + } else { + sign_dec = ((digit_t*)&P->x[0])[NWORDS_FIELD-1] >> (sizeof(digit_t)*8 - 2); + } + + if (sign != (unsigned int)sign_dec) { // If sign of x-coordinate decoded != input sign bit, then negate x-coordinate + fp2neg1271(P->x); + } + + point_setup(P, R); + if (ecc_point_validate(R) == false) { + fpneg1271(R->x[1]); + fpcopy1271(R->x[1], P->x[1]); + if (ecc_point_validate(R) == false) { // Final point validation + return ECCRYPTO_ERROR; + } + } + + return ECCRYPTO_SUCCESS; +} + + +void to_Montgomery(const digit_t* ma, digit_t* c) +{ // Converting to Montgomery representation + + Montgomery_multiply_mod_order(ma, (digit_t*)&Montgomery_Rprime, c); +} + + +void from_Montgomery(const digit_t* a, digit_t* mc) +{ // Converting from Montgomery to standard representation + digit_t one[NWORDS_ORDER] = {0}; + one[0] = 1; + + Montgomery_multiply_mod_order(a, one, mc); +} + + +const char* FourQ_get_error_message(ECCRYPTO_STATUS Status) +{ // Output error/success message for a given ECCRYPTO_STATUS + struct error_mapping { + unsigned int index; + char* string; + } mapping[ECCRYPTO_STATUS_TYPE_SIZE] = { + {ECCRYPTO_ERROR, ECCRYPTO_MSG_ERROR}, + {ECCRYPTO_SUCCESS, ECCRYPTO_MSG_SUCCESS}, + {ECCRYPTO_ERROR_DURING_TEST, ECCRYPTO_MSG_ERROR_DURING_TEST}, + {ECCRYPTO_ERROR_UNKNOWN, ECCRYPTO_MSG_ERROR_UNKNOWN}, + {ECCRYPTO_ERROR_NOT_IMPLEMENTED, ECCRYPTO_MSG_ERROR_NOT_IMPLEMENTED}, + {ECCRYPTO_ERROR_NO_MEMORY, ECCRYPTO_MSG_ERROR_NO_MEMORY}, + {ECCRYPTO_ERROR_INVALID_PARAMETER, ECCRYPTO_MSG_ERROR_INVALID_PARAMETER}, + {ECCRYPTO_ERROR_SHARED_KEY, ECCRYPTO_MSG_ERROR_SHARED_KEY}, + {ECCRYPTO_ERROR_SIGNATURE_VERIFICATION, ECCRYPTO_MSG_ERROR_SIGNATURE_VERIFICATION}, + }; + + if (Status >= ECCRYPTO_STATUS_TYPE_SIZE || mapping[Status].string == NULL) { + return "Unrecognized ECCRYPTO_STATUS"; + } else { + return mapping[Status].string; + } +}; \ No newline at end of file diff --git a/FourQ_ARM_side_channel/eccp2.c b/FourQ_ARM_side_channel/eccp2.c new file mode 100644 index 0000000..70f3fb8 --- /dev/null +++ b/FourQ_ARM_side_channel/eccp2.c @@ -0,0 +1,1082 @@ +/*********************************************************************************** +* 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) exploiting endomorphisms +* +* This code is based on the paper "FourQ: four-dimensional decompositions on a +* Q-curve over the Mersenne prime" by Craig Costello and Patrick Longa, in Advances +* in Cryptology - ASIACRYPT, 2015. +* Preprint available at http://eprint.iacr.org/2015/565. +************************************************************************************/ + +#include "FourQ_internal.h" +#include "FourQ_params.h" +#include "FourQ_tables.h" +#include "../random/random.h" +#include "ARM/fp_arm.h" + + +/***********************************************/ +/************* GF(p^2) FUNCTIONS ***************/ + +void fp2copy1271(f2elm_t a, f2elm_t c) +{// Copy of a GF(p^2) element, c = a + fpcopy1271(a[0], c[0]); + fpcopy1271(a[1], c[1]); +} + + +void fp2zero1271(f2elm_t a) +{// Zeroing a GF(p^2) element, a = 0 + fpzero1271(a[0]); + fpzero1271(a[1]); +} + + +void fp2neg1271(f2elm_t a) +{// GF(p^2) negation, a = -a in GF((2^127-1)^2) + fpneg1271(a[0]); + fpneg1271(a[1]); +} + + +void fp2sqr1271(f2elm_t a, f2elm_t c) +{// GF(p^2) squaring, c = a^2 in GF((2^127-1)^2) + + fp2sqr1271_a(a, c); +} + + +void fp2mul1271(f2elm_t a, f2elm_t b, f2elm_t c) +{// GF(p^2) multiplication, c = a*b in GF((2^127-1)^2) + + fp2mul1271_a(a, b, c); +} + + +void fp2add1271(f2elm_t a, f2elm_t b, f2elm_t c) +{// GF(p^2) addition, c = a+b in GF((2^127-1)^2) + + fp2add1271_a(a, b, c); +} + + +void fp2sub1271(f2elm_t a, f2elm_t b, f2elm_t c) +{// GF(p^2) subtraction, c = a-b in GF((2^127-1)^2) + + fp2sub1271_a(a, b, c); +} + + +void fp2inv1271(f2elm_t a) +{// GF(p^2) inversion, a = (a0-i*a1)/(a0^2+a1^2) + f2elm_t t1; + + fpsqr1271(a[0], t1[0]); // t10 = a0^2 + fpsqr1271(a[1], t1[1]); // t11 = a1^2 + fpadd1271(t1[0], t1[1], t1[0]); // t10 = a0^2+a1^2 + fpinv1271(t1[0]); // t10 = (a0^2+a1^2)^-1 + fpneg1271(a[1]); // a = a0-i*a1 + fpmul1271(a[0], t1[0], a[0]); + fpmul1271(a[1], t1[0], a[1]); // a = (a0-i*a1)*(a0^2+a1^2)^-1 +} + + +void felmt_randomize_point(point_extedwards_t P, felm_t random) +{ // Randomization of point coordinates using a random field element + // Input: P = (X,Y,Z,T) in extended twisted Edwards coordinates. + // Output: P = (X,Y,Z,T) in extended twisted Edwards coordinates, + // where X = random*(Xa+Xb*i), Y = random*(Ya+Yb*i), Z = random*(Za+Zb*i), T = random*(Ta+Tb*i). + + fpmul1271(P->x[0], random, P->x[0]); + fpmul1271(P->x[1], random, P->x[1]); + fpmul1271(P->y[0], random, P->y[0]); + fpmul1271(P->y[1], random, P->y[1]); + fpmul1271(P->z[0], random, P->z[0]); + fpmul1271(P->z[1], random, P->z[1]); + fpmul1271(P->t[0], random, P->t[0]); + fpmul1271(P->t[1], random, P->t[1]); +} + + +void randomize_table(point_extedwards_t* Table, felm_t random) +{ // Randomization of all the point coordinates in the precomputed table using a random field element ///// NOTE: SHOULD WE RANDOMIZE POINTS WITH AN ELEMENT IN GF(P^2) + unsigned int i; + + for (i = 0; i < 16; i++) { + felmt_randomize_point(Table[i], random); + } +} + + +void random_felmt(felm_t random) +{ // Generate random field element in [0, 2^127-1] + unsigned char* rand_byte = (unsigned char*)&random[0]; + + RandomBytesFunction(rand_byte, 16); + rand_byte[15] &= 0x7F; +} + + +__inline void clear_words(void* mem, unsigned int nwords) +{ // Clear integer-size digits from memory. "nwords" indicates the number of integer digits to be zeroed. + // This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing. + // It has been tested with MSVS 2013 and GNU GCC 4.6.3, 4.7.3, 4.8.2 and 4.8.4. Users are responsible for verifying correctness with different compilers. + // See "Compliant Solution (C99)" at https://www.securecoding.cert.org/confluence/display/c/MSC06-C.+Beware+of+compiler+optimizations + unsigned int i; + volatile unsigned int *v = mem; + + for (i = 0; i < nwords; i++) + v[i] = 0; +} + + +// Fixed GF(p^2) constants for the endomorphisms +static uint64_t ctau1[4] = {0x74DCD57CEBCE74C3, 0x1964DE2C3AFAD20C, 0x12, 0x0C}; +static uint64_t ctaudual1[4] = {0x9ECAA6D9DECDF034, 0x4AA740EB23058652, 0x11, 0x7FFFFFFFFFFFFFF4}; +static uint64_t cphi0[4] = {0xFFFFFFFFFFFFFFF7, 0x05, 0x4F65536CEF66F81A, 0x2553A0759182C329}; +static uint64_t cphi1[4] = {0x07, 0x05, 0x334D90E9E28296F9, 0x62C8CAA0C50C62CF}; +static uint64_t cphi2[4] = {0x15, 0x0F, 0x2C2CB7154F1DF391, 0x78DF262B6C9B5C98}; +static uint64_t cphi3[4] = {0x03, 0x02, 0x92440457A7962EA4, 0x5084C6491D76342A}; +static uint64_t cphi4[4] = {0x03, 0x03, 0xA1098C923AEC6855, 0x12440457A7962EA4}; +static uint64_t cphi5[4] = {0x0F, 0x0A, 0x669B21D3C5052DF3, 0x459195418A18C59E}; +static uint64_t cphi6[4] = {0x18, 0x12, 0xCD3643A78A0A5BE7, 0x0B232A8314318B3C}; +static uint64_t cphi7[4] = {0x23, 0x18, 0x66C183035F48781A, 0x3963BC1C99E2EA1A}; +static uint64_t cphi8[4] = {0xF0, 0xAA, 0x44E251582B5D0EF0, 0x1F529F860316CBE5}; +static uint64_t cphi9[4] = {0xBEF, 0x870, 0x14D3E48976E2505, 0xFD52E9CFE00375B}; +static uint64_t cpsi1[4] = {0xEDF07F4767E346EF, 0x2AF99E9A83D54A02, 0x13A, 0xDE}; +static uint64_t cpsi2[4] = {0x143, 0xE4, 0x4C7DEB770E03F372, 0x21B8D07B99A81F03}; +static uint64_t cpsi3[4] = {0x09, 0x06, 0x3A6E6ABE75E73A61, 0x4CB26F161D7D6906}; +static uint64_t cpsi4[4] = {0xFFFFFFFFFFFFFFF6, 0x7FFFFFFFFFFFFFF9, 0xC59195418A18C59E, 0x334D90E9E28296F9}; + +// Fixed integer constants for the decomposition +// Close "offset" vector +static uint64_t c1 = {0x72482C5251A4559C}; +static uint64_t c2 = {0x59F95B0ADD276F6C}; +static uint64_t c3 = {0x7DD2D17C4625FA78}; +static uint64_t c4 = {0x6BC57DEF56CE8877}; +// Optimal basis vectors +static uint64_t b11 = {0x0906FF27E0A0A196}; +static uint64_t b12 = {0x1363E862C22A2DA0}; +static uint64_t b13 = {0x07426031ECC8030F}; +static uint64_t b14 = {0x084F739986B9E651}; +static uint64_t b21 = {0x1D495BEA84FCC2D4}; +static uint64_t b24 = {0x25DBC5BC8DD167D0}; +static uint64_t b31 = {0x17ABAD1D231F0302}; +static uint64_t b32 = {0x02C4211AE388DA51}; +static uint64_t b33 = {0x2E4D21C98927C49F}; +static uint64_t b34 = {0x0A9E6F44C02ECD97}; +static uint64_t b41 = {0x136E340A9108C83F}; +static uint64_t b42 = {0x3122DF2DC3E0FF32}; +static uint64_t b43 = {0x068A49F02AA8A9B5}; +static uint64_t b44 = {0x18D5087896DE0AEA}; +// Precomputed integers for fast-Babai rounding +static uint64_t ell1[4] = {0x259686E09D1A7D4F, 0xF75682ACE6A6BD66, 0xFC5BB5C5EA2BE5DF, 0x07}; +static uint64_t ell2[4] = {0xD1BA1D84DD627AFB, 0x2BD235580F468D8D, 0x8FD4B04CAA6C0F8A, 0x03}; +static uint64_t ell3[4] = {0x9B291A33678C203C, 0xC42BD6C965DCA902, 0xD038BF8D0BFFBAF6, 0x00}; +static uint64_t ell4[4] = {0x12E5666B77E7FDC0, 0x81CBDC3714983D82, 0x1B073877A22D8410, 0x03}; + +// Fixed integer constants for scalar randomization +static uint64_t p11 = {0x190BE2D7F2E68811}; +static uint64_t p12 = {0x2E5EBE12E05824E0}; +static uint64_t p13 = {0x27C2D7D95E7F1AEB}; +static uint64_t p14 = {0x02684DFF36C48F4F}; +static uint64_t p21 = {0x36553EC277E34AE5}; +static uint64_t p22 = {0x2E5EBE12E05824DF}; +static uint64_t p23 = {0x27C2D7D95E7F1AEC}; +static uint64_t p24 = {0x284413BBC495F71F}; +static uint64_t p31 = {0x39BE8F1CF6A62CA9}; +static uint64_t p32 = {0x1DBEF6CB01B6D191}; +static uint64_t p33 = {0x00B81641C21F595B}; +static uint64_t p34 = {0x04B749AA70397695}; +static uint64_t p41 = {0x3F5C3DEA5883EC7B}; +static uint64_t p42 = {0x1AFAD5B01E2DF73F}; +static uint64_t p43 = {0x2F05380B4B471DFB}; +static uint64_t p44 = {0x1FF4A0223DDC10CE}; + + +/***********************************************/ +/********** CURVE/SCALAR FUNCTIONS ***********/ + +static __inline void ecc_tau(point_extedwards_t P) +{ // Apply tau mapping to a point, P = tau(P) + // Input: P = (X1:Y1:Z1) on E in twisted Edwards coordinates + // Output: P = (Xfinal:Yfinal:Zfinal) on Ehat in twisted Edwards coordinates + f2elm_t t0; + + fp2sqr1271(P->x, t0); // t0 = X1^2 + fp2sqr1271(P->y, P->t); // T = Y1^2 + fp2mul1271(P->x, P->y, P->x); // X = X1*Y1 + fp2sqr1271(P->z, P->y); // Y = Z1^2 + fp2add1271(t0, P->t, P->z); // Z = X1^2+Y1^2 + fp2add1271(P->y, P->y, P->y); // Y = 2*Z1^2 + fp2sub1271(t0, P->t, t0); // t0 = X1^2-Y1^2 + fp2neg1271(P->y); // Y = -2*Z1^2 + fp2mul1271(P->x, t0, P->x); // X = X1*Y1*(X1^2-Y1^2) + fp2sub1271(P->y, t0, P->y); // Y = -2*Z1^2-(X1^2-Y1^2) + fp2mul1271(P->x, (felm_t*)&ctau1, P->x); // Xfinal = X*ctau1 + fp2mul1271(P->y, P->z, P->y); // Yfinal = Y*Z + fp2mul1271(P->z, t0, P->z); // Zfinal = t0*Z +} + + +static __inline void ecc_tau_dual(point_extedwards_t P) +{ // Apply tau_dual mapping to a point, P = tau_dual(P) + // Input: P = (X1:Y1:Z1:T1) on Ehat in extended twisted Edwards coordinates + // Output: P = (Xfinal,Yfinal,Zfinal,Tfinal) on E in extended twisted Edwards coordinates + f2elm_t t0, t1; + + fp2sqr1271(P->x, t0); // t0 = X1^2 + fp2sqr1271(P->z, P->t); // T = Z1^2 + fp2sqr1271(P->y, t1); // t1 = Y1^2 + fp2add1271(P->t, P->t, P->z); // Z = 2*Z1^2 + fp2sub1271(t1, t0, P->t); // T = Y1^2-X1^2 + fp2add1271(t0, t1, t0); // t0 = X1^2+Y1^2 + fp2mul1271(P->x, P->y, P->x); // X = X1*Y1 + fp2sub1271(P->z, P->t, P->z); // Z = 2*Z1^2-(Y1^2-X1^2) + fp2mul1271(P->x, (felm_t*)&ctaudual1, t1); // t1 = ctaudual1*X1 + fp2mul1271(P->z, P->t, P->y); // Yfinal = Z*T + fp2mul1271(t0, t1, P->x); // Xfinal = t0*t1 + fp2mul1271(P->z, t0, P->z); // Zfinal = Z*t0 + fp2mul1271(P->t, t1, P->t); // Tfinal = T*t1 +} + + +static __inline void ecc_delphidel(point_extedwards_t P) +{ // Apply delta_phi_delta mapping to a point, P = delta(phi_W(delta_inv(P))), + // where phi_W is the endomorphism on the Weierstrass form. + // Input: P = (X1:Y1:Z1) on Ehat in twisted Edwards coordinates + // Output: P = (Xfinal:Yfinal:Zfinal) on Ehat in twisted Edwards coordinates + f2elm_t t0, t1, t2, t3, t4, t5; + + fp2sqr1271(P->y, t2); // t2 = Y1^2 + fp2sqr1271(P->z, t4); // t4 = Z1^2 + fp2mul1271(t4, (felm_t*)&cphi4, t0); // t0 = cphi4*t4 + fp2mul1271(P->y, P->z, t3); // t3 = Y1*Z1 + fp2add1271(t0, t2, t0); // t0 = t0+t2 + fp2mul1271(t3, (felm_t*)&cphi3, t1); // t1 = cphi3*t3 + fp2sub1271(t0, t1, t5); // t5 = t0-t1 + fp2add1271(t0, t1, t0); // t0 = t0+t1 + fp2mul1271(t0, P->z, t0); // t0 = t0*Z1 + fp2mul1271(t3, (felm_t*)&cphi1, t1); // t1 = cphi1*t3 + fp2mul1271(t0, t5, t0); // t0 = t0*t5 + fp2mul1271(t4, (felm_t*)&cphi2, t5); // t5 = cphi2*t4 + fp2add1271(t2, t5, t5); // t5 = t2+t5 + fp2sub1271(t1, t5, P->t); // T = t1-t5 + fp2add1271(t1, t5, t1); // t1 = t1+t5 + fp2mul1271(P->t, t1, P->t); // T = t1*P->t + fp2mul1271(P->t, (felm_t*)&cphi0, P->t); // T = cphi0*T + fp2mul1271(P->x, P->t, P->x); // X = X1*T + fp2sqr1271(t2, P->t); // T = t2^2 + fp2sqr1271(t3, t2); // t2 = t3^2 + fp2sqr1271(t4, t3); // t3 = t4^2 + fp2mul1271(t2, (felm_t*)&cphi8, t1); // t1 = cphi8*t2 + fp2mul1271(t3, (felm_t*)&cphi9, t5); // t5 = cphi9*t3 + fp2add1271(t1, P->t, t1); // t1 = t1+T + fp2mul1271(t2, (felm_t*)&cphi6, t2); // t2 = cphi6*t2 + fp2mul1271(t3, (felm_t*)&cphi7, t3); // t3 = cphi7*t3 + fp2add1271(t1, t5, t1); // t1 = t1+t5 + fp2add1271(t2, t3, t2); // t2 = t2+t3 + fp2mul1271(t1, P->y, t1); // t1 = Y1*t1 + fp2add1271(P->t, t2, P->y); // Y = T+t2 + fp2mul1271(P->x, t1, P->x); // X = X*t1 + fp2mul1271(P->y, (felm_t*)&cphi5, P->y); // Y = cphi5*Y + fpneg1271(P->x[1]); // Xfinal = X^p + fp2mul1271(P->y, P->z, P->y); // Y = Y*Z1 + fp2mul1271(t0, t1, P->z); // Z = t0*t1 + fp2mul1271(P->y, t0, P->y); // Y = Y*t0 + fpneg1271(P->z[1]); // Zfinal = Z^p + fpneg1271(P->y[1]); // Yfinal = Y^p +} + + +static __inline void ecc_delpsidel(point_extedwards_t P) +{ // Apply delta_psi_delta mapping to a point, P = delta(psi_W(delta_inv(P))), + // where psi_W is the endomorphism on the Weierstrass form. + // Input: P = (X1:Y1:Z1) on Ehat in twisted Edwards coordinates + // Output: P = (Xfinal:Yfinal:Zfinal) on Ehat in twisted Edwards coordinates + f2elm_t t0, t1; + + fpneg1271(P->x[1]); // X = X1^p + fpneg1271(P->z[1]); // Z = Z1^p + fpneg1271(P->y[1]); // Y = Y1^p + fp2sqr1271(P->z, P->t); // T = Z1^p^2 + fp2sqr1271(P->x, t0); // t0 = X1^p^2 + fp2mul1271(P->x, P->t, P->x); // X = X1^p*Z1^p^2 + fp2mul1271(P->t, (felm_t*)&cpsi2, P->z); // Z = cpsi2*Z1^p^2 + fp2mul1271(P->t, (felm_t*)&cpsi3, t1); // t1 = cpsi3*Z1^p^2 + fp2mul1271(P->t, (felm_t*)&cpsi4, P->t); // T = cpsi4*Z1^p^2 + fp2add1271(t0, P->z, P->z); // Z = X1^p^2 + cpsi2*Z1^p^2 + fp2add1271(t0, P->t, P->t); // T = X1^p^2 + cpsi4*Z1^p^2 + fp2add1271(t0, t1, t1); // t1 = X1^p^2 + cpsi3*Z1^p^2 + fp2neg1271(P->t); // T = -(X1^p^2 + cpsi4*Z1^p^2) + fp2mul1271(P->z, P->y, P->z); // Z = Y1^p*(X1^p^2 + cpsi2*Z1^p^2) + fp2mul1271(P->x, P->t, P->x); // X = -X1^p*Z1^p^2*(X1^p^2 + cpsi4*Z1^p^2) + fp2mul1271(t1, P->z, P->y); // Yfinal = t1*Z + fp2mul1271(P->x, (felm_t*)&cpsi1, P->x); // Xfinal = cpsi1*X + fp2mul1271(P->z, P->t, P->z); // Zfinal = Z*T +} + + +void ecc_psi(point_extedwards_t P) +{ // Apply psi mapping to a point, P = psi(P) + // Input: P = (X1:Y1:Z1) on E in twisted Edwards coordinates + // Output: P = (Xfinal,Yfinal,Zfinal,Tfinal) on E in extended twisted Edwards coordinates + + ecc_tau(P); + ecc_delpsidel(P); + ecc_tau_dual(P); +} + + +void ecc_phi(point_extedwards_t P) +{ // Apply phi mapping to a point, P = phi(P) + // Input: P = (X1:Y1:Z1) on E in twisted Edwards coordinates + // Output: P = (Xfinal,Yfinal,Zfinal,Tfinal) on E in extended twisted Edwards coordinates + + ecc_tau(P); + ecc_delphidel(P); + ecc_tau_dual(P); +} + + +static __inline void mul_truncate(uint64_t* s, uint64_t* C, uint64_t* out) +{ // 256-bit multiplication with truncation for the scalar decomposition + // Outputs 64-bit value "out" = (uint64_t)((s * C) >> 256). + uint128_t tt1, tt2; + unsigned int carry1, carry2; + uint64_t temp; + + MUL128(s[0], C[0], tt2); + tt2[0] = tt2[1]; + tt2[1] = 0; + MUL128(s[1], C[0], tt1); + ADD128(tt1, tt2, tt1); + MUL128(s[0], C[1], tt2); + ADC128(tt1, tt2, carry1, tt1); + tt1[0] = tt1[1]; + tt1[1] = (uint64_t)(carry1); + MUL128(s[2], C[0], tt2); + ADD128(tt1, tt2, tt1); + MUL128(s[0], C[2], tt2); + ADC128(tt1, tt2, carry1, tt1); + MUL128(s[1], C[1], tt2); + ADC128(tt1, tt2, carry2, tt1); + tt1[0] = tt1[1]; + tt1[1] = (uint64_t)carry1 + (uint64_t)carry2; + MUL128(s[0], C[3], tt2); + ADD128(tt1, tt2, tt1); + MUL128(s[3], C[0], tt2); + ADC128(tt1, tt2, carry1, tt1); + MUL128(s[1], C[2], tt2); + ADC128(tt1, tt2, carry2, tt1); + temp = (uint64_t)carry1 + (uint64_t)carry2; + MUL128(s[2], C[1], tt2); + ADC128(tt1, tt2, carry2, tt1); + tt1[0] = tt1[1]; + tt1[1] = temp + (uint64_t)carry2; + MUL128(s[1], C[3], tt2); + ADD128(tt1, tt2, tt1); + MUL128(s[3], C[1], tt2); + ADD128(tt1, tt2, tt1); + MUL128(s[2], C[2], tt2); + ADD128(tt1, tt2, tt1); + *out = tt1[0]; +} + + +void ecc_precomp(point_extedwards_t P, point_extedwards_t R, point_extedwards_t *Table) +{ // Generation of the precomputation table used by the variable-base scalar multiplication ecc_mul_SCA_secure(). + // Input: P = (XP,YP,ZP,TP) in extended twisted Edwards coordinates + // R = (XR,YR,ZR,TR) in extended twisted Edwards coordinates. R is used for point blinding + // Output: Table containing 16 points: P, P+phi(P), P+psi(P), P+phi(P)+psi(P), P+psi(phi(P)), P+phi(P)+psi(phi(P)), P+psi(P)+psi(phi(P)), P+phi(P)+psi(P)+psi(phi(P)) + // Precomputed points use the representation (X+Y,Y-X,2Z,2dT) in extended twisted Edwards coordinates + point_extedwards_t S, T, U; + unsigned int i; + + // Negating the random point R, Table[0] = -R + ecccopy(R, Table[0]); + fp2neg1271(Table[0]->x); + fp2neg1271(Table[0]->t); + + // Generating S = phi(P) = (XS,YS,ZS,TS) + ecccopy(P, S); + ecc_phi(S); + + // Generating T = psi(T) = (XT,YT,ZT,TT) + ecccopy(P, T); + ecc_psi(T); + + // Generating U = psi(phi(P)) = (XU,YU,ZU,TU) + ecccopy(S, U); + ecc_psi(U); + + eccadd(Table[0], P, Table[1]); // Table[1] = -R+P + eccadd(Table[0], S, Table[2]); // Table[2] = -R+S + eccadd(Table[1], S, Table[3]); // Table[3] = -R+P+S + eccadd(Table[0], T, Table[4]); // Table[4] = -R+T + eccadd(Table[4], P, Table[5]); // Table[5] = -R+P+T + eccadd(Table[4], S, Table[6]); // Table[6] = -R+S+T + eccadd(Table[6], P, Table[7]); // Table[7] = -R+P+S+T + eccadd(Table[0], U, Table[8]); // Table[8] = -R+U + eccadd(Table[1], U, Table[9]); // Table[9] = -R+P+U + eccadd(Table[2], U, Table[10]); // Table[10] = -R+S+U + eccadd(Table[3], U, Table[11]); // Table[11] = -R+P+S+U + eccadd(Table[4], U, Table[12]); // Table[12] = -R+T+U + eccadd(Table[5], U, Table[13]); // Table[13] = -R+P+T+U + eccadd(Table[6], U, Table[14]); // Table[14] = -R+S+T+U + eccadd(Table[7], U, Table[15]); // Table[15] = -R+P+S+T+U + + for (i = 0; i < 16; i++) { + fp2add1271(Table[i]->x, Table[i]->y, S->x); // Converting to coordinates (X+Y,Y-X,2*Z,2*d*T) + fp2sub1271(Table[i]->x, Table[i]->y, Table[i]->y); + fp2copy1271(S->x, Table[i]->x); + fp2add1271(Table[i]->z, Table[i]->z, Table[i]->z); + fp2mul1271(Table[i]->t, (felm_t*)&PARAMETER_d, Table[i]->t); + fp2add1271(Table[i]->t, Table[i]->t, Table[i]->t); + } +} + + +void decompose(uint64_t* k, uint64_t* scalars) +{ // Scalar decomposition for the variable-base scalar multiplication + // Input: scalar in the range [0, 2^256-1]. + // Output: 4 64-bit sub-scalars. + uint64_t a1, a2, a3, a4; + + mul_truncate(k, ell1, &a1); + mul_truncate(k, ell2, &a2); + mul_truncate(k, ell3, &a3); + mul_truncate(k, ell4, &a4); + + scalars[0] = (uint64_t)k[0] - (uint64_t)a1*b11 - (uint64_t)a2*b21 - (uint64_t)a3*b31 - (uint64_t)a4*b41 + c1; + scalars[1] = (uint64_t)a1*b12 + (uint64_t)a2 - (uint64_t)a3*b32 - (uint64_t)a4*b42 + c2; + scalars[2] = (uint64_t)a3*b33 - (uint64_t)a1*b13 - (uint64_t)a2 + (uint64_t)a4*b43 + c3; + scalars[3] = (uint64_t)a1*b14 - (uint64_t)a2*b24 - (uint64_t)a3*b34 + (uint64_t)a4*b44 + c4; +} + + +void randomize(uint64_t* scalars, unsigned char* r, uint128_t* random_scalars) +{ // Scalar randomization for the variable-base scalar multiplication + // Input: 4 64-bit sub-scalars, and 4 16-bit random values. + // Output: 4 80-bit sub-scalars. + uint128_t tt0; + uint64_t r0 = (uint64_t)r[0], r1 = (uint64_t)r[1]; + uint64_t r2 = (uint64_t)r[2], r3 = (uint64_t)r[3]; + + random_scalars[0][1] = 0; random_scalars[0][0] = scalars[0]; + random_scalars[1][1] = 0; random_scalars[1][0] = scalars[1]; + random_scalars[2][1] = 0; random_scalars[2][0] = scalars[2]; + random_scalars[3][1] = 0; random_scalars[3][0] = scalars[3]; + + MUL128(r0, p11, tt0); + ADD128((digit_t*)&random_scalars[0], tt0, (digit_t*)&random_scalars[0]); + MUL128(r1, p21, tt0); + ADD128((digit_t*)&random_scalars[0], tt0, (digit_t*)&random_scalars[0]); + MUL128(r2, p31, tt0); + ADD128((digit_t*)&random_scalars[0], tt0, (digit_t*)&random_scalars[0]); + MUL128(r3, p41, tt0); + ADD128((digit_t*)&random_scalars[0], tt0, (digit_t*)&random_scalars[0]); + + MUL128(r0, p12, tt0); + ADD128((digit_t*)&random_scalars[1], tt0, (digit_t*)&random_scalars[1]); + MUL128(r1, p22, tt0); + ADD128((digit_t*)&random_scalars[1], tt0, (digit_t*)&random_scalars[1]); + MUL128(r2, p32, tt0); + ADD128((digit_t*)&random_scalars[1], tt0, (digit_t*)&random_scalars[1]); + MUL128(r3, p42, tt0); + ADD128((digit_t*)&random_scalars[1], tt0, (digit_t*)&random_scalars[1]); + + MUL128(r0, p13, tt0); + ADD128((digit_t*)&random_scalars[2], tt0, (digit_t*)&random_scalars[2]); + MUL128(r1, p23, tt0); + ADD128((digit_t*)&random_scalars[2], tt0, (digit_t*)&random_scalars[2]); + MUL128(r2, p33, tt0); + ADD128((digit_t*)&random_scalars[2], tt0, (digit_t*)&random_scalars[2]); + MUL128(r3, p43, tt0); + ADD128((digit_t*)&random_scalars[2], tt0, (digit_t*)&random_scalars[2]); + + MUL128(r0, p14, tt0); + ADD128((digit_t*)&random_scalars[3], tt0, (digit_t*)&random_scalars[3]); + MUL128(r1, p24, tt0); + ADD128((digit_t*)&random_scalars[3], tt0, (digit_t*)&random_scalars[3]); + MUL128(r2, p34, tt0); + ADD128((digit_t*)&random_scalars[3], tt0, (digit_t*)&random_scalars[3]); + MUL128(r3, p44, tt0); + ADD128((digit_t*)&random_scalars[3], tt0, (digit_t*)&random_scalars[3]); +} + + +void recode(uint128_t* scalars, unsigned int* digits) +{ // Recoding sub-scalars for use in the variable-base scalar multiplication. + // Input: 4 80-bit sub-scalars passed through "scalars", which are obtained after calling randomize(). + // Outputs: "digits" array with 80 nonzero entries. Each entry is in the range [0, 15], corresponding to one entry in the precomputed table. + unsigned int i, bit; + + for (i = 0; i < 64; i++) + { + bit = (unsigned int)(scalars[0][0]) & 1; + scalars[0][0] >>= 1; + digits[i] = bit; + + bit = (unsigned int)(scalars[1][0]) & 1; + scalars[1][0] >>= 1; + digits[i] += (bit << 1); + + bit = (unsigned int)(scalars[2][0]) & 1; + scalars[2][0] >>= 1; + digits[i] += (bit << 2); + + bit = (unsigned int)(scalars[3][0]) & 1; + scalars[3][0] >>= 1; + digits[i] += (bit << 3); + } + + for (i = 64; i < 80; i++) + { + bit = (unsigned int)scalars[0][1] & 1; + scalars[0][1] >>= 1; + digits[i] = bit; + + bit = (unsigned int)scalars[1][1] & 1; + scalars[1][1] >>= 1; + digits[i] += (bit << 1); + + bit = (unsigned int)scalars[2][1] & 1; + scalars[2][1] >>= 1; + digits[i] += (bit << 2); + + bit = (unsigned int)scalars[3][1] & 1; + scalars[3][1] >>= 1; + digits[i] += (bit << 3); + } +} + + +void cofactor_clearing(point_extedwards_t P) +{ // Co-factor clearing + // Input: P = (X1,Y1,Z1,T1) in extended twisted Edwards coordinates + // Output: P = 392*P = (Xfinal,Yfinal,Zfinal,Tfinal) in extended twisted Edwards coordinates + point_extedwards_t Q; + + ecccopy(P, Q); + eccdouble(P); // P = 2*P using representations (X,Y,Z,T) <- 2*(X,Y,Z,T) + eccadd(P, Q, P); // P = P+Q using representations (X,Y,Z,T) <- (X,Y,Z,T) + (X,Y,Z,T) + eccdouble(P); + eccdouble(P); + eccdouble(P); + eccdouble(P); + eccadd(P, Q, P); + eccdouble(P); + eccdouble(P); + eccdouble(P); +} + + +void select_f2elm(f2elm_t a, f2elm_t b, digit_t bit, f2elm_t c) +{ // Select c <- a if bit = 0, c <- b if bit = 1 + unsigned int j; + digit_t mask, temp, value = 0xAAAAAAAA; + + // If digit=0 mask = 0x55...5 else mask = 0xAA...A + mask = bit - 1; + mask = (mask & ~value) | (~mask & value); + + for (j = 0; j < NWORDS_FIELD; j++) { + temp = a[0][j] ^ b[0][j]; + c[0][j] = ((mask & temp) ^ a[0][j]) ^ (value & temp); + temp = a[1][j] ^ b[1][j]; + c[1][j] = ((mask & temp) ^ a[1][j]) ^ (value & temp); + } +} + + +bool ecc_mul_SCA_secure(point_t P, point_t R, digit_t* k, point_t Q, bool clear_cofactor) +{ // Variable-base scalar multiplication Q = k*P using a 4-dimensional decomposition and protected against side-channel attacks + // The computation is executed as Q = (k*P + R) - R with a random point R used for point blinding + // Inputs: scalar "k" in [0, 2^256-1], + // point P = (x,y) in affine coordinates, + // random point R = (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). + // R is updated to 2*R. + // This function performs point validation and (if selected) cofactor clearing. + point_extedwards_t PP, RR, S, Table[16]; + uint64_t scalars[NWORDS64_ORDER]; + uint128_t rand_scalars[NWORDS64_ORDER]; + unsigned int digits[80]; + unsigned char rand_bytes[8]; + digit_t bit; + f2elm_t Ta, Tb; + felm_t rand_felmt[82]; + int i; + + point_setup(P, PP); // Convert to representation (X,Y,1,T) + if (ecc_point_validate(PP) == false) { // Check if point lies on the curve + return false; + } + if (clear_cofactor == true) { + cofactor_clearing(PP); + } + + point_setup(R, RR); // Convert to representation (X,Y,1,T) + if (ecc_point_validate(RR) == false) { // Check if blinding point lies on the curve + return false; + } + + RandomBytesFunction((unsigned char*)rand_felmt[0], 82*16); + bit = rand_felmt[81][NWORDS_FIELD-1] >> (RADIX-1); + for (i = 0; i < 82; i++) { + rand_felmt[i][NWORDS_FIELD-1] &= (digit_t)(-1) >> 1; + } + + felmt_randomize_point(RR, rand_felmt[81]); // Randomization of R's coordinates + ecccopy(RR, S); // Update R = ((-1)^b*3)*R + eccdouble(RR); + eccadd(S, RR, S); + ecccopy(S, RR); + fp2neg1271(S->y); + fp2neg1271(S->t); + select_f2elm(RR->y, S->y, bit, RR->y); + select_f2elm(RR->t, S->t, bit, RR->t); + felmt_randomize_point(PP, rand_felmt[80]); // Randomization of P's coordinates + + decompose((uint64_t*) k, scalars); // Scalar decomposition + RandomBytesFunction(&rand_bytes[0], 8); + randomize(scalars, rand_bytes, rand_scalars); // Scalar randomization + recode(rand_scalars, digits); // Scalar recoding + ecc_precomp(PP, RR, Table); // Precomputation + ecccopy(RR, PP); + + for (i = 79; i >= 0; i--) + { + eccdouble(PP); // P = 2*P using representations (X,Y,Z,T) <- 2*(X,Y,Z) +#ifdef FULL_TABLE_RANDOMIZATION + randomize_table(Table, rand_felmt[i]); // Randomization of the full table + table_lookup_1x16(Table, S, digits[i]); // Extract point S in (X+Y,Y-X,2Z,2dT) representation +#else + table_lookup_1x16(Table, S, digits[i]); // Extract point S in (X+Y,Y-X,2Z,2dT) representation + felmt_randomize_point(S, rand_felmt[i]); // Randomization of the extracted point +#endif + eccadd_core(PP, S, PP, Ta, Tb); // P = P+S using representations (X,Y,Z,Ta,Tb) <- (X,Y,Z,T) + (X+Y,Y-X,2Z,2dT) + } + + fp2mul1271(Ta, Tb, PP->t); + eccadd_core(PP, Table[0], PP, Ta, Tb); // Final correction: (k*P + R) - R + eccnorm2(PP, Q, RR, R); // Converting output and blinding point to affine coordinates (x,y). + + return true; +} + + +void eccset(point_t P) +{ // Set generator + // Output: P = (x,y) + + fp2copy1271((felm_t*)&GENERATOR_x, P->x); // X1 + fp2copy1271((felm_t*)&GENERATOR_y, P->y); // Y1 +} + + +void eccnorm(point_extedwards_t P, point_t Q) +{ // Normalize a projective point (X1:Y1:Z1), including full reduction + // Input: P = (X1:Y1:Z1) in twisted Edwards coordinates + // Output: Q = (X1/Z1,Y1/Z1), corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates + + fp2inv1271(P->z); // Z1 = Z1^-1 + fp2mul1271(P->x, P->z, Q->x); // X1 = X1/Z1 + fp2mul1271(P->y, P->z, Q->y); // Y1 = Y1/Z1 + mod1271(Q->x[0]); mod1271(Q->x[1]); + mod1271(Q->y[0]); mod1271(Q->y[1]); +} + + +void eccnorm2(point_extedwards_t P, point_t Q, point_extedwards_t R, point_t S) +{ // Normalize two projective points, including full reduction + // Inputs: P = (X1:Y1:Z1) and R = (X2:Y2:Z2) in twisted Edwards coordinates + // Outputs: Q = (X1/Z1,Y1/Z1) and S = (X2/Z2,Y2/Z2) in affine coordinates + f2elm_t t1; + + fp2mul1271(P->z, R->z, t1); // t1 = Z1*Z2 + fp2inv1271(t1); // t1 = (Z1*Z2)^-1 + fp2mul1271(R->z, t1, Q->y); // yQ = Z1^-1 + fp2mul1271(Q->y, P->x, Q->x); // xQ = X1/Z1 + fp2mul1271(Q->y, P->y, Q->y); // yQ = Y1/Z1 + mod1271(Q->x[0]); mod1271(Q->x[1]); + mod1271(Q->y[0]); mod1271(Q->y[1]); + fp2mul1271(t1, P->z, t1); // t1 = Z2^-1 + fp2mul1271(R->x, t1, S->x); // xS = X2/Z2 + fp2mul1271(R->y, t1, S->y); // yS = Y2/Z2 + mod1271(S->x[0]); mod1271(S->x[1]); + mod1271(S->y[0]); mod1271(S->y[1]); +} + + +void eccdouble(point_extedwards_t P) +{ // Point doubling 2P + // Input: P = (X1:Y1:Z1:T1) in twisted Edwards coordinates + // Output: 2P = (Xfinal,Yfinal,Zfinal,Tfinal) in extended twisted Edwards coordinates + f2elm_t t1, t2, t3; + + fp2sqr1271(P->x, t1); // t1 = X1^2 + fp2sqr1271(P->y, P->t); // T = Y1^2 + fp2add1271(P->x, P->y, P->x); // X1 = X1+Y1 + fp2add1271(t1, P->t, t2); // t2 = X1^2+Y1^2 + fp2sub1271(P->t, t1, t1); // t1 = Y1^2-X1^2 + fp2sqr1271(P->z, P->t); // T = Z1^2 + fp2sqr1271(P->x, t3); // t3 = (X1+Y1)^2 + fp2add1271(P->t, P->t, P->t); // T = 2Z1^2 + fp2sub1271(t3, t2, t3); // t3 = 2X1*Y1 = (X1+Y1)^2-(X1^2+Y1^2) + fp2sub1271(P->t, t1, P->t); // T = 2Z1^2-(Y1^2-X1^2) + fp2mul1271(t1, t2, P->y); // Yfinal = (X1^2+Y1^2)(Y1^2-X1^2) + fp2mul1271(P->t, t3, P->x); // Xfinal = 2X1Y1*[2Z1^2-(Y1^2-X1^2)] + fp2mul1271(t1, P->t, P->z); // Zfinal = (Y1^2-X1^2)[2Z1^2-(Y1^2-X1^2)] + fp2mul1271(t2, t3, P->t); // Tfinal = 2X1Y1*(X1^2+Y1^2) +} + + +void eccadd_core(point_extedwards_t P, point_extedwards_t Q, point_extedwards_t R, f2elm_t Ta, f2elm_t Tb) +{ // Basic point addition R = P+Q or R = P+P + // Inputs: P = (X1,Y1,Z1,T1) in extended twisted Edwards coordinates + // Q = (X2+Y2,Y2-X2,2Z2,2dT2) in extended twisted Edwards coordinates + // Output: R = (Xfinal,Yfinal,Zfinal,Tfinal) in extended twisted Edwards coordinates. Tfinal is only used for temporary storage + // Tafinal and Tbfinal such that Tfinal = Tafinal*Tbfinal + f2elm_t t1; + + fp2mul1271(P->z, Q->z, R->z); // Z = 2Z1*Z2 + fp2mul1271(P->t, Q->t, R->t); // T = 2dT1*T2 + fp2add1271(P->x, P->y, Ta); // Ta = X1+Y1 + fp2mul1271(Ta, Q->x, t1); // t1 = (X1+Y1)(X2+Y2) + fp2sub1271(P->x, P->y, Ta); // Ta = X1-Y1 + fp2add1271(R->z, R->t, R->y); // Y = alpha + fp2mul1271(Ta, Q->y, Ta); // Ta = (X1-Y1)(X2-Y2) + fp2sub1271(R->z, R->t, R->z); // Z = theta + fp2sub1271(t1, Ta, Tb); // Tbfinal = beta = (X1+Y1)(X2+Y2)-(X1-Y1)(X2-Y2) + fp2add1271(t1, Ta, Ta); // Tafinal = omega = (X1+Y1)(X2+Y2)+(X1-Y1)(X2-Y2) + fp2mul1271(Tb, R->z, R->x); // Xfinal = beta*theta + fp2mul1271(R->z, R->y, R->z); // Zfinal = theta*alpha + fp2mul1271(R->y, Ta, R->y); // Yfinal = alpha*omega +} + + +void eccadd(point_extedwards_t P, point_extedwards_t Q, point_extedwards_t R) +{ // Complete point addition P = P+Q or P = P+P + // Inputs: P = (X1,Y1,Z1,T1) in extended twisted Edwards coordinates + // Q = (X2,Y2,Z2,T2) in extended twisted Edwards coordinates + // Output: P = (Xfinal,Yfinal,Zfinal,Tfinal) in extended twisted Edwards coordinates + f2elm_t Ta, Tb, t1; + + fp2mul1271(P->z, Q->z, R->z); // Z = Z1*Z2 + fp2mul1271(P->t, Q->t, R->t); // T = T1*T2 + fp2add1271(R->z, R->z, R->z); // Z = 2Z1*Z2 + fp2add1271(R->t, R->t, R->t); // T = 2T1*T2 + fp2add1271(P->x, P->y, Ta); // Ta = X1+Y1 + fp2add1271(Q->x, Q->y, Tb); // Tb = X2+Y2 + fp2mul1271(R->t, (felm_t*)&PARAMETER_d, R->t); // T = 2d*T1*T2 + fp2mul1271(Ta, Tb, t1); // t1 = (X1+Y1)(X2+Y2) + fp2sub1271(P->x, P->y, Ta); // Ta = X1-Y1 + fp2sub1271(Q->x, Q->y, Tb); // Tb = X2-Y2 + fp2add1271(R->z, R->t, R->y); // Y = alpha + fp2mul1271(Ta, Tb, Ta); // Ta = (X1-Y1)(X2-Y2) + fp2sub1271(R->z, R->t, R->z); // Z = theta + fp2sub1271(t1, Ta, Tb); // Tb = beta = (X1+Y1)(X2+Y2)-(X1-Y1)(X2-Y2) + fp2add1271(t1, Ta, Ta); // Ta = omega = (X1+Y1)(X2+Y2)+(X1-Y1)(X2-Y2) + fp2mul1271(Tb, R->z, R->x); // Xfinal = beta*theta + fp2mul1271(R->z, R->y, R->z); // Zfinal = theta*alpha + fp2mul1271(R->y, Ta, R->y); // Yfinal = alpha*omega + fp2mul1271(Ta, Tb, R->t); // Tfinal = Ta*Tb +} + + +void point_setup(point_t P, point_extedwards_t Q) +{ // Point conversion to representation (X,Y,Z,T) + // Input: P = (x,y) in affine coordinates + // Output: P = (X,Y,1,T) corresponding to (X:Y:Z:T) in extended twisted Edwards coordinates + + fp2copy1271(P->x, Q->x); + fp2copy1271(P->y, Q->y); + fp2mul1271(P->x, P->y, Q->t); // T = X*Y + fp2zero1271(Q->z); Q->z[0][0]=1; // Z = 1 +} + + +bool ecc_point_validate(point_extedwards_t P) +{ // Point validation: check if point lies on the curve + // Input: P = (x,y) in affine coordinates, where x, y in [0, 2^127-1]. + // Output: TRUE (1) if point lies on the curve E: -x^2+y^2-1-dx^2*y^2 = 0, FALSE (0) otherwise. + // SECURITY NOTE: this function does not run in constant time (input point P is assumed to be public). + f2elm_t t1, t2, t3; + + fp2sqr1271(P->y, t1); + fp2sqr1271(P->x, t2); + fp2sub1271(t1, t2, t3); // -x^2 + y^2 + fp2mul1271(t1, t2, t1); // x^2*y^2 + fp2mul1271((felm_t*)&PARAMETER_d, t1, t2); // dx^2*y^2 + fp2zero1271(t1); t1[0][0] = 1; // t1 = 1 + fp2add1271(t2, t1, t2); // 1 + dx^2*y^2 + fp2sub1271(t3, t2, t1); // -x^2 + y^2 - 1 - dx^2*y^2 + + return ((is_digit_zero_ct(t1[0][0] | t1[0][1] | t1[0][2] | t1[0][3]) || is_digit_zero_ct((t1[0][0]+1) | (t1[0][1]+1) | (t1[0][2]+1) | (t1[0][3]+1))) && + (is_digit_zero_ct(t1[1][0] | t1[1][1] | t1[1][2] | t1[1][3]) || is_digit_zero_ct((t1[1][0]+1) | (t1[1][1]+1) | (t1[1][2]+1) | (t1[1][3]+1)))); +} + + +static __inline void eccmadd(point_precomp_t Q, point_extedwards_t P) +{ // Mixed point addition P = P+Q or P = P+P + // Inputs: P = (X1,Y1,Z1,T1) in extended twisted Edwards coordinates + // Q = (x2+y2,y2-x2,2dt2) corresponding to (X2:Y2:Z2:T2) in extended twisted Edwards coordinates, where Z2=1 + // Output: P = (Xfinal,Yfinal,Zfinal,Tfinal) in extended twisted Edwards coordinates + f2elm_t t1, t2, t3; + + fp2add1271(P->z, P->z, t1); // t1 = 2Z1 + fp2mul1271(P->t, Q->t2, P->t); // T = 2dT1*t2 + fp2add1271(P->x, P->y, P->z); // Z = (X1+Y1) + fp2sub1271(P->y, P->x, t3); // t3 = (Y1-X1) + fp2sub1271(t1, P->t, t2); // t2 = theta + fp2add1271(t1, P->t, t1); // t1 = alpha + fp2mul1271(Q->xy, P->z, P->t); // T = (X1+Y1)(x2+y2) + fp2mul1271(Q->yx, t3, P->x); // X = (Y1-X1)(y2-x2) + fp2mul1271(t1, t2, P->z); // Zfinal = theta*alpha + fp2sub1271(P->t, P->x, t3); // t3 = beta + fp2add1271(P->t, P->x, P->t); // T = omega + fp2mul1271(t3, t2, P->x); // Xfinal = beta*theta + fp2mul1271(P->t, t1, P->y); // Yfinal = alpha*omega + fp2mul1271(P->t, t3, P->t); // Tfinal = beta*omega +} + + +static __inline void eccneg_extproj_precomp(point_extedwards_t P, point_extedwards_t Q) +{ // Point negation + // Input : point P in coordinates (X+Y,X-Y,2Z,2dT) + // Output: point Q = -P = (Y-X,X+Y,2Z,-2dT) + fp2copy1271(P->t, Q->t); + fp2copy1271(P->x, Q->y); + fp2copy1271(P->y, Q->x); + fp2copy1271(P->z, Q->z); + fp2neg1271(Q->x); + fp2neg1271(Q->y); + fp2neg1271(Q->t); +} + + +static __inline void eccneg_precomp(point_precomp_t P, point_precomp_t Q) +{ // Point negation + // Input : point P in coordinates (x+y,y-x,2dt) + // Output: point Q = -P = (y-x,x+y,-2dt) + fp2copy1271(P->t2, Q->t2); + fp2copy1271(P->xy, Q->yx); + fp2copy1271(P->yx, Q->xy); + fp2neg1271(Q->t2); +} + + +bool ecc_mul_double(digit_t* k, point_t Q, digit_t* l, point_t R) +{ // Double scalar multiplication R = k*G + l*Q, where the G is the generator. Uses DOUBLE_SCALAR_TABLE, which contains multiples of G, Phi(G), Psi(G) and Phi(Psi(G)). + // Inputs: point Q in affine coordinates, + // scalars "k" and "l" in [0, 2^256-1]. + // Output: R = k*G + l*Q in affine coordinates (x,y). + // The function uses wNAF with interleaving. + + // SECURITY NOTE: this function is intended for a non-constant-time operation such as signature verification. + + unsigned int position; + int i, digits_k1[65] = {0}, digits_k2[65] = {0}, digits_k3[65] = {0}, digits_k4[65] = {0}; + int digits_l1[65] = {0}, digits_l2[65] = {0}, digits_l3[65] = {0}, digits_l4[65] = {0}; + point_precomp_t V; + point_extedwards_t Q1, Q2, Q3, Q4, T; + point_extedwards_t U, Q_table1[NPOINTS_DOUBLEMUL_WQ], Q_table2[NPOINTS_DOUBLEMUL_WQ], Q_table3[NPOINTS_DOUBLEMUL_WQ], Q_table4[NPOINTS_DOUBLEMUL_WQ]; + f2elm_t t0, t1; + uint64_t k_scalars[4], l_scalars[4]; + + point_setup(Q, Q1); // Convert to representation (X,Y,1,Ta,Tb) + + if (ecc_point_validate(Q1) == false) { // Check if point lies on the curve + return false; + } + + // Computing endomorphisms over point Q + ecccopy(Q1, Q2); + ecc_phi(Q2); + ecccopy(Q1, Q3); + ecc_psi(Q3); + ecccopy(Q2, Q4); + ecc_psi(Q4); + + decompose((uint64_t*)k, k_scalars); // Scalar decomposition + decompose((uint64_t*)l, l_scalars); + wNAF_recode(k_scalars[0], WP_DOUBLEBASE, digits_k1); // Scalar recoding + wNAF_recode(k_scalars[1], WP_DOUBLEBASE, digits_k2); + wNAF_recode(k_scalars[2], WP_DOUBLEBASE, digits_k3); + wNAF_recode(k_scalars[3], WP_DOUBLEBASE, digits_k4); + wNAF_recode(l_scalars[0], WQ_DOUBLEBASE, digits_l1); + wNAF_recode(l_scalars[1], WQ_DOUBLEBASE, digits_l2); + wNAF_recode(l_scalars[2], WQ_DOUBLEBASE, digits_l3); + wNAF_recode(l_scalars[3], WQ_DOUBLEBASE, digits_l4); + ecc_precomp_double(Q1, Q_table1, NPOINTS_DOUBLEMUL_WQ); // Precomputation + ecc_precomp_double(Q2, Q_table2, NPOINTS_DOUBLEMUL_WQ); + ecc_precomp_double(Q3, Q_table3, NPOINTS_DOUBLEMUL_WQ); + ecc_precomp_double(Q4, Q_table4, NPOINTS_DOUBLEMUL_WQ); + + fp2zero1271(T->x); // Initialize T as the neutral point (0:1:1) + fp2zero1271(T->y); T->y[0][0] = 1; + fp2zero1271(T->z); T->z[0][0] = 1; + + for (i = 64; i >= 0; i--) + { + eccdouble(T); // Double (X_T,Y_T,Z_T,T_T) = 2(X_T,Y_T,Z_T,T_T) + if (digits_l1[i] < 0) { + position = (-digits_l1[i])/2; + eccneg_extproj_precomp(Q_table1[position], U); // Load and negate U = (X_U,Y_U,Z_U,Td_U) <- -(X+Y,X-Y,2Z,2dT) from a point in the precomputed table + eccadd_core(T, U, T, t0, t1); // T = T+U = (X_T,Y_T,Z_T,T_T) = (X_T,Y_T,Z_T,T_T) + (X_U,Y_U,Z_U,Td_U) + fp2mul1271(t0, t1, T->t); + } else if (digits_l1[i] > 0) { + position = (digits_l1[i])/2; // Take U = (X_U,Y_U,Z_U,Td_U) <- (X+Y,X-Y,2Z,2dT) from a point in the precomputed table + eccadd_core(T, Q_table1[position], T, t0, t1); // T = T+U = (X_T,Y_T,Z_T,T_T) = (X_T,Y_T,Z_T,T_T) + (X_U,Y_U,Z_U,Td_U) + fp2mul1271(t0, t1, T->t); + } + if (digits_l2[i] < 0) { + position = (-digits_l2[i])/2; + eccneg_extproj_precomp(Q_table2[position], U); + eccadd_core(T, U, T, t0, t1); + fp2mul1271(t0, t1, T->t); + } else if (digits_l2[i] > 0) { + position = (digits_l2[i])/2; + eccadd_core(T, Q_table2[position], T, t0, t1); + fp2mul1271(t0, t1, T->t); + } + if (digits_l3[i] < 0) { + position = (-digits_l3[i])/2; + eccneg_extproj_precomp(Q_table3[position], U); + eccadd_core(T, U, T, t0, t1); + fp2mul1271(t0, t1, T->t); + } else if (digits_l3[i] > 0) { + position = (digits_l3[i])/2; + eccadd_core(T, Q_table3[position], T, t0, t1); + fp2mul1271(t0, t1, T->t); + } + if (digits_l4[i] < 0) { + position = (-digits_l4[i])/2; + eccneg_extproj_precomp(Q_table4[position], U); + eccadd_core(T, U, T, t0, t1); + fp2mul1271(t0, t1, T->t); + } else if (digits_l4[i] > 0) { + position = (digits_l4[i])/2; + eccadd_core(T, Q_table4[position], T, t0, t1); + fp2mul1271(t0, t1, T->t); + } + + if (digits_k1[i] < 0) { + position = (-digits_k1[i])/2; + eccneg_precomp(((point_precomp_t*)&DOUBLE_SCALAR_TABLE)[position], V); // Load and negate V = (X_V,Y_V,Z_V,Td_V) <- -(x+y,y-x,2dt) from a point in the precomputed table + eccmadd(V, T); // T = T+V = (X_T,Y_T,Z_T,Ta_T,Tb_T) = (X_T,Y_T,Z_T,Ta_T,Tb_T) + (X_V,Y_V,Z_V,Td_V) + } else if (digits_k1[i] > 0) { + position = (digits_k1[i])/2; // Take V = (X_V,Y_V,Z_V,Td_V) <- (x+y,y-x,2dt) from a point in the precomputed table + eccmadd(((point_precomp_t*)&DOUBLE_SCALAR_TABLE)[position], T); // T = T+V = (X_T,Y_T,Z_T,Ta_T,Tb_T) = (X_T,Y_T,Z_T,Ta_T,Tb_T) + (X_V,Y_V,Z_V,Td_V) + } + if (digits_k2[i] < 0) { + position = (-digits_k2[i])/2; + eccneg_precomp(((point_precomp_t*)&DOUBLE_SCALAR_TABLE)[NPOINTS_DOUBLEMUL_WP+position], V); + eccmadd(V, T); + } else if (digits_k2[i] > 0) { + position = (digits_k2[i])/2; + eccmadd(((point_precomp_t*)&DOUBLE_SCALAR_TABLE)[NPOINTS_DOUBLEMUL_WP+position], T); + } + if (digits_k3[i] < 0) { + position = (-digits_k3[i])/2; + eccneg_precomp(((point_precomp_t*)&DOUBLE_SCALAR_TABLE)[2*NPOINTS_DOUBLEMUL_WP+position], V); + eccmadd(V, T); + } else if (digits_k3[i] > 0) { + position = (digits_k3[i])/2; + eccmadd(((point_precomp_t*)&DOUBLE_SCALAR_TABLE)[2*NPOINTS_DOUBLEMUL_WP+position], T); + } + if (digits_k4[i] < 0) { + position = (-digits_k4[i])/2; + eccneg_precomp(((point_precomp_t*)&DOUBLE_SCALAR_TABLE)[3*NPOINTS_DOUBLEMUL_WP+position], V); + eccmadd(V, T); + } else if (digits_k4[i] > 0) { + position = (digits_k4[i])/2; + eccmadd(((point_precomp_t*)&DOUBLE_SCALAR_TABLE)[3*NPOINTS_DOUBLEMUL_WP+position], T); + } + } + eccnorm(T, R); // Output R = (x,y) + + return true; +} + + +static __inline void R_to_R2(point_extedwards_t P, point_extedwards_t Q) +{ // Conversion from representation (X,Y,Z,T) to (X+Y,X-Y,2Z,2dT), where T = Ta*Tb + // Input: P = (X1,Y1,Z1,T1) in extended twisted Edwards coordinates + // Output: Q = (X1+Y1,Y1-X1,2Z1,2dT1) corresponding to (X1:Y1:Z1:T1) in extended twisted Edwards coordinates + + fp2add1271(P->t, P->t, Q->t); // T = 2*T + fp2add1271(P->x, P->y, Q->x); // QX = X+Y + fp2sub1271(P->x, P->y, Q->y); // QY = X-Y + fp2add1271(P->z, P->z, Q->z); // QZ = 2*Z + fp2mul1271(Q->t, (felm_t*)&PARAMETER_d, Q->t); // QT = 2d*T +} + + +void ecc_precomp_double(point_extedwards_t P, point_extedwards_t* Table, unsigned int npoints) +{ // Generation of the precomputation table used internally by the double scalar multiplication function ecc_mul_double(). + // Inputs: point P in representation (X,Y,Z,T), + // Table with storage for npoints, + // number of points "npoints". + // Output: Table containing multiples of the base point P using representation (X+Y,X-Y,2Z,2dT). + point_extedwards_t Q; + unsigned int i; + + R_to_R2(P, Table[0]); // Precomputed point Table[0] = P in coordinates (X+Y,X-Y,2Z,2dT) + ecccopy(P, Q); + eccdouble(P); // 2*P in (X,Y,Z,T) + + for (i = 1; i < npoints; i++) { + eccadd(Q, P, Q); // Table[i] = Table[i-1]+2P + R_to_R2(Q, Table[i]); // Converting from (X,Y,Z,T) to (X+Y,X-Y,2Z,2dT) + } + + return; +} + + +void wNAF_recode(uint64_t scalar, unsigned int w, int* digits) +{ // Computes wNAF recoding of a scalar, where digits are in set {0,+-1,+-3,...,+-(2^(w-1)-1)} + unsigned int i; + int digit, index = 0; + int val1 = (int)(1 << (w-1)) - 1; // 2^(w-1) - 1 + int val2 = (int)(1 << w); // 2^w; + uint64_t k = scalar, mask = (uint64_t)val2 - 1; // 2^w - 1 + + while (k != 0) + { + digit = (int)(k & 1); + + if (digit == 0) { + k >>= 1; // Shift scalar to the right by 1 + digits[index] = 0; + } else { + digit = (int)(k & mask); + k >>= w; // Shift scalar to the right by w + + if (digit > val1) { + digit -= val2; + } + if (digit < 0) { // scalar + 1 + k += 1; + } + digits[index] = digit; + + if (k != 0) { // Check if scalar != 0 + for (i = 0; i < (w-1); i++) + { + index++; + digits[index] = 0; + } + } + } + index++; + } + return; +} \ No newline at end of file diff --git a/FourQ_ARM_side_channel/kex.c b/FourQ_ARM_side_channel/kex.c new file mode 100644 index 0000000..6f46974 --- /dev/null +++ b/FourQ_ARM_side_channel/kex.c @@ -0,0 +1,251 @@ +/******************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: Diffie-Hellman key exchange based on FourQ, including countermeasures +* against side-channel attacks +* option 1: co-factor ecdh using compressed 32-byte public keys, +* (see https://datatracker.ietf.org/doc/draft-ladd-cfrg-4q/). +* option 2: co-factor ecdh using uncompressed, 64-byte public keys. +*********************************************************************************/ + +#include "FourQ_internal.h" +#include "FourQ_params.h" +#include "../random/random.h" +#include + + +static __inline bool is_neutral_point(point_t P) +{ // Is P the neutral point (0,1)? + // SECURITY NOTE: this function does not run in constant time (input point P is assumed to be public). + + if (is_zero_ct((digit_t*)P->x, 2*NWORDS_FIELD) && is_zero_ct(&((digit_t*)P->y)[1], 2*NWORDS_FIELD-1) && is_digit_zero_ct(P->y[0][0] - 1)) { + return true; + } + return false; +} + + +/*************** ECDH USING COMPRESSED, 32-BYTE PUBLIC KEYS ***************/ + +ECCRYPTO_STATUS CompressedPublicKeyGeneration_SCA_secure(const unsigned char* SecretKey, unsigned char* PublicKey, unsigned char* BlindingPoint) +{ // Compressed public key generation for key exchange + // It produces a public key PublicKey, which is the encoding of P = SecretKey*G (G is the generator), and a blinding point BlindingPoint. + // Input: 32-byte SecretKey + // Output: 32-byte PublicKey and 64-byte BlindingPoint + point_t G, R; + point_extedwards_t S; + unsigned char SecretBlinding[32]; + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + Status = RandomBytesFunction(SecretBlinding, 32); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + // Set up an initial "weak" blinding point R + fp2copy1271((felm_t*)&GENERATOR_x[0], G->x); + fp2copy1271((felm_t*)&GENERATOR_y[0], G->y); + point_setup(G, S); + eccdouble(S); + eccnorm(S, R); + + // Computing an initial blinding point. This computation itself is not protected with a secure point blinding + Status = ecc_mul_SCA_secure(G, R, (digit_t*)SecretBlinding, (point_affine*)BlindingPoint, false); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + Status = ecc_mul_SCA_secure(G, (point_affine*)BlindingPoint, (digit_t*)SecretKey, R, false); // Compute public key + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + encode(R, PublicKey); // Encode public key + +// Cleanup + clear_words((unsigned int*)SecretBlinding, 256/(sizeof(unsigned int)*8)); + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)SecretBlinding, 256/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)BlindingPoint, 512/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)PublicKey, 256/(sizeof(unsigned int)*8)); + + return Status; +} + + +ECCRYPTO_STATUS CompressedKeyGeneration_SCA_secure(unsigned char* SecretKey, unsigned char* PublicKey, unsigned char* BlindingPoint) +{ // Keypair generation for key exchange. Public key is compressed to 32 bytes + // It produces a private key SecretKey, a public key PublicKey, which is the encoding of P = SecretKey*G (G is the generator), and a blinding point BlindingPoint. + // Outputs: 32-byte SecretKey, 32-byte PublicKey and 64-byte BlindingPoint + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + Status = RandomBytesFunction(SecretKey, 32); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + Status = CompressedPublicKeyGeneration_SCA_secure(SecretKey, PublicKey, BlindingPoint); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)SecretKey, 256/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)PublicKey, 256/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)BlindingPoint, 512/(sizeof(unsigned int)*8)); + + return Status; +} + + +ECCRYPTO_STATUS CompressedSecretAgreement_SCA_secure(const unsigned char* SecretKey, const unsigned char* PublicKey, unsigned char* SharedSecret, unsigned char* BlindingPoint) +{ // Secret agreement computation for key exchange using a compressed, 32-byte public key + // The output is the y-coordinate of SecretKey*A, where A is the decoding of the public key PublicKey. + // Inputs: 32-byte SecretKey, 32-byte PublicKey and 64-byte BlindingPoint + // Output: 32-byte SharedSecret and updated BlindingPoint + point_t A; + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + if ((PublicKey[15] & 0x80) != 0) { // Is bit128(PublicKey) = 0? + Status = ECCRYPTO_ERROR_INVALID_PARAMETER; + goto cleanup; + } + + Status = decode(PublicKey, A); // Also verifies that A is on the curve. If it is not, it fails + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + Status = ecc_mul_SCA_secure(A, (point_affine*)BlindingPoint, (digit_t*)SecretKey, A, true); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + if (is_neutral_point(A)) { // Is output = neutral point (0,1)? + Status = ECCRYPTO_ERROR_SHARED_KEY; + goto cleanup; + } + + memmove(SharedSecret, (unsigned char*)A->y, 32); + + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)SharedSecret, 256/(sizeof(unsigned int)*8)); + + return Status; +} + + +/*************** ECDH USING UNCOMPRESSED PUBLIC KEYS ***************/ + +ECCRYPTO_STATUS PublicKeyGeneration_SCA_secure(const unsigned char* SecretKey, unsigned char* PublicKey, unsigned char* BlindingPoint) +{ // Public key generation for key exchange + // It produces the public key PublicKey = SecretKey*G, where G is the generator, and a blinding point BlindingPoint. + // Input: 32-byte SecretKey + // Output: 64-byte PublicKey and 64-byte BlindingPoint + point_t G, R; + point_extedwards_t S; + unsigned char SecretBlinding[32]; + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + Status = RandomBytesFunction(SecretBlinding, 32); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + // Set up an initial "weak" blinding point R + fp2copy1271((felm_t*)&GENERATOR_x[0], G->x); + fp2copy1271((felm_t*)&GENERATOR_y[0], G->y); + point_setup(G, S); + eccdouble(S); + eccnorm(S, R); + + // Computing an initial blinding point. This computation itself is not protected with a secure point blinding + Status = ecc_mul_SCA_secure(G, R, (digit_t*)SecretBlinding, (point_affine*)BlindingPoint, false); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + Status = ecc_mul_SCA_secure(G, (point_affine*)BlindingPoint, (digit_t*)SecretKey, (point_affine*)PublicKey, false); // Compute public key + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + +// Cleanup + clear_words((unsigned int*)SecretBlinding, 256/(sizeof(unsigned int)*8)); + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)SecretBlinding, 256/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)BlindingPoint, 512/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)PublicKey, 512/(sizeof(unsigned int)*8)); + + return Status; +} + + +ECCRYPTO_STATUS KeyGeneration_SCA_secure(unsigned char* SecretKey, unsigned char* PublicKey, unsigned char* BlindingPoint) +{ // Keypair generation for key exchange + // It produces a private key SecretKey, the public key PublicKey = SecretKey*G, where G is the generator, and a blinding point BlindingPoint. + // Outputs: 32-byte SecretKey, 64-byte PublicKey and 64-byte BlindingPoint + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + Status = RandomBytesFunction(SecretKey, 32); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + Status = PublicKeyGeneration_SCA_secure(SecretKey, PublicKey, BlindingPoint); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)SecretKey, 256/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)PublicKey, 512/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)BlindingPoint, 512/(sizeof(unsigned int)*8)); + + return Status; +} + + +ECCRYPTO_STATUS SecretAgreement_SCA_secure(const unsigned char* SecretKey, const unsigned char* PublicKey, unsigned char* SharedSecret, unsigned char* BlindingPoint) +{ // Secret agreement computation for key exchange + // The output is the y-coordinate of SecretKey*PublicKey. + // Inputs: 32-byte SecretKey, 64-byte PublicKey and 64-byte BlindingPoint + // Output: 32-byte SharedSecret and updated BlindingPoint + point_t A; + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + if (((PublicKey[15] & 0x80) != 0) || ((PublicKey[31] & 0x80) != 0) || ((PublicKey[47] & 0x80) != 0) || ((PublicKey[63] & 0x80) != 0)) { // Are PublicKey_x[i] and PublicKey_y[i] < 2^127? + Status = ECCRYPTO_ERROR_INVALID_PARAMETER; + goto cleanup; + } + + Status = ecc_mul_SCA_secure((point_affine*)PublicKey, (point_affine*)BlindingPoint, (digit_t*)SecretKey, A, true); // Also verifies that PublicKey and BlindingPoint are points on the curve. If not, it fails + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + if (is_neutral_point(A)) { // Is output = neutral point (0,1)? + Status = ECCRYPTO_ERROR_SHARED_KEY; + goto cleanup; + } + + memmove(SharedSecret, (unsigned char*)A->y, 32); + + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)SharedSecret, 256/(sizeof(unsigned int)*8)); + + return Status; +} \ No newline at end of file diff --git a/FourQ_ARM_side_channel/libopencm3/include/common.h b/FourQ_ARM_side_channel/libopencm3/include/common.h new file mode 100644 index 0000000..a7a8df8 --- /dev/null +++ b/FourQ_ARM_side_channel/libopencm3/include/common.h @@ -0,0 +1,96 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef LIBOPENCM3_CM3_COMMON_H +#define LIBOPENCM3_CM3_COMMON_H + +#include +#include + +/* This must be placed around external function declaration for C++ + * support. */ +#ifdef __cplusplus +# define BEGIN_DECLS extern "C" { +# define END_DECLS } +#else +# define BEGIN_DECLS +# define END_DECLS +#endif + +/* Full-featured deprecation attribute with fallback for older compilers. */ + +#ifdef __GNUC__ +# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4) +# define LIBOPENCM3_DEPRECATED(x) __attribute__((deprecated(x))) +# else +# define LIBOPENCM3_DEPRECATED(x) __attribute__((deprecated)) +# endif +#else +# define LIBOPENCM3_DEPRECATED(x) +#endif + + +/* Generic memory-mapped I/O accessor functions */ +#define MMIO8(addr) (*(volatile uint8_t *)(addr)) +#define MMIO16(addr) (*(volatile uint16_t *)(addr)) +#define MMIO32(addr) (*(volatile uint32_t *)(addr)) +#define MMIO64(addr) (*(volatile uint64_t *)(addr)) + +/* Generic bit-band I/O accessor functions */ +#define BBIO_SRAM(addr, bit) \ + MMIO32((((uint32_t)addr) & 0x0FFFFF) * 32 + 0x22000000 + (bit) * 4) + +#define BBIO_PERIPH(addr, bit) \ + MMIO32((((uint32_t)addr) & 0x0FFFFF) * 32 + 0x42000000 + (bit) * 4) + +/* Generic bit definition */ +#define BIT0 (1<<0) +#define BIT1 (1<<1) +#define BIT2 (1<<2) +#define BIT3 (1<<3) +#define BIT4 (1<<4) +#define BIT5 (1<<5) +#define BIT6 (1<<6) +#define BIT7 (1<<7) +#define BIT8 (1<<8) +#define BIT9 (1<<9) +#define BIT10 (1<<10) +#define BIT11 (1<<11) +#define BIT12 (1<<12) +#define BIT13 (1<<13) +#define BIT14 (1<<14) +#define BIT15 (1<<15) +#define BIT16 (1<<16) +#define BIT17 (1<<17) +#define BIT18 (1<<18) +#define BIT19 (1<<19) +#define BIT20 (1<<20) +#define BIT21 (1<<21) +#define BIT22 (1<<22) +#define BIT23 (1<<23) +#define BIT24 (1<<24) +#define BIT25 (1<<25) +#define BIT26 (1<<26) +#define BIT27 (1<<27) +#define BIT28 (1<<28) +#define BIT29 (1<<29) +#define BIT30 (1<<30) +#define BIT31 (1<<31) + +#endif diff --git a/FourQ_ARM_side_channel/libopencm3/include/gpio.h b/FourQ_ARM_side_channel/libopencm3/include/gpio.h new file mode 100644 index 0000000..eb4c68a --- /dev/null +++ b/FourQ_ARM_side_channel/libopencm3/include/gpio.h @@ -0,0 +1,110 @@ +/** @addtogroup gpio_defines + * + * @author @htmlonly © @endhtmlonly 2011 + * Fergus Noble + * @author @htmlonly © @endhtmlonly 2012 + * Ken Sarkies + * + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Fergus Noble + * Copyright (C) 2012 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY, BUT ONLY VIA GPIO.H +The order of header inclusion is important. gpio.h includes the device +specific memorymap.h header before including this header file.*/ + +/** @cond */ +#ifndef LIBOPENCM3_GPIO_H +#define LIBOPENCM3_GPIO_H +/** @endcond */ +#ifndef LIBOPENCM3_GPIO_COMMON_F24_H +#define LIBOPENCM3_GPIO_COMMON_F24_H + +/**@{*/ +#include "memorymap_f4.h" +#include "gpio_common_f234.h" + +/* GPIO port base addresses (for convenience) */ +/** @defgroup gpio_port_id GPIO Port IDs +@ingroup gpio_defines + +@{*/ +#define GPIOG GPIO_PORT_G_BASE +#define GPIOH GPIO_PORT_H_BASE +#define GPIOI GPIO_PORT_I_BASE +/**@}*/ + +/* --- GPIO registers for STM32F2, STM32F3 and STM32F4 --------------------- */ + +/* Port mode register (GPIOx_MODER) */ +#define GPIOG_MODER GPIO_MODER(GPIOG) +#define GPIOH_MODER GPIO_MODER(GPIOH) +#define GPIOI_MODER GPIO_MODER(GPIOI) + +/* Port output type register (GPIOx_OTYPER) */ +#define GPIOG_OTYPER GPIO_OTYPER(GPIOG) +#define GPIOH_OTYPER GPIO_OTYPER(GPIOH) +#define GPIOI_OTYPER GPIO_OTYPER(GPIOI) + +/* Port output speed register (GPIOx_OSPEEDR) */ +#define GPIOG_OSPEEDR GPIO_OSPEEDR(GPIOG) +#define GPIOH_OSPEEDR GPIO_OSPEEDR(GPIOH) +#define GPIOI_OSPEEDR GPIO_OSPEEDR(GPIOI) + +/* Port pull-up/pull-down register (GPIOx_PUPDR) */ +#define GPIOG_PUPDR GPIO_PUPDR(GPIOG) +#define GPIOH_PUPDR GPIO_PUPDR(GPIOH) +#define GPIOI_PUPDR GPIO_PUPDR(GPIOI) + +/* Port input data register (GPIOx_IDR) */ +#define GPIOG_IDR GPIO_IDR(GPIOG) +#define GPIOH_IDR GPIO_IDR(GPIOH) +#define GPIOI_IDR GPIO_IDR(GPIOI) + +/* Port output data register (GPIOx_ODR) */ +#define GPIOG_ODR GPIO_ODR(GPIOG) +#define GPIOH_ODR GPIO_ODR(GPIOH) +#define GPIOI_ODR GPIO_ODR(GPIOI) + +/* Port bit set/reset register (GPIOx_BSRR) */ +#define GPIOG_BSRR GPIO_BSRR(GPIOG) +#define GPIOH_BSRR GPIO_BSRR(GPIOH) +#define GPIOI_BSRR GPIO_BSRR(GPIOI) + +/* Port configuration lock register (GPIOx_LCKR) */ +#define GPIOG_LCKR GPIO_LCKR(GPIOG) +#define GPIOH_LCKR GPIO_LCKR(GPIOH) +#define GPIOI_LCKR GPIO_LCKR(GPIOI) + +/* Alternate function low register (GPIOx_AFRL) */ +#define GPIOG_AFRL GPIO_AFRL(GPIOG) +#define GPIOH_AFRL GPIO_AFRL(GPIOH) +#define GPIOI_AFRL GPIO_AFRL(GPIOI) + +/* Alternate function high register (GPIOx_AFRH) */ +#define GPIOG_AFRH GPIO_AFRH(GPIOG) +#define GPIOH_AFRH GPIO_AFRH(GPIOH) +#define GPIOI_AFRH GPIO_AFRH(GPIOI) + +/**@}*/ +#endif +/** @cond */ +#endif +/** @endcond */ diff --git a/FourQ_ARM_side_channel/libopencm3/include/gpio_common_all.h b/FourQ_ARM_side_channel/libopencm3/include/gpio_common_all.h new file mode 100644 index 0000000..1f15d90 --- /dev/null +++ b/FourQ_ARM_side_channel/libopencm3/include/gpio_common_all.h @@ -0,0 +1,89 @@ +/** @addtogroup gpio_defines + * + * @author @htmlonly © @endhtmlonly 2011 + * Fergus Noble + * @author @htmlonly © @endhtmlonly 2012 + * Ken Sarkies + * + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Fergus Noble + * Copyright (C) 2012 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY, BUT ONLY VIA GPIO.H +The order of header inclusion is important. gpio.h includes the device +specific memorymap.h header before including this header file.*/ + +/** @cond */ +#if defined(LIBOPENCM3_GPIO_H) +/** @endcond */ +#ifndef LIBOPENCM3_GPIO_COMMON_ALL_H +#define LIBOPENCM3_GPIO_COMMON_ALL_H + +/**@{*/ + +/* --- Convenience macros -------------------------------------------------- */ + +/* --- GPIO_LCKR values ---------------------------------------------------- */ + +#define GPIO_LCKK (1 << 16) +/* GPIO_LCKR[15:0]: LCKy: Port x lock bit y (y = 0..15) */ + +/* GPIO number definitions (for convenience) */ +/** @defgroup gpio_pin_id GPIO Pin Identifiers +@ingroup gpio_defines + +@{*/ +#define GPIO0 (1 << 0) +#define GPIO1 (1 << 1) +#define GPIO2 (1 << 2) +#define GPIO3 (1 << 3) +#define GPIO4 (1 << 4) +#define GPIO5 (1 << 5) +#define GPIO6 (1 << 6) +#define GPIO7 (1 << 7) +#define GPIO8 (1 << 8) +#define GPIO9 (1 << 9) +#define GPIO10 (1 << 10) +#define GPIO11 (1 << 11) +#define GPIO12 (1 << 12) +#define GPIO13 (1 << 13) +#define GPIO14 (1 << 14) +#define GPIO15 (1 << 15) +#define GPIO_ALL 0xffff +/**@}*/ + + +void gpio_set(uint32_t gpioport, uint16_t gpios); +void gpio_clear(uint32_t gpioport, uint16_t gpios); +uint16_t gpio_get(uint32_t gpioport, uint16_t gpios); +void gpio_toggle(uint32_t gpioport, uint16_t gpios); +uint16_t gpio_port_read(uint32_t gpioport); +void gpio_port_write(uint32_t gpioport, uint16_t data); +void gpio_port_config_lock(uint32_t gpioport, uint16_t gpios); + + +/**@}*/ +#endif +/** @cond */ +#else +#warning "gpio_common_all.h should not be included explicitly, only via gpio.h" +#endif +/** @endcond */ + diff --git a/FourQ_ARM_side_channel/libopencm3/include/gpio_common_f234.h b/FourQ_ARM_side_channel/libopencm3/include/gpio_common_f234.h new file mode 100644 index 0000000..be561dd --- /dev/null +++ b/FourQ_ARM_side_channel/libopencm3/include/gpio_common_f234.h @@ -0,0 +1,270 @@ +/** @addtogroup gpio_defines + * + * @author @htmlonly © @endhtmlonly 2011 + * Fergus Noble + * @author @htmlonly © @endhtmlonly 2012 + * Ken Sarkies + * + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Fergus Noble + * Copyright (C) 2012 Ken Sarkies + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY, BUT ONLY VIA GPIO.H +The order of header inclusion is important. gpio.h includes the device +specific memorymap.h header before including this header file.*/ + +/** @cond */ +#ifdef LIBOPENCM3_GPIO_H +/** @endcond */ +#ifndef LIBOPENCM3_GPIO_COMMON_F234_H +#define LIBOPENCM3_GPIO_COMMON_F234_H + +/**@{*/ + +#include "gpio_common_all.h" + +/* GPIO port base addresses (for convenience) */ +/** @defgroup gpio_port_id GPIO Port IDs +@ingroup gpio_defines + +@{*/ +#define GPIOA GPIO_PORT_A_BASE +#define GPIOB GPIO_PORT_B_BASE +#define GPIOC GPIO_PORT_C_BASE +#define GPIOD GPIO_PORT_D_BASE +#define GPIOE GPIO_PORT_E_BASE +#define GPIOF GPIO_PORT_F_BASE + +/**@}*/ + +/* --- GPIO registers for STM32F2, STM32F3 and STM32F4 --------------------- */ + +/* Port mode register (GPIOx_MODER) */ +#define GPIO_MODER(port) MMIO32((port) + 0x00) +#define GPIOA_MODER GPIO_MODER(GPIOA) +#define GPIOB_MODER GPIO_MODER(GPIOB) +#define GPIOC_MODER GPIO_MODER(GPIOC) +#define GPIOD_MODER GPIO_MODER(GPIOD) +#define GPIOE_MODER GPIO_MODER(GPIOE) +#define GPIOF_MODER GPIO_MODER(GPIOF) + +/* Port output type register (GPIOx_OTYPER) */ +#define GPIO_OTYPER(port) MMIO32((port) + 0x04) +#define GPIOA_OTYPER GPIO_OTYPER(GPIOA) +#define GPIOB_OTYPER GPIO_OTYPER(GPIOB) +#define GPIOC_OTYPER GPIO_OTYPER(GPIOC) +#define GPIOD_OTYPER GPIO_OTYPER(GPIOD) +#define GPIOE_OTYPER GPIO_OTYPER(GPIOE) +#define GPIOF_OTYPER GPIO_OTYPER(GPIOF) + +/* Port output speed register (GPIOx_OSPEEDR) */ +#define GPIO_OSPEEDR(port) MMIO32((port) + 0x08) +#define GPIOA_OSPEEDR GPIO_OSPEEDR(GPIOA) +#define GPIOB_OSPEEDR GPIO_OSPEEDR(GPIOB) +#define GPIOC_OSPEEDR GPIO_OSPEEDR(GPIOC) +#define GPIOD_OSPEEDR GPIO_OSPEEDR(GPIOD) +#define GPIOE_OSPEEDR GPIO_OSPEEDR(GPIOE) +#define GPIOF_OSPEEDR GPIO_OSPEEDR(GPIOF) + +/* Port pull-up/pull-down register (GPIOx_PUPDR) */ +#define GPIO_PUPDR(port) MMIO32((port) + 0x0c) +#define GPIOA_PUPDR GPIO_PUPDR(GPIOA) +#define GPIOB_PUPDR GPIO_PUPDR(GPIOB) +#define GPIOC_PUPDR GPIO_PUPDR(GPIOC) +#define GPIOD_PUPDR GPIO_PUPDR(GPIOD) +#define GPIOE_PUPDR GPIO_PUPDR(GPIOE) +#define GPIOF_PUPDR GPIO_PUPDR(GPIOF) + +/* Port input data register (GPIOx_IDR) */ +#define GPIO_IDR(port) MMIO32((port) + 0x10) +#define GPIOA_IDR GPIO_IDR(GPIOA) +#define GPIOB_IDR GPIO_IDR(GPIOB) +#define GPIOC_IDR GPIO_IDR(GPIOC) +#define GPIOD_IDR GPIO_IDR(GPIOD) +#define GPIOE_IDR GPIO_IDR(GPIOE) +#define GPIOF_IDR GPIO_IDR(GPIOF) + +/* Port output data register (GPIOx_ODR) */ +#define GPIO_ODR(port) MMIO32((port) + 0x14) +#define GPIOA_ODR GPIO_ODR(GPIOA) +#define GPIOB_ODR GPIO_ODR(GPIOB) +#define GPIOC_ODR GPIO_ODR(GPIOC) +#define GPIOD_ODR GPIO_ODR(GPIOD) +#define GPIOE_ODR GPIO_ODR(GPIOE) +#define GPIOF_ODR GPIO_ODR(GPIOF) + +/* Port bit set/reset register (GPIOx_BSRR) */ +#define GPIO_BSRR(port) MMIO32((port) + 0x18) +#define GPIOA_BSRR GPIO_BSRR(GPIOA) +#define GPIOB_BSRR GPIO_BSRR(GPIOB) +#define GPIOC_BSRR GPIO_BSRR(GPIOC) +#define GPIOD_BSRR GPIO_BSRR(GPIOD) +#define GPIOE_BSRR GPIO_BSRR(GPIOE) +#define GPIOF_BSRR GPIO_BSRR(GPIOF) + +/* Port configuration lock register (GPIOx_LCKR) */ +#define GPIO_LCKR(port) MMIO32((port) + 0x1c) +#define GPIOA_LCKR GPIO_LCKR(GPIOA) +#define GPIOB_LCKR GPIO_LCKR(GPIOB) +#define GPIOC_LCKR GPIO_LCKR(GPIOC) +#define GPIOD_LCKR GPIO_LCKR(GPIOD) +#define GPIOE_LCKR GPIO_LCKR(GPIOE) +#define GPIOF_LCKR GPIO_LCKR(GPIOF) + +/* Alternate function low register (GPIOx_AFRL) */ +#define GPIO_AFRL(port) MMIO32((port) + 0x20) +#define GPIOA_AFRL GPIO_AFRL(GPIOA) +#define GPIOB_AFRL GPIO_AFRL(GPIOB) +#define GPIOC_AFRL GPIO_AFRL(GPIOC) +#define GPIOD_AFRL GPIO_AFRL(GPIOD) +#define GPIOE_AFRL GPIO_AFRL(GPIOE) +#define GPIOF_AFRL GPIO_AFRL(GPIOF) + +/* Alternate function high register (GPIOx_AFRH) */ +#define GPIO_AFRH(port) MMIO32((port) + 0x24) +#define GPIOA_AFRH GPIO_AFRH(GPIOA) +#define GPIOB_AFRH GPIO_AFRH(GPIOB) +#define GPIOC_AFRH GPIO_AFRH(GPIOC) +#define GPIOD_AFRH GPIO_AFRH(GPIOD) +#define GPIOE_AFRH GPIO_AFRH(GPIOE) +#define GPIOF_AFRH GPIO_AFRH(GPIOF) + +/* --- GPIOx_MODER values -------------------------------------------------- */ + +#define GPIO_MODE(n, mode) ((mode) << (2 * (n))) +#define GPIO_MODE_MASK(n) (0x3 << (2 * (n))) +/** @defgroup gpio_mode GPIO Pin Direction and Analog/Digital Mode +@ingroup gpio_defines +@{*/ +#define GPIO_MODE_INPUT 0x0 +#define GPIO_MODE_OUTPUT 0x1 +#define GPIO_MODE_AF 0x2 +#define GPIO_MODE_ANALOG 0x3 +/**@}*/ + +/* --- GPIOx_OTYPER values ------------------------------------------------- */ + +/** @defgroup gpio_output_type GPIO Output Pin Driver Type +@ingroup gpio_defines +@list Push Pull +@list Open Drain +@{*/ +#define GPIO_OTYPE_PP 0x0 +#define GPIO_OTYPE_OD 0x1 +/**@}*/ + +/* --- GPIOx_OSPEEDR values ------------------------------------------------ */ + +#define GPIO_OSPEED(n, speed) ((speed) << (2 * (n))) +#define GPIO_OSPEED_MASK(n) (0x3 << (2 * (n))) +/** @defgroup gpio_speed GPIO Output Pin Speed +@ingroup gpio_defines +@{*/ +#define GPIO_OSPEED_2MHZ 0x0 +#define GPIO_OSPEED_25MHZ 0x1 +#define GPIO_OSPEED_50MHZ 0x2 +#define GPIO_OSPEED_100MHZ 0x3 +/**@}*/ + +/* --- GPIOx_PUPDR values -------------------------------------------------- */ + +#define GPIO_PUPD(n, pupd) ((pupd) << (2 * (n))) +#define GPIO_PUPD_MASK(n) (0x3 << (2 * (n))) +/** @defgroup gpio_pup GPIO Output Pin Pullup +@ingroup gpio_defines +@{*/ +#define GPIO_PUPD_NONE 0x0 +#define GPIO_PUPD_PULLUP 0x1 +#define GPIO_PUPD_PULLDOWN 0x2 +/**@}*/ + +/* --- GPIOx_IDR values ---------------------------------------------------- */ + +/* GPIOx_IDR[15:0]: IDRy[15:0]: Port input data (y = 0..15) */ + +/* --- GPIOx_ODR values ---------------------------------------------------- */ + +/* GPIOx_ODR[15:0]: ODRy[15:0]: Port output data (y = 0..15) */ + +/* --- GPIOx_BSRR values --------------------------------------------------- */ + +/* GPIOx_BSRR[31:16]: BRy: Port x reset bit y (y = 0..15) */ +/* GPIOx_BSRR[15:0]: BSy: Port x set bit y (y = 0..15) */ + +/* --- GPIOx_LCKR values --------------------------------------------------- */ + +#define GPIO_LCKK (1 << 16) +/* GPIOx_LCKR[15:0]: LCKy: Port x lock bit y (y = 0..15) */ + +/* --- GPIOx_AFRL/H values ------------------------------------------------- */ + +/* Note: AFRL is used for bits 0..7, AFRH is used for 8..15 */ +/* See datasheet table 6 (pg. 48) for alternate function mappings. */ + +#define GPIO_AFR(n, af) ((af) << ((n) * 4)) +#define GPIO_AFR_MASK(n) (0xf << ((n) * 4)) +/** @defgroup gpio_af_num Alternate Function Pin Selection +@ingroup gpio_defines +@{*/ +#define GPIO_AF0 0x0 +#define GPIO_AF1 0x1 +#define GPIO_AF2 0x2 +#define GPIO_AF3 0x3 +#define GPIO_AF4 0x4 +#define GPIO_AF5 0x5 +#define GPIO_AF6 0x6 +#define GPIO_AF7 0x7 +#define GPIO_AF8 0x8 +#define GPIO_AF9 0x9 +#define GPIO_AF10 0xa +#define GPIO_AF11 0xb +#define GPIO_AF12 0xc +#define GPIO_AF13 0xd +#define GPIO_AF14 0xe +#define GPIO_AF15 0xf +/**@}*/ + +/* Note: EXTI source selection is now in the SYSCFG peripheral. */ + +/* --- Function prototypes ------------------------------------------------- */ + + +/* + * Note: The F2 and F4 series have a completely new GPIO peripheral with + * different configuration options. Here we implement a different API partly to + * more closely match the peripheral capabilities and also to deliberately + * break compatibility with old F1 code so there is no confusion with similar + * sounding functions that have very different functionality. + */ + +void gpio_mode_setup(uint32_t gpioport, uint8_t mode, uint8_t pull_up_down, + uint16_t gpios); +void gpio_set_output_options(uint32_t gpioport, uint8_t otype, uint8_t speed, + uint16_t gpios); +void gpio_set_af(uint32_t gpioport, uint8_t alt_func_num, uint16_t gpios); + +/**@}*/ +#endif +/** @cond */ +#else +#warning "gpio_common_f234.h should not be included explicitly, only via gpio.h" +#endif +/** @endcond */ + diff --git a/FourQ_ARM_side_channel/libopencm3/include/memorymap.h b/FourQ_ARM_side_channel/libopencm3/include/memorymap.h new file mode 100644 index 0000000..55cec86 --- /dev/null +++ b/FourQ_ARM_side_channel/libopencm3/include/memorymap.h @@ -0,0 +1,85 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef LIBOPENCM3_CM3_MEMORYMAP_H +#define LIBOPENCM3_CM3_MEMORYMAP_H + +/* --- ARM Cortex-M0, M3 and M4 specific definitions ----------------------- */ + +/* Private peripheral bus - Internal */ +#define PPBI_BASE (0xE0000000U) + +/* Those defined only on ARMv7 and above */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +/* ITM: Instrumentation Trace Macrocell */ +#define ITM_BASE (PPBI_BASE + 0x0000) + +/* DWT: Data Watchpoint and Trace unit */ +#define DWT_BASE (PPBI_BASE + 0x1000) + +/* FPB: Flash Patch and Breakpoint unit */ +#define FPB_BASE (PPBI_BASE + 0x2000) +#endif + +/* PPBI_BASE + 0x3000 (0xE000 3000 - 0xE000 DFFF): Reserved */ + +#define SCS_BASE (PPBI_BASE + 0xE000) + +/* PPBI_BASE + 0xF000 (0xE000 F000 - 0xE003 FFFF): Reserved */ + +/* Those defined only on ARMv7 and above */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +#define TPIU_BASE (PPBI_BASE + 0x40000) +#endif + +/* --- SCS: System Control Space --- */ + +/* Those defined only on ARMv7 and above */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +/* ITR: Interrupt Type Register */ +#define ITR_BASE (SCS_BASE + 0x0000) +#endif + +/* SYS_TICK: System Timer */ +#define SYS_TICK_BASE (SCS_BASE + 0x0010) + +/* NVIC: Nested Vector Interrupt Controller */ +#define NVIC_BASE (SCS_BASE + 0x0100) + +/* SCB: System Control Block */ +#define SCB_BASE (SCS_BASE + 0x0D00) + +/* MPU: Memory protection unit */ +#define MPU_BASE (SCS_BASE + 0x0D90) + +/* Those defined only on CM0*/ +#if defined(__ARM_ARCH_6M__) +/* DEBUG: Debug control and configuration */ +#define DEBUG_BASE (SCS_BASE + 0x0DF0) +#endif + +/* Those defined only on ARMv7 and above */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +/* STE: Software Trigger Interrupt Register */ +#define STIR_BASE (SCS_BASE + 0x0F00) +/* ID: ID space */ +#define ID_BASE (SCS_BASE + 0x0FD0) +#endif + +#endif diff --git a/FourQ_ARM_side_channel/libopencm3/include/memorymap_f4.h b/FourQ_ARM_side_channel/libopencm3/include/memorymap_f4.h new file mode 100644 index 0000000..c469fd5 --- /dev/null +++ b/FourQ_ARM_side_channel/libopencm3/include/memorymap_f4.h @@ -0,0 +1,155 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Fergus Noble + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef LIBOPENCM3_MEMORYMAP_H +#define LIBOPENCM3_MEMORYMAP_H + +#include "memorymap.h" + +/* --- STM32F4 specific peripheral definitions ----------------------------- */ + +/* Memory map for all busses */ +#define PERIPH_BASE (0x40000000U) +#define PERIPH_BASE_APB1 (PERIPH_BASE + 0x00000) +#define PERIPH_BASE_APB2 (PERIPH_BASE + 0x10000) +#define PERIPH_BASE_AHB1 (PERIPH_BASE + 0x20000) +#define PERIPH_BASE_AHB2 0x50000000U +#define PERIPH_BASE_AHB3 0x60000000U + +/* Register boundary addresses */ + +/* APB1 */ +#define TIM2_BASE (PERIPH_BASE_APB1 + 0x0000) +#define TIM3_BASE (PERIPH_BASE_APB1 + 0x0400) +#define TIM4_BASE (PERIPH_BASE_APB1 + 0x0800) +#define TIM5_BASE (PERIPH_BASE_APB1 + 0x0c00) +#define TIM6_BASE (PERIPH_BASE_APB1 + 0x1000) +#define TIM7_BASE (PERIPH_BASE_APB1 + 0x1400) +#define TIM12_BASE (PERIPH_BASE_APB1 + 0x1800) +#define TIM13_BASE (PERIPH_BASE_APB1 + 0x1c00) +#define TIM14_BASE (PERIPH_BASE_APB1 + 0x2000) +/* PERIPH_BASE_APB1 + 0x2400 (0x4000 2400 - 0x4000 27FF): Reserved */ +#define RTC_BASE (PERIPH_BASE_APB1 + 0x2800) +#define WWDG_BASE (PERIPH_BASE_APB1 + 0x2c00) +#define IWDG_BASE (PERIPH_BASE_APB1 + 0x3000) +#define I2S2_EXT_BASE (PERIPH_BASE_APB1 + 0x3400) +#define SPI2_BASE (PERIPH_BASE_APB1 + 0x3800) +#define SPI3_BASE (PERIPH_BASE_APB1 + 0x3c00) +#define I2S3_EXT_BASE (PERIPH_BASE_APB1 + 0x4000) +#define USART2_BASE (PERIPH_BASE_APB1 + 0x4400) +#define USART3_BASE (PERIPH_BASE_APB1 + 0x4800) +#define UART4_BASE (PERIPH_BASE_APB1 + 0x4c00) +#define UART5_BASE (PERIPH_BASE_APB1 + 0x5000) +#define I2C1_BASE (PERIPH_BASE_APB1 + 0x5400) +#define I2C2_BASE (PERIPH_BASE_APB1 + 0x5800) +#define I2C3_BASE (PERIPH_BASE_APB1 + 0x5C00) +/* PERIPH_BASE_APB1 + 0x6000 (0x4000 6000 - 0x4000 63FF): Reserved */ +#define BX_CAN1_BASE (PERIPH_BASE_APB1 + 0x6400) +#define BX_CAN2_BASE (PERIPH_BASE_APB1 + 0x6800) +/* PERIPH_BASE_APB1 + 0x6C00 (0x4000 6C00 - 0x4000 6FFF): Reserved */ +#define POWER_CONTROL_BASE (PERIPH_BASE_APB1 + 0x7000) +#define DAC_BASE (PERIPH_BASE_APB1 + 0x7400) +#define UART7_BASE (PERIPH_BASE_APB1 + 0x7800) +#define UART8_BASE (PERIPH_BASE_APB1 + 0x7c00) +/* PERIPH_BASE_APB1 + 0x7800 (0x4000 8000 - 0x4000 FFFF): Reserved */ + +/* APB2 */ +#define TIM1_BASE (PERIPH_BASE_APB2 + 0x0000) +#define TIM8_BASE (PERIPH_BASE_APB2 + 0x0400) +/* PERIPH_BASE_APB2 + 0x0800 (0x4001 0800 - 0x4001 0FFF): Reserved */ +#define USART1_BASE (PERIPH_BASE_APB2 + 0x1000) +#define USART6_BASE (PERIPH_BASE_APB2 + 0x1400) +/* PERIPH_BASE_APB2 + 0x1800 (0x4001 1800 - 0x4001 1FFF): Reserved */ +#define ADC1_BASE (PERIPH_BASE_APB2 + 0x2000) +#define ADC2_BASE (PERIPH_BASE_APB2 + 0x2100) +#define ADC3_BASE (PERIPH_BASE_APB2 + 0x2200) +#define ADC_COMMON_BASE (PERIPH_BASE_APB2 + 0x2300) +/* PERIPH_BASE_APB2 + 0x2400 (0x4001 2400 - 0x4001 27FF): Reserved */ +#define SDIO_BASE (PERIPH_BASE_APB2 + 0x2C00) +/* PERIPH_BASE_APB2 + 0x2C00 (0x4001 2C00 - 0x4001 2FFF): Reserved */ +#define SPI1_BASE (PERIPH_BASE_APB2 + 0x3000) +#define SPI4_BASE (PERIPH_BASE_APB2 + 0x3400) +/* PERIPH_BASE_APB2 + 0x3500 (0x4001 3500 - 0x4001 37FF): Reserved */ +#define SYSCFG_BASE (PERIPH_BASE_APB2 + 0x3800) +#define EXTI_BASE (PERIPH_BASE_APB2 + 0x3C00) +#define TIM9_BASE (PERIPH_BASE_APB2 + 0x4000) +#define TIM10_BASE (PERIPH_BASE_APB2 + 0x4400) +#define TIM11_BASE (PERIPH_BASE_APB2 + 0x4800) +/* PERIPH_BASE_APB2 + 0x4C00 (0x4001 4C00 - 0x4001 4FFF): Reserved */ +#define SPI5_BASE (PERIPH_BASE_APB2 + 0x5000) +#define SPI6_BASE (PERIPH_BASE_APB2 + 0x5400) +#define SAI1_BASE (PERIPH_BASE_APB2 + 0x5800) +#define LTDC_BASE (PERIPH_BASE_APB2 + 0x6800) +/* PERIPH_BASE_APB2 + 0x6C00 (0x4001 6C00 - 0x4001 FFFF): Reserved */ + +/* AHB1 */ +#define GPIO_PORT_A_BASE (PERIPH_BASE_AHB1 + 0x0000) +#define GPIO_PORT_B_BASE (PERIPH_BASE_AHB1 + 0x0400) +#define GPIO_PORT_C_BASE (PERIPH_BASE_AHB1 + 0x0800) +#define GPIO_PORT_D_BASE (PERIPH_BASE_AHB1 + 0x0C00) +#define GPIO_PORT_E_BASE (PERIPH_BASE_AHB1 + 0x1000) +#define GPIO_PORT_F_BASE (PERIPH_BASE_AHB1 + 0x1400) +#define GPIO_PORT_G_BASE (PERIPH_BASE_AHB1 + 0x1800) +#define GPIO_PORT_H_BASE (PERIPH_BASE_AHB1 + 0x1C00) +#define GPIO_PORT_I_BASE (PERIPH_BASE_AHB1 + 0x2000) +/* PERIPH_BASE_AHB1 + 0x2400 (0x4002 2400 - 0x4002 2FFF): Reserved */ +#define CRC_BASE (PERIPH_BASE_AHB1 + 0x3000) +/* PERIPH_BASE_AHB1 + 0x3400 (0x4002 3400 - 0x4002 37FF): Reserved */ +#define RCC_BASE (PERIPH_BASE_AHB1 + 0x3800) +#define FLASH_MEM_INTERFACE_BASE (PERIPH_BASE_AHB1 + 0x3C00) +#define BKPSRAM_BASE (PERIPH_BASE_AHB1 + 0x4000) +/* PERIPH_BASE_AHB1 + 0x5000 (0x4002 5000 - 0x4002 5FFF): Reserved */ +#define DMA1_BASE (PERIPH_BASE_AHB1 + 0x6000) +#define DMA2_BASE (PERIPH_BASE_AHB1 + 0x6400) +/* PERIPH_BASE_AHB1 + 0x6800 (0x4002 6800 - 0x4002 7FFF): Reserved */ +#define ETHERNET_BASE (PERIPH_BASE_AHB1 + 0x8000) +/* PERIPH_BASE_AHB1 + 0x9400 (0x4002 9400 - 0x4003 FFFF): Reserved */ +#define USB_OTG_HS_BASE (PERIPH_BASE_AHB1 + 0x20000) +/* PERIPH_BASE_AHB1 + 0x60000 (0x4008 0000 - 0x4FFF FFFF): Reserved */ + +/* AHB2 */ +#define USB_OTG_FS_BASE (PERIPH_BASE_AHB2 + 0x00000) +/* PERIPH_BASE_AHB2 + 0x40000 (0x5004 0000 - 0x5004 FFFF): Reserved */ +#define DCMI_BASE (PERIPH_BASE_AHB2 + 0x50000) +/* PERIPH_BASE_AHB2 + 0x50400 (0x5005 0400 - 0x5005 FFFF): Reserved */ +#define CRYP_BASE (PERIPH_BASE_AHB2 + 0x60000) +#define HASH_BASE (PERIPH_BASE_AHB2 + 0x60400) +/* PERIPH_BASE_AHB2 + 0x60C00 (0x5006 0C00 - 0x5006 07FF): Reserved */ +#define RNG_BASE (PERIPH_BASE_AHB2 + 0x60800) +/* PERIPH_BASE_AHB2 + 0x61000 (0x5006 1000 - 0x5FFF FFFF): Reserved */ + +/* AHB3 */ +#define FSMC_BASE (PERIPH_BASE_AHB3 + 0x40000000U) + +/* PPIB */ +#define DBGMCU_BASE (PPBI_BASE + 0x00042000) + +/* Device Electronic Signature */ +#define DESIG_FLASH_SIZE_BASE (0x1FFF7A22U) +#define DESIG_UNIQUE_ID_BASE (0x1FFF7A10U) +#define DESIG_UNIQUE_ID0 MMIO32(DESIG_UNIQUE_ID_BASE) +#define DESIG_UNIQUE_ID1 MMIO32(DESIG_UNIQUE_ID_BASE + 4) +#define DESIG_UNIQUE_ID2 MMIO32(DESIG_UNIQUE_ID_BASE + 8) + +/* ST provided factory calibration values @ 3.3V */ +#define ST_VREFINT_CAL MMIO16(0x1FFF7A2A) +#define ST_TSENSE_CAL1_30C MMIO16(0x1FFF7A2C) +#define ST_TSENSE_CAL2_110 MMIO16(0x1FFF7A2E) + +#endif diff --git a/FourQ_ARM_side_channel/libopencm3/include/nvic.h b/FourQ_ARM_side_channel/libopencm3/include/nvic.h new file mode 100644 index 0000000..7343ed6 --- /dev/null +++ b/FourQ_ARM_side_channel/libopencm3/include/nvic.h @@ -0,0 +1,213 @@ +/* This file is part of the libopencm3 project. + * + * It was generated by the irq2nvic_h script. + */ + +#ifndef LIBOPENCM3_STM32_F4_NVIC_H +#define LIBOPENCM3_STM32_F4_NVIC_H + +#include "nvic_cm3.h" + +/** @defgroup CM3_nvic_defines_STM32F4 User interrupts for STM32 F4 series + @ingroup CM3_nvic_defines + + @{*/ + +#define NVIC_NVIC_WWDG_IRQ 0 +#define NVIC_PVD_IRQ 1 +#define NVIC_TAMP_STAMP_IRQ 2 +#define NVIC_RTC_WKUP_IRQ 3 +#define NVIC_FLASH_IRQ 4 +#define NVIC_RCC_IRQ 5 +#define NVIC_EXTI0_IRQ 6 +#define NVIC_EXTI1_IRQ 7 +#define NVIC_EXTI2_IRQ 8 +#define NVIC_EXTI3_IRQ 9 +#define NVIC_EXTI4_IRQ 10 +#define NVIC_DMA1_STREAM0_IRQ 11 +#define NVIC_DMA1_STREAM1_IRQ 12 +#define NVIC_DMA1_STREAM2_IRQ 13 +#define NVIC_DMA1_STREAM3_IRQ 14 +#define NVIC_DMA1_STREAM4_IRQ 15 +#define NVIC_DMA1_STREAM5_IRQ 16 +#define NVIC_DMA1_STREAM6_IRQ 17 +#define NVIC_ADC_IRQ 18 +#define NVIC_CAN1_TX_IRQ 19 +#define NVIC_CAN1_RX0_IRQ 20 +#define NVIC_CAN1_RX1_IRQ 21 +#define NVIC_CAN1_SCE_IRQ 22 +#define NVIC_EXTI9_5_IRQ 23 +#define NVIC_TIM1_BRK_TIM9_IRQ 24 +#define NVIC_TIM1_UP_TIM10_IRQ 25 +#define NVIC_TIM1_TRG_COM_TIM11_IRQ 26 +#define NVIC_TIM1_CC_IRQ 27 +#define NVIC_TIM2_IRQ 28 +#define NVIC_TIM3_IRQ 29 +#define NVIC_TIM4_IRQ 30 +#define NVIC_I2C1_EV_IRQ 31 +#define NVIC_I2C1_ER_IRQ 32 +#define NVIC_I2C2_EV_IRQ 33 +#define NVIC_I2C2_ER_IRQ 34 +#define NVIC_SPI1_IRQ 35 +#define NVIC_SPI2_IRQ 36 +#define NVIC_USART1_IRQ 37 +#define NVIC_USART2_IRQ 38 +#define NVIC_USART3_IRQ 39 +#define NVIC_EXTI15_10_IRQ 40 +#define NVIC_RTC_ALARM_IRQ 41 +#define NVIC_USB_FS_WKUP_IRQ 42 +#define NVIC_TIM8_BRK_TIM12_IRQ 43 +#define NVIC_TIM8_UP_TIM13_IRQ 44 +#define NVIC_TIM8_TRG_COM_TIM14_IRQ 45 +#define NVIC_TIM8_CC_IRQ 46 +#define NVIC_DMA1_STREAM7_IRQ 47 +#define NVIC_FSMC_IRQ 48 +#define NVIC_SDIO_IRQ 49 +#define NVIC_TIM5_IRQ 50 +#define NVIC_SPI3_IRQ 51 +#define NVIC_UART4_IRQ 52 +#define NVIC_UART5_IRQ 53 +#define NVIC_TIM6_DAC_IRQ 54 +#define NVIC_TIM7_IRQ 55 +#define NVIC_DMA2_STREAM0_IRQ 56 +#define NVIC_DMA2_STREAM1_IRQ 57 +#define NVIC_DMA2_STREAM2_IRQ 58 +#define NVIC_DMA2_STREAM3_IRQ 59 +#define NVIC_DMA2_STREAM4_IRQ 60 +#define NVIC_ETH_IRQ 61 +#define NVIC_ETH_WKUP_IRQ 62 +#define NVIC_CAN2_TX_IRQ 63 +#define NVIC_CAN2_RX0_IRQ 64 +#define NVIC_CAN2_RX1_IRQ 65 +#define NVIC_CAN2_SCE_IRQ 66 +#define NVIC_OTG_FS_IRQ 67 +#define NVIC_DMA2_STREAM5_IRQ 68 +#define NVIC_DMA2_STREAM6_IRQ 69 +#define NVIC_DMA2_STREAM7_IRQ 70 +#define NVIC_USART6_IRQ 71 +#define NVIC_I2C3_EV_IRQ 72 +#define NVIC_I2C3_ER_IRQ 73 +#define NVIC_OTG_HS_EP1_OUT_IRQ 74 +#define NVIC_OTG_HS_EP1_IN_IRQ 75 +#define NVIC_OTG_HS_WKUP_IRQ 76 +#define NVIC_OTG_HS_IRQ 77 +#define NVIC_DCMI_IRQ 78 +#define NVIC_CRYP_IRQ 79 +#define NVIC_HASH_RNG_IRQ 80 +#define NVIC_FPU_IRQ 81 +#define NVIC_UART7_IRQ 82 +#define NVIC_UART8_IRQ 83 +#define NVIC_SPI4_IRQ 84 +#define NVIC_SPI5_IRQ 85 +#define NVIC_SPI6_IRQ 86 +#define NVIC_SAI1_IRQ 87 +#define NVIC_LCD_TFT_IRQ 88 +#define NVIC_LCD_TFT_ERR_IRQ 89 +#define NVIC_DMA2D_IRQ 90 + +#define NVIC_IRQ_COUNT 91 + +/**@}*/ + +/** @defgroup CM3_nvic_isrprototypes_STM32F4 User interrupt service routines (ISR) prototypes for STM32 F4 series + @ingroup CM3_nvic_isrprototypes + + @{*/ + + +void WEAK nvic_wwdg_isr(void); +void WEAK pvd_isr(void); +void WEAK tamp_stamp_isr(void); +void WEAK rtc_wkup_isr(void); +void WEAK flash_isr(void); +void WEAK rcc_isr(void); +void WEAK exti0_isr(void); +void WEAK exti1_isr(void); +void WEAK exti2_isr(void); +void WEAK exti3_isr(void); +void WEAK exti4_isr(void); +void WEAK dma1_stream0_isr(void); +void WEAK dma1_stream1_isr(void); +void WEAK dma1_stream2_isr(void); +void WEAK dma1_stream3_isr(void); +void WEAK dma1_stream4_isr(void); +void WEAK dma1_stream5_isr(void); +void WEAK dma1_stream6_isr(void); +void WEAK adc_isr(void); +void WEAK can1_tx_isr(void); +void WEAK can1_rx0_isr(void); +void WEAK can1_rx1_isr(void); +void WEAK can1_sce_isr(void); +void WEAK exti9_5_isr(void); +void WEAK tim1_brk_tim9_isr(void); +void WEAK tim1_up_tim10_isr(void); +void WEAK tim1_trg_com_tim11_isr(void); +void WEAK tim1_cc_isr(void); +void WEAK tim2_isr(void); +void WEAK tim3_isr(void); +void WEAK tim4_isr(void); +void WEAK i2c1_ev_isr(void); +void WEAK i2c1_er_isr(void); +void WEAK i2c2_ev_isr(void); +void WEAK i2c2_er_isr(void); +void WEAK spi1_isr(void); +void WEAK spi2_isr(void); +void WEAK usart1_isr(void); +void WEAK usart2_isr(void); +void WEAK usart3_isr(void); +void WEAK exti15_10_isr(void); +void WEAK rtc_alarm_isr(void); +void WEAK usb_fs_wkup_isr(void); +void WEAK tim8_brk_tim12_isr(void); +void WEAK tim8_up_tim13_isr(void); +void WEAK tim8_trg_com_tim14_isr(void); +void WEAK tim8_cc_isr(void); +void WEAK dma1_stream7_isr(void); +void WEAK fsmc_isr(void); +void WEAK sdio_isr(void); +void WEAK tim5_isr(void); +void WEAK spi3_isr(void); +void WEAK uart4_isr(void); +void WEAK uart5_isr(void); +void WEAK tim6_dac_isr(void); +void WEAK tim7_isr(void); +void WEAK dma2_stream0_isr(void); +void WEAK dma2_stream1_isr(void); +void WEAK dma2_stream2_isr(void); +void WEAK dma2_stream3_isr(void); +void WEAK dma2_stream4_isr(void); +void WEAK eth_isr(void); +void WEAK eth_wkup_isr(void); +void WEAK can2_tx_isr(void); +void WEAK can2_rx0_isr(void); +void WEAK can2_rx1_isr(void); +void WEAK can2_sce_isr(void); +void WEAK otg_fs_isr(void); +void WEAK dma2_stream5_isr(void); +void WEAK dma2_stream6_isr(void); +void WEAK dma2_stream7_isr(void); +void WEAK usart6_isr(void); +void WEAK i2c3_ev_isr(void); +void WEAK i2c3_er_isr(void); +void WEAK otg_hs_ep1_out_isr(void); +void WEAK otg_hs_ep1_in_isr(void); +void WEAK otg_hs_wkup_isr(void); +void WEAK otg_hs_isr(void); +void WEAK dcmi_isr(void); +void WEAK cryp_isr(void); +void WEAK hash_rng_isr(void); +void WEAK fpu_isr(void); +void WEAK uart7_isr(void); +void WEAK uart8_isr(void); +void WEAK spi4_isr(void); +void WEAK spi5_isr(void); +void WEAK spi6_isr(void); +void WEAK sai1_isr(void); +void WEAK lcd_tft_isr(void); +void WEAK lcd_tft_err_isr(void); +void WEAK dma2d_isr(void); + + +/**@}*/ + +#endif /* LIBOPENCM3_STM32_F4_NVIC_H */ diff --git a/FourQ_ARM_side_channel/libopencm3/include/nvic_cm3.h b/FourQ_ARM_side_channel/libopencm3/include/nvic_cm3.h new file mode 100644 index 0000000..f4b352e --- /dev/null +++ b/FourQ_ARM_side_channel/libopencm3/include/nvic_cm3.h @@ -0,0 +1,172 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Piotr Esden-Tempski + * Copyright (C) 2012 Michael Ossmann + * Copyright (C) 2012 Benjamin Vernoux + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +/** @defgroup CM3_nvic_defines NVIC Defines + * + * @brief libopencm3 Cortex Nested Vectored Interrupt Controller + * + * @ingroup CM3_defines + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2010 Piotr Esden-Tempski + * + * @date 18 August 2012 + * + * LGPL License Terms @ref lgpl_license + */ +/**@{*/ + +#ifndef LIBOPENCM3_NVIC_H +#define LIBOPENCM3_NVIC_H + +#include +#include + +/* --- NVIC Registers ------------------------------------------------------ */ + +/* ISER: Interrupt Set Enable Registers */ +/* Note: 8 32bit Registers */ +/* Note: Single register on CM0 */ +#define NVIC_ISER(iser_id) MMIO32(NVIC_BASE + 0x00 + \ + ((iser_id) * 4)) + +/* NVIC_BASE + 0x020 (0xE000 E120 - 0xE000 E17F): Reserved */ + +/* ICER: Interrupt Clear Enable Registers */ +/* Note: 8 32bit Registers */ +/* Note: Single register on CM0 */ +#define NVIC_ICER(icer_id) MMIO32(NVIC_BASE + 0x80 + \ + ((icer_id) * 4)) + +/* NVIC_BASE + 0x0A0 (0xE000 E1A0 - 0xE000 E1FF): Reserved */ + +/* ISPR: Interrupt Set Pending Registers */ +/* Note: 8 32bit Registers */ +/* Note: Single register on CM0 */ +#define NVIC_ISPR(ispr_id) MMIO32(NVIC_BASE + 0x100 + \ + ((ispr_id) * 4)) + +/* NVIC_BASE + 0x120 (0xE000 E220 - 0xE000 E27F): Reserved */ + +/* ICPR: Interrupt Clear Pending Registers */ +/* Note: 8 32bit Registers */ +/* Note: Single register on CM0 */ +#define NVIC_ICPR(icpr_id) MMIO32(NVIC_BASE + 0x180 + \ + ((icpr_id) * 4)) + +/* NVIC_BASE + 0x1A0 (0xE000 E2A0 - 0xE00 E2FF): Reserved */ + +/* Those defined only on ARMv7 and above */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +/* IABR: Interrupt Active Bit Register */ +/* Note: 8 32bit Registers */ +#define NVIC_IABR(iabr_id) MMIO32(NVIC_BASE + 0x200 + \ + ((iabr_id) * 4)) +#endif + +/* NVIC_BASE + 0x220 (0xE000 E320 - 0xE000 E3FF): Reserved */ + +/* IPR: Interrupt Priority Registers */ +/* Note: 240 8bit Registers */ +/* Note: 32 8bit Registers on CM0 */ +#define NVIC_IPR(ipr_id) MMIO8(NVIC_BASE + 0x300 + \ + (ipr_id)) + +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +/* STIR: Software Trigger Interrupt Register */ +#define NVIC_STIR MMIO32(STIR_BASE) +#endif + +/* --- IRQ channel numbers-------------------------------------------------- */ + +/* Cortex M0, M3 and M4 System Interrupts */ +/** @defgroup nvic_sysint Cortex M0/M3/M4 System Interrupts +@ingroup CM3_nvic_defines + +IRQ numbers -3 and -6 to -9 are reserved +@{*/ +#define NVIC_NMI_IRQ -14 +#define NVIC_HARD_FAULT_IRQ -13 + +/* Those defined only on ARMv7 and above */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +#define NVIC_MEM_MANAGE_IRQ -12 +#define NVIC_BUS_FAULT_IRQ -11 +#define NVIC_USAGE_FAULT_IRQ -10 +#endif + +/* irq numbers -6 to -9 are reserved */ +#define NVIC_SV_CALL_IRQ -5 + +/* Those defined only on ARMv7 and above */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +#define DEBUG_MONITOR_IRQ -4 +#endif + +/* irq number -3 reserved */ +#define NVIC_PENDSV_IRQ -2 +#define NVIC_SYSTICK_IRQ -1 +/**@}*/ + +/* Note: User interrupts are family specific and are defined in a family + * specific header file in the corresponding subfolder. + */ + +#define WEAK __attribute__((weak)) + +#include "nvic.h" + +/* --- NVIC functions ------------------------------------------------------ */ + + +void nvic_enable_irq(uint8_t irqn); +void nvic_disable_irq(uint8_t irqn); +uint8_t nvic_get_pending_irq(uint8_t irqn); +void nvic_set_pending_irq(uint8_t irqn); +void nvic_clear_pending_irq(uint8_t irqn); +uint8_t nvic_get_irq_enabled(uint8_t irqn); +void nvic_set_priority(uint8_t irqn, uint8_t priority); + +/* Those defined only on ARMv7 and above */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +uint8_t nvic_get_active_irq(uint8_t irqn); +void nvic_generate_software_interrupt(uint16_t irqn); +#endif + +void WEAK reset_handler(void); +void WEAK nmi_handler(void); +void WEAK hard_fault_handler(void); +void WEAK sv_call_handler(void); +void WEAK pend_sv_handler(void); +void WEAK sys_tick_handler(void); + +/* Those defined only on ARMv7 and above */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +void WEAK mem_manage_handler(void); +void WEAK bus_fault_handler(void); +void WEAK usage_fault_handler(void); +void WEAK debug_monitor_handler(void); +#endif + + +/**@}*/ + +#endif diff --git a/FourQ_ARM_side_channel/libopencm3/include/rcc.h b/FourQ_ARM_side_channel/libopencm3/include/rcc.h new file mode 100644 index 0000000..4e72373 --- /dev/null +++ b/FourQ_ARM_side_channel/libopencm3/include/rcc.h @@ -0,0 +1,872 @@ +/** @defgroup rcc_defines RCC Defines + * + * @brief Defined Constants and Types for the STM32F4xx Reset and Clock + * Control + * + * @ingroup STM32F4xx_defines + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2009 + * Federico Ruiz-Ugalde \ + * @author @htmlonly © @endhtmlonly 2009 + * Uwe Hermann + * @author @htmlonly © @endhtmlonly 2011 + * Fergus Noble + * @author @htmlonly © @endhtmlonly 2011 + * Stephen Caudle + * + * @date 18 August 2012 + * + * LGPL License Terms @ref lgpl_license + * */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2009 Federico Ruiz-Ugalde + * Copyright (C) 2011 Fergus Noble + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef LIBOPENCM3_RCC_H +#define LIBOPENCM3_RCC_H +#include "memorymap_f4.h" +#include "common.h" +#include + +/* --- RCC registers ------------------------------------------------------- */ + +#define RCC_CR MMIO32(RCC_BASE + 0x00) +#define RCC_PLLCFGR MMIO32(RCC_BASE + 0x04) +#define RCC_CFGR MMIO32(RCC_BASE + 0x08) +#define RCC_CIR MMIO32(RCC_BASE + 0x0c) +#define RCC_AHB1RSTR MMIO32(RCC_BASE + 0x10) +#define RCC_AHB2RSTR MMIO32(RCC_BASE + 0x14) +#define RCC_AHB3RSTR MMIO32(RCC_BASE + 0x18) +/* RCC_BASE + 0x1c Reserved */ +#define RCC_APB1RSTR MMIO32(RCC_BASE + 0x20) +#define RCC_APB2RSTR MMIO32(RCC_BASE + 0x24) +/* RCC_BASE + 0x28 Reserved */ +/* RCC_BASE + 0x2c Reserved */ +#define RCC_AHB1ENR MMIO32(RCC_BASE + 0x30) +#define RCC_AHB2ENR MMIO32(RCC_BASE + 0x34) +#define RCC_AHB3ENR MMIO32(RCC_BASE + 0x38) +/* RCC_BASE + 0x3c Reserved */ +#define RCC_APB1ENR MMIO32(RCC_BASE + 0x40) +#define RCC_APB2ENR MMIO32(RCC_BASE + 0x44) +/* RCC_BASE + 0x48 Reserved */ +/* RCC_BASE + 0x4c Reserved */ +#define RCC_AHB1LPENR MMIO32(RCC_BASE + 0x50) +#define RCC_AHB2LPENR MMIO32(RCC_BASE + 0x54) +#define RCC_AHB3LPENR MMIO32(RCC_BASE + 0x58) +/* RCC_BASE + 0x5c Reserved */ +#define RCC_APB1LPENR MMIO32(RCC_BASE + 0x60) +#define RCC_APB2LPENR MMIO32(RCC_BASE + 0x64) +/* RCC_BASE + 0x68 Reserved */ +/* RCC_BASE + 0x6c Reserved */ +#define RCC_BDCR MMIO32(RCC_BASE + 0x70) +#define RCC_CSR MMIO32(RCC_BASE + 0x74) +/* RCC_BASE + 0x78 Reserved */ +/* RCC_BASE + 0x7c Reserved */ +#define RCC_SSCGR MMIO32(RCC_BASE + 0x80) +#define RCC_PLLI2SCFGR MMIO32(RCC_BASE + 0x84) +#define RCC_PLLSAICFGR MMIO32(RCC_BASE + 0x88) +#define RCC_DCKCFGR MMIO32(RCC_BASE + 0x8C) + + +/* --- RCC_CR values ------------------------------------------------------- */ + +#define RCC_CR_PLLSAIRDY (1 << 29) +#define RCC_CR_PLLSAION (1 << 28) +#define RCC_CR_PLLI2SRDY (1 << 27) +#define RCC_CR_PLLI2SON (1 << 26) +#define RCC_CR_PLLRDY (1 << 25) +#define RCC_CR_PLLON (1 << 24) +#define RCC_CR_CSSON (1 << 19) +#define RCC_CR_HSEBYP (1 << 18) +#define RCC_CR_HSERDY (1 << 17) +#define RCC_CR_HSEON (1 << 16) +/* HSICAL: [15:8] */ +/* HSITRIM: [7:3] */ +#define RCC_CR_HSIRDY (1 << 1) +#define RCC_CR_HSION (1 << 0) + +/* --- RCC_PLLCFGR values -------------------------------------------------- */ + +/* PLLQ: [27:24] */ +#define RCC_PLLCFGR_PLLQ_SHIFT 24 +#define RCC_PLLCFGR_PLLSRC (1 << 22) +/* PLLP: [17:16] */ +#define RCC_PLLCFGR_PLLP_SHIFT 16 +/* PLLN: [14:6] */ +#define RCC_PLLCFGR_PLLN_SHIFT 6 +/* PLLM: [5:0] */ +#define RCC_PLLCFGR_PLLM_SHIFT 0 + +/* --- RCC_CFGR values ----------------------------------------------------- */ + +/* MCO2: Microcontroller clock output 2 */ +#define RCC_CFGR_MCO2_SHIFT 30 +#define RCC_CFGR_MCO2_SYSCLK 0x0 +#define RCC_CFGR_MCO2_PLLI2S 0x1 +#define RCC_CFGR_MCO2_HSE 0x2 +#define RCC_CFGR_MCO2_PLL 0x3 + +/* MCO1/2PRE: MCO Prescalers */ +#define RCC_CFGR_MCO2PRE_SHIFT 27 +#define RCC_CFGR_MCO1PRE_SHIFT 24 +#define RCC_CFGR_MCOPRE_DIV_NONE 0x0 +#define RCC_CFGR_MCOPRE_DIV_2 0x4 +#define RCC_CFGR_MCOPRE_DIV_3 0x5 +#define RCC_CFGR_MCOPRE_DIV_4 0x6 +#define RCC_CFGR_MCOPRE_DIV_5 0x7 + +/* I2SSRC: I2S clock selection */ +#define RCC_CFGR_I2SSRC (1 << 23) + +/* MCO1: Microcontroller clock output 1 */ +#define RCC_CFGR_MCO1_SHIFT 21 +#define RCC_CFGR_MCO1_MASK 0x3 +#define RCC_CFGR_MCO1_HSI 0x0 +#define RCC_CFGR_MCO1_LSE 0x1 +#define RCC_CFGR_MCO1_HSE 0x2 +#define RCC_CFGR_MCO1_PLL 0x3 +#define RCC_CFGR_MCO_SHIFT RCC_CFGR_MCO1_SHIFT +#define RCC_CFGR_MCO_MASK RCC_CFGR_MCO1_MASK + +/* RTCPRE: HSE division factor for RTC clock */ +#define RCC_CFGR_RTCPRE_SHIFT 16 +#define RCC_CFGR_RTCPRE_MASK 0x1f + +/* PPRE1/2: APB high-speed prescalers */ +#define RCC_CFGR_PPRE2_SHIFT 13 +#define RCC_CFGR_PPRE2_MASK 0x7 +#define RCC_CFGR_PPRE1_SHIFT 10 +#define RCC_CFGR_PPRE1_MASK 0x7 +#define RCC_CFGR_PPRE_DIV_NONE 0x0 +#define RCC_CFGR_PPRE_DIV_2 0x4 +#define RCC_CFGR_PPRE_DIV_4 0x5 +#define RCC_CFGR_PPRE_DIV_8 0x6 +#define RCC_CFGR_PPRE_DIV_16 0x7 + +/* HPRE: AHB high-speed prescaler */ +#define RCC_CFGR_HPRE_SHIFT 4 +#define RCC_CFGR_HPRE_MASK 0xf +#define RCC_CFGR_HPRE_DIV_NONE 0x0 +#define RCC_CFGR_HPRE_DIV_2 (0x8 + 0) +#define RCC_CFGR_HPRE_DIV_4 (0x8 + 1) +#define RCC_CFGR_HPRE_DIV_8 (0x8 + 2) +#define RCC_CFGR_HPRE_DIV_16 (0x8 + 3) +#define RCC_CFGR_HPRE_DIV_64 (0x8 + 4) +#define RCC_CFGR_HPRE_DIV_128 (0x8 + 5) +#define RCC_CFGR_HPRE_DIV_256 (0x8 + 6) +#define RCC_CFGR_HPRE_DIV_512 (0x8 + 7) + +/* SWS: System clock switch status */ +#define RCC_CFGR_SWS_SHIFT 2 +#define RCC_CFGR_SWS_HSI 0x0 +#define RCC_CFGR_SWS_HSE 0x1 +#define RCC_CFGR_SWS_PLL 0x2 + +/* SW: System clock switch */ +#define RCC_CFGR_SW_SHIFT 0 +#define RCC_CFGR_SW_HSI 0x0 +#define RCC_CFGR_SW_HSE 0x1 +#define RCC_CFGR_SW_PLL 0x2 + +/* --- RCC_CIR values ------------------------------------------------------ */ + +/* Clock security system interrupt clear bit */ +#define RCC_CIR_CSSC (1 << 23) + +/* OSC ready interrupt clear bits */ +#define RCC_CIR_PLLI2SRDYC (1 << 21) +#define RCC_CIR_PLLRDYC (1 << 20) +#define RCC_CIR_HSERDYC (1 << 19) +#define RCC_CIR_HSIRDYC (1 << 18) +#define RCC_CIR_LSERDYC (1 << 17) +#define RCC_CIR_LSIRDYC (1 << 16) + +/* OSC ready interrupt enable bits */ +#define RCC_CIR_PLLI2SRDYIE (1 << 13) +#define RCC_CIR_PLLRDYIE (1 << 12) +#define RCC_CIR_HSERDYIE (1 << 11) +#define RCC_CIR_HSIRDYIE (1 << 10) +#define RCC_CIR_LSERDYIE (1 << 9) +#define RCC_CIR_LSIRDYIE (1 << 8) + +/* Clock security system interrupt flag bit */ +#define RCC_CIR_CSSF (1 << 7) + +/* OSC ready interrupt flag bits */ +#define RCC_CIR_PLLI2SRDYF (1 << 5) +#define RCC_CIR_PLLRDYF (1 << 4) +#define RCC_CIR_HSERDYF (1 << 3) +#define RCC_CIR_HSIRDYF (1 << 2) +#define RCC_CIR_LSERDYF (1 << 1) +#define RCC_CIR_LSIRDYF (1 << 0) + +/* --- RCC_AHB1RSTR values ------------------------------------------------- */ + +#define RCC_AHB1RSTR_OTGHSRST (1 << 29) +#define RCC_AHB1RSTR_ETHMACRST (1 << 25) +#define RCC_AHB1RSTR_DMA2RST (1 << 22) +#define RCC_AHB1RSTR_DMA1RST (1 << 21) +#define RCC_AHB1RSTR_CRCRST (1 << 12) +#define RCC_AHB1RSTR_IOPIRST (1 << 8) +#define RCC_AHB1RSTR_IOPHRST (1 << 7) +#define RCC_AHB1RSTR_IOPGRST (1 << 6) +#define RCC_AHB1RSTR_IOPFRST (1 << 5) +#define RCC_AHB1RSTR_IOPERST (1 << 4) +#define RCC_AHB1RSTR_IOPDRST (1 << 3) +#define RCC_AHB1RSTR_IOPCRST (1 << 2) +#define RCC_AHB1RSTR_IOPBRST (1 << 1) +#define RCC_AHB1RSTR_IOPARST (1 << 0) + +/* --- RCC_AHB2RSTR values ------------------------------------------------- */ + +#define RCC_AHB2RSTR_OTGFSRST (1 << 7) +#define RCC_AHB2RSTR_RNGRST (1 << 6) +#define RCC_AHB2RSTR_HASHRST (1 << 5) +#define RCC_AHB2RSTR_CRYPRST (1 << 4) +#define RCC_AHB2RSTR_DCMIRST (1 << 0) + +/* --- RCC_AHB3RSTR values ------------------------------------------------- */ + +#define RCC_AHB3RSTR_FSMCRST (1 << 0) + +/* --- RCC_APB1RSTR values ------------------------------------------------- */ + +#define RCC_APB1RSTR_DACRST (1 << 29) +#define RCC_APB1RSTR_PWRRST (1 << 28) +#define RCC_APB1RSTR_CAN2RST (1 << 26) +#define RCC_APB1RSTR_CAN1RST (1 << 25) +#define RCC_APB1RSTR_I2C3RST (1 << 23) +#define RCC_APB1RSTR_I2C2RST (1 << 22) +#define RCC_APB1RSTR_I2C1RST (1 << 21) +#define RCC_APB1RSTR_UART5RST (1 << 20) +#define RCC_APB1RSTR_UART4RST (1 << 19) +#define RCC_APB1RSTR_USART3RST (1 << 18) +#define RCC_APB1RSTR_USART2RST (1 << 17) +#define RCC_APB1RSTR_SPI3RST (1 << 15) +#define RCC_APB1RSTR_SPI2RST (1 << 14) +#define RCC_APB1RSTR_WWDGRST (1 << 11) +#define RCC_APB1RSTR_TIM14RST (1 << 8) +#define RCC_APB1RSTR_TIM13RST (1 << 7) +#define RCC_APB1RSTR_TIM12RST (1 << 6) +#define RCC_APB1RSTR_TIM7RST (1 << 5) +#define RCC_APB1RSTR_TIM6RST (1 << 4) +#define RCC_APB1RSTR_TIM5RST (1 << 3) +#define RCC_APB1RSTR_TIM4RST (1 << 2) +#define RCC_APB1RSTR_TIM3RST (1 << 1) +#define RCC_APB1RSTR_TIM2RST (1 << 0) + +/* --- RCC_APB2RSTR values ------------------------------------------------- */ + +#define RCC_APB2RSTR_TIM11RST (1 << 18) +#define RCC_APB2RSTR_TIM10RST (1 << 17) +#define RCC_APB2RSTR_TIM9RST (1 << 16) +#define RCC_APB2RSTR_SYSCFGRST (1 << 14) +#define RCC_APB2RSTR_SPI1RST (1 << 12) +#define RCC_APB2RSTR_SDIORST (1 << 11) +#define RCC_APB2RSTR_ADCRST (1 << 8) +#define RCC_APB2RSTR_USART6RST (1 << 5) +#define RCC_APB2RSTR_USART1RST (1 << 4) +#define RCC_APB2RSTR_TIM8RST (1 << 1) +#define RCC_APB2RSTR_TIM1RST (1 << 0) + +/* --- RCC_AHB1ENR values ------------------------------------------------- */ + +#define RCC_AHB1ENR_OTGHSULPIEN (1 << 30) +#define RCC_AHB1ENR_OTGHSEN (1 << 29) +#define RCC_AHB1ENR_ETHMACPTPEN (1 << 28) +#define RCC_AHB1ENR_ETHMACRXEN (1 << 27) +#define RCC_AHB1ENR_ETHMACTXEN (1 << 26) +#define RCC_AHB1ENR_ETHMACEN (1 << 25) +#define RCC_AHB1ENR_DMA2EN (1 << 22) +#define RCC_AHB1ENR_DMA1EN (1 << 21) +#define RCC_AHB1ENR_BKPSRAMEN (1 << 18) +#define RCC_AHB1ENR_CRCEN (1 << 12) +#define RCC_AHB1ENR_IOPIEN (1 << 8) +#define RCC_AHB1ENR_IOPHEN (1 << 7) +#define RCC_AHB1ENR_IOPGEN (1 << 6) +#define RCC_AHB1ENR_IOPFEN (1 << 5) +#define RCC_AHB1ENR_IOPEEN (1 << 4) +#define RCC_AHB1ENR_IOPDEN (1 << 3) +#define RCC_AHB1ENR_IOPCEN (1 << 2) +#define RCC_AHB1ENR_IOPBEN (1 << 1) +#define RCC_AHB1ENR_IOPAEN (1 << 0) + +/* --- RCC_AHB2ENR values ------------------------------------------------- */ + +#define RCC_AHB2ENR_OTGFSEN (1 << 7) +#define RCC_AHB2ENR_RNGEN (1 << 6) +#define RCC_AHB2ENR_HASHEN (1 << 5) +#define RCC_AHB2ENR_CRYPEN (1 << 4) +#define RCC_AHB2ENR_DCMIEN (1 << 0) + +/* --- RCC_AHB3ENR values ------------------------------------------------- */ + +#define RCC_AHB3ENR_FSMCEN (1 << 0) +/* Alternate now that F429 has DRAM controller as well */ +#define RCC_AHB3ENR_FMCEN (1 << 0) + +/* --- RCC_APB1ENR values ------------------------------------------------- */ + +#define RCC_APB1ENR_UART8EN (1 << 31) +#define RCC_APB1ENR_UART7EN (1 << 30) +#define RCC_APB1ENR_DACEN (1 << 29) +#define RCC_APB1ENR_PWREN (1 << 28) +#define RCC_APB1ENR_CAN2EN (1 << 26) +#define RCC_APB1ENR_CAN1EN (1 << 25) +#define RCC_APB1ENR_I2C3EN (1 << 23) +#define RCC_APB1ENR_I2C2EN (1 << 22) +#define RCC_APB1ENR_I2C1EN (1 << 21) +#define RCC_APB1ENR_UART5EN (1 << 20) +#define RCC_APB1ENR_UART4EN (1 << 19) +#define RCC_APB1ENR_USART3EN (1 << 18) +#define RCC_APB1ENR_USART2EN (1 << 17) +#define RCC_APB1ENR_SPI3EN (1 << 15) +#define RCC_APB1ENR_SPI2EN (1 << 14) +#define RCC_APB1ENR_WWDGEN (1 << 11) +#define RCC_APB1ENR_TIM14EN (1 << 8) +#define RCC_APB1ENR_TIM13EN (1 << 7) +#define RCC_APB1ENR_TIM12EN (1 << 6) +#define RCC_APB1ENR_TIM7EN (1 << 5) +#define RCC_APB1ENR_TIM6EN (1 << 4) +#define RCC_APB1ENR_TIM5EN (1 << 3) +#define RCC_APB1ENR_TIM4EN (1 << 2) +#define RCC_APB1ENR_TIM3EN (1 << 1) +#define RCC_APB1ENR_TIM2EN (1 << 0) + +/* --- RCC_APB2ENR values ------------------------------------------------- */ + +#define RCC_APB2ENR_LTDCEN (1 << 26) +#define RCC_APB2ENR_SAI1EN (1 << 22) +#define RCC_APB2ENR_SPI6EN (1 << 21) +#define RCC_APB2ENR_SPI5EN (1 << 20) +#define RCC_APB2ENR_TIM11EN (1 << 18) +#define RCC_APB2ENR_TIM10EN (1 << 17) +#define RCC_APB2ENR_TIM9EN (1 << 16) +#define RCC_APB2ENR_SYSCFGEN (1 << 14) +#define RCC_APB2ENR_SPI4EN (1 << 13) +#define RCC_APB2ENR_SPI1EN (1 << 12) +#define RCC_APB2ENR_SDIOEN (1 << 11) +#define RCC_APB2ENR_ADC3EN (1 << 10) +#define RCC_APB2ENR_ADC2EN (1 << 9) +#define RCC_APB2ENR_ADC1EN (1 << 8) +#define RCC_APB2ENR_USART6EN (1 << 5) +#define RCC_APB2ENR_USART1EN (1 << 4) +#define RCC_APB2ENR_TIM8EN (1 << 1) +#define RCC_APB2ENR_TIM1EN (1 << 0) + +/* --- RCC_AHB1LPENR values ------------------------------------------------- */ + +#define RCC_AHB1LPENR_OTGHSULPILPEN (1 << 30) +#define RCC_AHB1LPENR_OTGHSLPEN (1 << 29) +#define RCC_AHB1LPENR_ETHMACPTPLPEN (1 << 28) +#define RCC_AHB1LPENR_ETHMACRXLPEN (1 << 27) +#define RCC_AHB1LPENR_ETHMACTXLPEN (1 << 26) +#define RCC_AHB1LPENR_ETHMACLPEN (1 << 25) +#define RCC_AHB1LPENR_DMA2LPEN (1 << 22) +#define RCC_AHB1LPENR_DMA1LPEN (1 << 21) +#define RCC_AHB1LPENR_BKPSRAMLPEN (1 << 18) +#define RCC_AHB1LPENR_SRAM2LPEN (1 << 17) +#define RCC_AHB1LPENR_SRAM1LPEN (1 << 16) +#define RCC_AHB1LPENR_FLITFLPEN (1 << 15) +#define RCC_AHB1LPENR_CRCLPEN (1 << 12) +#define RCC_AHB1LPENR_IOPILPEN (1 << 8) +#define RCC_AHB1LPENR_IOPHLPEN (1 << 7) +#define RCC_AHB1LPENR_IOPGLPEN (1 << 6) +#define RCC_AHB1LPENR_IOPFLPEN (1 << 5) +#define RCC_AHB1LPENR_IOPELPEN (1 << 4) +#define RCC_AHB1LPENR_IOPDLPEN (1 << 3) +#define RCC_AHB1LPENR_IOPCLPEN (1 << 2) +#define RCC_AHB1LPENR_IOPBLPEN (1 << 1) +#define RCC_AHB1LPENR_IOPALPEN (1 << 0) + +/* --- RCC_AHB2LPENR values ------------------------------------------------- */ + +#define RCC_AHB2LPENR_OTGFSLPEN (1 << 7) +#define RCC_AHB2LPENR_RNGLPEN (1 << 6) +#define RCC_AHB2LPENR_HASHLPEN (1 << 5) +#define RCC_AHB2LPENR_CRYPLPEN (1 << 4) +#define RCC_AHB2LPENR_DCMILPEN (1 << 0) + +/* --- RCC_AHB3LPENR values ------------------------------------------------- */ + +#define RCC_AHB3LPENR_FSMCLPEN (1 << 0) + +/* --- RCC_APB1LPENR values ------------------------------------------------- */ + +#define RCC_APB1LPENR_DACLPEN (1 << 29) +#define RCC_APB1LPENR_PWRLPEN (1 << 28) +#define RCC_APB1LPENR_CAN2LPEN (1 << 26) +#define RCC_APB1LPENR_CAN1LPEN (1 << 25) +#define RCC_APB1LPENR_I2C3LPEN (1 << 23) +#define RCC_APB1LPENR_I2C2LPEN (1 << 22) +#define RCC_APB1LPENR_I2C1LPEN (1 << 21) +#define RCC_APB1LPENR_UART5LPEN (1 << 20) +#define RCC_APB1LPENR_UART4LPEN (1 << 19) +#define RCC_APB1LPENR_USART3LPEN (1 << 18) +#define RCC_APB1LPENR_USART2LPEN (1 << 17) +#define RCC_APB1LPENR_SPI3LPEN (1 << 15) +#define RCC_APB1LPENR_SPI2LPEN (1 << 14) +#define RCC_APB1LPENR_WWDGLPEN (1 << 11) +#define RCC_APB1LPENR_TIM14LPEN (1 << 8) +#define RCC_APB1LPENR_TIM13LPEN (1 << 7) +#define RCC_APB1LPENR_TIM12LPEN (1 << 6) +#define RCC_APB1LPENR_TIM7LPEN (1 << 5) +#define RCC_APB1LPENR_TIM6LPEN (1 << 4) +#define RCC_APB1LPENR_TIM5LPEN (1 << 3) +#define RCC_APB1LPENR_TIM4LPEN (1 << 2) +#define RCC_APB1LPENR_TIM3LPEN (1 << 1) +#define RCC_APB1LPENR_TIM2LPEN (1 << 0) + +/* --- RCC_APB2LPENR values ------------------------------------------------- */ + +#define RCC_APB2LPENR_TIM11LPEN (1 << 18) +#define RCC_APB2LPENR_TIM10LPEN (1 << 17) +#define RCC_APB2LPENR_TIM9LPEN (1 << 16) +#define RCC_APB2LPENR_SYSCFGLPEN (1 << 14) +#define RCC_APB2LPENR_SPI1LPEN (1 << 12) +#define RCC_APB2LPENR_SDIOLPEN (1 << 11) +#define RCC_APB2LPENR_ADC3LPEN (1 << 10) +#define RCC_APB2LPENR_ADC2LPEN (1 << 9) +#define RCC_APB2LPENR_ADC1LPEN (1 << 8) +#define RCC_APB2LPENR_USART6LPEN (1 << 5) +#define RCC_APB2LPENR_USART1LPEN (1 << 4) +#define RCC_APB2LPENR_TIM8LPEN (1 << 1) +#define RCC_APB2LPENR_TIM1LPEN (1 << 0) + +/* --- RCC_BDCR values ----------------------------------------------------- */ + +#define RCC_BDCR_BDRST (1 << 16) +#define RCC_BDCR_RTCEN (1 << 15) +/* RCC_BDCR[9:8]: RTCSEL */ +#define RCC_BDCR_LSEBYP (1 << 2) +#define RCC_BDCR_LSERDY (1 << 1) +#define RCC_BDCR_LSEON (1 << 0) + +/* --- RCC_CSR values ------------------------------------------------------ */ + +#define RCC_CSR_LPWRRSTF (1 << 31) +#define RCC_CSR_WWDGRSTF (1 << 30) +#define RCC_CSR_IWDGRSTF (1 << 29) +#define RCC_CSR_SFTRSTF (1 << 28) +#define RCC_CSR_PORRSTF (1 << 27) +#define RCC_CSR_PINRSTF (1 << 26) +#define RCC_CSR_BORRSTF (1 << 25) +#define RCC_CSR_RMVF (1 << 24) +#define RCC_CSR_LSIRDY (1 << 1) +#define RCC_CSR_LSION (1 << 0) + +/* --- RCC_SSCGR values ---------------------------------------------------- */ + +/* PLL spread spectrum clock generation documented in Datasheet. */ + +#define RCC_SSCGR_SSCGEN (1 << 31) +#define RCC_SSCGR_SPREADSEL (1 << 30) +/* RCC_SSCGR[27:16]: INCSTEP */ +#define RCC_SSCGR_INCSTEP_SHIFT 16 +/* RCC_SSCGR[15:0]: MODPER */ +#define RCC_SSCGR_MODPER_SHIFT 15 + +/* --- RCC_PLLI2SCFGR values ----------------------------------------------- */ + +/* RCC_PLLI2SCFGR[30:28]: PLLI2SR */ +#define RCC_PLLI2SCFGR_PLLI2SR_SHIFT 28 +/* RCC_PLLI2SCFGR[14:6]: PLLI2SN */ +#define RCC_PLLI2SCFGR_PLLI2SN_SHIFT 6 + +/* --- RCC_PLLSAICFGR values ----------------------------------------------- */ + +/* RCC_PLLSAICFGR[30:28]: PLLSAIR */ +#define RCC_PLLSAICFGR_PLLSAIR_SHIFT 28 +#define RCC_PLLSAICFGR_PLLSAIR_MASK 0x7 + +/* RCC_PLLSAICFGR[27:24]: PLLSAIQ */ +#define RCC_PLLSAICFGR_PLLSAIQ_SHIFT 24 +#define RCC_PLLSAICFGR_PLLSAIQ_MASK 0xF + +/* RCC_PLLSAICFGR[14:6]: PLLSAIN */ +#define RCC_PLLSAICFGR_PLLSAIN_SHIFT 14 +#define RCC_PLLSAICFGR_PLLSAIN_MASK 0x1FF + + +/* --- RCC_DCKCFGR values -------------------------------------------------- */ +#define RCC_DCKCFGR_PLLSAIDIVR_MSK (0x3 << 16) +#define RCC_DCKCFGR_PLLSAIDIVR_DIVR_2 (0x0) +#define RCC_DCKCFGR_PLLSAIDIVR_DIVR_4 (0x1) +#define RCC_DCKCFGR_PLLSAIDIVR_DIVR_8 (0x2) +#define RCC_DCKCFGR_PLLSAIDIVR_DIVR_16 (0x3) + +/* PLLSAI1 helper macros */ +static inline void rcc_pllsai_enable(void) +{ + RCC_CR |= RCC_CR_PLLSAION; +} + +static inline bool rcc_pllsai_ready(void) +{ + return (RCC_CR & RCC_CR_PLLSAIRDY) != 0; +} + +/* pllsain=49..432, pllsaiq=2..15, pllsair=2..7 */ +static inline void rcc_pllsai_config(uint16_t pllsain, + uint16_t pllsaiq, + uint16_t pllsair) +{ + RCC_PLLSAICFGR = (((pllsain & 0x1ff) << 6) | + ((pllsaiq & 0xF) << 24) | + ((pllsair & 0x7) << 28)); +} + +static inline void rcc_ltdc_set_clock_divr(uint8_t pllsaidivr) +{ + RCC_DCKCFGR = (((RCC_DCKCFGR & + ~RCC_DCKCFGR_PLLSAIDIVR_MSK) | + ((pllsaidivr & 0x3) << 16))); +} + +/* --- Variable definitions ------------------------------------------------ */ +extern uint32_t rcc_ahb_frequency; +extern uint32_t rcc_apb1_frequency; +extern uint32_t rcc_apb2_frequency; + +/* --- Function prototypes ------------------------------------------------- */ + +typedef enum { + CLOCK_3V3_48MHZ, + CLOCK_3V3_84MHZ, + CLOCK_3V3_120MHZ, + CLOCK_3V3_168MHZ, + CLOCK_3V3_END +} clock_3v3_t; + +typedef struct { + uint8_t pllm; + uint16_t plln; + uint8_t pllp; + uint8_t pllq; + uint32_t flash_config; + uint8_t hpre; + uint8_t ppre1; + uint8_t ppre2; + uint8_t power_save; + uint32_t apb1_frequency; + uint32_t apb2_frequency; +} clock_scale_t; + +extern const clock_scale_t hse_8mhz_3v3[CLOCK_3V3_END]; +extern const clock_scale_t hse_12mhz_3v3[CLOCK_3V3_END]; +extern const clock_scale_t hse_16mhz_3v3[CLOCK_3V3_END]; +extern const clock_scale_t hse_25mhz_3v3[CLOCK_3V3_END]; + +enum rcc_osc { + PLL, HSE, HSI, LSE, LSI +}; + +#define _REG_BIT(base, bit) (((base) << 5) + (bit)) + +enum rcc_periph_clken { + /* AHB1 peripherals*/ + RCC_GPIOA = _REG_BIT(0x30, 0), + RCC_GPIOB = _REG_BIT(0x30, 1), + RCC_GPIOC = _REG_BIT(0x30, 2), + RCC_GPIOD = _REG_BIT(0x30, 3), + RCC_GPIOE = _REG_BIT(0x30, 4), + RCC_GPIOF = _REG_BIT(0x30, 5), + RCC_GPIOG = _REG_BIT(0x30, 6), + RCC_GPIOH = _REG_BIT(0x30, 7), + RCC_GPIOI = _REG_BIT(0x30, 8), + RCC_CRC = _REG_BIT(0x30, 12), + RCC_BKPSRAM = _REG_BIT(0x30, 18), + RCC_CCMDATARAM = _REG_BIT(0x30, 20), + RCC_DMA1 = _REG_BIT(0x30, 21), + RCC_DMA2 = _REG_BIT(0x30, 22), + RCC_ETHMAC = _REG_BIT(0x30, 25), + RCC_ETHMACTX = _REG_BIT(0x30, 26), + RCC_ETHMACRX = _REG_BIT(0x30, 27), + RCC_ETHMACPTP = _REG_BIT(0x30, 28), + RCC_OTGHS = _REG_BIT(0x30, 29), + RCC_OTGHSULPI = _REG_BIT(0x30, 30), + + /* AHB2 peripherals */ + RCC_DCMI = _REG_BIT(0x34, 0), + RCC_CRYP = _REG_BIT(0x34, 4), + RCC_HASH = _REG_BIT(0x34, 5), + RCC_RNG = _REG_BIT(0x34, 6), + RCC_OTGFS = _REG_BIT(0x34, 7), + + /* AHB3 peripherals */ + RCC_FSMC = _REG_BIT(0x38, 0), + + /* APB1 peripherals*/ + RCC_TIM2 = _REG_BIT(0x40, 0), + RCC_TIM3 = _REG_BIT(0x40, 1), + RCC_TIM4 = _REG_BIT(0x40, 2), + RCC_TIM5 = _REG_BIT(0x40, 3), + RCC_TIM6 = _REG_BIT(0x40, 4), + RCC_TIM7 = _REG_BIT(0x40, 5), + RCC_TIM12 = _REG_BIT(0x40, 6), + RCC_TIM13 = _REG_BIT(0x40, 7), + RCC_TIM14 = _REG_BIT(0x40, 8), + RCC_WWDG = _REG_BIT(0x40, 11), + RCC_SPI2 = _REG_BIT(0x40, 14), + RCC_SPI3 = _REG_BIT(0x40, 15), + RCC_USART2 = _REG_BIT(0x40, 17), + RCC_USART3 = _REG_BIT(0x40, 18), + RCC_UART4 = _REG_BIT(0x40, 19), + RCC_UART5 = _REG_BIT(0x40, 20), + RCC_I2C1 = _REG_BIT(0x40, 21), + RCC_I2C2 = _REG_BIT(0x40, 22), + RCC_I2C3 = _REG_BIT(0x40, 23), + RCC_CAN1 = _REG_BIT(0x40, 25), + RCC_CAN2 = _REG_BIT(0x40, 26), + RCC_PWR = _REG_BIT(0x40, 28), + RCC_DAC = _REG_BIT(0x40, 29), + RCC_UART7 = _REG_BIT(0x40, 30),/* F2xx, F3xx */ + RCC_UART8 = _REG_BIT(0x40, 31),/* F2xx, F3xx */ + + /* APB2 peripherals */ + RCC_TIM1 = _REG_BIT(0x44, 0), + RCC_TIM8 = _REG_BIT(0x44, 1), + RCC_USART1 = _REG_BIT(0x44, 4), + RCC_USART6 = _REG_BIT(0x44, 5), + RCC_ADC1 = _REG_BIT(0x44, 8), + RCC_ADC2 = _REG_BIT(0x44, 9), + RCC_ADC3 = _REG_BIT(0x44, 10), + RCC_SDIO = _REG_BIT(0x44, 11), + RCC_SPI1 = _REG_BIT(0x44, 12), + RCC_SPI4 = _REG_BIT(0x44, 13),/* F2xx, F3xx */ + RCC_SYSCFG = _REG_BIT(0x44, 14), + RCC_TIM9 = _REG_BIT(0x44, 16), + RCC_TIM10 = _REG_BIT(0x44, 17), + RCC_TIM11 = _REG_BIT(0x44, 18), + RCC_SPI5 = _REG_BIT(0x44, 20),/* F2xx, F3xx */ + RCC_SPI6 = _REG_BIT(0x44, 21),/* F2xx, F3xx */ + RCC_SAI1EN = _REG_BIT(0x44, 22),/* F42x, F43x */ + RCC_LTDC = _REG_BIT(0x44, 26),/* F42x, F43x */ + + + /* BDCR */ + RCC_RTC = _REG_BIT(0x70, 15), + + /* AHB1 peripherals*/ + SCC_GPIOA = _REG_BIT(0x50, 0), + SCC_GPIOB = _REG_BIT(0x50, 1), + SCC_GPIOC = _REG_BIT(0x50, 2), + SCC_GPIOD = _REG_BIT(0x50, 3), + SCC_GPIOE = _REG_BIT(0x50, 4), + SCC_GPIOF = _REG_BIT(0x50, 5), + SCC_GPIOG = _REG_BIT(0x50, 6), + SCC_GPIOH = _REG_BIT(0x50, 7), + SCC_GPIOI = _REG_BIT(0x50, 8), + SCC_CRC = _REG_BIT(0x50, 12), + SCC_FLTIF = _REG_BIT(0x50, 15), + SCC_SRAM1 = _REG_BIT(0x50, 16), + SCC_SRAM2 = _REG_BIT(0x50, 17), + SCC_BKPSRAM = _REG_BIT(0x50, 18), + SCC_SRAM3 = _REG_BIT(0x50, 19),/* F2xx, F3xx */ + SCC_DMA1 = _REG_BIT(0x50, 21), + SCC_DMA2 = _REG_BIT(0x50, 22), + SCC_ETHMAC = _REG_BIT(0x50, 25), + SCC_ETHMACTX = _REG_BIT(0x50, 26), + SCC_ETHMACRX = _REG_BIT(0x50, 27), + SCC_ETHMACPTP = _REG_BIT(0x50, 28), + SCC_OTGHS = _REG_BIT(0x50, 29), + SCC_OTGHSULPI = _REG_BIT(0x50, 30), + + /* AHB2 peripherals */ + SCC_DCMI = _REG_BIT(0x54, 0), + SCC_CRYP = _REG_BIT(0x54, 4), + SCC_HASH = _REG_BIT(0x54, 5), + SCC_RNG = _REG_BIT(0x54, 6), + SCC_OTGFS = _REG_BIT(0x54, 7), + + /* AHB3 peripherals */ + SCC_FSMC = _REG_BIT(0x58, 0), + + /* APB1 peripherals*/ + SCC_TIM2 = _REG_BIT(0x60, 0), + SCC_TIM3 = _REG_BIT(0x60, 1), + SCC_TIM4 = _REG_BIT(0x60, 2), + SCC_TIM5 = _REG_BIT(0x60, 3), + SCC_TIM6 = _REG_BIT(0x60, 4), + SCC_TIM7 = _REG_BIT(0x60, 5), + SCC_TIM12 = _REG_BIT(0x60, 6), + SCC_TIM13 = _REG_BIT(0x60, 7), + SCC_TIM14 = _REG_BIT(0x60, 8), + SCC_WWDG = _REG_BIT(0x60, 11), + SCC_SPI2 = _REG_BIT(0x60, 14), + SCC_SPI3 = _REG_BIT(0x60, 15), + SCC_USART2 = _REG_BIT(0x60, 17), + SCC_USART3 = _REG_BIT(0x60, 18), + SCC_UART4 = _REG_BIT(0x60, 19), + SCC_UART5 = _REG_BIT(0x60, 20), + SCC_I2C1 = _REG_BIT(0x60, 21), + SCC_I2C2 = _REG_BIT(0x60, 22), + SCC_I2C3 = _REG_BIT(0x60, 23), + SCC_CAN1 = _REG_BIT(0x60, 25), + SCC_CAN2 = _REG_BIT(0x60, 26), + SCC_PWR = _REG_BIT(0x60, 28), + SCC_DAC = _REG_BIT(0x60, 29), + SCC_UART7 = _REG_BIT(0x60, 30),/* F2xx, F3xx */ + SCC_UART8 = _REG_BIT(0x60, 31),/* F2xx, F3xx */ + + /* APB2 peripherals */ + SCC_TIM1 = _REG_BIT(0x64, 0), + SCC_TIM8 = _REG_BIT(0x64, 1), + SCC_USART1 = _REG_BIT(0x64, 4), + SCC_USART6 = _REG_BIT(0x64, 5), + SCC_ADC1 = _REG_BIT(0x64, 8), + SCC_ADC2 = _REG_BIT(0x64, 9), + SCC_ADC3 = _REG_BIT(0x64, 10), + SCC_SDIO = _REG_BIT(0x64, 11), + SCC_SPI1 = _REG_BIT(0x64, 12), + SCC_SPI4 = _REG_BIT(0x64, 13),/* F2xx, F3xx */ + SCC_SYSCFG = _REG_BIT(0x64, 14), + SCC_TIM9 = _REG_BIT(0x64, 16), + SCC_TIM10 = _REG_BIT(0x64, 17), + SCC_TIM11 = _REG_BIT(0x64, 18), + SCC_SPI5 = _REG_BIT(0x64, 20),/* F2xx, F3xx */ + SCC_SPI6 = _REG_BIT(0x64, 21),/* F2xx, F3xx */ +}; + +enum rcc_periph_rst { + /* AHB1 peripherals*/ + RST_GPIOA = _REG_BIT(0x10, 0), + RST_GPIOB = _REG_BIT(0x10, 1), + RST_GPIOC = _REG_BIT(0x10, 2), + RST_GPIOD = _REG_BIT(0x10, 3), + RST_GPIOE = _REG_BIT(0x10, 4), + RST_GPIOF = _REG_BIT(0x10, 5), + RST_GPIOG = _REG_BIT(0x10, 6), + RST_GPIOH = _REG_BIT(0x10, 7), + RST_GPIOI = _REG_BIT(0x10, 8), + RST_CRC = _REG_BIT(0x10, 12), + RST_DMA1 = _REG_BIT(0x10, 21), + RST_DMA2 = _REG_BIT(0x10, 22), + RST_ETHMAC = _REG_BIT(0x10, 25), + RST_OTGHS = _REG_BIT(0x10, 29), + + /* AHB2 peripherals */ + RST_DCMI = _REG_BIT(0x14, 0), + RST_CRYP = _REG_BIT(0x14, 4), + RST_HASH = _REG_BIT(0x14, 5), + RST_RNG = _REG_BIT(0x14, 6), + RST_OTGFS = _REG_BIT(0x14, 7), + + /* AHB3 peripherals */ + RST_FSMC = _REG_BIT(0x18, 0), + + /* APB1 peripherals*/ + RST_TIM2 = _REG_BIT(0x20, 0), + RST_TIM3 = _REG_BIT(0x20, 1), + RST_TIM4 = _REG_BIT(0x20, 2), + RST_TIM5 = _REG_BIT(0x20, 3), + RST_TIM6 = _REG_BIT(0x20, 4), + RST_TIM7 = _REG_BIT(0x20, 5), + RST_TIM12 = _REG_BIT(0x20, 6), + RST_TIM13 = _REG_BIT(0x20, 7), + RST_TIM14 = _REG_BIT(0x20, 8), + RST_WWDG = _REG_BIT(0x20, 11), + RST_SPI2 = _REG_BIT(0x20, 14), + RST_SPI3 = _REG_BIT(0x20, 15), + RST_USART2 = _REG_BIT(0x20, 17), + RST_USART3 = _REG_BIT(0x20, 18), + RST_UART4 = _REG_BIT(0x20, 19), + RST_UART5 = _REG_BIT(0x20, 20), + RST_I2C1 = _REG_BIT(0x20, 21), + RST_I2C2 = _REG_BIT(0x20, 22), + RST_I2C3 = _REG_BIT(0x20, 23), + RST_CAN1 = _REG_BIT(0x20, 25), + RST_CAN2 = _REG_BIT(0x20, 26), + RST_PWR = _REG_BIT(0x20, 28), + RST_DAC = _REG_BIT(0x20, 29), + RST_UART7 = _REG_BIT(0x20, 30),/* F2xx, F3xx */ + RST_UART8 = _REG_BIT(0x20, 31),/* F2xx, F3xx */ + + /* APB2 peripherals */ + RST_TIM1 = _REG_BIT(0x24, 0), + RST_TIM8 = _REG_BIT(0x24, 1), + RST_USART1 = _REG_BIT(0x24, 4), + RST_USART6 = _REG_BIT(0x24, 5), + RST_ADC = _REG_BIT(0x24, 8), + RST_SDIO = _REG_BIT(0x24, 11), + RST_SPI1 = _REG_BIT(0x24, 12), + RST_SPI4 = _REG_BIT(0x24, 13),/* F2xx, F3xx */ + RST_SYSCFG = _REG_BIT(0x24, 14), + RST_TIM9 = _REG_BIT(0x24, 16), + RST_TIM10 = _REG_BIT(0x24, 17), + RST_TIM11 = _REG_BIT(0x24, 18), + RST_SPI5 = _REG_BIT(0x24, 20),/* F2xx, F3xx */ + RST_SPI6 = _REG_BIT(0x24, 21),/* F2xx, F3xx */ + RST_SAI1RST = _REG_BIT(0x24, 22),/* F42x, F43x */ + RST_LTDC = _REG_BIT(0x24, 26),/* F42x, F43x */ +}; + +#undef _REG_BIT + + +void rcc_peripheral_enable_clock(volatile uint32_t *reg, uint32_t en); +void rcc_peripheral_disable_clock(volatile uint32_t *reg, uint32_t en); +void rcc_peripheral_reset(volatile uint32_t *reg, uint32_t reset); +void rcc_peripheral_clear_reset(volatile uint32_t *reg, uint32_t clear_reset); + +void rcc_periph_clock_enable(enum rcc_periph_clken clken); +void rcc_periph_clock_disable(enum rcc_periph_clken clken); +void rcc_periph_reset_pulse(enum rcc_periph_rst rst); +void rcc_periph_reset_hold(enum rcc_periph_rst rst); +void rcc_periph_reset_release(enum rcc_periph_rst rst); + +void rcc_set_mco(uint32_t mcosrc); + + + + +void rcc_osc_ready_int_clear(enum rcc_osc osc); +void rcc_osc_ready_int_enable(enum rcc_osc osc); +void rcc_osc_ready_int_disable(enum rcc_osc osc); +int rcc_osc_ready_int_flag(enum rcc_osc osc); +void rcc_css_int_clear(void); +int rcc_css_int_flag(void); +void rcc_wait_for_osc_ready(enum rcc_osc osc); +void rcc_wait_for_sysclk_status(enum rcc_osc osc); +void rcc_osc_on(enum rcc_osc osc); +void rcc_osc_off(enum rcc_osc osc); +void rcc_css_enable(void); +void rcc_css_disable(void); +void rcc_osc_bypass_enable(enum rcc_osc osc); +void rcc_osc_bypass_disable(enum rcc_osc osc); +void rcc_set_sysclk_source(uint32_t clk); +void rcc_set_pll_source(uint32_t pllsrc); +void rcc_set_ppre2(uint32_t ppre2); +void rcc_set_ppre1(uint32_t ppre1); +void rcc_set_hpre(uint32_t hpre); +void rcc_set_rtcpre(uint32_t rtcpre); +void rcc_set_main_pll_hsi(uint32_t pllm, uint32_t plln, uint32_t pllp, + uint32_t pllq); +void rcc_set_main_pll_hse(uint32_t pllm, uint32_t plln, uint32_t pllp, + uint32_t pllq); +uint32_t rcc_system_clock_source(void); +void rcc_clock_setup_hse_3v3(const clock_scale_t *clock); + + + +#endif diff --git a/FourQ_ARM_side_channel/libopencm3/include/rng.h b/FourQ_ARM_side_channel/libopencm3/include/rng.h new file mode 100644 index 0000000..b3433ae --- /dev/null +++ b/FourQ_ARM_side_channel/libopencm3/include/rng.h @@ -0,0 +1,68 @@ +/* + * This file is part of the libopencm3 project. + * + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY, BUT ONLY VIA RNG.H +The order of header inclusion is important. rng.h includes the device +specific memorymap.h header before including this header file.*/ + +/** @cond */ +#ifndef LIBOPENCM3_RNG_H +#define LIBOPENCM3_RNG_H +#include "memorymap_f4.h" +/** @endcond */ + +/* --- Random number generator registers ----------------------------------- */ + +/* Control register */ +#define RNG_CR MMIO32(RNG_BASE + 0x00) + +/* Status register */ +#define RNG_SR MMIO32(RNG_BASE + 0x04) + +/* Data register */ +#define RNG_DR MMIO32(RNG_BASE + 0x08) + +/* --- RNG_CR values ------------------------------------------------------- */ + +/* RNG ENABLE */ +#define RNG_CR_RNGEN (1 << 2) + +/* RNG interrupt enable */ +#define RNG_CR_IE (1 << 3) + +/* --- RNG_SR values ------------------------------------------------------- */ + +/* Data ready */ +#define RNG_SR_DRDY (1 << 0) + +/* Clock error current status */ +#define RNG_SR_CECS (1 << 1) + +/* Seed error current status */ +#define RNG_SR_SECS (1 << 2) + +/* Clock error interrupt status */ +#define RNG_SR_CEIS (1 << 5) + +/* Seed error interrupt status */ +#define RNG_SR_SEIS (1 << 6) + +#endif +/** @cond */ +/** @endcond */ + diff --git a/FourQ_ARM_side_channel/libopencm3/include/usart.h b/FourQ_ARM_side_channel/libopencm3/include/usart.h new file mode 100644 index 0000000..0d91e16 --- /dev/null +++ b/FourQ_ARM_side_channel/libopencm3/include/usart.h @@ -0,0 +1,97 @@ +/** @addtogroup usart_defines + +@author @htmlonly © @endhtmlonly 2011 Uwe Hermann +@author @htmlonly © @endhtmlonly 2011 Stephen Caudle + +*/ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Fergus Noble + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY, BUT ONLY VIA USART.H +The order of header inclusion is important. usart.h includes the device +specific memorymap.h header before including this header file.*/ + +/** @cond */ +#ifndef LIBOPENCM3_USART_H +#define LIBOPENCM3_USART_H +/** @endcond */ +#ifndef LIBOPENCM3_USART_COMMON_F24_H +#define LIBOPENCM3_USART_COMMON_F24_H + +#include "usart_common_f124.h" + +/* --- Convenience macros -------------------------------------------------- */ + +#define USART6 USART6_BASE +#define UART7 UART7_BASE +#define UART8 UART8_BASE + +/* --- USART registers ----------------------------------------------------- */ + +/* Status register (USARTx_SR) */ +#define USART6_SR USART_SR(USART6_BASE) +#define UART7_SR USART_SR(UART7) +#define UART8_SR USART_SR(UART8) + +/* Data register (USARTx_DR) */ +#define USART6_DR USART_DR(USART6_BASE) +#define UART7_DR USART_DR(UART7) +#define UART8_DR USART_DR(UART8) + +/* Baud rate register (USARTx_BRR) */ +#define USART6_BRR USART_BRR(USART6_BASE) +#define UART7_BRR USART_BRR(UART7) +#define UART8_BRR USART_BRR(UART8) + +/* Control register 1 (USARTx_CR1) */ +#define USART6_CR1 USART_CR1(USART6_BASE) +#define UART7_CR1 USART_CR1(UART7) +#define UART8_CR1 USART_CR1(UART8) + +/* Control register 2 (USARTx_CR2) */ +#define USART6_CR2 USART_CR2(USART6_BASE) +#define UART7_CR2 USART_CR2(UART7) +#define UART8_CR2 USART_CR2(UART8) + +/* Control register 3 (USARTx_CR3) */ +#define USART6_CR3 USART_CR3(USART6_BASE) +#define UART7_CR3 USART_CR3(UART7) +#define UART8_CR3 USART_CR3(UART8) + +/* Guard time and prescaler register (USARTx_GTPR) */ +#define USART6_GTPR USART_GTPR(USART6_BASE) +#define UART7_GTPR USART_GTPR(UART7) +#define UART8_GTPR USART_GTPR(UART8) + +/* --- USART_CR1 values ---------------------------------------------------- */ + +/* OVER8: Oversampling mode */ +#define USART_CR1_OVER8 (1 << 15) + +/* --- USART_CR3 values ---------------------------------------------------- */ + +/* ONEBIT: One sample bit method enable */ +#define USART_CR3_ONEBIT (1 << 11) + +#endif +/** @cond */ +#endif +/** @endcond */ + diff --git a/FourQ_ARM_side_channel/libopencm3/include/usart_common_all.h b/FourQ_ARM_side_channel/libopencm3/include/usart_common_all.h new file mode 100644 index 0000000..e3b2872 --- /dev/null +++ b/FourQ_ARM_side_channel/libopencm3/include/usart_common_all.h @@ -0,0 +1,139 @@ +/** @addtogroup usart_defines + * + * @author @htmlonly © @endhtmlonly 2009 Uwe Hermann + * + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +/* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY, BUT ONLY VIA USART.H +The order of header inclusion is important. usart.h includes the device +specific memorymap.h header before including this header file.*/ + +/** @cond */ +#if defined(LIBOPENCM3_USART_H) +/** @endcond */ +#ifndef LIBOPENCM3_USART_COMMON_ALL_H +#define LIBOPENCM3_USART_COMMON_ALL_H + +/* --- Convenience macros -------------------------------------------------- */ + +/****************************************************************************/ +/** @defgroup usart_reg_base USART register base addresses +@ingroup STM32F_usart_defines + +@{*/ +#define USART1 USART1_BASE +#define USART2 USART2_BASE +#define USART3 USART3_BASE +/**@}*/ +#define UART4 UART4_BASE +#define UART5 UART5_BASE + +/* --- Convenience defines ------------------------------------------------- */ + +/* CR1_PCE / CR1_PS combined values */ +/****************************************************************************/ +/** @defgroup usart_cr1_parity USART Parity Selection +@ingroup STM32F_usart_defines + +@{*/ +#define USART_PARITY_NONE 0x00 +#define USART_PARITY_EVEN USART_CR1_PCE +#define USART_PARITY_ODD (USART_CR1_PS | USART_CR1_PCE) +/**@}*/ +#define USART_PARITY_MASK (USART_CR1_PS | USART_CR1_PCE) + +/* CR1_TE/CR1_RE combined values */ +/****************************************************************************/ +/** @defgroup usart_cr1_mode USART Tx/Rx Mode Selection +@ingroup STM32F_usart_defines + +@{*/ +#define USART_MODE_RX USART_CR1_RE +#define USART_MODE_TX USART_CR1_TE +#define USART_MODE_TX_RX (USART_CR1_RE | USART_CR1_TE) +/**@}*/ +#define USART_MODE_MASK (USART_CR1_RE | USART_CR1_TE) + +/****************************************************************************/ +/** @defgroup usart_cr2_stopbits USART Stop Bit Selection +@ingroup STM32F_usart_defines + +@{*/ +#define USART_STOPBITS_1 USART_CR2_STOPBITS_1 /* 1 stop bit */ +#define USART_STOPBITS_0_5 USART_CR2_STOPBITS_0_5 /* .5 stop bit */ +#define USART_STOPBITS_2 USART_CR2_STOPBITS_2 /* 2 stop bits */ +#define USART_STOPBITS_1_5 USART_CR2_STOPBITS_1_5 /* 1.5 stop bit*/ +/**@}*/ + +/* CR3_CTSE/CR3_RTSE combined values */ +/****************************************************************************/ +/** @defgroup usart_cr3_flowcontrol USART Hardware Flow Control Selection +@ingroup STM32F_usart_defines + +@{*/ +#define USART_FLOWCONTROL_NONE 0x00 +#define USART_FLOWCONTROL_RTS USART_CR3_RTSE +#define USART_FLOWCONTROL_CTS USART_CR3_CTSE +#define USART_FLOWCONTROL_RTS_CTS (USART_CR3_RTSE | USART_CR3_CTSE) +/**@}*/ +#define USART_FLOWCONTROL_MASK (USART_CR3_RTSE | USART_CR3_CTSE) + +/* --- Function prototypes ------------------------------------------------- */ + + +void usart_set_baudrate(uint32_t usart, uint32_t baud); +void usart_set_databits(uint32_t usart, uint32_t bits); +void usart_set_stopbits(uint32_t usart, uint32_t stopbits); +void usart_set_parity(uint32_t usart, uint32_t parity); +void usart_set_mode(uint32_t usart, uint32_t mode); +void usart_set_flow_control(uint32_t usart, uint32_t flowcontrol); +void usart_enable(uint32_t usart); +void usart_disable(uint32_t usart); +void usart_send(uint32_t usart, uint16_t data); +uint16_t usart_recv(uint32_t usart); +void usart_wait_send_ready(uint32_t usart); +void usart_wait_recv_ready(uint32_t usart); +void usart_send_blocking(uint32_t usart, uint16_t data); +uint16_t usart_recv_blocking(uint32_t usart); +void usart_enable_rx_dma(uint32_t usart); +void usart_disable_rx_dma(uint32_t usart); +void usart_enable_tx_dma(uint32_t usart); +void usart_disable_tx_dma(uint32_t usart); +void usart_enable_rx_interrupt(uint32_t usart); +void usart_disable_rx_interrupt(uint32_t usart); +void usart_enable_tx_interrupt(uint32_t usart); +void usart_disable_tx_interrupt(uint32_t usart); +void usart_enable_error_interrupt(uint32_t usart); +void usart_disable_error_interrupt(uint32_t usart); +bool usart_get_flag(uint32_t usart, uint32_t flag); +bool usart_get_interrupt_source(uint32_t usart, uint32_t flag); + + +#endif +/** @cond */ +#else +#warning "usart_common_all.h should not be included directly, only via usart.h" +#endif +/** @endcond */ +/**@}*/ + diff --git a/FourQ_ARM_side_channel/libopencm3/include/usart_common_f124.h b/FourQ_ARM_side_channel/libopencm3/include/usart_common_f124.h new file mode 100644 index 0000000..4293be0 --- /dev/null +++ b/FourQ_ARM_side_channel/libopencm3/include/usart_common_f124.h @@ -0,0 +1,288 @@ +/** @addtogroup usart_defines + +@author @htmlonly © @endhtmlonly 2009 Uwe Hermann + +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +/* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY, BUT ONLY VIA USART.H +The order of header inclusion is important. usart.h includes the device +specific memorymap.h header before including this header file.*/ + +/** @cond */ +#if defined(LIBOPENCM3_USART_H) +/** @endcond */ +#ifndef LIBOPENCM3_USART_COMMON_F124_H +#define LIBOPENCM3_USART_COMMON_F124_H + +#include "usart_common_all.h" + +/* --- USART registers ----------------------------------------------------- */ + +/* Status register (USARTx_SR) */ +#define USART_SR(usart_base) MMIO32((usart_base) + 0x00) +#define USART1_SR USART_SR(USART1_BASE) +#define USART2_SR USART_SR(USART2_BASE) +#define USART3_SR USART_SR(USART3_BASE) +#define UART4_SR USART_SR(UART4_BASE) +#define UART5_SR USART_SR(UART5_BASE) + +/* Data register (USARTx_DR) */ +#define USART_DR(usart_base) MMIO32((usart_base) + 0x04) +#define USART1_DR USART_DR(USART1_BASE) +#define USART2_DR USART_DR(USART2_BASE) +#define USART3_DR USART_DR(USART3_BASE) +#define UART4_DR USART_DR(UART4_BASE) +#define UART5_DR USART_DR(UART5_BASE) + +/* Baud rate register (USARTx_BRR) */ +#define USART_BRR(usart_base) MMIO32((usart_base) + 0x08) +#define USART1_BRR USART_BRR(USART1_BASE) +#define USART2_BRR USART_BRR(USART2_BASE) +#define USART3_BRR USART_BRR(USART3_BASE) +#define UART4_BRR USART_BRR(UART4_BASE) +#define UART5_BRR USART_BRR(UART5_BASE) + +/* Control register 1 (USARTx_CR1) */ +#define USART_CR1(usart_base) MMIO32((usart_base) + 0x0c) +#define USART1_CR1 USART_CR1(USART1_BASE) +#define USART2_CR1 USART_CR1(USART2_BASE) +#define USART3_CR1 USART_CR1(USART3_BASE) +#define UART4_CR1 USART_CR1(UART4_BASE) +#define UART5_CR1 USART_CR1(UART5_BASE) + +/* Control register 2 (USARTx_CR2) */ +#define USART_CR2(usart_base) MMIO32((usart_base) + 0x10) +#define USART1_CR2 USART_CR2(USART1_BASE) +#define USART2_CR2 USART_CR2(USART2_BASE) +#define USART3_CR2 USART_CR2(USART3_BASE) +#define UART4_CR2 USART_CR2(UART4_BASE) +#define UART5_CR2 USART_CR2(UART5_BASE) + +/* Control register 3 (USARTx_CR3) */ +#define USART_CR3(usart_base) MMIO32((usart_base) + 0x14) +#define USART1_CR3 USART_CR3(USART1_BASE) +#define USART2_CR3 USART_CR3(USART2_BASE) +#define USART3_CR3 USART_CR3(USART3_BASE) +#define UART4_CR3 USART_CR3(UART4_BASE) +#define UART5_CR3 USART_CR3(UART5_BASE) + +/* Guard time and prescaler register (USARTx_GTPR) */ +#define USART_GTPR(usart_base) MMIO32((usart_base) + 0x18) +#define USART1_GTPR USART_GTPR(USART1_BASE) +#define USART2_GTPR USART_GTPR(USART2_BASE) +#define USART3_GTPR USART_GTPR(USART3_BASE) +#define UART4_GTPR USART_GTPR(UART4_BASE) +#define UART5_GTPR USART_GTPR(UART5_BASE) + +/* --- USART_SR values ----------------------------------------------------- */ +/****************************************************************************/ +/** @defgroup usart_sr_flags USART Status register Flags +@ingroup STM32F_usart_defines + +@{*/ + +/** CTS: CTS flag */ +/** @note: undefined on UART4 and UART5 */ +#define USART_SR_CTS (1 << 9) + +/** LBD: LIN break detection flag */ +#define USART_SR_LBD (1 << 8) + +/** TXE: Transmit data buffer empty */ +#define USART_SR_TXE (1 << 7) + +/** TC: Transmission complete */ +#define USART_SR_TC (1 << 6) + +/** RXNE: Read data register not empty */ +#define USART_SR_RXNE (1 << 5) + +/** IDLE: Idle line detected */ +#define USART_SR_IDLE (1 << 4) + +/** ORE: Overrun error */ +#define USART_SR_ORE (1 << 3) + +/** NE: Noise error flag */ +#define USART_SR_NE (1 << 2) + +/** FE: Framing error */ +#define USART_SR_FE (1 << 1) + +/** PE: Parity error */ +#define USART_SR_PE (1 << 0) +/**@}*/ + +/* --- USART_DR values ----------------------------------------------------- */ + +/* USART_DR[8:0]: DR[8:0]: Data value */ +#define USART_DR_MASK 0x1FF + +/* --- USART_BRR values ---------------------------------------------------- */ + +/* DIV_Mantissa[11:0]: mantissa of USARTDIV */ +#define USART_BRR_DIV_MANTISSA_MASK (0xFFF << 4) +/* DIV_Fraction[3:0]: fraction of USARTDIV */ +#define USART_BRR_DIV_FRACTION_MASK 0xF + +/* --- USART_CR1 values ---------------------------------------------------- */ + +/* UE: USART enable */ +#define USART_CR1_UE (1 << 13) + +/* M: Word length */ +#define USART_CR1_M (1 << 12) + +/* WAKE: Wakeup method */ +#define USART_CR1_WAKE (1 << 11) + +/* PCE: Parity control enable */ +#define USART_CR1_PCE (1 << 10) + +/* PS: Parity selection */ +#define USART_CR1_PS (1 << 9) + +/* PEIE: PE interrupt enable */ +#define USART_CR1_PEIE (1 << 8) + +/* TXEIE: TXE interrupt enable */ +#define USART_CR1_TXEIE (1 << 7) + +/* TCIE: Transmission complete interrupt enable */ +#define USART_CR1_TCIE (1 << 6) + +/* RXNEIE: RXNE interrupt enable */ +#define USART_CR1_RXNEIE (1 << 5) + +/* IDLEIE: IDLE interrupt enable */ +#define USART_CR1_IDLEIE (1 << 4) + +/* TE: Transmitter enable */ +#define USART_CR1_TE (1 << 3) + +/* RE: Receiver enable */ +#define USART_CR1_RE (1 << 2) + +/* RWU: Receiver wakeup */ +#define USART_CR1_RWU (1 << 1) + +/* SBK: Send break */ +#define USART_CR1_SBK (1 << 0) + +/* --- USART_CR2 values ---------------------------------------------------- */ + +/* LINEN: LIN mode enable */ +#define USART_CR2_LINEN (1 << 14) + +/* STOP[13:12]: STOP bits */ +#define USART_CR2_STOPBITS_1 (0x00 << 12) /* 1 stop bit */ +#define USART_CR2_STOPBITS_0_5 (0x01 << 12) /* 0.5 stop bits */ +#define USART_CR2_STOPBITS_2 (0x02 << 12) /* 2 stop bits */ +#define USART_CR2_STOPBITS_1_5 (0x03 << 12) /* 1.5 stop bits */ +#define USART_CR2_STOPBITS_MASK (0x03 << 12) +#define USART_CR2_STOPBITS_SHIFT 12 + +/* CLKEN: Clock enable */ +#define USART_CR2_CLKEN (1 << 11) + +/* CPOL: Clock polarity */ +#define USART_CR2_CPOL (1 << 10) + +/* CPHA: Clock phase */ +#define USART_CR2_CPHA (1 << 9) + +/* LBCL: Last bit clock pulse */ +#define USART_CR2_LBCL (1 << 8) + +/* LBDIE: LIN break detection interrupt enable */ +#define USART_CR2_LBDIE (1 << 6) + +/* LBDL: LIN break detection length */ +#define USART_CR2_LBDL (1 << 5) + +/* ADD[3:0]: Address of the usart node */ +#define USART_CR2_ADD_MASK 0xF + +/* --- USART_CR3 values ---------------------------------------------------- */ + +/* CTSIE: CTS interrupt enable */ +/* Note: N/A on UART4 & UART5 */ +#define USART_CR3_CTSIE (1 << 10) + +/* CTSE: CTS enable */ +/* Note: N/A on UART4 & UART5 */ +#define USART_CR3_CTSE (1 << 9) + +/* RTSE: RTS enable */ +/* Note: N/A on UART4 & UART5 */ +#define USART_CR3_RTSE (1 << 8) + +/* DMAT: DMA enable transmitter */ +/* Note: N/A on UART5 */ +#define USART_CR3_DMAT (1 << 7) + +/* DMAR: DMA enable receiver */ +/* Note: N/A on UART5 */ +#define USART_CR3_DMAR (1 << 6) + +/* SCEN: Smartcard mode enable */ +/* Note: N/A on UART4 & UART5 */ +#define USART_CR3_SCEN (1 << 5) + +/* NACK: Smartcard NACK enable */ +/* Note: N/A on UART4 & UART5 */ +#define USART_CR3_NACK (1 << 4) + +/* HDSEL: Half-duplex selection */ +#define USART_CR3_HDSEL (1 << 3) + +/* IRLP: IrDA low-power */ +#define USART_CR3_IRLP (1 << 2) + +/* IREN: IrDA mode enable */ +#define USART_CR3_IREN (1 << 1) + +/* EIE: Error interrupt enable */ +#define USART_CR3_EIE (1 << 0) + +/* --- USART_GTPR values --------------------------------------------------- */ + +/* GT[7:0]: Guard time value */ +/* Note: N/A on UART4 & UART5 */ +#define USART_GTPR_GT_MASK (0xFF << 8) + +/* PSC[7:0]: Prescaler value */ +/* Note: N/A on UART4/5 */ +#define USART_GTPR_PSC_MASK 0xFF + +/* TODO */ /* Note to Uwe: what needs to be done here? */ + +#endif +/** @cond */ +#else +#warning "usart_common_all.h should not be included directly, only via usart.h" +#endif +/** @endcond */ +/**@}*/ + diff --git a/FourQ_ARM_side_channel/libopencm3/lib/libopencm3_stm32f4.a b/FourQ_ARM_side_channel/libopencm3/lib/libopencm3_stm32f4.a new file mode 100644 index 0000000..41321eb Binary files /dev/null and b/FourQ_ARM_side_channel/libopencm3/lib/libopencm3_stm32f4.a differ diff --git a/FourQ_ARM_side_channel/makefile b/FourQ_ARM_side_channel/makefile new file mode 100644 index 0000000..f7f3281 --- /dev/null +++ b/FourQ_ARM_side_channel/makefile @@ -0,0 +1,78 @@ +#### Makefile for compilation using GNU GCC or clang on ARM-based processors without using NEON #### + +OPT=-O3 # Optimization option by default + +CC=gcc +ifeq "$(CC)" "gcc" + COMPILER=gcc +else ifeq "$(CC)" "clang" + COMPILER=clang +endif + +ADDITIONAL_SETTINGS=-fwrapv -fomit-frame-pointer -funroll-loops +ifeq "$(EXTENDED_SET)" "FALSE" + ADDITIONAL_SETTINGS= +endif + +INLINING_SETTINGS= +ifeq "$(CC)" "gcc" + INLINING_SETTINGS=-finline-functions -finline-limit=100 +endif + +CFLAGS=-c $(OPT) $(ADDITIONAL_SETTINGS) -D _ARM_ -D __LINUX__ $(INLINING_SETTINGS) +LDFLAGS= +OBJECTS=eccp2.o fp2_1271_arm.o crypto_util.o schnorrq.o kex.o sha512.o random.o +OBJECTS_FP_TEST=$(OBJECTS) fp_tests.o test_extras.o +OBJECTS_ECC_TEST=ecc_tests.o test_extras.o $(OBJECTS) +OBJECTS_CRYPTO_TEST=crypto_tests.o $(OBJECTS) test_extras.o +OBJECTS_ALL=$(OBJECTS) $(OBJECTS_FP_TEST) $(OBJECTS_ECC_TEST) $(OBJECTS_CRYPTO_TEST) + +all: crypto_test ecc_test fp_test + +crypto_test: $(OBJECTS_CRYPTO_TEST) + $(CC) -o crypto_test $(OBJECTS_CRYPTO_TEST) -lrt + +ecc_test: $(OBJECTS_ECC_TEST) + $(CC) -o ecc_test $(OBJECTS_ECC_TEST) -lrt + +fp_test: $(OBJECTS_FP_TEST) + $(CC) -o fp_test $(OBJECTS_FP_TEST) -lrt + +eccp2.o: eccp2.c FourQ_internal.h ARM/fp_arm.h + $(CC) $(CFLAGS) eccp2.c + +fp2_1271_arm.o: ARM/fp2_1271_arm.S + $(CC) $(CFLAGS) ARM/fp2_1271_arm.S + +schnorrq.o: schnorrq.c + $(CC) $(CFLAGS) schnorrq.c + +kex.o: kex.c + $(CC) $(CFLAGS) kex.c + +crypto_util.o: crypto_util.c + $(CC) $(CFLAGS) crypto_util.c + +sha512.o: ../sha512/sha512.c + $(CC) $(CFLAGS) ../sha512/sha512.c + +random.o: ../random/random.c + $(CC) $(CFLAGS) ../random/random.c + +test_extras.o: tests/test_extras.c + $(CC) $(CFLAGS) tests/test_extras.c + +crypto_tests.o: tests/crypto_tests.c + $(CC) $(CFLAGS) tests/crypto_tests.c + +ecc_tests.o: tests/ecc_tests.c + $(CC) $(CFLAGS) tests/ecc_tests.c + +fp_tests.o: tests/fp_tests.c FourQ_internal.h + $(CC) $(CFLAGS) tests/fp_tests.c + +.PHONY: clean + +clean: + rm -f crypto_test ecc_test fp_test fp2_1271_arm.o $(OBJECTS_ALL) + diff --git a/FourQ_ARM_side_channel/makefile_Cortex-M4 b/FourQ_ARM_side_channel/makefile_Cortex-M4 new file mode 100644 index 0000000..49e091d --- /dev/null +++ b/FourQ_ARM_side_channel/makefile_Cortex-M4 @@ -0,0 +1,62 @@ +#### Makefile for compilation using GNU GCC on ARM-based Cortex-M4 microcontroller #### + +OPT=-Ofast # Optimization option by default + +INLINING_SETTINGS=-finline-functions -finline-limit=100 +LDSCRIPT = stm32f407x6.ld +CC=gcc +PREFIX = arm-none-eabi +ARMCC = $(PREFIX)-$(CC) + +ARCH_FLAGS = -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -MD -DSTM32F4 +CFLAGS = -c $(OPT) $(ADDITIONAL_SETTINGS) -D _ARM_ -D __LINUX__ $(INLINING_SETTINGS) -I./libopencm3/include -fno-common +LDFLAGS += --static -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group -T$(LDSCRIPT) -nostartfiles -Wl,--gc-sections $(ARCH_FLAGS) + +OBJECTS=eccp2.o fp2_1271_arm_Cortex-M4.o crypto_util.o schnorrq.o kex.o sha512.o test_extras.o random_Cortex-M4.o stm32f4_wrapper.o + +all: lib tests_Cortex-M4/crypto_tests.bin tests_Cortex-M4/ecc_tests.bin tests_Cortex-M4/fp_tests.bin + +lib: $(OBJECTS) + $(PREFIX)-ar cr tests_Cortex-M4/libfourq.a $(OBJECTS) + +tests_Cortex-M4/crypto_tests.bin: tests_Cortex-M4/crypto_tests.elf + $(PREFIX)-objcopy -Obinary tests_Cortex-M4/crypto_tests.elf tests_Cortex-M4/crypto_tests.bin + +tests_Cortex-M4/ecc_tests.bin: tests_Cortex-M4/ecc_tests.elf + $(PREFIX)-objcopy -Obinary tests_Cortex-M4/ecc_tests.elf tests_Cortex-M4/ecc_tests.bin + +tests_Cortex-M4/fp_tests.bin: tests_Cortex-M4/fp_tests.elf + $(PREFIX)-objcopy -Obinary tests_Cortex-M4/fp_tests.elf tests_Cortex-M4/fp_tests.bin + +tests_Cortex-M4/crypto_tests.elf: crypto_tests.o $(LDSCRIPT) tests_Cortex-M4/libfourq.a + $(ARMCC) -o tests_Cortex-M4/crypto_tests.elf crypto_tests.o tests_Cortex-M4/libfourq.a $(LDFLAGS) libopencm3/lib/libopencm3_stm32f4.a + +tests_Cortex-M4/ecc_tests.elf: ecc_tests.o $(LDSCRIPT) tests_Cortex-M4/libfourq.a + $(ARMCC) -o tests_Cortex-M4/ecc_tests.elf ecc_tests.o tests_Cortex-M4/libfourq.a $(LDFLAGS) libopencm3/lib/libopencm3_stm32f4.a + +tests_Cortex-M4/fp_tests.elf: fp_tests.o $(LDSCRIPT) tests_Cortex-M4/libfourq.a + $(ARMCC) -o tests_Cortex-M4/fp_tests.elf fp_tests.o tests_Cortex-M4/libfourq.a $(LDFLAGS) libopencm3/lib/libopencm3_stm32f4.a + +%.o: %.c + $(ARMCC) $(CFLAGS) $(ARCH_FLAGS) -o $@ -c $< + +%.o: tests_Cortex-M4/%.c + $(ARMCC) $(CFLAGS) $(ARCH_FLAGS) -o $@ -c $< + +%.o: random/%.c + $(ARMCC) $(CFLAGS) $(ARCH_FLAGS) -o $@ -c $< + +%.o: ../sha512/%.c + $(ARMCC) $(CFLAGS) $(ARCH_FLAGS) -o $@ -c $< + +%.o: ARM/%.S + $(ARMCC) $(CFLAGS) $(ARCH_FLAGS) -o $@ -c $< + +stm32f4_wrapper.o: stm32f4_wrapper.c + $(ARMCC) $(CFLAGS) $(ARCH_FLAGS) -Wno-overflow -o $@ -c $< + +.PHONY: clean + +clean: + rm -f *.d *.o tests_Cortex-M4/*.o tests_Cortex-M4/*.d tests_Cortex-M4/*.a tests_Cortex-M4/*.bin tests_Cortex-M4/*.elf + diff --git a/FourQ_ARM_side_channel/random/random_Cortex-M4.c b/FourQ_ARM_side_channel/random/random_Cortex-M4.c new file mode 100644 index 0000000..5ddc0ea --- /dev/null +++ b/FourQ_ARM_side_channel/random/random_Cortex-M4.c @@ -0,0 +1,21 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: pseudorandom generation functions +************************************************************************************/ + +#include "../FourQ_internal.h" +#include "../stm32f4_wrapper.h" + + +ECCRYPTO_STATUS random_bytes(unsigned char* random_array, unsigned int nbytes) +{ // Generation of "nbytes" of random bytes + + if ((nbytes & 0x03) != 0) return ECCRYPTO_ERROR_INVALID_PARAMETER; + + rng_setup(); + random_int((uint32_t*)random_array, nbytes/4); + return ECCRYPTO_SUCCESS; +} diff --git a/FourQ_ARM_side_channel/schnorrq.c b/FourQ_ARM_side_channel/schnorrq.c new file mode 100644 index 0000000..73e6948 --- /dev/null +++ b/FourQ_ARM_side_channel/schnorrq.c @@ -0,0 +1,223 @@ +/********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: digital signature SchnorrQ +* +* See "SchnorrQ: Schnorr signatures on FourQ" by Craig Costello and Patrick Longa, +* MSR Technical Report, 2016. Available at: +* https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/SchnorrQ.pdf. +***********************************************************************************/ + +#include "FourQ_internal.h" +#include "FourQ_params.h" +#include "../random/random.h" +#include "../sha512/sha512.h" +#include +#include + + +ECCRYPTO_STATUS SchnorrQ_KeyGeneration_SCA_secure(const unsigned char* SecretKey, unsigned char* PublicKey, unsigned char* BlindingPoint) +{ // SchnorrQ public key generation + // It produces a blinding point BlindingPoint and a public key PublicKey, which is the encoding of P = s*G, where G is the generator and + // s is the output of hashing SecretKey and taking the least significant 32 bytes of the result. + // Input: 32-byte SecretKey + // Output: 32-byte PublicKey and 64-byte BlindingPoint + point_t G, R; + point_extedwards_t S; + unsigned char k[64], SecretBlinding[32]; + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + Status = RandomBytesFunction(SecretBlinding, 32); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + // Set up an initial "weak" blinding point R + fp2copy1271((felm_t*)&GENERATOR_x[0], G->x); + fp2copy1271((felm_t*)&GENERATOR_y[0], G->y); + point_setup(G, S); + eccdouble(S); + eccnorm(S, R); + + // Computing an initial blinding point. This computation itself is not protected with a secure point blinding + Status = ecc_mul_SCA_secure(G, R, (digit_t*)SecretBlinding, (point_affine*)BlindingPoint, false); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + if (CryptoHashFunction(SecretKey, 32, k) != 0) { + Status = ECCRYPTO_ERROR; + goto cleanup; + } + + Status = ecc_mul_SCA_secure(G, (point_affine*)BlindingPoint, (digit_t*)k, R, false); // Compute public key + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + encode(R, PublicKey); // Encode public key + +// Cleanup + clear_words((unsigned int*)SecretBlinding, 256/(sizeof(unsigned int)*8)); + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)SecretBlinding, 256/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)BlindingPoint, 512/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)k, 512/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)PublicKey, 256/(sizeof(unsigned int)*8)); + + return Status; +} + + +ECCRYPTO_STATUS SchnorrQ_FullKeyGeneration_SCA_secure(unsigned char* SecretKey, unsigned char* PublicKey, unsigned char* BlindingPoint) +{ // SchnorrQ keypair generation + // It produces a blinding point BlindingPoint, a private key SecretKey and computes the public key PublicKey, which is the encoding of P = s*G, + // where G is the generator and s is the output of hashing SecretKey and taking the least significant 32 bytes of the result. + // Outputs: 32-byte SecretKey, 32-byte PublicKey and 64-byte BlindingPoint + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + Status = RandomBytesFunction(SecretKey, 32); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + Status = SchnorrQ_KeyGeneration_SCA_secure(SecretKey, PublicKey, BlindingPoint); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + return ECCRYPTO_SUCCESS; + +cleanup: + clear_words((unsigned int*)SecretKey, 256/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)PublicKey, 256/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)BlindingPoint, 512/(sizeof(unsigned int)*8)); + + return Status; +} + + +ECCRYPTO_STATUS SchnorrQ_Sign_SCA_secure(const unsigned char* SecretKey, const unsigned char* PublicKey, const unsigned char* Message, const unsigned int SizeMessage, unsigned char* Signature, unsigned char* BlindingPoint) +{ // SchnorrQ signature generation + // It produces the signature Signature of a message Message of size SizeMessage in bytes + // Inputs: 32-byte SecretKey, 32-byte PublicKey, Message of size SizeMessage in bytes, and 64-byte BlindingPoint + // Output: 64-byte Signature and updated BlindingPoint + point_t G, R; + unsigned char k[64], r[64], h[64], *temp = NULL; + digit_t* H = (digit_t*)h; + digit_t* S = (digit_t*)(Signature+32); + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + if (CryptoHashFunction(SecretKey, 32, k) != 0) { + Status = ECCRYPTO_ERROR; + goto cleanup; + } + + temp = (unsigned char*)calloc(1, SizeMessage+64); + if (temp == NULL) { + Status = ECCRYPTO_ERROR_NO_MEMORY; + goto cleanup; + } + + memmove(temp+32, k+32, 32); + memmove(temp+64, Message, SizeMessage); + + if (CryptoHashFunction(temp+32, SizeMessage+32, r) != 0) { + Status = ECCRYPTO_ERROR; + goto cleanup; + } + + fp2copy1271((felm_t*)&GENERATOR_x[0], G->x); + fp2copy1271((felm_t*)&GENERATOR_y[0], G->y); + + Status = ecc_mul_SCA_secure(G, (point_affine*)BlindingPoint, (digit_t*)r, R, false); // Also verifies that BlindingPoint is a point on the curve. If not, it fails + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + encode(R, Signature); // Encode lowest 32 bytes of signature + memmove(temp, Signature, 32); + memmove(temp+32, PublicKey, 32); + + if (CryptoHashFunction(temp, SizeMessage+64, h) != 0) { + Status = ECCRYPTO_ERROR; + goto cleanup; + } + modulo_order((digit_t*)r, (digit_t*)r); + modulo_order(H, H); + to_Montgomery((digit_t*)k, S); // Converting to Montgomery representation + to_Montgomery(H, H); // Converting to Montgomery representation + Montgomery_multiply_mod_order(S, H, S); + from_Montgomery(S, S); // Converting back to standard representation + subtract_mod_order((digit_t*)r, S, S); + Status = ECCRYPTO_SUCCESS; + +cleanup: + if (temp != NULL) + free(temp); + clear_words((unsigned int*)k, 512/(sizeof(unsigned int)*8)); + clear_words((unsigned int*)r, 512/(sizeof(unsigned int)*8)); + + return Status; +} + + +ECCRYPTO_STATUS SchnorrQ_Verify(const unsigned char* PublicKey, const unsigned char* Message, const unsigned int SizeMessage, const unsigned char* Signature, unsigned int* valid) +{ // SchnorrQ signature verification + // It verifies the signature Signature of a message Message of size SizeMessage in bytes + // Inputs: 32-byte PublicKey, 64-byte Signature, and Message of size SizeMessage in bytes + // Output: true (valid signature) or false (invalid signature) + point_t A; + unsigned char *temp, h[64]; + unsigned int i; + ECCRYPTO_STATUS Status = ECCRYPTO_ERROR_UNKNOWN; + + *valid = false; + + temp = (unsigned char*)calloc(1, SizeMessage+64); + if (temp == NULL) { + Status = ECCRYPTO_ERROR_NO_MEMORY; + goto cleanup; + } + + if (((PublicKey[15] & 0x80) != 0) || ((Signature[15] & 0x80) != 0) || (Signature[63] != 0) || ((Signature[62] & 0xC0) != 0)) { // Are bit128(PublicKey) = bit128(Signature) = 0 and Signature+32 < 2^246? + Status = ECCRYPTO_ERROR_INVALID_PARAMETER; + goto cleanup; + } + + Status = decode(PublicKey, A); // Also verifies that A is on the curve. If it is not, it fails + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + memmove(temp, Signature, 32); + memmove(temp+32, PublicKey, 32); + memmove(temp+64, Message, SizeMessage); + + if (CryptoHashFunction(temp, SizeMessage+64, h) != 0) { + Status = ECCRYPTO_ERROR; + goto cleanup; + } + + Status = ecc_mul_double((digit_t*)(Signature+32), A, (digit_t*)h, A); + if (Status != ECCRYPTO_SUCCESS) { + goto cleanup; + } + + encode(A, (unsigned char*)A); + + for (i = 0; i < NWORDS_ORDER; i++) { + if (((digit_t*)A)[i] != ((digit_t*)Signature)[i]) { + goto cleanup; + } + } + *valid = true; + +cleanup: + if (temp != NULL) + free(temp); + + return Status; +} \ No newline at end of file diff --git a/FourQ_ARM_side_channel/stm32f407x6.ld b/FourQ_ARM_side_channel/stm32f407x6.ld new file mode 100644 index 0000000..63aea2e --- /dev/null +++ b/FourQ_ARM_side_channel/stm32f407x6.ld @@ -0,0 +1,114 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2011 Stephen Caudle + * Copyright (C) 2013 Sergey Krukowski + * Copyright (C) 2015 Joost Rijneveld + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for the STM32F407VGT6 chip (1024K flash, 192K RAM). */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K + ccm (rwx) : ORIGIN = 0x10000000, LENGTH = 64K +} +/* Enforce emmition of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + .text : { + *(.vectors) /* Vector table */ + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); + diff --git a/FourQ_ARM_side_channel/stm32f4_wrapper.c b/FourQ_ARM_side_channel/stm32f4_wrapper.c new file mode 100644 index 0000000..a88b331 --- /dev/null +++ b/FourQ_ARM_side_channel/stm32f4_wrapper.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include +#include "stm32f4_wrapper.h" + + +void clock_setup(void) +{ + rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_48MHZ]); + rcc_periph_clock_enable(RCC_GPIOD); + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_USART2); + rcc_periph_clock_enable(RCC_DMA1); + rcc_periph_clock_enable(RCC_RNG); +} + +void gpio_setup(void) +{ + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2 | GPIO3); + gpio_set_af(GPIOA, GPIO_AF7, GPIO2 | GPIO3); + gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT,GPIO_PUPD_NONE, GPIO12); +} + +void usart_setup(int baud) +{ + usart_set_baudrate(USART2, baud); + usart_set_databits(USART2, 8); + usart_set_stopbits(USART2, USART_STOPBITS_1); + usart_set_mode(USART2, USART_MODE_TX_RX); + usart_set_parity(USART2, USART_PARITY_NONE); + usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE); + usart_enable(USART2); + gpio_set(GPIOD, GPIO12); +} + +void rng_setup(void) +{ + RNG_CR |= RNG_CR_IE; + RNG_CR |= RNG_CR_RNGEN; +} + +void send_USART_str(const unsigned char* in) +{ + gpio_toggle(GPIOD, GPIO12); + int i; + + for(i = 0; in[i] != 0; i++) { + usart_send_blocking(USART2, in[i]); + } + usart_send_blocking(USART2, '\r'); + usart_send_blocking(USART2, '\n'); +} + +void signal_host(void) +{ + usart_send_blocking(USART2, (char)4); +} + +void random_int(uint32_t* urnd, int n) +{ + unsigned int last_value=0; + unsigned int new_value=0; + int i; + unsigned int error_bits = 0; + + for(i = 0; i < n; i++) + { + error_bits = RNG_SR_SEIS | RNG_SR_CEIS; + while (new_value == last_value) { + if (((RNG_SR & error_bits) == 0) && ((RNG_SR & RNG_SR_DRDY) == 1)) { + new_value = RNG_DR; + } + } + last_value = new_value; + urnd[i] = new_value; + } +} \ No newline at end of file diff --git a/FourQ_ARM_side_channel/stm32f4_wrapper.h b/FourQ_ARM_side_channel/stm32f4_wrapper.h new file mode 100644 index 0000000..cc366f6 --- /dev/null +++ b/FourQ_ARM_side_channel/stm32f4_wrapper.h @@ -0,0 +1,14 @@ +#ifndef STM32F4_WRAPPER_H +#define STM32F4_WRAPPER_H + + +void clock_setup(void); +void gpio_setup(void); +void usart_setup(int baud); +void rng_setup(void); +void signal_host(void); +void send_USART_str(const unsigned char* in); +void random_int(uint32_t*,int); + + +#endif diff --git a/FourQ_ARM_side_channel/table_lookup.h b/FourQ_ARM_side_channel/table_lookup.h new file mode 100644 index 0000000..dec2499 --- /dev/null +++ b/FourQ_ARM_side_channel/table_lookup.h @@ -0,0 +1,78 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: table lookup functions +************************************************************************************/ + +#ifndef __TABLE_LOOKUP_H__ +#define __TABLE_LOOKUP_H__ + + +// For C++ +#ifdef __cplusplus +extern "C" { +#endif + + +#include "FourQ_internal.h" + + +void table_lookup_1x16(point_extedwards_t* table, point_extedwards_t P, unsigned int digit) +{ // Constant-time table lookup using "interleaved" masking to extract a point represented as (X,Y,Z,T) in extended twisted Edwards coordinates + // Inputs: digit and table containing 16 points + // Output: P = table[digit] + point_extedwards_t point; + unsigned int i, j; + digit_t mask, temp, value = 0xAAAAAAAA; + f2elm_t tt; + + ecccopy(table[0], point); // point = table[0] + + for (i = 1; i < 16; i++) + { + digit--; + // While digit>=0 mask = 0x55...5 else mask = 0xAA...A + mask = ((digit_t)digit >> (RADIX-1)) - 1; + mask = (mask & ~value) | (~mask & value); + + fp2copy1271(table[i]->x, tt); // tt = table[i] + for (j = 0; j < NWORDS_FIELD; j++) { + temp = point->x[0][j] ^ tt[0][j]; + point->x[0][j] = ((mask & temp) ^ point->x[0][j]) ^ (value & temp); + temp = point->x[1][j] ^ tt[1][j]; + point->x[1][j] = ((mask & temp) ^ point->x[1][j]) ^ (value & temp); + } + fp2copy1271(table[i]->y, tt); + for (j = 0; j < NWORDS_FIELD; j++) { + temp = point->y[0][j] ^ tt[0][j]; + point->y[0][j] = ((mask & temp) ^ point->y[0][j]) ^ (value & temp); + temp = point->y[1][j] ^ tt[1][j]; + point->y[1][j] = ((mask & temp) ^ point->y[1][j]) ^ (value & temp); + } + fp2copy1271(table[i]->z, tt); + for (j = 0; j < NWORDS_FIELD; j++) { + temp = point->z[0][j] ^ tt[0][j]; + point->z[0][j] = ((mask & temp) ^ point->z[0][j]) ^ (value & temp); + temp = point->z[1][j] ^ tt[1][j]; + point->z[1][j] = ((mask & temp) ^ point->z[1][j]) ^ (value & temp); + } + fp2copy1271(table[i]->t, tt); + for (j = 0; j < NWORDS_FIELD; j++) { + temp = point->t[0][j] ^ tt[0][j]; + point->t[0][j] = ((mask & temp) ^ point->t[0][j]) ^ (value & temp); + temp = point->t[1][j] ^ tt[1][j]; + point->t[1][j] = ((mask & temp) ^ point->t[1][j]) ^ (value & temp); + } + } + ecccopy(point, P); +} + + +#ifdef __cplusplus +} +#endif + + +#endif \ No newline at end of file diff --git a/FourQ_ARM_side_channel/tests/crypto_tests.c b/FourQ_ARM_side_channel/tests/crypto_tests.c new file mode 100644 index 0000000..49c73e4 --- /dev/null +++ b/FourQ_ARM_side_channel/tests/crypto_tests.c @@ -0,0 +1,368 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: testing code for cryptographic functions based on FourQ +************************************************************************************/ + +#include "../FourQ_api.h" +#include "../FourQ_params.h" +#include "test_extras.h" +#include + + +// Benchmark and test parameters +#if defined(GENERIC_IMPLEMENTATION) + #define BENCH_LOOPS 100 // Number of iterations per bench + #define TEST_LOOPS 100 // Number of iterations per test +#else + #define BENCH_LOOPS 10000 + #define TEST_LOOPS 1000 +#endif + + +ECCRYPTO_STATUS SchnorrQ_test() +{ // Test the SchnorrQ digital signature scheme + int n, passed; + void *msg = NULL; + unsigned int len, valid = false; + unsigned char SecretKey[32], PublicKey[32], Signature[64], BlindingPoint[64]; + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + printf("\n--------------------------------------------------------------------------------------------------------\n\n"); + printf("Testing the SchnorrQ signature scheme. Includes side-channel countermeasures: \n\n"); + + passed = 1; + for (n = 0; n < TEST_LOOPS; n++) + { + // Signature key generation + Status = SchnorrQ_FullKeyGeneration_SCA_secure(SecretKey, PublicKey, BlindingPoint); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + + // Signature computation + msg = "a"; + len = 1; + Status = SchnorrQ_Sign_SCA_secure(SecretKey, PublicKey, msg, len, Signature, BlindingPoint); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + + // Valid signature test + Status = SchnorrQ_Verify(PublicKey, msg, len, Signature, &valid); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + if (valid == false) { + passed = 0; + break; + } + + // Invalid signature test (flipping one bit of the message) + msg = "b"; + Status = SchnorrQ_Verify(PublicKey, msg, len, Signature, &valid); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + if (valid == true) { + passed = 0; + break; + } + } + if (passed==1) printf(" Signature tests.................................................................. PASSED"); + else { printf(" Signature tests... FAILED"); printf("\n"); Status = ECCRYPTO_ERROR_SIGNATURE_VERIFICATION; } + printf("\n"); + + return Status; +} + + +ECCRYPTO_STATUS SchnorrQ_run() +{ // Benchmark the SchnorrQ digital signature scheme + int n; + unsigned long long nsec, nsec1, nsec2; + void *msg = NULL; + unsigned int len = 0, valid = false; + unsigned char SecretKey[32], PublicKey[32], Signature[64], BlindingPoint[64]; + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + printf("\n--------------------------------------------------------------------------------------------------------\n\n"); + printf("Benchmarking the SchnorrQ signature scheme. Includes side-channel countermeasures: \n\n"); + + nsec = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + nsec1 = cpu_nseconds(); + Status = SchnorrQ_FullKeyGeneration_SCA_secure(SecretKey, PublicKey, BlindingPoint); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + nsec2 = cpu_nseconds(); + nsec = nsec+(nsec2-nsec1); + } + printf(" SchnorrQ's key generation runs in ............................................... %8lld nsec", nsec/BENCH_LOOPS); + printf("\n"); + + nsec = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + nsec1 = cpu_nseconds(); + Status = SchnorrQ_Sign_SCA_secure(SecretKey, PublicKey, msg, len, Signature, BlindingPoint); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + nsec2 = cpu_nseconds(); + nsec = nsec+(nsec2-nsec1); + } + printf(" SchnorrQ's signing runs in ...................................................... %8lld nsec", nsec/BENCH_LOOPS); + printf("\n"); + + nsec = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + nsec1 = cpu_nseconds(); + Status = SchnorrQ_Verify(PublicKey, msg, len, Signature, &valid); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + nsec2 = cpu_nseconds(); + nsec = nsec+(nsec2-nsec1); + } + printf(" SchnorrQ's verification runs in ................................................. %8lld nsec", nsec/BENCH_LOOPS); + printf("\n"); + + return Status; +} + + +ECCRYPTO_STATUS compressedkex_test() +{ // Test ECDH key exchange based on FourQ + int n, passed; + unsigned int i; + unsigned char SecretKeyA[32], PublicKeyA[32], BlindingPointA[64], SecretAgreementA[32]; + unsigned char SecretKeyB[32], PublicKeyB[32], BlindingPointB[64], SecretAgreementB[32]; + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + printf("\n--------------------------------------------------------------------------------------------------------\n\n"); + printf("Testing DH key exchange using compressed, 32-byte public keys. Includes side-channel countermeasures: \n\n"); + + passed = 1; + for (n = 0; n < TEST_LOOPS; n++) + { + // Alice's keypair generation + Status = CompressedKeyGeneration_SCA_secure(SecretKeyA, PublicKeyA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + // Bob's keypair generation + Status = CompressedKeyGeneration_SCA_secure(SecretKeyB, PublicKeyB, BlindingPointB); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + + // Alice's shared secret computation + Status = CompressedSecretAgreement_SCA_secure(SecretKeyA, PublicKeyB, SecretAgreementA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + // Bob's shared secret computation + Status = CompressedSecretAgreement_SCA_secure(SecretKeyB, PublicKeyA, SecretAgreementB, BlindingPointB); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + + for (i = 0; i < 32; i++) { + if (SecretAgreementA[i] != SecretAgreementB[i]) { + passed = 0; + break; + } + } + } + if (passed==1) printf(" DH key exchange tests............................................................ PASSED"); + else { printf(" DH key exchange tests... FAILED"); printf("\n"); Status = ECCRYPTO_ERROR_SHARED_KEY; } + printf("\n"); + + return Status; +} + + +ECCRYPTO_STATUS compressedkex_run() +{ // Benchmark ECDH key exchange based on FourQ + int n; + unsigned long long nsec, nsec1, nsec2; + unsigned char SecretKeyA[32], PublicKeyA[32], BlindingPointA[64], SecretAgreementA[32]; + unsigned char SecretKeyB[32], PublicKeyB[32], BlindingPointB[64]; + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + printf("\n--------------------------------------------------------------------------------------------------------\n\n"); + printf("Benchmarking DH key exchange using compressed, 32-byte public keys. Includes side-channel countermeasures: \n\n"); + + nsec = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + nsec1 = cpu_nseconds(); + Status = CompressedKeyGeneration_SCA_secure(SecretKeyA, PublicKeyA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + nsec2 = cpu_nseconds(); + nsec = nsec + (nsec2 - nsec1); + } + printf(" Keypair generation runs in ...................................................... %8lld nsec", nsec / BENCH_LOOPS); + printf("\n"); + + Status = CompressedKeyGeneration_SCA_secure(SecretKeyB, PublicKeyB, BlindingPointB); + nsec = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + nsec1 = cpu_nseconds(); + Status = CompressedSecretAgreement_SCA_secure(SecretKeyA, PublicKeyB, SecretAgreementA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + nsec2 = cpu_nseconds(); + nsec = nsec + (nsec2 - nsec1); + } + printf(" Secret agreement runs in ........................................................ %8lld nsec", nsec / BENCH_LOOPS); + printf("\n"); + + return Status; +} + + +ECCRYPTO_STATUS kex_test() +{ // Test ECDH key exchange based on FourQ + int n, passed; + unsigned int i; + unsigned char SecretKeyA[32], PublicKeyA[64], BlindingPointA[64], SecretAgreementA[32]; + unsigned char SecretKeyB[32], PublicKeyB[64], BlindingPointB[64], SecretAgreementB[32]; + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + printf("\n--------------------------------------------------------------------------------------------------------\n\n"); + printf("Testing DH key exchange using uncompressed, 64-byte public keys. Includes side-channel countermeasures: \n\n"); + + passed = 1; + for (n = 0; n < TEST_LOOPS; n++) + { + // Alice's keypair generation + Status = KeyGeneration_SCA_secure(SecretKeyA, PublicKeyA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + // Bob's keypair generation + Status = KeyGeneration_SCA_secure(SecretKeyB, PublicKeyB, BlindingPointB); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + + // Alice's shared secret computation + Status = SecretAgreement_SCA_secure(SecretKeyA, PublicKeyB, SecretAgreementA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + // Bob's shared secret computation + Status = SecretAgreement_SCA_secure(SecretKeyB, PublicKeyA, SecretAgreementB, BlindingPointB); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + + for (i = 0; i < 32; i++) { + if (SecretAgreementA[i] != SecretAgreementB[i]) { + passed = 0; + break; + } + } + } + if (passed==1) printf(" DH key exchange tests............................................................ PASSED"); + else { printf(" DH key exchange tests... FAILED"); printf("\n"); Status = ECCRYPTO_ERROR_SHARED_KEY; } + printf("\n"); + + return Status; +} + + +ECCRYPTO_STATUS kex_run() +{ // Benchmark ECDH key exchange based on FourQ + int n; + unsigned long long nsec, nsec1, nsec2; + unsigned char SecretKeyA[32], PublicKeyA[64], BlindingPointA[64], SecretAgreementA[32]; + unsigned char SecretKeyB[32], PublicKeyB[64], BlindingPointB[64]; + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + printf("\n--------------------------------------------------------------------------------------------------------\n\n"); + printf("Benchmarking DH key exchange using uncompressed, 64-byte public keys. Includes side-channel countermeasures: \n\n"); + + nsec = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + nsec1 = cpu_nseconds(); + Status = KeyGeneration_SCA_secure(SecretKeyA, PublicKeyA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + nsec2 = cpu_nseconds(); + nsec = nsec + (nsec2 - nsec1); + } + printf(" Keypair generation runs in ...................................................... %8lld nsec", nsec / BENCH_LOOPS); + printf("\n"); + + Status = KeyGeneration_SCA_secure(SecretKeyB, PublicKeyB, BlindingPointB); + nsec = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + nsec1 = cpu_nseconds(); + Status = SecretAgreement_SCA_secure(SecretKeyA, PublicKeyB, SecretAgreementA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + nsec2 = cpu_nseconds(); + nsec = nsec + (nsec2 - nsec1); + } + printf(" Secret agreement runs in ........................................................ %8lld nsec", nsec / BENCH_LOOPS); + printf("\n"); + + return Status; +} + + +int main() +{ + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + Status = SchnorrQ_test(); // Test SchnorrQ signature scheme + if (Status != ECCRYPTO_SUCCESS) { + printf("\n\n Error detected: %s \n\n", FourQ_get_error_message(Status)); + return false; + } + Status = SchnorrQ_run(); // Benchmark SchnorrQ signature scheme + if (Status != ECCRYPTO_SUCCESS) { + printf("\n\n Error detected: %s \n\n", FourQ_get_error_message(Status)); + return false; + } + + Status = compressedkex_test(); // Test Diffie-Hellman key exchange using compressed public keys + if (Status != ECCRYPTO_SUCCESS) { + printf("\n\n Error detected: %s \n\n", FourQ_get_error_message(Status)); + return false; + } + Status = compressedkex_run(); // Benchmark Diffie-Hellman key exchange using compressed public keys + if (Status != ECCRYPTO_SUCCESS) { + printf("\n\n Error detected: %s \n\n", FourQ_get_error_message(Status)); + return false; + } + + Status = kex_test(); // Test Diffie-Hellman key exchange using uncompressed public keys + if (Status != ECCRYPTO_SUCCESS) { + printf("\n\n Error detected: %s \n\n", FourQ_get_error_message(Status)); + return false; + } + Status = kex_run(); // Benchmark Diffie-Hellman key exchange using uncompressed public keys + if (Status != ECCRYPTO_SUCCESS) { + printf("\n\n Error detected: %s \n\n", FourQ_get_error_message(Status)); + return false; + } + + return true; +} \ No newline at end of file diff --git a/FourQ_ARM_side_channel/tests/ecc_tests.c b/FourQ_ARM_side_channel/tests/ecc_tests.c new file mode 100644 index 0000000..0d9a261 --- /dev/null +++ b/FourQ_ARM_side_channel/tests/ecc_tests.c @@ -0,0 +1,456 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: testing code for FourQ's curve arithmetic +************************************************************************************/ + +#include "../FourQ_api.h" +#include "../FourQ_params.h" +#include "../FourQ_tables.h" +#include "test_extras.h" +#include + + +// Benchmark and test parameters +#define BENCH_LOOPS 100 // Number of iterations per bench +#define SHORT_BENCH_LOOPS 10 // Number of iterations per bench (for expensive operations) +#define TEST_LOOPS 1000 // Number of iterations per test + + +bool ecc_test() +{ + bool clear_cofactor, OK = true; + unsigned int n; + int passed; + point_t A, R; + point_extedwards_t P, Q; + f2elm_t t1; + uint64_t scalar[4], res_x[4], res_y[4]; + + + printf("\n--------------------------------------------------------------------------------------------------------\n\n"); + printf("Testing FourQ's curve arithmetic: \n\n"); + + // Point doubling + passed = 1; + eccset(A); + point_setup(A, P); + + for (n=0; nx[0]); mod1271(A->x[1]); // Fully reduced P + mod1271(A->y[0]); mod1271(A->y[1]); + + // Result + res_x[0] = 0xC9099C54855859D6; res_x[1] = 0x2C3FD8822C82270F; res_x[2] = 0xA7B3F6E2043E8E68; res_x[3] = 0x4DA5B9E83AA7A1B2; + res_y[0] = 0x3EE089F0EB49AA14; res_y[1] = 0x2001EB3A57688396; res_y[2] = 0x1FEE5617A7E954CD; res_y[3] = 0x0FFDB0D761421F50; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + if (passed==1) printf(" Point doubling tests .................................................................... PASSED"); + else { printf(" Point doubling tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + + // Point addition + eccset(A); + point_setup(A, P); + + for (n=0; nx[0]); mod1271(A->x[1]); // Fully reduced P + mod1271(A->y[0]); mod1271(A->y[1]); + + // Result + res_x[0] = 0xC9099C54855859D6; res_x[1] = 0x2C3FD8822C82270F; res_x[2] = 0xA7B3F6E2043E8E68; res_x[3] = 0x4DA5B9E83AA7A1B2; + res_y[0] = 0x3EE089F0EB49AA14; res_y[1] = 0x2001EB3A57688396; res_y[2] = 0x1FEE5617A7E954CD; res_y[3] = 0x0FFDB0D761421F50; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + eccset(A); + point_setup(A, P); + ecccopy(P, Q); + eccdouble(P); // P = 2P + + for (n=0; nx[0]); mod1271(A->x[1]); // Fully reduced P + mod1271(A->y[0]); mod1271(A->y[1]); + + // Result + res_x[0] = 0x6480B1EF0A151DB0; res_x[1] = 0x3E243958590C4D90; res_x[2] = 0xAA270F644A65D473; res_x[3] = 0x5327AF7D84238CD0; + res_y[0] = 0x5E06003D73C43EB1; res_y[1] = 0x3EF69A49CB7E0237; res_y[2] = 0x4E752648AC2EF0AB; res_y[3] = 0x293EB1E26DD23B4E; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + if (passed==1) printf(" Point addition tests .................................................................... PASSED"); + else { printf(" Point addition tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + + // Psi endomorphism + eccset(A); + point_setup(A, P); + + for (n=0; nx[0]); mod1271(A->x[1]); // Fully reduced P + mod1271(A->y[0]); mod1271(A->y[1]); + + // Result + res_x[0] = 0xD8F3C8C24A2BC7E2; res_x[1] = 0x75AF54EDB41A2B93; res_x[2] = 0x4DE2466701F009A9; res_x[3] = 0x065249F9EDE0C798; + res_y[0] = 0x1C6E119ADD608104; res_y[1] = 0x06DBB85BFFB7C21E; res_y[2] = 0xFD234D6C4CFA3EC1; res_y[3] = 0x060A30903424BF13; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + if (passed==1) printf(" Psi endomorphism tests .................................................................. PASSED"); + else { printf(" Psi endomorphism tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + + // Phi endomorphism + eccset(A); + point_setup(A, P); + + for (n=0; nx[0]); mod1271(A->x[1]); // Fully reduced P + mod1271(A->y[0]); mod1271(A->y[1]); + + // Result + res_x[0] = 0xD5B5A3061287DB16; res_x[1] = 0x5550AAB9E7A620EE; res_x[2] = 0xEC321E6CF33610FC; res_x[3] = 0x3E61EBB9A1CB0210; + res_y[0] = 0x7E2851D5A8E83FB9; res_y[1] = 0x5474BF8EC55603AE; res_y[2] = 0xA5077613491788D5; res_y[3] = 0x5476093DBF8BF6BF; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + if (passed==1) printf(" Phi endomorphism tests .................................................................. PASSED"); + else { printf(" Phi endomorphism tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + + // Scalar multiplication + eccset(A); + eccset(R); + clear_cofactor = false; + scalar[0] = 0x3AD457AB55456230; scalar[1] = 0x3A8B3C2C6FD86E0C; scalar[2] = 0x7E38F7C9CFBB9166; scalar[3] = 0x0028FD6CBDA458F0; + + for (n=0; nx, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + + eccset(A); + eccset(R); + clear_cofactor = true; + scalar[0] = 0x3AD457AB55456230; scalar[1] = 0x3A8B3C2C6FD86E0C; scalar[2] = 0x7E38F7C9CFBB9166; scalar[3] = 0x0028FD6CBDA458F0; + + for (n=0; nx, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + if (passed==1) printf(" Scalar multiplication tests ............................................................. PASSED"); + else { printf(" Scalar multiplication tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + + { + point_t PP, QQ, RR, UU, TT; + point_extedwards_t AA, BB; + uint64_t k[4], l[4], kk[4]; + + // Double scalar multiplication + eccset(QQ); + eccset(PP); + eccset(R); + + for (n=0; nx,(uint64_t*)RR->x)!=0 || fp2compare64((uint64_t*)UU->y,(uint64_t*)RR->y)!=0) { passed=0; break; } + } + + if (passed==1) printf(" Double scalar multiplication tests ...................................................... PASSED"); + else { printf(" Double scalar multiplication tests ... FAILED"); printf("\n"); return false; } + printf("\n"); + } + + return OK; +} + + +bool ecc_run() +{ + bool OK = true; + unsigned int n, i, digit=1; + unsigned long long nsec, nsec1, nsec2; + point_t A, B, R; + point_extedwards_t P, Q, RR, Table[16]; + f2elm_t t1; + uint64_t scalar[4]; + + printf("\n--------------------------------------------------------------------------------------------------------\n\n"); + printf("Benchmarking FourQ's curve arithmetic \n\n"); + + // Point doubling (twisted Edwards a=-1) + eccset(A); + point_setup(A, P); + + nsec = 0; + for (n=0; n + + +// Benchmark and test parameters +#define BENCH_LOOPS 10000 // Number of iterations per bench +#define SHORT_BENCH_LOOPS 1000 // Number of iterations per bench (for expensive operations) +#define TEST_LOOPS 1000 // Number of iterations per test + + +bool fp2_test() +{ // Tests for the quadratic extension field arithmetic + bool OK = true; + int n, passed; + f2elm_t a, b, c, d, e, f; + + printf("\n--------------------------------------------------------------------------------------------------------\n\n"); + printf("Testing quadratic extension field arithmetic over GF((2^127-1)^2): \n\n"); + + // GF(p^2) multiplication using p = 2^127-1 + passed = 1; + for (n=0; n> 1; + rand_f2elmt[j][1][NWORDS_FIELD-1] &= (digit_t)(-1) >> 1; + } + } + nsec2 = cpu_nseconds(); + nsec = nsec+(nsec2-nsec1); + } + printf(" PRNG generation for scalar mul runs in . %8lld nsec", nsec/(SHORT_BENCH_LOOPS*10)); + printf("\n"); + + return OK; +} + + +int main() +{ + bool OK = true; + + OK = OK && fp2_test(); // Test quadratic extension field operations using p = 2^127-1 + OK = OK && fp2_run(); // Benchmark quadratic extension field operations using p = 2^127-1 + + return OK; +} diff --git a/FourQ_ARM_side_channel/tests/test_extras.c b/FourQ_ARM_side_channel/tests/test_extras.c new file mode 100644 index 0000000..45b8e0a --- /dev/null +++ b/FourQ_ARM_side_channel/tests/test_extras.c @@ -0,0 +1,137 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: utility functions for tests +************************************************************************************/ + +#include "../FourQ_internal.h" +#include "test_extras.h" +#if (OS_TARGET == OS_LINUX) && (TARGET == TARGET_ARM) + #include +#endif +#include +#include +#include + + +int64_t cpu_nseconds(void) +{ // Access system counter for benchmarking + struct timespec time; + + clock_gettime(CLOCK_REALTIME, &time); + return (int64_t)(time.tv_sec*1e9 + time.tv_nsec); +} + + +int fp2compare64(uint64_t* a, uint64_t* b) +{ // Comparing uint64_t digits of two quadratic extension field elements, ai=bi? : (0) equal, (1) unequal + // NOTE: this function does not have constant-time execution. TO BE USED FOR TESTING ONLY. + unsigned int i; + + for (i = 0; i < (2*NWORDS64_FIELD); i++) { + if (a[i] != b[i]) return 1; + } + + return 0; +} + + +void random_scalar_test(uint64_t* a) +{ // Generating a pseudo-random scalar value in [0, 2^256-1] + // NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY. + unsigned char* string = (unsigned char*)&a[0]; + unsigned int i; + + for (i = 0; i < (sizeof(uint64_t)*NWORDS64_ORDER); i++) { + string[i] = (unsigned char)rand(); + } +} + + +void fp2random1271_test(f2elm_t a) +{ // Generating a pseudo-random GF(p^2) element a+b*i, where a,b in [0, 2^127-1] + // NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY. + digit_t mask_7fff = (digit_t)-1 >> 1; + + random_scalar_test((uint64_t*)&a[0]); + a[0][NWORDS_FIELD-1] &= mask_7fff; + a[1][NWORDS_FIELD-1] &= mask_7fff; +} + + +bool verify_mLSB_recoding(uint64_t* scalar, int* digits) +{ // Verification of the mLSB-set's recoding algorithm used in fixed-base scalar multiplication + unsigned int j, l = L_FIXEDBASE, d = D_FIXEDBASE; + uint64_t temp, temp2, carry, borrow, generated_scalar[NWORDS64_ORDER] = {0}; + int i, digit; + + for (i = (l-1); i >= 0; i--) + { + // Shift generated scalar to the left by 1 (multiply by 2) + temp = ((generated_scalar[0] >> (RADIX64-1)) & 1) ; + generated_scalar[0] = generated_scalar[0] << 1; + + for (j = 1; j < NWORDS64_ORDER; j++) { + temp2 = ((generated_scalar[j] >> (RADIX64-1)) & 1) ; + generated_scalar[j] = (generated_scalar[j] << 1) | temp; + temp = temp2; + } + + // generated scalar + digit_i + if (i < (int)d) { + digit = digits[i] | 1; + if (digit >= 0) { + generated_scalar[0] = generated_scalar[0] + digit; + carry = (generated_scalar[0] < (unsigned int)digit); + for (j = 1; j < NWORDS64_ORDER; j++) + { + generated_scalar[j] = generated_scalar[j] + carry; + carry = (generated_scalar[j] < carry); + } + } else { + borrow = 0; + temp = (uint64_t)(-digit); + for (j = 0; j < NWORDS64_ORDER; j++) + { + temp2 = generated_scalar[j] - temp; + carry = (generated_scalar[j] < temp); + generated_scalar[j] = temp2 - borrow; + borrow = carry || (temp2 < borrow); + temp = 0; + } + } + } else { + digit = digits[i]*(digits[i-(i/d)*d] | 1); + if (digit >= 0) { + generated_scalar[0] = generated_scalar[0] + digit; + carry = (generated_scalar[0] < (unsigned int)digit); + for (j = 1; j < NWORDS64_ORDER; j++) + { + generated_scalar[j] = generated_scalar[j] + carry; + carry = (generated_scalar[j] < carry); + } + } else { + borrow = 0; + temp = (uint64_t)(-digit); + for (j = 0; j < NWORDS64_ORDER; j++) + { + temp2 = generated_scalar[j] - temp; + carry = (generated_scalar[j] < temp); + generated_scalar[j] = temp2 - borrow; + borrow = carry || (temp2 < borrow); + temp = 0; + } + } + } + } + + for (j = 0; j < NWORDS64_ORDER; j++) + { + if (scalar[j] != generated_scalar[j]) + return false; + } + + return true; +} diff --git a/FourQ_ARM_side_channel/tests/test_extras.h b/FourQ_ARM_side_channel/tests/test_extras.h new file mode 100644 index 0000000..ab119ef --- /dev/null +++ b/FourQ_ARM_side_channel/tests/test_extras.h @@ -0,0 +1,40 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: utility header file for tests +************************************************************************************/ + +#ifndef __TEST_EXTRAS_H__ +#define __TEST_EXTRAS_H__ + + +// For C++ +#ifdef __cplusplus +extern "C" { +#endif + + +// Access system counter for benchmarking +int64_t cpu_nseconds(void); + +// Comparing uint64_t digits of two quadratic extension field elements, ai=bi? : (0) equal, (1) unequal +int fp2compare64(uint64_t* a, uint64_t* b); + +// Generating a pseudo-random scalar value in [0, 2^256-1] +void random_scalar_test(uint64_t* a); + +// Generating a pseudo-random GF(p^2) element a+b*i, where a,b in [0, 2^127-1] +void fp2random1271_test(f2elm_t a); + +// Verification of the mLSB-set's recoding algorithm used in fixed-base scalar multiplication +bool verify_mLSB_recoding(uint64_t* scalar, int* digits); + + +#ifdef __cplusplus +} +#endif + + +#endif \ No newline at end of file diff --git a/FourQ_ARM_side_channel/tests_Cortex-M4/crypto_tests.c b/FourQ_ARM_side_channel/tests_Cortex-M4/crypto_tests.c new file mode 100644 index 0000000..ad4d26c --- /dev/null +++ b/FourQ_ARM_side_channel/tests_Cortex-M4/crypto_tests.c @@ -0,0 +1,386 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: testing code for cryptographic functions based on FourQ +************************************************************************************/ + +#include "../FourQ_internal.h" +#include "../FourQ_params.h" +#include "test_extras.h" +#include "../stm32f4_wrapper.h" +#include + +static unsigned int *DWT_CYCCNT = (unsigned int*)0xE0001004; +static unsigned int *DWT_CTRL = (unsigned int*)0xE0001000; +static unsigned int *SCB_DEMCR = (unsigned int*)0xE000EDFC; + +// Benchmark and test parameters +#define BENCH_LOOPS 10 // Number of iterations per bench +#define TEST_LOOPS 10 // Number of iterations per test + +#define cpucycles() (*DWT_CYCCNT); + + +static void print_test(const char *text) +{ + unsigned char output[100]; + + sprintf((char*)output, "%s", text); + send_USART_str(output); +} + + +static void print_bench(const char *s, unsigned int cycles) +{ + unsigned char output[100]; + + sprintf((char*)output, "%s %8u cycles", s, cycles); + send_USART_str(output); +} + + +ECCRYPTO_STATUS SchnorrQ_test() +{ // Test the SchnorrQ digital signature scheme + int n, passed; + void *msg = NULL; + unsigned int len, valid = false; + unsigned char SecretKey[32], PublicKey[32], Signature[64], BlindingPoint[64]; + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + print_test("\n--------------------------------------------------------------------------------------------------------\n"); + print_test("Testing the SchnorrQ signature scheme. Includes side-channel countermeasures: \n"); + + passed = 1; + for (n = 0; n < TEST_LOOPS; n++) + { + // Signature key generation + Status = SchnorrQ_FullKeyGeneration_SCA_secure(SecretKey, PublicKey, BlindingPoint); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + + // Signature computation + msg = "a"; + len = 1; + Status = SchnorrQ_Sign_SCA_secure(SecretKey, PublicKey, msg, len, Signature, BlindingPoint); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + + // Valid signature test + Status = SchnorrQ_Verify(PublicKey, msg, len, Signature, &valid); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + if (valid == false) { + passed = 0; + break; + } + + // Invalid signature test (flipping one bit of the message) + msg = "b"; + Status = SchnorrQ_Verify(PublicKey, msg, len, Signature, &valid); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + if (valid == true) { + passed = 0; + break; + } + } + if (passed==1) print_test(" Signature tests.................................................................. PASSED"); + else { print_test(" Signature tests... FAILED"); print_test("\n"); Status = ECCRYPTO_ERROR_SIGNATURE_VERIFICATION; } + + return Status; +} + + +ECCRYPTO_STATUS SchnorrQ_run() +{ // Benchmark the SchnorrQ digital signature scheme + int n; + unsigned int cycles, cycles1, cycles2; + void *msg = NULL; + unsigned int len = 0, valid = false; + unsigned char SecretKey[32], PublicKey[32], Signature[64], BlindingPoint[64]; + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + print_test("\n--------------------------------------------------------------------------------------------------------\n"); + print_test("Benchmarking the SchnorrQ signature scheme. Includes side-channel countermeasures: \n"); + + cycles = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + cycles1 = cpucycles(); + Status = SchnorrQ_FullKeyGeneration_SCA_secure(SecretKey, PublicKey, BlindingPoint); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + cycles2 = cpucycles(); + cycles = cycles+(cycles2-cycles1); + } + print_bench(" SchnorrQ's key generation runs in ............................................... ", cycles/BENCH_LOOPS); + + cycles = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + cycles1 = cpucycles(); + Status = SchnorrQ_Sign_SCA_secure(SecretKey, PublicKey, msg, len, Signature, BlindingPoint); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + cycles2 = cpucycles(); + cycles = cycles+(cycles2-cycles1); + } + print_bench(" SchnorrQ's signing runs in ...................................................... ", cycles/BENCH_LOOPS); + + cycles = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + cycles1 = cpucycles(); + Status = SchnorrQ_Verify(PublicKey, msg, len, Signature, &valid); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + cycles2 = cpucycles(); + cycles = cycles+(cycles2-cycles1); + } + print_bench(" SchnorrQ's verification runs in ................................................. ", cycles/BENCH_LOOPS); + + return Status; +} + + +ECCRYPTO_STATUS compressedkex_test() +{ // Test ECDH key exchange based on FourQ + int n, passed; + unsigned int i; + unsigned char SecretKeyA[32], PublicKeyA[32], BlindingPointA[64], SecretAgreementA[32]; + unsigned char SecretKeyB[32], PublicKeyB[32], BlindingPointB[64], SecretAgreementB[32]; + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + print_test("\n--------------------------------------------------------------------------------------------------------\n"); + print_test("Testing DH key exchange using compressed, 32-byte public keys. Includes side-channel countermeasures: \n"); + + passed = 1; + for (n = 0; n < TEST_LOOPS; n++) + { + // Alice's keypair generation + Status = CompressedKeyGeneration_SCA_secure(SecretKeyA, PublicKeyA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + // Bob's keypair generation + Status = CompressedKeyGeneration_SCA_secure(SecretKeyB, PublicKeyB, BlindingPointB); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + + // Alice's shared secret computation + Status = CompressedSecretAgreement_SCA_secure(SecretKeyA, PublicKeyB, SecretAgreementA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + // Bob's shared secret computation + Status = CompressedSecretAgreement_SCA_secure(SecretKeyB, PublicKeyA, SecretAgreementB, BlindingPointB); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + + for (i = 0; i < 32; i++) { + if (SecretAgreementA[i] != SecretAgreementB[i]) { + passed = 0; + break; + } + } + } + if (passed==1) print_test(" DH key exchange tests............................................................ PASSED"); + else { print_test(" DH key exchange tests... FAILED"); print_test("\n"); Status = ECCRYPTO_ERROR_SHARED_KEY; } + + return Status; +} + + +ECCRYPTO_STATUS compressedkex_run() +{ // Benchmark ECDH key exchange based on FourQ + int n; + unsigned int cycles, cycles1, cycles2; + unsigned char SecretKeyA[32], PublicKeyA[32], BlindingPointA[64], SecretAgreementA[32]; + unsigned char SecretKeyB[32], PublicKeyB[32], BlindingPointB[64]; + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + print_test("\n--------------------------------------------------------------------------------------------------------\n"); + print_test("Benchmarking DH key exchange using compressed, 32-byte public keys. Includes side-channel countermeasures: \n"); + + cycles = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + cycles1 = cpucycles(); + Status = CompressedKeyGeneration_SCA_secure(SecretKeyA, PublicKeyA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + cycles2 = cpucycles(); + cycles = cycles + (cycles2 - cycles1); + } + print_bench(" Keypair generation runs in ...................................................... ", cycles/BENCH_LOOPS); + + Status = CompressedKeyGeneration_SCA_secure(SecretKeyB, PublicKeyB, BlindingPointB); + cycles = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + cycles1 = cpucycles(); + Status = CompressedSecretAgreement_SCA_secure(SecretKeyA, PublicKeyB, SecretAgreementA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + cycles2 = cpucycles(); + cycles = cycles + (cycles2 - cycles1); + } + print_bench(" Secret agreement runs in ........................................................ ", cycles/BENCH_LOOPS); + + return Status; +} + + +ECCRYPTO_STATUS kex_test() +{ // Test ECDH key exchange based on FourQ + int n, passed; + unsigned int i; + unsigned char SecretKeyA[32], PublicKeyA[64], BlindingPointA[64], SecretAgreementA[32]; + unsigned char SecretKeyB[32], PublicKeyB[64], BlindingPointB[64], SecretAgreementB[32]; + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + print_test("\n--------------------------------------------------------------------------------------------------------\n"); + print_test("Testing DH key exchange using uncompressed, 64-byte public keys. Includes side-channel countermeasures: \n"); + + passed = 1; + for (n = 0; n < TEST_LOOPS; n++) + { + // Alice's keypair generation + Status = KeyGeneration_SCA_secure(SecretKeyA, PublicKeyA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + // Bob's keypair generation + Status = KeyGeneration_SCA_secure(SecretKeyB, PublicKeyB, BlindingPointB); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + + // Alice's shared secret computation + Status = SecretAgreement_SCA_secure(SecretKeyA, PublicKeyB, SecretAgreementA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + // Bob's shared secret computation + Status = SecretAgreement_SCA_secure(SecretKeyB, PublicKeyA, SecretAgreementB, BlindingPointB); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + + for (i = 0; i < 32; i++) { + if (SecretAgreementA[i] != SecretAgreementB[i]) { + passed = 0; + break; + } + } + } + if (passed==1) print_test(" DH key exchange tests............................................................ PASSED"); + else { print_test(" DH key exchange tests... FAILED"); print_test("\n"); Status = ECCRYPTO_ERROR_SHARED_KEY; } + + return Status; +} + + +ECCRYPTO_STATUS kex_run() +{ // Benchmark ECDH key exchange based on FourQ + int n; + unsigned int cycles, cycles1, cycles2; + unsigned char SecretKeyA[32], PublicKeyA[64], BlindingPointA[64], SecretAgreementA[32]; + unsigned char SecretKeyB[32], PublicKeyB[64], BlindingPointB[64]; + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + print_test("\n--------------------------------------------------------------------------------------------------------\n"); + print_test("Benchmarking DH key exchange using uncompressed, 64-byte public keys. Includes side-channel countermeasures: \n"); + + cycles = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + cycles1 = cpucycles(); + Status = KeyGeneration_SCA_secure(SecretKeyA, PublicKeyA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + cycles2 = cpucycles(); + cycles = cycles + (cycles2 - cycles1); + } + print_bench(" Keypair generation runs in ...................................................... ", cycles/BENCH_LOOPS); + + Status = KeyGeneration_SCA_secure(SecretKeyB, PublicKeyB, BlindingPointB); + cycles = 0; + for (n = 0; n < BENCH_LOOPS; n++) + { + cycles1 = cpucycles(); + Status = SecretAgreement_SCA_secure(SecretKeyA, PublicKeyB, SecretAgreementA, BlindingPointA); + if (Status != ECCRYPTO_SUCCESS) { + return Status; + } + cycles2 = cpucycles(); + cycles = cycles + (cycles2 - cycles1); + } + print_bench(" Secret agreement runs in ........................................................ ", cycles/BENCH_LOOPS); + + return Status; +} + + +int main() +{ + clock_setup(); + gpio_setup(); + usart_setup(115200); + rng_setup(); + + *SCB_DEMCR = *SCB_DEMCR | 0x01000000; + *DWT_CYCCNT = 0; // reset the counter + *DWT_CTRL = *DWT_CTRL | 1 ; // enable the counter + ECCRYPTO_STATUS Status = ECCRYPTO_SUCCESS; + + Status = SchnorrQ_test(); // Test SchnorrQ signature scheme + if (Status != ECCRYPTO_SUCCESS) { + print_test("\n\n Error detected \n\n"); + return false; + } + Status = SchnorrQ_run(); // Benchmark SchnorrQ signature scheme + if (Status != ECCRYPTO_SUCCESS) { + print_test("\n\n Error detected \n\n"); + return false; + } + + Status = compressedkex_test(); // Test Diffie-Hellman key exchange using compressed public keys + if (Status != ECCRYPTO_SUCCESS) { + print_test("\n\n Error detected \n\n"); + return false; + } + Status = compressedkex_run(); // Benchmark Diffie-Hellman key exchange using compressed public keys + if (Status != ECCRYPTO_SUCCESS) { + print_test("\n\n Error detected \n\n"); + return false; + } + + Status = kex_test(); // Test Diffie-Hellman key exchange using uncompressed public keys + if (Status != ECCRYPTO_SUCCESS) { + print_test("\n\n Error detected \n\n"); + return false; + } + Status = kex_run(); // Benchmark Diffie-Hellman key exchange using uncompressed public keys + if (Status != ECCRYPTO_SUCCESS) { + print_test("\n\n Error detected \n\n"); + return false; + } + signal_host(); + + return 0; +} \ No newline at end of file diff --git a/FourQ_ARM_side_channel/tests_Cortex-M4/ecc_tests.c b/FourQ_ARM_side_channel/tests_Cortex-M4/ecc_tests.c new file mode 100644 index 0000000..73233dd --- /dev/null +++ b/FourQ_ARM_side_channel/tests_Cortex-M4/ecc_tests.c @@ -0,0 +1,468 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: testing code for FourQ's curve arithmetic +************************************************************************************/ + +#include "../FourQ_internal.h" +#include "../FourQ_params.h" +#include "../FourQ_tables.h" +#include "test_extras.h" +#include "../stm32f4_wrapper.h" +#include + +static unsigned int *DWT_CYCCNT = (unsigned int*)0xE0001004; +static unsigned int *DWT_CTRL = (unsigned int*)0xE0001000; +static unsigned int *SCB_DEMCR = (unsigned int*)0xE000EDFC; + +// Benchmark and test parameters +#define BENCH_LOOPS 10 // Number of iterations per bench +#define TEST_LOOPS 10 // Number of iterations per test + +#define cpucycles() (*DWT_CYCCNT); + + +static void print_test(const char *text) +{ + unsigned char output[100]; + + sprintf((char*)output, "%s", text); + send_USART_str(output); +} + + +static void print_bench(const char *s, unsigned int cycles) +{ + unsigned char output[100]; + + sprintf((char*)output, "%s %8u cycles", s, cycles); + send_USART_str(output); +} + + +bool ecc_test() +{ + bool clear_cofactor, OK = true; + unsigned int n; + int passed; + point_t A, R; + point_extedwards_t P, Q; + f2elm_t t1; + uint64_t scalar[4], res_x[4], res_y[4]; + + print_test("\n--------------------------------------------------------------------------------------------------------\n"); + print_test("Testing FourQ's curve arithmetic: \n"); + + // Point doubling + passed = 1; + eccset(A); + point_setup(A, P); + + for (n=0; nx[0]); mod1271(A->x[1]); // Fully reduced P + mod1271(A->y[0]); mod1271(A->y[1]); + + // Result + res_x[0] = 0xFA4FAD9EC7732700; res_x[1] = 0x619F5D1FD93BC4F5; res_x[2] = 0x814B78DADF6A9024; res_x[3] = 0x72EC1D429F026578; + res_y[0] = 0x7FF28C92C8CEF9DE; res_y[1] = 0x799208A76EAD2BA3; res_y[2] = 0x9B1AE60FFFCB520A; res_y[3] = 0x051698145D42F3E2; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + if (passed==1) print_test(" Point doubling tests .................................................................... PASSED"); + else { print_test(" Point doubling tests ... FAILED"); print_test("\n"); return false; } + + // Point addition + eccset(A); + point_setup(A, P); + + for (n=0; nx[0]); mod1271(A->x[1]); // Fully reduced P + mod1271(A->y[0]); mod1271(A->y[1]); + + // Result + res_x[0] = 0xFA4FAD9EC7732700; res_x[1] = 0x619F5D1FD93BC4F5; res_x[2] = 0x814B78DADF6A9024; res_x[3] = 0x72EC1D429F026578; + res_y[0] = 0x7FF28C92C8CEF9DE; res_y[1] = 0x799208A76EAD2BA3; res_y[2] = 0x9B1AE60FFFCB520A; res_y[3] = 0x051698145D42F3E2; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + eccset(A); + point_setup(A, P); + ecccopy(P, Q); + eccdouble(P); // P = 2P + + for (n=0; nx[0]); mod1271(A->x[1]); // Fully reduced P + mod1271(A->y[0]); mod1271(A->y[1]); + + // Result + res_x[0] = 0xB92B573D2C4B06FF; res_x[1] = 0x6B62D585800A9F6A; res_x[2] = 0xECB6DFB3FA1ACB7C; res_x[3] = 0xD9D9F54A8335E2B; + res_y[0] = 0xDF3BD744D9BB783D; res_y[1] = 0x2B827EEDA23988A6; res_y[2] = 0x947C187247366CDD; res_y[3] = 0x3B7E00BA2F9525B3; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + if (passed==1) print_test(" Point addition tests .................................................................... PASSED"); + else { print_test(" Point addition tests ... FAILED"); print_test("\n"); return false; } + + // Psi endomorphism + eccset(A); + point_setup(A, P); + + for (n=0; nx[0]); mod1271(A->x[1]); // Fully reduced P + mod1271(A->y[0]); mod1271(A->y[1]); + + // Result + res_x[0] = 0xABC340A7DDC08580; res_x[1] = 0x6B74D34E155D2119; res_x[2] = 0x1B6E0A6DC6A5BC70; res_x[3] = 0x5CAE354597C9106A; + res_y[0] = 0xE276B58944E2D60B; res_y[1] = 0x1812145CDE0E8DCB; res_y[2] = 0xF4D6895A6375AA22; res_y[3] = 0x1A593C1711EEBCDE; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + if (passed==1) print_test(" Psi endomorphism tests .................................................................. PASSED"); + else { print_test(" Psi endomorphism tests ... FAILED"); print_test("\n"); return false; } + + // Phi endomorphism + eccset(A); + point_setup(A, P); + + for (n=0; nx[0]); mod1271(A->x[1]); // Fully reduced P + mod1271(A->y[0]); mod1271(A->y[1]); + + // Result + res_x[0] = 0x1365D931AFEBC83E; res_x[1] = 0x1873BB71FF4FFF87; res_x[2] = 0x7BF9ACB5C770F61F; res_x[3] = 0x773EA05D9B4B0D62; + res_y[0] = 0xCFFDD1A374E18F42; res_y[1] = 0x369B19C1F39C1A97; res_y[2] = 0x38B8E623E4E0049A; res_y[3] = 0x12435E356960429A; + + if (fp2compare64((uint64_t*)A->x, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + if (passed==1) print_test(" Phi endomorphism tests .................................................................. PASSED"); + else { print_test(" Phi endomorphism tests ... FAILED"); print_test("\n"); return false; } + + // Scalar multiplication + eccset(A); + eccset(R); + clear_cofactor = false; + scalar[0] = 0x3AD457AB55456230; scalar[1] = 0x3A8B3C2C6FD86E0C; scalar[2] = 0x7E38F7C9CFBB9166; scalar[3] = 0x0028FD6CBDA458F0; + + for (n=0; nx, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + + eccset(A); + eccset(R); + clear_cofactor = true; + scalar[0] = 0x3AD457AB55456230; scalar[1] = 0x3A8B3C2C6FD86E0C; scalar[2] = 0x7E38F7C9CFBB9166; scalar[3] = 0x0028FD6CBDA458F0; + + for (n=0; nx, res_x)!=0 || fp2compare64((uint64_t*)A->y, res_y)!=0) passed=0; + + if (passed==1) print_test(" Scalar multiplication tests ............................................................. PASSED"); + else { print_test(" Scalar multiplication tests ... FAILED"); print_test("\n"); return false; } + + { + point_t PP, QQ, RR, UU, TT; + point_extedwards_t AA, BB; + uint64_t k[4], l[4], kk[4]; + + // Double scalar multiplication + eccset(QQ); + eccset(PP); + eccset(R); + + for (n=0; nx,(uint64_t*)RR->x)!=0 || fp2compare64((uint64_t*)UU->y,(uint64_t*)RR->y)!=0) { passed=0; break; } + } + + if (passed==1) print_test(" Double scalar multiplication tests ...................................................... PASSED"); + else { print_test(" Double scalar multiplication tests ... FAILED"); print_test("\n"); return false; } + } + + return OK; +} + + +bool ecc_run() +{ + bool OK = true; + unsigned int n, i, digit=1; + unsigned int cycles, cycles1, cycles2; + point_t A, B, R; + point_extedwards_t P, Q, RR, Table[16]; + f2elm_t t1; + uint64_t scalar[4]; + + print_test("\n--------------------------------------------------------------------------------------------------------\n"); + print_test("Benchmarking FourQ's curve arithmetic \n"); + + // Point doubling (twisted Edwards a=-1) + eccset(A); + point_setup(A, P); + + cycles = 0; + for (n=0; n + +static unsigned int *DWT_CYCCNT = (unsigned int*)0xE0001004; +static unsigned int *DWT_CTRL = (unsigned int*)0xE0001000; +static unsigned int *SCB_DEMCR = (unsigned int*)0xE000EDFC; + +// Benchmark and test parameters +#define BENCH_LOOPS 100 // Number of iterations per bench +#define TEST_LOOPS 100 // Number of iterations per test + +#define cpucycles() (*DWT_CYCCNT); + + +static void print_test(const char *text) +{ + unsigned char output[100]; + + sprintf((char*)output, "%s", text); + send_USART_str(output); +} + + +static void print_bench(const char *s, unsigned int cycles) +{ + unsigned char output[100]; + + sprintf((char*)output, "%s %8u cycles", s, cycles); + send_USART_str(output); +} + + +bool fp2_test() +{ // Tests for the quadratic extension field arithmetic + bool OK = true; + int n, passed; + f2elm_t a, b, c, d, e, f; + + print_test("\n--------------------------------------------------------------------------------------------------------\n"); + print_test("Testing quadratic extension field arithmetic over GF((2^127-1)^2): \n"); + + // GF(p^2) multiplication using p = 2^127-1 + passed = 1; + for (n=0; n/dev/null 2>&1 +cat < $DEVICE diff --git a/FourQ_ARM_side_channel/tests_Cortex-M4/test_extras.c b/FourQ_ARM_side_channel/tests_Cortex-M4/test_extras.c new file mode 100644 index 0000000..7ef00f2 --- /dev/null +++ b/FourQ_ARM_side_channel/tests_Cortex-M4/test_extras.c @@ -0,0 +1,124 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: utility functions for tests +************************************************************************************/ + +#include "../FourQ_internal.h" +#include +#include +#include + + +int fp2compare64(uint64_t* a, uint64_t* b) +{ // Comparing uint64_t digits of two quadratic extension field elements, ai=bi? : (0) equal, (1) unequal + // NOTE: this function does not have constant-time execution. TO BE USED FOR TESTING ONLY. + unsigned int i; + + for (i = 0; i < (2*NWORDS64_FIELD); i++) { + if (a[i] != b[i]) return 1; + } + + return 0; +} + + +void random_scalar_test(uint64_t* a) +{ // Generating a pseudo-random scalar value in [0, 2^256-1] + // NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY. + unsigned char* string = (unsigned char*)&a[0]; + unsigned int i; + + for (i = 0; i < (sizeof(uint64_t)*NWORDS64_ORDER); i++) { + string[i] = (unsigned char)rand(); + } +} + + +void fp2random1271_test(f2elm_t a) +{ // Generating a pseudo-random GF(p^2) element a+b*i, where a,b in [0, 2^127-1] + // NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY. + digit_t mask_7fff = (digit_t)-1 >> 1; + + random_scalar_test((uint64_t*)&a[0]); + a[0][NWORDS_FIELD-1] &= mask_7fff; + a[1][NWORDS_FIELD-1] &= mask_7fff; +} + + +bool verify_mLSB_recoding(uint64_t* scalar, int* digits) +{ // Verification of the mLSB-set's recoding algorithm used in fixed-base scalar multiplication + unsigned int j, l = L_FIXEDBASE, d = D_FIXEDBASE; + uint64_t temp, temp2, carry, borrow, generated_scalar[NWORDS64_ORDER] = {0}; + int i, digit; + + for (i = (l-1); i >= 0; i--) + { + // Shift generated scalar to the left by 1 (multiply by 2) + temp = ((generated_scalar[0] >> (RADIX64-1)) & 1) ; + generated_scalar[0] = generated_scalar[0] << 1; + + for (j = 1; j < NWORDS64_ORDER; j++) { + temp2 = ((generated_scalar[j] >> (RADIX64-1)) & 1) ; + generated_scalar[j] = (generated_scalar[j] << 1) | temp; + temp = temp2; + } + + // generated scalar + digit_i + if (i < (int)d) { + digit = digits[i] | 1; + if (digit >= 0) { + generated_scalar[0] = generated_scalar[0] + digit; + carry = (generated_scalar[0] < (unsigned int)digit); + for (j = 1; j < NWORDS64_ORDER; j++) + { + generated_scalar[j] = generated_scalar[j] + carry; + carry = (generated_scalar[j] < carry); + } + } else { + borrow = 0; + temp = (uint64_t)(-digit); + for (j = 0; j < NWORDS64_ORDER; j++) + { + temp2 = generated_scalar[j] - temp; + carry = (generated_scalar[j] < temp); + generated_scalar[j] = temp2 - borrow; + borrow = carry || (temp2 < borrow); + temp = 0; + } + } + } else { + digit = digits[i]*(digits[i-(i/d)*d] | 1); + if (digit >= 0) { + generated_scalar[0] = generated_scalar[0] + digit; + carry = (generated_scalar[0] < (unsigned int)digit); + for (j = 1; j < NWORDS64_ORDER; j++) + { + generated_scalar[j] = generated_scalar[j] + carry; + carry = (generated_scalar[j] < carry); + } + } else { + borrow = 0; + temp = (uint64_t)(-digit); + for (j = 0; j < NWORDS64_ORDER; j++) + { + temp2 = generated_scalar[j] - temp; + carry = (generated_scalar[j] < temp); + generated_scalar[j] = temp2 - borrow; + borrow = carry || (temp2 < borrow); + temp = 0; + } + } + } + } + + for (j = 0; j < NWORDS64_ORDER; j++) + { + if (scalar[j] != generated_scalar[j]) + return false; + } + + return true; +} diff --git a/FourQ_ARM_side_channel/tests_Cortex-M4/test_extras.h b/FourQ_ARM_side_channel/tests_Cortex-M4/test_extras.h new file mode 100644 index 0000000..de850f1 --- /dev/null +++ b/FourQ_ARM_side_channel/tests_Cortex-M4/test_extras.h @@ -0,0 +1,37 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: utility header file for tests +************************************************************************************/ + +#ifndef __TEST_EXTRAS_H__ +#define __TEST_EXTRAS_H__ + + +// For C++ +#ifdef __cplusplus +extern "C" { +#endif + + +// Comparing uint64_t digits of two quadratic extension field elements, ai=bi? : (0) equal, (1) unequal +int fp2compare64(uint64_t* a, uint64_t* b); + +// Generating a pseudo-random scalar value in [0, 2^256-1] +void random_scalar_test(uint64_t* a); + +// Generating a pseudo-random GF(p^2) element a+b*i, where a,b in [0, 2^127-1] +void fp2random1271_test(f2elm_t a); + +// Verification of the mLSB-set's recoding algorithm used in fixed-base scalar multiplication +bool verify_mLSB_recoding(uint64_t* scalar, int* digits); + + +#ifdef __cplusplus +} +#endif + + +#endif \ No newline at end of file diff --git a/random/random.c b/random/random.c new file mode 100644 index 0000000..fc547fe --- /dev/null +++ b/random/random.c @@ -0,0 +1,61 @@ +/*********************************************************************************** +* FourQlib: a high-performance crypto library based on the elliptic curve FourQ +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* Abstract: pseudo-random function +************************************************************************************/ + +#include "random.h" +#include +#include +#if defined(__WINDOWS__) + #include + #include +#elif defined(__LINUX__) + #include + #include + static int lock = -1; +#endif + + +static __inline void delay(unsigned int count) +{ + while (count--) {} +} + + +int random_bytes(unsigned char* random_array, unsigned int nbytes) +{ // Generation of "nbytes" of random values + +#if defined(__WINDOWS__) + if (!BCRYPT_SUCCESS(BCryptGenRandom(NULL, random_array, nbytes, BCRYPT_USE_SYSTEM_PREFERRED_RNG))) { + return false; + } + +#elif defined(__LINUX__) + int r, n = nbytes, count = 0; + + if (lock == -1) { + do { + lock = open("/dev/urandom", O_RDONLY); + if (lock == -1) { + delay(0xFFFFF); + } + } while (lock == -1); + } + + while (n > 0) { + do { + r = read(lock, random_array+count, n); + if (r == -1) { + delay(0xFFFF); + } + } while (r == -1); + count += r; + n -= r; + } +#endif + + return true; +} \ No newline at end of file diff --git a/random/random.h b/random/random.h new file mode 100644 index 0000000..e5f48df --- /dev/null +++ b/random/random.h @@ -0,0 +1,20 @@ +#ifndef __RANDOM_H__ +#define __RANDOM_H__ + + +// For C++ +#ifdef __cplusplus +extern "C" { +#endif + + +// Generate random bytes and output the result to random_array +int random_bytes(unsigned char* random_array, unsigned int nbytes); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/sha512/sha512.c b/sha512/sha512.c new file mode 100644 index 0000000..92b1f7e --- /dev/null +++ b/sha512/sha512.c @@ -0,0 +1,306 @@ +/* +20080913 +D. J. Bernstein +Public domain. +*/ + +#include "sha512.h" + +typedef unsigned long long uint64; + +static uint64 load_bigendian(const unsigned char *x) +{ + return + (uint64) (x[7]) \ + | (((uint64) (x[6])) << 8) \ + | (((uint64) (x[5])) << 16) \ + | (((uint64) (x[4])) << 24) \ + | (((uint64) (x[3])) << 32) \ + | (((uint64) (x[2])) << 40) \ + | (((uint64) (x[1])) << 48) \ + | (((uint64) (x[0])) << 56) + ; +} + +static void store_bigendian(unsigned char *x,uint64 u) +{ + x[7] = (unsigned char)u; u >>= 8; + x[6] = (unsigned char)u; u >>= 8; + x[5] = (unsigned char)u; u >>= 8; + x[4] = (unsigned char)u; u >>= 8; + x[3] = (unsigned char)u; u >>= 8; + x[2] = (unsigned char)u; u >>= 8; + x[1] = (unsigned char)u; u >>= 8; + x[0] = (unsigned char)u; +} + +#define SHR(x,c) ((x) >> (c)) +#define ROTR(x,c) (((x) >> (c)) | ((x) << (64 - (c)))) + +#define Ch(x,y,z) ((x & y) ^ (~x & z)) +#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z)) +#define Sigma0(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) +#define Sigma1(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) +#define sigma0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x,7)) +#define sigma1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x,6)) + +#define M(w0,w14,w9,w1) w0 = sigma1(w14) + w9 + sigma0(w1) + w0; + +#define EXPAND \ + M(w0 ,w14,w9 ,w1 ) \ + M(w1 ,w15,w10,w2 ) \ + M(w2 ,w0 ,w11,w3 ) \ + M(w3 ,w1 ,w12,w4 ) \ + M(w4 ,w2 ,w13,w5 ) \ + M(w5 ,w3 ,w14,w6 ) \ + M(w6 ,w4 ,w15,w7 ) \ + M(w7 ,w5 ,w0 ,w8 ) \ + M(w8 ,w6 ,w1 ,w9 ) \ + M(w9 ,w7 ,w2 ,w10) \ + M(w10,w8 ,w3 ,w11) \ + M(w11,w9 ,w4 ,w12) \ + M(w12,w10,w5 ,w13) \ + M(w13,w11,w6 ,w14) \ + M(w14,w12,w7 ,w15) \ + M(w15,w13,w8 ,w0 ) + +#define F(w,k) \ + T1 = h + Sigma1(e) + Ch(e,f,g) + k + w; \ + T2 = Sigma0(a) + Maj(a,b,c); \ + h = g; \ + g = f; \ + f = e; \ + e = d + T1; \ + d = c; \ + c = b; \ + b = a; \ + a = T1 + T2; + +static int crypto_hashblocks_sha512(unsigned char *statebytes,const unsigned char *in,unsigned long long inlen) +{ + uint64 state[8]; + uint64 a; + uint64 b; + uint64 c; + uint64 d; + uint64 e; + uint64 f; + uint64 g; + uint64 h; + uint64 T1; + uint64 T2; + + a = load_bigendian(statebytes + 0); state[0] = a; + b = load_bigendian(statebytes + 8); state[1] = b; + c = load_bigendian(statebytes + 16); state[2] = c; + d = load_bigendian(statebytes + 24); state[3] = d; + e = load_bigendian(statebytes + 32); state[4] = e; + f = load_bigendian(statebytes + 40); state[5] = f; + g = load_bigendian(statebytes + 48); state[6] = g; + h = load_bigendian(statebytes + 56); state[7] = h; + + while (inlen >= 128) { + uint64 w0 = load_bigendian(in + 0); + uint64 w1 = load_bigendian(in + 8); + uint64 w2 = load_bigendian(in + 16); + uint64 w3 = load_bigendian(in + 24); + uint64 w4 = load_bigendian(in + 32); + uint64 w5 = load_bigendian(in + 40); + uint64 w6 = load_bigendian(in + 48); + uint64 w7 = load_bigendian(in + 56); + uint64 w8 = load_bigendian(in + 64); + uint64 w9 = load_bigendian(in + 72); + uint64 w10 = load_bigendian(in + 80); + uint64 w11 = load_bigendian(in + 88); + uint64 w12 = load_bigendian(in + 96); + uint64 w13 = load_bigendian(in + 104); + uint64 w14 = load_bigendian(in + 112); + uint64 w15 = load_bigendian(in + 120); + + F(w0 ,0x428a2f98d728ae22ULL) + F(w1 ,0x7137449123ef65cdULL) + F(w2 ,0xb5c0fbcfec4d3b2fULL) + F(w3 ,0xe9b5dba58189dbbcULL) + F(w4 ,0x3956c25bf348b538ULL) + F(w5 ,0x59f111f1b605d019ULL) + F(w6 ,0x923f82a4af194f9bULL) + F(w7 ,0xab1c5ed5da6d8118ULL) + F(w8 ,0xd807aa98a3030242ULL) + F(w9 ,0x12835b0145706fbeULL) + F(w10,0x243185be4ee4b28cULL) + F(w11,0x550c7dc3d5ffb4e2ULL) + F(w12,0x72be5d74f27b896fULL) + F(w13,0x80deb1fe3b1696b1ULL) + F(w14,0x9bdc06a725c71235ULL) + F(w15,0xc19bf174cf692694ULL) + + EXPAND + + F(w0 ,0xe49b69c19ef14ad2ULL) + F(w1 ,0xefbe4786384f25e3ULL) + F(w2 ,0x0fc19dc68b8cd5b5ULL) + F(w3 ,0x240ca1cc77ac9c65ULL) + F(w4 ,0x2de92c6f592b0275ULL) + F(w5 ,0x4a7484aa6ea6e483ULL) + F(w6 ,0x5cb0a9dcbd41fbd4ULL) + F(w7 ,0x76f988da831153b5ULL) + F(w8 ,0x983e5152ee66dfabULL) + F(w9 ,0xa831c66d2db43210ULL) + F(w10,0xb00327c898fb213fULL) + F(w11,0xbf597fc7beef0ee4ULL) + F(w12,0xc6e00bf33da88fc2ULL) + F(w13,0xd5a79147930aa725ULL) + F(w14,0x06ca6351e003826fULL) + F(w15,0x142929670a0e6e70ULL) + + EXPAND + + F(w0 ,0x27b70a8546d22ffcULL) + F(w1 ,0x2e1b21385c26c926ULL) + F(w2 ,0x4d2c6dfc5ac42aedULL) + F(w3 ,0x53380d139d95b3dfULL) + F(w4 ,0x650a73548baf63deULL) + F(w5 ,0x766a0abb3c77b2a8ULL) + F(w6 ,0x81c2c92e47edaee6ULL) + F(w7 ,0x92722c851482353bULL) + F(w8 ,0xa2bfe8a14cf10364ULL) + F(w9 ,0xa81a664bbc423001ULL) + F(w10,0xc24b8b70d0f89791ULL) + F(w11,0xc76c51a30654be30ULL) + F(w12,0xd192e819d6ef5218ULL) + F(w13,0xd69906245565a910ULL) + F(w14,0xf40e35855771202aULL) + F(w15,0x106aa07032bbd1b8ULL) + + EXPAND + + F(w0 ,0x19a4c116b8d2d0c8ULL) + F(w1 ,0x1e376c085141ab53ULL) + F(w2 ,0x2748774cdf8eeb99ULL) + F(w3 ,0x34b0bcb5e19b48a8ULL) + F(w4 ,0x391c0cb3c5c95a63ULL) + F(w5 ,0x4ed8aa4ae3418acbULL) + F(w6 ,0x5b9cca4f7763e373ULL) + F(w7 ,0x682e6ff3d6b2b8a3ULL) + F(w8 ,0x748f82ee5defb2fcULL) + F(w9 ,0x78a5636f43172f60ULL) + F(w10,0x84c87814a1f0ab72ULL) + F(w11,0x8cc702081a6439ecULL) + F(w12,0x90befffa23631e28ULL) + F(w13,0xa4506cebde82bde9ULL) + F(w14,0xbef9a3f7b2c67915ULL) + F(w15,0xc67178f2e372532bULL) + + EXPAND + + F(w0 ,0xca273eceea26619cULL) + F(w1 ,0xd186b8c721c0c207ULL) + F(w2 ,0xeada7dd6cde0eb1eULL) + F(w3 ,0xf57d4f7fee6ed178ULL) + F(w4 ,0x06f067aa72176fbaULL) + F(w5 ,0x0a637dc5a2c898a6ULL) + F(w6 ,0x113f9804bef90daeULL) + F(w7 ,0x1b710b35131c471bULL) + F(w8 ,0x28db77f523047d84ULL) + F(w9 ,0x32caab7b40c72493ULL) + F(w10,0x3c9ebe0a15c9bebcULL) + F(w11,0x431d67c49c100d4cULL) + F(w12,0x4cc5d4becb3e42b6ULL) + F(w13,0x597f299cfc657e2aULL) + F(w14,0x5fcb6fab3ad6faecULL) + F(w15,0x6c44198c4a475817ULL) + + a += state[0]; + b += state[1]; + c += state[2]; + d += state[3]; + e += state[4]; + f += state[5]; + g += state[6]; + h += state[7]; + + state[0] = a; + state[1] = b; + state[2] = c; + state[3] = d; + state[4] = e; + state[5] = f; + state[6] = g; + state[7] = h; + + in += 128; + inlen -= 128; + } + + store_bigendian(statebytes + 0,state[0]); + store_bigendian(statebytes + 8,state[1]); + store_bigendian(statebytes + 16,state[2]); + store_bigendian(statebytes + 24,state[3]); + store_bigendian(statebytes + 32,state[4]); + store_bigendian(statebytes + 40,state[5]); + store_bigendian(statebytes + 48,state[6]); + store_bigendian(statebytes + 56,state[7]); + + return (int)inlen; +} + +static const unsigned char iv[64] = { + 0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08, + 0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b, + 0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b, + 0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1, + 0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1, + 0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f, + 0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b, + 0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79 +} ; + +typedef unsigned long long uint64; + +int crypto_sha512(const unsigned char *in, unsigned long long inlen, unsigned char *out) +{ + unsigned char h[64]; + unsigned char padded[256]; + int i; + unsigned long long bytes = inlen; + + for (i = 0;i < 64;++i) h[i] = iv[i]; + + crypto_hashblocks_sha512(h,in,inlen); + in += inlen; + inlen &= 127; + in -= inlen; + + for (i = 0;i < inlen;++i) padded[i] = in[i]; + padded[inlen] = 0x80; + + if (inlen < 112) { + for (i = (int)inlen + 1;i < 119;++i) padded[i] = 0; + padded[119] = (unsigned char)(bytes >> 61); + padded[120] = (unsigned char)(bytes >> 53); + padded[121] = (unsigned char)(bytes >> 45); + padded[122] = (unsigned char)(bytes >> 37); + padded[123] = (unsigned char)(bytes >> 29); + padded[124] = (unsigned char)(bytes >> 21); + padded[125] = (unsigned char)(bytes >> 13); + padded[126] = (unsigned char)(bytes >> 5); + padded[127] = (unsigned char)(bytes << 3); + crypto_hashblocks_sha512(h,padded,128); + } else { + for (i = (int)inlen + 1;i < 247;++i) padded[i] = 0; + padded[247] = (unsigned char)(bytes >> 61); + padded[248] = (unsigned char)(bytes >> 53); + padded[249] = (unsigned char)(bytes >> 45); + padded[250] = (unsigned char)(bytes >> 37); + padded[251] = (unsigned char)(bytes >> 29); + padded[252] = (unsigned char)(bytes >> 21); + padded[253] = (unsigned char)(bytes >> 13); + padded[254] = (unsigned char)(bytes >> 5); + padded[255] = (unsigned char)(bytes << 3); + crypto_hashblocks_sha512(h,padded,256); + } + + for (i = 0;i < 64;++i) out[i] = h[i]; + + return 0; +} diff --git a/sha512/sha512.h b/sha512/sha512.h new file mode 100644 index 0000000..4ac8bd8 --- /dev/null +++ b/sha512/sha512.h @@ -0,0 +1,20 @@ +#ifndef __SHA512_H__ +#define __SHA512_H__ + + +// For C++ +#ifdef __cplusplus +extern "C" { +#endif + + +// Hashing using SHA-512. Output is 64 bytes long +int crypto_sha512(const unsigned char *in, unsigned long long inlen, unsigned char *out); + + +#ifdef __cplusplus +} +#endif + + +#endif