@@ -13,11 +13,11 @@ private import core.bitop : rol, bswap;
13
13
version (SHA3D_Trace)
14
14
private import std.stdio ;
15
15
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.
17
17
// /
18
18
// / It supports SHA-3 and SHAKE XOFs. Though, it is recommended to use the
19
19
// / SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHAKE128, and SHAKE256 template
20
- // / aliases respectively .
20
+ // / aliases.
21
21
// /
22
22
// / Examples:
23
23
// / ---
@@ -40,7 +40,12 @@ public struct KECCAK(uint digestSize, uint shake = 0)
40
40
@safe : @nogc : nothrow : pure :
41
41
}
42
42
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.
44
49
private enum ROUNDS = 24 ;
45
50
// / RC constants.
46
51
private immutable static ulong [ROUNDS ] K_RC = [
@@ -66,10 +71,10 @@ public struct KECCAK(uint digestSize, uint shake = 0)
66
71
{
67
72
static assert (digestSize == 128 || digestSize == 256 ,
68
73
" 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. " );
71
76
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 ." );
73
78
private enum digestSizeBytes = shake / 8 ; // / Digest size in bytes
74
79
}
75
80
else // SHA-3
@@ -81,7 +86,7 @@ public struct KECCAK(uint digestSize, uint shake = 0)
81
86
}
82
87
83
88
// / Digest size in bits.
84
- enum blockSize = (1600 - digestSize * 2 ); // Required for HMAC.
89
+ enum blockSize = (SPONGE - digestSize * 2 ); // Required for HMAC.
85
90
86
91
// ...0: Reserved
87
92
// 01: SHA-3
@@ -158,24 +163,54 @@ public struct KECCAK(uint digestSize, uint shake = 0)
158
163
{
159
164
state[pt] ^= delim;
160
165
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 ;
169
166
170
- version (SHA3D_Trace )
167
+ static if (shake )
171
168
{
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;
175
192
}
176
- else
193
+ else // SHA-3
177
194
{
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
+ }
179
214
}
180
215
}
181
216
@@ -716,3 +751,24 @@ else
716
751
assert (shake256_512.finish() == shake256_512empty);
717
752
}
718
753
}
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