authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2023-03-02 07:13:40+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-03-02 06:13:40+00:00
log28364166e83ed52a7053029d5d7b33ad956d804d
treeb377f5a0b9967f81faa1e2c9f35a56977b9fc05a
parentdb8217f9a080f7c645a6448640a9af65f3944818
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

crypto.hash.sha3: make permutation generic and public, add SHAKE (#14756)

Make the Keccak permutation public, as it's useful for more than SHA-3 (kMAC, SHAKE, TurboSHAKE, TupleHash, etc). Our Keccak implementation was accepting f as a comptime parameter, but always used 64-bit words and 200 byte states, so it actually didn't work with anything besides f=1600. That has been fixed. The ability to use reduced-round versions was also added in order to support M14 and K12. The state was constantly converted back and forth between bytes and words, even though only a part of the state is actually used for absorbing and squeezing bytes. It was changed to something similar to the other permutations we have, so we can avoid extra copies, and eventually add vectorized implementations. In addition, the SHAKE extendable output function (XOF) was added (SHAKE128, SHAKE256). It is required by newer schemes, such as the Kyber post-quantum key exchange mechanism, whose implementation is currently blocked by SHAKE missing from our standard library. Breaking change: `Keccak_256` and `Keccak_512` were renamed to `Keccak256` and `Keccak512` for consistency with all other hash functions.

4 files changed, 419 insertions(+), 135 deletions(-)

lib/std/crypto.zig+2
......@@ -47,6 +47,8 @@ pub const auth = struct {
4747/// Core functions, that should rarely be used directly by applications.
4848pub const core = struct {
4949 pub const aes = @import("crypto/aes.zig");
50 pub const keccak = @import("crypto/keccak_p.zig");
51
5052 pub const Ascon = @import("crypto/ascon.zig").State;
5153 pub const Gimli = @import("crypto/gimli.zig").State;
5254 pub const Xoodoo = @import("crypto/xoodoo.zig").State;
lib/std/crypto/benchmark.zig+2
......@@ -25,6 +25,8 @@ const hashes = [_]Crypto{
2525 Crypto{ .ty = crypto.hash.sha2.Sha512, .name = "sha512" },
2626 Crypto{ .ty = crypto.hash.sha3.Sha3_256, .name = "sha3-256" },
2727 Crypto{ .ty = crypto.hash.sha3.Sha3_512, .name = "sha3-512" },
28 Crypto{ .ty = crypto.hash.sha3.Shake128, .name = "shake-128" },
29 Crypto{ .ty = crypto.hash.sha3.Shake256, .name = "shake-256" },
2830 Crypto{ .ty = crypto.hash.Gimli, .name = "gimli-hash" },
2931 Crypto{ .ty = crypto.hash.blake2.Blake2s256, .name = "blake2s" },
3032 Crypto{ .ty = crypto.hash.blake2.Blake2b512, .name = "blake2b" },
lib/std/crypto/keccak_p.zig created+251
......@@ -0,0 +1,251 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const math = std.math;
4const mem = std.mem;
5
6/// The Keccak-f permutation.
7pub fn KeccakF(comptime f: u11) type {
8 comptime assert(f > 200 and f <= 1600 and f % 200 == 0); // invalid bit size
9 const T = std.meta.Int(.unsigned, f / 25);
10 const Block = [25]T;
11
12 const RC = [_]u64{
13 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000,
14 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
15 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
16 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003,
17 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,
18 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
19 };
20
21 const RHO = [_]u6{
22 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
23 };
24
25 const PI = [_]u5{
26 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
27 };
28
29 return struct {
30 const Self = @This();
31
32 /// Number of bytes in the state.
33 pub const block_bytes = f / 8;
34
35 st: Block = [_]T{0} ** 25,
36
37 /// Initialize the state from a slice of bytes.
38 pub fn init(bytes: [block_bytes]u8) Self {
39 var self: Self = undefined;
40 inline for (&self.st, 0..) |*r, i| {
41 r.* = mem.readIntLittle(T, bytes[@sizeOf(T) * i ..][0..@sizeOf(T)]);
42 }
43 return self;
44 }
45
46 /// A representation of the state as bytes. The byte order is architecture-dependent.
47 pub fn asBytes(self: *Self) *[block_bytes]u8 {
48 return mem.asBytes(&self.st);
49 }
50
51 /// Byte-swap the entire state if the architecture doesn't match the required endianness.
52 pub fn endianSwap(self: *Self) void {
53 for (&self.st) |*w| {
54 w.* = mem.littleTooNative(T, w.*);
55 }
56 }
57
58 /// Set bytes starting at the beginning of the state.
59 pub fn setBytes(self: *Self, bytes: []const u8) void {
60 var i: usize = 0;
61 while (i + @sizeOf(T) <= bytes.len) : (i += @sizeOf(T)) {
62 self.st[i / @sizeOf(T)] = mem.readIntLittle(T, bytes[i..][0..@sizeOf(T)]);
63 }
64 if (i < bytes.len) {
65 var padded = [_]u8{0} ** @sizeOf(T);
66 mem.copy(u8, padded[0 .. bytes.len - i], bytes[i..]);
67 self.st[i / @sizeOf(T)] = mem.readIntLittle(T, padded[0..]);
68 }
69 }
70
71 /// XOR a byte into the state at a given offset.
72 pub fn addByte(self: *Self, byte: u8, offset: usize) void {
73 const z = @sizeOf(T) * @truncate(math.Log2Int(T), offset % @sizeOf(T));
74 self.st[offset / @sizeOf(T)] ^= @as(T, byte) << z;
75 }
76
77 /// XOR bytes into the beginning of the state.
78 pub fn addBytes(self: *Self, bytes: []const u8) void {
79 var i: usize = 0;
80 while (i + @sizeOf(T) <= bytes.len) : (i += @sizeOf(T)) {
81 self.st[i / @sizeOf(T)] ^= mem.readIntLittle(T, bytes[i..][0..@sizeOf(T)]);
82 }
83 if (i < bytes.len) {
84 var padded = [_]u8{0} ** @sizeOf(T);
85 mem.copy(u8, padded[0 .. bytes.len - i], bytes[i..]);
86 self.st[i / @sizeOf(T)] ^= mem.readIntLittle(T, padded[0..]);
87 }
88 }
89
90 /// Extract the first bytes of the state.
91 pub fn extractBytes(self: *Self, out: []u8) void {
92 var i: usize = 0;
93 while (i + @sizeOf(T) <= out.len) : (i += @sizeOf(T)) {
94 mem.writeIntLittle(T, out[i..][0..@sizeOf(T)], self.st[i / @sizeOf(T)]);
95 }
96 if (i < out.len) {
97 var padded = [_]u8{0} ** @sizeOf(T);
98 mem.writeIntLittle(T, padded[0..], self.st[i / @sizeOf(T)]);
99 mem.copy(u8, out[i..], padded[0 .. out.len - i]);
100 }
101 }
102
103 /// XOR the first bytes of the state into a slice of bytes.
104 pub fn xorBytes(self: *Self, out: []u8, in: []const u8) void {
105 assert(out.len == in.len);
106
107 var i: usize = 0;
108 while (i + @sizeOf(T) <= in.len) : (i += @sizeOf(T)) {
109 const x = mem.readIntNative(T, in[i..][0..@sizeOf(T)]) ^ mem.nativeToLittle(T, self.st[i / @sizeOf(T)]);
110 mem.writeIntNative(T, out[i..][0..@sizeOf(T)], x);
111 }
112 if (i < in.len) {
113 var padded = [_]u8{0} ** @sizeOf(T);
114 mem.copy(u8, padded[0 .. in.len - i], in[i..]);
115 const x = mem.readIntNative(T, &padded) ^ mem.nativeToLittle(T, self.st[i / @sizeOf(T)]);
116 mem.writeIntNative(T, &padded, x);
117 mem.copy(u8, out[i..], padded[0 .. in.len - i]);
118 }
119 }
120
121 /// Set the words storing the bytes of a given range to zero.
122 pub fn clear(self: *Self, from: usize, to: usize) void {
123 mem.set(T, self.st[from / @sizeOf(T) .. (to + @sizeOf(T) - 1) / @sizeOf(T)], 0);
124 }
125
126 /// Clear the entire state, disabling compiler optimizations.
127 pub fn secureZero(self: *Self) void {
128 std.crypto.utils.secureZero(T, &self.st);
129 }
130
131 inline fn round(self: *Self, rc: T) void {
132 const st = &self.st;
133
134 // theta
135 var t = [_]T{0} ** 5;
136 inline for (0..5) |i| {
137 inline for (0..5) |j| {
138 t[i] ^= st[j * 5 + i];
139 }
140 }
141 inline for (0..5) |i| {
142 inline for (0..5) |j| {
143 st[j * 5 + i] ^= t[(i + 4) % 5] ^ math.rotl(T, t[(i + 1) % 5], 1);
144 }
145 }
146
147 // rho+pi
148 var last = st[1];
149 inline for (0..24) |i| {
150 const x = PI[i];
151 const tmp = st[x];
152 st[x] = math.rotl(T, last, RHO[i]);
153 last = tmp;
154 }
155 inline for (0..5) |i| {
156 inline for (0..5) |j| {
157 t[j] = st[i * 5 + j];
158 }
159 inline for (0..5) |j| {
160 st[i * 5 + j] = t[j] ^ (~t[(j + 1) % 5] & t[(j + 2) % 5]);
161 }
162 }
163
164 // iota
165 st[0] ^= rc;
166 }
167
168 /// Apply a (possibly) reduced-round permutation to the state.
169 pub fn permuteR(self: *Self, comptime rounds: u5) void {
170 var i = RC.len - rounds;
171 while (i < rounds - rounds % 3) : (i += 3) {
172 self.round(RC[i]);
173 self.round(RC[i + 1]);
174 self.round(RC[i + 2]);
175 }
176 while (i < rounds) : (i += 1) {
177 self.round(RC[i]);
178 }
179 }
180
181 /// Apply a full-round permutation to the state.
182 pub fn permute(self: *Self) void {
183 self.permuteR(comptime 12 + 2 * math.log2(f / 25));
184 }
185 };
186}
187
188/// A generic Keccak-P state.
189pub fn State(comptime f: u11, comptime capacity: u11, comptime delim: u8, comptime rounds: u5) type {
190 comptime assert(f > 200 and f <= 1600 and f % 200 == 0); // invalid state size
191 comptime assert(capacity < f and capacity % 8 == 0); // invalid capacity size
192
193 return struct {
194 const Self = @This();
195
196 /// The block length, or rate, in bytes.
197 pub const rate = KeccakF(f).block_bytes - capacity / 8;
198 /// Keccak does not have any options.
199 pub const Options = struct {};
200
201 offset: usize = 0,
202 buf: [rate]u8 = undefined,
203
204 st: KeccakF(f) = .{},
205
206 /// Absorb a slice of bytes into the sponge.
207 pub fn absorb(self: *Self, bytes_: []const u8) void {
208 var bytes = bytes_;
209 if (self.offset > 0) {
210 const left = math.min(rate - self.offset, bytes.len);
211 mem.copy(u8, self.buf[self.offset..], bytes[0..left]);
212 self.offset += left;
213 if (self.offset == rate) {
214 self.offset = 0;
215 self.st.addBytes(self.buf[0..]);
216 self.st.permuteR(rounds);
217 }
218 if (left == bytes.len) return;
219 bytes = bytes[left..];
220 }
221 while (bytes.len >= rate) {
222 self.st.addBytes(bytes[0..rate]);
223 self.st.permuteR(rounds);
224 bytes = bytes[rate..];
225 }
226 if (bytes.len > 0) {
227 self.st.addBytes(bytes[0..]);
228 self.offset = bytes.len;
229 }
230 }
231
232 /// Mark the end of the input.
233 pub fn pad(self: *Self) void {
234 self.st.addBytes(self.buf[0..self.offset]);
235 self.st.addByte(delim, self.offset);
236 self.st.addByte(0x80, rate - 1);
237 self.st.permuteR(rounds);
238 self.offset = 0;
239 }
240
241 /// Squeeze a slice of bytes from the sponge.
242 pub fn squeeze(self: *Self, out: []u8) void {
243 var i: usize = 0;
244 while (i < out.len) : (i += rate) {
245 const left = math.min(rate, out.len - i);
246 self.st.extractBytes(out[i..][0..left]);
247 self.st.permuteR(rounds);
248 }
249 }
250 };
251}
lib/std/crypto/sha3.zig+164-135
......@@ -1,84 +1,63 @@
1const std = @import("../std.zig");
2const mem = std.mem;
1const std = @import("std");
2const assert = std.debug.assert;
33const math = std.math;
4const debug = std.debug;
5const htest = @import("test.zig");
4const mem = std.mem;
5
6const KeccakState = std.crypto.core.keccak.State;
7
8pub const Sha3_224 = Keccak(1600, 224, 0x06, 24);
9pub const Sha3_256 = Keccak(1600, 256, 0x06, 24);
10pub const Sha3_384 = Keccak(1600, 384, 0x06, 24);
11pub const Sha3_512 = Keccak(1600, 512, 0x06, 24);
12
13pub const Keccak256 = Keccak(1600, 256, 0x01, 24);
14pub const Keccak512 = Keccak(1600, 512, 0x01, 24);
15pub const Keccak_256 = @compileError("Deprecated: use `Keccak256` instead");
16pub const Keccak_512 = @compileError("Deprecated: use `Keccak512` instead");
17
18pub const Shake128 = Shake(128);
19pub const Shake256 = Shake(256);
20
21/// A generic Keccak hash function.
22pub fn Keccak(comptime f: u11, comptime output_bits: u11, comptime delim: u8, comptime rounds: u5) type {
23 comptime assert(output_bits > 0 and output_bits * 2 < f and output_bits % 8 == 0); // invalid output length
624
7pub const Sha3_224 = Keccak(224, 0x06);
8pub const Sha3_256 = Keccak(256, 0x06);
9pub const Sha3_384 = Keccak(384, 0x06);
10pub const Sha3_512 = Keccak(512, 0x06);
11pub const Keccak_256 = Keccak(256, 0x01);
12pub const Keccak_512 = Keccak(512, 0x01);
25 const State = KeccakState(f, output_bits * 2, delim, rounds);
1326
14fn Keccak(comptime bits: usize, comptime delim: u8) type {
1527 return struct {
1628 const Self = @This();
29
30 st: State = .{},
31
1732 /// The output length, in bytes.
18 pub const digest_length = bits / 8;
33 pub const digest_length = output_bits / 8;
1934 /// The block length, or rate, in bytes.
20 pub const block_length = 200 - bits / 4;
35 pub const block_length = State.rate;
2136 /// Keccak does not have any options.
2237 pub const Options = struct {};
2338
24 s: [200]u8,
25 offset: usize,
26
39 /// Initialize a Keccak hash function.
2740 pub fn init(options: Options) Self {
2841 _ = options;
29 return Self{ .s = [_]u8{0} ** 200, .offset = 0 };
42 return Self{};
3043 }
3144
32 pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
33 var d = Self.init(options);
34 d.update(b);
35 d.final(out);
45 /// Hash a slice of bytes.
46 pub fn hash(bytes: []const u8, out: *[digest_length]u8, options: Options) void {
47 var st = Self.init(options);
48 st.update(bytes);
49 st.final(out);
3650 }
3751
38 pub fn update(d: *Self, b: []const u8) void {
39 var ip: usize = 0;
40 var len = b.len;
41 var rate = block_length - d.offset;
42 var offset = d.offset;
43
44 // absorb
45 while (len >= rate) {
46 for (d.s[offset .. offset + rate], 0..) |*r, i|
47 r.* ^= b[ip..][i];
48
49 keccakF(1600, &d.s);
50
51 ip += rate;
52 len -= rate;
53 rate = block_length;
54 offset = 0;
55 }
56
57 for (d.s[offset .. offset + len], 0..) |*r, i|
58 r.* ^= b[ip..][i];
59
60 d.offset = offset + len;
52 /// Absorb a slice of bytes into the state.
53 pub fn update(self: *Self, bytes: []const u8) void {
54 self.st.absorb(bytes);
6155 }
6256
63 pub fn final(d: *Self, out: *[digest_length]u8) void {
64 // padding
65 d.s[d.offset] ^= delim;
66 d.s[block_length - 1] ^= 0x80;
67
68 keccakF(1600, &d.s);
69
70 // squeeze
71 var op: usize = 0;
72 var len: usize = bits / 8;
73
74 while (len >= block_length) {
75 mem.copy(u8, out[op..], d.s[0..block_length]);
76 keccakF(1600, &d.s);
77 op += block_length;
78 len -= block_length;
79 }
80
81 mem.copy(u8, out[op..], d.s[0..len]);
57 /// Return the hash of the absorbed bytes.
58 pub fn final(self: *Self, out: *[digest_length]u8) void {
59 self.st.pad();
60 self.st.squeeze(out[0..]);
8261 }
8362
8463 pub const Error = error{};
......@@ -95,87 +74,101 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type {
9574 };
9675}
9776
98const RC = [_]u64{
99 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000,
100 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
101 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
102 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003,
103 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,
104 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
105};
106
107const ROTC = [_]usize{
108 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
109};
110
111const PIL = [_]usize{
112 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
113};
114
115const M5 = [_]usize{
116 0, 1, 2, 3, 4, 0, 1, 2, 3, 4,
117};
118
119fn keccakF(comptime F: usize, d: *[F / 8]u8) void {
120 const B = F / 25;
121 const no_rounds = comptime x: {
122 break :x 12 + 2 * math.log2(B);
123 };
77/// The SHAKE extendable output hash function.
78pub fn Shake(comptime security_level: u11) type {
79 const f = 1600;
80 const rounds = 24;
81 const State = KeccakState(f, security_level * 2, 0x1f, rounds);
12482
125 var s = [_]u64{0} ** 25;
126 var t = [_]u64{0} ** 1;
127 var c = [_]u64{0} ** 5;
83 return struct {
84 const Self = @This();
12885
129 for (&s, 0..) |*r, i| {
130 r.* = mem.readIntLittle(u64, d[8 * i ..][0..8]);
131 }
86 st: State = .{},
87 buf: [State.rate]u8 = undefined,
88 offset: usize = 0,
89 padded: bool = false,
13290
133 for (RC[0..no_rounds]) |round| {
134 // theta
135 comptime var x: usize = 0;
136 inline while (x < 5) : (x += 1) {
137 c[x] = s[x] ^ s[x + 5] ^ s[x + 10] ^ s[x + 15] ^ s[x + 20];
91 /// The recommended output length, in bytes.
92 pub const digest_length = security_level / 2;
93 /// The block length, or rate, in bytes.
94 pub const block_length = State.rate;
95 /// Keccak does not have any options.
96 pub const Options = struct {};
97
98 /// Initialize a SHAKE extensible hash function.
99 pub fn init(options: Options) Self {
100 _ = options;
101 return Self{};
138102 }
139 x = 0;
140 inline while (x < 5) : (x += 1) {
141 t[0] = c[M5[x + 4]] ^ math.rotl(u64, c[M5[x + 1]], @as(usize, 1));
142 comptime var y: usize = 0;
143 inline while (y < 5) : (y += 1) {
144 s[x + y * 5] ^= t[0];
145 }
103
104 /// Hash a slice of bytes.
105 /// `out` can be any length.
106 pub fn hash(bytes: []const u8, out: []u8, options: Options) void {
107 var st = Self.init(options);
108 st.update(bytes);
109 st.squeeze(out);
146110 }
147111
148 // rho+pi
149 t[0] = s[1];
150 x = 0;
151 inline while (x < 24) : (x += 1) {
152 c[0] = s[PIL[x]];
153 s[PIL[x]] = math.rotl(u64, t[0], ROTC[x]);
154 t[0] = c[0];
112 /// Absorb a slice of bytes into the state.
113 pub fn update(self: *Self, bytes: []const u8) void {
114 self.st.absorb(bytes);
155115 }
156116
157 // chi
158 comptime var y: usize = 0;
159 inline while (y < 5) : (y += 1) {
160 x = 0;
161 inline while (x < 5) : (x += 1) {
162 c[x] = s[x + y * 5];
117 /// Squeeze a slice of bytes from the state.
118 /// `out` can be any length, and the function can be called multiple times.
119 pub fn squeeze(self: *Self, out_: []u8) void {
120 if (!self.padded) {
121 self.st.pad();
122 self.padded = true;
123 }
124 var out = out_;
125 if (self.offset > 0) {
126 const left = self.buf.len - self.offset;
127 if (left > 0) {
128 const n = math.min(left, out.len);
129 mem.copy(u8, out[0..n], self.buf[self.offset..][0..n]);
130 out = out[n..];
131 self.offset += n;
132 if (out.len == 0) {
133 return;
134 }
135 }
163136 }
164 x = 0;
165 inline while (x < 5) : (x += 1) {
166 s[x + y * 5] = c[x] ^ (~c[M5[x + 1]] & c[M5[x + 2]]);
137 const full_blocks = out[0 .. out.len - out.len % State.rate];
138 if (full_blocks.len > 0) {
139 self.st.squeeze(full_blocks);
140 out = out[full_blocks.len..];
141 }
142 if (out.len > 0) {
143 self.st.squeeze(self.buf[0..]);
144 mem.copy(u8, out[0..], self.buf[0..out.len]);
145 self.offset = out.len;
167146 }
168147 }
169148
170 // iota
171 s[0] ^= round;
172 }
149 /// Return the hash of the absorbed bytes.
150 /// `out` can be of any length, but the function must not be called multiple times (use `squeeze` for that purpose instead).
151 pub fn final(self: *Self, out: []u8) void {
152 self.squeeze(out);
153 self.st.st.clear(0, State.rate);
154 }
173155
174 for (s, 0..) |r, i| {
175 mem.writeIntLittle(u64, d[8 * i ..][0..8], r);
176 }
156 pub const Error = error{};
157 pub const Writer = std.io.Writer(*Self, Error, write);
158
159 fn write(self: *Self, bytes: []const u8) Error!usize {
160 self.update(bytes);
161 return bytes.len;
162 }
163
164 pub fn writer(self: *Self) Writer {
165 return .{ .context = self };
166 }
167 };
177168}
178169
170const htest = @import("test.zig");
171
179172test "sha3-224 single" {
180173 try htest.assertEqualHash(Sha3_224, "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", "");
181174 try htest.assertEqualHash(Sha3_224, "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc");
......@@ -309,13 +302,49 @@ test "sha3-512 aligned final" {
309302}
310303
311304test "keccak-256 single" {
312 try htest.assertEqualHash(Keccak_256, "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "");
313 try htest.assertEqualHash(Keccak_256, "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", "abc");
314 try htest.assertEqualHash(Keccak_256, "f519747ed599024f3882238e5ab43960132572b7345fbeb9a90769dafd21ad67", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
305 try htest.assertEqualHash(Keccak256, "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "");
306 try htest.assertEqualHash(Keccak256, "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", "abc");
307 try htest.assertEqualHash(Keccak256, "f519747ed599024f3882238e5ab43960132572b7345fbeb9a90769dafd21ad67", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
315308}
316309
317310test "keccak-512 single" {
318 try htest.assertEqualHash(Keccak_512, "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e", "");
319 try htest.assertEqualHash(Keccak_512, "18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", "abc");
320 try htest.assertEqualHash(Keccak_512, "ac2fb35251825d3aa48468a9948c0a91b8256f6d97d8fa4160faff2dd9dfcc24f3f1db7a983dad13d53439ccac0b37e24037e7b95f80f59f37a2f683c4ba4682", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
311 try htest.assertEqualHash(Keccak512, "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e", "");
312 try htest.assertEqualHash(Keccak512, "18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", "abc");
313 try htest.assertEqualHash(Keccak512, "ac2fb35251825d3aa48468a9948c0a91b8256f6d97d8fa4160faff2dd9dfcc24f3f1db7a983dad13d53439ccac0b37e24037e7b95f80f59f37a2f683c4ba4682", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
314}
315
316test "SHAKE-128 single" {
317 var out: [10]u8 = undefined;
318 Shake128.hash("hello123", &out, .{});
319 try htest.assertEqual("1b85861510bc4d8e467d", &out);
320}
321
322test "SHAKE-128 multisqueeze" {
323 var out: [10]u8 = undefined;
324 var h = Shake128.init(.{});
325 h.update("hello123");
326 h.squeeze(out[0..4]);
327 h.squeeze(out[4..]);
328 try htest.assertEqual("1b85861510bc4d8e467d", &out);
329}
330
331test "SHAKE-128 multisqueeze with multiple blocks" {
332 var out: [100]u8 = undefined;
333 var out2: [100]u8 = undefined;
334
335 var h = Shake128.init(.{});
336 h.update("hello123");
337 h.squeeze(out[0..50]);
338 h.squeeze(out[50..]);
339
340 var h2 = Shake128.init(.{});
341 h2.update("hello123");
342 h2.squeeze(&out2);
343 try std.testing.expectEqualSlices(u8, &out, &out2);
344}
345
346test "SHAKE-256 single" {
347 var out: [10]u8 = undefined;
348 Shake256.hash("hello123", &out, .{});
349 try htest.assertEqual("ade612ba265f92de4a37", &out);
321350}