1 /// Computes SHA-3 hashes of arbitary data.
2 /// Reference: NIST FIPS PUB 202
3 /// License: $(LINK2 www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
4 /// Authors: $(LINK2 github.com/dd86k, dd86k)
5 module sha3d;
6 
7 private import std.digest;
8 private import core.bitop : rol, bswap;
9 
10 private immutable ulong[24] K_RC = [
11     0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000,
12     0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
13     0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
14     0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003,
15     0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,
16     0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008
17 ];
18 private immutable int[24] K_ROTC = [
19      1,  3,  6, 10, 15, 21, 28, 36, 45, 55,  2, 14,
20     27, 41, 56,  8, 25, 43, 62, 18, 39, 61, 20, 44
21 ];
22 private immutable int[24] K_PI = [
23     10,  7, 11, 17, 18, 3,  5, 16,  8, 21, 24, 4,
24     15, 23, 19, 13, 12, 2, 20, 14, 22,  9,  6, 1
25 ];
26 
27 /// Template API SHA-3/SHAKE implementation using the Keccak[1600] function.
28 ///
29 /// Supports SHA-3-224, SHA-3-256, SHA-3-384, SHA-3-512, SHAKE-128, and SHAKE-256.
30 /// It is recommended to use the SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHAKE128,
31 /// and SHAKE256 aliases.
32 /// Params:
33 ///   digestSize = Digest size in bits
34 ///   shake = Set to true for SHAKE; Otherwise false for SHA-3
35 public struct KECCAK(uint digestSize, bool shake = false)
36 {
37     static if (shake)
38         static assert(digestSize == 128 || digestSize == 256,
39             "digest size must be 128 or 256 bits for SHAKE");
40     else
41         static assert(digestSize == 224 || digestSize == 256 ||
42             digestSize == 384 || digestSize == 512,
43             "digest size must be 224, 256, 384, or 512 bits for SHA-3");
44 
45     @safe @nogc pure nothrow:
46 
47     enum blockSize = 1600 - digestSize * 2; /// Sponge rate in bits
48     
49     private enum
50     {
51         digestSizeBytes = digestSize / 8, /// Digest size in bytes
52         delim = shake ? 0x1f : 0x06, /// Delimiter when finishing
53         rate = blockSize / 8 /// Sponge rate in bytes
54     }
55 
56     union
57     {
58         private ubyte[200] st;  // state (8bit)
59         private ulong[25] st64; // state (64bit)
60         private size_t[200 / size_t.sizeof] stz; // state (size_t)
61     }
62 
63     static assert(st64.sizeof == st.sizeof);
64     static assert(stz.sizeof == st.sizeof);
65 
66     private size_t pt; // left-over pointer
67 
68     /// Initiates the structure. Begins the SHA-3/SHAKE operation.
69     /// This is better used when restarting the operation (e.g.,
70     /// for a file).
71     void start()
72     {
73         this = typeof(this).init;
74     }
75 
76     /// Feed the algorithm with data
77     /// Also implements the $(REF isOutputRange, std,range,primitives)
78     /// interface for `ubyte` and `const(ubyte)[]`.
79     /// Params: input = Input data to digest
80     void put(scope const(ubyte)[] input...) @trusted
81     {
82         size_t j = pt;
83         
84         // Process wordwise if properly aligned.
85         if ((j | cast(size_t) input.ptr) % size_t.alignof == 0)
86         {
87             static assert(rate % size_t.sizeof == 0);
88             foreach (const word; (cast(size_t*) input.ptr)[0 .. input.length / size_t.sizeof])
89             {
90                 stz.ptr[j / size_t.sizeof] ^= word;
91                 j += size_t.sizeof;
92                 if (j >= rate)
93                 {
94                     transform;
95                     j = 0;
96                 }
97             }
98             input = input.ptr[input.length - (input.length % size_t.sizeof) .. input.length];
99         }
100         
101         // Process remainder bytewise.
102         foreach (const b; input)
103         {
104             st.ptr[j++] ^= b;
105             if (j >= rate)
106             {
107                 transform;
108                 j = 0;
109             }
110         }
111         
112         pt = j;
113     }
114 
115     /// Returns the finished hash. This also clears part of the state,
116     /// leaving just the final digest.
117     ubyte[digestSizeBytes] finish()
118     {
119         st[pt] ^= delim;
120         st[rate - 1] ^= 0x80;
121         transform;
122 
123         st[digestSizeBytes .. $] = 0; // Zero possible sensitive data
124         return st[0 .. digestSizeBytes];
125     }
126 
127 private:
128     void transform()
129     {
130         ulong[5] bc = void;
131 
132         version (BigEndian) swap;
133 
134         ROUND(bc, st64,  0);
135         ROUND(bc, st64,  1);
136         ROUND(bc, st64,  2);
137         ROUND(bc, st64,  3);
138         ROUND(bc, st64,  4);
139         ROUND(bc, st64,  5);
140         ROUND(bc, st64,  6);
141         ROUND(bc, st64,  7);
142         ROUND(bc, st64,  8);
143         ROUND(bc, st64,  9);
144         ROUND(bc, st64, 10);
145         ROUND(bc, st64, 11);
146         ROUND(bc, st64, 12);
147         ROUND(bc, st64, 13);
148         ROUND(bc, st64, 14);
149         ROUND(bc, st64, 15);
150         ROUND(bc, st64, 16);
151         ROUND(bc, st64, 17);
152         ROUND(bc, st64, 18);
153         ROUND(bc, st64, 19);
154         ROUND(bc, st64, 20);
155         ROUND(bc, st64, 21);
156         ROUND(bc, st64, 22);
157         ROUND(bc, st64, 23);
158 
159         version (BigEndian) swap;
160     }
161 }
162 
163 private:
164 @safe:
165 pure:
166 nothrow:
167 
168 static void THETA1(ref ulong[5] bc, ref ulong[25] st64, size_t i) @nogc
169 {
170     bc[i] = st64[i] ^ st64[i + 5] ^ st64[i + 10] ^ st64[i + 15] ^ st64[i + 20];
171 }
172 
173 static void THETA2(ref ulong[5] bc, ref ulong[25] st64, ref ulong t, size_t i) @nogc
174 {
175     t = bc[(i + 4) % 5] ^ rol(bc[(i + 1) % 5], 1);
176     st64[     i] ^= t;
177     st64[ 5 + i] ^= t;
178     st64[10 + i] ^= t;
179     st64[15 + i] ^= t;
180     st64[20 + i] ^= t;
181 }
182 
183 static void RHO(ref ulong[5] bc, ref ulong[25] st64, ref ulong t, size_t i) @nogc
184 {
185     int j = K_PI[i];
186     bc[0] = st64[j];
187     st64[j] = rol(t, K_ROTC[i]);
188     t = bc[0];
189 }
190 
191 static void CHI(ref ulong[5] bc, ref ulong[25] st64, size_t j) @nogc
192 {
193     bc[0] = st64[j];
194     bc[1] = st64[j + 1];
195     bc[2] = st64[j + 2];
196     bc[3] = st64[j + 3];
197     bc[4] = st64[j + 4];
198 
199     st64[j]     ^= (~bc[1]) & bc[2];
200     st64[j + 1] ^= (~bc[2]) & bc[3];
201     st64[j + 2] ^= (~bc[3]) & bc[4];
202     st64[j + 3] ^= (~bc[4]) & bc[0];
203     st64[j + 4] ^= (~bc[0]) & bc[1];
204 }
205 
206 static void ROUND(ref ulong[5] bc, ref ulong[25] st64, size_t r) @nogc
207 {
208     ulong t = void;
209     // Theta
210     THETA1(bc, st64, 0);
211     THETA1(bc, st64, 1);
212     THETA1(bc, st64, 2);
213     THETA1(bc, st64, 3);
214     THETA1(bc, st64, 4);
215     THETA2(bc, st64, t, 0);
216     THETA2(bc, st64, t, 1);
217     THETA2(bc, st64, t, 2);
218     THETA2(bc, st64, t, 3);
219     THETA2(bc, st64, t, 4);
220     t = st64[1];
221     // Rho
222     RHO(bc, st64, t, 0);
223     RHO(bc, st64, t, 1);
224     RHO(bc, st64, t, 2);
225     RHO(bc, st64, t, 3);
226     RHO(bc, st64, t, 4);
227     RHO(bc, st64, t, 5);
228     RHO(bc, st64, t, 6);
229     RHO(bc, st64, t, 7);
230     RHO(bc, st64, t, 8);
231     RHO(bc, st64, t, 9);
232     RHO(bc, st64, t, 10);
233     RHO(bc, st64, t, 11);
234     RHO(bc, st64, t, 12);
235     RHO(bc, st64, t, 13);
236     RHO(bc, st64, t, 14);
237     RHO(bc, st64, t, 15);
238     RHO(bc, st64, t, 16);
239     RHO(bc, st64, t, 17);
240     RHO(bc, st64, t, 18);
241     RHO(bc, st64, t, 19);
242     RHO(bc, st64, t, 20);
243     RHO(bc, st64, t, 21);
244     RHO(bc, st64, t, 22);
245     RHO(bc, st64, t, 23);
246     // Chi
247     CHI(bc, st64, 0);
248     CHI(bc, st64, 5);
249     CHI(bc, st64, 10);
250     CHI(bc, st64, 15);
251     CHI(bc, st64, 20);
252     // Iota
253     st64[0] ^= K_RC[r];
254 }
255 
256 version (BigEndian)
257 void swap() @nogc
258 {
259     st64[ 0] = bswap(st64[ 0]);
260     st64[ 1] = bswap(st64[ 1]);
261     st64[ 2] = bswap(st64[ 2]);
262     st64[ 3] = bswap(st64[ 3]);
263     st64[ 4] = bswap(st64[ 4]);
264     st64[ 5] = bswap(st64[ 5]);
265     st64[ 6] = bswap(st64[ 6]);
266     st64[ 7] = bswap(st64[ 7]);
267     st64[ 8] = bswap(st64[ 8]);
268     st64[ 9] = bswap(st64[ 9]);
269     st64[10] = bswap(st64[10]);
270     st64[11] = bswap(st64[11]);
271     st64[12] = bswap(st64[12]);
272     st64[13] = bswap(st64[13]);
273     st64[14] = bswap(st64[14]);
274     st64[15] = bswap(st64[15]);
275     st64[16] = bswap(st64[16]);
276     st64[17] = bswap(st64[17]);
277     st64[18] = bswap(st64[18]);
278     st64[19] = bswap(st64[19]);
279     st64[20] = bswap(st64[20]);
280     st64[21] = bswap(st64[21]);
281     st64[22] = bswap(st64[22]);
282     st64[23] = bswap(st64[23]);
283 }
284 
285 /// Test against empty datasets
286 @safe unittest
287 {
288     assert(toHexString(sha3_224Of("")) ==
289         "6B4E03423667DBB73B6E15454F0EB1ABD4597F9A1B078E3F5B5A6BC7");
290 
291     assert(toHexString(sha3_256Of("")) ==
292         "A7FFC6F8BF1ED76651C14756A061D662F580FF4DE43B49FA82D80A4B80F8434A");
293 
294     assert(toHexString(sha3_384Of("")) ==
295         "0C63A75B845E4F7D01107D852E4C2485C51A50AAAA94FC61995E71BBEE983A2AC37138"~
296         "31264ADB47FB6BD1E058D5F004");
297 
298     assert(toHexString(sha3_512Of("")) ==
299         "A69F73CCA23A9AC5C8B567DC185A756E97C982164FE25859E0D1DCC1475C80A615B212"~
300         "3AF1F5F94C11E3E9402C3AC558F500199D95B6D3E301758586281DCD26");
301 }
302 
303 /// Of wrappers + toHexString
304 @safe unittest
305 {
306     assert(toHexString(sha3_224Of("abc")) ==
307         "E642824C3F8CF24AD09234EE7D3C766FC9A3A5168D0C94AD73B46FDF");
308 
309     assert(toHexString(sha3_256Of("abc")) ==
310         "3A985DA74FE225B2045C172D6BD390BD855F086E3E9D525B46BFE24511431532");
311 
312     assert(toHexString(sha3_384Of("abc")) ==
313         "EC01498288516FC926459F58E2C6AD8DF9B473CB0FC08C2596DA7CF0E49BE4B298D88C"~
314         "EA927AC7F539F1EDF228376D25");
315 
316     assert(toHexString(sha3_512Of("abc")) ==
317         "B751850B1A57168A5693CD924B6B096E08F621827444F70D884F5D0240D2712E10E116"~
318         "E9192AF3C91A7EC57647E3934057340B4CF408D5A56592F8274EEC53F0");
319 }
320 
321 /// Structure functions
322 @safe unittest
323 {
324     SHA3_224 hash;
325     hash.start();
326     ubyte[1024] data;
327     hash.put(data);
328     ubyte[28] result = hash.finish();
329 }
330 
331 /// Template usage
332 @safe unittest
333 {
334     // Let's use the template features:
335     // NOTE: When passing a SHA3 to a function, it must be passed by reference!
336     void doSomething(T)(ref T hash)
337         if (isDigest!T)
338         {
339             hash.put(cast(ubyte) 0);
340         }
341     SHA3_224 sha;
342     sha.start();
343     doSomething(sha);
344     assert(toHexString(sha.finish()) ==
345         "BDD5167212D2DC69665F5A8875AB87F23D5CE7849132F56371A19096");
346 }
347 
348 /// Alias for SHA-3-224. Recommended to use over the $(D KECCAK) structure.
349 public alias SHA3_224 = KECCAK!(224, false);
350 /// Alias for SHA-3-256. Recommended to use over the $(D KECCAK) structure.
351 public alias SHA3_256 = KECCAK!(256, false);
352 /// Alias for SHA-3-384. Recommended to use over the $(D KECCAK) structure.
353 public alias SHA3_384 = KECCAK!(384, false);
354 /// Alias for SHA-3-512. Recommended to use over the $(D KECCAK) structure.
355 public alias SHA3_512 = KECCAK!(512, false);
356 /// Alias for SHAKE-128. Recommended to use over the $(D KECCAK) structure.
357 public alias SHAKE128 = KECCAK!(128, true);
358 /// Alias for SHAKE-256. Recommended to use over the $(D KECCAK) structure.
359 public alias SHAKE256 = KECCAK!(256, true);
360 
361 @safe unittest
362 {
363     assert(isDigest!SHA3_224);
364     assert(isDigest!SHA3_256);
365     assert(isDigest!SHA3_384);
366     assert(isDigest!SHA3_512);
367     assert(isDigest!SHAKE128);
368     assert(isDigest!SHAKE256);
369 }
370 
371 /// Convience alias for $(REF digest, std,digest) using the SHA-3 implementation.
372 auto sha3_224Of(T...)(T data)
373 {
374     return digest!(SHA3_224, T)(data);
375 }
376 /// Ditto
377 auto sha3_256Of(T...)(T data)
378 {
379     return digest!(SHA3_256, T)(data);
380 }
381 /// Ditto
382 auto sha3_384Of(T...)(T data)
383 {
384     return digest!(SHA3_384, T)(data);
385 }
386 /// Ditto
387 auto sha3_512Of(T...)(T data)
388 {
389     return digest!(SHA3_512, T)(data);
390 }
391 /// Ditto
392 auto shake128Of(T...)(T data)
393 {
394     return digest!(SHAKE128, T)(data);
395 }
396 /// Ditto
397 auto shake256Of(T...)(T data)
398 {
399     return digest!(SHAKE256, T)(data);
400 }
401 
402 /// digest! wrappers
403 @safe unittest
404 {
405     ubyte[28] hash224 = sha3_224Of("abc");
406     assert(hash224 == digest!SHA3_224("abc"));
407 
408     ubyte[32] hash256 = sha3_256Of("abc");
409     assert(hash256 == digest!SHA3_256("abc"));
410 
411     ubyte[48] hash384 = sha3_384Of("abc");
412     assert(hash384 == digest!SHA3_384("abc"));
413 
414     ubyte[64] hash512 = sha3_512Of("abc");
415     assert(hash512 == digest!SHA3_512("abc"));
416 
417     ubyte[16] shakeHash128 = shake128Of("abc");
418     assert(shakeHash128 == digest!SHAKE128("abc"));
419 
420     ubyte[32] shakeHash256 = shake256Of("abc");
421     assert(shakeHash256 == digest!SHAKE256("abc"));
422 }
423 
424 /// Structures
425 @system unittest
426 {
427     import std.conv : hexString;
428     
429     SHA3_224 dgst_sha3_224;
430     dgst_sha3_224.put(cast(ubyte[]) "abcdef");
431     dgst_sha3_224.start();
432     dgst_sha3_224.put(cast(ubyte[]) "");
433     assert(dgst_sha3_224.finish() ==
434         cast(ubyte[]) hexString!"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7");
435     
436     SHA3_256 dgst_sha3_256;
437     dgst_sha3_256.put(cast(ubyte[]) "abcdef");
438     dgst_sha3_256.start();
439     dgst_sha3_256.put(cast(ubyte[]) "");
440     assert(dgst_sha3_256.finish() ==
441         cast(ubyte[]) hexString!"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a");
442     
443     SHA3_384 dgst_sha3_384;
444     dgst_sha3_384.put(cast(ubyte[]) "abcdef");
445     dgst_sha3_384.start();
446     dgst_sha3_384.put(cast(ubyte[]) "");
447     assert(dgst_sha3_384.finish() ==
448         cast(ubyte[]) hexString!("0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2a"
449         ~"c3713831264adb47fb6bd1e058d5f004"));
450     
451     SHA3_512 dgst_sha3_512;
452     dgst_sha3_512.put(cast(ubyte[]) "abcdef");
453     dgst_sha3_512.start();
454     dgst_sha3_512.put(cast(ubyte[]) "");
455     assert(dgst_sha3_512.finish() ==
456         cast(ubyte[]) hexString!("a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a6"
457         ~"15b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"));
458     
459     SHAKE128 dgst_shake128;
460     dgst_shake128.put(cast(ubyte[]) "abcdef");
461     dgst_shake128.start();
462     dgst_shake128.put(cast(ubyte[]) "");
463     assert(dgst_shake128.finish() == cast(ubyte[]) hexString!"7f9c2ba4e88f827d616045507605853e");
464     
465     SHAKE256 dgst_shake256;
466     dgst_shake256.put(cast(ubyte[]) "abcdef");
467     dgst_shake256.start();
468     dgst_shake256.put(cast(ubyte[]) "");
469     assert(dgst_shake256.finish() ==
470         cast(ubyte[]) hexString!"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f");
471 }
472 
473 /// Of wrappers
474 @system unittest
475 {
476     import std.conv : hexString;
477     
478     immutable string a = "a";
479     
480     auto digest224      = sha3_224Of(a);
481     assert(digest224 == cast(ubyte[]) hexString!"9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b");
482     auto digest256      = sha3_256Of(a);
483     assert(digest256 == cast(ubyte[]) hexString!"80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b");
484     auto digest384      = sha3_384Of(a);
485     assert(digest384 == cast(ubyte[]) hexString!("1815f774f320491b48569efec794d"
486         ~"249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9"));
487     auto digest512      = sha3_512Of(a);
488     assert(digest512 == cast(ubyte[]) hexString!("697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa8"
489         ~"03f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a"));
490     auto digestshake128 = shake128Of(a);
491     assert(digestshake128 == cast(ubyte[]) hexString!"85c8de88d28866bf0868090b3961162b");
492     auto digestshake256 = shake256Of(a);
493     assert(digestshake256 == cast(ubyte[]) hexString!("867e2cb04f5a04dcbd592501a5e8fe9ceaafca50255626ca736c138042"
494         ~"530ba4"));
495         
496     immutable string abc = "abc";
497     
498     digest224      = sha3_224Of(abc);
499     assert(digest224 == cast(ubyte[]) hexString!"e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf");
500     digest256      = sha3_256Of(abc);
501     assert(digest256 == cast(ubyte[]) hexString!"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532");
502     digest384      = sha3_384Of(abc);
503     assert(digest384 == cast(ubyte[]) hexString!("ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b"
504         ~"298d88cea927ac7f539f1edf228376d25"));
505     digest512      = sha3_512Of(abc);
506     assert(digest512 == cast(ubyte[]) hexString!("b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712"
507         ~"e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"));
508     digestshake128 = shake128Of(abc);
509     assert(digestshake128 == cast(ubyte[]) hexString!"5881092dd818bf5cf8a3ddb793fbcba7");
510     digestshake256 = shake256Of(abc);
511     assert(digestshake256 == cast(ubyte[]) hexString!("483366601360a8771c6863080cc4114d8db44530f8f1e1ee4f94ea37e7"
512         ~"8b5739"));
513     
514     immutable string longString = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
515     
516     digest224      = sha3_224Of(longString);
517     assert(digest224 == cast(ubyte[]) hexString!"8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33");
518     digest256      = sha3_256Of(longString);
519     assert(digest256 == cast(ubyte[]) hexString!"41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376");
520     digest384      = sha3_384Of(longString);
521     assert(digest384 == cast(ubyte[]) hexString!("991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5"
522         ~"aa04a1f076e62fea19eef51acd0657c22"));
523     digest512      = sha3_512Of(longString);
524     assert(digest512 == cast(ubyte[]) hexString!("04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636"
525         ~"dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e"));
526     digestshake128 = shake128Of(longString);
527     assert(digestshake128 == cast(ubyte[]) hexString!"1a96182b50fb8c7e74e0a707788f55e9");
528     digestshake256 = shake256Of(longString);
529     assert(digestshake256 == cast(ubyte[]) hexString!("4d8c2dd2435a0128eefbb8c36f6f87133a7911e18d979ee1ae6be5d4fd"
530         ~"2e3329"));
531     
532     ubyte[] onemilliona = new ubyte[1_000_000];
533     onemilliona[] = 'a';
534     
535     digest224      = sha3_224Of(onemilliona);
536     assert(digest224 == cast(ubyte[]) hexString!"d69335b93325192e516a912e6d19a15cb51c6ed5c15243e7a7fd653c");
537     digest256      = sha3_256Of(onemilliona);
538     assert(digest256 == cast(ubyte[]) hexString!"5c8875ae474a3634ba4fd55ec85bffd661f32aca75c6d699d0cdcb6c115891c1");
539     digest384      = sha3_384Of(onemilliona);
540     assert(digest384 == cast(ubyte[]) hexString!("eee9e24d78c1855337983451df97c8ad9eedf256c6334f8e948d252d5e0e768"
541         ~"47aa0774ddb90a842190d2c558b4b8340"));
542     digest512      = sha3_512Of(onemilliona);
543     assert(digest512 == cast(ubyte[]) hexString!("3c3a876da14034ab60627c077bb98f7e120a2a5370212dffb3385a18d4f3885"
544         ~"9ed311d0a9d5141ce9cc5c66ee689b266a8aa18ace8282a0e0db596c90b0a7b87"));
545     digestshake128 = shake128Of(onemilliona);
546     assert(digestshake128 == cast(ubyte[]) hexString!"9d222c79c4ff9d092cf6ca86143aa411");
547     digestshake256 = shake256Of(onemilliona);
548     assert(digestshake256 == cast(ubyte[]) hexString!("3578a7a4ca9137569cdf76ed617d31bb994fca9c1bbf8b184013de8234"
549         ~"dfd13a"));
550 }
551 
552 /// An OOP API SHA-3 implementation. See `std.digest` for differences between
553 /// the templates and the OOP API. This is similar to
554 /// $(D $(REF WrapperDigest, std,digest)!SHA1Digest).
555 public alias SHA3_224Digest = WrapperDigest!SHA3_224;
556 /// Ditto
557 public alias SHA3_256Digest = WrapperDigest!SHA3_256;
558 /// Ditto
559 public alias SHA3_384Digest = WrapperDigest!SHA3_384;
560 /// Ditto
561 public alias SHA3_512Digest = WrapperDigest!SHA3_512;
562 /// Ditto
563 public alias SHAKE128Digest = WrapperDigest!SHAKE128;
564 /// Ditto
565 public alias SHAKE256Digest = WrapperDigest!SHAKE256;