;
54 |
55 | // Bitlengths of group orders lA^eA and lB^eB, needed during the ladder
56 | // functions
57 | eAbits:=eA;
58 | eBbits:=379;
59 |
60 | // E0 is the starting curve E0/Fp2: y^2=x^3+x (the A=0 Montgomery curve)
61 | E0:=EllipticCurve([Fp2|1,0]);
62 | assert IsSupersingular(E0);
63 |
64 | // The orders of the points on each side
65 | oA:=lA^eA;
66 | oB:=lB^eB;
67 |
68 | // Identifyers for Alice and Bob
69 | Alice:=0;
70 | Bob:=1;
71 |
72 | // Generator PA for the base field subgroup of order lA^eA
73 | PA:=3^239*E0![11,Sqrt(Fp!11^3+11)];
74 | // Generator PB for the base field subgroup of order lB^eB
75 | PB:=2^372*E0![6,Sqrt(Fp!6^3+6)];
76 |
77 | ////////////////////////////////////////////////////////////////////////////////
78 | /////////////////////// Generator point coordinates ///////////////////////////
79 | /////////////////// specified explicitly by 4 Fp elements //////////////////////
80 | ////////////////////////////////////////////////////////////////////////////////
81 |
82 | XPA:=Fp!57843070331575741623916724745225229838323045112189057077049620587995724\
83 | 6271947419276998036192253718730996052447524118652730054908853394186541287466114\
84 | 3122262830946833377212881592965099601886901183961091839303261748866970694633;
85 |
86 | YPA:=Fp!55289417931846173645114523009626950849421654600788978815806665527365554\
87 | 1827349664589467431477400107235381696676468949309812255666275584200196978168790\
88 | 9521301233517912821073526079191975713749455487083964491867894271185073160661;
89 |
90 | assert XPA eq PA[1] and YPA eq PA[2];
91 |
92 | XPB:=Fp!43599173968491012310533367637003008929150967000137042101947814578014127\
93 | 3164398836738987088688433645324515677545433624919918565425015905192997560085704\
94 | 7173121187832546031604804277991148436536445770452624367894371450077315674371;
95 |
96 | YPB:=Fp!10686693760744079753638500261776672082694467465027140072103951425088918\
97 | 6719923133049487966730514682296643039694531052672873754128006844434636819566554\
98 | 364257913332237123293860767683395958817983684370065598726191088239028762772;
99 |
100 | assert XPB eq PB[1] and YPB eq PB[2];
101 |
102 | params_Alice:=[XPB,XPA,YPA];
103 | params_Bob:=[XPA,XPB,YPB];
104 |
105 | ////////////////////////////////////////////////////////////////////////////////
106 | /////////////////// Strategies for traversing isogeny trees ////////////////////
107 | ////////////////////////////////////////////////////////////////////////////////
108 |
109 | /*
110 | These are optimal strategies with respect to the cost ratios of
111 | scalar multiplication by 4 and 4-isogeny evaluation of
112 | pA/qA = 2*12.1/21.6,
113 | and of point tripling and 3-isogeny evaluation of
114 | pB/qB = 24.3/16.0.
115 |
116 | See the file optimalstrategies.txt for how they are computed.
117 | */
118 |
119 | splits_Alice := [
120 | 0, 1, 1, 2, 2, 2, 3, 4, 4, 4, 4, 5, 5, 6, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 12, 11,
121 | 12, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 17, 17, 18, 18, 17, 21, 17, 18, 21,
122 | 20, 21, 21, 21, 21, 21, 22, 25, 25, 25, 26, 27, 28, 28, 29, 30, 31, 32, 32, 32,
123 | 32, 32, 32, 32, 33, 33, 33, 35, 36, 36, 33, 36, 35, 36, 36, 35, 36, 36, 37, 38,
124 | 38, 39, 40, 41, 42, 38, 39, 40, 41, 42, 40, 46, 42, 43, 46, 46, 46, 46, 48, 48,
125 | 48, 48, 49, 49, 48, 53, 54, 51, 52, 53, 54, 55, 56, 57, 58, 59, 59, 60, 62, 62,
126 | 63, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 66, 67, 65, 66, 67, 66,
127 | 69, 70, 66, 67, 66, 69, 70, 69, 70, 70, 71, 72, 71, 72, 72, 74, 74, 75, 72, 72,
128 | 74, 74, 75, 72, 72, 74, 75, 75, 72, 72, 74, 75, 75, 77, 77, 79, 80, 80, 82 ];
129 |
130 | splits_Bob := [
131 | 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10,
132 | 12, 12, 12, 12, 12, 12, 13, 14, 14, 15, 16, 16, 16, 16, 16, 17, 16, 16, 17, 19,
133 | 19, 20, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24, 25, 27, 27, 28, 28,
134 | 29, 28, 29, 28, 28, 28, 30, 28, 28, 28, 29, 30, 33, 33, 33, 33, 34, 35, 37, 37,
135 | 37, 37, 38, 38, 37, 38, 38, 38, 38, 38, 39, 43, 38, 38, 38, 38, 43, 40, 41, 42,
136 | 43, 48, 45, 46, 47, 47, 48, 49, 49, 49, 50, 51, 50, 49, 49, 49, 49, 51, 49, 53,
137 | 50, 51, 50, 51, 51, 51, 52, 55, 55, 55, 56, 56, 56, 56, 56, 58, 58, 61, 61, 61,
138 | 63, 63, 63, 64, 65, 65, 65, 65, 66, 66, 65, 65, 66, 66, 66, 66, 66, 66, 66, 71,
139 | 66, 73, 66, 66, 71, 66, 73, 66, 66, 71, 66, 73, 68, 68, 71, 71, 73, 73, 73, 75,
140 | 75, 78, 78, 78, 80, 80, 80, 81, 81, 82, 83, 84, 85, 86, 86, 86, 86, 86, 87, 86,
141 | 88, 86, 86, 86, 86, 88, 86, 88, 86, 86, 86, 88, 88, 86, 86, 86, 93, 90, 90, 92,
142 | 92, 92, 93, 93, 93, 93, 93, 97, 97, 97, 97, 97, 97 ];
143 |
144 | MAX_Alice:=185;
145 | MAX_Bob:=239;
146 |
147 |
148 |
149 | ////////////////////////////////////////////////////////////////////////////////
150 | /////////////////// Hardcoded parameters for compression ///////////////////////
151 | ////////////////////////////////////////////////////////////////////////////////
152 |
153 | //sqrt17 needs to be hardcoded
154 | sqrt17:=Fp!1483538965666804829947069469909104059154140781635831028330640820709265337955392648044549164145551021689748496013107072560229759910814321769438913101160612783079068256317507381028230709001284064164607572283647211914550735845927;
155 |
156 | /*
157 | This is a list of Fp2 values (coming in pairs of 2 Fp values) that are used
158 | in the elligator part of generating the 3-torsion basis. It is unclear how many
159 | of them actually need to be included. This list contains 10 pairs and was
160 | sufficient for all our experiments so far.
161 | */
162 |
163 | list:=[
164 | 8363425868352131165866658961353958144229814713712711329709230125390317605935848299098482339530092345619831440153678625003433928904114370855920283455545930313711955524679122308520245936538779748714805262456570059204845333965902,
165 | 9956459367085870435555546382564235885987874659181799202034797768321806673733152737022002785154871840023608857325807886908849915362040917685619385066126107516323756576998955129190768972069975891327149121972107213339101588054645
166 | ,
167 | 6144930856590964756685167380504563157961827953588137317347640432488186518896815315465645259926403525134570922304951070923678387107378958508658993589664191734009127665751748568914329020663777907486631313836162169963778632575103,
168 | 7536876520238641856265785405922723873301247545284897704150144618852913851906591160405377059136251837457871517965188606326279568717337728115592798767433428535635504650811536918778900787775462405867580948462033158740104179180513
169 | ,
170 | 3649145355892493092601130737620646564999583523362465770985774431722028233578445993491705627684624200456652890439467133392302895875864155375755562758304867985155239445020913595763546387942667577715103537504039074108229067555697,
171 | 3406345077809626624600272723767218026428182662708211688376153432351090934279684420539224235627330222344077159960128811405339493801931902376194527271450923735653716663943201145164797704596188717358325611329602031995352769518723
172 | ,
173 | 998267811748346322090246792849466614339797439606605388415575528085610645475302580158278377887610091561215574072604098957912985934804227515687363830062293591817437481569759107440934765403168660668480597527254704041283544182368,
174 | 6299254756541648319486140641915847200671962547147236779677914096206885693439062114609876986392650716657114941948886050368682406616380380110564244909143084100218367071201766960379602246502402243014532659396519266704951253335961
175 | ,
176 | 9039574854744291884896812083509992341844657264001872494805847834541453045297442044919522100073770691895959024848481318376368203592288440935586584203801603161116465577829836497600335844932077945214317550880170024404079352766731,
177 | 5313177263581054007047062863601524437514238821450682648253781051833432617355548678396777617808675927783520514552249891395696261872305818368128608110476976569675374699486270420502578099523615806334306845322118768973088647192804
178 | ,
179 | 2859481213219210500396709977967429237098625947545561341006056770829848169453286125614612704377152243303693651557660096209954612849929887786332341970767679754484316157978872890685237038734505830827748267342391094374943375131920,
180 | 1138411242251775238152745990579505410097343944723687139978725391891052467202849473111333480944440558901243384315784859847376479547976629563215374301794919876298590501570433821178061598483854203252967918244358816611958313201449
181 | ,
182 | 5367316808588549611959672587456268587017968216903026189392184608936835643094356482410776062932320943211212840412279678795203609893969868585047714432744978742112094996625228530338019331542883407309507442131133935246348240313824,
183 | 8851386602506850670872308704570103155979681025085103860948386649455451954463035242071270463410742468353606794120283518792127595418513953496815497229638470396909450421146806115735096998841868535615936457279783490329250009902864
184 | ,
185 | 7188443013090000550274508548166825175454104585924265018176320088548672687938897853151391910056849450233961696385929752588921372836392363086801317815771330941328643756283167206927316748142794608941899319827441473735709267505672,
186 | 903722033147219142615010295134657953920856503101452900469759971703938191957489992134730188791030728074838046354416419117573859136364260859565419493760310662535197081402282520962892909728318313535861418514530899913956220955925
187 | ,
188 | 5579969524527689275567102658266073446837331226905933874007222354369088971520147421829210289266033980819107236272056980685624788284996978462833907271313354456842447471315232788660234394084377803028810298750081928633804592071001,
189 | 2027913496375781342709202092544270940376528068585729437528950167030737801559327747994534434959292574519503847293579752256122111048046788748770552918005553068750068867624960377134298401661200309492117956725466050020896876890116
190 | ,
191 | 4624494142656684527622186866310605773524761035076660546060228364634691625190720012705349560205003073647077848112696936658132795530946054014061987955095884870409424853882937383611296712998217950743726984385808530127744032926811,
192 | 197817600549137552124791176633388479949283507786410028208787576903855465620499461221766306353468426335659142098186050318106570598412146855021358748541286458386045716472254226907403693901668635351880299813202412577271257317552
193 | ,
194 | 2376687573372173187082388104863803606689914688520586156889427110064854329629004523727865483902066455992739113122842261239999958200657732612662289575390386558617143244720633294000738727837611339026692156860041836920186210943397,
195 | 571596863167553918317507613300316352758870696217405884151555650801634422565829007267152248774410256621643050466484687438463486660418686787090913150831887879949892011899211783999445332654429272361339208027245506732927558500153];
196 |
197 |
--------------------------------------------------------------------------------
/SIDH-Magma/TestSIDH-kex.mag:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Code for SIDH key exchange with optional public key compression
4 | //
5 | // (c) 2016 Microsoft Corporation. All rights reserved.
6 | //
7 | ////////////////////////////////////////////////////////////////////////////////
8 | //
9 | // TestSIDH-kex.mag
10 | //
11 | // Test file that demonstrates and tests SIDH key exchange without public key
12 | // compression (function kextest) and with public key compression (function
13 | // kextest_compress).
14 | //
15 | // For the 4 stages of SIDH key exchange (i.e. Alice's key generation, Bob's
16 | // key generation, Alice's shared secret and Bob's shared secret computation),
17 | // the isogeny computation/evaluation can be performed using two different
18 | // strategies:
19 | // (1) the slow but simple "scalar-multiplication-based" strategy.
20 | // (2) a fast way to traverse the isogeny tree using an optimal strategy.
21 | //
22 | // The function kextest can be run using the fast computations (2) only by
23 | // setting the input boolean simple:=false. If one sets simple:=true, then the
24 | // computation is done using the simple algorithm (1) and the fast algorithm (2)
25 | // and the results from both are asserted to be equal.
26 | //
27 | ////////////////////////////////////////////////////////////////////////////////
28 | //
29 | // References:
30 | //
31 | // Efficient algorithms for supersingular isogeny Diffie-Hellman
32 | // Craig Costello, Patrick Longa, Michael Naehrig, CRYPTO 2016.
33 | //
34 | // Efficient compression of SIDH public keys
35 | // Craig Costello, David Jao, Patrick Longa, Michael Naehrig, Joost Renes,
36 | // David Urbanik, EUROCRYPT 2017.
37 | //
38 | ////////////////////////////////////////////////////////////////////////////////
39 |
40 | clear;
41 | load "SIDH-parameters.mag";
42 | load "SIDH-field-arithmetic.mag";
43 | load "SIDH-curve-and-isogeny-arithmetic.mag";
44 | load "SIDH.mag";
45 | load "SIDH-pairings.mag";
46 | load "SIDH-pohlig-hellman.mag";
47 | load "SIDH-compression.mag";
48 |
49 | ////////////////////////////////////////////////////////////////////////////////
50 | ///////////////////////// Key exchange testing /////////////////////////////////
51 | ////////////////////////////////////////////////////////////////////////////////
52 |
53 | kextest := procedure(n, simple)
54 | for j in [1..n] do
55 | "\n";
56 | j;
57 | "====================================================================";
58 | "Generating secret keys...";
59 | SK_Alice:=Random(1, (oA div lA)-1)*lA; // Random even number between 1 and oA-1
60 | SK_Bob:=Random(1, (oB div lB)-1)*lB; // Random multiple of lB between 1 and oB-1
61 | "Done with secret keys.";
62 | "====================================================================";
63 |
64 | "Generating Alice's public key... (fast algorithm).";
65 | PK_Alice:=keygen_Alice_fast(SK_Alice,params_Alice,splits_Alice,MAX_Alice);
66 | if simple then
67 | "Generating Alice's public key... (simple algorithm).";
68 | PK_Alice_simple:=keygen_Alice_simple(SK_Alice,params_Alice);
69 | equal := PK_Alice eq PK_Alice_simple;
70 | "Result from simple key gen equal to result from fast key gen?", equal;
71 | assert equal;
72 | end if;
73 | "\nDone with Alice's public key.";
74 | "====================================================================";
75 |
76 | "Generating Bob's public key... (fast algorithm).";
77 | PK_Bob:=keygen_Bob_fast(SK_Bob,params_Bob,splits_Bob,MAX_Bob);
78 | if simple then
79 | "Generating Bob's public key... (simple algorithm).";
80 | PK_Bob_simple:=keygen_Bob_simple(SK_Bob,params_Bob);
81 | equal := PK_Bob eq PK_Bob_simple;
82 | "Result from simple key gen equal to result from fast key gen?", equal;
83 | assert equal;
84 | end if;
85 | "\nDone with Bob's public key.\n";
86 |
87 | "Generating shared secret for Alice... (fast algorithm).";
88 | secret_Alice:=shared_secret_Alice_fast(SK_Alice,PK_Bob,params_Alice,splits_Alice,MAX_Alice);
89 | if simple then
90 | "Generating shared secret for Alice... (simple algorithm).";
91 | secret_Alice_simple:=shared_secret_Alice_simple(SK_Alice,PK_Bob);
92 | equal := secret_Alice eq secret_Alice_simple;
93 | "Results from simple and fast algorithms equal?", equal;
94 | assert equal;
95 | end if;
96 | "\nDone with Alice's shared secret computation.";
97 | "====================================================================";
98 |
99 | "Generating shared secret for Bob... (fast algorithm).";
100 | secret_Bob:=shared_secret_Bob_fast(SK_Bob,PK_Alice,params_Bob,splits_Bob,MAX_Bob);
101 | if simple then
102 | "Generating shared secret for Bob... (simple algorithm).";
103 | secret_Bob_simple:=shared_secret_Bob_simple(SK_Bob,PK_Alice);
104 | equal := secret_Bob eq secret_Bob_simple;
105 | "Results from simple and fast algorithms equal?", equal;
106 | assert equal;
107 | end if;
108 | "\nDone with Bob's shared secret computation.";
109 |
110 | "====================================================================";
111 | "Shared secrets are equal?", secret_Alice eq secret_Bob;
112 | assert secret_Alice eq secret_Bob;
113 | "====================================================================\n";
114 | end for;
115 | end procedure;
116 |
117 | ////////////////////////////////////////////////////////////////////////////////
118 | ///////////////// Key exchange testing with compression ////////////////////////
119 | ////////////////////////////////////////////////////////////////////////////////
120 |
121 | kextest_compress := procedure(n)
122 | for j in [1..n] do
123 | "\n";
124 | j;
125 | "====================================================================";
126 | "Generating secret keys...";
127 | SK_Alice:=Random(1, (oA div lA)-1)*lA; // Random even number between 1 and oA-1
128 | SK_Bob:=Random(1, (oB div lB)-1)*lB; // Random multiple of lB between 1 and oB-1
129 | "Done with secret keys.";
130 | "====================================================================";
131 |
132 | "Generating Alice's public key... (fast algorithm).";
133 | PK_Alice:=keygen_Alice_fast(SK_Alice,params_Alice,splits_Alice,MAX_Alice);
134 | "Compressing Alice's public key.";
135 | PK_Alice_comp_0, PK_Alice_comp_1 := compress_3_torsion(PK_Alice);
136 |
137 | "\nDone with Alice's public key.";
138 | "====================================================================";
139 |
140 | "Generating Bob's public key... (fast algorithm).";
141 | PK_Bob:=keygen_Bob_fast(SK_Bob,params_Bob,splits_Bob,MAX_Bob);
142 | "Compressing Bob's public key.";
143 | PK_Bob_comp_0, PK_Bob_comp_1 := compress_2_torsion(PK_Bob);
144 |
145 | "\nDone with Bob's public key.\n";
146 |
147 | "Decompressing Bob's public key and";
148 | "generating shared secret for Alice... (fast algorithm).";
149 | secret_Alice:=shared_secret_Alice_decompression(SK_Alice,PK_Bob_comp_0,PK_Bob_comp_1,params_Alice,splits_Alice,MAX_Alice);
150 |
151 | "Done with Alice's shared secret computation.";
152 | "====================================================================";
153 |
154 | "Decompressing Alice's public key and";
155 | "generating shared secret for Bob... (fast algorithm).";
156 | secret_Bob:=shared_secret_Bob_decompression(SK_Bob,PK_Alice_comp_0,PK_Alice_comp_1,params_Bob,splits_Bob,MAX_Bob);
157 | // secret_Bob:=shared_secret_Bob_fast(SK_Bob,PK_Alice,params_Bob,splits_Bob,MAX_Bob);
158 | "\nDone with Bob's shared secret computation.";
159 | "====================================================================";
160 | "Shared secrets are equal?", secret_Alice eq secret_Bob;
161 | assert secret_Alice eq secret_Bob;
162 | "====================================================================\n";
163 | end for;
164 | end procedure;
165 |
166 |
167 |
168 | simple := false;
169 | "\n\n\n";
170 | "====================================================================";
171 | "====================================================================";
172 | "=== Testing SIDH ephemeral key exchange ============================";
173 | if simple then
174 | "=== Including simple, but slow isogeny tree traversal ==============";
175 | else
176 | "=== Only fast isogeny tree traversal via optimal strategy ==========";
177 | end if;
178 | "====================================================================";
179 | kextest(10, simple);
180 |
181 | "\n\n\n";
182 | "====================================================================";
183 | "====================================================================";
184 | "=== Testing SIDH ephemeral key exchange with PK compression ========";
185 | "=== Only fast isogeny tree traversal via optimal strategy ==========";
186 | "====================================================================";
187 | kextest_compress(10);
188 |
189 |
--------------------------------------------------------------------------------
/SIDH-Magma/optimalstrategies.mag:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Code to compute optimal strategies for isogeny tree traversal
4 | //
5 | // Based on the relative cost ratios of scalar multiplications,
6 | // optimal strategies are computed by a dynamic programming approach
7 | // as described in DeFeo, Jao, Plut: Towards quantum-resistant
8 | // cryptosystems from supersingular elliptic curve isogenies,
9 | // J. Math. Crypt., 8(3):209-247, 2014.
10 | //
11 | // (c) 2016 Microsoft Corporation. All rights reserved.
12 | //
13 | ////////////////////////////////////////////////////////////////////////////////
14 | //
15 | // Reference:
16 | //
17 | // Efficient algorithms for supersingular isogeny Diffie-Hellman
18 | // Craig Costello, Patrick Longa, Michael Naehrig, CRYPTO 2016.
19 | //
20 | ////////////////////////////////////////////////////////////////////////////////
21 |
22 | clear;
23 | RR := RealField(10);
24 | Z := Integers();
25 | ZPQ := PolynomialRing(Z,2);
26 |
27 | ////////////////////////////////////////////////////////////////////////////////
28 |
29 | nA := 185; // Computing 4^nA-isogenies
30 | //pA := RR!(2*12.9); // Linux cost for 2 doublings
31 | //qA := RR!(22.8); // Linux cost for 4-isogeny evaluation
32 | // New op counts 2016-06-15
33 | pA := RR!(2*12.1); // Linux cost for 2 doublings
34 | qA := RR!(21.6); // Linux cost for 4-isogeny evaluation
35 |
36 | nB := 239; // Computing 3^nB-isogenies
37 | pB := RR!24.3; // Linux cost for tripling
38 | qB := RR!16.0; // Linux cost for 3-isogeny evaluation
39 |
40 | ////////////////////////////////////////////////////////////////////////////////
41 |
42 | NextCpq := function(p,q,Cpq,PQcounts)
43 | /*
44 | Computes the cost of an optimal strategy for traversing a tree on n leaves
45 | together with the operation counts in terms of scalar multiplications and
46 | isogeny evaluation, given this information for trees on 1 up to n-1 leaves.
47 |
48 | Input:
49 | - The cost p for a scalar multiplication by \ell,
50 | - the cost q for the evaluation of an \ell-isogeny,
51 | - a list Cpq of length n-1 that contains the cost of an optimal strategy
52 | for traversal of a tree with i leaves in Cpq[i], and
53 | - a list PQcounts of pairs such that the i-th pair contains the number
54 | PQcounts[i][1] of \ell-scalar multiplications and the number
55 | PQcounts[i][2] of \ell-isogeny evaluations in order to traverse a tree
56 | on i leaves using the optimal strategy with cost Cpq[i].
57 |
58 | Output:
59 | - The cost newCpq of an optimal strategy for traversing a tree on n leaves,
60 | - the corresponding operation counts newPQcount, and
61 | - the splitting newSpq of the n-node strategy into two optimal
62 | sub-strategies.
63 | */
64 |
65 | pgtq := p gt q;
66 | n := #Cpq + 1; // new index = number of leaves in new strategy
67 |
68 | // Compute all possibilities for the cost of a strategy on n leaves by going
69 | // through all possible splits into two optimal sub-strategies from the
70 | // (n-1) strategies provided in PQcounts.
71 | // Cost = cost of subtree with i leaves + cost of subtree with (n-i) leaves
72 | // + cost of (n-i) scalar mults to get to i-subtree root
73 | // + cost of i isogeny evaluations to get to (n-i) subtree root
74 | newCpqs := [(Cpq[i] + Cpq[n-i] + (n-i)*p + i*q) : i in [1..(n-1)]];
75 |
76 | newCpq := newCpqs[1];
77 | m := 1;
78 | // Choose the cheapest strategy.
79 | for i in [2..(n-1)] do
80 | tmpCpq := newCpqs[i];
81 | if newCpq ge tmpCpq then
82 | // including equality in the condition prefers larger number of isogenies
83 | newCpq := tmpCpq;
84 | m := i;
85 | end if;
86 | end for;
87 | // chosen strategy (m-leave sub-tree on the left, (n-m)-subtree on the right)
88 | newSpq := [m,n-m];
89 | // updating operation counts
90 | newPQcount := [PQcounts[m][1] + PQcounts[n-m][1] + (n-m),
91 | PQcounts[m][2] + PQcounts[n-m][2] + m];
92 |
93 | return newCpq, newSpq, newPQcount;
94 | end function;
95 |
96 | ////////////////////////////////////////////////////////////////////////////////
97 |
98 | GetStrategies := function (n,p,q)
99 | /*
100 | Computes a list of optimal strategies for traversing trees with number of
101 | leaves between 1 and n.
102 |
103 | Input:
104 | - The number n of leaves on the tree,
105 | - the cost p for scalar multiplication by \ell, and
106 | - the cost q for \ell-isogeny evaluation.
107 |
108 | Output:
109 | - A list Spq of length n containing the splits into two subtrees for all
110 | optimal strategies on trees with 1<=i<=n leaves.
111 | - A list PQcounts of length n containing operation counts for the above
112 | strategies.
113 | */
114 |
115 | assert n ge 3;
116 | // Cost for sub-trees with one leaf (=0) and two leaves (p+q)
117 | Cpq := [0, p+q];
118 | // Splits for these sub-trees
119 | Spq := [[0,0], [1,1]];
120 | // Operation counts for these sub-trees
121 | PQcounts := [[0,0], [1,1]];
122 |
123 | // Compute in sequence all optimal strategies for trees with 3<=i<=n leaves.
124 | repeat
125 | newCpq, newSpq, newPQcount := NextCpq(p,q,Cpq,PQcounts);
126 | Append(~Cpq, newCpq);
127 | Append(~Spq, newSpq);
128 | Append(~PQcounts, newPQcount);
129 | until #Cpq eq n;
130 |
131 | return Spq, PQcounts;
132 | end function;
133 |
134 | ////////////////////////////////////////////////////////////////////////////////
135 |
136 | function GetSplits(n,Spq)
137 | /*
138 | Assembles a list of splits by taking the number of leaves in the respective
139 | right subtrees which is equal to the number of scalar multiplications to
140 | reach the root of the next sub-strategy.
141 |
142 | Input:
143 | - The number n of leaves on the tree and
144 | - the list of splits into two sub-trees as above.
145 |
146 | Output:
147 | - A list of length n describing the splits by giving the number of scalar
148 | multiplications by \ell to the root of the next subtree.
149 | */
150 |
151 | return [Spq[i][2]: i in [1..n]];
152 | end function;
153 |
154 | ////////////////////////////////////////////////////////////////////////////////
155 | //
156 | // Computing optimal strategies
157 | //
158 | ////////////////////////////////////////////////////////////////////////////////
159 |
160 | "";
161 | SpqA, PQcountsA := GetStrategies(nA,pA,qA);
162 | "Top Strategy for A:", SpqA[nA];
163 | PQcountsA[nA][1], "MUL-BY-4 and", PQcountsA[nA][2], "4-ISO-EVAL == ",
164 | PQcountsA[nA][1]*pA + PQcountsA[nA][2]*qA, "total units";
165 | "Splits for A:", GetSplits(nA,SpqA);
166 |
167 |
168 | "";
169 | SpqB, PQcountsB := GetStrategies(nB,pB,qB);
170 | "Top Strategy for B:", SpqB[nB];
171 | PQcountsB[nB][1], "MUL-BY-3 and", PQcountsB[nB][2], "3-ISO-EVAL == ",
172 | PQcountsB[nB][1]*pB + PQcountsB[nB][2]*qB, "total units";
173 | "Splits for B:", GetSplits(nB,SpqB);
174 | "";
175 |
176 | ////////////////////////////////////////////////////////////////////////////////
177 |
178 |
--------------------------------------------------------------------------------
/SIDH.c:
--------------------------------------------------------------------------------
1 | /********************************************************************************************
2 | * SIDH: an efficient supersingular isogeny-based cryptography library for ephemeral
3 | * Diffie-Hellman key exchange.
4 | *
5 | * Copyright (c) Microsoft Corporation. All rights reserved.
6 | *
7 | *
8 | * Abstract: supersingular elliptic curve isogeny parameters
9 | *
10 | *********************************************************************************************/
11 |
12 | #include "SIDH_internal.h"
13 |
14 |
15 | // Encoding of field elements, elements over Z_order, elements over GF(p^2) and elliptic curve points:
16 | // --------------------------------------------------------------------------------------------------
17 | // Elements over GF(p) and Z_order are encoded with the least significant octet (and digit) located
18 | // at the leftmost position (i.e., little endian format).
19 | // Elements (a+b*i) over GF(p^2), where a and b are defined over GF(p), are encoded as {b, a}, with b
20 | // in the least significant position.
21 | // Elliptic curve points P = (x,y) are encoded as {x, y}, with x in the least significant position.
22 |
23 | //
24 | // Curve isogeny system "SIDHp751". Base curve: Montgomery curve By^2 = Cx^3 + Ax^2 + Cx defined over GF(p751^2), where A=0, B=1 and C=1
25 | //
26 |
27 | CurveIsogenyStaticData CurveIsogeny_SIDHp751 = {
28 | "SIDHp751", 768, 384, // Curve isogeny system ID, smallest multiple of 32 larger than the prime bitlength and smallest multiple of 32 larger than the order bitlength
29 | 751, // Bitlength of the prime
30 | // Prime p751 = 2^372*3^239-1
31 | { 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xEEAFFFFFFFFFFFFF,
32 | 0xE3EC968549F878A8, 0xDA959B1A13F7CC76, 0x084E9867D6EBE876, 0x8562B5045CB25748, 0x0E12909F97BADC66, 0x00006FE5D541F71C },
33 | // Base curve parameter "A"
34 | { 0 },
35 | // Base curve parameter "C"
36 | { 1 },
37 | // Order bitlength for Alice
38 | 372,
39 | // Order of Alice's subgroup
40 | { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0010000000000000 },
41 | // Order bitlength for Bob
42 | 379,
43 | // Power of Bob's subgroup order
44 | 239,
45 | // Order of Bob's subgroup
46 | { 0xC968549F878A8EEB, 0x59B1A13F7CC76E3E, 0xE9867D6EBE876DA9, 0x2B5045CB25748084, 0x2909F97BADC66856, 0x06FE5D541F71C0E1 },
47 | // Alice's generator PA = (XPA,YPA), where XPA and YPA are defined over GF(p751)
48 | { 0x4B0346F5CCE233E9, 0x632646086CE3ACD5, 0x5661D14AB7347693, 0xA58A20449AF1F133, 0xB9AC2F40C56D6FA4, 0x8E561E008FA0E3F3,
49 | 0x6CAE096D5DB822C9, 0x83FDB7A4AD3E83E8, 0xB1317AD904386217, 0x3FA23F89F6BE06D2, 0x429C8D36FF46BCC9, 0x00003E82027A38E9,
50 | 0x12E0D620BFB341D5, 0x0F8EEA7370893430, 0x5A99EBEC3B5B8B00, 0x236C7FAC9E69F7FD, 0x0F147EF3BD0CFEC5, 0x8ED5950D80325A8D,
51 | 0x1E911F50BF3F721A, 0x163A7421DFA8378D, 0xC331B043DA010E6A, 0x5E15915A755883B7, 0xB6236F5F598D56EB, 0x00003BBF8DCD4E7E },
52 | // Bob's generator PB = (XPB,YPB), where XPB and YPB are defined over GF(p751)
53 | { 0x76ED2325DCC93103, 0xD9E1DF566C1D26D3, 0x76AECB94B919AEED, 0xD3785AAAA4D646C5, 0xCB610E30288A7770, 0x9BD3778659023B9E,
54 | 0xD5E69CF26DF23742, 0xA3AD8E17B9F9238C, 0xE145FE2D525160E0, 0xF8D5BCE859ED725D, 0x960A01AB8FF409A2, 0x00002F1D80EF06EF,
55 | 0x91479226A0687894, 0xBBC6BAF5F6BA40BB, 0x15B529122CFE3CA6, 0x7D12754F00E898A3, 0x76EBA0C8419745E9, 0x0A94F06CDFB3EADE,
56 | 0x399A6EDB2EEB2F9B, 0xE302C5129C049EEB, 0xC35892123951D4B6, 0x15445287ED1CC55D, 0x1ACAF351F09AB55A, 0x00000127A46D082A },
57 | // BigMont's curve parameter A24 = (A+2)/4
58 | 156113,
59 | // BigMont's order, where BigMont is defined by y^2=x^3+A*x^2+x
60 | { 0xA59B73D250E58055, 0xCB063593D0BE10E1, 0xF6515CCB5D076CBB, 0x66880747EDDF5E20, 0xBA515248A6BFD4AB, 0x3B8EF00DDDDC789D,
61 | 0xB8FB25A1527E1E2A, 0xB6A566C684FDF31D, 0x0213A619F5BAFA1D, 0xA158AD41172C95D2, 0x0384A427E5EEB719, 0x00001BF975507DC7 },
62 | // Montgomery constant Montgomery_R2 = (2^768)^2 mod p751
63 | { 0x233046449DAD4058, 0xDB010161A696452A, 0x5E36941472E3FD8E, 0xF40BFE2082A2E706, 0x4932CCA8904F8751 ,0x1F735F1F1EE7FC81,
64 | 0xA24F4D80C1048E18, 0xB56C383CCDB607C5, 0x441DD47B735F9C90, 0x5673ED2C6A6AC82A, 0x06C905261132294B, 0x000041AD830F1F35 },
65 | // Montgomery constant -p751^-1 mod 2^768
66 | { 0x0000000000000001, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0xEEB0000000000000,
67 | 0xE3EC968549F878A8, 0xDA959B1A13F7CC76, 0x084E9867D6EBE876, 0x8562B5045CB25748, 0x0E12909F97BADC66, 0x258C28E5D541F71C },
68 | // Value one in Montgomery representation
69 | { 0x00000000000249ad, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x8310000000000000,
70 | 0x5527b1e4375c6c66, 0x697797bf3f4f24d0, 0xc89db7b2ac5c4e2e, 0x4ca4b439d2076956, 0x10f7926c7512c7e9, 0x00002d5b24bce5e2 }
71 | };
72 |
73 |
74 | // Fixed parameters for isogeny tree computation
75 |
76 | const unsigned int splits_Alice[MAX_Alice] = {
77 | 0, 1, 1, 2, 2, 2, 3, 4, 4, 4, 4, 5, 5, 6, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 12,
78 | 11, 12, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 17, 17, 18, 18, 17, 21, 17,
79 | 18, 21, 20, 21, 21, 21, 21, 21, 22, 25, 25, 25, 26, 27, 28, 28, 29, 30, 31,
80 | 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 35, 36, 36, 33, 36, 35, 36, 36, 35,
81 | 36, 36, 37, 38, 38, 39, 40, 41, 42, 38, 39, 40, 41, 42, 40, 46, 42, 43, 46,
82 | 46, 46, 46, 48, 48, 48, 48, 49, 49, 48, 53, 54, 51, 52, 53, 54, 55, 56, 57,
83 | 58, 59, 59, 60, 62, 62, 63, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65,
84 | 65, 66, 67, 65, 66, 67, 66, 69, 70, 66, 67, 66, 69, 70, 69, 70, 70, 71, 72,
85 | 71, 72, 72, 74, 74, 75, 72, 72, 74, 74, 75, 72, 72, 74, 75, 75, 72, 72, 74,
86 | 75, 75, 77, 77, 79, 80, 80, 82 };
87 |
88 | const unsigned int splits_Bob[MAX_Bob] = {
89 | 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9,
90 | 10, 12, 12, 12, 12, 12, 12, 13, 14, 14, 15, 16, 16, 16, 16, 16, 17, 16, 16,
91 | 17, 19, 19, 20, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24, 25, 27,
92 | 27, 28, 28, 29, 28, 29, 28, 28, 28, 30, 28, 28, 28, 29, 30, 33, 33, 33, 33,
93 | 34, 35, 37, 37, 37, 37, 38, 38, 37, 38, 38, 38, 38, 38, 39, 43, 38, 38, 38,
94 | 38, 43, 40, 41, 42, 43, 48, 45, 46, 47, 47, 48, 49, 49, 49, 50, 51, 50, 49,
95 | 49, 49, 49, 51, 49, 53, 50, 51, 50, 51, 51, 51, 52, 55, 55, 55, 56, 56, 56,
96 | 56, 56, 58, 58, 61, 61, 61, 63, 63, 63, 64, 65, 65, 65, 65, 66, 66, 65, 65,
97 | 66, 66, 66, 66, 66, 66, 66, 71, 66, 73, 66, 66, 71, 66, 73, 66, 66, 71, 66,
98 | 73, 68, 68, 71, 71, 73, 73, 73, 75, 75, 78, 78, 78, 80, 80, 80, 81, 81, 82,
99 | 83, 84, 85, 86, 86, 86, 86, 86, 87, 86, 88, 86, 86, 86, 86, 88, 86, 88, 86,
100 | 86, 86, 88, 88, 86, 86, 86, 93, 90, 90, 92, 92, 92, 93, 93, 93, 93, 93, 97,
101 | 97, 97, 97, 97, 97 };
102 |
103 |
104 | const uint64_t LIST[22][NWORDS64_FIELD] = {
105 | { 0xC4EC4EC4EC4EDB72, 0xEC4EC4EC4EC4EC4E, 0x4EC4EC4EC4EC4EC4, 0xC4EC4EC4EC4EC4EC, 0xEC4EC4EC4EC4EC4E, 0x7464EC4EC4EC4EC4,
106 | 0x40E503E18E2D8BE1, 0x4C633882E467773F, 0x998CB725CB703B25, 0x51F8F01043ABC448, 0x70A53813C7A0B43A, 0x00006D56A7157672 },
107 | { 0x276276276275B6C1, 0x6276276276276276, 0x7627627627627627, 0x2762762762762762, 0x6276276276276276, 0x6377627627627627,
108 | 0x2F25DD32AAF69FE5, 0xC6FBECF3EDD1AA16, 0x29C9664A396A6297, 0x0110D8C47D20DEFD, 0x1322BABB1082C8DD, 0x00000CCBE6DE8350 },
109 | { 0x093B97EBDB11A7FE, 0x5093B97EBDB11A05, 0x05093B97EBDB11A0, 0xA05093B97EBDB11A, 0x1A05093B97EBDB11, 0x6F005093B97EBDB1,
110 | 0x7204A6634D6196D9, 0x1D6428F62F917BE5, 0x037CE7F8E9689A28, 0x913EC08959C36290, 0x03D1055241F89FDD, 0x000066963FEC58EB },
111 | { 0x98C2BA559CF4F604, 0xA98C2BA559CF516A, 0x6A98C2BA559CF516, 0x16A98C2BA559CF51, 0x516A98C2BA559CF5, 0x1A56A98C2BA559CF,
112 | 0xDD14E231C3FF5DDC, 0x5AB78BDF0FB0C987, 0x168ED3F1672906EC, 0xAEF17C4BE3A425E0, 0x6F1B34309268385F, 0x0000438BAFFC5E17 },
113 | { 0xA37CA5409E30BE12, 0x20D6AFD873D163ED, 0xCA5409E30BA70497, 0x6AFD873D163EDA37, 0x409E30BA7049720D, 0x7013D163EDA37CA5,
114 | 0x196C325CFB1D98A8, 0x2A83CC98457F6BB1, 0x157AA4649C505D94, 0x556B2CFA3ED1E977, 0x9C8FB301D3BE27CD, 0x0000659B5D688370 },
115 | { 0x437158A103E247EB, 0x23A9D7BF076A48BD, 0x158A103E256DD0AF, 0x9D7BF076A48BD437, 0xA103E256DD0AF23A, 0xD3776A48BD437158,
116 | 0xD4F7B332C1F74531, 0x6A60D92C4C627CD9, 0xC8009067FA1223C2, 0x195578D349C85ABC, 0x24DCFD2C3CE56026, 0x00001170D9C4A49E },
117 | { 0xBBC96234E708BFC3, 0xEE2CE77DBE4CE5A9, 0x21EF6EA93828AD37, 0x66C6ED51865018AE, 0xCB18F74253FB3379, 0x6231B31A5644369D,
118 | 0xF1831316FD5F9AD5, 0xD64412327D9D93D5, 0x2D9659AFA40085D6, 0xB872D3713E1F01AD, 0x96B929E85C90E590, 0x00002A0A122F3E1B },
119 | { 0x751DE109156C74F6, 0xC86993912AE79AFE, 0x96234E708BDAC04C, 0xCE77DBE4CE5A9BBC, 0xF6EA93828AD37EE2, 0x51B51865018AE21E,
120 | 0x57F8534430BDF5AF, 0xA5BA9F3225E0FA02, 0x05DBA7E2AB49759E, 0xE4706D1BDBA54763, 0xC5316BE14AF60ADD, 0x00002007A8A7A392 },
121 | { 0x2DEC0AC86E1972FF, 0xD121D09CA2E105D1, 0x258D13A0778EDFB2, 0x25140153000C1B6E, 0xA06B73718D440E30, 0xA46BFDEB49118BC0,
122 | 0x11C799EE82EF46CF, 0xF094D7258BE44445, 0x6B087550522BC899, 0xD4380D82ADEEA2D3, 0x2AFFEB03C6970E0B, 0x00004FF89FD0E867 },
123 | { 0xF48E11E080A36CD8, 0x75AA967CF316BF89, 0xED69E3E85A6CDEA8, 0x228638171449F794, 0xD4107549BB0BC6AE, 0xB7888349726731CC,
124 | 0x0589577AC89D03A2, 0x79218D005004DCD2, 0xA69CB3C82106FDB8, 0xE54D908CD9B31ED9, 0x2BB46423F8B44F5D, 0x0000158FC37F2F78 },
125 | { 0xA2B8F30D2D8B2266, 0x37AE9DA734F3D4D4, 0x4BC3AC46B1EE2D59, 0xA541D219D9E660D2, 0xFD629383B8C12367, 0x0E789576DA7C1E23,
126 | 0x2321F1135780B208, 0x059EED9A8BB7694E, 0x3EAC20CCA7C7B679, 0xADED37DC1395BAAB, 0xD701BA16F6CD4328, 0x0000250A355A8E3D },
127 | { 0x8D08D7B596C87C8E, 0xFC2B5A576AB81FA7, 0x4ED68A1C251D1EAD, 0xA6618E345258FA06, 0xB532F4F490BD3165, 0x0987A5FDBAA88699,
128 | 0x77E908F4AE484907, 0xC85226731C871CED, 0x6F3E5A699F216EC7, 0x70E42ADFCCD68C99, 0x2277864817AA0CAD, 0x000037F521DA6BAC },
129 | { 0xDB72B65CA8D1D274, 0x286A73457D063FD5, 0x7355642D132BA567, 0x2A970D9461C0DC41, 0x93D2A07ED36F3BCC, 0xFD59A18D2D03447E,
130 | 0xBC047FB33098286A, 0x153E65AE22E4D2F0, 0xBC3F628AF44DDCEB, 0xCF8C49463A2BEC5D, 0x64D31CBF9A0FAE5B, 0x00000E88DF789F48 },
131 | { 0x7E0E3CF3F602CC03, 0x240AE231C56EB636, 0x1630875FADB3CA47, 0x3FDF66239B9021FE, 0x4FA6BEA94AAE8287, 0x20BD32942BAEF1D9,
132 | 0x3DBE52BE754CD223, 0xD46D6B986A4C461E, 0x31772CCF6AB0EC49, 0x0362808B445792BE, 0xA57068B23D5D4F04, 0x0000233188CFA1F9 },
133 | { 0x5CFEB9EE80FF8802, 0x641C991F35243E77, 0x109BF7F4D15352D9, 0xF57027C40F2AEC39, 0x78834C224A9E8F4D, 0x3B53C38C5DDA4903,
134 | 0x2472CAD0E4A1DD20, 0x91121637EFEFBFEB, 0x555DDF1E4E875433, 0xD185E0CEBC9A6BF8, 0x247E7766FEA9846A, 0x00004E24131398C0 },
135 | { 0xAE911D5E41FDE1D5, 0x09FD291EAE9A7528, 0xD94DB04CE76D674F, 0xF269A050B317A36A, 0x1010C2464C5B488A, 0x165E22C0571F72CE,
136 | 0xB649686CDD7FAA40, 0xC65F833CCBC8E854, 0xA1DC607E92B4EC01, 0x6A9F6EA6C5D5598C, 0xB73B45E033D20693, 0x0000126974812437 },
137 | { 0x7EF889C1569E078D, 0x8B4790D31AFC6D2F, 0x24BAD80FCF2607D2, 0x13C099586804EDD0, 0x0B219830D09F67F8, 0xFEEBDD0A795A4E0D,
138 | 0x2C86D567D8A5A5C6, 0x29EFDB5516CD064B, 0xAFB0A05F0230B35C, 0x73FCFA65EC7C5CB4, 0x245E08DC310C14E1, 0x00001778AC2903DF },
139 | { 0xF2BF1FF8427C7315, 0x591042D093B90137, 0x23EF8D48782832C9, 0x8DFB39E92296E3D6, 0x0C39FF556BEBDD42, 0x369F6980A4270C5D,
140 | 0x901F9AD6FCBAA761, 0x0E8E81D435F5FC7F, 0x9A795B9A8409D3D3, 0xD29FB9AE4384290F, 0x3B58F53DD7270C90, 0x00001E27D50D0631 },
141 | { 0x838A7C8B0026C13C, 0xD38CAB350DC1F6BD, 0x426C57FE2436E928, 0xB81B289B8792A253, 0xF8EDB68037D3FB8E, 0x677EE0B4C50C01CD,
142 | 0xF43DCE6FED67139A, 0xF87EFEBF43D77877, 0x3EEA0E8543763A8A, 0x26E5A18357A35379, 0x55867648B9EA7D35, 0x000069DEC7A3C7DA },
143 | { 0x91CCFD3901F3F3FE, 0x2053992393125D73, 0x2129B3A10D7FF7C0, 0x74C64B3E68087A32, 0xEE46C5739B026DF9, 0x53E7B33F97EC0300,
144 | 0x14672E57801EC044, 0x18610440AA870975, 0xB6B9D9E0E0097AE6, 0x37AD3B922ED0F367, 0xA737A55936D5A8B8, 0x00005A30AF4F51DA },
145 | { 0xC925488939591E52, 0x8F87728BF0ED44E9, 0xF987EF64E4365147, 0x9338B89963265410, 0x340DA16F22024645, 0x5D295419E474BDC1,
146 | 0xBA0C2E509FC0510B, 0x957E35D641D5DDB5, 0x922F901AA4A236D8, 0xCBFA24C0F7E172E3, 0xB05A32F88CB5B9DC, 0x00001DC7A766A676 },
147 | { 0x6128F8C2B276D2A1, 0x857530A2A633CE28, 0xEB624F41494C5D1E, 0x3FA62AE33B92CCA8, 0x11BCABB4CC4FBE22, 0x91EA14743FDBAC70,
148 | 0x9876F7DF900DC277, 0x375FD25E09091CBA, 0x580F3084B099A111, 0x58E9B3FB623FB297, 0x957732F791F6C337, 0x00000B070F784B99 } };
--------------------------------------------------------------------------------
/SIDH_api.h:
--------------------------------------------------------------------------------
1 | /********************************************************************************************
2 | * SIDH: an efficient supersingular isogeny-based cryptography library for ephemeral
3 | * Diffie-Hellman key exchange.
4 | *
5 | * Copyright (c) Microsoft Corporation. All rights reserved.
6 | *
7 | *
8 | * Abstract: API header file
9 | *
10 | *********************************************************************************************/
11 |
12 | #ifndef __SIDH_API_H__
13 | #define __SIDH_API_H__
14 |
15 |
16 | // For C++
17 | #ifdef __cplusplus
18 | extern "C" {
19 | #endif
20 |
21 |
22 | #include "SIDH.h"
23 |
24 |
25 | /*********************** Ephemeral key exchange API ***********************/
26 |
27 | // SECURITY NOTE: SIDH supports ephemeral Diffie-Hellman key exchange. It is NOT secure to use it with static keys.
28 | // See "On the Security of Supersingular Isogeny Cryptosystems", S.D. Galbraith, C. Petit, B. Shani and Y.B. Ti, in ASIACRYPT 2016, 2016.
29 | // Extended version available at: http://eprint.iacr.org/2016/859
30 |
31 | // Alice's ephemeral key-pair generation
32 | // It produces a private key pPrivateKeyA and computes the public key pPublicKeyA.
33 | // The private key is an even integer in the range [2, oA-2], where oA = 2^372 (i.e., 372 bits in total).
34 | // The public key consists of 3 elements in GF(p751^2), i.e., 564 bytes.
35 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize().
36 | CRYPTO_STATUS EphemeralKeyGeneration_A(unsigned char* pPrivateKeyA, unsigned char* pPublicKeyA, PCurveIsogenyStruct CurveIsogeny);
37 |
38 | // Bob's ephemeral key-pair generation
39 | // It produces a private key pPrivateKeyB and computes the public key pPublicKeyB.
40 | // The private key is an integer in the range [1, oB-1], where oA = 3^239 (i.e., 379 bits in total).
41 | // The public key consists of 3 elements in GF(p751^2), i.e., 564 bytes.
42 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize().
43 | CRYPTO_STATUS EphemeralKeyGeneration_B(unsigned char* pPrivateKeyB, unsigned char* pPublicKeyB, PCurveIsogenyStruct CurveIsogeny);
44 |
45 | // Alice's ephemeral shared secret computation
46 | // It produces a shared secret key pSharedSecretA using her secret key pPrivateKeyA and Bob's public key pPublicKeyB
47 | // Inputs: Alice's pPrivateKeyA is an even integer in the range [2, oA-2], where oA = 2^372 (i.e., 372 bits in total).
48 | // Bob's pPublicKeyB consists of 3 elements in GF(p751^2), i.e., 564 bytes.
49 | // Output: a shared secret pSharedSecretA that consists of one element in GF(p751^2), i.e., 1502 bits in total.
50 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize().
51 | CRYPTO_STATUS EphemeralSecretAgreement_A(const unsigned char* pPrivateKeyA, const unsigned char* pPublicKeyB, unsigned char* pSharedSecretA, PCurveIsogenyStruct CurveIsogeny);
52 |
53 | // Bob's ephemeral shared secret computation
54 | // It produces a shared secret key pSharedSecretB using his secret key pPrivateKeyB and Alice's public key pPublicKeyA
55 | // Inputs: Bob's pPrivateKeyB is an integer in the range [1, oB-1], where oA = 3^239 (i.e., 379 bits in total).
56 | // Alice's pPublicKeyA consists of 3 elements in GF(p751^2), i.e., 564 bytes.
57 | // Output: a shared secret pSharedSecretB that consists of one element in GF(p751^2), i.e., 1502 bits in total.
58 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize().
59 | CRYPTO_STATUS EphemeralSecretAgreement_B(const unsigned char* pPrivateKeyB, const unsigned char* pPublicKeyA, unsigned char* pSharedSecretB, PCurveIsogenyStruct CurveIsogeny);
60 |
61 | /*********************** Ephemeral key exchange API with compressed public keys ***********************/
62 |
63 | // Alice's public key compression
64 | // It produces a compressed output that consists of three elements in Z_orderB and one field element
65 | // Input : Alice's public key PublicKeyA, which consists of 3 elements in GF(p751^2).
66 | // Output: a compressed value CompressedPKA that consists of three elements in Z_orderB and one element in GF(p751^2).
67 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize().
68 | void PublicKeyCompression_A(const unsigned char* PublicKeyA, unsigned char* CompressedPKA, PCurveIsogenyStruct CurveIsogeny);
69 |
70 | // Alice's public key value decompression computed by Bob
71 | // Inputs: Bob's private key SecretKeyB, and
72 | // Alice's compressed public key data CompressedPKA, which consists of three elements in Z_orderB and one element in GF(p751^2),
73 | // Output: a point point_R in coordinates (X:Z) and the curve parameter param_A in GF(p751^2). Outputs are stored in Montgomery representation.
74 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize().
75 | void PublicKeyADecompression_B(const unsigned char* SecretKeyB, const unsigned char* CompressedPKA, unsigned char* point_R, unsigned char* param_A, PCurveIsogenyStruct CurveIsogeny);
76 |
77 | // Alice's ephemeral shared secret computation
78 | // It produces a shared secret key SharedSecretA using her secret key PrivateKeyA and Bob's public key PublicKeyB
79 | // Inputs: Alice's PrivateKeyA is an even integer in the range [2, oA-2], where oA = 2^372 (i.e., 372 bits in total).
80 | // Bob's PublicKeyB consists of 3 elements in GF(p751^2), i.e., 564 bytes.
81 | // Output: a shared secret SharedSecretA that consists of one element in GF(p751^2), i.e., 1502 bits in total.
82 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize().
83 | CRYPTO_STATUS EphemeralSecretAgreement_Compression_A(const unsigned char* PrivateKeyA, const unsigned char* point_R, const unsigned char* param_A, unsigned char* SharedSecretA, PCurveIsogenyStruct CurveIsogeny);
84 |
85 | // Bob's public key compression
86 | // It produces a compressed output that consists of three elements in Z_orderA and one field element
87 | // Input : Bob's public key PublicKeyB, which consists of 3 elements in GF(p751^2).
88 | // Output: a compressed value CompressedPKB that consists of three elements in Z_orderA and one element in GF(p751^2).
89 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize().
90 | void PublicKeyCompression_B(const unsigned char* PublicKeyB, unsigned char* CompressedPKB, PCurveIsogenyStruct CurveIsogeny);
91 |
92 | // Bob's public key value decompression computed by Alice
93 | // Inputs: Alice's private key SecretKeyA, and
94 | // Bob's compressed public key data CompressedPKB, which consists of three elements in Z_orderA and one element in GF(p751^2).
95 | // Output: a point point_R in coordinates (X:Z) and the curve parameter param_A in GF(p751^2). Outputs are stored in Montgomery representation.
96 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize().
97 | void PublicKeyBDecompression_A(const unsigned char* SecretKeyA, const unsigned char* CompressedPKB, unsigned char* point_R, unsigned char* param_A, PCurveIsogenyStruct CurveIsogeny);
98 |
99 | // Bob's ephemeral shared secret computation
100 | // It produces a shared secret key SharedSecretB using his secret key PrivateKeyB and Alice's decompressed data point_R and param_A
101 | // Inputs: Bob's PrivateKeyB is an integer in the range [1, oB-1], where oB = 3^239.
102 | // Alice's decompressed data consists of point_R in (X:Z) coordinates and the curve paramater param_A in GF(p751^2).
103 | // Output: a shared secret SharedSecretB that consists of one element in GF(p751^2).
104 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize().
105 | CRYPTO_STATUS EphemeralSecretAgreement_Compression_B(const unsigned char* PrivateKeyB, const unsigned char* point_R, const unsigned char* param_A, unsigned char* SharedSecretB, PCurveIsogenyStruct CurveIsogeny);
106 |
107 | /*********************** Scalar multiplication API using BigMont ***********************/
108 |
109 | // BigMont's scalar multiplication using the Montgomery ladder
110 | // Inputs: x, the affine x-coordinate of a point P on BigMont: y^2=x^3+A*x^2+x,
111 | // scalar m.
112 | // Output: xout, the affine x-coordinate of m*(x:1)
113 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize().
114 | CRYPTO_STATUS BigMont_ladder(unsigned char* x, digit_t* m, unsigned char* xout, PCurveIsogenyStruct CurveIsogeny);
115 |
116 |
117 | // Encoding of keys for isogeny system "SIDHp751" (wire format):
118 | // ------------------------------------------------------------
119 | // Elements over GF(p751) are encoded in 96 octets in little endian format (i.e., the least significant octet located at the leftmost position).
120 | // Elements (a+b*i) over GF(p751^2), where a and b are defined over GF(p751), are encoded as {b, a}, with b in the least significant position.
121 | // Elements over Z_oA and Z_oB are encoded in 48 octets in little endian format.
122 | //
123 | // Private keys pPrivateKeyA and pPrivateKeyB are defined in Z_oA and Z_oB (resp.) and can have values in the range [2, 2^372-2] and [1, 3^239-1], resp.
124 | // In the key exchange API, they are encoded in 48 octets in little endian format.
125 | // Public keys pPublicKeyA and pPublicKeyB consist of four elements in GF(p751^2). In the key exchange API, they are encoded in 768 octets in little
126 | // endian format.
127 | // Shared keys pSharedSecretA and pSharedSecretB consist of one element in GF(p751^2). In the key exchange API, they are encoded in 192 octets in little
128 | // endian format.
129 |
130 |
131 | #ifdef __cplusplus
132 | }
133 | #endif
134 |
135 |
136 | #endif
137 |
--------------------------------------------------------------------------------
/SIDH_setup.c:
--------------------------------------------------------------------------------
1 | /********************************************************************************************
2 | * SIDH: an efficient supersingular isogeny-based cryptography library for ephemeral
3 | * Diffie-Hellman key exchange.
4 | *
5 | * Copyright (c) Microsoft Corporation. All rights reserved.
6 | *
7 | *
8 | * Abstract: functions for initialization and getting randomness
9 | *
10 | *********************************************************************************************/
11 |
12 | #include "SIDH_internal.h"
13 | #include
14 |
15 |
16 | CRYPTO_STATUS SIDH_curve_initialize(PCurveIsogenyStruct pCurveIsogeny, RandomBytes RandomBytesFunction, PCurveIsogenyStaticData pCurveIsogenyData)
17 | { // Initialize curve isogeny structure pCurveIsogeny with static data extracted from pCurveIsogenyData.
18 | // This needs to be called after allocating memory for "pCurveIsogeny" using SIDH_curve_allocate().
19 | unsigned int i, pwords, owords;
20 |
21 | if (is_CurveIsogenyStruct_null(pCurveIsogeny)) {
22 | return CRYPTO_ERROR_INVALID_PARAMETER;
23 | }
24 |
25 | for (i = 0; i < 8; i++) { // Copy 8-character identifier
26 | pCurveIsogeny->CurveIsogeny[i] = pCurveIsogenyData->CurveIsogeny[i];
27 | }
28 | pCurveIsogeny->pwordbits = pCurveIsogenyData->pwordbits;
29 | pCurveIsogeny->owordbits = pCurveIsogenyData->owordbits;
30 | pCurveIsogeny->pbits = pCurveIsogenyData->pbits;
31 | pCurveIsogeny->oAbits = pCurveIsogenyData->oAbits;
32 | pCurveIsogeny->oBbits = pCurveIsogenyData->oBbits;
33 | pCurveIsogeny->eB = pCurveIsogenyData->eB;
34 | pCurveIsogeny->BigMont_A24 = pCurveIsogenyData->BigMont_A24;
35 | pCurveIsogeny->RandomBytesFunction = RandomBytesFunction;
36 |
37 | pwords = (pCurveIsogeny->pwordbits + RADIX - 1)/RADIX;
38 | owords = (pCurveIsogeny->owordbits + RADIX - 1)/RADIX;
39 | copy_words((digit_t*)pCurveIsogenyData->prime, pCurveIsogeny->prime, pwords);
40 | copy_words((digit_t*)pCurveIsogenyData->A, pCurveIsogeny->A, pwords);
41 | copy_words((digit_t*)pCurveIsogenyData->C, pCurveIsogeny->C, pwords);
42 | copy_words((digit_t*)pCurveIsogenyData->Aorder, pCurveIsogeny->Aorder, owords);
43 | copy_words((digit_t*)pCurveIsogenyData->Border, pCurveIsogeny->Border, owords);
44 | copy_words((digit_t*)pCurveIsogenyData->PA, pCurveIsogeny->PA, 2*pwords);
45 | copy_words((digit_t*)pCurveIsogenyData->PB, pCurveIsogeny->PB, 2*pwords);
46 | copy_words((digit_t*)pCurveIsogenyData->BigMont_order, pCurveIsogeny->BigMont_order, pwords);
47 | copy_words((digit_t*)pCurveIsogenyData->Montgomery_R2, pCurveIsogeny->Montgomery_R2, pwords);
48 | copy_words((digit_t*)pCurveIsogenyData->Montgomery_pp, pCurveIsogeny->Montgomery_pp, pwords);
49 | copy_words((digit_t*)pCurveIsogenyData->Montgomery_one, pCurveIsogeny->Montgomery_one, pwords);
50 |
51 | return CRYPTO_SUCCESS;
52 | }
53 |
54 |
55 | PCurveIsogenyStruct SIDH_curve_allocate(PCurveIsogenyStaticData CurveData)
56 | { // Dynamic allocation of memory for curve isogeny structure.
57 | // Returns NULL on error.
58 | digit_t pbytes = (CurveData->pwordbits + 7)/8;
59 | digit_t obytes = (CurveData->owordbits + 7)/8;
60 | PCurveIsogenyStruct pCurveIsogeny = NULL;
61 |
62 | pCurveIsogeny = (PCurveIsogenyStruct)calloc(1, sizeof(CurveIsogenyStruct));
63 | pCurveIsogeny->prime = (digit_t*)calloc(1, pbytes);
64 | pCurveIsogeny->A = (digit_t*)calloc(1, pbytes);
65 | pCurveIsogeny->C = (digit_t*)calloc(1, pbytes);
66 | pCurveIsogeny->Aorder = (digit_t*)calloc(1, obytes);
67 | pCurveIsogeny->Border = (digit_t*)calloc(1, obytes);
68 | pCurveIsogeny->PA = (digit_t*)calloc(1, 2*pbytes);
69 | pCurveIsogeny->PB = (digit_t*)calloc(1, 2*pbytes);
70 | pCurveIsogeny->BigMont_order = (digit_t*)calloc(1, pbytes);
71 | pCurveIsogeny->Montgomery_R2 = (digit_t*)calloc(1, pbytes);
72 | pCurveIsogeny->Montgomery_pp = (digit_t*)calloc(1, pbytes);
73 | pCurveIsogeny->Montgomery_one = (digit_t*)calloc(1, pbytes);
74 |
75 | if (is_CurveIsogenyStruct_null(pCurveIsogeny)) {
76 | return NULL;
77 | }
78 | return pCurveIsogeny;
79 | }
80 |
81 |
82 | void SIDH_curve_free(PCurveIsogenyStruct pCurveIsogeny)
83 | { // Free memory for curve isogeny structure
84 |
85 | if (pCurveIsogeny != NULL)
86 | {
87 | if (pCurveIsogeny->prime != NULL)
88 | free(pCurveIsogeny->prime);
89 | if (pCurveIsogeny->A != NULL)
90 | free(pCurveIsogeny->A);
91 | if (pCurveIsogeny->C != NULL)
92 | free(pCurveIsogeny->C);
93 | if (pCurveIsogeny->Aorder != NULL)
94 | free(pCurveIsogeny->Aorder);
95 | if (pCurveIsogeny->Border != NULL)
96 | free(pCurveIsogeny->Border);
97 | if (pCurveIsogeny->PA != NULL)
98 | free(pCurveIsogeny->PA);
99 | if (pCurveIsogeny->PB != NULL)
100 | free(pCurveIsogeny->PB);
101 | if (pCurveIsogeny->BigMont_order != NULL)
102 | free(pCurveIsogeny->BigMont_order);
103 | if (pCurveIsogeny->Montgomery_R2 != NULL)
104 | free(pCurveIsogeny->Montgomery_R2);
105 | if (pCurveIsogeny->Montgomery_pp != NULL)
106 | free(pCurveIsogeny->Montgomery_pp);
107 | if (pCurveIsogeny->Montgomery_one != NULL)
108 | free(pCurveIsogeny->Montgomery_one);
109 |
110 | free(pCurveIsogeny);
111 | }
112 | }
113 |
114 |
115 | bool is_CurveIsogenyStruct_null(PCurveIsogenyStruct pCurveIsogeny)
116 | { // Check if curve isogeny structure is NULL
117 |
118 | if (pCurveIsogeny == NULL || pCurveIsogeny->prime == NULL || pCurveIsogeny->A == NULL || pCurveIsogeny->C == NULL || pCurveIsogeny->Aorder == NULL || pCurveIsogeny->Border == NULL ||
119 | pCurveIsogeny->PA == NULL || pCurveIsogeny->PB == NULL || pCurveIsogeny->BigMont_order == NULL || pCurveIsogeny->Montgomery_R2 == NULL || pCurveIsogeny->Montgomery_pp == NULL ||
120 | pCurveIsogeny->Montgomery_one == NULL)
121 | {
122 | return true;
123 | }
124 | return false;
125 | }
126 |
127 |
128 | const char* SIDH_get_error_message(CRYPTO_STATUS Status)
129 | { // Output error/success message for a given CRYPTO_STATUS
130 | struct error_mapping {
131 | unsigned int index;
132 | char* string;
133 | } mapping[CRYPTO_STATUS_TYPE_SIZE] = {
134 | {CRYPTO_SUCCESS, CRYPTO_MSG_SUCCESS},
135 | {CRYPTO_ERROR, CRYPTO_MSG_ERROR},
136 | {CRYPTO_ERROR_DURING_TEST, CRYPTO_MSG_ERROR_DURING_TEST},
137 | {CRYPTO_ERROR_UNKNOWN, CRYPTO_MSG_ERROR_UNKNOWN},
138 | {CRYPTO_ERROR_NOT_IMPLEMENTED, CRYPTO_MSG_ERROR_NOT_IMPLEMENTED},
139 | {CRYPTO_ERROR_NO_MEMORY, CRYPTO_MSG_ERROR_NO_MEMORY},
140 | {CRYPTO_ERROR_INVALID_PARAMETER, CRYPTO_MSG_ERROR_INVALID_PARAMETER},
141 | {CRYPTO_ERROR_SHARED_KEY, CRYPTO_MSG_ERROR_SHARED_KEY},
142 | {CRYPTO_ERROR_PUBLIC_KEY_VALIDATION, CRYPTO_MSG_ERROR_PUBLIC_KEY_VALIDATION},
143 | {CRYPTO_ERROR_TOO_MANY_ITERATIONS, CRYPTO_MSG_ERROR_TOO_MANY_ITERATIONS}
144 | };
145 |
146 | if (Status >= CRYPTO_STATUS_TYPE_SIZE || mapping[Status].string == NULL) {
147 | return "Unrecognized CRYPTO_STATUS";
148 | } else {
149 | return mapping[Status].string;
150 | }
151 | };
152 |
153 |
154 | const uint64_t Border_div3[NWORDS_ORDER] = { 0xEDCD718A828384F9, 0x733B35BFD4427A14, 0xF88229CF94D7CF38, 0x63C56C990C7C2AD6, 0xB858A87E8F4222C7, 0x254C9C6B525EAF5 };
155 |
156 |
157 | CRYPTO_STATUS random_mod_order(digit_t* random_digits, unsigned int AliceOrBob, PCurveIsogenyStruct pCurveIsogeny)
158 | { // Output random values in the range [1, order-1] in little endian format that can be used as private keys.
159 | // It makes requests of random values with length "oAbits" (when AliceOrBob = 0) or "oBbits" (when AliceOrBob = 1) to the "random_bytes" function.
160 | // The process repeats until random value is in [0, Aorder-2] ([0, Border-2], resp.).
161 | // If successful, the output is given in "random_digits" in the range [1, Aorder-1] ([1, Border-1], resp.).
162 | // The "random_bytes" function, which is passed through the curve isogeny structure PCurveIsogeny, should be set up in advance using SIDH_curve_initialize().
163 | // The caller is responsible of providing the "random_bytes" function passing random values as octets.
164 | unsigned int ntry = 0, nbytes, nwords;
165 | digit_t t1[MAXWORDS_ORDER] = {0}, order2[MAXWORDS_ORDER] = {0};
166 | unsigned char mask;
167 | CRYPTO_STATUS Status = CRYPTO_ERROR_UNKNOWN;
168 |
169 | if (random_digits == NULL || is_CurveIsogenyStruct_null(pCurveIsogeny) || AliceOrBob > 1) {
170 | return CRYPTO_ERROR_INVALID_PARAMETER;
171 | }
172 |
173 | clear_words((void*)random_digits, MAXWORDS_ORDER);
174 | t1[0] = 2;
175 | if (AliceOrBob == ALICE) {
176 | nbytes = (pCurveIsogeny->oAbits+7)/8; // Number of random bytes to be requested
177 | nwords = NBITS_TO_NWORDS(pCurveIsogeny->oAbits);
178 | mask = 0x07; // Value for masking last random byte
179 | copy_words(pCurveIsogeny->Aorder, order2, nwords);
180 | mp_shiftr1(order2, nwords); // order/2
181 | mp_sub(order2, t1, order2, nwords); // order2 = order/2-2
182 | } else {
183 | nbytes = (pCurveIsogeny->oBbits+7)/8;
184 | nwords = NBITS_TO_NWORDS(pCurveIsogeny->oBbits);
185 | mask = 0x03; // Value for masking last random byte
186 | mp_sub((digit_t*)Border_div3, t1, order2, nwords); // order2 = order/3-2
187 | }
188 |
189 | do {
190 | ntry++;
191 | if (ntry > 100) { // Max. 100 iterations to obtain random value in [0, order-2]
192 | return CRYPTO_ERROR_TOO_MANY_ITERATIONS;
193 | }
194 | Status = (pCurveIsogeny->RandomBytesFunction)(nbytes, (unsigned char*)random_digits);
195 | if (Status != CRYPTO_SUCCESS) {
196 | return Status;
197 | }
198 | ((unsigned char*)random_digits)[nbytes-1] &= mask; // Masking last byte
199 | } while (mp_sub(order2, random_digits, t1, nwords) == 1);
200 |
201 | clear_words((void*)t1, MAXWORDS_ORDER);
202 | t1[0] = 1;
203 | mp_add(random_digits, t1, random_digits, nwords);
204 | copy_words(random_digits, t1, nwords);
205 | mp_shiftl1(random_digits, nwords); // Alice's output in the range [2, order-2]
206 | if (AliceOrBob == BOB) {
207 | mp_add(random_digits, t1, random_digits, nwords); // Bob's output in the range [3, order-3]
208 | }
209 |
210 | return Status;
211 | }
212 |
213 |
214 | CRYPTO_STATUS random_BigMont_mod_order(digit_t* random_digits, PCurveIsogenyStruct pCurveIsogeny)
215 | { // Output random values in the range [1, BigMont_order-1] in little endian format that can be used as private keys to compute scalar multiplications
216 | // using the elliptic curve BigMont.
217 | // It makes requests of random values with length "BIGMONT_NBITS_ORDER" to the "random_bytes" function.
218 | // The process repeats until random value is in [0, BigMont_order-2]
219 | // If successful, the output is given in "random_digits" in the range [1, BigMont_order-1].
220 | // The "random_bytes" function, which is passed through the curve isogeny structure PCurveIsogeny, should be set up in advance using SIDH_curve_initialize().
221 | // The caller is responsible of providing the "random_bytes" function passing random values as octets.
222 | unsigned int ntry = 0, nbytes = (BIGMONT_NBITS_ORDER+7)/8, nwords = NBITS_TO_NWORDS(BIGMONT_NBITS_ORDER);
223 | digit_t t1[BIGMONT_MAXWORDS_ORDER] = {0}, order2[BIGMONT_MAXWORDS_ORDER] = {0};
224 | unsigned char mask;
225 | CRYPTO_STATUS Status = CRYPTO_ERROR_UNKNOWN;
226 |
227 | if (random_digits == NULL || is_CurveIsogenyStruct_null(pCurveIsogeny)) {
228 | return CRYPTO_ERROR_INVALID_PARAMETER;
229 | }
230 |
231 | clear_words((void*)random_digits, BIGMONT_MAXWORDS_ORDER);
232 | t1[0] = 2;
233 | mask = (unsigned char)(8*nbytes - BIGMONT_NBITS_ORDER);
234 | mp_sub(pCurveIsogeny->BigMont_order, t1, order2, nwords); // order2 = order-2
235 | mask = ((unsigned char)-1 >> mask); // Value for masking last random byte
236 |
237 | do {
238 | ntry++;
239 | if (ntry > 100) { // Max. 100 iterations to obtain random value in [0, order-2]
240 | return CRYPTO_ERROR_TOO_MANY_ITERATIONS;
241 | }
242 | Status = (pCurveIsogeny->RandomBytesFunction)(nbytes, (unsigned char*)random_digits);
243 | if (Status != CRYPTO_SUCCESS) {
244 | return Status;
245 | }
246 | ((unsigned char*)random_digits)[nbytes-1] &= mask; // Masking last byte
247 | } while (mp_sub(order2, random_digits, t1, nwords) == 1);
248 |
249 | clear_words((void*)t1, BIGMONT_MAXWORDS_ORDER);
250 | t1[0] = 1;
251 | mp_add(random_digits, t1, random_digits, nwords); // Output in the range [1, order-1]
252 |
253 | return Status;
254 | }
255 |
256 |
257 | void clear_words(void* mem, digit_t nwords)
258 | { // Clear digits from memory. "nwords" indicates the number of digits to be zeroed.
259 | // This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing.
260 | unsigned int i;
261 | volatile digit_t *v = mem;
262 |
263 | for (i = 0; i < nwords; i++) {
264 | v[i] = 0;
265 | }
266 | }
267 |
268 |
269 |
270 |
271 |
272 |
273 |
--------------------------------------------------------------------------------
/Visual Studio/SIDH/SIDH.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kex_tests", "..\kex_tests\kex_tests.vcxproj", "{98A48FFD-CE31-44B0-B236-D340521E9C0C}"
7 | ProjectSection(ProjectDependencies) = postProject
8 | {8283DD76-E88A-4B63-ABDE-33F014178413} = {8283DD76-E88A-4B63-ABDE-33F014178413}
9 | EndProjectSection
10 | EndProject
11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "arith_tests", "..\arith_tests\arith_tests.vcxproj", "{C9639168-C3FF-4427-BC3B-D907FF11DE73}"
12 | ProjectSection(ProjectDependencies) = postProject
13 | {8283DD76-E88A-4B63-ABDE-33F014178413} = {8283DD76-E88A-4B63-ABDE-33F014178413}
14 | EndProjectSection
15 | EndProject
16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SIDH", "SIDH.vcxproj", "{8283DD76-E88A-4B63-ABDE-33F014178413}"
17 | EndProject
18 | Global
19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
20 | Debug|Win32 = Debug|Win32
21 | Debug|x64 = Debug|x64
22 | Generic|Win32 = Generic|Win32
23 | Generic|x64 = Generic|x64
24 | Release|Win32 = Release|Win32
25 | Release|x64 = Release|x64
26 | EndGlobalSection
27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
28 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Debug|Win32.ActiveCfg = Debug|Win32
29 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Debug|x64.ActiveCfg = Debug|x64
30 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Debug|x64.Build.0 = Debug|x64
31 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Generic|Win32.ActiveCfg = Generic|Win32
32 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Generic|Win32.Build.0 = Generic|Win32
33 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Generic|x64.ActiveCfg = Generic|x64
34 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Generic|x64.Build.0 = Generic|x64
35 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Release|Win32.ActiveCfg = Release|Win32
36 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Release|x64.ActiveCfg = Release|x64
37 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Release|x64.Build.0 = Release|x64
38 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Debug|Win32.ActiveCfg = Debug|Win32
39 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Debug|x64.ActiveCfg = Debug|x64
40 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Debug|x64.Build.0 = Debug|x64
41 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Generic|Win32.ActiveCfg = Generic|Win32
42 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Generic|Win32.Build.0 = Generic|Win32
43 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Generic|x64.ActiveCfg = Generic|x64
44 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Generic|x64.Build.0 = Generic|x64
45 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Release|Win32.ActiveCfg = Release|Win32
46 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Release|x64.ActiveCfg = Release|x64
47 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Release|x64.Build.0 = Release|x64
48 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Debug|Win32.ActiveCfg = Debug|Win32
49 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Debug|x64.ActiveCfg = Debug|x64
50 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Debug|x64.Build.0 = Debug|x64
51 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Generic|Win32.ActiveCfg = Generic|Win32
52 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Generic|Win32.Build.0 = Generic|Win32
53 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Generic|x64.ActiveCfg = Generic|x64
54 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Generic|x64.Build.0 = Generic|x64
55 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Release|Win32.ActiveCfg = Release|Win32
56 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Release|x64.ActiveCfg = Release|x64
57 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Release|x64.Build.0 = Release|x64
58 | EndGlobalSection
59 | GlobalSection(SolutionProperties) = preSolution
60 | HideSolutionNode = FALSE
61 | EndGlobalSection
62 | EndGlobal
63 |
--------------------------------------------------------------------------------
/Visual Studio/SIDH/SIDH.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Generic
14 | Win32
15 |
16 |
17 | Generic
18 | x64
19 |
20 |
21 | Release
22 | Win32
23 |
24 |
25 | Release
26 | x64
27 |
28 |
29 |
30 | {8283DD76-E88A-4B63-ABDE-33F014178413}
31 | Win32Proj
32 | isoECClib
33 | 8.1
34 |
35 |
36 |
37 | StaticLibrary
38 | true
39 | v140
40 | Unicode
41 |
42 |
43 | StaticLibrary
44 | true
45 | v140
46 | Unicode
47 |
48 |
49 | StaticLibrary
50 | false
51 | v140
52 | true
53 | Unicode
54 |
55 |
56 | StaticLibrary
57 | false
58 | v140
59 | true
60 | Unicode
61 |
62 |
63 | StaticLibrary
64 | false
65 | v140
66 | true
67 | Unicode
68 |
69 |
70 | StaticLibrary
71 | false
72 | v140
73 | true
74 | Unicode
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 | Level4
104 | Disabled
105 | __WINDOWS__; _X86_; _GENERIC_;
106 | ProgramDatabase
107 | false
108 | false
109 | false
110 | Default
111 | MultiThreadedDLL
112 | true
113 |
114 |
115 | Windows
116 | true
117 |
118 |
119 |
120 |
121 |
122 |
123 | Level4
124 | Disabled
125 | __WINDOWS__; _AMD64_;
126 | ProgramDatabase
127 | false
128 | false
129 | true
130 | Default
131 | MultiThreadedDLL
132 |
133 |
134 | AdvancedVectorExtensions
135 |
136 |
137 | Windows
138 | true
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 | Level4
154 |
155 |
156 | MaxSpeed
157 | true
158 | true
159 | __WINDOWS__; _X86_; _GENERIC_;
160 | MultiThreadedDLL
161 |
162 |
163 | Windows
164 | true
165 | true
166 | true
167 |
168 |
169 |
170 |
171 | Level4
172 |
173 |
174 | MaxSpeed
175 | true
176 | true
177 | __WINDOWS__; _AMD64_;
178 | MultiThreadedDLL
179 | AdvancedVectorExtensions
180 |
181 |
182 | Windows
183 | true
184 | true
185 | true
186 |
187 |
188 |
189 |
190 | Level4
191 |
192 |
193 | MaxSpeed
194 | true
195 | true
196 | __WINDOWS__; _X86_; _GENERIC_;
197 | MultiThreadedDLL
198 |
199 |
200 | Windows
201 | true
202 | true
203 | true
204 |
205 |
206 |
207 |
208 | Level4
209 |
210 |
211 | MaxSpeed
212 | true
213 | true
214 | __WINDOWS__; _AMD64_; _GENERIC_;
215 | MultiThreadedDLL
216 | AdvancedVectorExtensions
217 |
218 |
219 | Windows
220 | true
221 | true
222 | true
223 |
224 |
225 |
226 |
227 | true
228 | true
229 | true
230 | true
231 |
232 |
233 |
234 |
235 | true
236 | true
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
--------------------------------------------------------------------------------
/Visual Studio/SIDH/SIDH.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 | {c12e408e-2171-41d7-8815-33244cd7b1db}
18 |
19 |
20 | {e81738a2-8bd8-449a-8918-07266c29f2b7}
21 |
22 |
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files\generic
32 |
33 |
34 | Source Files
35 |
36 |
37 | Source Files\x64
38 |
39 |
40 | Source Files
41 |
42 |
43 | Source Files
44 |
45 |
46 |
47 |
48 | Header Files
49 |
50 |
51 | Header Files
52 |
53 |
54 | Header Files
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Visual Studio/arith_tests/arith_tests.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Generic
14 | Win32
15 |
16 |
17 | Generic
18 | x64
19 |
20 |
21 | Release
22 | Win32
23 |
24 |
25 | Release
26 | x64
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | {8283dd76-e88a-4b63-abde-33f014178413}
41 |
42 |
43 |
44 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}
45 | Win32Proj
46 | fp_tests
47 | arith_tests
48 | 8.1
49 |
50 |
51 |
52 | Application
53 | true
54 | v140
55 | Unicode
56 |
57 |
58 | Application
59 | true
60 | v140
61 | Unicode
62 |
63 |
64 | Application
65 | false
66 | v140
67 | true
68 | Unicode
69 |
70 |
71 | Application
72 | false
73 | v140
74 | true
75 | Unicode
76 |
77 |
78 | v140
79 |
80 |
81 | v140
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | true
101 |
102 |
103 | true
104 |
105 |
106 | false
107 |
108 |
109 | false
110 |
111 |
112 |
113 |
114 |
115 | Level4
116 | Disabled
117 | __WINDOWS__; _X86_;
118 | false
119 | Default
120 | MultiThreadedDLL
121 | true
122 | ProgramDatabase
123 |
124 |
125 | Console
126 | true
127 |
128 |
129 |
130 |
131 |
132 |
133 | Level4
134 | Disabled
135 | __WINDOWS__; _AMD64_;
136 | false
137 | Default
138 | MultiThreadedDLL
139 | true
140 | ProgramDatabase
141 | AdvancedVectorExtensions
142 |
143 |
144 | Console
145 | true
146 |
147 |
148 |
149 |
150 | Level4
151 |
152 |
153 | MaxSpeed
154 | true
155 | true
156 | __WINDOWS__; _X86_;
157 | MultiThreadedDLL
158 |
159 |
160 | Console
161 | true
162 | true
163 | true
164 |
165 |
166 |
167 |
168 | Level4
169 |
170 |
171 | MaxSpeed
172 | true
173 | true
174 | __WINDOWS__; _AMD64_;
175 | MultiThreadedDLL
176 | AdvancedVectorExtensions
177 |
178 |
179 | Console
180 | true
181 | true
182 | true
183 |
184 |
185 |
186 |
187 | Level4
188 | true
189 | true
190 | __WINDOWS__; _X86_; _GENERIC_;
191 | true
192 |
193 |
194 | UseLinkTimeCodeGeneration
195 | true
196 |
197 |
198 |
199 |
200 | Level4
201 | true
202 | true
203 | __WINDOWS__; _AMD64_; _GENERIC_;
204 | true
205 | AdvancedVectorExtensions
206 | MaxSpeed
207 |
208 |
209 | UseLinkTimeCodeGeneration
210 | true
211 |
212 |
213 |
214 |
215 |
216 |
--------------------------------------------------------------------------------
/Visual Studio/arith_tests/arith_tests.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 |
29 |
30 | Source Files
31 |
32 |
33 | Source Files
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Visual Studio/kex_tests/kex_tests.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Generic
14 | Win32
15 |
16 |
17 | Generic
18 | x64
19 |
20 |
21 | Release
22 | Win32
23 |
24 |
25 | Release
26 | x64
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | {8283dd76-e88a-4b63-abde-33f014178413}
40 |
41 |
42 |
43 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}
44 | Win32Proj
45 | kex_tests
46 | 8.1
47 |
48 |
49 |
50 | Application
51 | true
52 | v140
53 | Unicode
54 |
55 |
56 | Application
57 | true
58 | v140
59 | Unicode
60 |
61 |
62 | Application
63 | false
64 | v140
65 | true
66 | Unicode
67 |
68 |
69 | Application
70 | false
71 | v140
72 | true
73 | Unicode
74 |
75 |
76 | Application
77 | false
78 | v140
79 | true
80 | Unicode
81 |
82 |
83 | Application
84 | false
85 | v140
86 | true
87 | Unicode
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | true
113 |
114 |
115 | true
116 |
117 |
118 | false
119 |
120 |
121 | false
122 |
123 |
124 | false
125 |
126 |
127 | false
128 |
129 |
130 |
131 |
132 |
133 | Level4
134 | Disabled
135 | __WINDOWS__; _X86_;
136 | AdvancedVectorExtensions
137 |
138 |
139 | Console
140 | true
141 |
142 |
143 |
144 |
145 |
146 |
147 | Level4
148 | Disabled
149 | __WINDOWS__; _AMD64_;
150 | AdvancedVectorExtensions
151 | MultiThreadedDLL
152 |
153 |
154 | Console
155 | true
156 |
157 |
158 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
159 |
160 |
161 | true
162 |
163 |
164 |
165 |
166 | Level4
167 |
168 |
169 | MaxSpeed
170 | true
171 | true
172 | __WINDOWS__; _X86_;
173 | AdvancedVectorExtensions
174 |
175 |
176 | Console
177 | true
178 | true
179 | true
180 |
181 |
182 |
183 |
184 | Level4
185 |
186 |
187 | MaxSpeed
188 | true
189 | true
190 | __WINDOWS__; _X86_; _GENERIC_;
191 | AdvancedVectorExtensions
192 |
193 |
194 | Console
195 | true
196 | true
197 | true
198 |
199 |
200 |
201 |
202 | Level4
203 |
204 |
205 | MaxSpeed
206 | true
207 | true
208 | __WINDOWS__; _AMD64_;
209 | AdvancedVectorExtensions
210 |
211 |
212 | Console
213 | true
214 | true
215 | true
216 |
217 |
218 |
219 |
220 | Level4
221 |
222 |
223 | MaxSpeed
224 | true
225 | true
226 | __WINDOWS__; _AMD64_; _GENERIC_;
227 | AdvancedVectorExtensions
228 |
229 |
230 | Console
231 | true
232 | true
233 | true
234 |
235 |
236 |
237 |
238 |
239 |
--------------------------------------------------------------------------------
/Visual Studio/kex_tests/kex_tests.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 |
26 |
27 | Header Files
28 |
29 |
30 | Header Files
31 |
32 |
33 |
--------------------------------------------------------------------------------
/generic/fp_generic.c:
--------------------------------------------------------------------------------
1 | /********************************************************************************************
2 | * SIDH: an efficient supersingular isogeny-based cryptography library for ephemeral
3 | * Diffie-Hellman key exchange.
4 | *
5 | * Copyright (c) Microsoft Corporation. All rights reserved.
6 | *
7 | *
8 | * Abstract: portable modular arithmetic
9 | *
10 | *********************************************************************************************/
11 |
12 | #include "../SIDH_internal.h"
13 |
14 |
15 | // Global constants
16 | extern const uint64_t p751[NWORDS_FIELD];
17 | extern const uint64_t p751p1[NWORDS_FIELD];
18 | extern const uint64_t p751x2[NWORDS_FIELD];
19 |
20 |
21 | __inline void fpadd751(const digit_t* a, const digit_t* b, digit_t* c)
22 | { // Modular addition, c = a+b mod p751.
23 | // Inputs: a, b in [0, 2*p751-1]
24 | // Output: c in [0, 2*p751-1]
25 | unsigned int i, carry = 0;
26 | digit_t mask;
27 |
28 | for (i = 0; i < NWORDS_FIELD; i++) {
29 | ADDC(carry, a[i], b[i], carry, c[i]);
30 | }
31 |
32 | carry = 0;
33 | for (i = 0; i < NWORDS_FIELD; i++) {
34 | SUBC(carry, c[i], ((digit_t*)p751x2)[i], carry, c[i]);
35 | }
36 | mask = 0 - (digit_t)carry;
37 |
38 | carry = 0;
39 | for (i = 0; i < NWORDS_FIELD; i++) {
40 | ADDC(carry, c[i], ((digit_t*)p751x2)[i] & mask, carry, c[i]);
41 | }
42 | }
43 |
44 |
45 | __inline void fpsub751(const digit_t* a, const digit_t* b, digit_t* c)
46 | { // Modular subtraction, c = a-b mod p751.
47 | // Inputs: a, b in [0, 2*p751-1]
48 | // Output: c in [0, 2*p751-1]
49 | unsigned int i, borrow = 0;
50 | digit_t mask;
51 |
52 | for (i = 0; i < NWORDS_FIELD; i++) {
53 | SUBC(borrow, a[i], b[i], borrow, c[i]);
54 | }
55 | mask = 0 - (digit_t)borrow;
56 |
57 | borrow = 0;
58 | for (i = 0; i < NWORDS_FIELD; i++) {
59 | ADDC(borrow, c[i], ((digit_t*)p751x2)[i] & mask, borrow, c[i]);
60 | }
61 | }
62 |
63 |
64 | __inline void fpneg751(digit_t* a)
65 | { // Modular negation, a = -a mod p751.
66 | // Input/output: a in [0, 2*p751-1]
67 | unsigned int i, borrow = 0;
68 |
69 | for (i = 0; i < NWORDS_FIELD; i++) {
70 | SUBC(borrow, ((digit_t*)p751x2)[i], a[i], borrow, a[i]);
71 | }
72 | }
73 |
74 |
75 | void fpdiv2_751(const digit_t* a, digit_t* c)
76 | { // Modular division by two, c = a/2 mod p751.
77 | // Input : a in [0, 2*p751-1]
78 | // Output: c in [0, 2*p751-1]
79 | unsigned int i, carry = 0;
80 | digit_t mask;
81 |
82 | mask = 0 - (digit_t)(a[0] & 1); // If a is odd compute a+p751
83 | for (i = 0; i < NWORDS_FIELD; i++) {
84 | ADDC(carry, a[i], ((digit_t*)p751)[i] & mask, carry, c[i]);
85 | }
86 |
87 | mp_shiftr1(c, NWORDS_FIELD);
88 | }
89 |
90 |
91 | void fpcorrection751(digit_t* a)
92 | { // Modular correction to reduce field element a in [0, 2*p751-1] to [0, p751-1].
93 | unsigned int i, borrow = 0;
94 | digit_t mask;
95 |
96 | for (i = 0; i < NWORDS_FIELD; i++) {
97 | SUBC(borrow, a[i], ((digit_t*)p751)[i], borrow, a[i]);
98 | }
99 | mask = 0 - (digit_t)borrow;
100 |
101 | borrow = 0;
102 | for (i = 0; i < NWORDS_FIELD; i++) {
103 | ADDC(borrow, a[i], ((digit_t*)p751)[i] & mask, borrow, a[i]);
104 | }
105 | }
106 |
107 |
108 | void digit_x_digit(const digit_t a, const digit_t b, digit_t* c)
109 | { // Digit multiplication, digit * digit -> 2-digit result
110 | register digit_t al, ah, bl, bh, temp;
111 | digit_t albl, albh, ahbl, ahbh, res1, res2, res3, carry;
112 | digit_t mask_low = (digit_t)(-1) >> (sizeof(digit_t)*4), mask_high = (digit_t)(-1) << (sizeof(digit_t)*4);
113 |
114 | al = a & mask_low; // Low part
115 | ah = a >> (sizeof(digit_t) * 4); // High part
116 | bl = b & mask_low;
117 | bh = b >> (sizeof(digit_t) * 4);
118 |
119 | albl = al*bl;
120 | albh = al*bh;
121 | ahbl = ah*bl;
122 | ahbh = ah*bh;
123 | c[0] = albl & mask_low; // C00
124 |
125 | res1 = albl >> (sizeof(digit_t) * 4);
126 | res2 = ahbl & mask_low;
127 | res3 = albh & mask_low;
128 | temp = res1 + res2 + res3;
129 | carry = temp >> (sizeof(digit_t) * 4);
130 | c[0] ^= temp << (sizeof(digit_t) * 4); // C01
131 |
132 | res1 = ahbl >> (sizeof(digit_t) * 4);
133 | res2 = albh >> (sizeof(digit_t) * 4);
134 | res3 = ahbh & mask_low;
135 | temp = res1 + res2 + res3 + carry;
136 | c[1] = temp & mask_low; // C10
137 | carry = temp & mask_high;
138 | c[1] ^= (ahbh & mask_high) + carry; // C11
139 | }
140 |
141 |
142 | void mp_mul_schoolbook(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords)
143 | { // Multiprecision schoolbook multiply, c = a*b, where lng(a) = lng(b) = nwords.
144 | unsigned int i, j;
145 | digit_t u, v, UV[2];
146 | unsigned int carry = 0;
147 |
148 | for (i = 0; i < (2*nwords); i++) c[i] = 0;
149 |
150 | for (i = 0; i < nwords; i++) {
151 | u = 0;
152 | for (j = 0; j < nwords; j++) {
153 | MUL(a[i], b[j], UV+1, UV[0]);
154 | ADDC(0, UV[0], u, carry, v);
155 | u = UV[1] + carry;
156 | ADDC(0, c[i+j], v, carry, v);
157 | u = u + carry;
158 | c[i+j] = v;
159 | }
160 | c[nwords+i] = u;
161 | }
162 | }
163 |
164 |
165 | void mp_mul_comba(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords)
166 | { // Multiprecision comba multiply, c = a*b, where lng(a) = lng(b) = nwords.
167 | unsigned int i, j;
168 | digit_t t = 0, u = 0, v = 0, UV[2];
169 | unsigned int carry = 0;
170 |
171 | for (i = 0; i < nwords; i++) {
172 | for (j = 0; j <= i; j++) {
173 | MUL(a[j], b[i-j], UV+1, UV[0]);
174 | ADDC(0, UV[0], v, carry, v);
175 | ADDC(carry, UV[1], u, carry, u);
176 | t += carry;
177 | }
178 | c[i] = v;
179 | v = u;
180 | u = t;
181 | t = 0;
182 | }
183 |
184 | for (i = nwords; i < 2*nwords-1; i++) {
185 | for (j = i-nwords+1; j < nwords; j++) {
186 | MUL(a[j], b[i-j], UV+1, UV[0]);
187 | ADDC(0, UV[0], v, carry, v);
188 | ADDC(carry, UV[1], u, carry, u);
189 | t += carry;
190 | }
191 | c[i] = v;
192 | v = u;
193 | u = t;
194 | t = 0;
195 | }
196 | c[2*nwords-1] = v;
197 | }
198 |
199 |
200 | void rdc_mont(const dfelm_t ma, felm_t mc)
201 | { // Efficient Montgomery reduction using comba and exploiting the special form of the prime p751.
202 | // mc = ma*R^-1 mod p751x2, where R = 2^768.
203 | // If ma < 2^768*p751, the output mc is in the range [0, 2*p751-1].
204 | // ma is assumed to be in Montgomery representation.
205 | unsigned int i, j, carry, count = p751_ZERO_WORDS;
206 | digit_t UV[2], t = 0, u = 0, v = 0;
207 |
208 | for (i = 0; i < NWORDS_FIELD; i++) {
209 | mc[i] = 0;
210 | }
211 |
212 | for (i = 0; i < NWORDS_FIELD; i++) {
213 | for (j = 0; j < i; j++) {
214 | if (j < (i-p751_ZERO_WORDS+1)) {
215 | MUL(mc[j], ((digit_t*)p751p1)[i-j], UV+1, UV[0]);
216 | ADDC(0, UV[0], v, carry, v);
217 | ADDC(carry, UV[1], u, carry, u);
218 | t += carry;
219 | }
220 | }
221 | ADDC(0, v, ma[i], carry, v);
222 | ADDC(carry, u, 0, carry, u);
223 | t += carry;
224 | mc[i] = v;
225 | v = u;
226 | u = t;
227 | t = 0;
228 | }
229 |
230 | for (i = NWORDS_FIELD; i < 2*NWORDS_FIELD-1; i++) {
231 | if (count > 0) {
232 | count -= 1;
233 | }
234 | for (j = i-NWORDS_FIELD+1; j < NWORDS_FIELD; j++) {
235 | if (j < (NWORDS_FIELD-count)) {
236 | MUL(mc[j], ((digit_t*)p751p1)[i-j], UV+1, UV[0]);
237 | ADDC(0, UV[0], v, carry, v);
238 | ADDC(carry, UV[1], u, carry, u);
239 | t += carry;
240 | }
241 | }
242 | ADDC(0, v, ma[i], carry, v);
243 | ADDC(carry, u, 0, carry, u);
244 | t += carry;
245 | mc[i-NWORDS_FIELD] = v;
246 | v = u;
247 | u = t;
248 | t = 0;
249 | }
250 | ADDC(0, v, ma[2*NWORDS_FIELD-1], carry, v);
251 | mc[NWORDS_FIELD-1] = v;
252 | }
--------------------------------------------------------------------------------
/makefile:
--------------------------------------------------------------------------------
1 | #### Makefile for compilation on Linux ####
2 |
3 | OPT=-O3 # Optimization option by default
4 |
5 | CC=clang
6 | ifeq "$(CC)" "gcc"
7 | COMPILER=gcc
8 | else ifeq "$(CC)" "clang"
9 | COMPILER=clang
10 | endif
11 |
12 | ifeq "$(ARCH)" "x64"
13 | ARCHITECTURE=_AMD64_
14 | else ifeq "$(ARCH)" "x86"
15 | ARCHITECTURE=_X86_
16 | else ifeq "$(ARCH)" "ARM"
17 | ARCHITECTURE=_ARM_
18 | else ifeq "$(ARCH)" "ARM64"
19 | ARCHITECTURE=_ARM64_
20 | endif
21 |
22 | ifeq "$(ARCH_EX)" "haswell"
23 | ARCH_EXTRA=__HASWELL__
24 | else ifeq "$(ARCH_EX)" "skylake"
25 | ARCH_EXTRA=__SKYLAKE__
26 | else ifeq "$(ARCH_EX)" "native"
27 | ARCH_EXTRA=__NATIVE__
28 | endif
29 |
30 | ADDITIONAL_SETTINGS=
31 | ifeq "$(SET)" "EXTENDED"
32 | ADDITIONAL_SETTINGS=-fwrapv -fomit-frame-pointer -march=native
33 | endif
34 |
35 | ifeq "$(ARCH_EX)" "haswell"
36 | ADDITIONAL_SETTINGS+= -march=haswell -m64 -mbmi2
37 | else ifeq "$(ARCH_EX)" "skylake"
38 | ADDITIONAL_SETTINGS+= -march=skylake -m64 -mbmi2 -madx
39 | endif
40 |
41 | ifeq "$(GENERIC)" "TRUE"
42 | USE_GENERIC=-D _GENERIC_
43 | endif
44 |
45 | ifeq "$(ARCH)" "ARM"
46 | ARM_SETTING=-lrt
47 | endif
48 |
49 | ifeq "$(ARCH)" "ARM64"
50 | ARM_SETTING=-lrt
51 | endif
52 |
53 | cc=$(COMPILER)
54 | CFLAGS=-c $(OPT) $(ADDITIONAL_SETTINGS) -D $(ARCHITECTURE) -D __LINUX__ $(USE_GENERIC) -D $(ARCH_EXTRA)
55 | LDFLAGS=
56 | ifeq "$(GENERIC)" "TRUE"
57 | EXTRA_OBJECTS=fp_generic.o
58 | else
59 | ifeq "$(ARCH)" "x64"
60 | EXTRA_OBJECTS=fp_x64.o fp_x64_asm.o
61 | ifeq "$(ARCH_EX)" "haswell"
62 | EXTRA_OBJECTS+= ZREDC_6x4_SH_HW.o
63 | else ifeq "$(ARCH_EX)" "skylake"
64 | EXTRA_OBJECTS+= ZREDC_6x4_SH_SK.o
65 | endif
66 | endif
67 | ifeq "$(ARCH)" "ARM64"
68 | EXTRA_OBJECTS=fp_arm64.o fp_arm64_asm.o
69 | endif
70 | endif
71 | OBJECTS=kex.o ec_isogeny.o SIDH.o SIDH_setup.o fpx.o $(EXTRA_OBJECTS)
72 | OBJECTS_TEST=test_extras.o
73 | OBJECTS_ARITH_TEST=arith_tests.o $(OBJECTS_TEST) $(OBJECTS)
74 | OBJECTS_KEX_TEST=kex_tests.o $(OBJECTS_TEST) $(OBJECTS)
75 | OBJECTS_ALL=$(OBJECTS) $(OBJECTS_ARITH_TEST) $(OBJECTS_KEX_TEST)
76 |
77 | all: arith_test kex_test
78 |
79 | kex_test: $(OBJECTS_KEX_TEST)
80 | $(CC) -o kex_test $(OBJECTS_KEX_TEST) $(ARM_SETTING)
81 |
82 | arith_test: $(OBJECTS_ARITH_TEST)
83 | $(CC) -o arith_test $(OBJECTS_ARITH_TEST) $(ARM_SETTING)
84 |
85 | kex.o: kex.c SIDH_internal.h
86 | $(CC) $(CFLAGS) kex.c
87 |
88 | ec_isogeny.o: ec_isogeny.c SIDH_internal.h
89 | $(CC) $(CFLAGS) ec_isogeny.c
90 |
91 | SIDH.o: SIDH.c SIDH_internal.h
92 | $(CC) $(CFLAGS) SIDH.c
93 |
94 | SIDH_setup.o: SIDH_setup.c SIDH_internal.h
95 | $(CC) $(CFLAGS) SIDH_setup.c
96 |
97 | fpx.o: fpx.c SIDH_internal.h
98 | $(CC) $(CFLAGS) fpx.c
99 |
100 | ifeq "$(GENERIC)" "TRUE"
101 | fp_generic.o: generic/fp_generic.c
102 | $(CC) $(CFLAGS) generic/fp_generic.c
103 | else
104 | ifeq "$(ARCH)" "x64"
105 | fp_x64.o: AMD64/fp_x64.c
106 | $(CC) $(CFLAGS) AMD64/fp_x64.c
107 |
108 | fp_x64_asm.o: AMD64/fp_x64_asm.S
109 | $(CC) $(CFLAGS) AMD64/fp_x64_asm.S
110 |
111 | ifeq "$(ARCH_EX)" "haswell"
112 |
113 | ZREDC_6x4_SH_HW.o: AMD64/ZMULT_HW.h AMD64/ZREDC_6x4_SH_HW.S
114 | $(CC) $(CFLAGS) AMD64/ZREDC_6x4_SH_HW.S
115 |
116 | else ifeq "$(ARCH_EX)" "skylake"
117 |
118 | ZREDC_6x4_SH_SK.o: AMD64/ZMULT_SK.h AMD64/ZREDC_6x4_SH_SK.S
119 | $(CC) $(CFLAGS) AMD64/ZREDC_6x4_SH_SK.S
120 | endif
121 | endif
122 | ifeq "$(ARCH)" "ARM64"
123 | fp_arm64.o: ARM64/fp_arm64.c
124 | $(CC) $(CFLAGS) ARM64/fp_arm64.c
125 |
126 | fp_arm64_asm.o: ARM64/fp_arm64_asm.S
127 | $(CC) $(CFLAGS) ARM64/fp_arm64_asm.S
128 | endif
129 | endif
130 |
131 | test_extras.o: tests/test_extras.c tests/test_extras.h
132 | $(CC) $(CFLAGS) tests/test_extras.c
133 |
134 | arith_tests.o: tests/arith_tests.c SIDH_internal.h
135 | $(CC) $(CFLAGS) tests/arith_tests.c
136 |
137 | kex_tests.o: tests/kex_tests.c SIDH.h
138 | $(CC) $(CFLAGS) tests/kex_tests.c
139 |
140 | .PHONY: clean
141 |
142 | clean:
143 | rm -f arith_test kex_test fp_generic.o fp_x64.o fp_x64_asm.o fp_arm64.o fp_arm64_asm.o ZREDC_6x4_SH_SK.o ZREDC_6x4_SH_HW.o $(OBJECTS_ALL)
144 |
145 |
--------------------------------------------------------------------------------
/tests/test/P503_api.h:
--------------------------------------------------------------------------------
1 | /********************************************************************************************
2 | * SIDH: an efficient supersingular isogeny-based cryptography library
3 | *
4 | * Copyright (c) Microsoft Corporation. All rights reserved.
5 | *
6 | *
7 | * Abstract: API header file for P503
8 | *
9 | *********************************************************************************************/
10 |
11 | #ifndef __P503_API_H__
12 | #define __P503_API_H__
13 |
14 | #include "../config.h"
15 |
16 |
17 | /*********************** Key encapsulation mechanism API ***********************/
18 |
19 | #define CRYPTO_SECRETKEYBYTES 442 // CRYPTO_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes
20 | #define CRYPTO_PUBLICKEYBYTES 378
21 | #define CRYPTO_BYTES 32
22 | #define CRYPTO_CIPHERTEXTBYTES 410 // CRYPTO_PUBLICKEYBYTES + CRYPTO_BYTES bytes
23 |
24 | // SIKE's key generation
25 | // It produces a private key sk and computes the public key pk.
26 | // Outputs: secret key sk (CRYPTO_SECRETKEYBYTES = 442 bytes)
27 | // public key pk (CRYPTO_PUBLICKEYBYTES = 378 bytes)
28 | int crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
29 |
30 | // SIKE's encapsulation
31 | // Input: public key pk (CRYPTO_PUBLICKEYBYTES = 378 bytes)
32 | // Outputs: shared secret ss (CRYPTO_BYTES = 32 bytes)
33 | // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 410 bytes)
34 | int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
35 |
36 | // SIKE's decapsulation
37 | // Input: secret key sk (CRYPTO_SECRETKEYBYTES = 442 bytes)
38 | // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 410 bytes)
39 | // Outputs: shared secret ss (CRYPTO_BYTES = 32 bytes)
40 | int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
41 |
42 |
43 | // Encoding of keys for KEM-based isogeny system "SIKEp503" (wire format):
44 | // ----------------------------------------------------------------------
45 | // Elements over GF(p503) are encoded in 63 octets in little endian format (i.e., the least significant octet is located in the lowest memory address).
46 | // Elements (a+b*i) over GF(p503^2), where a and b are defined over GF(p503), are encoded as {a, b}, with a in the lowest memory portion.
47 | //
48 | // Private keys sk consist of the concatenation of a 32-byte random value and a value in the range [0, 2^252-1]. In the SIDH API, private keys are
49 | // encoded in 64 octets in little endian format (the top 4 bits are zeroes).
50 | // Public keys pk consist of 3 elements in GF(p503^2). In the SIDH API, they are encoded in 378 octets.
51 | // Ciphertexts ct consist of the concatenation of a public key value and a 32-byte value. In the SIDH API, ct is encoded in 378 + 32 = 410 octets.
52 | // Shared keys ss consist of a value of 32 octets.
53 |
54 |
55 | /*********************** Ephemeral key exchange API ***********************/
56 |
57 | #define SIDH_SECRETKEYBYTES 32
58 | #define SIDH_PUBLICKEYBYTES 378
59 | #define SIDH_BYTES 126
60 |
61 | // SECURITY NOTE: SIDH supports ephemeral Diffie-Hellman key exchange. It is NOT secure to use it with static keys.
62 | // See "On the Security of Supersingular Isogeny Cryptosystems", S.D. Galbraith, C. Petit, B. Shani and Y.B. Ti, in ASIACRYPT 2016, 2016.
63 | // Extended version available at: http://eprint.iacr.org/2016/859
64 |
65 | // Generation of Alice's secret key
66 | // Outputs random value in [0, 2^eA - 1] to be used as Alice's private key
67 | void random_mod_order_A(unsigned char* random_digits);
68 |
69 | // Generation of Bob's secret key
70 | // Outputs random value in [0, 2^Floor(Log(2, oB)) - 1] to be used as Bob's private key
71 | void random_mod_order_B(unsigned char* random_digits);
72 |
73 | // Alice's ephemeral public key generation
74 | // Input: a private key PrivateKeyA in the range [0, oA-1], where oA = 2^250, stored in 32 bytes.
75 | // Output: the public key PublicKeyA consisting of 3 GF(p503^2) elements encoded in 378 bytes.
76 | int EphemeralKeyGeneration_A(const unsigned char* PrivateKeyA, unsigned char* PublicKeyA);
77 |
78 | // Bob's ephemeral key-pair generation
79 | // It produces a private key PrivateKeyB and computes the public key PublicKeyB.
80 | // The private key is an integer in the range [0, 2^Floor(Log(2,oB)) - 1], where oB = 3^159, stored in 32 bytes.
81 | // The public key consists of 3 GF(p503^2) elements encoded in 378 bytes.
82 | int EphemeralKeyGeneration_B(const unsigned char* PrivateKeyB, unsigned char* PublicKeyB);
83 |
84 | // Alice's ephemeral shared secret computation
85 | // It produces a shared secret key SharedSecretA using her secret key PrivateKeyA and Bob's public key PublicKeyB
86 | // Inputs: Alice's PrivateKeyA is an integer in the range [0, oA-1], where oA = 2^250, stored in 32 bytes.
87 | // Bob's PublicKeyB consists of 3 GF(p503^2) elements encoded in 378 bytes.
88 | // Output: a shared secret SharedSecretA that consists of one element in GF(p503^2) encoded in 126 bytes.
89 | int EphemeralSecretAgreement_A(const unsigned char* PrivateKeyA, const unsigned char* PublicKeyB, unsigned char* SharedSecretA);
90 |
91 | // Bob's ephemeral shared secret computation
92 | // It produces a shared secret key SharedSecretB using his secret key PrivateKeyB and Alice's public key PublicKeyA
93 | // Inputs: Bob's PrivateKeyB is an integer in the range [0, 2^Floor(Log(2,oB)) - 1], where oB = 3^159, stored in 32 bytes.
94 | // Alice's PublicKeyA consists of 3 GF(p503^2) elements encoded in 378 bytes.
95 | // Output: a shared secret SharedSecretB that consists of one element in GF(p503^2) encoded in 126 bytes.
96 | int EphemeralSecretAgreement_B(const unsigned char* PrivateKeyB, const unsigned char* PublicKeyA, unsigned char* SharedSecretB);
97 |
98 |
99 | // Encoding of keys for KEX-based isogeny system "SIDHp503" (wire format):
100 | // ----------------------------------------------------------------------
101 | // Elements over GF(p503) are encoded in 63 octets in little endian format (i.e., the least significant octet is located in the lowest memory address).
102 | // Elements (a+b*i) over GF(p503^2), where a and b are defined over GF(p503), are encoded as {a, b}, with a in the lowest memory portion.
103 | //
104 | // Private keys PrivateKeyA and PrivateKeyB can have values in the range [0, 2^250-1] and [0, 2^252-1], resp. In the SIDH API, private keys are encoded
105 | // in 32 octets in little endian format.
106 | // Public keys PublicKeyA and PublicKeyB consist of 3 elements in GF(p503^2). In the SIDH API, they are encoded in 378 octets.
107 | // Shared keys SharedSecretA and SharedSecretB consist of one element in GF(p503^2). In the SIDH API, they are encoded in 126 octets.
108 |
109 |
110 | #endif
111 |
--------------------------------------------------------------------------------
/tests/test/P751_api.h:
--------------------------------------------------------------------------------
1 | /********************************************************************************************
2 | * SIDH: an efficient supersingular isogeny-based cryptography library
3 | *
4 | * Copyright (c) Microsoft Corporation. All rights reserved.
5 | *
6 | *
7 | * Abstract: API header file for P751
8 | *
9 | *********************************************************************************************/
10 |
11 | #ifndef __P751_API_H__
12 | #define __P751_API_H__
13 |
14 | #include "../config.h"
15 |
16 |
17 | /*********************** Key encapsulation mechanism API ***********************/
18 |
19 | #define CRYPTO_SECRETKEYBYTES 660 // CRYPTO_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes
20 | #define CRYPTO_PUBLICKEYBYTES 564
21 | #define CRYPTO_BYTES 48
22 | #define CRYPTO_CIPHERTEXTBYTES 612 // CRYPTO_PUBLICKEYBYTES + CRYPTO_BYTES bytes
23 |
24 | // SIKE's key generation
25 | // It produces a private key sk and computes the public key pk.
26 | // Outputs: secret key sk (CRYPTO_SECRETKEYBYTES = 660 bytes)
27 | // public key pk (CRYPTO_PUBLICKEYBYTES = 564 bytes)
28 | int crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
29 |
30 | // SIKE's encapsulation
31 | // Input: public key pk (CRYPTO_PUBLICKEYBYTES = 564 bytes)
32 | // Outputs: shared secret ss (CRYPTO_BYTES = 48 bytes)
33 | // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 612 bytes)
34 | int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
35 |
36 | // SIKE's decapsulation
37 | // Input: secret key sk (CRYPTO_SECRETKEYBYTES = 660 bytes)
38 | // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 410 bytes)
39 | // Outputs: shared secret ss (CRYPTO_BYTES = 32 bytes)
40 | int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
41 |
42 |
43 | // Encoding of keys for KEM-based isogeny system "SIKEp751" (wire format):
44 | // ----------------------------------------------------------------------
45 | // Elements over GF(p751) are encoded in 94 octets in little endian format (i.e., the least significant octet is located in the lowest memory address).
46 | // Elements (a+b*i) over GF(p751^2), where a and b are defined over GF(p751), are encoded as {a, b}, with a in the lowest memory portion.
47 | //
48 | // Private keys sk consist of the concatenation of a 48-byte random value and a value in the range [0, 2^378-1]. In the SIDH API, private keys are
49 | // encoded in 96 octets in little endian format (the top 6 bits are zeroes).
50 | // Public keys pk consist of 3 elements in GF(p751^2). In the SIDH API, they are encoded in 564 octets.
51 | // Ciphertexts ct consist of the concatenation of a public key value and a 48-byte value. In the SIDH API, ct is encoded in 564 + 48 = 612 octets.
52 | // Shared keys ss consist of a value of 48 octets.
53 |
54 |
55 | /*********************** Ephemeral key exchange API ***********************/
56 |
57 | #define SIDH_SECRETKEYBYTES 48
58 | #define SIDH_PUBLICKEYBYTES 564
59 | #define SIDH_BYTES 188
60 |
61 | // SECURITY NOTE: SIDH supports ephemeral Diffie-Hellman key exchange. It is NOT secure to use it with static keys.
62 | // See "On the Security of Supersingular Isogeny Cryptosystems", S.D. Galbraith, C. Petit, B. Shani and Y.B. Ti, in ASIACRYPT 2016, 2016.
63 | // Extended version available at: http://eprint.iacr.org/2016/859
64 |
65 | // Generation of Alice's secret key
66 | // Outputs random value in [0, 2^eA - 1] to be used as Alice's private key
67 | void random_mod_order_A(unsigned char* random_digits);
68 |
69 | // Generation of Bob's secret key
70 | // Outputs random value in [0, 2^Floor(Log(2, oB)) - 1] to be used as Bob's private key
71 | void random_mod_order_B(unsigned char* random_digits);
72 |
73 | // Alice's ephemeral public key generation
74 | // Input: a private key PrivateKeyA in the range [0, oA-1], where oA = 2^372, stored in 47 bytes.
75 | // Output: the public key PublicKeyA consisting of 3 GF(p751^2) elements encoded in 564 bytes.
76 | int EphemeralKeyGeneration_A(const unsigned char* PrivateKeyA, unsigned char* PublicKeyA);
77 |
78 | // Bob's ephemeral key-pair generation
79 | // It produces a private key PrivateKeyB and computes the public key PublicKeyB.
80 | // The private key is an integer in the range [0, 2^Floor(Log(2,oB)) - 1], where oB = 3^239, stored in 48 bytes.
81 | // The public key consists of 3 GF(p751^2) elements encoded in 564 bytes.
82 | int EphemeralKeyGeneration_B(const unsigned char* PrivateKeyB, unsigned char* PublicKeyB);
83 |
84 | // Alice's ephemeral shared secret computation
85 | // It produces a shared secret key SharedSecretA using her secret key PrivateKeyA and Bob's public key PublicKeyB
86 | // Inputs: Alice's PrivateKeyA is an integer in the range [0, oA-1], where oA = 2^372, stored in 47 bytes.
87 | // Bob's PublicKeyB consists of 3 GF(p751^2) elements encoded in 564 bytes.
88 | // Output: a shared secret SharedSecretA that consists of one element in GF(p751^2) encoded in 188 bytes.
89 | int EphemeralSecretAgreement_A(const unsigned char* PrivateKeyA, const unsigned char* PublicKeyB, unsigned char* SharedSecretA);
90 |
91 | // Bob's ephemeral shared secret computation
92 | // It produces a shared secret key SharedSecretB using his secret key PrivateKeyB and Alice's public key PublicKeyA
93 | // Inputs: Bob's PrivateKeyB is an integer in the range [0, 2^Floor(Log(2,oB)) - 1], where oB = 3^239, stored in 48 bytes.
94 | // Alice's PublicKeyA consists of 3 GF(p751^2) elements encoded in 564 bytes.
95 | // Output: a shared secret SharedSecretB that consists of one element in GF(p751^2) encoded in 188 bytes.
96 | int EphemeralSecretAgreement_B(const unsigned char* PrivateKeyB, const unsigned char* PublicKeyA, unsigned char* SharedSecretB);
97 |
98 |
99 | // Encoding of keys for KEX-based isogeny system "SIDHp751" (wire format):
100 | // ----------------------------------------------------------------------
101 | // Elements over GF(p751) are encoded in 94 octets in little endian format (i.e., the least significant octet is located in the lowest memory address).
102 | // Elements (a+b*i) over GF(p751^2), where a and b are defined over GF(p751), are encoded as {a, b}, with a in the lowest memory portion.
103 | //
104 | // Private keys PrivateKeyA and PrivateKeyB can have values in the range [0, 2^372-1] and [0, 2^378-1], resp. In the SIDH API, private keys are encoded
105 | // in 48 octets in little endian format.
106 | // Public keys PublicKeyA and PublicKeyB consist of 3 elements in GF(p751^2). In the SIDH API, they are encoded in 564 octets.
107 | // Shared keys SharedSecretA and SharedSecretB consist of one element in GF(p751^2). In the SIDH API, they are encoded in 188 octets.
108 |
109 |
110 | #endif
111 |
--------------------------------------------------------------------------------
/tests/test/sike.c:
--------------------------------------------------------------------------------
1 | /********************************************************************************************
2 | * SIDH: an efficient supersingular isogeny-based cryptography library
3 | *
4 | * Copyright (c) Microsoft Corporation. All rights reserved.
5 | *
6 | *
7 | * Abstract: isogeny-based key encapsulation mechanism (KEM)
8 | *
9 | *********************************************************************************************/
10 |
11 | #include
12 | #include "sha3/fips202.h"
13 |
14 |
15 | int crypto_kem_keypair(unsigned char *pk, unsigned char *sk)
16 | { // SIKE's key generation
17 | // Outputs: secret key sk (CRYPTO_SECRETKEYBYTES = CRYPTO_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes)
18 | // public key pk (CRYPTO_PUBLICKEYBYTES bytes)
19 |
20 | // Generate lower portion of secret key sk <- s||SK
21 | RandomBytesFunction(sk, CRYPTO_BYTES);
22 | random_mod_order_B(sk + CRYPTO_BYTES); // Get random value in [0, 2^Floor(Log(2,oB))-1]
23 |
24 | // Generate public key pk
25 | EphemeralKeyGeneration_B(sk + CRYPTO_BYTES, pk);
26 |
27 | // Append public key pk to secret key sk
28 | memcpy(&sk[CRYPTO_BYTES + SECRETKEY_B_BYTES], pk, CRYPTO_PUBLICKEYBYTES);
29 |
30 | return 0;
31 | }
32 |
33 |
34 | int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk)
35 | { // SIKE's encapsulation
36 | // Input: public key pk (CRYPTO_PUBLICKEYBYTES bytes)
37 | // Outputs: shared secret ss (CRYPTO_BYTES bytes)
38 | // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = CRYPTO_PUBLICKEYBYTES + CRYPTO_BYTES bytes)
39 | const uint16_t G = 0;
40 | const uint16_t H = 1;
41 | const uint16_t P = 2;
42 | unsigned char ephemeralsk[SECRETKEY_A_BYTES];
43 | unsigned char jinvariant[FP2_ENCODED_BYTES];
44 | unsigned char h[CRYPTO_BYTES];
45 | unsigned char message[CRYPTO_BYTES];
46 | unsigned char temp[SHAKE256_RATE+CRYPTO_CIPHERTEXTBYTES+3];
47 | unsigned int i;
48 |
49 | // Generate ephemeralsk <- KMAC() mod oA
50 | RandomBytesFunction(message, CRYPTO_BYTES);
51 | kmac256_simple(ephemeralsk, SECRETKEY_A_BYTES, G, pk, (unsigned long long)CRYPTO_PUBLICKEYBYTES, message, CRYPTO_BYTES, temp);
52 | ephemeralsk[SECRETKEY_A_BYTES - 1] &= MASK_ALICE;
53 |
54 | // Encrypt
55 | EphemeralKeyGeneration_A(ephemeralsk, ct);
56 | EphemeralSecretAgreement_A(ephemeralsk, pk, jinvariant);
57 | cshake256_simple(h, CRYPTO_BYTES, P, jinvariant, FP2_ENCODED_BYTES); // TODO: PRF
58 | for (i = 0; i < CRYPTO_BYTES; i++) ct[i + CRYPTO_PUBLICKEYBYTES] = message[i] ^ h[i];
59 |
60 | // Generate shared secret ss <- KMAC()
61 | kmac256_simple(ss, CRYPTO_BYTES, H, ct, (unsigned long long)CRYPTO_CIPHERTEXTBYTES, message, CRYPTO_BYTES, temp);
62 |
63 | return 0;
64 | }
65 |
66 |
67 | int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk)
68 | { // SIKE's decapsulation
69 | // Input: secret key sk (CRYPTO_SECRETKEYBYTES = CRYPTO_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes)
70 | // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = CRYPTO_PUBLICKEYBYTES + CRYPTO_BYTES bytes)
71 | // Outputs: shared secret ss (CRYPTO_BYTES bytes)
72 | const uint16_t G = 0;
73 | const uint16_t H = 1;
74 | const uint16_t P = 2;
75 | unsigned char ephemeralsk_[SECRETKEY_A_BYTES];
76 | unsigned char jinvariant_[FP2_ENCODED_BYTES];
77 | unsigned char h_[CRYPTO_BYTES];
78 | unsigned char message_[CRYPTO_BYTES];
79 | unsigned char c0_[CRYPTO_PUBLICKEYBYTES];
80 | unsigned char pk[CRYPTO_PUBLICKEYBYTES];
81 | unsigned char temp[SHAKE256_RATE+CRYPTO_CIPHERTEXTBYTES+3];
82 | unsigned int i;
83 |
84 | // Decrypt
85 | EphemeralSecretAgreement_B(sk + CRYPTO_BYTES, ct, jinvariant_);
86 | cshake256_simple(h_, CRYPTO_BYTES, P, jinvariant_, FP2_ENCODED_BYTES); // TODO: PRF
87 | for (i = 0; i < CRYPTO_BYTES; i++) message_[i] = ct[i + CRYPTO_PUBLICKEYBYTES] ^ h_[i];
88 |
89 | // Generate ephemeralsk_ <- KMAC() mod oA
90 | memcpy(pk, &sk[CRYPTO_BYTES + SECRETKEY_B_BYTES], CRYPTO_PUBLICKEYBYTES);
91 | kmac256_simple(ephemeralsk_, SECRETKEY_A_BYTES, G, pk, (unsigned long long)CRYPTO_PUBLICKEYBYTES, message_, CRYPTO_BYTES, temp);
92 | ephemeralsk_[SECRETKEY_A_BYTES - 1] &= MASK_ALICE;
93 |
94 | EphemeralKeyGeneration_A(ephemeralsk_, c0_);
95 | if (memcmp(c0_, ct, CRYPTO_PUBLICKEYBYTES) == 0) {
96 | kmac256_simple(ss, CRYPTO_BYTES, H, ct, (unsigned long long)CRYPTO_CIPHERTEXTBYTES, message_, CRYPTO_BYTES, temp);
97 | } else {
98 | kmac256_simple(ss, CRYPTO_BYTES, H, ct, (unsigned long long)CRYPTO_CIPHERTEXTBYTES, sk, CRYPTO_BYTES, temp);
99 | }
100 |
101 | return 0;
102 | }
103 |
--------------------------------------------------------------------------------
/tests/test_extras.c:
--------------------------------------------------------------------------------
1 | /********************************************************************************************
2 | * SIDH: an efficient supersingular isogeny-based cryptography library for ephemeral
3 | * Diffie-Hellman key exchange.
4 | *
5 | * Copyright (c) Microsoft Corporation. All rights reserved.
6 | *
7 | *
8 | * Abstract: utility functions for testing and benchmarking
9 | *
10 | *********************************************************************************************/
11 |
12 |
13 | #include "../SIDH_internal.h"
14 | #include "test_extras.h"
15 | #if (OS_TARGET == OS_WIN)
16 | #include
17 | #include
18 | #endif
19 | #if (OS_TARGET == OS_LINUX) && (TARGET == TARGET_ARM || TARGET == TARGET_ARM64)
20 | #include
21 | #endif
22 | #include
23 |
24 |
25 | // Global constants
26 | extern const uint64_t p751[NWORDS_FIELD];
27 | extern const uint64_t Montgomery_R2[NWORDS_FIELD];
28 |
29 | // Montgomery constant -p751^-1 mod 2^768
30 | static uint64_t Montgomery_pp751[NWORDS_FIELD] = { 0x0000000000000001, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0xEEB0000000000000,
31 | 0xE3EC968549F878A8, 0xDA959B1A13F7CC76, 0x084E9867D6EBE876, 0x8562B5045CB25748, 0x0E12909F97BADC66, 0x258C28E5D541F71C };
32 |
33 |
34 | int64_t cpucycles(void)
35 | { // Access system counter for benchmarking
36 | #if (OS_TARGET == OS_WIN) && (TARGET == TARGET_AMD64 || TARGET == TARGET_x86)
37 | return __rdtsc();
38 | #elif (OS_TARGET == OS_WIN) && (TARGET == TARGET_ARM)
39 | return __rdpmccntr64();
40 | #elif (OS_TARGET == OS_LINUX) && (TARGET == TARGET_AMD64 || TARGET == TARGET_x86)
41 | unsigned int hi, lo;
42 |
43 | __asm__ __volatile__ ("rdtsc\n\t" : "=a" (lo), "=d"(hi));
44 | return ((int64_t)lo) | (((int64_t)hi) << 32);
45 | #elif (OS_TARGET == OS_LINUX) && (TARGET == TARGET_ARM || TARGET == TARGET_ARM64)
46 | struct timespec time;
47 |
48 | clock_gettime(CLOCK_REALTIME, &time);
49 | return (int64_t)(time.tv_sec*1e9 + time.tv_nsec);
50 | #else
51 | return 0;
52 | #endif
53 | }
54 |
55 |
56 | CRYPTO_STATUS random_bytes_test(unsigned int nbytes, unsigned char* random_array)
57 | { // Generate "nbytes" random bytes and output the result to random_array
58 | // Returns CRYPTO_SUCCESS (=1) on success, CRYPTO_ERROR (=0) otherwise.
59 | // SECURITY NOTE: TO BE USED FOR TESTING ONLY.
60 | unsigned int i;
61 |
62 | if (nbytes == 0) {
63 | return CRYPTO_ERROR;
64 | }
65 |
66 | for (i = 0; i < nbytes; i++) {
67 | *(random_array + i) = (unsigned char)rand(); // nbytes of random values
68 | }
69 |
70 | return CRYPTO_SUCCESS;
71 | }
72 |
73 |
74 | int compare_words(digit_t* a, digit_t* b, unsigned int nwords)
75 | { // Comparing "nword" elements, a=b? : (1) a!=b, (0) a=b
76 | // SECURITY NOTE: this function does not have constant-time execution. TO BE USED FOR TESTING ONLY.
77 | unsigned int i;
78 |
79 | for (i = 0; i < nwords; i++)
80 | {
81 | if (a[i] != b[i]) return 1;
82 | }
83 |
84 | return 0;
85 | }
86 |
87 |
88 |
89 | static __inline void sub751_test(felm_t a, felm_t b, felm_t c)
90 | { // 751-bit subtraction without borrow, c = a-b where a>b
91 | // SECURITY NOTE: this function does not have constant-time execution. It is for TESTING ONLY.
92 | unsigned int i;
93 | digit_t res, carry, borrow = 0;
94 |
95 | for (i = 0; i < NWORDS_FIELD; i++)
96 | {
97 | res = a[i] - b[i];
98 | carry = (a[i] < b[i]);
99 | c[i] = res - borrow;
100 | borrow = carry || (res < borrow);
101 | }
102 |
103 | return;
104 | }
105 |
106 |
107 | void fprandom751_test(felm_t a)
108 | { // Generating a pseudo-random field element in [0, p751-1]
109 | // SECURITY NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY.
110 | unsigned int i;
111 | int diff = 768-751;
112 | unsigned char* string = NULL;
113 |
114 | string = (unsigned char*)a;
115 | for (i = 0; i < sizeof(digit_t)*NWORDS_FIELD; i++) {
116 | *(string + i) = (unsigned char)rand(); // Obtain 768-bit number
117 | }
118 | a[NWORDS_FIELD-1] &= (((digit_t)(-1) << diff) >> diff);
119 |
120 | while (fpcompare751((digit_t*)p751, a) < 1) { // Force it to [0, modulus-1]
121 | sub751_test(a, (digit_t*)p751, a);
122 | }
123 |
124 | return;
125 | }
126 |
127 |
128 | void fp2random751_test(f2elm_t a)
129 | { // Generating a pseudo-random element in GF(p751^2)
130 | // SECURITY NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY.
131 |
132 | fprandom751_test(a[0]);
133 | fprandom751_test(a[1]);
134 | }
135 |
136 |
137 | int fpcompare751(felm_t a, felm_t b)
138 | { // Comparing two field elements, a=b? : (1) a>b, (0) a=b, (-1) a= 0; i--)
143 | {
144 | if (a[i] > b[i]) return 1;
145 | else if (a[i] < b[i]) return -1;
146 | }
147 |
148 | return 0;
149 | }
150 |
151 |
152 | int fp2compare751(f2elm_t a, f2elm_t b)
153 | { // Comparing two quadratic extension field elements, ai=bi? : (1) ai!=bi, (0) ai=bi
154 | // SECURITY NOTE: this function does not have constant-time execution. TO BE USED FOR TESTING ONLY.
155 |
156 | if (fpcompare751(a[0], b[0])!=0 || fpcompare751(a[1], b[1])!=0) return 1;
157 | return 0;
158 | }
159 |
160 |
161 | static __inline void mp_mul_basic(digit_t* a, digit_t* b, digit_t* c, unsigned int nwords)
162 | { // Multiprecision schoolbook multiprecision multiply, c = a*b, where lng(a) = lng(b) = nwords.
163 | unsigned int i, j;
164 | digit_t u, v, UV[2];
165 | unsigned int carry = 0;
166 |
167 | for (i = 0; i < (2*nwords); i++) c[i] = 0;
168 |
169 | for (i = 0; i < nwords; i++) {
170 | u = 0;
171 | for (j = 0; j < nwords; j++) {
172 | MUL(a[i], b[j], UV+1, UV[0]);
173 | ADDC(0, UV[0], u, carry, v);
174 | u = UV[1] + carry;
175 | ADDC(0, c[i+j], v, carry, v);
176 | u = u + carry;
177 | c[i+j] = v;
178 | }
179 | c[nwords+i] = u;
180 | }
181 | }
182 |
183 |
184 | void fpmul751_mont_basic(felm_t ma, felm_t mb, felm_t mc)
185 | { // Basic Montgomery multiplication, mc = ma*mb*R^-1 mod p751, where ma,mb,mc in [0, p751-1] and R = 2^768.
186 | // ma and mb are assumed to be in Montgomery representation.
187 | // The Montgomery constant pp751 = -p751^(-1) mod R is the global value "Montgomery_pp751".
188 | unsigned int i, bout = 0;
189 | digit_t mask, P[2*NWORDS_FIELD], Q[2*NWORDS_FIELD], temp[2*NWORDS_FIELD];
190 |
191 | mp_mul_basic(ma, mb, P, NWORDS_FIELD); // P = ma * mb
192 | mp_mul_basic(P, (digit_t*)&Montgomery_pp751, Q, NWORDS_FIELD); // Q = P * pp751 mod R
193 | mp_mul_basic(Q, (digit_t*)&p751, temp, NWORDS_FIELD); // temp = Q * p751
194 | mp_add(P, temp, temp, 2*NWORDS_FIELD); // temp = P + Q * p751
195 |
196 | for (i = 0; i < NWORDS_FIELD; i++) { // mc = (P + Q * p751)/R
197 | mc[i] = temp[NWORDS_FIELD+i];
198 | }
199 |
200 | // Final, constant-time subtraction
201 | bout = mp_sub(mc, (digit_t*)&p751, mc, NWORDS_FIELD); // (bout, mc) = mc - p751
202 | mask = 0 - (digit_t)bout; // if mc < 0 then mask = 0xFF..F, else if mc >= 0 then mask = 0x00..0
203 |
204 | for (i = 0; i < NWORDS_FIELD; i++) { // temp = mask & p751
205 | temp[i] = (((digit_t*)p751)[i] & mask);
206 | }
207 | mp_add(mc, temp, mc, NWORDS_FIELD); // mc = mc + (mask & p751)
208 |
209 | return;
210 | }
211 |
212 |
213 | void to_mont_basic(felm_t a, felm_t mc)
214 | { // Conversion to Montgomery representation
215 | // mc = a*R^2*R^-1 mod p751 = a*R mod p751, where a in [0, p751-1]
216 | // The Montgomery constant R^2 mod p751 is the global value "Montgomery_R2".
217 |
218 | fpmul751_mont_basic(a, (digit_t*)&Montgomery_R2, mc);
219 | }
220 |
221 |
222 | void from_mont_basic(felm_t ma, felm_t c)
223 | { // Conversion from Montgomery representation to standard representation
224 | // c = ma*R^-1 mod p751 = a mod p751, where ma in [0, p751-1].
225 | digit_t one[NWORDS_FIELD] = {0};
226 |
227 | one[0] = 1;
228 | fpmul751_mont_basic(ma, one, c);
229 | }
230 |
--------------------------------------------------------------------------------
/tests/test_extras.h:
--------------------------------------------------------------------------------
1 | /********************************************************************************************
2 | * SIDH: an efficient supersingular isogeny-based cryptography library for ephemeral
3 | * Diffie-Hellman key exchange.
4 | *
5 | * Copyright (c) Microsoft Corporation. All rights reserved.
6 | *
7 | *
8 | * Abstract: utility header file for tests
9 | *
10 | *********************************************************************************************/
11 |
12 | #ifndef __TEST_EXTRAS_H__
13 | #define __TEST_EXTRAS_H__
14 |
15 |
16 | // For C++
17 | #ifdef __cplusplus
18 | extern "C" {
19 | #endif
20 |
21 |
22 | #include "../SIDH_internal.h"
23 |
24 |
25 | #if (TARGET == TARGET_ARM || TARGET == TARGET_ARM64)
26 | #define print_unit printf("nsec");
27 | #else
28 | #define print_unit printf("cycles");
29 | #endif
30 |
31 |
32 | // Access system counter for benchmarking
33 | int64_t cpucycles(void);
34 |
35 | // Generate "nbytes" random bytes and output the result to random_array
36 | CRYPTO_STATUS random_bytes_test(unsigned int nbytes, unsigned char* random_array);
37 |
38 | // Comparing "nword" elements, a=b? : (1) a!=b, (0) a=b
39 | int compare_words(digit_t* a, digit_t* b, unsigned int nwords);
40 |
41 | // Generating a pseudo-random field element in [0, p751-1]
42 | void fprandom751_test(felm_t a);
43 |
44 | // Generating a pseudo-random element in GF(p751^2)
45 | void fp2random751_test(f2elm_t a);
46 |
47 | // Comparing two field elements, a=b? : (1) a>b, (0) a=b, (-1) a