cosmetix
[tweetnacl.d.git] / tweetNaCl.d
blob0b0aad147fb8351cd250b670d2a237c52e0c3c88
1 /*
2 * Contributors (alphabetical order)
3 * Daniel J. Bernstein, University of Illinois at Chicago and Technische Universiteit Eindhoven
4 * Wesley Janssen, Radboud Universiteit Nijmegen
5 * Tanja Lange, Technische Universiteit Eindhoven
6 * Peter Schwabe, Radboud Universiteit Nijmegen
8 * Ported by Ketmar // Invisible Vector ( ketmar@ketmar.no-ip.org )
10 * Public Domain (or WTFPL).
12 module tweetNaCl;
14 // define tweetnacl_enable_inlining to speed up tweetNaCl on GDC
15 version(GNU) {
16 version(tweetnacl_enable_inlining) version=tweetnacl_enable_inlining_on_;
17 else version=tweetnacl_enable_inlining_off_;
18 } else {
19 version=tweetnacl_enable_inlining_off_;
22 version(tweetnacl_enable_inlining_off_) {
23 private struct tweetNaCl_gdc_Attribute(A...) {
24 A args;
26 auto tweetNaCl_gdc_attribute(A...)(A args) if(A.length > 0 && is(A[0] == string)) {
27 return tweetNaCl_gdc_Attribute!A(args);
29 } else {
30 import gcc.attribute;
31 alias tweetNaCl_gdc_attribute = attribute;
35 enum {
36 crypto_auth_BYTES = 32,
37 crypto_auth_KEYBYTES = 32,
39 crypto_box_PUBLICKEYBYTES = 32,
40 crypto_box_SECRETKEYBYTES = 32,
41 crypto_box_BEFORENMBYTES = 32,
42 crypto_box_NONCEBYTES = 24,
43 crypto_box_ZEROBYTES = 32,
44 crypto_box_BOXZEROBYTES = 16,
46 crypto_core_salsa20_OUTPUTBYTES = 64,
47 crypto_core_salsa20_INPUTBYTES = 16,
48 crypto_core_salsa20_KEYBYTES = 32,
49 crypto_core_salsa20_CONSTBYTES = 16,
51 crypto_core_hsalsa20_OUTPUTBYTES = 32,
52 crypto_core_hsalsa20_INPUTBYTES = 16,
53 crypto_core_hsalsa20_KEYBYTES = 32,
54 crypto_core_hsalsa20_CONSTBYTES = 16,
56 crypto_hash_BYTES = 64,
58 crypto_onetimeauth_BYTES = 16,
59 crypto_onetimeauth_KEYBYTES = 32,
61 crypto_scalarmult_BYTES = 32,
62 crypto_scalarmult_SCALARBYTES = 32,
64 crypto_secretbox_KEYBYTES = 32,
65 crypto_secretbox_NONCEBYTES = 24,
66 crypto_secretbox_ZEROBYTES = 32,
67 crypto_secretbox_BOXZEROBYTES = 16,
69 crypto_sign_BYTES = 64,
70 crypto_sign_PUBLICKEYBYTES = 32,
71 crypto_sign_SECRETKEYBYTES = 64,
73 crypto_stream_xsalsa20_KEYBYTES = 32,
74 crypto_stream_xsalsa20_NONCEBYTES = 24,
76 crypto_stream_salsa20_KEYBYTES = 32,
77 crypto_stream_salsa20_NONCEBYTES = 8,
79 crypto_stream_KEYBYTES = 32,
80 crypto_stream_NONCEBYTES = 24,
82 crypto_verify_16_BYTES = 16,
83 crypto_verify_32_BYTES = 32,
87 /// set this callback to good (cryptograpic strong) random bytes generator
88 /// you can use /dev/urandom as prng
89 void function (ubyte[] dest, size_t len) randombytes = null;
92 private static __gshared immutable ubyte[16] _0 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
93 private static __gshared immutable ubyte[32] _9 = [9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
95 private static __gshared immutable long[16]
96 gf0 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
97 gf1 = [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
98 _121665 = [0xDB41,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
99 D = [0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203],
100 D2 =[0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406],
101 X = [0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169],
102 Y = [0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666],
103 I = [0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83];
105 private @tweetNaCl_gdc_attribute("forceinline") uint ld32() (const(ubyte)[] x) @safe nothrow
106 in {
107 assert(x.length >= 4);
109 body {
110 uint u = x[3];
111 u = (u<<8)|x[2];
112 u = (u<<8)|x[1];
113 return (u<<8)|x[0];
116 private @tweetNaCl_gdc_attribute("forceinline") ulong dl64() (const(ubyte)[] x) @safe nothrow
117 in {
118 assert(x.length >= 8);
120 body {
121 ulong u = x[0];
122 u = (u<<8)|x[1];
123 u = (u<<8)|x[2];
124 u = (u<<8)|x[3];
125 u = (u<<8)|x[4];
126 u = (u<<8)|x[5];
127 u = (u<<8)|x[6];
128 return (u<<8)|x[7];
131 private @tweetNaCl_gdc_attribute("forceinline") void st32() (ubyte[] x, uint u) @safe nothrow
132 in {
133 assert(x.length >= 4);
135 body {
136 x[0] = u&0xff;
137 x[1] = (u>>8)&0xff;
138 x[2] = (u>>16)&0xff;
139 x[3] = (u>>24)&0xff;
142 private @tweetNaCl_gdc_attribute("forceinline") void ts64() (ubyte[] x, ulong u) @safe nothrow
143 in {
144 assert(x.length >= 8);
146 body {
147 x[0] = (u>>56)&0xff;
148 x[1] = (u>>48)&0xff;
149 x[2] = (u>>40)&0xff;
150 x[3] = (u>>32)&0xff;
151 x[4] = (u>>24)&0xff;
152 x[5] = (u>>16)&0xff;
153 x[6] = (u>>8)&0xff;
154 x[7] = u&0xff;
157 private @tweetNaCl_gdc_attribute("forceinline") bool vn() (const(ubyte)[] x, const(ubyte)[] y) @safe nothrow
158 in {
159 assert(x.length >= y.length);
161 body {
162 uint d = 0;
163 foreach (immutable i, immutable v; x) d |= v^y[i];
164 return (1&((d-1)>>8)) != 0;
168 * The crypto_verify_16() function checks that strings 'x' and 'y' has same content.
170 * Params:
171 * x = first string, slice length must be at least crypto_verify_16_BYTES, extra ignored
172 * y = second string, slice length must be at least crypto_verify_16_BYTES, extra ignored
174 * Returns:
175 * success flag
177 @tweetNaCl_gdc_attribute("forceinline") bool crypto_verify_16() (const(ubyte)[] x, const(ubyte)[] y) @safe nothrow
178 in {
179 assert(x.length >= 16 && y.length >= 16);
181 body {
182 return vn(x[0..16], y[0..16]);
186 * The crypto_verify_32() function checks that strings 'x' and 'y' has same content.
188 * Params:
189 * x = first string, slice length must be at least crypto_verify_32_BYTES, extra ignored
190 * y = second string, slice length must be at least crypto_verify_32_BYTES, extra ignored
192 * Returns:
193 * success flag
195 @tweetNaCl_gdc_attribute("forceinline") bool crypto_verify_32() (const(ubyte)[] x, const(ubyte)[] y) @safe nothrow
196 in {
197 assert(x.length >= 32 && y.length >= 32);
199 body {
200 return vn(x[0..32], y[0..32]);
204 private void salsa_core(string type) (ubyte[] output, const(ubyte)[] input, const(ubyte)[] key, const(ubyte)[] constant) @safe nothrow
205 if (type == "salsa" || type == "hsalsa") // constraint
206 in {
207 // magic!
208 assert(mixin(`output.length >= crypto_core_`~type~`20_OUTPUTBYTES`));
209 assert(mixin(`input.length >= crypto_core_`~type~`20_INPUTBYTES`));
210 assert(mixin(`key.length >= crypto_core_`~type~`20_KEYBYTES`));
211 assert(mixin(`constant.length >= crypto_core_`~type~`20_CONSTBYTES`));
213 body {
214 static @tweetNaCl_gdc_attribute("forceinline") uint ROTL32() (uint x, int c) @safe nothrow pure { return (x<<c)|((x&0xffffffff)>>(32-c)); }
216 uint[16] w = void, x = void, y = void;
217 uint[4] t = void;
219 foreach (i; 0..4) {
220 x[5*i] = ld32(constant[4*i..$]);
221 x[1+i] = ld32(key[4*i..$]);
222 x[6+i] = ld32(input[4*i..$]);
223 x[11+i] = ld32(key[16+4*i..$]);
226 y[] = x[];
228 foreach (i; 0..20) {
229 foreach (j; 0..4) {
230 foreach (m; 0..4) t[m] = x[(5*j+4*m)%16];
231 t[1] ^= ROTL32(t[0]+t[3], 7);
232 t[2] ^= ROTL32(t[1]+t[0], 9);
233 t[3] ^= ROTL32(t[2]+t[1], 13);
234 t[0] ^= ROTL32(t[3]+t[2], 18);
235 for (auto m = 0; m < 4; ++m) w[4*j+(j+m)%4] = t[m];
237 for (auto m = 0; m < 16; ++m) x[m] = w[m];
240 static if (type == "hsalsa") {
241 for (auto i = 0; i < 16; ++i) x[i] += y[i];
242 for (auto i = 0; i < 4; ++i) {
243 x[5*i] -= ld32(constant[4*i..$]);
244 x[6+i] -= ld32(input[4*i..$]);
246 for (auto i = 0; i < 4; ++i) {
247 st32(output[4*i..$], x[5*i]);
248 st32(output[16+4*i..$], x[6+i]);
250 } else {
251 for (auto i = 0; i < 16; ++i) st32(output[4*i..$], x[i]+y[i]);
255 @tweetNaCl_gdc_attribute("forceinline") void crypto_core_salsa20() (ubyte[] output, const(ubyte)[] input, const(ubyte)[] key, const(ubyte)[] constant)
256 @safe nothrow {
257 salsa_core!"salsa"(output, input, key, constant);
260 @tweetNaCl_gdc_attribute("forceinline") void crypto_core_hsalsa20() (ubyte[] output, const(ubyte)[] input, const(ubyte)[] key, const(ubyte)[] constant)
261 @safe nothrow {
262 salsa_core!"hsalsa"(output, input, key, constant);
265 private static __gshared immutable immutable(ubyte)[] sigma = cast(immutable(ubyte)[])"expand 32-byte k";
268 * The crypto_stream_salsa20_xor() function encrypts a message 'msg' using a secret key 'key'
269 * and a nonce 'nonce'. The crypto_stream_salsa20_xor() function returns the ciphertext 'output'.
271 * Params:
272 * output = resulting ciphertext
273 * msg = message
274 * nonce = nonce
275 * key = secret key
277 * Returns:
278 * ciphertext in 'output'
280 void crypto_stream_salsa20_xor (ubyte[] output, const(ubyte)[] msg, const(ubyte)[] nonce, const(ubyte)[] key) @trusted nothrow
281 in {
282 assert(nonce.length == crypto_stream_salsa20_NONCEBYTES);
283 assert(key.length == crypto_stream_salsa20_KEYBYTES);
284 import std.stdio;
285 assert(msg.length == 0 || output.length <= msg.length);
287 body {
288 ubyte[16] z; // autoclear
289 ubyte[64] x = void;
290 uint u;
291 uint cpos = 0, mpos = 0;
292 size_t b = output.length;
293 if (!b) return;
294 z[0..8] = nonce[0..8];
295 while (b >= 64) {
296 crypto_core_salsa20(x, z, key, sigma);
297 if (msg !is null) {
298 foreach (v; x) output[cpos++] = msg[mpos++]^v;
299 } else {
300 output[cpos..cpos+64] = x[];
301 cpos += 64;
303 u = 1;
304 foreach (i; 8..16) {
305 u += cast(uint)z[i];
306 z[i] = u&0xff;
307 u >>= 8;
309 b -= 64;
311 if (b) {
312 crypto_core_salsa20(x, z, key, sigma);
313 if (msg !is null) {
314 foreach (i; 0..b) output[cpos++] = msg[mpos++]^x[i];
315 } else {
316 output[cpos..cpos+b] = x[0..b];
322 * The crypto_stream_salsa20() function produces a stream 'c'
323 * as a function of a secret key 'key' and a nonce 'nonce'.
325 * Params:
326 * c = resulting stream
327 * nonce = nonce
328 * key = secret key
330 * Returns:
331 * ciphertext in 'c'
333 void crypto_stream_salsa20() (ubyte[] c, const(ubyte)[] nonce, const(ubyte)[] key) @safe nothrow
334 in {
335 assert(nonce.length == crypto_stream_salsa20_NONCEBYTES);
336 assert(key.length == crypto_stream_salsa20_KEYBYTES);
338 body {
339 crypto_stream_salsa20_xor(c, null, nonce, key);
343 * The crypto_stream() function produces a stream 'c'
344 * as a function of a secret key 'key' and a nonce 'nonce'.
346 * Params:
347 * c = output slice
348 * nonce = nonce
349 * key = secret key
351 * Returns:
352 * stream in 'c'
354 void crypto_stream() (ubyte[] c, const(ubyte)[] nonce, const(ubyte)[] key) @safe nothrow
355 in {
356 assert(c !is null);
357 assert(nonce.length == crypto_stream_NONCEBYTES);
358 assert(key.length == crypto_stream_KEYBYTES);
360 body {
361 ubyte[32] s = void;
362 crypto_core_hsalsa20(s, nonce, key, sigma);
363 crypto_stream_salsa20(c, nonce[16..$], s);
367 * The crypto_stream_xor() function encrypts a message 'msg' using a secret key 'key'
368 * and a nonce 'nonce'. The crypto_stream_xor() function returns the ciphertext 'c'.
370 * Params:
371 * c = output slice
372 * nonce = nonce
373 * key = secret key
375 * Returns:
376 * ciphertext in 'c'
378 void crypto_stream_xor() (ubyte[] c, const(ubyte)[] msg, const(ubyte)[] nonce, const(ubyte)[] key) @safe nothrow
379 in {
380 assert(c !is null);
381 assert(msg.length >= c.length);
382 assert(nonce.length == crypto_stream_NONCEBYTES);
383 assert(key.length == crypto_stream_KEYBYTES);
385 body {
386 ubyte s[32] = void;
387 crypto_core_hsalsa20(s, nonce, key, sigma);
388 crypto_stream_salsa20_xor(c, msg, nonce[16..$], s);
391 private @tweetNaCl_gdc_attribute("forceinline") void add1305() (uint[] h, const(uint)[] c) @safe nothrow {
392 uint u = 0;
393 foreach (j; 0..17) {
394 u += h[j]+c[j];
395 h[j] = u&255;
396 u >>= 8;
400 private static __gshared immutable uint[17] minusp = [5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,252];
403 * The crypto_onetimeauth() function authenticates a message 'msg'
404 * using a secret key 'key'. The function returns an authenticator 'output'.
406 * Params:
407 * output = authenticator, slice size must be at least crypto_onetimeauth_BYTES, extra ignored
408 * msg == message
409 * key == secret key, slice size must be at least crypto_onetimeauth_KEYBYTES, extra ignored
411 * Returns:
412 * authenticator in 'output'
414 void crypto_onetimeauth() (ubyte[] output, const(ubyte)[] msg, const(ubyte)[] key) @safe nothrow
415 in {
416 assert(key.length >= crypto_onetimeauth_KEYBYTES);
417 assert(output.length >= crypto_onetimeauth_BYTES);
419 body {
420 uint s, u;
421 uint[17] x = void, r = void, h/*autoclear*/, c = void, g = void;
422 uint mpos = 0;
423 size_t n = msg.length;
425 foreach (i; 0..16) r[i] = key[i];
426 r[16..17] = 0;
428 r[3] &= 15;
429 r[4] &= 252;
430 r[7] &= 15;
431 r[8] &= 252;
432 r[11] &= 15;
433 r[12] &= 252;
434 r[15] &= 15;
436 while (n > 0) {
437 c[0..17] = 0;
439 size_t jj;
440 for (jj = 0; jj < 16 && jj < n; ++jj) c[jj] = msg[mpos+jj];
441 c[jj] = 1;
442 mpos += jj;
443 n -= jj;
445 add1305(h, c);
446 foreach (i; 0..17) {
447 x[i] = 0;
448 foreach (j; 0..17) x[i] += h[j]*(j <= i ? r[i-j] : 320*r[i+17-j]);
450 h[] = x[];
451 u = 0;
452 foreach (j; 0..16) {
453 u += h[j];
454 h[j] = u&255;
455 u >>= 8;
457 u += h[16];
458 h[16] = u&3;
459 u = 5*(u>>2);
460 foreach (j; 0..16) {
461 u += h[j];
462 h[j] = u&255;
463 u >>= 8;
465 u += h[16];
466 h[16] = u;
469 g[] = h[];
470 add1305(h, minusp);
471 s = -(h[16]>>7);
472 foreach (j; 0..17) h[j] ^= s&(g[j]^h[j]);
474 foreach (j; 0..16) c[j] = key[j+16];
475 c[16] = 0;
476 add1305(h, c);
477 foreach (j; 0..16) output[j] = cast(ubyte)(h[j]&0xff);
481 * The crypto_onetimeauth_verify() function checks that
482 * 'h' is a correct authenticator of a message 'msg' under the secret key 'key'.
484 * Params:
485 * h = authenticator, slice size must be at least crypto_onetimeauth_BYTES, extra ignored
486 * msg == message
487 * key == secret key, slice size must be at least crypto_onetimeauth_KEYBYTES, extra ignored
489 * Returns:
490 * success flag
492 bool crypto_onetimeauth_verify() (const(ubyte)[] h, const(ubyte)[] msg, const(ubyte)[] key) @safe nothrow
493 in {
494 assert(h.length >= crypto_onetimeauth_BYTES);
495 assert(key.length >= crypto_onetimeauth_KEYBYTES);
497 body {
498 ubyte x[16] = void;
499 crypto_onetimeauth(x, msg, key);
500 return crypto_verify_16(h, x);
504 * The crypto_secretbox() function encrypts and authenticates
505 * a message 'msg' using a secret key 'key' and a nonce 'nonce'.
506 * The crypto_secretbox() function returns the resulting ciphertext 'c'.
508 * Params:
509 * c = resulting cyphertext
510 * key = secret key
511 * nonce = nonce
513 * Returns:
514 * success flag and cyphertext in 'c'
516 bool crypto_secretbox() (ubyte[] c, const(ubyte)[] msg, const(ubyte)[] nonce, const(ubyte)[] key) @safe nothrow
517 in {
518 assert(key.length >= crypto_secretbox_KEYBYTES);
519 assert(nonce.length >= crypto_secretbox_NONCEBYTES);
521 body {
522 //c.length = msg.length+crypto_secretbox_ZEROBYTES;
523 if (c is null || c.length < 32) return false;
524 crypto_stream_xor(c, msg, nonce, key);
525 crypto_onetimeauth(c[16..$], c[32..$], c);
526 c[0..16] = 0;
527 //return c[crypto_secretbox_BOXZEROBYTES..$];
528 return true;
532 * The crypto_secretbox_open() function verifies and decrypts
533 * a ciphertext 'c' using a secret key 'key' and a nonce 'nonce'.
534 * The crypto_secretbox_open() function returns the resulting plaintext 'output'.
536 * Params:
537 * output = resulting message
538 * c = cyphertext
539 * key = secret key
540 * nonce = nonce
542 * Returns:
543 * success flag and message in 'output'
545 bool crypto_secretbox_open() (ubyte[] output, const(ubyte)[] c, const(ubyte)[] nonce, const(ubyte)[] key) @safe nothrow
546 in {
547 assert(key.length >= crypto_secretbox_KEYBYTES);
548 assert(nonce.length >= crypto_secretbox_NONCEBYTES);
550 body {
551 ubyte x[32] = void;
552 if (output is null || output.length < 32) return false;
553 crypto_stream(x, nonce, key);
554 if (!crypto_onetimeauth_verify(c[16..$], c[32../*$*/32+(output.length-32)], x)) return false;
555 crypto_stream_xor(output, c, nonce, key);
556 output[0..32] = 0;
557 return true;
561 private @tweetNaCl_gdc_attribute("forceinline") void car25519() (long[] o) @safe nothrow {
562 foreach (i; 0..16) {
563 o[i] += (1<<16);
564 long c = o[i]>>16;
565 o[(i+1)*(i<15)] += c-1+37*(c-1)*(i==15);
566 o[i] -= c<<16;
570 private @tweetNaCl_gdc_attribute("forceinline") void sel25519() (long[] p,long[] q, int b) @safe nothrow {
571 long c = ~(b-1);
572 foreach (i; 0..16) {
573 long t = c&(p[i]^q[i]);
574 p[i] ^= t;
575 q[i] ^= t;
579 private @tweetNaCl_gdc_attribute("forceinline") void pack25519() (ubyte[] o, const(long)[] n) @safe nothrow {
580 int b;
581 long[16] m = void, t = void;
582 t[0..16] = n[0..16];
583 car25519(t);
584 car25519(t);
585 car25519(t);
586 foreach (j; 0..2) {
587 m[0] = t[0]-0xffed;
588 foreach (i; 1..15) {
589 m[i] = t[i]-0xffff-((m[i-1]>>16)&1);
590 m[i-1] &= 0xffff;
592 m[15] = t[15]-0x7fff-((m[14]>>16)&1);
593 b = (m[15]>>16)&1;
594 m[14] &= 0xffff;
595 sel25519(t, m, 1-b);
597 foreach (i; 0..16) {
598 o[2*i] = t[i]&0xff;
599 o[2*i+1] = (t[i]>>8)&0xff;
603 private @tweetNaCl_gdc_attribute("forceinline") bool neq25519() (const(long)[] a, const(long)[] b) @safe nothrow {
604 ubyte[32] c = void, d = void;
605 pack25519(c, a);
606 pack25519(d, b);
607 return crypto_verify_32(c, d);
610 private @tweetNaCl_gdc_attribute("forceinline") ubyte par25519() (const(long)[] a) @safe nothrow {
611 ubyte d[32] = void;
612 pack25519(d, a);
613 return d[0]&1;
616 private @tweetNaCl_gdc_attribute("forceinline") void unpack25519() (long[] o, const(ubyte)[] n) @safe nothrow {
617 foreach (i; 0..16) o[i] = n[2*i]+(cast(long)n[2*i+1]<<8);
618 o[15] &= 0x7fff;
621 private @tweetNaCl_gdc_attribute("forceinline") void A() (long[] o, const(long)[] a, const(long)[] b) @safe nothrow {
622 foreach (i; 0..16) o[i] = a[i]+b[i];
625 private @tweetNaCl_gdc_attribute("forceinline") void Z() (long[] o, const(long)[] a, const(long)[] b) @safe nothrow {
626 foreach (i; 0..16) o[i] = a[i]-b[i];
629 private @tweetNaCl_gdc_attribute("forceinline") void M() (long[] o, const(long)[] a, const(long)[] b) @safe nothrow {
630 long[31] t; // automatically becomes 0
631 foreach (i; 0..16) foreach (j; 0..16) t[i+j] += a[i]*b[j];
632 foreach (i; 0..15) t[i] += 38*t[i+16];
633 o[0..16] = t[0..16];
634 car25519(o);
635 car25519(o);
638 private @tweetNaCl_gdc_attribute("forceinline") void S() (long[] o, const(long)[] a) @safe nothrow {
639 M(o, a, a);
642 private @tweetNaCl_gdc_attribute("forceinline") void inv25519() (long[] o, const(long)[] i) @safe nothrow {
643 long[16] c = void;
644 c[] = i[0..16];
645 for (auto a = 253; a >= 0; --a) {
646 S(c, c);
647 if (a != 2 && a != 4) M(c, c, i);
649 o[0..16] = c[];
652 private @tweetNaCl_gdc_attribute("forceinline") void pow2523() (long[] o, const(long)[] i) @safe nothrow {
653 long[16] c = void;
654 c[] = i[0..16];
655 for(auto a = 250; a >= 0; --a) {
656 S(c, c);
657 if (a != 1) M(c, c, i);
659 o[0..16] = c[];
662 /* FIXME!
663 * This function multiplies a group element 'p' by an integer 'n'.
665 * Params:
666 * p = group element
667 * n = number
669 * Returns:
670 * resulting group element 'q' of length crypto_scalarmult_BYTES.
672 private void crypto_scalarmult (ubyte[] q, const(ubyte)[] n, const(ubyte)[] p) @safe nothrow
673 in {
674 assert(q.length == crypto_scalarmult_BYTES);
675 assert(n.length == crypto_scalarmult_BYTES);
676 assert(p.length == crypto_scalarmult_BYTES);
678 body {
679 ubyte[32] z = void;
680 long[80] x = void;
681 long r;
682 long[16] a = void, b = void, c = void, d = void, e = void, f = void;
683 z[] = n[0..32];
684 z[31] = (n[31]&127)|64;
685 z[0] &= 248;
686 unpack25519(x, p);
687 foreach (i; 0..16) {
688 b[i] = x[i];
689 d[i] = a[i] = c[i] = 0;
691 a[0] = d[0] = 1;
692 for (int i = 254; i >= 0; --i) {
693 r = (z[i>>3]>>(i&7))&1;
694 sel25519(a, b, cast(int)r);
695 sel25519(c, d, cast(int)r);
696 A(e, a, c);
697 Z(a, a, c);
698 A(c, b, d);
699 Z(b, b, d);
700 S(d, e);
701 S(f, a);
702 M(a, c, a);
703 M(c, b, e);
704 A(e, a, c);
705 Z(a, a, c);
706 S(b, a);
707 Z(c, d, f);
708 M(a, c, _121665);
709 A(a, a, d);
710 M(c, c, a);
711 M(a, d, f);
712 M(d, b, x);
713 S(b, e);
714 sel25519(a, b, cast(int)r);
715 sel25519(c, d, cast(int)r);
717 foreach (i; 0..16) {
718 x[i+16] = a[i];
719 x[i+32] = c[i];
720 x[i+48] = b[i];
721 x[i+64] = d[i];
723 inv25519(x[32..$], x[32..$]);
724 M(x[16..$], x[16..$], x[32..$]);
725 pack25519(q, x[16..$]);
728 /* FIXME!
729 * The crypto_scalarmult_base() function computes
730 * the scalar product of a standard group element and an integer 'n'.
732 * Params:
733 * n = number
735 * Returns:
736 * resulting group element 'q' of length crypto_scalarmult_BYTES.
738 private void crypto_scalarmult_base() (ubyte[] q, const(ubyte)[] n) @safe nothrow
739 in {
740 assert(q.length == crypto_scalarmult_BYTES);
741 assert(n.length == crypto_scalarmult_SCALARBYTES);
743 body {
744 crypto_scalarmult(q, n, _9);
748 * The crypto_box_keypair() function randomly generates a secret key and
749 * a corresponding public key.
751 * Params:
752 * pk = slice to put generated public key into
753 * sk = slice to put generated secret key into
755 * Returns:
756 * pair of new keys
758 void crypto_box_keypair() (ubyte[] pk, ubyte[] sk) @trusted
759 in {
760 assert(pk.length >= crypto_box_PUBLICKEYBYTES);
761 assert(sk.length >= crypto_box_SECRETKEYBYTES);
763 body {
764 randombytes(sk, 32);
765 crypto_scalarmult_base(pk, sk);
769 * Function crypto_box_beforenm() computes a shared secret 's' from
770 * public key 'pk' and secret key 'sk'.
772 * Params:
773 * skey = slice to put secret into
774 * pk = public
775 * sk = secret
777 * Returns:
778 * generated secret
780 void crypto_box_beforenm() (ubyte[] skey, const(ubyte)[] pk, const(ubyte)[] sk) @safe nothrow
781 in {
782 assert(pk.length >= crypto_box_PUBLICKEYBYTES);
783 assert(sk.length >= crypto_box_SECRETKEYBYTES);
784 assert(skey.length >= crypto_box_BEFORENMBYTES);
786 body {
787 ubyte s[32] = void;
788 crypto_scalarmult(s, sk, pk);
789 crypto_core_hsalsa20(skey, _0, s, sigma);
793 * The crypto_box_afternm() function encrypts and authenticates
794 * a message 'msg' using a secret key 'key' and a nonce 'nonce'.
795 * The crypto_box_afternm() function returns the resulting ciphertext 'c'.
797 * Params:
798 * c = resulting cyphertext
799 * msg = message
800 * nonce = nonce
801 * key = secret
803 * Returns:
804 * success flag and cyphertext in 'c'
806 bool crypto_box_afternm() (ubyte[] c, const(ubyte)[] msg, const(ubyte)[] nonce, const(ubyte)[] key) @safe nothrow
807 in {
808 assert(nonce.length >= crypto_box_NONCEBYTES);
809 assert(key.length >= crypto_box_BEFORENMBYTES);
811 body {
812 return crypto_secretbox(c, msg, nonce, key);
816 * The crypto_box_open_afternm() function verifies and decrypts
817 * a ciphertext 'c' using a secret key 'key' and a nonce 'nonce'.
818 * The crypto_box_open_afternm() function returns the resulting message 'msg'.
820 * Params:
821 * msg = resulting message
822 * c = cyphertext
823 * nonce = nonce
824 * key = secret
826 * Returns:
827 * success flag and resulting message in 'msg'
829 bool crypto_box_open_afternm() (ubyte[] msg, const(ubyte)[] c, const(ubyte)[] nonce, const(ubyte)[] key) @safe nothrow
830 in {
831 assert(nonce.length >= crypto_box_NONCEBYTES);
832 assert(key.length >= crypto_box_BEFORENMBYTES);
834 body {
835 return crypto_secretbox_open(msg, c, nonce, key);
839 * The crypto_box() function encrypts and authenticates a message 'msg'
840 * using the sender's secret key 'sk', the receiver's public key 'pk',
841 * and a nonce 'nonce'. The crypto_box() function returns the resulting ciphertext 'c'.
843 * Params:
844 * c = resulting cyphertext
845 * msg = message
846 * nonce = nonce
847 * pk = receiver's public key
848 * sk = sender's secret key
850 * Returns:
851 * success flag and cyphertext in 'c'
853 bool crypto_box() (ubyte[] c, const(ubyte)[] msg, const(ubyte)[] nonce, const(ubyte)[] pk, const(ubyte)[] sk) @safe nothrow
854 in {
855 assert(nonce.length >= crypto_box_NONCEBYTES);
856 assert(pk.length >= crypto_box_PUBLICKEYBYTES);
857 assert(sk.length >= crypto_box_SECRETKEYBYTES);
859 body {
860 ubyte k[32] = void;
861 crypto_box_beforenm(k, pk, sk);
862 return crypto_box_afternm(c, msg, nonce, k);
866 * The crypto_box_open() function verifies and decrypts
867 * a ciphertext 'c' using the receiver's secret key 'sk',
868 * the sender's public key 'pk', and a nonce 'nonce'.
869 * The crypto_box_open() function returns the resulting message 'msg'.
871 * Params:
872 * msg = resulting message
873 * c = cyphertext
874 * nonce = nonce
875 * pk = receiver's public key
876 * sk = sender's secret key
878 * Returns:
879 * success flag and message in 'msg'
881 bool crypto_box_open() (ubyte[] msg, const(ubyte)[] c, const(ubyte)[] nonce, const(ubyte)[] pk, const(ubyte)[] sk) @safe nothrow
882 in {
883 assert(nonce.length >= crypto_box_NONCEBYTES);
884 assert(pk.length >= crypto_box_PUBLICKEYBYTES);
885 assert(sk.length >= crypto_box_SECRETKEYBYTES);
887 body {
888 ubyte k[32] = void;
889 crypto_box_beforenm(k, pk, sk);
890 return crypto_box_open_afternm(msg, c, nonce, k);
893 private @tweetNaCl_gdc_attribute("forceinline") ulong R() (ulong x, int c) @safe nothrow pure { return (x>>c)|(x<<(64-c)); }
894 private @tweetNaCl_gdc_attribute("forceinline") ulong Ch() (ulong x, ulong y, ulong z) @safe nothrow pure { return (x&y)^(~x&z); }
895 private @tweetNaCl_gdc_attribute("forceinline") ulong Maj() (ulong x, ulong y, ulong z) @safe nothrow pure { return (x&y)^(x&z)^(y&z); }
896 private @tweetNaCl_gdc_attribute("forceinline") ulong Sigma0() (ulong x) @safe nothrow pure { return R(x, 28)^R(x, 34)^R(x, 39); }
897 private @tweetNaCl_gdc_attribute("forceinline") ulong Sigma1() (ulong x) @safe nothrow pure { return R(x, 14)^R(x, 18)^R(x, 41); }
898 private @tweetNaCl_gdc_attribute("forceinline") ulong sigma0() (ulong x) @safe nothrow pure { return R(x, 1)^R(x, 8)^(x>>7); }
899 private @tweetNaCl_gdc_attribute("forceinline") ulong sigma1() (ulong x) @safe nothrow pure { return R(x, 19)^R(x, 61)^(x>>6); }
901 private static __gshared immutable ulong[80] K = [
902 0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL,
903 0x3956c25bf348b538UL, 0x59f111f1b605d019UL, 0x923f82a4af194f9bUL, 0xab1c5ed5da6d8118UL,
904 0xd807aa98a3030242UL, 0x12835b0145706fbeUL, 0x243185be4ee4b28cUL, 0x550c7dc3d5ffb4e2UL,
905 0x72be5d74f27b896fUL, 0x80deb1fe3b1696b1UL, 0x9bdc06a725c71235UL, 0xc19bf174cf692694UL,
906 0xe49b69c19ef14ad2UL, 0xefbe4786384f25e3UL, 0x0fc19dc68b8cd5b5UL, 0x240ca1cc77ac9c65UL,
907 0x2de92c6f592b0275UL, 0x4a7484aa6ea6e483UL, 0x5cb0a9dcbd41fbd4UL, 0x76f988da831153b5UL,
908 0x983e5152ee66dfabUL, 0xa831c66d2db43210UL, 0xb00327c898fb213fUL, 0xbf597fc7beef0ee4UL,
909 0xc6e00bf33da88fc2UL, 0xd5a79147930aa725UL, 0x06ca6351e003826fUL, 0x142929670a0e6e70UL,
910 0x27b70a8546d22ffcUL, 0x2e1b21385c26c926UL, 0x4d2c6dfc5ac42aedUL, 0x53380d139d95b3dfUL,
911 0x650a73548baf63deUL, 0x766a0abb3c77b2a8UL, 0x81c2c92e47edaee6UL, 0x92722c851482353bUL,
912 0xa2bfe8a14cf10364UL, 0xa81a664bbc423001UL, 0xc24b8b70d0f89791UL, 0xc76c51a30654be30UL,
913 0xd192e819d6ef5218UL, 0xd69906245565a910UL, 0xf40e35855771202aUL, 0x106aa07032bbd1b8UL,
914 0x19a4c116b8d2d0c8UL, 0x1e376c085141ab53UL, 0x2748774cdf8eeb99UL, 0x34b0bcb5e19b48a8UL,
915 0x391c0cb3c5c95a63UL, 0x4ed8aa4ae3418acbUL, 0x5b9cca4f7763e373UL, 0x682e6ff3d6b2b8a3UL,
916 0x748f82ee5defb2fcUL, 0x78a5636f43172f60UL, 0x84c87814a1f0ab72UL, 0x8cc702081a6439ecUL,
917 0x90befffa23631e28UL, 0xa4506cebde82bde9UL, 0xbef9a3f7b2c67915UL, 0xc67178f2e372532bUL,
918 0xca273eceea26619cUL, 0xd186b8c721c0c207UL, 0xeada7dd6cde0eb1eUL, 0xf57d4f7fee6ed178UL,
919 0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL, 0x113f9804bef90daeUL, 0x1b710b35131c471bUL,
920 0x28db77f523047d84UL, 0x32caab7b40c72493UL, 0x3c9ebe0a15c9bebcUL, 0x431d67c49c100d4cUL,
921 0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL, 0x5fcb6fab3ad6faecUL, 0x6c44198c4a475817UL
924 private void crypto_hashblocks (ubyte[] x, const(ubyte)[] m, ulong n) @safe nothrow {
925 ulong[8] z = void, b = void, a = void;
926 ulong[16] w = void;
927 ulong t;
928 uint mpos = 0;
929 foreach (i; 0..8) z[i] = a[i] = dl64(x[8*i..$]);
930 while (n >= 128) {
931 foreach (i; 0..16) w[i] = dl64(m[mpos+8*i..$]);
932 foreach (i; 0..80) {
933 b[0..8] = a[0..8];
934 t = a[7]+Sigma1(a[4])+Ch(a[4], a[5], a[6])+K[i]+w[i%16];
935 b[7] = t+Sigma0(a[0])+Maj(a[0], a[1], a[2]);
936 b[3] += t;
937 //foreach (j; 0..8) a[(j+1)%8] = b[j];
938 a[1..8] = b[0..7];
939 a[0] = b[7];
940 if (i%16 == 15) {
941 foreach (j; 0..16) w[j] += w[(j+9)%16]+sigma0(w[(j+1)%16])+sigma1(w[(j+14)%16]);
944 foreach (i; 0..8) { a[i] += z[i]; z[i] = a[i]; }
945 mpos += 128;
946 n -= 128;
948 foreach (i; 0..8) ts64(x[8*i..$], z[i]);
951 private static __gshared immutable ubyte[64] iv = [
952 0x6a, 0x09, 0xe6, 0x67, 0xf3, 0xbc, 0xc9, 0x08,
953 0xbb, 0x67, 0xae, 0x85, 0x84, 0xca, 0xa7, 0x3b,
954 0x3c, 0x6e, 0xf3, 0x72, 0xfe, 0x94, 0xf8, 0x2b,
955 0xa5, 0x4f, 0xf5, 0x3a, 0x5f, 0x1d, 0x36, 0xf1,
956 0x51, 0x0e, 0x52, 0x7f, 0xad, 0xe6, 0x82, 0xd1,
957 0x9b, 0x05, 0x68, 0x8c, 0x2b, 0x3e, 0x6c, 0x1f,
958 0x1f, 0x83, 0xd9, 0xab, 0xfb, 0x41, 0xbd, 0x6b,
959 0x5b, 0xe0, 0xcd, 0x19, 0x13, 0x7e, 0x21, 0x79
963 * The crypto_hash() function hashes a message 'msg'.
964 * It returns a hash 'output'. The output length of 'output' should be at least crypto_hash_BYTES.
966 * Params:
967 * output = resulting hash
968 * msg = message
970 * Returns:
971 * sha512 hash
973 void crypto_hash() (ubyte[] output, const(ubyte)[] msg) @safe nothrow
974 in {
975 assert(output.length >= crypto_hash_BYTES);
977 body {
978 ubyte[64] h = void;
979 ubyte[256] x; /*autoinit*/
980 size_t n = msg.length;
981 ulong b = n;
982 uint mpos = 0;
984 h[] = iv[];
986 crypto_hashblocks(h, msg, n);
987 mpos += n;
988 n &= 127;
989 mpos -= n;
991 x[0..n] = msg[mpos..mpos+n];
992 x[n] = 128;
994 n = 256-128*(n<112);
995 x[n-9] = b>>61;
996 ts64(x[n-8..$], b<<3);
997 crypto_hashblocks(h, x, n);
999 output[0..64] = h;
1002 private @tweetNaCl_gdc_attribute("forceinline") void add() (ref long[16][4] p, ref long[16][4] q) @safe nothrow {
1003 long[16] a = void, b = void, c = void, d = void, t = void, e = void, f = void, g = void, h = void;
1005 Z(a, p[1], p[0]);
1006 Z(t, q[1], q[0]);
1007 M(a, a, t);
1008 A(b, p[0], p[1]);
1009 A(t, q[0], q[1]);
1010 M(b, b, t);
1011 M(c, p[3], q[3]);
1012 M(c, c, D2);
1013 M(d, p[2], q[2]);
1014 A(d, d, d);
1015 Z(e, b, a);
1016 Z(f, d, c);
1017 A(g, d, c);
1018 A(h, b, a);
1020 M(p[0], e, f);
1021 M(p[1], h, g);
1022 M(p[2], g, f);
1023 M(p[3], e, h);
1026 private @tweetNaCl_gdc_attribute("forceinline") void cswap() (ref long[16][4] p, ref long[16][4] q, ubyte b) @safe nothrow {
1027 foreach (i; 0..4) sel25519(p[i], q[i], b);
1030 private @tweetNaCl_gdc_attribute("forceinline") void pack() (ubyte[] r, ref long[16][4] p) @safe nothrow {
1031 long[16] tx = void, ty = void, zi = void;
1032 inv25519(zi, p[2]);
1033 M(tx, p[0], zi);
1034 M(ty, p[1], zi);
1035 pack25519(r, ty);
1036 r[31] ^= par25519(tx)<<7;
1039 private @tweetNaCl_gdc_attribute("forceinline") void scalarmult() (ref long[16][4] p, ref long[16][4] q, const(ubyte)[] s) @safe nothrow {
1040 p[0][] = gf0[];
1041 p[1][] = gf1[];
1042 p[2][] = gf1[];
1043 p[3][] = gf0[];
1044 for (int i = 255; i >= 0; --i) {
1045 ubyte b = (s[i/8]>>(i&7))&1;
1046 cswap(p, q, b);
1047 add(q, p);
1048 add(p, p);
1049 cswap(p, q, b);
1053 private @tweetNaCl_gdc_attribute("forceinline") void scalarbase() (ref long[16][4] p, const(ubyte)[] s) @safe nothrow {
1054 long[16][4] q = void;
1055 q[0][] = X[];
1056 q[1][] = Y[];
1057 q[2][] = gf1[];
1058 M(q[3], X, Y);
1059 scalarmult(p, q, s);
1063 * The crypto_sign_keypair() function randomly generates a secret key and
1064 * a corresponding public key.
1066 * Params:
1067 * pk = slice to put generated public key into
1068 * sk = slice to put generated secret key into
1070 * Returns:
1071 * pair of new keys
1073 void crypto_sign_keypair() (ubyte[] pk, ubyte[] sk) @trusted
1074 in {
1075 assert(pk.length >= crypto_sign_PUBLICKEYBYTES);
1076 assert(sk.length >= crypto_sign_SECRETKEYBYTES);
1078 body {
1079 ubyte d[64] = void;
1080 long[16][4] p = void;
1082 randombytes(sk, 32);
1083 crypto_hash(d, sk[0..32]);
1084 d[0] &= 248;
1085 d[31] &= 127;
1086 d[31] |= 64;
1088 scalarbase(p, d);
1089 pack(pk, p);
1091 sk[32..64] = pk[0..32];
1094 private static __gshared immutable ulong[32] L = [
1095 0xed,0xd3,0xf5,0x5c,0x1a,0x63,0x12,0x58,0xd6,0x9c,0xf7,0xa2,0xde,0xf9,0xde,0x14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x10
1098 private @tweetNaCl_gdc_attribute("forceinline") void modL() (ubyte[] r, long[] x) @safe nothrow {
1099 long carry;
1100 for (auto i = 63; i >= 32; --i) {
1101 int j;
1102 carry = 0;
1103 for (j = i-32; j < i-12; ++j) {
1104 x[j] += carry-16*x[i]*L[j-(i-32)];
1105 carry = (x[j]+128)>>8;
1106 x[j] -= carry<<8;
1108 x[j] += carry;
1109 x[i] = 0;
1111 carry = 0;
1112 foreach (j; 0..32) {
1113 x[j] += carry-(x[31]>>4)*L[j];
1114 carry = x[j]>>8;
1115 x[j] &= 255;
1117 foreach (j; 0..32) x[j] -= carry*L[j];
1118 foreach (i; 0..32) {
1119 x[i+1] += x[i]>>8;
1120 r[i] = x[i]&255;
1124 private @tweetNaCl_gdc_attribute("forceinline") void reduce() (ubyte[] r) @safe nothrow {
1125 long[64] x = void;
1126 foreach (i; 0..64) x[i] = cast(ulong)r[i];
1127 r[0..64] = 0;
1128 modL(r, x);
1132 * The crypto_sign() function signs a message 'msg' using the sender's secret key 'sk'.
1133 * The crypto_sign() function returns the resulting signed message.
1135 * Params:
1136 * sm = buffer to receive signed message, must be of size at least msg.length+64
1137 * msg == message
1138 * sk == secret key, slice size must be at least crypto_sign_SECRETKEYBYTES, extra ignored
1140 * Returns:
1141 * signed message
1143 void crypto_sign() (ubyte[] sm, const(ubyte)[] msg, const(ubyte)[] sk) @trusted nothrow
1144 in {
1145 assert(sk.length >= crypto_sign_SECRETKEYBYTES);
1146 assert(sm.length >= msg.length+64);
1148 body {
1149 ubyte[64] d = void, h = void, r = void;
1150 ulong[64] x;/*autoinit*/
1151 long[16][4] p = void;
1152 size_t n = msg.length;
1153 size_t smlen = n+64;
1155 crypto_hash(d, sk[0..32]);
1156 d[0] &= 248;
1157 d[31] &= 127;
1158 d[31] |= 64;
1160 sm[64..64+n] = msg[];
1161 sm[32..64] = d[32..64];
1163 crypto_hash(r, sm[32..32+n+32]);
1164 reduce(r);
1165 scalarbase(p, r);
1166 pack(sm, p);
1168 sm[32..64] = sk[32..64];
1169 crypto_hash(h, sm[0..n+64]);
1170 reduce(h);
1172 foreach (i; 0..32) x[i] = cast(ulong)r[i];
1173 foreach (i; 0..32) foreach (j; 0..32) x[i+j] += h[i]*cast(ulong)d[j];
1174 modL(sm[32..$], cast(long[])x);
1178 * The crypto_sign() function signs a message 'msg' using the sender's secret key 'sk'.
1179 * The crypto_sign() function returns the resulting signed message.
1181 * WARNING! This function allocates!
1183 * Params:
1184 * msg == message
1185 * sk == secret key, slice size must be at least crypto_sign_SECRETKEYBYTES, extra ignored
1187 * Returns:
1188 * signed message
1190 ubyte[] crypto_sign() (const(ubyte)[] msg, const(ubyte)[] sk) @safe nothrow
1191 in {
1192 assert(sk.length >= crypto_sign_SECRETKEYBYTES);
1194 body {
1195 ubyte[] sm;
1196 size_t n = msg.length;
1197 size_t smlen = n+64;
1198 sm.length = smlen;
1199 crypto_sign(sm, msg, sk);
1200 return sm;
1203 private @tweetNaCl_gdc_attribute("forceinline") bool unpackneg() (ref long[16][4] r, const(ubyte)[] p) @safe nothrow {
1204 long[16] t = void, chk = void, num = void, den = void, den2 = void, den4 = void, den6 = void;
1205 r[2][] = gf1[];
1206 unpack25519(r[1], p);
1207 S(num, r[1]);
1208 M(den, num, D);
1209 Z(num, num, r[2]);
1210 A(den, r[2], den);
1212 S(den2, den);
1213 S(den4, den2);
1214 M(den6, den4, den2);
1215 M(t, den6, num);
1216 M(t, t, den);
1218 pow2523(t, t);
1219 M(t, t, num);
1220 M(t, t, den);
1221 M(t, t, den);
1222 M(r[0], t, den);
1224 S(chk, r[0]);
1225 M(chk, chk, den);
1226 if (!neq25519(chk, num)) M(r[0], r[0], I);
1228 S(chk, r[0]);
1229 M(chk, chk, den);
1230 if (!neq25519(chk, num)) return false;
1232 if (par25519(r[0]) == (p[31]>>7)) Z(r[0], gf0, r[0]);
1234 M(r[3], r[0], r[1]);
1235 return true;
1239 * The crypto_sign_open() function verifies the signature in
1240 * 'sm' using the receiver's public key 'pk'.
1242 * Params:
1243 * msg = decrypted message, last 64 bytes are useless zeroes, must be of size at least sm.length
1244 * sm == signed message
1245 * pk == public key, slice size must be at least crypto_sign_PUBLICKEYBYTES, extra ignored
1247 * Returns:
1248 * success flag
1250 bool crypto_sign_open() (ubyte[] msg, const(ubyte)[] sm, const(ubyte)[] pk) @safe nothrow
1251 in {
1252 assert(pk.length >= crypto_sign_PUBLICKEYBYTES);
1253 assert(msg.length >= sm.length);
1255 body {
1256 ubyte[32] t = void;
1257 ubyte[64] h = void;
1258 long[16][4] p = void, q = void;
1259 size_t n = sm.length;
1261 if (n < 64) return false;
1263 if (!unpackneg(q, pk)) return false;
1264 msg[0..n] = sm[];
1265 msg[32..64] = pk[0..32];
1266 crypto_hash(h, msg);
1267 reduce(h);
1268 scalarmult(p, q, h);
1270 scalarbase(q, sm[32..$]);
1271 add(p, q);
1272 pack(t, p);
1274 n -= 64;
1275 if (!crypto_verify_32(sm, t)) {
1276 msg[0..n] = 0;
1277 return false;
1280 msg[0..n] = sm[64..64+n];
1281 msg[n..n+64] = 0;
1283 return true;
1288 * The crypto_sign_open() function verifies the signature in
1289 * 'sm' using the receiver's public key 'pk'.
1290 * The crypto_sign_open() function returns the message.
1292 * WARNING! This function allocates!
1294 * Params:
1295 * sm == signed message
1296 * pk == public key, slice size must be at least crypto_sign_PUBLICKEYBYTES, extra ignored
1298 * Returns:
1299 * decrypted message or null on error
1301 ubyte[] crypto_sign_open() (const(ubyte)[] sm, const(ubyte)[] pk) @safe nothrow {
1302 ubyte[] msg;
1303 msg.length = sm.length;
1304 if (!crypto_sign_open(msg, sm, pk)) return null;
1305 return msg[0..sm.length-64]; // remove signature
1309 unittest {
1310 import std.exception;
1311 import std.random;
1312 import std.range;
1313 import std.stdio;
1316 private extern(C) int open(const(char)* filename, int flags, ...);
1317 void randombytes (ubyte[] dest, size_t len) {
1318 import core.sys.posix.unistd;
1319 static int fd = -1;
1320 if (fd == -1) {
1321 for (;;) {
1322 fd = open("/dev/urandom", /*O_RDONLY*/0);
1323 if (fd != -1) break;
1324 sleep(1);
1327 size_t pos = 0;
1328 while (len > 0) {
1329 ssize_t i = read(fd, cast(void*)(&dest[pos]), (len < 1048576 ? len : 1048576));
1330 if (i < 1) {
1331 sleep(1);
1332 continue;
1334 pos += i;
1335 len -= i;
1340 static void rnd (ubyte[] dest, size_t len) {
1341 for (size_t f = 0; f < len; ++f) dest[f] = cast(ubyte)uniform(0, 256);
1343 randombytes = &rnd;
1346 randombytes = (ubyte[] dest, size_t len) {
1347 for (size_t f = 0; f < len; ++f) dest[f] = cast(ubyte)uniform(0, 256);
1350 void dumpArray(T) (T[] arr) @trusted {
1351 writefln("============================= (%s)", arr.length);
1352 for (auto f = 0; f < arr.length; ++f) {
1353 if (f && f%16 == 0) writeln();
1354 static if (T.sizeof == 1) writef(" 0x%02x", arr[f]);
1355 else static if (T.sizeof == 2) writef(" 0x%04x", arr[f]);
1356 else static if (T.sizeof == 4) writef(" 0x%08x", arr[f]);
1357 else writef(" 0x%08x", arr[f]);
1359 writeln();
1360 writeln("-----------------------------");
1363 string hashToString (const(ubyte)[] hash) {
1364 char[] s;
1365 s.length = hash.length*2;
1366 char toHex(int a) { return cast(char)(a < 10 ? a+'0' : a+'a'-10); }
1367 for (int a = 0; a < hash.length; ++a) {
1368 s[a*2] = toHex(hash[a]>>4);
1369 s[a*2+1] = toHex(hash[a]&0x0f);
1371 return assumeUnique(s);
1374 static immutable ubyte[crypto_sign_PUBLICKEYBYTES] pk = [0x8f,0x58,0xd8,0xbf,0xb1,0x92,0xd1,0xd7,0xe0,0xc3,0x99,0x8a,0x8d,0x5c,0xb5,0xef,0xfc,0x92,0x2a,0x0d,0x70,0x80,0xe8,0x3b,0xe0,0x27,0xeb,0xf6,0x14,0x95,0xfd,0x16];
1375 static immutable ubyte[crypto_sign_SECRETKEYBYTES] sk = [0x78,0x34,0x09,0x59,0x54,0xaa,0xa9,0x2c,0x52,0x3a,0x41,0x3f,0xb6,0xfa,0x6b,0xe1,0xd7,0x0f,0x39,0x30,0x5a,0xe1,0x70,0x12,0x59,0x7d,0x32,0x59,0x9b,0x8b,0x6b,0x2f, 0x8f,0x58,0xd8,0xbf,0xb1,0x92,0xd1,0xd7,0xe0,0xc3,0x99,0x8a,0x8d,0x5c,0xb5,0xef,0xfc,0x92,0x2a,0x0d,0x70,0x80,0xe8,0x3b,0xe0,0x27,0xeb,0xf6,0x14,0x95,0xfd,0x16];
1376 static immutable ubyte[5] m = [0x61,0x68,0x6f,0x6a,0x0a];
1377 static immutable ubyte[69] sm = [0xce,0x1e,0x15,0xad,0xc3,0x17,0x47,0x15,0x7d,0x44,0x60,0xc1,0x7f,0xb8,0xba,0x45,0xf3,0x6d,0x0b,0xbf,0x51,0xf9,0xbb,0x6b,0xb9,0xa1,0xd2,0x4e,0x44,0x8d,0x9e,0x8c,0x36,0x6f,0x7a,0x8b,0x5e,0x2c,0x69,0xba,0x90,0x2e,0x95,0x46,0x19,0xd8,0xc1,0x8a,0x47,0xc5,0x6e,0x4a,0x28,0x9e,0x81,0x17,0xae,0x90,0x69,0x71,0x7d,0x84,0x6a,0x01,0x61,0x68,0x6f,0x6a,0x0a];
1378 ubyte[] smres, t;
1380 writeln("crypto_sign");
1381 smres = crypto_sign(m, sk);
1382 assert(smres.length == sm.length);
1383 assert(smres == sm);
1385 writeln("crypto_sign_open");
1386 t = crypto_sign_open(smres, pk);
1387 assert(t !is null);
1388 assert(t.length == m.length);
1389 assert(t == m);
1392 // based on the code by Adam D. Ruppe
1393 // This does the preprocessing of input data, fetching one byte at a time of the data until it is empty, then the padding and length at the end
1394 template SHARange(T) if (isInputRange!(T)) {
1395 struct SHARange {
1396 T r;
1398 bool empty () { return state == 5; }
1400 void popFront () {
1401 if (state == 0) {
1402 r.popFront;
1403 ++length; // FIXME
1404 if (r.empty) {
1405 state = 1;
1406 position = 2;
1407 current = 0x80;
1409 } else {
1410 bool hackforward = false;
1411 if (state == 1) {
1412 current = 0x0;
1413 state = 2;
1414 if (((position+length+8)*8)%512 == 8) {
1415 --position;
1416 hackforward = true;
1418 goto proceed;
1419 //++position;
1420 } else if (state == 2) {
1421 proceed:
1422 if (!(((position+length+8)*8)%512)) {
1423 state = 3;
1424 position = 7;
1425 length *= 8;
1426 if (hackforward) goto proceedmoar;
1427 } else {
1428 ++position;
1430 } else if (state == 3) {
1431 proceedmoar:
1432 current = (length>>(position*8))&0xff;
1433 if (position == 0) state = 4; else --position;
1434 } else if (state == 4) {
1435 current = 0xff;
1436 state = 5;
1441 ubyte front () {
1442 if (state == 0) return cast(ubyte)r.front();
1443 assert(state != 5);
1444 //writefln("%x", current);
1445 return current;
1448 ubyte current;
1449 uint position;
1450 ulong length;
1451 int state = 0; // reading range, reading appended bit, reading padding, reading length, done
1456 immutable(ubyte)[] SHA256(T) (T data) if (isInputRange!(T)) {
1457 uint[8] h = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19];
1458 static immutable(uint[64]) k = [
1459 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
1460 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
1461 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
1462 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
1463 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
1464 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
1465 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
1466 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
1470 SHARange!(T) range;
1471 static if (is(data == SHARange)) range = data; else range.r = data;
1474 while(!range.empty) {
1475 uint[64] words;
1477 for(int a = 0; a < 16; ++a) {
1478 for(int b = 3; b >= 0; --b) {
1479 words[a] |= cast(uint)(range.front())<<(b*8);
1480 range.popFront;
1484 uint ror (uint n, int cnt) {
1485 return cast(uint)(n>>cnt)|cast(uint)(n<<(32-(cnt)));
1488 uint xrot00 (uint reax, int r0, int r1, int r2) {
1489 uint rebx = reax, recx = reax;
1490 reax = ror(reax, r0);
1491 rebx = ror(rebx, r1);
1492 recx >>= r2;
1493 reax ^= rebx;
1494 reax ^= recx;
1495 return reax;
1498 for(int a = 16; a < 64; ++a) {
1499 uint t1 = xrot00(words[a-15], 7, 18, 3);
1500 uint t2 = xrot00(words[a-2], 17, 19, 10);
1501 words[a] = words[a-16]+t1+words[a-7]+t2;
1504 uint A = h[0];
1505 uint B = h[1];
1506 uint C = h[2];
1507 uint D = h[3];
1508 uint E = h[4];
1509 uint F = h[5];
1510 uint G = h[6];
1511 uint H = h[7];
1513 uint xrot01 (uint reax, int r0, int r1, int r2) {
1514 uint rebx = reax, recx = reax;
1515 reax = ror(reax, r0);
1516 rebx = ror(rebx, r1);
1517 recx = ror(recx, r2);
1518 reax ^= rebx;
1519 reax ^= recx;
1520 return reax;
1523 for(int i = 0; i < 64; ++i) {
1524 uint s0 = xrot01(A, 2, 13, 22);
1525 uint maj = (A&B)^(A&C)^(B&C);
1526 uint t2 = s0+maj;
1527 uint s1 = xrot01(E, 6, 11, 25);
1528 uint ch = (E&F)^((~E)&G);
1529 uint t1 = H+s1+ch+k[i]+words[i];
1531 H = G;
1532 G = F;
1533 F = E;
1534 E = D+t1;
1535 D = C;
1536 C = B;
1537 B = A;
1538 A = t1+t2;
1541 h[0] += A;
1542 h[1] += B;
1543 h[2] += C;
1544 h[3] += D;
1545 h[4] += E;
1546 h[5] += F;
1547 h[6] += G;
1548 h[7] += H;
1551 ubyte[] hash;
1552 for(int j = 0; j < 8; ++j)
1553 for(int i = 3; i >= 0; --i) {
1554 hash ~= cast(ubyte)(h[j]>>(i*8))&0xff;
1557 return hash.idup;
1561 void box () {
1562 writeln("box");
1564 static immutable ubyte[32] alicesk = [
1565 0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d
1566 ,0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45
1567 ,0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a
1568 ,0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a
1571 static immutable ubyte[32] bobpk = [
1572 0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4
1573 ,0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37
1574 ,0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d
1575 ,0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f
1578 static immutable ubyte[24] nonce = [
1579 0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
1580 ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
1581 ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37
1584 // API requires first 32 bytes to be 0
1585 static immutable ubyte[163] m = [
1586 0, 0, 0, 0, 0, 0, 0, 0
1587 , 0, 0, 0, 0, 0, 0, 0, 0
1588 , 0, 0, 0, 0, 0, 0, 0, 0
1589 , 0, 0, 0, 0, 0, 0, 0, 0
1590 ,0xbe,0x07,0x5f,0xc5,0x3c,0x81,0xf2,0xd5
1591 ,0xcf,0x14,0x13,0x16,0xeb,0xeb,0x0c,0x7b
1592 ,0x52,0x28,0xc5,0x2a,0x4c,0x62,0xcb,0xd4
1593 ,0x4b,0x66,0x84,0x9b,0x64,0x24,0x4f,0xfc
1594 ,0xe5,0xec,0xba,0xaf,0x33,0xbd,0x75,0x1a
1595 ,0x1a,0xc7,0x28,0xd4,0x5e,0x6c,0x61,0x29
1596 ,0x6c,0xdc,0x3c,0x01,0x23,0x35,0x61,0xf4
1597 ,0x1d,0xb6,0x6c,0xce,0x31,0x4a,0xdb,0x31
1598 ,0x0e,0x3b,0xe8,0x25,0x0c,0x46,0xf0,0x6d
1599 ,0xce,0xea,0x3a,0x7f,0xa1,0x34,0x80,0x57
1600 ,0xe2,0xf6,0x55,0x6a,0xd6,0xb1,0x31,0x8a
1601 ,0x02,0x4a,0x83,0x8f,0x21,0xaf,0x1f,0xde
1602 ,0x04,0x89,0x77,0xeb,0x48,0xf5,0x9f,0xfd
1603 ,0x49,0x24,0xca,0x1c,0x60,0x90,0x2e,0x52
1604 ,0xf0,0xa0,0x89,0xbc,0x76,0x89,0x70,0x40
1605 ,0xe0,0x82,0xf9,0x37,0x76,0x38,0x48,0x64
1606 ,0x5e,0x07,0x05
1609 ubyte[163] c;
1612 static immutable ubyte[] res = [
1613 0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5
1614 ,0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9
1615 ,0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73
1616 ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce
1617 ,0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4
1618 ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a
1619 ,0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b
1620 ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72
1621 ,0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2
1622 ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38
1623 ,0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a
1624 ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae
1625 ,0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea
1626 ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda
1627 ,0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde
1628 ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3
1629 ,0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6
1630 ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74
1631 ,0xe3,0x55,0xa5];
1632 /*crypto_box_curve25519xsalsa20poly1305*/crypto_box(c,m,nonce,bobpk,alicesk);
1633 for (auto f = 16; f < 163; ++f) assert(c[f] == res[f-16]);
1635 box();
1637 void box2 () {
1638 writeln("box2");
1639 static immutable ubyte[32] bobsk = [
1640 0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b
1641 ,0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6
1642 ,0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd
1643 ,0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb
1646 static immutable ubyte[32] alicepk = [
1647 0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54
1648 ,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a
1649 ,0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4
1650 ,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a
1653 static immutable ubyte[24] nonce = [
1654 0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
1655 ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
1656 ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37
1659 // API requires first 16 bytes to be 0
1660 static immutable ubyte[163] c = [
1661 0, 0, 0, 0, 0, 0, 0, 0
1662 , 0, 0, 0, 0, 0, 0, 0, 0
1663 ,0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5
1664 ,0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9
1665 ,0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73
1666 ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce
1667 ,0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4
1668 ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a
1669 ,0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b
1670 ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72
1671 ,0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2
1672 ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38
1673 ,0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a
1674 ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae
1675 ,0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea
1676 ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda
1677 ,0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde
1678 ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3
1679 ,0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6
1680 ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74
1681 ,0xe3,0x55,0xa5
1684 ubyte m[163];
1686 static immutable ubyte[] res = [
1687 0xbe,0x07,0x5f,0xc5,0x3c,0x81,0xf2,0xd5
1688 ,0xcf,0x14,0x13,0x16,0xeb,0xeb,0x0c,0x7b
1689 ,0x52,0x28,0xc5,0x2a,0x4c,0x62,0xcb,0xd4
1690 ,0x4b,0x66,0x84,0x9b,0x64,0x24,0x4f,0xfc
1691 ,0xe5,0xec,0xba,0xaf,0x33,0xbd,0x75,0x1a
1692 ,0x1a,0xc7,0x28,0xd4,0x5e,0x6c,0x61,0x29
1693 ,0x6c,0xdc,0x3c,0x01,0x23,0x35,0x61,0xf4
1694 ,0x1d,0xb6,0x6c,0xce,0x31,0x4a,0xdb,0x31
1695 ,0x0e,0x3b,0xe8,0x25,0x0c,0x46,0xf0,0x6d
1696 ,0xce,0xea,0x3a,0x7f,0xa1,0x34,0x80,0x57
1697 ,0xe2,0xf6,0x55,0x6a,0xd6,0xb1,0x31,0x8a
1698 ,0x02,0x4a,0x83,0x8f,0x21,0xaf,0x1f,0xde
1699 ,0x04,0x89,0x77,0xeb,0x48,0xf5,0x9f,0xfd
1700 ,0x49,0x24,0xca,0x1c,0x60,0x90,0x2e,0x52
1701 ,0xf0,0xa0,0x89,0xbc,0x76,0x89,0x70,0x40
1702 ,0xe0,0x82,0xf9,0x37,0x76,0x38,0x48,0x64
1703 ,0x5e,0x07,0x05
1706 assert(/*crypto_box_curve25519xsalsa20poly1305_open*/crypto_box_open(m,c,nonce,alicepk,bobsk));
1707 for (auto f = 32; f < 163; ++f) assert(m[f] == res[f-32]);
1709 box2();
1711 void box7 () {
1712 writeln("box7");
1713 ubyte[crypto_box_SECRETKEYBYTES] alicesk;
1714 ubyte[crypto_box_PUBLICKEYBYTES] alicepk;
1715 ubyte[crypto_box_SECRETKEYBYTES] bobsk;
1716 ubyte[crypto_box_PUBLICKEYBYTES] bobpk;
1717 ubyte[crypto_box_NONCEBYTES] n;
1718 ubyte[10000] m, c, m2;
1719 for (auto mlen = 0; mlen < 1000 && mlen+crypto_box_ZEROBYTES < m.length; ++mlen) {
1720 crypto_box_keypair(alicepk,alicesk);
1721 crypto_box_keypair(bobpk,bobsk);
1722 randombytes(n,crypto_box_NONCEBYTES);
1723 randombytes(m[crypto_box_ZEROBYTES..$],mlen);
1724 crypto_box(c[0..mlen+crypto_box_ZEROBYTES],m,n,bobpk,alicesk);
1725 assert(crypto_box_open(m2[0..mlen+crypto_box_ZEROBYTES],c,n,alicepk,bobsk));
1726 for (auto i = 0; i < mlen+crypto_box_ZEROBYTES; ++i) assert(m2[i] == m[i]);
1729 version(unittest_full) box7(); // it's slow
1731 void box8 () {
1732 writeln("box8");
1733 ubyte[crypto_box_SECRETKEYBYTES] alicesk;
1734 ubyte[crypto_box_PUBLICKEYBYTES] alicepk;
1735 ubyte[crypto_box_SECRETKEYBYTES] bobsk;
1736 ubyte[crypto_box_PUBLICKEYBYTES] bobpk;
1737 ubyte[crypto_box_NONCEBYTES] n;
1738 ubyte[10000] m, c, m2;
1739 for (auto mlen = 0; mlen < 1000 && mlen+crypto_box_ZEROBYTES < m.length; ++mlen) {
1740 crypto_box_keypair(alicepk,alicesk);
1741 crypto_box_keypair(bobpk,bobsk);
1742 randombytes(n,crypto_box_NONCEBYTES);
1743 randombytes(m[crypto_box_ZEROBYTES..$],mlen);
1744 crypto_box(c[0..mlen+crypto_box_ZEROBYTES],m,n,bobpk,alicesk);
1745 int caught = 0;
1746 while (caught < 10) {
1747 c[uniform(0, mlen+crypto_box_ZEROBYTES)] = cast(ubyte)uniform(0, 256);
1748 if (crypto_box_open(m2[0..mlen+crypto_box_ZEROBYTES],c,n,alicepk,bobsk)) {
1749 for (auto i = 0; i < mlen+crypto_box_ZEROBYTES; ++i) assert(m2[i] == m[i]);
1750 } else {
1751 ++caught;
1754 assert(caught == 10);
1757 version(unittest_full) box8(); // it's slow
1759 void core1 () {
1760 writeln("core1");
1761 static immutable ubyte[32] shared_ = [
1762 0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1
1763 ,0x72,0x8e,0x3b,0xf4,0x80,0x35,0x0f,0x25
1764 ,0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33
1765 ,0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42
1768 static immutable ubyte[32] zero = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
1770 static immutable ubyte[16] c = [
1771 0x65,0x78,0x70,0x61,0x6e,0x64,0x20,0x33
1772 ,0x32,0x2d,0x62,0x79,0x74,0x65,0x20,0x6b
1775 ubyte[32] firstkey;
1777 static immutable ubyte[32] res = [
1778 0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
1779 ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
1780 ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
1781 ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89
1784 crypto_core_hsalsa20(firstkey,zero,shared_,c);
1785 assert(firstkey == res);
1787 core1();
1789 void core2 () {
1790 writeln("core2");
1791 static immutable ubyte[32]firstkey = [
1792 0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
1793 ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
1794 ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
1795 ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89
1798 static immutable ubyte[16]nonceprefix = [
1799 0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
1800 ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
1803 static immutable ubyte[16] c = [
1804 0x65,0x78,0x70,0x61,0x6e,0x64,0x20,0x33
1805 ,0x32,0x2d,0x62,0x79,0x74,0x65,0x20,0x6b
1808 ubyte[32] secondkey;
1810 static immutable ubyte[32] res = [
1811 0xdc,0x90,0x8d,0xda,0x0b,0x93,0x44,0xa9
1812 ,0x53,0x62,0x9b,0x73,0x38,0x20,0x77,0x88
1813 ,0x80,0xf3,0xce,0xb4,0x21,0xbb,0x61,0xb9
1814 ,0x1c,0xbd,0x4c,0x3e,0x66,0x25,0x6c,0xe4
1817 crypto_core_hsalsa20(secondkey,nonceprefix,firstkey,c);
1818 assert(secondkey == res);
1820 core2();
1822 void core3 () {
1823 writeln("core3");
1824 static immutable ubyte[32] secondkey = [
1825 0xdc,0x90,0x8d,0xda,0x0b,0x93,0x44,0xa9
1826 ,0x53,0x62,0x9b,0x73,0x38,0x20,0x77,0x88
1827 ,0x80,0xf3,0xce,0xb4,0x21,0xbb,0x61,0xb9
1828 ,0x1c,0xbd,0x4c,0x3e,0x66,0x25,0x6c,0xe4
1831 static immutable ubyte[8] noncesuffix = [
1832 0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37
1835 static immutable ubyte[16] c = [
1836 0x65,0x78,0x70,0x61,0x6e,0x64,0x20,0x33
1837 ,0x32,0x2d,0x62,0x79,0x74,0x65,0x20,0x6b
1840 static ubyte[16] input = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] ;
1842 static ubyte output[64*256*256];
1844 static ubyte[64] h;
1846 static immutable ubyte[64] res = [0x2b,0xd8,0xe7,0xdb,0x68,0x77,0x53,0x9e,0x4f,0x2b,0x29,0x5e,0xe4,0x15,0xcd,0x37,0x8a,0xe2,0x14,0xaa,0x3b,0xeb,0x3e,0x08,0xe9,0x11,0xa5,0xbd,0x4a,0x25,0xe6,0xac,0x16,0xca,0x28,0x3c,0x79,0xc3,0x4c,0x08,0xc9,0x9f,0x7b,0xdb,0x56,0x01,0x11,0xe8,0xca,0xc1,0xae,0x65,0xee,0xa0,0x8a,0xc3,0x84,0xd7,0xa5,0x91,0x46,0x1a,0xb6,0xe3];
1848 int pos = 0;
1849 for (auto i = 0; i < 8; ++i) input[i] = noncesuffix[i];
1850 do {
1851 do {
1852 crypto_core_salsa20(output[pos..$],input,secondkey,c);
1853 pos += 64;
1854 } while (++input[8]);
1855 } while (++input[9]);
1856 crypto_hash(h,output);
1857 assert(h == res);
1859 version(unittest_full) core3(); // it's slow
1861 void core4 () {
1862 writeln("core4");
1863 static immutable ubyte[32] k = [
1864 1, 2, 3, 4, 5, 6, 7, 8
1865 , 9, 10, 11, 12, 13, 14, 15, 16
1866 ,201,202,203,204,205,206,207,208
1867 ,209,210,211,212,213,214,215,216
1870 static immutable ubyte[16] input = [
1871 101,102,103,104,105,106,107,108
1872 ,109,110,111,112,113,114,115,116
1875 static immutable ubyte[16] c = [
1876 101,120,112, 97,110,100, 32, 51
1877 , 50, 45, 98,121,116,101, 32,107
1880 ubyte[64] output;
1882 static immutable ubyte[64] res = [
1883 69, 37, 68, 39, 41, 15,107,193
1884 ,255,139,122, 6,170,233,217, 98
1885 , 89,144,182,106, 21, 51,200, 65
1886 ,239, 49,222, 34,215,114, 40,126
1887 ,104,197, 7,225,197,153, 31, 2
1888 ,102, 78, 76,176, 84,245,246,184
1889 ,177,160,133,130, 6, 72,149,119
1890 ,192,195,132,236,234,103,246, 74
1893 crypto_core_salsa20(output,input,k,c);
1894 assert(output == res);
1896 core4();
1898 void core5 () {
1899 writeln("core5");
1900 static immutable ubyte[32] k = [
1901 0xee,0x30,0x4f,0xca,0x27,0x00,0x8d,0x8c
1902 ,0x12,0x6f,0x90,0x02,0x79,0x01,0xd8,0x0f
1903 ,0x7f,0x1d,0x8b,0x8d,0xc9,0x36,0xcf,0x3b
1904 ,0x9f,0x81,0x96,0x92,0x82,0x7e,0x57,0x77
1907 static immutable ubyte[16] input = [
1908 0x81,0x91,0x8e,0xf2,0xa5,0xe0,0xda,0x9b
1909 ,0x3e,0x90,0x60,0x52,0x1e,0x4b,0xb3,0x52
1912 static immutable ubyte[16] c = [
1913 101,120,112, 97,110,100, 32, 51
1914 , 50, 45, 98,121,116,101, 32,107
1917 ubyte output[32];
1919 static immutable ubyte[32] res = [
1920 0xbc,0x1b,0x30,0xfc,0x07,0x2c,0xc1,0x40
1921 ,0x75,0xe4,0xba,0xa7,0x31,0xb5,0xa8,0x45
1922 ,0xea,0x9b,0x11,0xe9,0xa5,0x19,0x1f,0x94
1923 ,0xe1,0x8c,0xba,0x8f,0xd8,0x21,0xa7,0xcd
1926 crypto_core_hsalsa20(output,input,k,c);
1927 assert(output == res);
1929 core5();
1931 void core6 () {
1932 writeln("core6");
1933 static immutable ubyte[32] k = [
1934 0xee,0x30,0x4f,0xca,0x27,0x00,0x8d,0x8c
1935 ,0x12,0x6f,0x90,0x02,0x79,0x01,0xd8,0x0f
1936 ,0x7f,0x1d,0x8b,0x8d,0xc9,0x36,0xcf,0x3b
1937 ,0x9f,0x81,0x96,0x92,0x82,0x7e,0x57,0x77
1940 static immutable ubyte[16] input = [
1941 0x81,0x91,0x8e,0xf2,0xa5,0xe0,0xda,0x9b
1942 ,0x3e,0x90,0x60,0x52,0x1e,0x4b,0xb3,0x52
1945 static immutable ubyte[16] c = [
1946 101,120,112, 97,110,100, 32, 51
1947 , 50, 45, 98,121,116,101, 32,107
1950 ubyte output[64];
1952 static immutable ubyte[32] res = [
1953 0xbc,0x1b,0x30,0xfc,0x07,0x2c,0xc1,0x40
1954 ,0x75,0xe4,0xba,0xa7,0x31,0xb5,0xa8,0x45
1955 ,0xea,0x9b,0x11,0xe9,0xa5,0x19,0x1f,0x94
1956 ,0xe1,0x8c,0xba,0x8f,0xd8,0x21,0xa7,0xcd
1959 ubyte[32] pp;
1960 uint pppos = 0;
1962 void print(const(ubyte)[] x, const(ubyte)[] y)
1964 uint borrow = 0;
1965 for (auto i = 0; i < 4; ++i) {
1966 uint xi = x[i];
1967 uint yi = y[i];
1968 //printf(",0x%02x",255&(xi-yi-borrow));
1969 pp[pppos++] = cast(ubyte)(255&(xi-yi-borrow));
1970 borrow = (xi < yi+borrow);
1974 crypto_core_salsa20(output,input,k,c);
1975 print(output,c);
1976 print(output[20..$],c[4..$]);
1977 print(output[40..$],c[8..$]);
1978 print(output[60..$],c[12..$]);
1979 print(output[24..$],input);
1980 print(output[28..$],input[4..$]);
1981 print(output[32..$],input[8..$]);
1982 print(output[36..$],input[12..$]);
1983 assert(pp == res);
1985 core6();
1987 void hash () {
1988 writeln("hash");
1989 static immutable ubyte x[8] = ['t','e','s','t','i','n','g','\n'];
1990 static ubyte[crypto_hash_BYTES] h;
1991 static immutable ubyte[crypto_hash_BYTES] res = [0x24,0xf9,0x50,0xaa,0xc7,0xb9,0xea,0x9b,0x3c,0xb7,0x28,0x22,0x8a,0x0c,0x82,0xb6,0x7c,0x39,0xe9,0x6b,0x4b,0x34,0x47,0x98,0x87,0x0d,0x5d,0xae,0xe9,0x3e,0x3a,0xe5,0x93,0x1b,0xaa,0xe8,0xc7,0xca,0xcf,0xea,0x4b,0x62,0x94,0x52,0xc3,0x80,0x26,0xa8,0x1d,0x13,0x8b,0xc7,0xaa,0xd1,0xaf,0x3e,0xf7,0xbf,0xd5,0xec,0x64,0x6d,0x6c,0x28];
1992 crypto_hash(h,x);
1993 //for (auto f = 0; f < crypto_hash_BYTES; ++f) assert(h[f] == res[f]);
1994 assert(h == res);
1996 hash();
1998 void onetimeauth () {
1999 writeln("onetimeauth");
2000 static immutable ubyte rs[32] = [
2001 0xee,0xa6,0xa7,0x25,0x1c,0x1e,0x72,0x91
2002 ,0x6d,0x11,0xc2,0xcb,0x21,0x4d,0x3c,0x25
2003 ,0x25,0x39,0x12,0x1d,0x8e,0x23,0x4e,0x65
2004 ,0x2d,0x65,0x1f,0xa4,0xc8,0xcf,0xf8,0x80
2007 static immutable ubyte c[131] = [
2008 0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73
2009 ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce
2010 ,0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4
2011 ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a
2012 ,0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b
2013 ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72
2014 ,0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2
2015 ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38
2016 ,0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a
2017 ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae
2018 ,0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea
2019 ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda
2020 ,0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde
2021 ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3
2022 ,0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6
2023 ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74
2024 ,0xe3,0x55,0xa5
2027 ubyte a[16];
2029 static immutable ubyte[16] res = [0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5,0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9];
2031 /*crypto_onetimeauth_poly1305*/crypto_onetimeauth(a,c,rs);
2032 assert(a == res);
2034 onetimeauth();
2036 void onetimeauth2 () {
2037 writeln("onetimeauth2");
2038 static immutable ubyte[32] rs = [
2039 0xee,0xa6,0xa7,0x25,0x1c,0x1e,0x72,0x91
2040 ,0x6d,0x11,0xc2,0xcb,0x21,0x4d,0x3c,0x25
2041 ,0x25,0x39,0x12,0x1d,0x8e,0x23,0x4e,0x65
2042 ,0x2d,0x65,0x1f,0xa4,0xc8,0xcf,0xf8,0x80
2045 static immutable ubyte[131] c = [
2046 0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73
2047 ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce
2048 ,0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4
2049 ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a
2050 ,0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b
2051 ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72
2052 ,0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2
2053 ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38
2054 ,0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a
2055 ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae
2056 ,0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea
2057 ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda
2058 ,0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde
2059 ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3
2060 ,0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6
2061 ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74
2062 ,0xe3,0x55,0xa5
2065 static immutable ubyte[16] a = [
2066 0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5
2067 ,0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9
2070 assert(/*crypto_onetimeauth_poly1305_verify*/crypto_onetimeauth_verify(a,c,rs));
2072 onetimeauth2();
2074 void onetimeauth7 () {
2075 writeln("onetimeauth7");
2076 static ubyte[32] key;
2077 static ubyte[10000] c;
2078 static ubyte[16] a;
2080 for (auto clen = 0; clen < 10000; ++clen) {
2081 //if (clen%512 == 0) { writef("\r%s", clen); stdout.flush(); }
2082 randombytes(key, key.length);
2083 randombytes(c, clen);
2084 crypto_onetimeauth(a,c[0..clen],key);
2085 assert(crypto_onetimeauth_verify(a,c[0..clen],key));
2086 if (clen > 0) {
2087 c[uniform(0, clen)] += 1+(uniform(0, 255));
2088 assert(!crypto_onetimeauth_verify(a,c[0..clen],key));
2089 a[uniform(0, a.length)] += 1+(uniform(0, 255));
2090 assert(!crypto_onetimeauth_verify(a,c[0..clen],key));
2094 version(unittest_full) onetimeauth7(); // it's slow
2096 void scalarmult () {
2097 writeln("scalarmult");
2098 static immutable ubyte[32] alicesk = [
2099 0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d
2100 ,0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45
2101 ,0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a
2102 ,0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a
2105 ubyte[32] alicepk;
2107 static immutable ubyte[32] res = [
2108 0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54
2109 ,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a
2110 ,0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4
2111 ,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a
2114 /*crypto_scalarmult_curve25519_base*/crypto_scalarmult_base(alicepk,alicesk);
2115 assert(alicepk == res);
2117 scalarmult();
2119 void scalarmult2 () {
2120 writeln("scalarmult2");
2121 static immutable ubyte[32] bobsk = [
2122 0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b
2123 ,0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6
2124 ,0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd
2125 ,0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb
2128 ubyte[32] bobpk;
2130 static immutable ubyte[32] res = [
2131 0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4
2132 ,0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37
2133 ,0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d
2134 ,0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f
2137 /*crypto_scalarmult_curve25519_base*/crypto_scalarmult_base(bobpk,bobsk);
2138 assert(bobpk == res);
2140 scalarmult2();
2142 void scalarmult5 () {
2143 writeln("scalarmult5");
2144 static immutable ubyte[32] alicesk = [
2145 0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d
2146 ,0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45
2147 ,0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a
2148 ,0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a
2151 static immutable ubyte[32] bobpk = [
2152 0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4
2153 ,0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37
2154 ,0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d
2155 ,0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f
2158 ubyte[32] k;
2160 static immutable ubyte[32] res = [
2161 0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1
2162 ,0x72,0x8e,0x3b,0xf4,0x80,0x35,0x0f,0x25
2163 ,0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33
2164 ,0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42
2167 crypto_scalarmult(k,alicesk,bobpk);
2168 assert(k == res);
2170 scalarmult5();
2172 void scalarmult6 () {
2173 writeln("scalarmult6");
2174 static immutable ubyte[32] bobsk = [
2175 0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b
2176 ,0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6
2177 ,0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd
2178 ,0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb
2181 static immutable ubyte[32] alicepk = [
2182 0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54
2183 ,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a
2184 ,0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4
2185 ,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a
2188 ubyte[32] k;
2190 static immutable ubyte[32] res = [
2191 0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1
2192 ,0x72,0x8e,0x3b,0xf4,0x80,0x35,0x0f,0x25
2193 ,0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33
2194 ,0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42
2197 crypto_scalarmult(k,bobsk,alicepk);
2198 assert(k == res);
2200 scalarmult6();
2202 void secretbox () {
2203 writeln("secretbox");
2204 static immutable ubyte[32] firstkey = [
2205 0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
2206 ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
2207 ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
2208 ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89
2211 static immutable ubyte[24] nonce = [
2212 0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
2213 ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
2214 ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37
2217 // API requires first 32 bytes to be 0
2218 static immutable ubyte[163] m = [
2219 0, 0, 0, 0, 0, 0, 0, 0
2220 , 0, 0, 0, 0, 0, 0, 0, 0
2221 , 0, 0, 0, 0, 0, 0, 0, 0
2222 , 0, 0, 0, 0, 0, 0, 0, 0
2223 ,0xbe,0x07,0x5f,0xc5,0x3c,0x81,0xf2,0xd5
2224 ,0xcf,0x14,0x13,0x16,0xeb,0xeb,0x0c,0x7b
2225 ,0x52,0x28,0xc5,0x2a,0x4c,0x62,0xcb,0xd4
2226 ,0x4b,0x66,0x84,0x9b,0x64,0x24,0x4f,0xfc
2227 ,0xe5,0xec,0xba,0xaf,0x33,0xbd,0x75,0x1a
2228 ,0x1a,0xc7,0x28,0xd4,0x5e,0x6c,0x61,0x29
2229 ,0x6c,0xdc,0x3c,0x01,0x23,0x35,0x61,0xf4
2230 ,0x1d,0xb6,0x6c,0xce,0x31,0x4a,0xdb,0x31
2231 ,0x0e,0x3b,0xe8,0x25,0x0c,0x46,0xf0,0x6d
2232 ,0xce,0xea,0x3a,0x7f,0xa1,0x34,0x80,0x57
2233 ,0xe2,0xf6,0x55,0x6a,0xd6,0xb1,0x31,0x8a
2234 ,0x02,0x4a,0x83,0x8f,0x21,0xaf,0x1f,0xde
2235 ,0x04,0x89,0x77,0xeb,0x48,0xf5,0x9f,0xfd
2236 ,0x49,0x24,0xca,0x1c,0x60,0x90,0x2e,0x52
2237 ,0xf0,0xa0,0x89,0xbc,0x76,0x89,0x70,0x40
2238 ,0xe0,0x82,0xf9,0x37,0x76,0x38,0x48,0x64
2239 ,0x5e,0x07,0x05
2242 static immutable ubyte[] res = [
2243 0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5
2244 ,0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9
2245 ,0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73
2246 ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce
2247 ,0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4
2248 ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a
2249 ,0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b
2250 ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72
2251 ,0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2
2252 ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38
2253 ,0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a
2254 ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae
2255 ,0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea
2256 ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda
2257 ,0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde
2258 ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3
2259 ,0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6
2260 ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74
2261 ,0xe3,0x55,0xa5
2264 ubyte c[163];
2265 crypto_secretbox(c,m,nonce,firstkey);
2266 for (auto i = 16; i < 163; ++i) assert(c[i] == res[i-16]);
2268 secretbox();
2270 void secretbox2 () {
2271 writeln("secretbox2");
2272 static immutable ubyte[32] firstkey = [
2273 0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
2274 ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
2275 ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
2276 ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89
2279 static immutable ubyte[24] nonce = [
2280 0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
2281 ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
2282 ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37
2285 // API requires first 16 bytes to be 0
2286 static immutable ubyte[163] c = [
2287 0, 0, 0, 0, 0, 0, 0, 0
2288 , 0, 0, 0, 0, 0, 0, 0, 0
2289 ,0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5
2290 ,0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9
2291 ,0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73
2292 ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce
2293 ,0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4
2294 ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a
2295 ,0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b
2296 ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72
2297 ,0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2
2298 ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38
2299 ,0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a
2300 ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae
2301 ,0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea
2302 ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda
2303 ,0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde
2304 ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3
2305 ,0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6
2306 ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74
2307 ,0xe3,0x55,0xa5
2310 static immutable ubyte[] res = [
2311 0xbe,0x07,0x5f,0xc5,0x3c,0x81,0xf2,0xd5
2312 ,0xcf,0x14,0x13,0x16,0xeb,0xeb,0x0c,0x7b
2313 ,0x52,0x28,0xc5,0x2a,0x4c,0x62,0xcb,0xd4
2314 ,0x4b,0x66,0x84,0x9b,0x64,0x24,0x4f,0xfc
2315 ,0xe5,0xec,0xba,0xaf,0x33,0xbd,0x75,0x1a
2316 ,0x1a,0xc7,0x28,0xd4,0x5e,0x6c,0x61,0x29
2317 ,0x6c,0xdc,0x3c,0x01,0x23,0x35,0x61,0xf4
2318 ,0x1d,0xb6,0x6c,0xce,0x31,0x4a,0xdb,0x31
2319 ,0x0e,0x3b,0xe8,0x25,0x0c,0x46,0xf0,0x6d
2320 ,0xce,0xea,0x3a,0x7f,0xa1,0x34,0x80,0x57
2321 ,0xe2,0xf6,0x55,0x6a,0xd6,0xb1,0x31,0x8a
2322 ,0x02,0x4a,0x83,0x8f,0x21,0xaf,0x1f,0xde
2323 ,0x04,0x89,0x77,0xeb,0x48,0xf5,0x9f,0xfd
2324 ,0x49,0x24,0xca,0x1c,0x60,0x90,0x2e,0x52
2325 ,0xf0,0xa0,0x89,0xbc,0x76,0x89,0x70,0x40
2326 ,0xe0,0x82,0xf9,0x37,0x76,0x38,0x48,0x64
2327 ,0x5e,0x07,0x05
2330 ubyte m[163];
2332 assert(crypto_secretbox_open(m,c,nonce,firstkey));
2333 for (auto i = 32; i < 163; ++i) assert(m[i] == res[i-32]);
2335 secretbox2();
2337 void secretbox7 () {
2338 writeln("secretbox7");
2339 static ubyte[crypto_secretbox_KEYBYTES] k;
2340 static ubyte[crypto_secretbox_NONCEBYTES] n;
2341 static ubyte[10000] m, c, m2;
2342 for (auto mlen = 0; mlen < 1000 && mlen+crypto_secretbox_ZEROBYTES < m.length; ++mlen) {
2343 randombytes(k,crypto_secretbox_KEYBYTES);
2344 randombytes(n,crypto_secretbox_NONCEBYTES);
2345 randombytes(m[crypto_secretbox_ZEROBYTES..$],mlen);
2346 crypto_secretbox(c[0..mlen+crypto_secretbox_ZEROBYTES],m,n,k);
2347 assert(crypto_secretbox_open(m2[0..mlen+crypto_secretbox_ZEROBYTES],c,n,k));
2348 for (auto i = 0; i < mlen+crypto_secretbox_ZEROBYTES; ++i) assert(m2[i] == m[i]);
2351 secretbox7();
2353 void secretbox8 () {
2354 writeln("secretbox8");
2355 static ubyte[crypto_secretbox_KEYBYTES] k;
2356 static ubyte[crypto_secretbox_NONCEBYTES] n;
2357 static ubyte[10000] m, c, m2;
2358 for (auto mlen = 0; mlen < 1000 && mlen+crypto_secretbox_ZEROBYTES < m.length; ++mlen) {
2359 randombytes(k,crypto_secretbox_KEYBYTES);
2360 randombytes(n,crypto_secretbox_NONCEBYTES);
2361 randombytes(m[crypto_secretbox_ZEROBYTES..$],mlen);
2362 crypto_secretbox(c[0..mlen+crypto_secretbox_ZEROBYTES],m,n,k);
2363 auto caught = 0;
2364 while (caught < 10) {
2365 c[uniform(0, mlen+crypto_secretbox_ZEROBYTES)] = cast(ubyte)uniform(0, 256);
2366 if (crypto_secretbox_open(m2[0..mlen+crypto_secretbox_ZEROBYTES],c,n,k)) {
2367 for (auto i = 0; i < mlen+crypto_secretbox_ZEROBYTES; ++i) assert(m2[i] == m[i]);
2369 ++caught;
2371 assert(caught == 10);
2374 version(unittest_full) secretbox8(); // it's slow
2376 void stream () {
2377 writeln("stream");
2378 static immutable ubyte[32] firstkey = [
2379 0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
2380 ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
2381 ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
2382 ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89
2385 static immutable ubyte[24] nonce = [
2386 0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
2387 ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
2388 ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37
2391 static ubyte[4194304] output;
2393 //ubyte h[32];
2394 //static immutable ubyte[32] res = [0x66,0x2b,0x9d,0x0e,0x34,0x63,0x02,0x91,0x56,0x06,0x9b,0x12,0xf9,0x18,0x69,0x1a,0x98,0xf7,0xdf,0xb2,0xca,0x03,0x93,0xc9,0x6b,0xbf,0xc6,0xb1,0xfb,0xd6,0x30,0xa2];
2396 crypto_stream(output,nonce,firstkey);
2397 //crypto_hash_sha256(h,output,sizeof output);
2398 assert(hashToString(SHA256(output[0..$])) == "662b9d0e3463029156069b12f918691a98f7dfb2ca0393c96bbfc6b1fbd630a2");
2400 stream();
2402 void stream2 () {
2403 writeln("stream2");
2404 static immutable ubyte[32] secondkey = [
2405 0xdc,0x90,0x8d,0xda,0x0b,0x93,0x44,0xa9
2406 ,0x53,0x62,0x9b,0x73,0x38,0x20,0x77,0x88
2407 ,0x80,0xf3,0xce,0xb4,0x21,0xbb,0x61,0xb9
2408 ,0x1c,0xbd,0x4c,0x3e,0x66,0x25,0x6c,0xe4
2411 static immutable ubyte[8] noncesuffix = [
2412 0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37
2415 static ubyte[4194304] output;
2417 crypto_stream_salsa20(output,noncesuffix,secondkey);
2418 assert(hashToString(SHA256(output[0..$])) == "662b9d0e3463029156069b12f918691a98f7dfb2ca0393c96bbfc6b1fbd630a2");
2420 stream2();
2422 void stream3 () {
2423 writeln("stream3");
2424 static immutable ubyte[32] firstkey = [
2425 0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
2426 ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
2427 ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
2428 ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89
2431 static immutable ubyte[24] nonce = [
2432 0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
2433 ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
2434 ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37
2437 ubyte rs[32];
2439 static immutable ubyte[32] res = [
2440 0xee,0xa6,0xa7,0x25,0x1c,0x1e,0x72,0x91
2441 ,0x6d,0x11,0xc2,0xcb,0x21,0x4d,0x3c,0x25
2442 ,0x25,0x39,0x12,0x1d,0x8e,0x23,0x4e,0x65
2443 ,0x2d,0x65,0x1f,0xa4,0xc8,0xcf,0xf8,0x80
2446 crypto_stream/*_xsalsa20*/(rs,nonce,firstkey);
2447 assert(rs == res);
2449 stream3();
2451 void stream4 () {
2452 writeln("stream4");
2453 static immutable ubyte[32] firstkey = [
2454 0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
2455 ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
2456 ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
2457 ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89
2460 static immutable ubyte[24] nonce = [
2461 0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
2462 ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
2463 ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37
2466 static immutable ubyte[163] m = [
2467 0, 0, 0, 0, 0, 0, 0, 0
2468 , 0, 0, 0, 0, 0, 0, 0, 0
2469 , 0, 0, 0, 0, 0, 0, 0, 0
2470 , 0, 0, 0, 0, 0, 0, 0, 0
2471 ,0xbe,0x07,0x5f,0xc5,0x3c,0x81,0xf2,0xd5
2472 ,0xcf,0x14,0x13,0x16,0xeb,0xeb,0x0c,0x7b
2473 ,0x52,0x28,0xc5,0x2a,0x4c,0x62,0xcb,0xd4
2474 ,0x4b,0x66,0x84,0x9b,0x64,0x24,0x4f,0xfc
2475 ,0xe5,0xec,0xba,0xaf,0x33,0xbd,0x75,0x1a
2476 ,0x1a,0xc7,0x28,0xd4,0x5e,0x6c,0x61,0x29
2477 ,0x6c,0xdc,0x3c,0x01,0x23,0x35,0x61,0xf4
2478 ,0x1d,0xb6,0x6c,0xce,0x31,0x4a,0xdb,0x31
2479 ,0x0e,0x3b,0xe8,0x25,0x0c,0x46,0xf0,0x6d
2480 ,0xce,0xea,0x3a,0x7f,0xa1,0x34,0x80,0x57
2481 ,0xe2,0xf6,0x55,0x6a,0xd6,0xb1,0x31,0x8a
2482 ,0x02,0x4a,0x83,0x8f,0x21,0xaf,0x1f,0xde
2483 ,0x04,0x89,0x77,0xeb,0x48,0xf5,0x9f,0xfd
2484 ,0x49,0x24,0xca,0x1c,0x60,0x90,0x2e,0x52
2485 ,0xf0,0xa0,0x89,0xbc,0x76,0x89,0x70,0x40
2486 ,0xe0,0x82,0xf9,0x37,0x76,0x38,0x48,0x64
2487 ,0x5e,0x07,0x05
2490 ubyte c[163];
2492 static immutable ubyte[] res = [
2493 0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73
2494 ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce
2495 ,0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4
2496 ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a
2497 ,0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b
2498 ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72
2499 ,0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2
2500 ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38
2501 ,0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a
2502 ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae
2503 ,0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea
2504 ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda
2505 ,0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde
2506 ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3
2507 ,0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6
2508 ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74
2509 ,0xe3,0x55,0xa5
2512 /*crypto_stream_xsalsa20_xor*/crypto_stream_xor(c,m,nonce,firstkey);
2513 for (auto i = 32; i < 163; ++i) assert(c[i] == res[i-32]);
2515 stream4();
2517 version(unittest) {
2518 version(unittest_main) {
2519 void main () {}