1 module dcrypt.digests.sha3;
2 
3 /// Implementation of Keccak, SHA3 and extendable output functions SHAKE128/256.
4 /// 
5 /// Standard: FIPS 202, SHA 3
6 
7 import dcrypt.digest;
8 import dcrypt.bitmanip;
9 
10 import std.conv: text;
11 import std.algorithm: min;
12 
13 alias Keccak!(224*2) Keccak224;
14 alias Keccak!(256*2) Keccak256;
15 alias Keccak!(288*2) Keccak288;
16 alias Keccak!(384*2) Keccak384;
17 alias Keccak!(512*2) Keccak512;
18 
19 alias SHA3!224 SHA3_224;
20 alias SHA3!256 SHA3_256;
21 alias SHA3!384 SHA3_384;
22 alias SHA3!512 SHA3_512;
23 
24 alias WrapperDigest!SHA3_224 SHA3_224Digest;
25 alias WrapperDigest!SHA3_256 SHA3_256Digest;
26 alias WrapperDigest!SHA3_384 SHA3_384Digest;
27 alias WrapperDigest!SHA3_512 SHA3_512Digest;
28 
29 static assert(isDigest!Keccak224);
30 static assert(isDigest!Keccak256);
31 static assert(isDigest!Keccak384);
32 static assert(isDigest!Keccak512);
33 
34 static assert(isDigest!SHA3_224);
35 static assert(isDigest!SHA3_256);
36 static assert(isDigest!SHA3_384);
37 static assert(isDigest!SHA3_512);
38 
39 /// Test Keccak
40 unittest {
41 
42 	string msg1600 = x"8C3798E51BC68482D7337D3ABB75DC9FFE860714A9AD73551E120059860DDE24AB87327222B64CF774415A70F724CDF270DE3FE47DDA07B61C9EF2A3551F45A5584860248FABDE676E1CD75F6355AA3EAEABE3B51DC813D9FB2EAA4F0F1D9F834D7CAD9C7C695AE84B329385BC0BEF895B9F1EDF44A03D4B410CC23A79A6B62E4F346A5E8DD851C2857995DDBF5B2D717AEB847310E1F6A46AC3D26A7F9B44985AF656D2B7C9406E8A9E8F47DCB4EF6B83CAACF9AEFB6118BFCFF7E44BEF6937EBDDC89186839B77";
43 
44 	immutable string[] plaintexts = [x"",x"",x"",x"",
45 		// https://cloud.github.com/downloads/johanns/sha3/KeccakTestVectors.zip
46 		x"CC",
47 		msg1600,
48 		x"CC",
49 		msg1600,
50 		x"CC",
51 		msg1600,
52 		x"CC",
53 		msg1600
54 	];
55 
56 	immutable string[] hexHashes = [
57 		x"f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd",
58 		x"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
59 		x"2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff",
60 		x"0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e",
61 		// https://cloud.github.com/downloads/johanns/sha3/KeccakTestVectors.zip
62 		x"A9CAB59EB40A10B246290F2D6086E32E3689FAF1D26B470C899F2802",
63 		x"1029CA117957D80F3C859E8394DD34969331CA3BCEDC436B1EAB0849",
64 		x"EEAD6DBFC7340A56CAEDC044696A168870549A6A7F6F56961E84A54BD9970B8A",
65 		x"E83EA21F5BC0976953AF86069A10EB6024A1AC59D609688E4A9759BB8B6C9441",
66 		x"1B84E62A46E5A201861754AF5DC95C4A1A69CAF4A796AE405680161E29572641F5FA1E8641D7958336EE7B11C58F73E9",
67 		x"B5A7160112E0825A7C03643BEB98B1FC2549B81F01C3C4271DFF99BE57D472A7FAD133808D7D2D414D6011E9A2E8DFEC",
68 		x"8630C13CBD066EA74BBE7FE468FEC1DEE10EDC1254FB4C1B7C5FD69B646E44160B8CE01D05A0908CA790DFB080F4B513BC3B6225ECE7A810371441A5AC666EB9",
69 		x"2A11CB6921EA662A39DDEE7982E3CF5B317195661D5505AD04D11EE23E178ED65F3E06A7F096F4EAF1FF6A09239CF5A0A39DC9F4C92AF63FDF7211E1CF467653",
70 
71 	];
72 	
73 
74 	for(size_t i = 0; i < plaintexts.length; ++i) {
75 		const (ubyte)[] plain = cast(const ubyte[]) plaintexts[i];
76 		const ubyte[] expectedHash = cast(const ubyte[]) hexHashes[i];
77 		ubyte[] actualHash;
78 
79 		switch(expectedHash.length*8) {
80 			case 224: 
81 				Keccak224 k;
82 				k.put(plain);
83 				actualHash = k.finish!224();
84 				break;
85 			case 256: 
86 				Keccak256 k;
87 				k.put(plain);
88 				actualHash = k.finish!256();
89 				break;
90 			case 384: 
91 				Keccak384 k;
92 				k.put(plain);
93 				actualHash = k.finish!384();
94 				break;
95 			case 512: 
96 				Keccak512 k;
97 				k.put(plain);
98 				actualHash = k.finish!512();
99 				break;
100 			default: assert(0);
101 		}
102 		
103 		assert(expectedHash == actualHash, "Keccak Produced wrong hash.");
104 	}
105 }
106 
107 unittest {
108 	SHA3!224 sha3;
109 
110 	// empty message
111 	assert(sha3.finish() == x"
112 		6B 4E 03 42 36 67 DB B7 3B 6E 15 45 4F 0E B1 AB
113 		D4 59 7F 9A 1B 07 8E 3F 5B 5A 6B C7",
114 		sha3.name~" failed.");
115 
116 	ubyte[200] msg = 0b10100011;
117 	sha3.put(msg);
118 
119 	assert(sha3.finish() == x"
120 		93 76 81 6A BA 50 3F 72 F9 6C E7 EB 65 AC 09 5D 
121 		EE E3 BE 4B F9 BB C2 A1 CB 7E 11 E0",
122 		sha3.name~" failed.");
123 }
124 
125 unittest {
126 	SHA3!256 sha3;
127 
128 	// empty message
129 	assert(sha3.finish() == x"A7 FF C6 F8 BF 1E D7 66 51 C1 47 56 A0 61 D6 62
130 		F5 80 FF 4D E4 3B 49 FA 82 D8 0A 4B 80 F8 43 4A", 
131 		sha3.name~" failed.");
132 }
133 
134 unittest {
135 	SHA3!384 sha3;
136 	
137 	// empty message
138 	assert(sha3.finish() == x"
139 		0C 63 A7 5B 84 5E 4F 7D 01 10 7D 85 2E 4C 24 85
140 		C5 1A 50 AA AA 94 FC 61 99 5E 71 BB EE 98 3A 2A
141 		C3 71 38 31 26 4A DB 47 FB 6B D1 E0 58 D5 F0 04", 
142 		sha3.name~" failed.");
143 }
144 
145 unittest {
146 	SHA3!512 sha3;
147 	
148 	// empty message
149 	assert(sha3.finish() == x"A6 9F 73 CC A2 3A 9A C5 C8 B5 67 DC 18 5A 75 6E
150 		97 C9 82 16 4F E2 58 59 E0 D1 DC C1 47 5C 80 A6
151 		15 B2 12 3A F1 F5 F9 4C 11 E3 E9 40 2C 3A C5 58
152 		F5 00 19 9D 95 B6 D3 E3 01 75 85 86 28 1D CD 26",
153 		sha3.name~" failed.");
154 }
155 
156 /// Implementation of SHA3.
157 /// 
158 /// Standard: FIPS 202, SHA 3
159 @safe
160 public struct SHA3(uint bitLength)
161 	if(bitLength == 224 || bitLength == 256 || bitLength == 384 || bitLength == 512)
162 {
163 	private Keccak!(bitLength*2) keccak;
164 
165 	enum name = text("SHA3-", bitLength);
166 	enum digestLength = keccak.digestLength;
167 
168 	enum blockSize = [224: 144, 256: 136, 384: 104, 512: 72][bitLength]; /// Block size for HMAC as defined in FIPS 202, section 7, table 3.
169 
170 	void start() nothrow @nogc {
171 		keccak.start();
172 	}
173 
174 	public void put(in ubyte[] b...) nothrow @nogc {
175 		keccak.put(b);
176 	}
177 
178 	/// Calculate the final hash value.
179 	/// Params:
180 	/// output = buffer for hash value.
181 	/// Returns: length of hash value in bytes.
182 	ubyte[] finish(ubyte[] output) nothrow @nogc
183 	in {
184 		assert(output.length == digestLength, "output.length != digestLength.");
185 	} body {
186 
187 		keccak.absorbBits(0b10, 2);
188 
189 		return keccak.finish(output);
190 	}
191 	
192 	/// Calculate the final hash value.
193 	/// Returns: the hash value
194 	ubyte[digestLength] finish() nothrow @nogc {
195 		ubyte[digestLength] hash;
196 		finish(hash);
197 		return hash;
198 	}
199 }
200 
201 
202 /// Implementation of SHA-3 based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
203 @safe
204 public struct Keccak(uint capacity)
205 	if(capacity % 8 == 0)
206 {
207 
208 	public {
209 		//static assert(bitLength == 224 || bitLength == 256 || bitLength == 288 || bitLength == 384 || bitLength == 512);
210 		enum name = text("Keccak[", capacity, ", ", rate, "]");
211 		enum digestLength = bitLength / 8;
212 
213 		public enum blockSize = 0;
214 
215 		@nogc
216 		void put(in ubyte[] input...) nothrow
217 		{
218 			absorb(input);
219 		}
220 
221 		/// Fills the output buffer with the hash value.
222 		/// Note: Hash will be as long as the output buffer.
223 		/// Params:
224 		/// output = buffer for hash value.
225 		/// Returns: Slice of `output` containing the hash.
226 		ubyte[] finish(ubyte[] output) nothrow @nogc {
227 			squeeze(output);
228 			start();
229 			return output;
230 		}
231 
232 		/// Calculate the final hash value.
233 		/// Params:
234 		/// outputLen = Hash size in bits.
235 		/// Returns: the hash value
236 		ubyte[outputLen/8] finish(uint outputLen = bitLength)() nothrow @nogc 
237 			if (outputLen % 8 == 0)
238 		{
239 			ubyte[outputLen/8] buf;
240 			finish(buf);
241 			return buf;
242 		}
243 
244 		void start() nothrow @nogc
245 		{
246 			initSponge();
247 		}
248 	}
249 
250 	private {
251 
252 		enum rate = 1600 - capacity;
253 		enum bitLength = capacity / 2;
254 		enum byteStateLength = 1600 / 8;
255 		enum longStateLength = byteStateLength / 8;
256 		enum rounds = 24;
257 
258 		uint bitsInQueue;
259 		bool squeezing;
260 		uint bitsAvailableForSqueezing;
261 		ulong[longStateLength] state;
262 		ubyte[rate / 8] dataQueue;
263 	}
264 
265 private:
266 	nothrow @nogc:
267 
268 	void clearDataQueueSection(in size_t off, in size_t len) {
269 		dataQueue[off..off+len] = 0;
270 	}
271 
272 	/// Handles data with arbitrary bit size.
273 	void doUpdate(in ubyte[] data, in size_t databitlen)
274 	in {
275 		assert(data.length == (databitlen+7) / 8);
276 	} body	{
277 		if ((databitlen % 8) == 0)
278 		{
279 			assert(databitlen == data.length * 8);
280 			absorb(data);
281 		}
282 		else
283 		{
284 			if(databitlen > 8) {
285 				// Absorb all bytes except the last.
286 				absorb(data[0..$-2]);
287 			}
288 
289 			immutable size_t bitLen = databitlen % 8;
290 
291 			ubyte lastByte = cast(ubyte)(data[(databitlen / 8)] >>> (8 - bitLen));
292 			//absorb(lastByte, databitlen % 8);
293 			absorbBits(lastByte, bitLen);
294 		}
295 	}
296 
297 	/// Resets Keccak.
298 	void initSponge() 
299 	{
300 		state[] = 0;
301 		dataQueue[] = 0;
302 		bitsInQueue = 0;
303 		squeezing = false;
304 		bitsAvailableForSqueezing = 0;
305 	}
306 
307 	void absorbQueue()
308 	{
309 		KeccakAbsorb!rounds(state, dataQueue[0..rate / 8]);
310 		bitsInQueue = 0;
311 	}
312 
313 	package void absorbBits(in ubyte partialByte, in ulong bitLen) 
314 	in {
315 		assert(bitLen < 8, "bitLen must be < 8.");
316 		assert ((bitsInQueue % 8) == 0, "attempt to absorb with odd length queue.");
317 		assert(!squeezing, "attempt to absorb while squeezing.");
318 	}
319 	body {
320 		if (bitsInQueue == rate)
321 		{
322 			absorbQueue();
323 		}
324 		uint mask = (1 << bitLen) - 1;
325 		dataQueue[bitsInQueue / 8] = cast(ubyte)(partialByte & mask);
326 		bitsInQueue += bitLen;
327 	}
328 
329 	/// Absorb even bytes.
330 	void absorb(in ubyte[] data) 
331 	in {
332 		assert ((bitsInQueue % 8) == 0, "attempt to absorb with odd length queue.");
333 		assert(!squeezing, "attempt to absorb while squeezing.");
334 	}
335 	body {
336 
337 		const (ubyte)[] iBuf = data;
338 
339 		while (iBuf.length > 0)
340 		{
341 			assert(bitsInQueue % 8 == 0);
342 
343 			if ((bitsInQueue == 0) && (iBuf.length >= rate/8))
344 			{
345 				while(iBuf.length > rate/8)
346 				{
347 					KeccakAbsorb!rounds(state, iBuf[0..rate / 8]);
348 					iBuf = iBuf[rate / 8..$];
349 				}
350 			} else {
351 				immutable size_t partialBlock = min(iBuf.length, rate/8 - bitsInQueue/8);
352 
353 				dataQueue[bitsInQueue / 8 .. bitsInQueue / 8 + partialBlock]
354 				= iBuf[0 .. partialBlock];
355 				iBuf = iBuf[partialBlock..$];
356 				
357 				bitsInQueue += partialBlock*8;
358 
359 				if (bitsInQueue == rate)
360 				{
361 					absorbQueue();
362 				}
363 			}
364 		}
365 	}
366 
367 	void padAndSwitchToSqueezingPhase()
368 	{
369 		if (bitsInQueue + 1 == rate)
370 		{
371 			dataQueue[bitsInQueue / 8] |= 1 << (bitsInQueue % 8);
372 			absorbQueue();
373 			dataQueue[0..rate/8] = 0;
374 		}
375 		else
376 		{
377 			clearDataQueueSection((bitsInQueue + 7) / 8, rate / 8 - (bitsInQueue + 7) / 8);
378 			dataQueue[bitsInQueue / 8] |= 1 << (bitsInQueue % 8);
379 		}
380 		dataQueue[(rate - 1) / 8] |= 1 << ((rate - 1) % 8);
381 		absorbQueue();
382 
383 		KeccakExtract(state, dataQueue, rate / 64);
384 
385 		bitsAvailableForSqueezing = rate;
386 		
387 		squeezing = true;
388 	}
389 
390 	
391 	package void squeeze(ubyte[] output)
392 	{
393 		immutable size_t outputLength = output.length*8;
394 		uint partialBlock;
395 
396 		if (!squeezing)
397 		{
398 			padAndSwitchToSqueezingPhase();
399 		}
400 
401 		while (output.length > 0)
402 		{
403 			if (bitsAvailableForSqueezing == 0)
404 			{
405 				keccakPermutation!rounds(state);
406 
407 				KeccakExtract(state, dataQueue, rate / 64);
408 				bitsAvailableForSqueezing = rate;
409 				
410 			}
411 			partialBlock = min(bitsAvailableForSqueezing/8, output.length);
412 
413 			output[0..partialBlock] = dataQueue[(rate/8 - bitsAvailableForSqueezing/8)..(rate/8 - bitsAvailableForSqueezing/8) + partialBlock];
414 			output = output[partialBlock..$];
415 
416 			bitsAvailableForSqueezing -= partialBlock*8;
417 		}
418 	}
419 
420 
421 	/// Note: This can safely be @trusted because array indices are fixed and
422 	/// do never depend on input data.
423 	@safe
424 	static void keccakPermutation(uint rounds)(ref ulong[25] state) pure
425 	{
426 		foreach (uint i; 0..rounds)
427 		{
428 			immutable ulong c0 = state[0] ^ state[5] ^ state[10] ^ state[15] ^ state[20];
429 			immutable ulong c1 = state[1] ^ state[6] ^ state[11] ^ state[16] ^ state[21];
430 			immutable ulong c2 = state[2] ^ state[7] ^ state[12] ^ state[17] ^ state[22];
431 			immutable ulong c3 = state[3] ^ state[8] ^ state[13] ^ state[18] ^ state[23];
432 			immutable ulong c4 = state[4] ^ state[9] ^ state[14] ^ state[19] ^ state[24];
433 			
434 			immutable ulong d0 = rol(c0, 1) ^ c3;
435 			immutable ulong d1 = rol(c1, 1) ^ c4;
436 			immutable ulong d2 = rol(c2, 1) ^ c0;
437 			immutable ulong d3 = rol(c3, 1) ^ c1;
438 			immutable ulong d4 = rol(c4, 1) ^ c2;
439 			
440 			immutable ulong b00 = state[ 0] ^ d1;
441 			immutable ulong b01 = rol(state[6] ^ d2, 44);
442 			immutable ulong b02 = rol(state[12] ^ d3, 43);
443 			immutable ulong b03 = rol(state[18] ^ d4, 21);
444 			immutable ulong b04 = rol(state[24] ^ d0, 14);
445 			immutable ulong b05 = rol(state[3] ^ d4, 28);
446 			immutable ulong b06 = rol(state[9] ^ d0, 20);
447 			immutable ulong b07 = rol(state[10] ^ d1, 3);
448 			immutable ulong b08 = rol(state[16] ^ d2, 45);
449 			immutable ulong b09 = rol(state[22] ^ d3, 61);
450 			immutable ulong b10 = rol(state[1] ^ d2, 1);
451 			immutable ulong b11 = rol(state[7] ^ d3, 6);
452 			immutable ulong b12 = rol(state[13] ^ d4, 25);
453 			immutable ulong b13 = rol(state[19] ^ d0, 8);
454 			immutable ulong b14 = rol(state[20] ^ d1, 18);
455 			immutable ulong b15 = rol(state[4] ^ d0, 27);
456 			immutable ulong b16 = rol(state[5] ^ d1, 36);
457 			immutable ulong b17 = rol(state[11] ^ d2, 10);
458 			immutable ulong b18 = rol(state[17] ^ d3, 15);
459 			immutable ulong b19 = rol(state[23] ^ d4, 56);
460 			immutable ulong b20 = rol(state[2] ^ d3, 62);
461 			immutable ulong b21 = rol(state[8] ^ d4, 55);
462 			immutable ulong b22 = rol(state[14] ^ d0, 39);
463 			immutable ulong b23 = rol(state[15] ^ d1, 41);
464 			immutable ulong b24 = rol(state[21] ^ d2, 2);
465 			
466 			state[0] = b00 ^ (~b01 & b02);
467 			state[1] = b01 ^ (~b02 & b03);
468 			state[2] = b02 ^ (~b03 & b04);
469 			state[3] = b03 ^ (~b04 & b00);
470 			state[4] = b04 ^ (~b00 & b01);
471 			state[5] = b05 ^ (~b06 & b07);
472 			state[6] = b06 ^ (~b07 & b08);
473 			state[7] = b07 ^ (~b08 & b09);
474 			state[8] = b08 ^ (~b09 & b05);
475 			state[9] = b09 ^ (~b05 & b06);
476 			state[10] = b10 ^ (~b11 & b12);
477 			state[11] = b11 ^ (~b12 & b13);
478 			state[12] = b12 ^ (~b13 & b14);
479 			state[13] = b13 ^ (~b14 & b10);
480 			state[14] = b14 ^ (~b10 & b11);
481 			state[15] = b15 ^ (~b16 & b17);
482 			state[16] = b16 ^ (~b17 & b18);
483 			state[17] = b17 ^ (~b18 & b19);
484 			state[18] = b18 ^ (~b19 & b15);
485 			state[19] = b19 ^ (~b15 & b16);
486 			state[20] = b20 ^ (~b21 & b22);
487 			state[21] = b21 ^ (~b22 & b23);
488 			state[22] = b22 ^ (~b23 & b24);
489 			state[23] = b23 ^ (~b24 & b20);
490 			state[24] = b24 ^ (~b20 & b21);
491 			
492 			state[0] ^= KeccakRoundConstants[i];
493 		}
494 	}
495 
496 	
497 	static void KeccakAbsorb(uint rounds)(ref ulong[longStateLength] longState, in ubyte[] data) pure
498 	in {
499 		assert(data.length <= longState.length*8);
500 		assert(data.length % 8 == 0);
501 	} body {
502 		ubyte[byteStateLength] byteBuf;
503 		byteBuf[0..data.length] = data;
504 		ulong[longStateLength] buf;
505 		fromLittleEndian!ulong(byteBuf, buf);
506 		longState[] ^= buf[];
507 		keccakPermutation!rounds(longState);
508 	}
509 
510 	static void KeccakExtract(in ulong[] longState, ubyte[] data, size_t laneCount) pure
511 	{
512 		toLittleEndian(longState[0..laneCount], data[0..laneCount*8]);
513 	}
514 }
515 
516 
517 // Keccak constants
518 private @safe {
519 	immutable ulong[24] KeccakRoundConstants = keccakInitializeRoundConstants();
520 	
521 	static ulong[24] keccakInitializeRoundConstants() pure nothrow @nogc
522 	{
523 		ulong[24] keccakRoundConstants;
524 		ubyte[1] LFSRstate;
525 		
526 		LFSRstate[0] = 0x01;
527 		uint i, j, bitPosition;
528 		
529 		for (i = 0; i < 24; i++)
530 		{
531 			keccakRoundConstants[i] = 0;
532 			for (j = 0; j < 7; j++)
533 			{
534 				bitPosition = (1 << j) - 1;
535 				if (LFSR86540(LFSRstate))
536 				{
537 					keccakRoundConstants[i] ^= 1L << bitPosition;
538 				}
539 			}
540 		}
541 		
542 		return keccakRoundConstants;
543 	}
544 	
545 	static bool LFSR86540(ubyte[] LFSR) pure nothrow @nogc
546 	{
547 		bool result = (((LFSR[0]) & 0x01) != 0);
548 		if (((LFSR[0]) & 0x80) != 0)
549 		{
550 			LFSR[0] = cast(ubyte)(((LFSR[0]) << 1) ^ 0x71);
551 		}
552 		else
553 		{
554 			LFSR[0] <<= 1;
555 		}
556 		
557 		return result;
558 	}
559 }
560 
561 alias SHAKE!128 SHAKE128;
562 alias SHAKE!256 SHAKE256;
563 alias SHAKE!(128, true) RawSHAKE128;
564 alias SHAKE!(256, true) RawSHAKE256;
565 
566 /// Implementation of the SHAKE extendable output function (XOF).
567 /// Standard: FIPS 202, SHA 3, Section 6.3
568 public struct SHAKE(uint bitsize, bool raw = false) if(bitsize == 128 || bitsize == 256) {
569 
570 	public enum name = text(raw ? "RawSHAKE" : "SHAKE", bitsize);
571 
572 	private {
573 		Keccak!(bitsize*2) keccak;
574 		bool squeezing = false;
575 	}
576 
577 	public void start() {
578 		keccak.start();
579 		squeezing = false;
580 	}
581 
582 	public void put(in ubyte[] b...) {
583 		assert(!squeezing, name~": Illegal state. Can't absorb data while after extracting some. Use start() to reset.");
584 
585 		keccak.put(b);
586 	}
587 
588 	public void nextBytes(ubyte[] buf) {
589 
590 		if(!squeezing) {
591 			// switch to squeezing
592 			static if(raw) {
593 				keccak.absorbBits(0b11, 2);
594 			} else {
595 				keccak.absorbBits(0b1111, 4);
596 			}
597 			squeezing = true;
598 		}
599 
600 		keccak.squeeze(buf);
601 	}
602 
603 }
604 
605 /// Test SHAKE128
606 unittest {
607 	import std.stdio;
608 
609 	SHAKE128 shake;
610 	ubyte[32] buf;
611 
612 	shake.nextBytes(buf);
613 
614 	assert(buf == x"7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26", shake.name~" failed.");
615 
616 	shake.start();
617 	shake.put(cast(const ubyte[]) "The quick brown fox jumps over the lazy dog");
618 	shake.nextBytes(buf);
619 	assert(buf == x"f4202e3c5852f9182a0430fd8144f0a74b95e7417ecae17db0f8cfeed0e3e66e", shake.name~" failed.");
620 }
621 
622 /// Test SHAKE256
623 unittest {
624 	import std.stdio;
625 	
626 	SHAKE256 shake;
627 	ubyte[64] buf;
628 	
629 	shake.nextBytes(buf);
630 	
631 	assert(buf == x"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762fd75dc4ddd8c0f200cb05019d67b592f6fc821c49479ab48640292eacb3b7c4be", shake.name~" failed.");
632 }