diff options
author | Florian Dold <florian.dold@gmail.com> | 2019-11-26 18:26:54 +0100 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2019-11-26 18:29:56 +0100 |
commit | bc340979c19807c76baedc7da98778178b9bcc4a (patch) | |
tree | c7e0e017a441ea5bc13d9e165417c5156e390c9b /src/util/tweetnacl-gnunet.c | |
parent | c36c37830eb909fe73357383136cf8b2405d9633 (diff) | |
download | gnunet-bc340979c19807c76baedc7da98778178b9bcc4a.tar.gz gnunet-bc340979c19807c76baedc7da98778178b9bcc4a.zip |
use Curve25519 for ECDH and tweetnacl where we can
This leads to some performance improvements and makes it easier to write
software that interoperates with GNUnet / GNU Taler. It also avoids
using the rather inconvenient libgcrypt APIs. We still need to keep
libgcrypt though, as we need it for RSA, ECDSA and some other
primitives.
This change is still behind a #define NEW_CRYPTO, as it is a breaking
change for both EdDSA (removing the superfluous additional hash) and for
ECDHE (using Curve25519 instead of Ed25519).
Diffstat (limited to 'src/util/tweetnacl-gnunet.c')
-rw-r--r-- | src/util/tweetnacl-gnunet.c | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/src/util/tweetnacl-gnunet.c b/src/util/tweetnacl-gnunet.c new file mode 100644 index 000000000..b0d87c2fe --- /dev/null +++ b/src/util/tweetnacl-gnunet.c | |||
@@ -0,0 +1,530 @@ | |||
1 | /* | ||
2 | This file has been placed in the public domain. | ||
3 | |||
4 | Based on TweetNaCl version 20140427 | ||
5 | |||
6 | Originally obtained from: | ||
7 | https://tweetnacl.cr.yp.to/20140427/tweetnacl.h | ||
8 | */ | ||
9 | |||
10 | #include "platform.h" | ||
11 | #include "gnunet_crypto_lib.h" | ||
12 | #include "tweetnacl-gnunet.h" | ||
13 | #define FOR(i,n) for (i = 0; i < n; ++i) | ||
14 | #define sv static void | ||
15 | |||
16 | typedef uint8_t u8; | ||
17 | typedef uint32_t u32; | ||
18 | typedef uint64_t u64; | ||
19 | typedef int64_t i64; | ||
20 | typedef i64 gf[16]; | ||
21 | |||
22 | static void randombytes (u8 *data,u64 len) | ||
23 | { | ||
24 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, data, len); | ||
25 | } | ||
26 | |||
27 | static const u8 _9[32] = {9}; | ||
28 | static const gf | ||
29 | gf0, | ||
30 | gf1 = {1}, | ||
31 | _121665 = {0xDB41,1}, | ||
32 | D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, | ||
33 | 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203}, | ||
34 | D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, | ||
35 | 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406}, | ||
36 | X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, | ||
37 | 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169}, | ||
38 | Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, | ||
39 | 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666}, | ||
40 | I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, | ||
41 | 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83}; | ||
42 | |||
43 | static int vn (const u8 *x,const u8 *y,int n) | ||
44 | { | ||
45 | u32 i,d = 0; | ||
46 | FOR (i,n) d |= x[i] ^ y[i]; | ||
47 | return (1 & ((d - 1) >> 8)) - 1; | ||
48 | } | ||
49 | |||
50 | int crypto_verify_16 (const u8 *x,const u8 *y) | ||
51 | { | ||
52 | return vn (x,y,16); | ||
53 | } | ||
54 | |||
55 | int crypto_verify_32 (const u8 *x,const u8 *y) | ||
56 | { | ||
57 | return vn (x,y,32); | ||
58 | } | ||
59 | |||
60 | sv set25519 (gf r, const gf a) | ||
61 | { | ||
62 | int i; | ||
63 | FOR (i,16) r[i] = a[i]; | ||
64 | } | ||
65 | |||
66 | sv car25519 (gf o) | ||
67 | { | ||
68 | int i; | ||
69 | i64 c; | ||
70 | FOR (i,16) { | ||
71 | o[i] += (1LL << 16); | ||
72 | c = o[i] >> 16; | ||
73 | o[(i + 1) * (i<15)] += c - 1 + 37 * (c - 1) * (i==15); | ||
74 | o[i] -= c << 16; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | sv sel25519 (gf p,gf q,int b) | ||
79 | { | ||
80 | i64 t,i,c = ~(b - 1); | ||
81 | FOR (i,16) { | ||
82 | t = c & (p[i] ^ q[i]); | ||
83 | p[i] ^= t; | ||
84 | q[i] ^= t; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | sv pack25519 (u8 *o,const gf n) | ||
89 | { | ||
90 | int i,j,b; | ||
91 | gf m,t; | ||
92 | FOR (i,16) t[i] = n[i]; | ||
93 | car25519 (t); | ||
94 | car25519 (t); | ||
95 | car25519 (t); | ||
96 | FOR (j,2) { | ||
97 | m[0] = t[0] - 0xffed; | ||
98 | for (i = 1; i<15; i++) { | ||
99 | m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1); | ||
100 | m[i - 1] &= 0xffff; | ||
101 | } | ||
102 | m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1); | ||
103 | b = (m[15] >> 16) & 1; | ||
104 | m[14] &= 0xffff; | ||
105 | sel25519 (t,m,1 - b); | ||
106 | } | ||
107 | FOR (i,16) { | ||
108 | o[2 * i] = t[i] & 0xff; | ||
109 | o[2 * i + 1] = t[i] >> 8; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | static int neq25519 (const gf a, const gf b) | ||
114 | { | ||
115 | u8 c[32],d[32]; | ||
116 | pack25519 (c,a); | ||
117 | pack25519 (d,b); | ||
118 | return crypto_verify_32 (c,d); | ||
119 | } | ||
120 | |||
121 | static u8 par25519 (const gf a) | ||
122 | { | ||
123 | u8 d[32]; | ||
124 | pack25519 (d,a); | ||
125 | return d[0] & 1; | ||
126 | } | ||
127 | |||
128 | sv unpack25519 (gf o, const u8 *n) | ||
129 | { | ||
130 | int i; | ||
131 | FOR (i,16) o[i] = n[2 * i] + ((i64) n[2 * i + 1] << 8); | ||
132 | o[15] &= 0x7fff; | ||
133 | } | ||
134 | |||
135 | sv A (gf o,const gf a,const gf b) | ||
136 | { | ||
137 | int i; | ||
138 | FOR (i,16) o[i] = a[i] + b[i]; | ||
139 | } | ||
140 | |||
141 | sv Z (gf o,const gf a,const gf b) | ||
142 | { | ||
143 | int i; | ||
144 | FOR (i,16) o[i] = a[i] - b[i]; | ||
145 | } | ||
146 | |||
147 | sv M (gf o,const gf a,const gf b) | ||
148 | { | ||
149 | i64 i,j,t[31]; | ||
150 | FOR (i,31) t[i] = 0; | ||
151 | FOR (i,16) FOR (j,16) t[i + j] += a[i] * b[j]; | ||
152 | FOR (i,15) t[i] += 38 * t[i + 16]; | ||
153 | FOR (i,16) o[i] = t[i]; | ||
154 | car25519 (o); | ||
155 | car25519 (o); | ||
156 | } | ||
157 | |||
158 | sv S (gf o,const gf a) | ||
159 | { | ||
160 | M (o,a,a); | ||
161 | } | ||
162 | |||
163 | sv inv25519 (gf o,const gf i) | ||
164 | { | ||
165 | gf c; | ||
166 | int a; | ||
167 | FOR (a,16) c[a] = i[a]; | ||
168 | for (a = 253; a>=0; a--) { | ||
169 | S (c,c); | ||
170 | if ((a!=2)&&(a!=4)) | ||
171 | M (c,c,i); | ||
172 | } | ||
173 | FOR (a,16) o[a] = c[a]; | ||
174 | } | ||
175 | |||
176 | sv pow2523 (gf o,const gf i) | ||
177 | { | ||
178 | gf c; | ||
179 | int a; | ||
180 | FOR (a,16) c[a] = i[a]; | ||
181 | for (a = 250; a>=0; a--) { | ||
182 | S (c,c); | ||
183 | if (a!=1) | ||
184 | M (c,c,i); | ||
185 | } | ||
186 | FOR (a,16) o[a] = c[a]; | ||
187 | } | ||
188 | |||
189 | int crypto_scalarmult (u8 *q,const u8 *n,const u8 *p) | ||
190 | { | ||
191 | u8 z[32]; | ||
192 | i64 x[80],r,i; | ||
193 | gf a,b,c,d,e,f; | ||
194 | FOR (i,31) z[i] = n[i]; | ||
195 | z[31] = (n[31] & 127) | 64; | ||
196 | z[0] &= 248; | ||
197 | unpack25519 (x,p); | ||
198 | FOR (i,16) { | ||
199 | b[i] = x[i]; | ||
200 | d[i] = a[i] = c[i] = 0; | ||
201 | } | ||
202 | a[0] = d[0] = 1; | ||
203 | for (i = 254; i>=0; --i) { | ||
204 | r = (z[i >> 3] >> (i & 7)) & 1; | ||
205 | sel25519 (a,b,r); | ||
206 | sel25519 (c,d,r); | ||
207 | A (e,a,c); | ||
208 | Z (a,a,c); | ||
209 | A (c,b,d); | ||
210 | Z (b,b,d); | ||
211 | S (d,e); | ||
212 | S (f,a); | ||
213 | M (a,c,a); | ||
214 | M (c,b,e); | ||
215 | A (e,a,c); | ||
216 | Z (a,a,c); | ||
217 | S (b,a); | ||
218 | Z (c,d,f); | ||
219 | M (a,c,_121665); | ||
220 | A (a,a,d); | ||
221 | M (c,c,a); | ||
222 | M (a,d,f); | ||
223 | M (d,b,x); | ||
224 | S (b,e); | ||
225 | sel25519 (a,b,r); | ||
226 | sel25519 (c,d,r); | ||
227 | } | ||
228 | FOR (i,16) { | ||
229 | x[i + 16] = a[i]; | ||
230 | x[i + 32] = c[i]; | ||
231 | x[i + 48] = b[i]; | ||
232 | x[i + 64] = d[i]; | ||
233 | } | ||
234 | inv25519 (x + 32,x + 32); | ||
235 | M (x + 16,x + 16,x + 32); | ||
236 | pack25519 (q,x + 16); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | int crypto_scalarmult_base (u8 *q,const u8 *n) | ||
241 | { | ||
242 | return crypto_scalarmult (q,n,_9); | ||
243 | } | ||
244 | |||
245 | int crypto_box_keypair (u8 *y,u8 *x) | ||
246 | { | ||
247 | randombytes (x,32); | ||
248 | return crypto_scalarmult_base (y,x); | ||
249 | } | ||
250 | |||
251 | int crypto_hash (u8 *out,const u8 *m,u64 n) | ||
252 | { | ||
253 | struct GNUNET_HashCode *hc = (void *) out; | ||
254 | GNUNET_CRYPTO_hash (m, n, hc); | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | sv add (gf p[4],gf q[4]) | ||
259 | { | ||
260 | gf a,b,c,d,t,e,f,g,h; | ||
261 | |||
262 | Z (a, p[1], p[0]); | ||
263 | Z (t, q[1], q[0]); | ||
264 | M (a, a, t); | ||
265 | A (b, p[0], p[1]); | ||
266 | A (t, q[0], q[1]); | ||
267 | M (b, b, t); | ||
268 | M (c, p[3], q[3]); | ||
269 | M (c, c, D2); | ||
270 | M (d, p[2], q[2]); | ||
271 | A (d, d, d); | ||
272 | Z (e, b, a); | ||
273 | Z (f, d, c); | ||
274 | A (g, d, c); | ||
275 | A (h, b, a); | ||
276 | |||
277 | M (p[0], e, f); | ||
278 | M (p[1], h, g); | ||
279 | M (p[2], g, f); | ||
280 | M (p[3], e, h); | ||
281 | } | ||
282 | |||
283 | sv cswap (gf p[4],gf q[4],u8 b) | ||
284 | { | ||
285 | int i; | ||
286 | FOR (i,4) | ||
287 | sel25519 (p[i],q[i],b); | ||
288 | } | ||
289 | |||
290 | sv pack (u8 *r,gf p[4]) | ||
291 | { | ||
292 | gf tx, ty, zi; | ||
293 | inv25519 (zi, p[2]); | ||
294 | M (tx, p[0], zi); | ||
295 | M (ty, p[1], zi); | ||
296 | pack25519 (r, ty); | ||
297 | r[31] ^= par25519 (tx) << 7; | ||
298 | } | ||
299 | |||
300 | sv scalarmult (gf p[4],gf q[4],const u8 *s) | ||
301 | { | ||
302 | int i; | ||
303 | set25519 (p[0],gf0); | ||
304 | set25519 (p[1],gf1); | ||
305 | set25519 (p[2],gf1); | ||
306 | set25519 (p[3],gf0); | ||
307 | for (i = 255; i >= 0; --i) { | ||
308 | u8 b = (s[i / 8] >> (i & 7)) & 1; | ||
309 | cswap (p,q,b); | ||
310 | add (q,p); | ||
311 | add (p,p); | ||
312 | cswap (p,q,b); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | sv scalarbase (gf p[4],const u8 *s) | ||
317 | { | ||
318 | gf q[4]; | ||
319 | set25519 (q[0],X); | ||
320 | set25519 (q[1],Y); | ||
321 | set25519 (q[2],gf1); | ||
322 | M (q[3],X,Y); | ||
323 | scalarmult (p,q,s); | ||
324 | } | ||
325 | |||
326 | static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, | ||
327 | 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, | ||
328 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
329 | 0, 0, 0, 0x10}; | ||
330 | |||
331 | sv modL (u8 *r,i64 x[64]) | ||
332 | { | ||
333 | i64 carry,i,j; | ||
334 | for (i = 63; i >= 32; --i) { | ||
335 | carry = 0; | ||
336 | for (j = i - 32; j < i - 12; ++j) { | ||
337 | x[j] += carry - 16 * x[i] * L[j - (i - 32)]; | ||
338 | carry = (x[j] + 128) >> 8; | ||
339 | x[j] -= carry << 8; | ||
340 | } | ||
341 | x[j] += carry; | ||
342 | x[i] = 0; | ||
343 | } | ||
344 | carry = 0; | ||
345 | FOR (j,32) { | ||
346 | x[j] += carry - (x[31] >> 4) * L[j]; | ||
347 | carry = x[j] >> 8; | ||
348 | x[j] &= 255; | ||
349 | } | ||
350 | FOR (j,32) x[j] -= carry * L[j]; | ||
351 | FOR (i,32) { | ||
352 | x[i + 1] += x[i] >> 8; | ||
353 | r[i] = x[i] & 255; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | sv reduce (u8 *r) | ||
358 | { | ||
359 | i64 x[64],i; | ||
360 | FOR (i,64) x[i] = (u64) r[i]; | ||
361 | FOR (i,64) r[i] = 0; | ||
362 | modL (r,x); | ||
363 | } | ||
364 | |||
365 | static int unpackneg (gf r[4],const u8 p[32]) | ||
366 | { | ||
367 | gf t, chk, num, den, den2, den4, den6; | ||
368 | set25519 (r[2],gf1); | ||
369 | unpack25519 (r[1],p); | ||
370 | S (num,r[1]); | ||
371 | M (den,num,D); | ||
372 | Z (num,num,r[2]); | ||
373 | A (den,r[2],den); | ||
374 | |||
375 | S (den2,den); | ||
376 | S (den4,den2); | ||
377 | M (den6,den4,den2); | ||
378 | M (t,den6,num); | ||
379 | M (t,t,den); | ||
380 | |||
381 | pow2523 (t,t); | ||
382 | M (t,t,num); | ||
383 | M (t,t,den); | ||
384 | M (t,t,den); | ||
385 | M (r[0],t,den); | ||
386 | |||
387 | S (chk,r[0]); | ||
388 | M (chk,chk,den); | ||
389 | if (neq25519 (chk, num)) | ||
390 | M (r[0],r[0],I); | ||
391 | |||
392 | S (chk,r[0]); | ||
393 | M (chk,chk,den); | ||
394 | if (neq25519 (chk, num)) | ||
395 | return -1; | ||
396 | |||
397 | if (par25519 (r[0]) == (p[31] >> 7)) | ||
398 | Z (r[0],gf0,r[0]); | ||
399 | |||
400 | M (r[3],r[0],r[1]); | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | /* The following functions have been added for GNUnet */ | ||
405 | |||
406 | void | ||
407 | crypto_sign_pk_from_seed (u8 *pk, const u8 *seed) | ||
408 | { | ||
409 | u8 d[64]; | ||
410 | gf p[4]; | ||
411 | |||
412 | crypto_hash (d, seed, 32); | ||
413 | d[0] &= 248; | ||
414 | d[31] &= 127; | ||
415 | d[31] |= 64; | ||
416 | |||
417 | scalarbase (p,d); | ||
418 | pack (pk,p); | ||
419 | } | ||
420 | |||
421 | void | ||
422 | crypto_sign_sk_from_seed (u8 *sk, const u8 *seed) | ||
423 | { | ||
424 | u8 d[64]; | ||
425 | gf p[4]; | ||
426 | u8 pk[32]; | ||
427 | int i; | ||
428 | |||
429 | crypto_hash (d, seed, 32); | ||
430 | d[0] &= 248; | ||
431 | d[31] &= 127; | ||
432 | d[31] |= 64; | ||
433 | |||
434 | scalarbase (p,d); | ||
435 | pack (pk,p); | ||
436 | |||
437 | FOR (i,32) sk[i] = seed[i]; | ||
438 | FOR (i,32) sk[32 + i] = pk[i]; | ||
439 | } | ||
440 | |||
441 | |||
442 | int | ||
443 | crypto_sign_ed25519_pk_to_curve25519 (u8 *x25519_pk, const u8 *ed25519_pk) | ||
444 | { | ||
445 | gf ge_a[4]; | ||
446 | gf x; | ||
447 | gf one_minus_y; | ||
448 | |||
449 | if (0 != unpackneg (ge_a, ed25519_pk)) | ||
450 | return -1; | ||
451 | |||
452 | set25519 (one_minus_y, gf1); | ||
453 | Z (one_minus_y, one_minus_y, ge_a[1]); | ||
454 | |||
455 | set25519 (x, gf1); | ||
456 | A (x, x, ge_a[1]); | ||
457 | |||
458 | inv25519 (one_minus_y, one_minus_y); | ||
459 | M (x, x, one_minus_y); | ||
460 | pack25519 (x25519_pk, x); | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | |||
466 | int crypto_sign_detached_verify (const u8 *sig,const u8 *m,u64 n,const u8 *pk) | ||
467 | { | ||
468 | struct GNUNET_HashContext *hc; | ||
469 | u8 t[32],h[64]; | ||
470 | gf p[4],q[4]; | ||
471 | |||
472 | if (unpackneg (q,pk)) | ||
473 | return -1; | ||
474 | |||
475 | hc = GNUNET_CRYPTO_hash_context_start (); | ||
476 | GNUNET_CRYPTO_hash_context_read (hc, sig, 32); | ||
477 | GNUNET_CRYPTO_hash_context_read (hc, pk, 32); | ||
478 | GNUNET_CRYPTO_hash_context_read (hc, m, n); | ||
479 | GNUNET_CRYPTO_hash_context_finish (hc, (void *) h); | ||
480 | |||
481 | reduce (h); | ||
482 | scalarmult (p,q,h); | ||
483 | |||
484 | scalarbase (q,sig+32); | ||
485 | add (p,q); | ||
486 | pack (t,p); | ||
487 | |||
488 | if (crypto_verify_32 (sig, t)) | ||
489 | return -1; | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | |||
494 | int | ||
495 | crypto_sign_detached (u8 *sig,const u8 *m,u64 n,const u8 *sk) | ||
496 | { | ||
497 | struct GNUNET_HashContext *hc; | ||
498 | u8 d[64],h[64],r[64]; | ||
499 | i64 i,j,x[64]; | ||
500 | gf p[4]; | ||
501 | |||
502 | crypto_hash (d, sk, 32); | ||
503 | d[0] &= 248; | ||
504 | d[31] &= 127; | ||
505 | d[31] |= 64; | ||
506 | |||
507 | hc = GNUNET_CRYPTO_hash_context_start (); | ||
508 | GNUNET_CRYPTO_hash_context_read (hc, d + 32, 32); | ||
509 | GNUNET_CRYPTO_hash_context_read (hc, m, n); | ||
510 | GNUNET_CRYPTO_hash_context_finish (hc, (void *) r); | ||
511 | |||
512 | reduce (r); | ||
513 | scalarbase (p,r); | ||
514 | pack (sig,p); | ||
515 | |||
516 | hc = GNUNET_CRYPTO_hash_context_start (); | ||
517 | GNUNET_CRYPTO_hash_context_read (hc, sig, 32); | ||
518 | GNUNET_CRYPTO_hash_context_read (hc, sk + 32, 32); | ||
519 | GNUNET_CRYPTO_hash_context_read (hc, m, n); | ||
520 | GNUNET_CRYPTO_hash_context_finish (hc, (void *) h); | ||
521 | |||
522 | reduce (h); | ||
523 | |||
524 | FOR (i,64) x[i] = 0; | ||
525 | FOR (i,32) x[i] = (u64) r[i]; | ||
526 | FOR (i,32) FOR (j,32) x[i + j] += h[i] * (u64) d[j]; | ||
527 | modL (sig + 32,x); | ||
528 | |||
529 | return 0; | ||
530 | } | ||