aboutsummaryrefslogtreecommitdiff
path: root/lib/std/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/crypto')
-rw-r--r--lib/std/crypto/25519/field.zig2
-rw-r--r--lib/std/crypto/benchmark.zig2
-rw-r--r--lib/std/crypto/keccak_p.zig277
-rw-r--r--lib/std/crypto/sha3.zig299
4 files changed, 444 insertions, 136 deletions
diff --git a/lib/std/crypto/25519/field.zig b/lib/std/crypto/25519/field.zig
index 1a786e0c32..66a50bee70 100644
--- a/lib/std/crypto/25519/field.zig
+++ b/lib/std/crypto/25519/field.zig
@@ -287,7 +287,7 @@ pub const Fe = struct {
return _carry128(&r);
}
- inline fn _sq(a: Fe, comptime double: bool) Fe {
+ fn _sq(a: Fe, comptime double: bool) Fe {
var ax: [5]u128 = undefined;
var r: [5]u128 = undefined;
comptime var i = 0;
diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig
index 71c22f2b4c..e6e0e1fc39 100644
--- a/lib/std/crypto/benchmark.zig
+++ b/lib/std/crypto/benchmark.zig
@@ -25,6 +25,8 @@ const hashes = [_]Crypto{
Crypto{ .ty = crypto.hash.sha2.Sha512, .name = "sha512" },
Crypto{ .ty = crypto.hash.sha3.Sha3_256, .name = "sha3-256" },
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.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
new file mode 100644
index 0000000000..10367caffd
--- /dev/null
+++ b/lib/std/crypto/keccak_p.zig
@@ -0,0 +1,277 @@
+const std = @import("std");
+const assert = std.debug.assert;
+const math = std.math;
+const mem = std.mem;
+
+/// The Keccak-f permutation.
+pub fn KeccakF(comptime f: u11) type {
+ comptime assert(f > 200 and f <= 1600 and f % 200 == 0); // invalid bit size
+ const T = std.meta.Int(.unsigned, f / 25);
+ const Block = [25]T;
+
+ const PI = [_]u5{
+ 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
+ };
+
+ return struct {
+ const Self = @This();
+
+ /// Number of bytes in the state.
+ pub const block_bytes = f / 8;
+
+ /// Maximum number of rounds for the given f parameter.
+ pub const max_rounds = 12 + 2 * math.log2(f / 25);
+
+ // Round constants
+ const RC = rc: {
+ const RC64 = [_]u64{
+ 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000,
+ 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
+ 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
+ 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003,
+ 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,
+ 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
+ };
+ var rc: [max_rounds]T = undefined;
+ for (&rc, RC64[0..max_rounds]) |*t, c| t.* = @truncate(T, c);
+ break :rc rc;
+ };
+
+ st: Block = [_]T{0} ** 25,
+
+ /// Initialize the state from a slice of bytes.
+ pub fn init(bytes: [block_bytes]u8) Self {
+ var self: Self = undefined;
+ inline for (&self.st, 0..) |*r, i| {
+ r.* = mem.readIntLittle(T, bytes[@sizeOf(T) * i ..][0..@sizeOf(T)]);
+ }
+ return self;
+ }
+
+ /// A representation of the state as bytes. The byte order is architecture-dependent.
+ pub fn asBytes(self: *Self) *[block_bytes]u8 {
+ return mem.asBytes(&self.st);
+ }
+
+ /// Byte-swap the entire state if the architecture doesn't match the required endianness.
+ pub fn endianSwap(self: *Self) void {
+ for (&self.st) |*w| {
+ w.* = mem.littleTooNative(T, w.*);
+ }
+ }
+
+ /// Set bytes starting at the beginning of the state.
+ pub fn setBytes(self: *Self, bytes: []const u8) void {
+ var i: usize = 0;
+ while (i + @sizeOf(T) <= bytes.len) : (i += @sizeOf(T)) {
+ self.st[i / @sizeOf(T)] = mem.readIntLittle(T, bytes[i..][0..@sizeOf(T)]);
+ }
+ if (i < bytes.len) {
+ var padded = [_]u8{0} ** @sizeOf(T);
+ mem.copy(u8, padded[0 .. bytes.len - i], bytes[i..]);
+ self.st[i / @sizeOf(T)] = mem.readIntLittle(T, padded[0..]);
+ }
+ }
+
+ /// XOR a byte into the state at a given offset.
+ pub fn addByte(self: *Self, byte: u8, offset: usize) void {
+ const z = @sizeOf(T) * @truncate(math.Log2Int(T), offset % @sizeOf(T));
+ self.st[offset / @sizeOf(T)] ^= @as(T, byte) << z;
+ }
+
+ /// XOR bytes into the beginning of the state.
+ pub fn addBytes(self: *Self, bytes: []const u8) void {
+ var i: usize = 0;
+ while (i + @sizeOf(T) <= bytes.len) : (i += @sizeOf(T)) {
+ self.st[i / @sizeOf(T)] ^= mem.readIntLittle(T, bytes[i..][0..@sizeOf(T)]);
+ }
+ if (i < bytes.len) {
+ var padded = [_]u8{0} ** @sizeOf(T);
+ mem.copy(u8, padded[0 .. bytes.len - i], bytes[i..]);
+ self.st[i / @sizeOf(T)] ^= mem.readIntLittle(T, padded[0..]);
+ }
+ }
+
+ /// Extract the first bytes of the state.
+ pub fn extractBytes(self: *Self, out: []u8) void {
+ var i: usize = 0;
+ while (i + @sizeOf(T) <= out.len) : (i += @sizeOf(T)) {
+ mem.writeIntLittle(T, out[i..][0..@sizeOf(T)], self.st[i / @sizeOf(T)]);
+ }
+ if (i < out.len) {
+ var padded = [_]u8{0} ** @sizeOf(T);
+ mem.writeIntLittle(T, padded[0..], self.st[i / @sizeOf(T)]);
+ mem.copy(u8, out[i..], padded[0 .. out.len - i]);
+ }
+ }
+
+ /// XOR the first bytes of the state into a slice of bytes.
+ pub fn xorBytes(self: *Self, out: []u8, in: []const u8) void {
+ assert(out.len == in.len);
+
+ var i: usize = 0;
+ while (i + @sizeOf(T) <= in.len) : (i += @sizeOf(T)) {
+ const x = mem.readIntNative(T, in[i..][0..@sizeOf(T)]) ^ mem.nativeToLittle(T, self.st[i / @sizeOf(T)]);
+ mem.writeIntNative(T, out[i..][0..@sizeOf(T)], x);
+ }
+ if (i < in.len) {
+ var padded = [_]u8{0} ** @sizeOf(T);
+ mem.copy(u8, padded[0 .. in.len - i], in[i..]);
+ const x = mem.readIntNative(T, &padded) ^ mem.nativeToLittle(T, self.st[i / @sizeOf(T)]);
+ mem.writeIntNative(T, &padded, x);
+ mem.copy(u8, out[i..], padded[0 .. in.len - i]);
+ }
+ }
+
+ /// Set the words storing the bytes of a given range to zero.
+ pub fn clear(self: *Self, from: usize, to: usize) void {
+ mem.set(T, self.st[from / @sizeOf(T) .. (to + @sizeOf(T) - 1) / @sizeOf(T)], 0);
+ }
+
+ /// Clear the entire state, disabling compiler optimizations.
+ pub fn secureZero(self: *Self) void {
+ std.crypto.utils.secureZero(T, &self.st);
+ }
+
+ inline fn round(self: *Self, rc: T) void {
+ const st = &self.st;
+
+ // theta
+ var t = [_]T{0} ** 5;
+ inline for (0..5) |i| {
+ inline for (0..5) |j| {
+ t[i] ^= st[j * 5 + i];
+ }
+ }
+ inline for (0..5) |i| {
+ inline for (0..5) |j| {
+ st[j * 5 + i] ^= t[(i + 4) % 5] ^ math.rotl(T, t[(i + 1) % 5], 1);
+ }
+ }
+
+ // rho+pi
+ var last = st[1];
+ comptime var rotc = 0;
+ inline for (0..24) |i| {
+ const x = PI[i];
+ const tmp = st[x];
+ rotc = (rotc + i + 1) % @bitSizeOf(T);
+ st[x] = math.rotl(T, last, rotc);
+ last = tmp;
+ }
+ inline for (0..5) |i| {
+ inline for (0..5) |j| {
+ t[j] = st[i * 5 + j];
+ }
+ inline for (0..5) |j| {
+ st[i * 5 + j] = t[j] ^ (~t[(j + 1) % 5] & t[(j + 2) % 5]);
+ }
+ }
+
+ // iota
+ st[0] ^= rc;
+ }
+
+ /// 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) {
+ self.round(RC[i]);
+ self.round(RC[i + 1]);
+ self.round(RC[i + 2]);
+ }
+ while (i < rounds) : (i += 1) {
+ self.round(RC[i]);
+ }
+ }
+
+ /// Apply a full-round permutation to the state.
+ pub fn permute(self: *Self) void {
+ self.permuteR(max_rounds);
+ }
+ };
+}
+
+/// A generic Keccak-P state.
+pub fn State(comptime f: u11, comptime capacity: u11, comptime delim: u8, comptime rounds: u5) type {
+ comptime assert(f > 200 and f <= 1600 and f % 200 == 0); // invalid state size
+ comptime assert(capacity < f and capacity % 8 == 0); // invalid capacity size
+
+ return struct {
+ const Self = @This();
+
+ /// The block length, or rate, in bytes.
+ pub const rate = KeccakF(f).block_bytes - capacity / 8;
+ /// Keccak does not have any options.
+ pub const Options = struct {};
+
+ offset: usize = 0,
+ buf: [rate]u8 = undefined,
+
+ st: KeccakF(f) = .{},
+
+ /// Absorb a slice of bytes into the sponge.
+ pub fn absorb(self: *Self, bytes_: []const u8) void {
+ var bytes = bytes_;
+ if (self.offset > 0) {
+ const left = math.min(rate - self.offset, bytes.len);
+ mem.copy(u8, self.buf[self.offset..], bytes[0..left]);
+ self.offset += left;
+ if (self.offset == rate) {
+ self.offset = 0;
+ self.st.addBytes(self.buf[0..]);
+ self.st.permuteR(rounds);
+ }
+ if (left == bytes.len) return;
+ bytes = bytes[left..];
+ }
+ while (bytes.len >= rate) {
+ self.st.addBytes(bytes[0..rate]);
+ self.st.permuteR(rounds);
+ bytes = bytes[rate..];
+ }
+ if (bytes.len > 0) {
+ self.st.addBytes(bytes[0..]);
+ self.offset = bytes.len;
+ }
+ }
+
+ /// Mark the end of the input.
+ pub fn pad(self: *Self) void {
+ self.st.addBytes(self.buf[0..self.offset]);
+ self.st.addByte(delim, self.offset);
+ self.st.addByte(0x80, rate - 1);
+ self.st.permuteR(rounds);
+ self.offset = 0;
+ }
+
+ /// Squeeze a slice of bytes from the sponge.
+ pub fn squeeze(self: *Self, out: []u8) void {
+ var i: usize = 0;
+ while (i < out.len) : (i += rate) {
+ const left = math.min(rate, out.len - i);
+ self.st.extractBytes(out[i..][0..left]);
+ self.st.permuteR(rounds);
+ }
+ }
+ };
+}
+
+test "Keccak-f800" {
+ var st: KeccakF(800) = .{
+ .st = .{
+ 0xE531D45D, 0xF404C6FB, 0x23A0BF99, 0xF1F8452F, 0x51FFD042, 0xE539F578, 0xF00B80A7,
+ 0xAF973664, 0xBF5AF34C, 0x227A2424, 0x88172715, 0x9F685884, 0xB15CD054, 0x1BF4FC0E,
+ 0x6166FA91, 0x1A9E599A, 0xA3970A1F, 0xAB659687, 0xAFAB8D68, 0xE74B1015, 0x34001A98,
+ 0x4119EFF3, 0x930A0E76, 0x87B28070, 0x11EFE996,
+ },
+ };
+ st.permute();
+ const expected: [25]u32 = .{
+ 0x75BF2D0D, 0x9B610E89, 0xC826AF40, 0x64CD84AB, 0xF905BDD6, 0xBC832835, 0x5F8001B9,
+ 0x15662CCE, 0x8E38C95E, 0x701FE543, 0x1B544380, 0x89ACDEFF, 0x51EDB5DE, 0x0E9702D9,
+ 0x6C19AA16, 0xA2913EEE, 0x60754E9A, 0x9819063C, 0xF4709254, 0xD09F9084, 0x772DA259,
+ 0x1DB35DF7, 0x5AA60162, 0x358825D5, 0xB3783BAB,
+ };
+ try std.testing.expectEqualSlices(u32, &st.st, &expected);
+}
diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig
index c2801a4709..985027f3ee 100644
--- a/lib/std/crypto/sha3.zig
+++ b/lib/std/crypto/sha3.zig
@@ -1,84 +1,63 @@
-const std = @import("../std.zig");
-const mem = std.mem;
+const std = @import("std");
+const assert = std.debug.assert;
const math = std.math;
-const debug = std.debug;
-const htest = @import("test.zig");
+const mem = std.mem;
+
+const KeccakState = std.crypto.core.keccak.State;
+
+pub const Sha3_224 = Keccak(1600, 224, 0x06, 24);
+pub const Sha3_256 = Keccak(1600, 256, 0x06, 24);
+pub const Sha3_384 = Keccak(1600, 384, 0x06, 24);
+pub const Sha3_512 = Keccak(1600, 512, 0x06, 24);
+
+pub const Keccak256 = Keccak(1600, 256, 0x01, 24);
+pub const Keccak512 = Keccak(1600, 512, 0x01, 24);
+pub const Keccak_256 = @compileError("Deprecated: use `Keccak256` instead");
+pub const Keccak_512 = @compileError("Deprecated: use `Keccak512` instead");
+
+pub const Shake128 = Shake(128);
+pub const Shake256 = Shake(256);
+
+/// 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
-pub const Sha3_224 = Keccak(224, 0x06);
-pub const Sha3_256 = Keccak(256, 0x06);
-pub const Sha3_384 = Keccak(384, 0x06);
-pub const Sha3_512 = Keccak(512, 0x06);
-pub const Keccak_256 = Keccak(256, 0x01);
-pub const Keccak_512 = Keccak(512, 0x01);
+ const State = KeccakState(f, output_bits * 2, delim, rounds);
-fn Keccak(comptime bits: usize, comptime delim: u8) type {
return struct {
const Self = @This();
+
+ st: State = .{},
+
/// The output length, in bytes.
- pub const digest_length = bits / 8;
+ pub const digest_length = output_bits / 8;
/// The block length, or rate, in bytes.
- pub const block_length = 200 - bits / 4;
+ pub const block_length = State.rate;
/// Keccak does not have any options.
pub const Options = struct {};
- s: [200]u8,
- offset: usize,
-
+ /// Initialize a Keccak hash function.
pub fn init(options: Options) Self {
_ = options;
- return Self{ .s = [_]u8{0} ** 200, .offset = 0 };
+ return Self{};
}
- pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
- var d = Self.init(options);
- d.update(b);
- d.final(out);
+ /// Hash a slice of bytes.
+ pub fn hash(bytes: []const u8, out: *[digest_length]u8, options: Options) void {
+ var st = Self.init(options);
+ st.update(bytes);
+ st.final(out);
}
- pub fn update(d: *Self, b: []const u8) void {
- var ip: usize = 0;
- var len = b.len;
- var rate = block_length - d.offset;
- var offset = d.offset;
-
- // absorb
- while (len >= rate) {
- for (d.s[offset .. offset + rate], 0..) |*r, i|
- r.* ^= b[ip..][i];
-
- keccakF(1600, &d.s);
-
- ip += rate;
- len -= rate;
- rate = block_length;
- offset = 0;
- }
-
- for (d.s[offset .. offset + len], 0..) |*r, i|
- r.* ^= b[ip..][i];
-
- d.offset = offset + len;
+ /// Absorb a slice of bytes into the state.
+ pub fn update(self: *Self, bytes: []const u8) void {
+ self.st.absorb(bytes);
}
- pub fn final(d: *Self, out: *[digest_length]u8) void {
- // padding
- d.s[d.offset] ^= delim;
- d.s[block_length - 1] ^= 0x80;
-
- keccakF(1600, &d.s);
-
- // squeeze
- var op: usize = 0;
- var len: usize = bits / 8;
-
- while (len >= block_length) {
- mem.copy(u8, out[op..], d.s[0..block_length]);
- keccakF(1600, &d.s);
- op += block_length;
- len -= block_length;
- }
-
- mem.copy(u8, out[op..], d.s[0..len]);
+ /// Return the hash of the absorbed bytes.
+ pub fn final(self: *Self, out: *[digest_length]u8) void {
+ self.st.pad();
+ self.st.squeeze(out[0..]);
}
pub const Error = error{};
@@ -95,87 +74,101 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type {
};
}
-const RC = [_]u64{
- 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000,
- 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
- 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
- 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003,
- 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,
- 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
-};
-
-const ROTC = [_]usize{
- 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
-};
-
-const PIL = [_]usize{
- 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
-};
-
-const M5 = [_]usize{
- 0, 1, 2, 3, 4, 0, 1, 2, 3, 4,
-};
-
-fn keccakF(comptime F: usize, d: *[F / 8]u8) void {
- const B = F / 25;
- const no_rounds = comptime x: {
- break :x 12 + 2 * math.log2(B);
- };
+/// The SHAKE extendable output hash function.
+pub fn Shake(comptime security_level: u11) type {
+ const f = 1600;
+ const rounds = 24;
+ const State = KeccakState(f, security_level * 2, 0x1f, rounds);
- var s = [_]u64{0} ** 25;
- var t = [_]u64{0} ** 1;
- var c = [_]u64{0} ** 5;
+ return struct {
+ const Self = @This();
- for (&s, 0..) |*r, i| {
- r.* = mem.readIntLittle(u64, d[8 * i ..][0..8]);
- }
+ st: State = .{},
+ buf: [State.rate]u8 = undefined,
+ offset: usize = 0,
+ padded: bool = false,
- for (RC[0..no_rounds]) |round| {
- // theta
- comptime var x: usize = 0;
- inline while (x < 5) : (x += 1) {
- c[x] = s[x] ^ s[x + 5] ^ s[x + 10] ^ s[x + 15] ^ s[x + 20];
+ /// The recommended output length, in bytes.
+ pub const digest_length = security_level / 2;
+ /// The block length, or rate, in bytes.
+ pub const block_length = State.rate;
+ /// Keccak does not have any options.
+ pub const Options = struct {};
+
+ /// Initialize a SHAKE extensible hash function.
+ pub fn init(options: Options) Self {
+ _ = options;
+ return Self{};
}
- x = 0;
- inline while (x < 5) : (x += 1) {
- t[0] = c[M5[x + 4]] ^ math.rotl(u64, c[M5[x + 1]], @as(usize, 1));
- comptime var y: usize = 0;
- inline while (y < 5) : (y += 1) {
- s[x + y * 5] ^= t[0];
- }
+
+ /// Hash a slice of bytes.
+ /// `out` can be any length.
+ pub fn hash(bytes: []const u8, out: []u8, options: Options) void {
+ var st = Self.init(options);
+ st.update(bytes);
+ st.squeeze(out);
}
- // rho+pi
- t[0] = s[1];
- x = 0;
- inline while (x < 24) : (x += 1) {
- c[0] = s[PIL[x]];
- s[PIL[x]] = math.rotl(u64, t[0], ROTC[x]);
- t[0] = c[0];
+ /// Absorb a slice of bytes into the state.
+ pub fn update(self: *Self, bytes: []const u8) void {
+ self.st.absorb(bytes);
}
- // chi
- comptime var y: usize = 0;
- inline while (y < 5) : (y += 1) {
- x = 0;
- inline while (x < 5) : (x += 1) {
- c[x] = s[x + y * 5];
+ /// Squeeze a slice of bytes from the state.
+ /// `out` can be any length, and the function can be called multiple times.
+ pub fn squeeze(self: *Self, out_: []u8) void {
+ if (!self.padded) {
+ self.st.pad();
+ self.padded = true;
+ }
+ var out = out_;
+ if (self.offset > 0) {
+ const left = self.buf.len - self.offset;
+ if (left > 0) {
+ const n = math.min(left, out.len);
+ mem.copy(u8, out[0..n], self.buf[self.offset..][0..n]);
+ out = out[n..];
+ self.offset += n;
+ if (out.len == 0) {
+ return;
+ }
+ }
}
- x = 0;
- inline while (x < 5) : (x += 1) {
- s[x + y * 5] = c[x] ^ (~c[M5[x + 1]] & c[M5[x + 2]]);
+ const full_blocks = out[0 .. out.len - out.len % State.rate];
+ if (full_blocks.len > 0) {
+ self.st.squeeze(full_blocks);
+ out = out[full_blocks.len..];
+ }
+ if (out.len > 0) {
+ self.st.squeeze(self.buf[0..]);
+ mem.copy(u8, out[0..], self.buf[0..out.len]);
+ self.offset = out.len;
}
}
- // iota
- s[0] ^= round;
- }
+ /// Return the hash of the absorbed bytes.
+ /// `out` can be of any length, but the function must not be called multiple times (use `squeeze` for that purpose instead).
+ pub fn final(self: *Self, out: []u8) void {
+ self.squeeze(out);
+ self.st.st.clear(0, State.rate);
+ }
- for (s, 0..) |r, i| {
- mem.writeIntLittle(u64, d[8 * i ..][0..8], r);
- }
+ pub const Error = error{};
+ pub const Writer = std.io.Writer(*Self, Error, write);
+
+ fn write(self: *Self, bytes: []const u8) Error!usize {
+ self.update(bytes);
+ return bytes.len;
+ }
+
+ pub fn writer(self: *Self) Writer {
+ return .{ .context = self };
+ }
+ };
}
+const htest = @import("test.zig");
+
test "sha3-224 single" {
try htest.assertEqualHash(Sha3_224, "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", "");
try htest.assertEqualHash(Sha3_224, "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc");
@@ -309,13 +302,49 @@ test "sha3-512 aligned final" {
}
test "keccak-256 single" {
- try htest.assertEqualHash(Keccak_256, "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "");
- try htest.assertEqualHash(Keccak_256, "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", "abc");
- try htest.assertEqualHash(Keccak_256, "f519747ed599024f3882238e5ab43960132572b7345fbeb9a90769dafd21ad67", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
+ try htest.assertEqualHash(Keccak256, "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "");
+ try htest.assertEqualHash(Keccak256, "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", "abc");
+ try htest.assertEqualHash(Keccak256, "f519747ed599024f3882238e5ab43960132572b7345fbeb9a90769dafd21ad67", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
}
test "keccak-512 single" {
- try htest.assertEqualHash(Keccak_512, "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e", "");
- try htest.assertEqualHash(Keccak_512, "18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", "abc");
- try htest.assertEqualHash(Keccak_512, "ac2fb35251825d3aa48468a9948c0a91b8256f6d97d8fa4160faff2dd9dfcc24f3f1db7a983dad13d53439ccac0b37e24037e7b95f80f59f37a2f683c4ba4682", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
+ try htest.assertEqualHash(Keccak512, "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e", "");
+ try htest.assertEqualHash(Keccak512, "18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", "abc");
+ try htest.assertEqualHash(Keccak512, "ac2fb35251825d3aa48468a9948c0a91b8256f6d97d8fa4160faff2dd9dfcc24f3f1db7a983dad13d53439ccac0b37e24037e7b95f80f59f37a2f683c4ba4682", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
+}
+
+test "SHAKE-128 single" {
+ var out: [10]u8 = undefined;
+ Shake128.hash("hello123", &out, .{});
+ try htest.assertEqual("1b85861510bc4d8e467d", &out);
+}
+
+test "SHAKE-128 multisqueeze" {
+ var out: [10]u8 = undefined;
+ var h = Shake128.init(.{});
+ h.update("hello123");
+ h.squeeze(out[0..4]);
+ h.squeeze(out[4..]);
+ try htest.assertEqual("1b85861510bc4d8e467d", &out);
+}
+
+test "SHAKE-128 multisqueeze with multiple blocks" {
+ var out: [100]u8 = undefined;
+ var out2: [100]u8 = undefined;
+
+ var h = Shake128.init(.{});
+ h.update("hello123");
+ h.squeeze(out[0..50]);
+ h.squeeze(out[50..]);
+
+ var h2 = Shake128.init(.{});
+ h2.update("hello123");
+ h2.squeeze(&out2);
+ try std.testing.expectEqualSlices(u8, &out, &out2);
+}
+
+test "SHAKE-256 single" {
+ var out: [10]u8 = undefined;
+ Shake256.hash("hello123", &out, .{});
+ try htest.assertEqual("ade612ba265f92de4a37", &out);
}