Skip to content

Commit 36d47dd

Browse files
authored
std.crypto.hash.sha3: add TurboSHAKE (#14824)
1 parent 6218e40 commit 36d47dd

File tree

3 files changed

+35
-4
lines changed

3 files changed

+35
-4
lines changed

lib/std/crypto/benchmark.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ const hashes = [_]Crypto{
2727
Crypto{ .ty = crypto.hash.sha3.Sha3_512, .name = "sha3-512" },
2828
Crypto{ .ty = crypto.hash.sha3.Shake128, .name = "shake-128" },
2929
Crypto{ .ty = crypto.hash.sha3.Shake256, .name = "shake-256" },
30+
Crypto{ .ty = crypto.hash.sha3.TurboShake128(null), .name = "turboshake-128" },
31+
Crypto{ .ty = crypto.hash.sha3.TurboShake256(null), .name = "turboshake-256" },
3032
Crypto{ .ty = crypto.hash.Gimli, .name = "gimli-hash" },
3133
Crypto{ .ty = crypto.hash.blake2.Blake2s256, .name = "blake2s" },
3234
Crypto{ .ty = crypto.hash.blake2.Blake2b512, .name = "blake2b" },

lib/std/crypto/keccak_p.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,12 @@ pub fn KeccakF(comptime f: u11) type {
175175
/// Apply a (possibly) reduced-round permutation to the state.
176176
pub fn permuteR(self: *Self, comptime rounds: u5) void {
177177
var i = RC.len - rounds;
178-
while (i < rounds - rounds % 3) : (i += 3) {
178+
while (i < RC.len - RC.len % 3) : (i += 3) {
179179
self.round(RC[i]);
180180
self.round(RC[i + 1]);
181181
self.round(RC[i + 2]);
182182
}
183-
while (i < rounds) : (i += 1) {
183+
while (i < RC.len) : (i += 1) {
184184
self.round(RC[i]);
185185
}
186186
}

lib/std/crypto/sha3.zig

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@ pub const Keccak_512 = @compileError("Deprecated: use `Keccak512` instead");
1818
pub const Shake128 = Shake(128);
1919
pub const Shake256 = Shake(256);
2020

21+
/// TurboSHAKE128 is a XOF (a secure hash function with a variable output length), with a 128 bit security level.
22+
/// It is based on the same permutation as SHA3 and SHAKE128, but which much higher performance.
23+
/// The delimiter is 0x01 by default, but can be changed for context-separation.
24+
pub fn TurboShake128(comptime delim: ?u8) type {
25+
return TurboShake(128, delim);
26+
}
27+
28+
/// TurboSHAKE256 is a XOF (a secure hash function with a variable output length), with a 256 bit security level.
29+
/// It is based on the same permutation as SHA3 and SHAKE256, but which much higher performance.
30+
/// The delimiter is 0x01 by default, but can be changed for context-separation.
31+
pub fn TurboShake256(comptime delim: ?u8) type {
32+
return TurboShake(256, delim);
33+
}
34+
2135
/// A generic Keccak hash function.
2236
pub fn Keccak(comptime f: u11, comptime output_bits: u11, comptime delim: u8, comptime rounds: u5) type {
2337
comptime assert(output_bits > 0 and output_bits * 2 < f and output_bits % 8 == 0); // invalid output length
@@ -76,9 +90,18 @@ pub fn Keccak(comptime f: u11, comptime output_bits: u11, comptime delim: u8, co
7690

7791
/// The SHAKE extendable output hash function.
7892
pub fn Shake(comptime security_level: u11) type {
93+
return ShakeLike(security_level, 0x1f, 24);
94+
}
95+
96+
/// The TurboSHAKE extendable output hash function.
97+
/// https://datatracker.ietf.org/doc/draft-irtf-cfrg-kangarootwelve/
98+
pub fn TurboShake(comptime security_level: u11, comptime delim: ?u8) type {
99+
return ShakeLike(security_level, delim orelse 0x01, 12);
100+
}
101+
102+
fn ShakeLike(comptime security_level: u11, comptime delim: u8, comptime rounds: u5) type {
79103
const f = 1600;
80-
const rounds = 24;
81-
const State = KeccakState(f, security_level * 2, 0x1f, rounds);
104+
const State = KeccakState(f, security_level * 2, delim, rounds);
82105

83106
return struct {
84107
const Self = @This();
@@ -348,3 +371,9 @@ test "SHAKE-256 single" {
348371
Shake256.hash("hello123", &out, .{});
349372
try htest.assertEqual("ade612ba265f92de4a37", &out);
350373
}
374+
375+
test "TurboSHAKE-128" {
376+
var out: [32]u8 = undefined;
377+
TurboShake(128, 0x06).hash("\xff", &out, .{});
378+
try htest.assertEqual("8ec9c66465ed0d4a6c35d13506718d687a25cb05c74cca1e42501abd83874a67", &out);
379+
}

0 commit comments

Comments
 (0)