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