From fc55cd458a7cd72ea876cf747b1ddd43d8dc6e20 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 21 Aug 2020 00:51:14 +0200 Subject: [PATCH] Hash functions now accept an option set - This avoids having multiple `init()` functions for every combination of optional parameters - The API is consistent across all hash functions - New options can be added later without breaking existing applications. For example, this is going to come in handy if we implement parallelization for BLAKE2 and BLAKE3. - We don't have a mix of snake_case and camelCase functions any more, at least in the public crypto API Support for BLAKE2 salt and personalization (more commonly called context) parameters have been implemented by the way to illustrate this. --- lib/std/bloom_filter.zig | 2 +- lib/std/cache_hash.zig | 10 +- lib/std/crypto.zig | 2 +- lib/std/crypto/25519/ed25519.zig | 10 +- lib/std/crypto/benchmark.zig | 2 +- lib/std/crypto/blake2.zig | 157 +++++++++++++++++++------------ lib/std/crypto/blake3.zig | 34 +++---- lib/std/crypto/gimli.zig | 9 +- lib/std/crypto/hmac.zig | 6 +- lib/std/crypto/md5.zig | 15 +-- lib/std/crypto/sha1.zig | 15 +-- lib/std/crypto/sha2.zig | 42 +++++---- lib/std/crypto/sha3.zig | 35 +++---- lib/std/crypto/test.zig | 2 +- lib/std/zig.zig | 2 +- 15 files changed, 194 insertions(+), 149 deletions(-) diff --git a/lib/std/bloom_filter.zig b/lib/std/bloom_filter.zig index 5ccef8d140..0e251f548f 100644 --- a/lib/std/bloom_filter.zig +++ b/lib/std/bloom_filter.zig @@ -158,7 +158,7 @@ pub fn BloomFilter( } fn hashFunc(out: []u8, Ki: usize, in: []const u8) void { - var st = std.crypto.hash.Gimli.init(); + var st = std.crypto.hash.Gimli.init(.{}); st.update(std.mem.asBytes(&Ki)); st.update(in); st.final(out); diff --git a/lib/std/cache_hash.zig b/lib/std/cache_hash.zig index 8025929347..edd0ebf126 100644 --- a/lib/std/cache_hash.zig +++ b/lib/std/cache_hash.zig @@ -56,7 +56,7 @@ pub const CacheHash = struct { pub fn init(allocator: *Allocator, dir: fs.Dir, manifest_dir_path: []const u8) !CacheHash { return CacheHash{ .allocator = allocator, - .blake3 = Blake3.init(), + .blake3 = Blake3.init(.{}), .manifest_dir = try dir.makeOpenPath(manifest_dir_path, .{}), .manifest_file = null, .manifest_dirty = false, @@ -137,7 +137,7 @@ pub const CacheHash = struct { base64_encoder.encode(self.b64_digest[0..], &bin_digest); - self.blake3 = Blake3.init(); + self.blake3 = Blake3.init(.{}); self.blake3.update(&bin_digest); const manifest_file_path = try fmt.allocPrint(self.allocator, "{}.txt", .{self.b64_digest}); @@ -256,7 +256,7 @@ pub const CacheHash = struct { // cache miss // keep the manifest file open // reset the hash - self.blake3 = Blake3.init(); + self.blake3 = Blake3.init(.{}); self.blake3.update(&bin_digest); // Remove files not in the initial hash @@ -304,7 +304,7 @@ pub const CacheHash = struct { // Hash while reading from disk, to keep the contents in the cpu cache while // doing hashing. - var blake3 = Blake3.init(); + var blake3 = Blake3.init(.{}); var off: usize = 0; while (true) { // give me everything you've got, captain @@ -434,7 +434,7 @@ pub const CacheHash = struct { }; fn hashFile(file: fs.File, bin_digest: []u8) !void { - var blake3 = Blake3.init(); + var blake3 = Blake3.init(.{}); var buf: [1024]u8 = undefined; while (true) { diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig index bb55f52a40..32ab5071c5 100644 --- a/lib/std/crypto.zig +++ b/lib/std/crypto.zig @@ -112,7 +112,7 @@ test "issue #4532: no index out of bounds" { var block = [_]u8{'#'} ** Hasher.block_length; var out1: [Hasher.digest_length]u8 = undefined; var out2: [Hasher.digest_length]u8 = undefined; - const h0 = Hasher.init(); + const h0 = Hasher.init(.{}); var h = h0; h.update(block[0..]); h.final(out1[0..]); diff --git a/lib/std/crypto/25519/ed25519.zig b/lib/std/crypto/25519/ed25519.zig index d02fa0a2fd..9993afb6d2 100644 --- a/lib/std/crypto/25519/ed25519.zig +++ b/lib/std/crypto/25519/ed25519.zig @@ -33,7 +33,7 @@ pub const Ed25519 = struct { /// from which the actual secret is derived. pub fn createKeyPair(seed: [seed_length]u8) ![keypair_length]u8 { var az: [Sha512.digest_length]u8 = undefined; - var h = Sha512.init(); + var h = Sha512.init(.{}); h.update(&seed); h.final(&az); const p = try Curve.basePoint.clampedMul(az[0..32].*); @@ -56,11 +56,11 @@ pub const Ed25519 = struct { pub fn sign(msg: []const u8, key_pair: [keypair_length]u8, noise: ?[noise_length]u8) ![signature_length]u8 { const public_key = key_pair[32..]; var az: [Sha512.digest_length]u8 = undefined; - var h = Sha512.init(); + var h = Sha512.init(.{}); h.update(key_pair[0..seed_length]); h.final(&az); - h = Sha512.init(); + h = Sha512.init(.{}); if (noise) |*z| { h.update(z); } @@ -74,7 +74,7 @@ pub const Ed25519 = struct { var sig: [signature_length]u8 = undefined; mem.copy(u8, sig[0..32], &r.toBytes()); mem.copy(u8, sig[32..], public_key); - h = Sha512.init(); + h = Sha512.init(.{}); h.update(&sig); h.update(msg); var hram64: [Sha512.digest_length]u8 = undefined; @@ -98,7 +98,7 @@ pub const Ed25519 = struct { const a = try Curve.fromBytes(public_key); try a.rejectIdentity(); - var h = Sha512.init(); + var h = Sha512.init(.{}); h.update(r); h.update(&public_key); h.update(msg); diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig index 681739e1bd..70bd30d6bb 100644 --- a/lib/std/crypto/benchmark.zig +++ b/lib/std/crypto/benchmark.zig @@ -35,7 +35,7 @@ const hashes = [_]Crypto{ }; pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 { - var h = Hash.init(); + var h = Hash.init(.{}); var block: [Hash.digest_length]u8 = undefined; prng.random.bytes(block[0..]); diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index bb07390286..1cb143811c 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -40,6 +40,7 @@ pub fn Blake2s(comptime out_len: usize) type { const Self = @This(); pub const block_length = 64; pub const digest_length = out_len / 8; + pub const Options = struct { key: ?[]const u8 = null, salt: ?[8]u8 = null, context: ?[8]u8 = null }; const iv = [8]u32{ 0x6A09E667, @@ -71,35 +72,36 @@ pub fn Blake2s(comptime out_len: usize) type { buf: [64]u8, buf_len: u8, - pub fn init() Self { - return init_keyed(""); - } - - pub fn init_keyed(key: []const u8) Self { + pub fn init(options: Options) Self { debug.assert(8 <= out_len and out_len <= 512); var d: Self = undefined; mem.copy(u32, d.h[0..], iv[0..]); + const key_len = if (options.key) |key| key.len else 0; // default parameters - d.h[0] ^= 0x01010000 ^ @truncate(u32, key.len << 8) ^ @intCast(u32, out_len >> 3); + d.h[0] ^= 0x01010000 ^ @truncate(u32, key_len << 8) ^ @intCast(u32, out_len >> 3); d.t = 0; d.buf_len = 0; - if (key.len > 0) { - mem.set(u8, d.buf[key.len..], 0); - d.update(key); + if (options.salt) |salt| { + d.h[4] ^= mem.readIntLittle(u32, salt[0..4]); + d.h[5] ^= mem.readIntLittle(u32, salt[4..8]); + } + if (options.context) |context| { + d.h[6] ^= mem.readIntLittle(u32, context[0..4]); + d.h[7] ^= mem.readIntLittle(u32, context[4..8]); + } + if (key_len > 0) { + mem.set(u8, d.buf[key_len..], 0); + d.update(options.key.?); d.buf_len = 64; } return d; } - pub fn hash(b: []const u8, out: []u8) void { - Self.hash_keyed("", b, out); - } - - pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void { - var d = Self.init_keyed(key); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Self.init(options); d.update(b); d.final(out); } @@ -208,7 +210,7 @@ test "blake2s224 single" { } test "blake2s224 streaming" { - var h = Blake2s224.init(); + var h = Blake2s224.init(.{}); var out: [28]u8 = undefined; const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4"; @@ -218,12 +220,12 @@ test "blake2s224 streaming" { const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55"; - h = Blake2s224.init(); + h = Blake2s224.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Blake2s224.init(); + h = Blake2s224.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -232,16 +234,29 @@ test "blake2s224 streaming" { const h3 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01"; - h = Blake2s224.init(); + h = Blake2s224.init(.{}); h.update("a" ** 32); h.update("b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h = Blake2s224.init(); + h = Blake2s224.init(.{}); h.update("a" ** 32 ++ "b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); + + const h4 = "a4d6a9d253441b80e5dfd60a04db169ffab77aec56a2855c402828c3"; + + h = Blake2s224.init(.{ .context = [_]u8{0x69} ** 8, .salt = [_]u8{0x42} ** 8 }); + h.update("a" ** 32); + h.update("b" ** 32); + h.final(out[0..]); + htest.assertEqual(h4, out[0..]); + + h = Blake2s224.init(.{ .context = [_]u8{0x69} ** 8, .salt = [_]u8{0x42} ** 8 }); + h.update("a" ** 32 ++ "b" ** 32); + h.final(out[0..]); + htest.assertEqual(h4, out[0..]); } test "comptime blake2s224" { @@ -254,7 +269,7 @@ test "comptime blake2s224" { htest.assertEqualHash(Blake2s224, h1, block[0..]); - var h = Blake2s224.init(); + var h = Blake2s224.init(.{}); h.update(&block); h.final(out[0..]); @@ -277,7 +292,7 @@ test "blake2s256 single" { } test "blake2s256 streaming" { - var h = Blake2s256.init(); + var h = Blake2s256.init(.{}); var out: [32]u8 = undefined; const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9"; @@ -287,12 +302,12 @@ test "blake2s256 streaming" { const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"; - h = Blake2s256.init(); + h = Blake2s256.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Blake2s256.init(); + h = Blake2s256.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -301,13 +316,13 @@ test "blake2s256 streaming" { const h3 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977"; - h = Blake2s256.init(); + h = Blake2s256.init(.{}); h.update("a" ** 32); h.update("b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h = Blake2s256.init(); + h = Blake2s256.init(.{}); h.update("a" ** 32 ++ "b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); @@ -319,16 +334,16 @@ test "blake2s256 keyed" { const h1 = "10f918da4d74fab3302e48a5d67d03804b1ec95372a62a0f33b7c9fa28ba1ae6"; const key = "secret_key"; - Blake2s256.hash_keyed(key, "a" ** 64 ++ "b" ** 64, &out); + Blake2s256.hash("a" ** 64 ++ "b" ** 64, &out, .{ .key = key }); htest.assertEqual(h1, out[0..]); - var h = Blake2s256.init_keyed(key); + var h = Blake2s256.init(.{ .key = key }); h.update("a" ** 64 ++ "b" ** 64); h.final(out[0..]); htest.assertEqual(h1, out[0..]); - h = Blake2s256.init_keyed(key); + h = Blake2s256.init(.{ .key = key }); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); @@ -346,7 +361,7 @@ test "comptime blake2s256" { htest.assertEqualHash(Blake2s256, h1, block[0..]); - var h = Blake2s256.init(); + var h = Blake2s256.init(.{}); h.update(&block); h.final(out[0..]); @@ -366,6 +381,7 @@ pub fn Blake2b(comptime out_len: usize) type { const Self = @This(); pub const block_length = 128; pub const digest_length = out_len / 8; + pub const Options = struct { key: ?[]const u8 = null, salt: ?[16]u8 = null, context: ?[16]u8 = null }; const iv = [8]u64{ 0x6a09e667f3bcc908, @@ -399,35 +415,36 @@ pub fn Blake2b(comptime out_len: usize) type { buf: [128]u8, buf_len: u8, - pub fn init() Self { - return init_keyed(""); - } - - pub fn init_keyed(key: []const u8) Self { + pub fn init(options: Options) Self { debug.assert(8 <= out_len and out_len <= 512); var d: Self = undefined; mem.copy(u64, d.h[0..], iv[0..]); + const key_len = if (options.key) |key| key.len else 0; // default parameters - d.h[0] ^= 0x01010000 ^ (key.len << 8) ^ (out_len >> 3); + d.h[0] ^= 0x01010000 ^ (key_len << 8) ^ (out_len >> 3); d.t = 0; d.buf_len = 0; - if (key.len > 0) { - mem.set(u8, d.buf[key.len..], 0); - d.update(key); + if (options.salt) |salt| { + d.h[4] ^= mem.readIntLittle(u64, salt[0..8]); + d.h[5] ^= mem.readIntLittle(u64, salt[8..16]); + } + if (options.context) |context| { + d.h[6] ^= mem.readIntLittle(u64, context[0..8]); + d.h[7] ^= mem.readIntLittle(u64, context[8..16]); + } + if (key_len > 0) { + mem.set(u8, d.buf[key_len..], 0); + d.update(options.key.?); d.buf_len = 128; } return d; } - pub fn hash(b: []const u8, out: []u8) void { - Self.hash_keyed("", b, out); - } - - pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void { - var d = Self.init_keyed(key); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Self.init(options); d.update(b); d.final(out); } @@ -534,7 +551,7 @@ test "blake2b384 single" { } test "blake2b384 streaming" { - var h = Blake2b384.init(); + var h = Blake2b384.init(.{}); var out: [48]u8 = undefined; const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100"; @@ -544,12 +561,12 @@ test "blake2b384 streaming" { const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4"; - h = Blake2b384.init(); + h = Blake2b384.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Blake2b384.init(); + h = Blake2b384.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -558,16 +575,36 @@ test "blake2b384 streaming" { const h3 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c"; - h = Blake2b384.init(); + h = Blake2b384.init(.{}); h.update("a" ** 64 ++ "b" ** 64); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h = Blake2b384.init(); + h = Blake2b384.init(.{}); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); htest.assertEqual(h3, out[0..]); + + h = Blake2b384.init(.{}); + h.update("a" ** 64); + h.update("b" ** 64); + h.final(out[0..]); + htest.assertEqual(h3, out[0..]); + + const h4 = "934c48fcb197031c71f583d92f98703510805e72142e0b46f5752d1e971bc86c355d556035613ff7a4154b4de09dac5c"; + + h = Blake2b384.init(.{ .context = [_]u8{0x69} ** 16, .salt = [_]u8{0x42} ** 16 }); + h.update("a" ** 64); + h.update("b" ** 64); + h.final(out[0..]); + htest.assertEqual(h4, out[0..]); + + h = Blake2b384.init(.{ .context = [_]u8{0x69} ** 16, .salt = [_]u8{0x42} ** 16 }); + h.update("a" ** 64); + h.update("b" ** 64); + h.final(out[0..]); + htest.assertEqual(h4, out[0..]); } test "comptime blake2b384" { @@ -580,7 +617,7 @@ test "comptime blake2b384" { htest.assertEqualHash(Blake2b384, h1, block[0..]); - var h = Blake2b384.init(); + var h = Blake2b384.init(.{}); h.update(&block); h.final(out[0..]); @@ -603,7 +640,7 @@ test "blake2b512 single" { } test "blake2b512 streaming" { - var h = Blake2b512.init(); + var h = Blake2b512.init(.{}); var out: [64]u8 = undefined; const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce"; @@ -613,12 +650,12 @@ test "blake2b512 streaming" { const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"; - h = Blake2b512.init(); + h = Blake2b512.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Blake2b512.init(); + h = Blake2b512.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -627,12 +664,12 @@ test "blake2b512 streaming" { const h3 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920"; - h = Blake2b512.init(); + h = Blake2b512.init(.{}); h.update("a" ** 64 ++ "b" ** 64); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h = Blake2b512.init(); + h = Blake2b512.init(.{}); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); @@ -645,16 +682,16 @@ test "blake2b512 keyed" { const h1 = "8a978060ccaf582f388f37454363071ac9a67e3a704585fd879fb8a419a447e389c7c6de790faa20a7a7dccf197de736bc5b40b98a930b36df5bee7555750c4d"; const key = "secret_key"; - Blake2b512.hash_keyed(key, "a" ** 64 ++ "b" ** 64, &out); + Blake2b512.hash("a" ** 64 ++ "b" ** 64, &out, .{ .key = key }); htest.assertEqual(h1, out[0..]); - var h = Blake2b512.init_keyed(key); + var h = Blake2b512.init(.{ .key = key }); h.update("a" ** 64 ++ "b" ** 64); h.final(out[0..]); htest.assertEqual(h1, out[0..]); - h = Blake2b512.init_keyed(key); + h = Blake2b512.init(.{ .key = key }); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); @@ -672,7 +709,7 @@ test "comptime blake2b512" { htest.assertEqualHash(Blake2b512, h1, block[0..]); - var h = Blake2b512.init(); + var h = Blake2b512.init(.{}); h.update(&block); h.final(out[0..]); diff --git a/lib/std/crypto/blake3.zig b/lib/std/crypto/blake3.zig index 056a11be25..163c91b358 100644 --- a/lib/std/crypto/blake3.zig +++ b/lib/std/crypto/blake3.zig @@ -279,6 +279,9 @@ fn parent_cv( /// An incremental hasher that can accept any number of writes. pub const Blake3 = struct { + pub const Options = struct { key: ?[KEY_LEN]u8 = null }; + pub const KdfOptions = struct {}; + chunk_state: ChunkState, key: [8]u32, cv_stack: [54][8]u32 = undefined, // Space for 54 subtree chaining values: @@ -296,21 +299,20 @@ pub const Blake3 = struct { }; } - /// Construct a new `Blake3` for the regular hash function. - pub fn init() Blake3 { - return comptime Blake3.init_internal(IV, 0); - } - - /// Construct a new `Blake3` for the keyed hash function. - pub fn init_keyed(key: [KEY_LEN]u8) Blake3 { - var key_words: [8]u32 = undefined; - words_from_little_endian_bytes(key_words[0..], key[0..]); - return Blake3.init_internal(key_words, KEYED_HASH); + /// Construct a new `Blake3` for the hash function, with an optional key + pub fn init(options: Options) Blake3 { + if (options.key) |key| { + var key_words: [8]u32 = undefined; + words_from_little_endian_bytes(key_words[0..], key[0..]); + return Blake3.init_internal(key_words, KEYED_HASH); + } else { + return Blake3.init_internal(IV, 0); + } } /// Construct a new `Blake3` for the key derivation function. The context /// string should be hardcoded, globally unique, and application-specific. - pub fn init_derive_key(context: []const u8) Blake3 { + pub fn initKdf(context: []const u8, options: KdfOptions) Blake3 { var context_hasher = Blake3.init_internal(IV, DERIVE_KEY_CONTEXT); context_hasher.update(context); var context_key: [KEY_LEN]u8 = undefined; @@ -320,8 +322,8 @@ pub const Blake3 = struct { return Blake3.init_internal(context_key_words, DERIVE_KEY_MATERIAL); } - pub fn hash(in: []const u8, out: []u8) void { - var hasher = Blake3.init(); + pub fn hash(in: []const u8, out: []u8, options: Options) void { + var hasher = Blake3.init(options); hasher.update(in); hasher.final(out); } @@ -589,9 +591,9 @@ fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void { } test "BLAKE3 reference test cases" { - var hash = &Blake3.init(); - var keyed_hash = &Blake3.init_keyed(reference_test.key.*); - var derive_key = &Blake3.init_derive_key(reference_test.context_string); + var hash = &Blake3.init(.{}); + var keyed_hash = &Blake3.init(.{ .key = reference_test.key.* }); + var derive_key = &Blake3.initKdf(reference_test.context_string, .{}); for (reference_test.cases) |t| { test_blake3(hash, t.input_len, t.hash.*); diff --git a/lib/std/crypto/gimli.zig b/lib/std/crypto/gimli.zig index b59d06e754..9d139d6716 100644 --- a/lib/std/crypto/gimli.zig +++ b/lib/std/crypto/gimli.zig @@ -110,10 +110,11 @@ pub const Hash = struct { buf_off: usize, pub const block_length = State.RATE; + pub const Options = struct {}; const Self = @This(); - pub fn init() Self { + pub fn init(options: Options) Self { return Self{ .state = State{ .data = [_]u32{0} ** (State.BLOCKBYTES / 4) }, .buf_off = 0, @@ -160,8 +161,8 @@ pub const Hash = struct { } }; -pub fn hash(out: []u8, in: []const u8) void { - var st = Hash.init(); +pub fn hash(out: []u8, in: []const u8, options: Hash.Options) void { + var st = Hash.init(options); st.update(in); st.final(out); } @@ -174,7 +175,7 @@ test "hash" { var msg: [58 / 2]u8 = undefined; try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C"); var md: [32]u8 = undefined; - hash(&md, &msg); + hash(&md, &msg, .{}); htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", &md); } diff --git a/lib/std/crypto/hmac.zig b/lib/std/crypto/hmac.zig index 77db5bcaae..700904555d 100644 --- a/lib/std/crypto/hmac.zig +++ b/lib/std/crypto/hmac.zig @@ -45,7 +45,7 @@ pub fn Hmac(comptime Hash: type) type { // Normalize key length to block size of hash if (key.len > Hash.block_length) { - Hash.hash(key, ctx.scratch[0..mac_length]); + Hash.hash(key, ctx.scratch[0..mac_length], .{}); mem.set(u8, ctx.scratch[mac_length..Hash.block_length], 0); } else if (key.len < Hash.block_length) { mem.copy(u8, ctx.scratch[0..key.len], key); @@ -62,7 +62,7 @@ pub fn Hmac(comptime Hash: type) type { b.* = ctx.scratch[i] ^ 0x36; } - ctx.hash = Hash.init(); + ctx.hash = Hash.init(.{}); ctx.hash.update(ctx.i_key_pad[0..]); return ctx; } @@ -75,7 +75,7 @@ pub fn Hmac(comptime Hash: type) type { debug.assert(Hash.block_length >= out.len and out.len >= mac_length); ctx.hash.final(ctx.scratch[0..mac_length]); - var ohash = Hash.init(); + var ohash = Hash.init(.{}); ohash.update(ctx.o_key_pad[0..]); ohash.update(ctx.scratch[0..mac_length]); ohash.final(out[0..mac_length]); diff --git a/lib/std/crypto/md5.zig b/lib/std/crypto/md5.zig index c33bee2e56..0d221fabf6 100644 --- a/lib/std/crypto/md5.zig +++ b/lib/std/crypto/md5.zig @@ -39,6 +39,7 @@ pub const Md5 = struct { const Self = @This(); pub const block_length = 64; pub const digest_length = 16; + pub const Options = struct {}; s: [4]u32, // Streaming Cache @@ -46,7 +47,7 @@ pub const Md5 = struct { buf_len: u8, total_len: u64, - pub fn init() Self { + pub fn init(options: Options) Self { return Self{ .s = [_]u32{ 0x67452301, @@ -60,8 +61,8 @@ pub const Md5 = struct { }; } - pub fn hash(b: []const u8, out: []u8) void { - var d = Md5.init(); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Md5.init(options); d.update(b); d.final(out); } @@ -257,18 +258,18 @@ test "md5 single" { } test "md5 streaming" { - var h = Md5.init(); + var h = Md5.init(.{}); var out: [16]u8 = undefined; h.final(out[0..]); htest.assertEqual("d41d8cd98f00b204e9800998ecf8427e", out[0..]); - h = Md5.init(); + h = Md5.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]); - h = Md5.init(); + h = Md5.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -281,7 +282,7 @@ test "md5 aligned final" { var block = [_]u8{0} ** Md5.block_length; var out: [Md5.digest_length]u8 = undefined; - var h = Md5.init(); + var h = Md5.init(.{}); h.update(&block); h.final(out[0..]); } diff --git a/lib/std/crypto/sha1.zig b/lib/std/crypto/sha1.zig index a62343eb7a..03fd55b6a0 100644 --- a/lib/std/crypto/sha1.zig +++ b/lib/std/crypto/sha1.zig @@ -36,6 +36,7 @@ pub const Sha1 = struct { const Self = @This(); pub const block_length = 64; pub const digest_length = 20; + pub const Options = struct {}; s: [5]u32, // Streaming Cache @@ -43,7 +44,7 @@ pub const Sha1 = struct { buf_len: u8 = 0, total_len: u64 = 0, - pub fn init() Self { + pub fn init(options: Options) Self { return Self{ .s = [_]u32{ 0x67452301, @@ -55,8 +56,8 @@ pub const Sha1 = struct { }; } - pub fn hash(b: []const u8, out: []u8) void { - var d = Sha1.init(); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Sha1.init(options); d.update(b); d.final(out); } @@ -276,18 +277,18 @@ test "sha1 single" { } test "sha1 streaming" { - var h = Sha1.init(); + var h = Sha1.init(.{}); var out: [20]u8 = undefined; h.final(out[0..]); htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]); - h = Sha1.init(); + h = Sha1.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]); - h = Sha1.init(); + h = Sha1.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -299,7 +300,7 @@ test "sha1 aligned final" { var block = [_]u8{0} ** Sha1.block_length; var out: [Sha1.digest_length]u8 = undefined; - var h = Sha1.init(); + var h = Sha1.init(.{}); h.update(&block); h.final(out[0..]); } diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig index 851b1dc405..af2c22fe1c 100644 --- a/lib/std/crypto/sha2.zig +++ b/lib/std/crypto/sha2.zig @@ -88,6 +88,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { const Self = @This(); pub const block_length = 64; pub const digest_length = params.out_len / 8; + pub const Options = struct {}; s: [8]u32, // Streaming Cache @@ -95,7 +96,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { buf_len: u8 = 0, total_len: u64 = 0, - pub fn init() Self { + pub fn init(options: Options) Self { return Self{ .s = [_]u32{ params.iv0, @@ -110,8 +111,8 @@ fn Sha2_32(comptime params: Sha2Params32) type { }; } - pub fn hash(b: []const u8, out: []u8) void { - var d = Self.init(); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Self.init(options); d.update(b); d.final(out); } @@ -296,18 +297,18 @@ test "sha224 single" { } test "sha224 streaming" { - var h = Sha224.init(); + var h = Sha224.init(.{}); var out: [28]u8 = undefined; h.final(out[0..]); htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]); - h = Sha224.init(); + h = Sha224.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]); - h = Sha224.init(); + h = Sha224.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -322,18 +323,18 @@ test "sha256 single" { } test "sha256 streaming" { - var h = Sha256.init(); + var h = Sha256.init(.{}); var out: [32]u8 = undefined; h.final(out[0..]); htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]); - h = Sha256.init(); + h = Sha256.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]); - h = Sha256.init(); + h = Sha256.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -345,7 +346,7 @@ test "sha256 aligned final" { var block = [_]u8{0} ** Sha256.block_length; var out: [Sha256.digest_length]u8 = undefined; - var h = Sha256.init(); + var h = Sha256.init(.{}); h.update(&block); h.final(out[0..]); } @@ -458,6 +459,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { const Self = @This(); pub const block_length = 128; pub const digest_length = params.out_len / 8; + pub const Options = struct {}; s: [8]u64, // Streaming Cache @@ -465,7 +467,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { buf_len: u8 = 0, total_len: u128 = 0, - pub fn init() Self { + pub fn init(options: Options) Self { return Self{ .s = [_]u64{ params.iv0, @@ -480,8 +482,8 @@ fn Sha2_64(comptime params: Sha2Params64) type { }; } - pub fn hash(b: []const u8, out: []u8) void { - var d = Self.init(); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Self.init(options); d.update(b); d.final(out); } @@ -693,7 +695,7 @@ test "sha384 single" { } test "sha384 streaming" { - var h = Sha384.init(); + var h = Sha384.init(.{}); var out: [48]u8 = undefined; const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"; @@ -702,12 +704,12 @@ test "sha384 streaming" { const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"; - h = Sha384.init(); + h = Sha384.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Sha384.init(); + h = Sha384.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -727,7 +729,7 @@ test "sha512 single" { } test "sha512 streaming" { - var h = Sha512.init(); + var h = Sha512.init(.{}); var out: [64]u8 = undefined; const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"; @@ -736,12 +738,12 @@ test "sha512 streaming" { const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; - h = Sha512.init(); + h = Sha512.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Sha512.init(); + h = Sha512.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -753,7 +755,7 @@ test "sha512 aligned final" { var block = [_]u8{0} ** Sha512.block_length; var out: [Sha512.digest_length]u8 = undefined; - var h = Sha512.init(); + var h = Sha512.init(.{}); h.update(&block); h.final(out[0..]); } diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig index 273e5eea6d..3d6dad1be1 100644 --- a/lib/std/crypto/sha3.zig +++ b/lib/std/crypto/sha3.zig @@ -20,17 +20,18 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type { const Self = @This(); pub const block_length = 200; pub const digest_length = bits / 8; + pub const Options = struct {}; s: [200]u8, offset: usize, rate: usize, - pub fn init() Self { + pub fn init(options: Options) Self { return Self{ .s = [_]u8{0} ** 200, .offset = 0, .rate = 200 - (bits / 4) }; } - pub fn hash(b: []const u8, out: []u8) void { - var d = Self.init(); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Self.init(options); d.update(b); d.final(out); } @@ -175,18 +176,18 @@ test "sha3-224 single" { } test "sha3-224 streaming" { - var h = Sha3_224.init(); + var h = Sha3_224.init(.{}); var out: [28]u8 = undefined; h.final(out[0..]); htest.assertEqual("6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", out[0..]); - h = Sha3_224.init(); + h = Sha3_224.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual("e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", out[0..]); - h = Sha3_224.init(); + h = Sha3_224.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -201,18 +202,18 @@ test "sha3-256 single" { } test "sha3-256 streaming" { - var h = Sha3_256.init(); + var h = Sha3_256.init(.{}); var out: [32]u8 = undefined; h.final(out[0..]); htest.assertEqual("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", out[0..]); - h = Sha3_256.init(); + h = Sha3_256.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]); - h = Sha3_256.init(); + h = Sha3_256.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -224,7 +225,7 @@ test "sha3-256 aligned final" { var block = [_]u8{0} ** Sha3_256.block_length; var out: [Sha3_256.digest_length]u8 = undefined; - var h = Sha3_256.init(); + var h = Sha3_256.init(.{}); h.update(&block); h.final(out[0..]); } @@ -239,7 +240,7 @@ test "sha3-384 single" { } test "sha3-384 streaming" { - var h = Sha3_384.init(); + var h = Sha3_384.init(.{}); var out: [48]u8 = undefined; const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004"; @@ -247,12 +248,12 @@ test "sha3-384 streaming" { htest.assertEqual(h1, out[0..]); const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25"; - h = Sha3_384.init(); + h = Sha3_384.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Sha3_384.init(); + h = Sha3_384.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -270,7 +271,7 @@ test "sha3-512 single" { } test "sha3-512 streaming" { - var h = Sha3_512.init(); + var h = Sha3_512.init(.{}); var out: [64]u8 = undefined; const h1 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"; @@ -278,12 +279,12 @@ test "sha3-512 streaming" { htest.assertEqual(h1, out[0..]); const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"; - h = Sha3_512.init(); + h = Sha3_512.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Sha3_512.init(); + h = Sha3_512.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -295,7 +296,7 @@ test "sha3-512 aligned final" { var block = [_]u8{0} ** Sha3_512.block_length; var out: [Sha3_512.digest_length]u8 = undefined; - var h = Sha3_512.init(); + var h = Sha3_512.init(.{}); h.update(&block); h.final(out[0..]); } diff --git a/lib/std/crypto/test.zig b/lib/std/crypto/test.zig index e4e34e543b..2987706b11 100644 --- a/lib/std/crypto/test.zig +++ b/lib/std/crypto/test.zig @@ -11,7 +11,7 @@ const fmt = std.fmt; // Hash using the specified hasher `H` asserting `expected == H(input)`. pub fn assertEqualHash(comptime Hasher: anytype, comptime expected: []const u8, input: []const u8) void { var h: [expected.len / 2]u8 = undefined; - Hasher.hash(input, h[0..]); + Hasher.hash(input, h[0..], .{}); assertEqual(expected, &h); } diff --git a/lib/std/zig.zig b/lib/std/zig.zig index c93c22f257..e86a12884f 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -26,7 +26,7 @@ pub fn hashSrc(src: []const u8) SrcHash { std.mem.copy(u8, &out, src); std.mem.set(u8, out[src.len..], 0); } else { - std.crypto.hash.Blake3.hash(src, &out); + std.crypto.hash.Blake3.hash(src, &out, .{}); } return out; }