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