From 36d47dd1991f0ccd7a9673075624f09500cc415e Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Tue, 7 Mar 2023 10:04:45 +0100 Subject: [PATCH] std.crypto.hash.sha3: add TurboSHAKE (#14824) --- lib/std/crypto/benchmark.zig | 2 ++ lib/std/crypto/keccak_p.zig | 4 ++-- lib/std/crypto/sha3.zig | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig index e6e0e1fc3930..47ca24aa6651 100644 --- a/lib/std/crypto/benchmark.zig +++ b/lib/std/crypto/benchmark.zig @@ -27,6 +27,8 @@ const hashes = [_]Crypto{ Crypto{ .ty = crypto.hash.sha3.Sha3_512, .name = "sha3-512" }, Crypto{ .ty = crypto.hash.sha3.Shake128, .name = "shake-128" }, Crypto{ .ty = crypto.hash.sha3.Shake256, .name = "shake-256" }, + Crypto{ .ty = crypto.hash.sha3.TurboShake128(null), .name = "turboshake-128" }, + Crypto{ .ty = crypto.hash.sha3.TurboShake256(null), .name = "turboshake-256" }, Crypto{ .ty = crypto.hash.Gimli, .name = "gimli-hash" }, Crypto{ .ty = crypto.hash.blake2.Blake2s256, .name = "blake2s" }, Crypto{ .ty = crypto.hash.blake2.Blake2b512, .name = "blake2b" }, diff --git a/lib/std/crypto/keccak_p.zig b/lib/std/crypto/keccak_p.zig index 10367caffd34..cef3b0cce4c8 100644 --- a/lib/std/crypto/keccak_p.zig +++ b/lib/std/crypto/keccak_p.zig @@ -175,12 +175,12 @@ pub fn KeccakF(comptime f: u11) type { /// Apply a (possibly) reduced-round permutation to the state. pub fn permuteR(self: *Self, comptime rounds: u5) void { var i = RC.len - rounds; - while (i < rounds - rounds % 3) : (i += 3) { + while (i < RC.len - RC.len % 3) : (i += 3) { self.round(RC[i]); self.round(RC[i + 1]); self.round(RC[i + 2]); } - while (i < rounds) : (i += 1) { + while (i < RC.len) : (i += 1) { self.round(RC[i]); } } diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig index 985027f3eee3..6fc4977f0b21 100644 --- a/lib/std/crypto/sha3.zig +++ b/lib/std/crypto/sha3.zig @@ -18,6 +18,20 @@ pub const Keccak_512 = @compileError("Deprecated: use `Keccak512` instead"); pub const Shake128 = Shake(128); pub const Shake256 = Shake(256); +/// TurboSHAKE128 is a XOF (a secure hash function with a variable output length), with a 128 bit security level. +/// It is based on the same permutation as SHA3 and SHAKE128, but which much higher performance. +/// The delimiter is 0x01 by default, but can be changed for context-separation. +pub fn TurboShake128(comptime delim: ?u8) type { + return TurboShake(128, delim); +} + +/// TurboSHAKE256 is a XOF (a secure hash function with a variable output length), with a 256 bit security level. +/// It is based on the same permutation as SHA3 and SHAKE256, but which much higher performance. +/// The delimiter is 0x01 by default, but can be changed for context-separation. +pub fn TurboShake256(comptime delim: ?u8) type { + return TurboShake(256, delim); +} + /// A generic Keccak hash function. pub fn Keccak(comptime f: u11, comptime output_bits: u11, comptime delim: u8, comptime rounds: u5) type { 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 /// The SHAKE extendable output hash function. pub fn Shake(comptime security_level: u11) type { + return ShakeLike(security_level, 0x1f, 24); +} + +/// The TurboSHAKE extendable output hash function. +/// https://datatracker.ietf.org/doc/draft-irtf-cfrg-kangarootwelve/ +pub fn TurboShake(comptime security_level: u11, comptime delim: ?u8) type { + return ShakeLike(security_level, delim orelse 0x01, 12); +} + +fn ShakeLike(comptime security_level: u11, comptime delim: u8, comptime rounds: u5) type { const f = 1600; - const rounds = 24; - const State = KeccakState(f, security_level * 2, 0x1f, rounds); + const State = KeccakState(f, security_level * 2, delim, rounds); return struct { const Self = @This(); @@ -348,3 +371,9 @@ test "SHAKE-256 single" { Shake256.hash("hello123", &out, .{}); try htest.assertEqual("ade612ba265f92de4a37", &out); } + +test "TurboSHAKE-128" { + var out: [32]u8 = undefined; + TurboShake(128, 0x06).hash("\xff", &out, .{}); + try htest.assertEqual("8ec9c66465ed0d4a6c35d13506718d687a25cb05c74cca1e42501abd83874a67", &out); +}