1 /// Computes BLAKE2b and BLAKE2s hashes of arbitary data.
2 /// Reference: IETF RFC 7693
3 /// License: $(LINK2 www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
4 /// Authors: $(LINK2 github.com/dd86k, dd86k)
5 module blake2d;
6 
7 private import std.digest;
8 private import core.bitop : ror, bswap;
9 
10 // "For BLAKE2b, the two extra permutations for rounds 10 and 11 are
11 // SIGMA[10..11] = SIGMA[0..1]."
12 private immutable ubyte[16][12] SIGMA = [
13     [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, ],
14     [ 14, 10, 4,  8,  9,  15, 13, 6,  1,  12, 0,  2,  11, 7,  5,  3,  ],
15     [ 11, 8,  12, 0,  5,  2,  15, 13, 10, 14, 3,  6,  7,  1,  9,  4,  ],
16     [ 7,  9,  3,  1,  13, 12, 11, 14, 2,  6,  5,  10, 4,  0,  15, 8,  ],
17     [ 9,  0,  5,  7,  2,  4,  10, 15, 14, 1,  11, 12, 6,  8,  3,  13, ],
18     [ 2,  12, 6,  10, 0,  11, 8,  3,  4,  13, 7,  5,  15, 14, 1,  9,  ],
19     [ 12, 5,  1,  15, 14, 13, 4,  10, 0,  7,  6,  3,  9,  2,  8,  11, ],
20     [ 13, 11, 7,  14, 12, 1,  3,  9,  5,  0,  15, 4,  8,  6,  2,  10, ],
21     [ 6,  15, 14, 9,  11, 3,  0,  8,  12, 2,  13, 7,  1,  4,  10, 5,  ],
22     [ 10, 2,  8,  4,  7,  6,  1,  5,  15, 11, 9,  14, 3,  12, 13, 0,  ],
23     [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, ],
24     [ 14, 10, 4,  8,  9,  15, 13, 6,  1,  12, 0,  2,  11, 7,  5,  3,  ],
25 ];
26 
27 private
28 immutable ulong[8] B2B_IV = [
29     0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
30     0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
31     0x510e527fade682d1, 0x9b05688c2b3e6c1f,
32     0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
33 ];
34 
35 private
36 immutable uint[8] B2S_IV = [
37     0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
38     0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
39 ];
40 
41 /// Used with the BLAKE2 structure template to make the BLAKE2s and BLAKE2p
42 /// aliases.
43 enum BLAKE2Variant {
44     b,  /// BLAKE2b (default)
45     s,  /// BLAKE2s
46 }
47 
48 /// BLAKE2 structure template.
49 ///
50 /// It is recommended to use the BLAKE2p512 and BLAKE2s256 aliases.
51 /// However, if you wish to use a custom digest size, this is the structure
52 /// to use.
53 ///
54 /// Example definitions for BLAKE2s-160:
55 /// ---
56 /// alias BLAKE2s160 = BLAKE2!(BLAKE2Variant.s, 160);
57 /// auto blake2s160_Of(T...)(T data) { return digest!(BLAKE2s160, T)(data); }
58 /// public alias BLAKE2s160Digest = WrapperDigest!BLAKE2s160;
59 /// ---
60 /// Params:
61 ///   var = BLAKE2 hash variation.
62 ///   digestSize = Digest size in bits.
63 //   key = HMAC key. This is a temporary hack to allow HMAC usage.
64 struct BLAKE2(BLAKE2Variant var, uint digestSize/*, const(ubyte)[] key = null*/)
65 {
66     @safe:
67     @nogc:
68     nothrow:
69     pure:
70     
71     static assert(digestSize > 0,
72         "Digest size must be non-zero.");
73     static assert(digestSize % 8 == 0,
74         "Digest size must be dividable by 8.");
75     
76     static if (var == BLAKE2Variant.b) { // BLAKE2b
77         // 8 to 512 bits
78         static assert(digestSize >= 8 && digestSize <= 512,
79             "BLAKE2b digest size must be between 8 and 512 bits.");
80         
81         private enum MAXED = digestSize == 512;
82         private enum BSIZE = 128;   /// bb
83         private enum ROUNDS = 12;
84         private enum R1 = 32;
85         private enum R2 = 24;
86         private enum R3 = 16;
87         private enum R4 = 63;
88         alias IV = B2B_IV;
89         alias inner_t = ulong;
90     } else static if (var == BLAKE2Variant.s) { // BLAKE2s
91         // 8 to 256 bits
92         static assert(digestSize >= 8 && digestSize <= 256,
93             "BLAKE2s digest size must be between 8 and 256 bits.");
94         
95         private enum MAXED = digestSize == 256;
96         private enum BSIZE = 64;    /// bb
97         private enum ROUNDS = 10;
98         private enum R1 = 16;
99         private enum R2 = 12;
100         private enum R3 = 8;
101         private enum R4 = 7;
102         alias IV = B2S_IV;
103         alias inner_t = uint;
104     } else static assert(0, "Invalid BLAKE2 variant.");
105     
106     enum blockSize = digestSize;    /// Digest size in bits
107     
108     /// Initiate or reset the state of the structure.
109     void start()
110     {
111         this = typeof(this).init;
112     }
113     
114     /// Feed the algorithm with data.
115     /// Also implements the $(REF isOutputRange, std,range,primitives)
116     /// interface for `ubyte` and `const(ubyte)[]`.
117     /// Params: input = Input data to digest
118     void put(scope const(ubyte)[] input...) @trusted
119     {
120         version (BLAKE2Trace) writefln("put() len=%u", input.length);
121         
122         // Process wordwise if properly aligned.
123         if ((c | cast(size_t) input.ptr) % size_t.alignof == 0)
124         {
125             foreach (const word; (cast(size_t*) input.ptr)[0 .. input.length / size_t.sizeof])
126             {
127                 if (c >= BSIZE)
128                 {
129                     t[0] += c;
130                     if (t[0] < c) ++t[1]; // Overflow
131                     compress();
132                     c = 0;
133                 }
134                 mz.ptr[c / size_t.sizeof] = word;
135                 c += size_t.sizeof;
136             }
137             input = input.ptr[input.length - (input.length % size_t.sizeof) .. input.length];
138         }
139         
140         // Process remainder bytewise.
141         foreach (const i; input)
142         {
143             if (c >= BSIZE)
144             {
145                 t[0] += c;
146                 if (t[0] < c) ++t[1]; // Overflow
147                 compress();
148                 c = 0;
149             }
150             m8[c++] = i;
151         }
152     }
153     
154     /// Returns the finished hash.
155     /// Returns: Raw digest data.
156     ubyte[digestSizeBytes] finish()
157     {
158         // final counter update
159         t[0] += c;
160         if (t[0] < c) ++t[1];
161         
162         // 0-pad message buffer
163         m8[c..$] = 0;
164         last = 1;
165         compress();
166         
167         // Clear out possible sensitive data
168         t[0] = t[1] = c = 0; // clear size information
169         mz[] = 0; // clear input message buffer
170         // Only clear remaining of state if digest not at maximum.
171         // e.g., BLAKE2b-512 has a digest size of 64 bytes
172         //       ulong[8] (8*8) is 64 bytes of state
173         //       So is BLAKE2x-256 is used, a digest of 32 bytes
174         //       state (h) will still be 64 bytes, so upper range is cleared
175         static if (MAXED == false)
176             h8[digestSizeBytes..$] = 0; // clear unused state space
177         
178         return h8[0..digestSizeBytes];
179     }
180     
181 private:
182 
183     /*static if (key)
184     {
185         enum KEYLEN = key.length;
186     }
187     else
188         enum KEYLEN = 0;*/
189     
190     public ubyte[32] key;
191     
192     enum digestSizeBytes = digestSize / 8;
193     //           3 2 1 0
194     // p[0] = 0x0101kknn
195     // kk - Key size. Set to zero since HMAC is done elsewhere.
196     // nn - Digest size in bytes.
197     enum p0 = 0x0101_0000 ^ (0 << 8) ^ digestSizeBytes;
198     enum msz = 16 * inner_t.sizeof; /// message size in bytes
199     enum hsz = 8 * inner_t.sizeof;  /// state size in bytes
200     
201     static assert(msz == BSIZE); // e.g. 128 for b2b and 64 for b2s
202     static assert(hsz == BSIZE / 2); // e.g., 64 for b2b and 32 for b2s
203     
204     union // input message buffer
205     {
206         size_t[BSIZE / size_t.sizeof] mz = void;
207         inner_t[16] m;   /// Message
208         ubyte[16 * inner_t.sizeof] m8; /// Message in byte-size
209     }
210     union // state
211     {
212         struct // .init hack since start() can't cover this
213         {
214             inner_t h0 = IV[0] ^ p0;
215             inner_t h1 = IV[1];
216             inner_t h2 = IV[2];
217             inner_t h3 = IV[3];
218             inner_t h4 = IV[4];
219             inner_t h5 = IV[5];
220             inner_t h6 = IV[6];
221             inner_t h7 = IV[7];
222         }
223         inner_t[8] h;   /// State
224         ubyte[8 * inner_t.sizeof] h8;   /// State in byte-size
225     }
226     inner_t[2] t;  /// Total count of input size
227     size_t c;      /// Counter, pointer for buffer
228     uint last;     /// If set, this is the last block to compress.
229     
230     void compress()
231     {
232         //TODO: bswap m on BigEndian platforms?
233         
234         inner_t[16] v = void;
235         v[0]  = h[0];
236         v[1]  = h[1];
237         v[2]  = h[2];
238         v[3]  = h[3];
239         v[4]  = h[4];
240         v[5]  = h[5];
241         v[6]  = h[6];
242         v[7]  = h[7];
243         v[8]  = IV[0];
244         v[9]  = IV[1];
245         v[10] = IV[2];
246         v[11] = IV[3];
247         v[12] = t[0] ^ IV[4];
248         v[13] = t[1] ^ IV[5];
249         v[14] = last ? ~IV[6] : IV[6];
250         v[15] = IV[7];
251         
252         // See i=0 v[16]
253         
254         for (size_t round; round < ROUNDS; ++round)
255         {
256             //   a  b   c   d  x                      y
257             G(v, 0, 4,  8, 12, m[SIGMA[round][ 0]], m[SIGMA[round][ 1]]);
258             G(v, 1, 5,  9, 13, m[SIGMA[round][ 2]], m[SIGMA[round][ 3]]);
259             G(v, 2, 6, 10, 14, m[SIGMA[round][ 4]], m[SIGMA[round][ 5]]);
260             G(v, 3, 7, 11, 15, m[SIGMA[round][ 6]], m[SIGMA[round][ 7]]);
261             G(v, 0, 5, 10, 15, m[SIGMA[round][ 8]], m[SIGMA[round][ 9]]);
262             G(v, 1, 6, 11, 12, m[SIGMA[round][10]], m[SIGMA[round][11]]);
263             G(v, 2, 7,  8, 13, m[SIGMA[round][12]], m[SIGMA[round][13]]);
264             G(v, 3, 4,  9, 14, m[SIGMA[round][14]], m[SIGMA[round][15]]);
265             
266             // See i=1..i=10/12 v[16]
267         }
268         
269         h[0] ^= v[0] ^ v[8];
270         h[1] ^= v[1] ^ v[9];
271         h[2] ^= v[2] ^ v[10];
272         h[3] ^= v[3] ^ v[11];
273         h[4] ^= v[4] ^ v[12];
274         h[5] ^= v[5] ^ v[13];
275         h[6] ^= v[6] ^ v[14];
276         h[7] ^= v[7] ^ v[15];
277         
278         // See h[8]
279     }
280     
281     static void G(ref inner_t[16] v, uint a, uint b, uint c, uint d, inner_t x, inner_t y)
282     {
283         v[a] = v[a] + v[b] + x;
284         v[d] = ror(v[d] ^ v[a], R1);
285         v[c] = v[c] + v[d];
286         v[b] = ror(v[b] ^ v[c], R2);
287         v[a] = v[a] + v[b] + y;
288         v[d] = ror(v[d] ^ v[a], R3);
289         v[c] = v[c] + v[d];
290         v[b] = ror(v[b] ^ v[c], R4);
291     }
292 }
293 
294 /// Alias for BLAKE2b-512
295 public alias BLAKE2b512 = BLAKE2!(BLAKE2Variant.b, 512);
296 /// Alias for BLAKE2s-256
297 public alias BLAKE2s256 = BLAKE2!(BLAKE2Variant.s, 256);
298 
299 /// Convience alias for $(REF digest, std,digest) using the BLAKE2b-512 implementation.
300 auto blake2b_Of(T...)(T data) { return digest!(BLAKE2b512, T)(data); }
301 /// Alias of blake2b_Of. 
302 alias blake2_Of = blake2b_Of;
303 /// Convience alias for $(REF digest, std,digest) using the BLAKE2s-256 implementation.
304 auto blake2s_Of(T...)(T data) { return digest!(BLAKE2s256, T)(data); }
305 
306 /// OOP API BLAKE2 implementation aliases.
307 public alias BLAKE2b512Digest = WrapperDigest!BLAKE2b512;
308 /// Ditto
309 public alias BLAKE2s256Digest = WrapperDigest!BLAKE2s256;
310 
311 /// Of course they correspond to the digest API!
312 @safe unittest
313 {
314     assert(isDigest!BLAKE2b512);
315     assert(isDigest!BLAKE2s256);
316 }
317 
318 /// Testing "Of" wrappers against digest wrappers.
319 @safe unittest
320 {
321     enum TEXT = "abc";
322     
323     ubyte[64] b2b = blake2b_Of(TEXT);
324     assert(b2b == digest!BLAKE2b512(TEXT));
325     
326     ubyte[32] b2s = blake2s_Of(TEXT);
327     assert(b2s == digest!BLAKE2s256(TEXT));
328 }
329 
330 /// Testing template API
331 @system unittest
332 {
333     import std.conv : hexString;
334     
335     ubyte[] s = [ 'a', 'b', 'c' ];
336     
337     BLAKE2s256 b2s;
338     b2s.put(s);
339     assert(b2s.finish() == cast(ubyte[])hexString!(
340         "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"));
341 }
342 
343 /// Test against empty input
344 @safe unittest
345 {
346     assert(toHexString!(LetterCase.lower)(blake2b_Of("")) ==
347         "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419"~
348         "d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce");
349     assert(toHexString!(LetterCase.lower)(blake2s_Of("")) ==
350         "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9");
351 }
352 
353 /// Test against "abc"
354 @safe unittest
355 {
356     assert(toHexString!(LetterCase.lower)(blake2b_Of("abc")) ==
357         "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1"~
358         "7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923");
359     assert(toHexString!(LetterCase.lower)(blake2s_Of("abc")) ==
360         "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982");
361 }
362 
363 
364 /// Testing template API against one million 'a'
365 @system unittest
366 {
367     import std.conv : hexString;
368     
369     ubyte[] onemilliona = new ubyte[1_000_000];
370     onemilliona[] = 'a';
371     
372     BLAKE2b512 b2b;
373     b2b.put(onemilliona);
374     assert(b2b.finish() == cast(ubyte[]) hexString!(
375         "98fb3efb7206fd19ebf69b6f312cf7b64e3b94dbe1a17107913975a793f177e1"~
376         "d077609d7fba363cbba00d05f7aa4e4fa8715d6428104c0a75643b0ff3fd3eaf"));
377     
378     BLAKE2s256 b2s;
379     b2s.put(onemilliona);
380     assert(b2s.finish() == cast(ubyte[]) hexString!(
381         "bec0c0e6cde5b67acb73b81f79a67a4079ae1c60dac9d2661af18e9f8b50dfa5"));
382 }
383 
384 /// Testing OOP API
385 @system unittest
386 {
387     import std.conv : hexString;
388     
389     ubyte[] s = ['a', 'b', 'c'];
390     
391     BLAKE2b512Digest b2b = new BLAKE2b512Digest();
392     b2b.put(s);
393     assert(b2b.finish() == cast(ubyte[]) hexString!(
394         "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1"~
395         "7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"));
396     
397     BLAKE2s256Digest b2s = new BLAKE2s256Digest();
398     b2s.put(s);
399     assert(b2s.finish() == cast(ubyte[]) hexString!(
400         "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"));
401 }
402 
403 /// BLAKE2s Template usage
404 @system unittest
405 {
406     import std.conv : hexString;
407     
408     // Let's use the template features:
409     // NOTE: When passing a digest to a function, it must be passed by reference!
410     void doSomething(T)(ref T hash)
411         if (isDigest!T)
412         {
413             hash.put([ 'a', 'b', 'c' ]);
414         }
415     BLAKE2b512 b2b;
416     b2b.start();
417     doSomething(b2b);
418     assert(b2b.finish() == cast(ubyte[]) hexString!(
419         "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1"~
420         "7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"));
421     BLAKE2s256 b2s;
422     b2s.start();
423     doSomething(b2s);
424     assert(b2s.finish() == cast(ubyte[]) hexString!(
425         "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"));
426 }
427 
428 /// Testing with HMAC
429 /*@system unittest
430 {
431     import std.ascii : LetterCase;
432     import std.digest.hmac : hmac;
433     import std.string : representation;
434     
435     auto secret = "secret".representation;
436     
437     // Temporary hack
438     //alias HMACBLAKE2b512 = BLAKE2!(BLAKE2Variant.b, 512, "secret".representation);
439     //alias HMACBLAKE2s256 = BLAKE2!(BLAKE2Variant.s, 256, "secret".representation);
440 
441     assert("The quick brown fox jumps over the lazy dog"
442         .representation
443         .hmac!BLAKE2b512(secret)
444         .toHexString!(LetterCase.lower) ==
445         "97504d0493aaaa40b08cf700fd380f17fe32e26e008fa20f9f3f04901d9f5bf3"~
446         "3e826ea234f93bedfe7c5c50a540ad61454eb011581194cd68bff57938760ae0");
447     assert("The quick brown fox jumps over the lazy dog"
448         .representation
449         .hmac!BLAKE2s256(secret)
450         .toHexString!(LetterCase.lower) ==
451         "e95b806f87e9477966cd5f0ca2d496bfdfa424c69e820d33e4f1007aeb6c9de1");
452 }*/