/src/libtorrent/src/ed25519/ge.cpp
Line | Count | Source |
1 | | // ignore warnings in this file |
2 | | #include "libtorrent/aux_/disable_warnings_push.hpp" |
3 | | |
4 | | #include "ge.h" |
5 | | #include "precomp_data.h" |
6 | | |
7 | | |
8 | | /* |
9 | | r = p + q |
10 | | */ |
11 | | |
12 | 0 | void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { |
13 | 0 | fe t0; |
14 | 0 | fe_add(r->X, p->Y, p->X); |
15 | 0 | fe_sub(r->Y, p->Y, p->X); |
16 | 0 | fe_mul(r->Z, r->X, q->YplusX); |
17 | 0 | fe_mul(r->Y, r->Y, q->YminusX); |
18 | 0 | fe_mul(r->T, q->T2d, p->T); |
19 | 0 | fe_mul(r->X, p->Z, q->Z); |
20 | 0 | fe_add(t0, r->X, r->X); |
21 | 0 | fe_sub(r->X, r->Z, r->Y); |
22 | 0 | fe_add(r->Y, r->Z, r->Y); |
23 | 0 | fe_add(r->Z, t0, r->T); |
24 | 0 | fe_sub(r->T, t0, r->T); |
25 | 0 | } |
26 | | |
27 | | |
28 | 0 | static void slide(signed char *r, const unsigned char *a) { |
29 | 0 | int i; |
30 | 0 | int b; |
31 | 0 | int k; |
32 | |
|
33 | 0 | for (i = 0; i < 256; ++i) { |
34 | 0 | r[i] = 1 & (a[i >> 3] >> (i & 7)); |
35 | 0 | } |
36 | |
|
37 | 0 | for (i = 0; i < 256; ++i) |
38 | 0 | if (r[i]) { |
39 | 0 | for (b = 1; b <= 6 && i + b < 256; ++b) { |
40 | 0 | if (r[i + b]) { |
41 | 0 | if (r[i] + (r[i + b] << b) <= 15) { |
42 | 0 | r[i] += r[i + b] << b; |
43 | 0 | r[i + b] = 0; |
44 | 0 | } else if (r[i] - (r[i + b] << b) >= -15) { |
45 | 0 | r[i] -= r[i + b] << b; |
46 | |
|
47 | 0 | for (k = i + b; k < 256; ++k) { |
48 | 0 | if (!r[k]) { |
49 | 0 | r[k] = 1; |
50 | 0 | break; |
51 | 0 | } |
52 | | |
53 | 0 | r[k] = 0; |
54 | 0 | } |
55 | 0 | } else { |
56 | 0 | break; |
57 | 0 | } |
58 | 0 | } |
59 | 0 | } |
60 | 0 | } |
61 | 0 | } |
62 | | |
63 | | /* |
64 | | r = a * A + b * B |
65 | | where a = a[0]+256*a[1]+...+256^31 a[31]. |
66 | | and b = b[0]+256*b[1]+...+256^31 b[31]. |
67 | | B is the Ed25519 base point (x,4/5) with x positive. |
68 | | */ |
69 | | |
70 | 0 | void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) { |
71 | 0 | signed char aslide[256]; |
72 | 0 | signed char bslide[256]; |
73 | 0 | ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ |
74 | 0 | ge_p1p1 t; |
75 | 0 | ge_p3 u; |
76 | 0 | ge_p3 A2; |
77 | 0 | int i; |
78 | 0 | slide(aslide, a); |
79 | 0 | slide(bslide, b); |
80 | 0 | ge_p3_to_cached(&Ai[0], A); |
81 | 0 | ge_p3_dbl(&t, A); |
82 | 0 | ge_p1p1_to_p3(&A2, &t); |
83 | 0 | ge_add(&t, &A2, &Ai[0]); |
84 | 0 | ge_p1p1_to_p3(&u, &t); |
85 | 0 | ge_p3_to_cached(&Ai[1], &u); |
86 | 0 | ge_add(&t, &A2, &Ai[1]); |
87 | 0 | ge_p1p1_to_p3(&u, &t); |
88 | 0 | ge_p3_to_cached(&Ai[2], &u); |
89 | 0 | ge_add(&t, &A2, &Ai[2]); |
90 | 0 | ge_p1p1_to_p3(&u, &t); |
91 | 0 | ge_p3_to_cached(&Ai[3], &u); |
92 | 0 | ge_add(&t, &A2, &Ai[3]); |
93 | 0 | ge_p1p1_to_p3(&u, &t); |
94 | 0 | ge_p3_to_cached(&Ai[4], &u); |
95 | 0 | ge_add(&t, &A2, &Ai[4]); |
96 | 0 | ge_p1p1_to_p3(&u, &t); |
97 | 0 | ge_p3_to_cached(&Ai[5], &u); |
98 | 0 | ge_add(&t, &A2, &Ai[5]); |
99 | 0 | ge_p1p1_to_p3(&u, &t); |
100 | 0 | ge_p3_to_cached(&Ai[6], &u); |
101 | 0 | ge_add(&t, &A2, &Ai[6]); |
102 | 0 | ge_p1p1_to_p3(&u, &t); |
103 | 0 | ge_p3_to_cached(&Ai[7], &u); |
104 | 0 | ge_p2_0(r); |
105 | |
|
106 | 0 | for (i = 255; i >= 0; --i) { |
107 | 0 | if (aslide[i] || bslide[i]) { |
108 | 0 | break; |
109 | 0 | } |
110 | 0 | } |
111 | |
|
112 | 0 | for (; i >= 0; --i) { |
113 | 0 | ge_p2_dbl(&t, r); |
114 | |
|
115 | 0 | if (aslide[i] > 0) { |
116 | 0 | ge_p1p1_to_p3(&u, &t); |
117 | 0 | ge_add(&t, &u, &Ai[aslide[i] / 2]); |
118 | 0 | } else if (aslide[i] < 0) { |
119 | 0 | ge_p1p1_to_p3(&u, &t); |
120 | 0 | ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]); |
121 | 0 | } |
122 | |
|
123 | 0 | if (bslide[i] > 0) { |
124 | 0 | ge_p1p1_to_p3(&u, &t); |
125 | 0 | ge_madd(&t, &u, &Bi[bslide[i] / 2]); |
126 | 0 | } else if (bslide[i] < 0) { |
127 | 0 | ge_p1p1_to_p3(&u, &t); |
128 | 0 | ge_msub(&t, &u, &Bi[(-bslide[i]) / 2]); |
129 | 0 | } |
130 | |
|
131 | 0 | ge_p1p1_to_p2(r, &t); |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | | |
136 | | static const fe d = { |
137 | | -10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116 |
138 | | }; |
139 | | |
140 | | static const fe sqrtm1 = { |
141 | | -32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482 |
142 | | }; |
143 | | |
144 | 0 | int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s) { |
145 | 0 | fe u; |
146 | 0 | fe v; |
147 | 0 | fe v3; |
148 | 0 | fe vxx; |
149 | 0 | fe check; |
150 | 0 | fe_frombytes(h->Y, s); |
151 | 0 | fe_1(h->Z); |
152 | 0 | fe_sq(u, h->Y); |
153 | 0 | fe_mul(v, u, d); |
154 | 0 | fe_sub(u, u, h->Z); /* u = y^2-1 */ |
155 | 0 | fe_add(v, v, h->Z); /* v = dy^2+1 */ |
156 | 0 | fe_sq(v3, v); |
157 | 0 | fe_mul(v3, v3, v); /* v3 = v^3 */ |
158 | 0 | fe_sq(h->X, v3); |
159 | 0 | fe_mul(h->X, h->X, v); |
160 | 0 | fe_mul(h->X, h->X, u); /* x = uv^7 */ |
161 | 0 | fe_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */ |
162 | 0 | fe_mul(h->X, h->X, v3); |
163 | 0 | fe_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */ |
164 | 0 | fe_sq(vxx, h->X); |
165 | 0 | fe_mul(vxx, vxx, v); |
166 | 0 | fe_sub(check, vxx, u); /* vx^2-u */ |
167 | |
|
168 | 0 | if (fe_isnonzero(check)) { |
169 | 0 | fe_add(check, vxx, u); /* vx^2+u */ |
170 | |
|
171 | 0 | if (fe_isnonzero(check)) { |
172 | 0 | return -1; |
173 | 0 | } |
174 | | |
175 | 0 | fe_mul(h->X, h->X, sqrtm1); |
176 | 0 | } |
177 | | |
178 | 0 | if (fe_isnegative(h->X) == (s[31] >> 7)) { |
179 | 0 | fe_neg(h->X, h->X); |
180 | 0 | } |
181 | |
|
182 | 0 | fe_mul(h->T, h->X, h->Y); |
183 | 0 | return 0; |
184 | 0 | } |
185 | | |
186 | | |
187 | | /* |
188 | | r = p + q |
189 | | */ |
190 | | |
191 | 0 | void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) { |
192 | 0 | fe t0; |
193 | 0 | fe_add(r->X, p->Y, p->X); |
194 | 0 | fe_sub(r->Y, p->Y, p->X); |
195 | 0 | fe_mul(r->Z, r->X, q->yplusx); |
196 | 0 | fe_mul(r->Y, r->Y, q->yminusx); |
197 | 0 | fe_mul(r->T, q->xy2d, p->T); |
198 | 0 | fe_add(t0, p->Z, p->Z); |
199 | 0 | fe_sub(r->X, r->Z, r->Y); |
200 | 0 | fe_add(r->Y, r->Z, r->Y); |
201 | 0 | fe_add(r->Z, t0, r->T); |
202 | 0 | fe_sub(r->T, t0, r->T); |
203 | 0 | } |
204 | | |
205 | | |
206 | | /* |
207 | | r = p - q |
208 | | */ |
209 | | |
210 | 0 | void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) { |
211 | 0 | fe t0; |
212 | |
|
213 | 0 | fe_add(r->X, p->Y, p->X); |
214 | 0 | fe_sub(r->Y, p->Y, p->X); |
215 | 0 | fe_mul(r->Z, r->X, q->yminusx); |
216 | 0 | fe_mul(r->Y, r->Y, q->yplusx); |
217 | 0 | fe_mul(r->T, q->xy2d, p->T); |
218 | 0 | fe_add(t0, p->Z, p->Z); |
219 | 0 | fe_sub(r->X, r->Z, r->Y); |
220 | 0 | fe_add(r->Y, r->Z, r->Y); |
221 | 0 | fe_sub(r->Z, t0, r->T); |
222 | 0 | fe_add(r->T, t0, r->T); |
223 | 0 | } |
224 | | |
225 | | |
226 | | /* |
227 | | r = p |
228 | | */ |
229 | | |
230 | 0 | void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) { |
231 | 0 | fe_mul(r->X, p->X, p->T); |
232 | 0 | fe_mul(r->Y, p->Y, p->Z); |
233 | 0 | fe_mul(r->Z, p->Z, p->T); |
234 | 0 | } |
235 | | |
236 | | |
237 | | |
238 | | /* |
239 | | r = p |
240 | | */ |
241 | | |
242 | 0 | void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) { |
243 | 0 | fe_mul(r->X, p->X, p->T); |
244 | 0 | fe_mul(r->Y, p->Y, p->Z); |
245 | 0 | fe_mul(r->Z, p->Z, p->T); |
246 | 0 | fe_mul(r->T, p->X, p->Y); |
247 | 0 | } |
248 | | |
249 | | |
250 | 0 | void ge_p2_0(ge_p2 *h) { |
251 | 0 | fe_0(h->X); |
252 | 0 | fe_1(h->Y); |
253 | 0 | fe_1(h->Z); |
254 | 0 | } |
255 | | |
256 | | |
257 | | |
258 | | /* |
259 | | r = 2 * p |
260 | | */ |
261 | | |
262 | 0 | void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) { |
263 | 0 | fe t0; |
264 | |
|
265 | 0 | fe_sq(r->X, p->X); |
266 | 0 | fe_sq(r->Z, p->Y); |
267 | 0 | fe_sq2(r->T, p->Z); |
268 | 0 | fe_add(r->Y, p->X, p->Y); |
269 | 0 | fe_sq(t0, r->Y); |
270 | 0 | fe_add(r->Y, r->Z, r->X); |
271 | 0 | fe_sub(r->Z, r->Z, r->X); |
272 | 0 | fe_sub(r->X, t0, r->Y); |
273 | 0 | fe_sub(r->T, r->T, r->Z); |
274 | 0 | } |
275 | | |
276 | | |
277 | 0 | void ge_p3_0(ge_p3 *h) { |
278 | 0 | fe_0(h->X); |
279 | 0 | fe_1(h->Y); |
280 | 0 | fe_1(h->Z); |
281 | 0 | fe_0(h->T); |
282 | 0 | } |
283 | | |
284 | | |
285 | | /* |
286 | | r = 2 * p |
287 | | */ |
288 | | |
289 | 0 | void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) { |
290 | 0 | ge_p2 q; |
291 | 0 | ge_p3_to_p2(&q, p); |
292 | 0 | ge_p2_dbl(r, &q); |
293 | 0 | } |
294 | | |
295 | | |
296 | | |
297 | | /* |
298 | | r = p |
299 | | */ |
300 | | |
301 | | static const fe d2 = { |
302 | | -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199 |
303 | | }; |
304 | | |
305 | 0 | void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) { |
306 | 0 | fe_add(r->YplusX, p->Y, p->X); |
307 | 0 | fe_sub(r->YminusX, p->Y, p->X); |
308 | 0 | fe_copy(r->Z, p->Z); |
309 | 0 | fe_mul(r->T2d, p->T, d2); |
310 | 0 | } |
311 | | |
312 | | |
313 | | /* |
314 | | r = p |
315 | | */ |
316 | | |
317 | 0 | void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) { |
318 | 0 | fe_copy(r->X, p->X); |
319 | 0 | fe_copy(r->Y, p->Y); |
320 | 0 | fe_copy(r->Z, p->Z); |
321 | 0 | } |
322 | | |
323 | | |
324 | 0 | void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) { |
325 | 0 | fe recip; |
326 | 0 | fe x; |
327 | 0 | fe y; |
328 | 0 | fe_invert(recip, h->Z); |
329 | 0 | fe_mul(x, h->X, recip); |
330 | 0 | fe_mul(y, h->Y, recip); |
331 | 0 | fe_tobytes(s, y); |
332 | 0 | s[31] ^= fe_isnegative(x) << 7; |
333 | 0 | } |
334 | | |
335 | | |
336 | 0 | static unsigned char equal(signed char b, signed char c) { |
337 | 0 | unsigned char ub = b; |
338 | 0 | unsigned char uc = c; |
339 | 0 | unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ |
340 | 0 | u64 y = x; /* 0: yes; 1..255: no */ |
341 | 0 | y -= 1; /* large: yes; 0..254: no */ |
342 | 0 | y >>= 63; /* 1: yes; 0: no */ |
343 | 0 | return (unsigned char) y; |
344 | 0 | } |
345 | | |
346 | 0 | static unsigned char negative(signed char b) { |
347 | 0 | u64 x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ |
348 | 0 | x >>= 63; /* 1: yes; 0: no */ |
349 | 0 | return (unsigned char) x; |
350 | 0 | } |
351 | | |
352 | 0 | static void cmov(ge_precomp *t, const ge_precomp *u, unsigned char b) { |
353 | 0 | fe_cmov(t->yplusx, u->yplusx, b); |
354 | 0 | fe_cmov(t->yminusx, u->yminusx, b); |
355 | 0 | fe_cmov(t->xy2d, u->xy2d, b); |
356 | 0 | } |
357 | | |
358 | | |
359 | 0 | static void select(ge_precomp *t, int pos, signed char b) { |
360 | 0 | typedef signed char schar; |
361 | 0 | typedef unsigned char uchar; |
362 | 0 | ge_precomp minust; |
363 | 0 | unsigned char const bnegative = negative(b); |
364 | 0 | unsigned char const babs = b - schar(uchar((-bnegative) & b) << 1); |
365 | 0 | fe_1(t->yplusx); |
366 | 0 | fe_1(t->yminusx); |
367 | 0 | fe_0(t->xy2d); |
368 | 0 | cmov(t, &base[pos][0], equal(babs, 1)); |
369 | 0 | cmov(t, &base[pos][1], equal(babs, 2)); |
370 | 0 | cmov(t, &base[pos][2], equal(babs, 3)); |
371 | 0 | cmov(t, &base[pos][3], equal(babs, 4)); |
372 | 0 | cmov(t, &base[pos][4], equal(babs, 5)); |
373 | 0 | cmov(t, &base[pos][5], equal(babs, 6)); |
374 | 0 | cmov(t, &base[pos][6], equal(babs, 7)); |
375 | 0 | cmov(t, &base[pos][7], equal(babs, 8)); |
376 | 0 | fe_copy(minust.yplusx, t->yminusx); |
377 | 0 | fe_copy(minust.yminusx, t->yplusx); |
378 | 0 | fe_neg(minust.xy2d, t->xy2d); |
379 | 0 | cmov(t, &minust, bnegative); |
380 | 0 | } |
381 | | |
382 | | /* |
383 | | h = a * B |
384 | | where a = a[0]+256*a[1]+...+256^31 a[31] |
385 | | B is the Ed25519 base point (x,4/5) with x positive. |
386 | | |
387 | | Preconditions: |
388 | | a[31] <= 127 |
389 | | */ |
390 | | |
391 | 0 | void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) { |
392 | 0 | signed char e[64]; |
393 | 0 | signed char carry; |
394 | 0 | ge_p1p1 r; |
395 | 0 | ge_p2 s; |
396 | 0 | ge_precomp t; |
397 | 0 | int i; |
398 | |
|
399 | 0 | for (i = 0; i < 32; ++i) { |
400 | 0 | e[2 * i + 0] = (a[i] >> 0) & 15; |
401 | 0 | e[2 * i + 1] = (a[i] >> 4) & 15; |
402 | 0 | } |
403 | | |
404 | | /* each e[i] is between 0 and 15 */ |
405 | | /* e[63] is between 0 and 7 */ |
406 | 0 | carry = 0; |
407 | |
|
408 | 0 | for (i = 0; i < 63; ++i) { |
409 | 0 | e[i] += carry; |
410 | 0 | carry = e[i] + 8; |
411 | 0 | carry >>= 4; |
412 | 0 | e[i] -= carry << 4; |
413 | 0 | } |
414 | |
|
415 | 0 | e[63] += carry; |
416 | | /* each e[i] is between -8 and 8 */ |
417 | 0 | ge_p3_0(h); |
418 | |
|
419 | 0 | for (i = 1; i < 64; i += 2) { |
420 | 0 | select(&t, i / 2, e[i]); |
421 | 0 | ge_madd(&r, h, &t); |
422 | 0 | ge_p1p1_to_p3(h, &r); |
423 | 0 | } |
424 | |
|
425 | 0 | ge_p3_dbl(&r, h); |
426 | 0 | ge_p1p1_to_p2(&s, &r); |
427 | 0 | ge_p2_dbl(&r, &s); |
428 | 0 | ge_p1p1_to_p2(&s, &r); |
429 | 0 | ge_p2_dbl(&r, &s); |
430 | 0 | ge_p1p1_to_p2(&s, &r); |
431 | 0 | ge_p2_dbl(&r, &s); |
432 | 0 | ge_p1p1_to_p3(h, &r); |
433 | |
|
434 | 0 | for (i = 0; i < 64; i += 2) { |
435 | 0 | select(&t, i / 2, e[i]); |
436 | 0 | ge_madd(&r, h, &t); |
437 | 0 | ge_p1p1_to_p3(h, &r); |
438 | 0 | } |
439 | 0 | } |
440 | | |
441 | | |
442 | | /* |
443 | | r = p - q |
444 | | */ |
445 | | |
446 | 0 | void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { |
447 | 0 | fe t0; |
448 | | |
449 | 0 | fe_add(r->X, p->Y, p->X); |
450 | 0 | fe_sub(r->Y, p->Y, p->X); |
451 | 0 | fe_mul(r->Z, r->X, q->YminusX); |
452 | 0 | fe_mul(r->Y, r->Y, q->YplusX); |
453 | 0 | fe_mul(r->T, q->T2d, p->T); |
454 | 0 | fe_mul(r->X, p->Z, q->Z); |
455 | 0 | fe_add(t0, r->X, r->X); |
456 | 0 | fe_sub(r->X, r->Z, r->Y); |
457 | 0 | fe_add(r->Y, r->Z, r->Y); |
458 | 0 | fe_sub(r->Z, t0, r->T); |
459 | 0 | fe_add(r->T, t0, r->T); |
460 | 0 | } |
461 | | |
462 | | |
463 | 0 | void ge_tobytes(unsigned char *s, const ge_p2 *h) { |
464 | 0 | fe recip; |
465 | 0 | fe x; |
466 | 0 | fe y; |
467 | 0 | fe_invert(recip, h->Z); |
468 | 0 | fe_mul(x, h->X, recip); |
469 | 0 | fe_mul(y, h->Y, recip); |
470 | 0 | fe_tobytes(s, y); |
471 | 0 | s[31] ^= fe_isnegative(x) << 7; |
472 | 0 | } |