1 /********************************************************************************************
2 * Supersingular Isogeny Key Encapsulation Library
3 *
4 * Abstract: ephemeral supersingular isogeny Diffie-Hellman key exchange (SIDH)
5 *********************************************************************************************/
6
7 #include "sikep434r3.h"
8 #include "pq-crypto/s2n_pq_random.h"
9 #include "utils/s2n_safety.h"
10 #include "sikep434r3_fpx.h"
11 #include "sikep434r3_ec_isogeny.h"
12 #include "sikep434r3_api.h"
13
14 /* Initialization of basis points */
init_basis(const digit_t * gen,f2elm_t * XP,f2elm_t * XQ,f2elm_t * XR)15 static void init_basis(const digit_t *gen, f2elm_t *XP, f2elm_t *XQ, f2elm_t *XR)
16 {
17 fpcopy(gen, XP->e[0]);
18 fpcopy(gen + S2N_SIKE_P434_R3_NWORDS_FIELD, XP->e[1]);
19 fpcopy(gen + 2*S2N_SIKE_P434_R3_NWORDS_FIELD, XQ->e[0]);
20 fpcopy(gen + 3*S2N_SIKE_P434_R3_NWORDS_FIELD, XQ->e[1]);
21 fpcopy(gen + 4*S2N_SIKE_P434_R3_NWORDS_FIELD, XR->e[0]);
22 fpcopy(gen + 5*S2N_SIKE_P434_R3_NWORDS_FIELD, XR->e[1]);
23 }
24
25 /* Generation of Bob's secret key
26 * Outputs random value in [0, 2^Floor(Log(2, oB)) - 1] */
random_mod_order_B(unsigned char * random_digits)27 int random_mod_order_B(unsigned char* random_digits)
28 {
29 POSIX_GUARD_RESULT(s2n_get_random_bytes(random_digits, S2N_SIKE_P434_R3_SECRETKEY_B_BYTES));
30 random_digits[S2N_SIKE_P434_R3_SECRETKEY_B_BYTES-1] &= S2N_SIKE_P434_R3_MASK_BOB; /* Masking last byte */
31
32 return 0;
33 }
34
35 /* Alice's ephemeral public key generation
36 * Input: a private key PrivateKeyA in the range [0, 2^eA - 1].
37 * Output: the public key PublicKeyA consisting of 3 elements in GF(p^2) which are encoded
38 * by removing leading 0 bytes. */
EphemeralKeyGeneration_A(const unsigned char * PrivateKeyA,unsigned char * PublicKeyA)39 int EphemeralKeyGeneration_A(const unsigned char* PrivateKeyA, unsigned char* PublicKeyA)
40 {
41 point_proj_t R, phiP = {0}, phiQ = {0}, phiR = {0}, pts[S2N_SIKE_P434_R3_MAX_INT_POINTS_ALICE];
42 f2elm_t _XPA, _XQA, _XRA, coeff[3], _A24plus = {0}, _C24 = {0}, _A = {0};
43 f2elm_t *XPA=&_XPA, *XQA=&_XQA, *XRA=&_XRA, *A24plus=&_A24plus, *C24=&_C24, *A=&_A;
44 unsigned int i, row, m, tree_index = 0, pts_index[S2N_SIKE_P434_R3_MAX_INT_POINTS_ALICE], npts = 0, ii = 0;
45 digit_t SecretKeyA[S2N_SIKE_P434_R3_NWORDS_ORDER] = {0};
46
47 /* Initialize basis points */
48 init_basis((const digit_t*)A_gen, XPA, XQA, XRA);
49 init_basis((const digit_t*)B_gen, &phiP->X, &phiQ->X, &phiR->X);
50 fpcopy((const digit_t*)&Montgomery_one, (phiP->Z.e)[0]);
51 fpcopy((const digit_t*)&Montgomery_one, (phiQ->Z.e)[0]);
52 fpcopy((const digit_t*)&Montgomery_one, (phiR->Z.e)[0]);
53
54 /* Initialize constants: A24plus = A+2C, C24 = 4C, where A=6, C=1 */
55 fpcopy((const digit_t*)&Montgomery_one, A24plus->e[0]);
56 mp2_add(A24plus, A24plus, A24plus);
57 mp2_add(A24plus, A24plus, C24);
58 mp2_add(A24plus, C24, A);
59 mp2_add(C24, C24, A24plus);
60
61 /* Retrieve kernel point */
62 decode_to_digits(PrivateKeyA, SecretKeyA, S2N_SIKE_P434_R3_SECRETKEY_A_BYTES, S2N_SIKE_P434_R3_NWORDS_ORDER);
63 LADDER3PT(XPA, XQA, XRA, SecretKeyA, S2N_SIKE_P434_R3_ALICE, R, A);
64
65 /* Traverse tree */
66 tree_index = 0;
67 for (row = 1; row < S2N_SIKE_P434_R3_MAX_ALICE; row++) {
68 while (tree_index < S2N_SIKE_P434_R3_MAX_ALICE-row) {
69 fp2copy(&R->X, &pts[npts]->X);
70 fp2copy(&R->Z, &pts[npts]->Z);
71 pts_index[npts++] = tree_index;
72 m = strat_Alice[ii++];
73 xDBLe(R, R, A24plus, C24, (int)(2*m));
74 tree_index += m;
75 }
76 get_4_isog(R, A24plus, C24, coeff);
77
78 for (i = 0; i < npts; i++) {
79 eval_4_isog(pts[i], coeff);
80 }
81 eval_4_isog(phiP, coeff);
82 eval_4_isog(phiQ, coeff);
83 eval_4_isog(phiR, coeff);
84
85 fp2copy(&pts[npts-1]->X, &R->X);
86 fp2copy(&pts[npts-1]->Z, &R->Z);
87 tree_index = pts_index[npts-1];
88 npts -= 1;
89 }
90
91 get_4_isog(R, A24plus, C24, coeff);
92 eval_4_isog(phiP, coeff);
93 eval_4_isog(phiQ, coeff);
94 eval_4_isog(phiR, coeff);
95
96 inv_3_way(&phiP->Z, &phiQ->Z, &phiR->Z);
97 fp2mul_mont(&phiP->X, &phiP->Z, &phiP->X);
98 fp2mul_mont(&phiQ->X, &phiQ->Z, &phiQ->X);
99 fp2mul_mont(&phiR->X, &phiR->Z, &phiR->X);
100
101 /* Format public key */
102 fp2_encode(&phiP->X, PublicKeyA);
103 fp2_encode(&phiQ->X, PublicKeyA + S2N_SIKE_P434_R3_FP2_ENCODED_BYTES);
104 fp2_encode(&phiR->X, PublicKeyA + 2*S2N_SIKE_P434_R3_FP2_ENCODED_BYTES);
105
106 return 0;
107 }
108
109 /* Bob's ephemeral public key generation
110 * Input: a private key PrivateKeyB in the range [0, 2^Floor(Log(2,oB)) - 1].
111 * Output: the public key PublicKeyB consisting of 3 elements in GF(p^2) which are encoded
112 * by removing leading 0 bytes. */
EphemeralKeyGeneration_B(const unsigned char * PrivateKeyB,unsigned char * PublicKeyB)113 int EphemeralKeyGeneration_B(const unsigned char* PrivateKeyB, unsigned char* PublicKeyB)
114 {
115 point_proj_t R, phiP = {0}, phiQ = {0}, phiR = {0}, pts[S2N_SIKE_P434_R3_MAX_INT_POINTS_BOB];
116 f2elm_t _XPB, _XQB, _XRB, coeff[3], _A24plus = {0}, _A24minus = {0}, _A = {0};
117 f2elm_t *XPB=&_XPB, *XQB=&_XQB, *XRB=&_XRB, *A24plus=&_A24plus, *A24minus=&_A24minus, *A=&_A;
118
119 unsigned int i, row, m, tree_index = 0, pts_index[S2N_SIKE_P434_R3_MAX_INT_POINTS_BOB], npts = 0, ii = 0;
120 digit_t SecretKeyB[S2N_SIKE_P434_R3_NWORDS_ORDER] = {0};
121
122 /* Initialize basis points */
123 init_basis((const digit_t*)B_gen, XPB, XQB, XRB);
124 init_basis((const digit_t*)A_gen, &phiP->X, &phiQ->X, &phiR->X);
125 fpcopy((const digit_t*)&Montgomery_one, (phiP->Z.e)[0]);
126 fpcopy((const digit_t*)&Montgomery_one, (phiQ->Z.e)[0]);
127 fpcopy((const digit_t*)&Montgomery_one, (phiR->Z.e)[0]);
128
129 /* Initialize constants: A24minus = A-2C, A24plus = A+2C, where A=6, C=1 */
130 fpcopy((const digit_t*)&Montgomery_one, A24plus->e[0]);
131 mp2_add(A24plus, A24plus, A24plus);
132 mp2_add(A24plus, A24plus, A24minus);
133 mp2_add(A24plus, A24minus, A);
134 mp2_add(A24minus, A24minus, A24plus);
135
136 /* Retrieve kernel point */
137 decode_to_digits(PrivateKeyB, SecretKeyB, S2N_SIKE_P434_R3_SECRETKEY_B_BYTES, S2N_SIKE_P434_R3_NWORDS_ORDER);
138 LADDER3PT(XPB, XQB, XRB, SecretKeyB, S2N_SIKE_P434_R3_BOB, R, A);
139
140 /* Traverse tree */
141 tree_index = 0;
142 for (row = 1; row < S2N_SIKE_P434_R3_MAX_BOB; row++) {
143 while (tree_index < S2N_SIKE_P434_R3_MAX_BOB-row) {
144 fp2copy(&R->X, &pts[npts]->X);
145 fp2copy(&R->Z, &pts[npts]->Z);
146 pts_index[npts++] = tree_index;
147 m = strat_Bob[ii++];
148 xTPLe(R, R, A24minus, A24plus, (int)m);
149 tree_index += m;
150 }
151 get_3_isog(R, A24minus, A24plus, coeff);
152
153 for (i = 0; i < npts; i++) {
154 eval_3_isog(pts[i], coeff);
155 }
156 eval_3_isog(phiP, coeff);
157 eval_3_isog(phiQ, coeff);
158 eval_3_isog(phiR, coeff);
159
160 fp2copy(&pts[npts-1]->X, &R->X);
161 fp2copy(&pts[npts-1]->Z, &R->Z);
162 tree_index = pts_index[npts-1];
163 npts -= 1;
164 }
165
166 get_3_isog(R, A24minus, A24plus, coeff);
167 eval_3_isog(phiP, coeff);
168 eval_3_isog(phiQ, coeff);
169 eval_3_isog(phiR, coeff);
170
171 inv_3_way(&phiP->Z, &phiQ->Z, &phiR->Z);
172 fp2mul_mont(&phiP->X, &phiP->Z, &phiP->X);
173 fp2mul_mont(&phiQ->X, &phiQ->Z, &phiQ->X);
174 fp2mul_mont(&phiR->X, &phiR->Z, &phiR->X);
175
176 /* Format public key */
177 fp2_encode(&phiP->X, PublicKeyB);
178 fp2_encode(&phiQ->X, PublicKeyB + S2N_SIKE_P434_R3_FP2_ENCODED_BYTES);
179 fp2_encode(&phiR->X, PublicKeyB + 2*S2N_SIKE_P434_R3_FP2_ENCODED_BYTES);
180
181 return 0;
182 }
183
184 /* Alice's ephemeral shared secret computation
185 * It produces a shared secret key SharedSecretA using her secret key PrivateKeyA and Bob's public key PublicKeyB
186 * Inputs: Alice's PrivateKeyA is an integer in the range [0, oA-1].
187 * Bob's PublicKeyB consists of 3 elements in GF(p^2) encoded by removing leading 0 bytes.
188 * Output: a shared secret SharedSecretA that consists of one element in GF(p^2) encoded
189 * by removing leading 0 bytes. */
EphemeralSecretAgreement_A(const unsigned char * PrivateKeyA,const unsigned char * PublicKeyB,unsigned char * SharedSecretA)190 int EphemeralSecretAgreement_A(const unsigned char* PrivateKeyA, const unsigned char* PublicKeyB,
191 unsigned char* SharedSecretA)
192 {
193 point_proj_t R, pts[S2N_SIKE_P434_R3_MAX_INT_POINTS_ALICE];
194 f2elm_t coeff[3], PKB[3], _jinv;
195 f2elm_t _A24plus = {0}, _C24 = {0}, _A = {0};
196 f2elm_t *jinv=&_jinv, *A24plus=&_A24plus, *C24=&_C24, *A=&_A;
197 unsigned int i, row, m, tree_index = 0, pts_index[S2N_SIKE_P434_R3_MAX_INT_POINTS_ALICE], npts = 0, ii = 0;
198 digit_t SecretKeyA[S2N_SIKE_P434_R3_NWORDS_ORDER] = {0};
199
200 /* Initialize images of Bob's basis */
201 fp2_decode(PublicKeyB, &PKB[0]);
202 fp2_decode(PublicKeyB + S2N_SIKE_P434_R3_FP2_ENCODED_BYTES, &PKB[1]);
203 fp2_decode(PublicKeyB + 2*S2N_SIKE_P434_R3_FP2_ENCODED_BYTES, &PKB[2]);
204
205 /* Initialize constants: A24plus = A+2C, C24 = 4C, where C=1 */
206 get_A(&PKB[0], &PKB[1], &PKB[2], A);
207 mp_add((const digit_t*)&Montgomery_one, (const digit_t*)&Montgomery_one, C24->e[0], S2N_SIKE_P434_R3_NWORDS_FIELD);
208 mp2_add(A, C24, A24plus);
209 mp_add(C24->e[0], C24->e[0], C24->e[0], S2N_SIKE_P434_R3_NWORDS_FIELD);
210
211 /* Retrieve kernel point */
212 decode_to_digits(PrivateKeyA, SecretKeyA, S2N_SIKE_P434_R3_SECRETKEY_A_BYTES, S2N_SIKE_P434_R3_NWORDS_ORDER);
213 LADDER3PT(&PKB[0], &PKB[1], &PKB[2], SecretKeyA, S2N_SIKE_P434_R3_ALICE, R, A);
214
215 /* Traverse tree */
216 tree_index = 0;
217 for (row = 1; row < S2N_SIKE_P434_R3_MAX_ALICE; row++) {
218 while (tree_index < S2N_SIKE_P434_R3_MAX_ALICE-row) {
219 fp2copy(&R->X, &pts[npts]->X);
220 fp2copy(&R->Z, &pts[npts]->Z);
221 pts_index[npts++] = tree_index;
222 m = strat_Alice[ii++];
223 xDBLe(R, R, A24plus, C24, (int)(2*m));
224 tree_index += m;
225 }
226 get_4_isog(R, A24plus, C24, coeff);
227
228 for (i = 0; i < npts; i++) {
229 eval_4_isog(pts[i], coeff);
230 }
231
232 fp2copy(&pts[npts-1]->X, &R->X);
233 fp2copy(&pts[npts-1]->Z, &R->Z);
234 tree_index = pts_index[npts-1];
235 npts -= 1;
236 }
237
238 get_4_isog(R, A24plus, C24, coeff);
239 mp2_add(A24plus, A24plus, A24plus);
240 fp2sub(A24plus, C24, A24plus);
241 fp2add(A24plus, A24plus, A24plus);
242 j_inv(A24plus, C24, jinv);
243 fp2_encode(jinv, SharedSecretA); /* Format shared secret */
244
245 return 0;
246 }
247
248 /* Bob's ephemeral shared secret computation
249 * It produces a shared secret key SharedSecretB using his secret key PrivateKeyB and Alice's public key PublicKeyA
250 * Inputs: Bob's PrivateKeyB is an integer in the range [0, 2^Floor(Log(2,oB)) - 1].
251 * Alice's PublicKeyA consists of 3 elements in GF(p^2) encoded by removing leading 0 bytes.
252 * Output: a shared secret SharedSecretB that consists of one element in GF(p^2) encoded
253 * by removing leading 0 bytes. */
EphemeralSecretAgreement_B(const unsigned char * PrivateKeyB,const unsigned char * PublicKeyA,unsigned char * SharedSecretB)254 int EphemeralSecretAgreement_B(const unsigned char* PrivateKeyB, const unsigned char* PublicKeyA,
255 unsigned char* SharedSecretB)
256 {
257 point_proj_t R, pts[S2N_SIKE_P434_R3_MAX_INT_POINTS_BOB];
258 f2elm_t coeff[3], PKB[3], _jinv;
259 f2elm_t _A24plus = {0}, _A24minus = {0}, _A = {0};
260 f2elm_t *jinv=&_jinv, *A24plus=&_A24plus, *A24minus=&_A24minus, *A=&_A;
261 unsigned int i, row, m, tree_index = 0, pts_index[S2N_SIKE_P434_R3_MAX_INT_POINTS_BOB], npts = 0, ii = 0;
262 digit_t SecretKeyB[S2N_SIKE_P434_R3_NWORDS_ORDER] = {0};
263
264 /* Initialize images of Alice's basis */
265 fp2_decode(PublicKeyA, &PKB[0]);
266 fp2_decode(PublicKeyA + S2N_SIKE_P434_R3_FP2_ENCODED_BYTES, &PKB[1]);
267 fp2_decode(PublicKeyA + 2*S2N_SIKE_P434_R3_FP2_ENCODED_BYTES, &PKB[2]);
268
269 /* Initialize constants: A24plus = A+2C, A24minus = A-2C, where C=1 */
270 get_A(&PKB[0], &PKB[1], &PKB[2], A);
271 mp_add((const digit_t*)&Montgomery_one, (const digit_t*)&Montgomery_one, A24minus->e[0], S2N_SIKE_P434_R3_NWORDS_FIELD);
272 mp2_add(A, A24minus, A24plus);
273 mp2_sub_p2(A, A24minus, A24minus);
274
275 /* Retrieve kernel point */
276 decode_to_digits(PrivateKeyB, SecretKeyB, S2N_SIKE_P434_R3_SECRETKEY_B_BYTES, S2N_SIKE_P434_R3_NWORDS_ORDER);
277 LADDER3PT(&PKB[0], &PKB[1], &PKB[2], SecretKeyB, S2N_SIKE_P434_R3_BOB, R, A);
278
279 /* Traverse tree */
280 tree_index = 0;
281 for (row = 1; row < S2N_SIKE_P434_R3_MAX_BOB; row++) {
282 while (tree_index < S2N_SIKE_P434_R3_MAX_BOB-row) {
283 fp2copy(&R->X, &pts[npts]->X);
284 fp2copy(&R->Z, &pts[npts]->Z);
285 pts_index[npts++] = tree_index;
286 m = strat_Bob[ii++];
287 xTPLe(R, R, A24minus, A24plus, (int)m);
288 tree_index += m;
289 }
290 get_3_isog(R, A24minus, A24plus, coeff);
291
292 for (i = 0; i < npts; i++) {
293 eval_3_isog(pts[i], coeff);
294 }
295
296 fp2copy(&pts[npts-1]->X, &R->X);
297 fp2copy(&pts[npts-1]->Z, &R->Z);
298 tree_index = pts_index[npts-1];
299 npts -= 1;
300 }
301
302 get_3_isog(R, A24minus, A24plus, coeff);
303 fp2add(A24plus, A24minus, A);
304 fp2add(A, A, A);
305 fp2sub(A24plus, A24minus, A24plus);
306 j_inv(A, A24plus, jinv);
307 fp2_encode(jinv, SharedSecretB); /* Format shared secret */
308
309 return 0;
310 }
311