Skip to content

Commit aa52c6d

Browse files
committed
Add proper XOF
1 parent 7bb67e1 commit aa52c6d

File tree

1 file changed

+77
-21
lines changed

1 file changed

+77
-21
lines changed

source/sha3d.d

Lines changed: 77 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ private import core.bitop : rol, bswap;
1313
version (SHA3D_Trace)
1414
private import std.stdio;
1515

16-
/// Template API SHA-3/SHAKE implementation using the Keccak[1600] function.
16+
/// Template API SHA-3/SHAKE implementation using the Keccak[1600,24] function.
1717
///
1818
/// It supports SHA-3 and SHAKE XOFs. Though, it is recommended to use the
1919
/// SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHAKE128, and SHAKE256 template
20-
/// aliases respectively.
20+
/// aliases.
2121
///
2222
/// Examples:
2323
/// ---
@@ -40,7 +40,12 @@ public struct KECCAK(uint digestSize, uint shake = 0)
4040
@safe: @nogc: nothrow: pure:
4141
}
4242

43-
/// Number of official rounds for SHA-3.
43+
//TODO: Consider moving the definitions as template parameters
44+
45+
/// Sponge size. Default is 1600 bits (200 Bytes).
46+
/// Must be a power of 25 (25, 50, 100, 200, 400, 800, or 1600).
47+
private enum SPONGE = 1600;
48+
/// Number of rounds. 24 rounds for SHA-3 and SHAKE.
4449
private enum ROUNDS = 24;
4550
/// RC constants.
4651
private immutable static ulong[ROUNDS] K_RC = [
@@ -66,10 +71,10 @@ public struct KECCAK(uint digestSize, uint shake = 0)
6671
{
6772
static assert(digestSize == 128 || digestSize == 256,
6873
"SHAKE digest size must be 128 or 256 bits");
69-
static assert(shake >= 8 && shake <= 1600,
70-
"SHAKE digest size must be between 8 to 1600 bits");
74+
static assert(shake > 0,
75+
"SHAKE digest size must be higher than zero.");
7176
static assert(shake % 8 == 0,
72-
"SHAKE digest size must be a factor of 8.");
77+
"SHAKE digest size must be a factor of 25.");
7378
private enum digestSizeBytes = shake / 8; /// Digest size in bytes
7479
}
7580
else // SHA-3
@@ -81,7 +86,7 @@ public struct KECCAK(uint digestSize, uint shake = 0)
8186
}
8287

8388
/// Digest size in bits.
84-
enum blockSize = (1600 - digestSize * 2); // Required for HMAC.
89+
enum blockSize = (SPONGE - digestSize * 2); // Required for HMAC.
8590

8691
// ...0: Reserved
8792
// 01: SHA-3
@@ -158,24 +163,54 @@ public struct KECCAK(uint digestSize, uint shake = 0)
158163
{
159164
state[pt] ^= delim;
160165
state[rate - 1] ^= 0x80;
161-
transform;
162-
163-
// Clear potentially sensitive data
164-
// State sanitized only if digestSize is less than state
165-
// of 1600 bits, so 200 Bytes.
166-
static if (digestSizeBytes < stateSize)
167-
state[digestSizeBytes..$] = 0;
168-
bc[] = t = 0;
169166

170-
version (SHA3D_Trace)
167+
static if (shake)
171168
{
172-
ubyte[digestSizeBytes] r = state[0..digestSizeBytes];
173-
writeln("HASH=", toHexString!(LetterCase.lower)(r));
174-
return r;
169+
ubyte[digestSizeBytes] output = void;
170+
171+
size_t i;
172+
173+
// Transform at {rate} until output is filled.
174+
do
175+
{
176+
transform;
177+
size_t end = i + rate;
178+
if (end > digestSizeBytes)
179+
{
180+
output[i..$] = state[0..digestSizeBytes - i];
181+
break;
182+
}
183+
output[i..end] = state[0..rate];
184+
i += rate;
185+
} while (true);
186+
187+
// Clear state of potential sensitive data.
188+
state64[] = 0;
189+
bc[] = t = 0;
190+
191+
return output;
175192
}
176-
else
193+
else // SHA-3
177194
{
178-
return state[0..digestSizeBytes];
195+
transform;
196+
197+
// Clear potentially sensitive data.
198+
// State sanitized only if digestSize is less than state
199+
// of 1600 bits, so 200 Bytes.
200+
static if (digestSizeBytes < stateSize)
201+
state[digestSizeBytes..$] = 0;
202+
bc[] = t = 0;
203+
204+
version (SHA3D_Trace)
205+
{
206+
ubyte[digestSizeBytes] r = state[0..digestSizeBytes];
207+
writeln("HASH=", toHexString!(LetterCase.lower)(r));
208+
return r;
209+
}
210+
else
211+
{
212+
return state[0..digestSizeBytes];
213+
}
179214
}
180215
}
181216

@@ -716,3 +751,24 @@ else
716751
assert(shake256_512.finish() == shake256_512empty);
717752
}
718753
}
754+
755+
/// Stretching out XOFs functions to extremes.
756+
@system unittest
757+
{
758+
import std.conv : hexString;
759+
760+
// Define SHAKE-256/2048
761+
alias SHAKE256_2048 = KECCAK!(256, 2048);
762+
auto shake256_2048Of(T...)(T data) { return digest!(SHAKE256_2048, T)(data); }
763+
764+
// SHAKE-256/2048('abc')
765+
assert(shake256_2048Of("abc") == hexString!(
766+
"483366601360a8771c6863080cc4114d8db44530f8f1e1ee4f94ea37e78b5739"~
767+
"d5a15bef186a5386c75744c0527e1faa9f8726e462a12a4feb06bd8801e751e4"~
768+
"1385141204f329979fd3047a13c5657724ada64d2470157b3cdc288620944d78"~
769+
"dbcddbd912993f0913f164fb2ce95131a2d09a3e6d51cbfc622720d7a75c6334"~
770+
"e8a2d7ec71a7cc29cf0ea610eeff1a588290a53000faa79932becec0bd3cd0b3"~
771+
"3a7e5d397fed1ada9442b99903f4dcfd8559ed3950faf40fe6f3b5d710ed3b67"~
772+
"7513771af6bfe11934817e8762d9896ba579d88d84ba7aa3cdc7055f6796f195"~
773+
"bd9ae788f2f5bb96100d6bbaff7fbc6eea24d4449a2477d172a5507dcc931412"));
774+
}

0 commit comments

Comments
 (0)