From 6f9ea9eaef79863ebdc9bf44b2af67ec4caad031 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 19 Aug 2020 16:21:05 +0200 Subject: [PATCH 1/7] Breaking: sort std/crypto functions into categories Instead of having all primitives and constructions share the same namespace, they are now organized by category and function family. Types within the same category are expected to share the exact same API. --- lib/std/bloom_filter.zig | 2 +- lib/std/build/write_file.zig | 2 +- lib/std/cache_hash.zig | 2 +- lib/std/crypto.zig | 129 ++++++++++++++++------------- lib/std/crypto/25519/ed25519.zig | 2 +- lib/std/crypto/benchmark.zig | 33 ++++---- lib/std/crypto/chacha20.zig | 134 ++++++++++++++++--------------- lib/std/crypto/gimli.zig | 10 ++- lib/std/crypto/hmac.zig | 23 ++++-- lib/std/crypto/md5.zig | 26 +++--- lib/std/crypto/sha1.zig | 28 ++++--- lib/std/crypto/sha2.zig | 31 +++---- lib/std/crypto/sha3.zig | 10 +-- lib/std/rand.zig | 4 +- lib/std/zig.zig | 2 +- tools/process_headers.zig | 2 +- 16 files changed, 244 insertions(+), 196 deletions(-) diff --git a/lib/std/bloom_filter.zig b/lib/std/bloom_filter.zig index 34fa42fe00064873349a7ad8c31df5c52c06bcab..5ccef8d1408dd584cfd6f6a71c3b83cd8c6d5ec3 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.gimli.Hash.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/build/write_file.zig b/lib/std/build/write_file.zig index fe15e6e0e30b5d985b0723c9e66b4081e42d73a1..222de7c79ab76a5918e6ab02848ebf24a2def1ff 100644 --- a/lib/std/build/write_file.zig +++ b/lib/std/build/write_file.zig @@ -58,7 +58,7 @@ pub const WriteFileStep = struct { // TODO port the cache system from stage1 to zig std lib. Until then we use blake2b // directly and construct the path, and no "cache hit" detection happens; the files // are always written. - var hash = std.crypto.Blake2b384.init(); + var hash = std.crypto.hash.blake2.Blake2b384.init(); // Random bytes to make WriteFileStep unique. Refresh this with // new random bytes when WriteFileStep implementation is modified diff --git a/lib/std/cache_hash.zig b/lib/std/cache_hash.zig index 58c9f444f31ae252603f3e30b70b596d3af8bf02..802592934779423d04817824a2b9157843ec8935 100644 --- a/lib/std/cache_hash.zig +++ b/lib/std/cache_hash.zig @@ -4,7 +4,7 @@ // The MIT license requires this copyright notice to be included in all copies // and substantial portions of the software. const std = @import("std.zig"); -const Blake3 = std.crypto.Blake3; +const Blake3 = std.crypto.hash.Blake3; const fs = std.fs; const base64 = std.base64; const ArrayList = std.ArrayList; diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig index edca2bc2ff4775368aa75c8ba8d5b914865bca11..2a18bd88c78d4f3827ba77aa0455b161fa2ed3b9 100644 --- a/lib/std/crypto.zig +++ b/lib/std/crypto.zig @@ -3,60 +3,68 @@ // This file is part of [zig](https://ziglang.org/), which is MIT licensed. // The MIT license requires this copyright notice to be included in all copies // and substantial portions of the software. -pub const Md5 = @import("crypto/md5.zig").Md5; -pub const Sha1 = @import("crypto/sha1.zig").Sha1; - -const sha2 = @import("crypto/sha2.zig"); -pub const Sha224 = sha2.Sha224; -pub const Sha256 = sha2.Sha256; -pub const Sha384 = sha2.Sha384; -pub const Sha512 = sha2.Sha512; - -const sha3 = @import("crypto/sha3.zig"); -pub const Sha3_224 = sha3.Sha3_224; -pub const Sha3_256 = sha3.Sha3_256; -pub const Sha3_384 = sha3.Sha3_384; -pub const Sha3_512 = sha3.Sha3_512; - -pub const gimli = @import("crypto/gimli.zig"); - -const blake2 = @import("crypto/blake2.zig"); -pub const Blake2s224 = blake2.Blake2s224; -pub const Blake2s256 = blake2.Blake2s256; -pub const Blake2b384 = blake2.Blake2b384; -pub const Blake2b512 = blake2.Blake2b512; - -pub const Blake3 = @import("crypto/blake3.zig").Blake3; - -const hmac = @import("crypto/hmac.zig"); -pub const HmacMd5 = hmac.HmacMd5; -pub const HmacSha1 = hmac.HmacSha1; -pub const HmacSha256 = hmac.HmacSha256; -pub const HmacBlake2s256 = hmac.HmacBlake2s256; - -pub const chacha20 = @import("crypto/chacha20.zig"); -pub const chaCha20IETF = chacha20.chaCha20IETF; -pub const chaCha20With64BitNonce = chacha20.chaCha20With64BitNonce; -pub const xChaCha20IETF = chacha20.xChaCha20IETF; - -pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305; - -const import_aes = @import("crypto/aes.zig"); -pub const AES128 = import_aes.AES128; -pub const AES256 = import_aes.AES256; - -pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519; -pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519; -pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519; -pub const X25519 = @import("crypto/25519/x25519.zig").X25519; -pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255; +/// Hash functions. +pub const hash = struct { + pub const Md5 = @import("crypto/md5.zig").Md5; + pub const Sha1 = @import("crypto/sha1.zig").Sha1; + pub const sha2 = @import("crypto/sha2.zig"); + pub const sha3 = @import("crypto/sha3.zig"); + pub const blake2 = @import("crypto/blake2.zig"); + pub const Blake3 = @import("crypto/blake3.zig").Blake3; + pub const Gimli = @import("crypto/gimli.zig").Hash; +}; + +/// Authentication (MAC) functions. +pub const auth = struct { + pub const hmac = @import("crypto/hmac.zig"); +}; + +/// Authenticated Encryption with Associated Data pub const aead = struct { - pub const Gimli = gimli.Aead; + const chacha20 = @import("crypto/chacha20.zig"); + + pub const Gimli = @import("crypto/gimli.zig").Aead; pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305; pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305; }; +/// MAC functions requiring single-use secret keys. +pub const onetimeauth = struct { + pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305; +}; + +/// Core functions, that should rarely be used directly by applications. +pub const core = struct { + pub const aes = @import("crypto/aes.zig"); + pub const Gimli = @import("crypto/gimli.zig").State; +}; + +/// Elliptic-curve arithmetic. +pub const ecc = struct { + pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519; + pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519; + pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255; +}; + +/// Diffie-Hellman key exchange functions. +pub const dh = struct { + pub const X25519 = @import("crypto/25519/x25519.zig").X25519; +}; + +/// Digital signature functions. +pub const sign = struct { + pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519; +}; + +/// Stream ciphers. These do not provide any kind of authentication. +/// Most applications should be using AEAD constructions instead of stream ciphers directly. +pub const stream = struct { + pub const ChaCha20IETF = @import("crypto/chacha20.zig").ChaCha20IETF; + pub const XChaCha20IETF = @import("crypto/chacha20.zig").XChaCha20IETF; + pub const ChaCha20With64BitNonce = @import("crypto/chacha20.zig").ChaCha20With64BitNonce; +}; + const std = @import("std.zig"); pub const randomBytes = std.os.getrandom; @@ -83,16 +91,21 @@ test "crypto" { test "issue #4532: no index out of bounds" { const types = [_]type{ - Md5, - Sha1, - Sha224, - Sha256, - Sha384, - Sha512, - Blake2s224, - Blake2s256, - Blake2b384, - Blake2b512, + hash.Md5, + hash.Sha1, + hash.sha2.Sha224, + hash.sha2.Sha256, + hash.sha2.Sha384, + hash.sha2.Sha512, + hash.sha3.Sha3_224, + hash.sha3.Sha3_256, + hash.sha3.Sha3_384, + hash.sha3.Sha3_512, + hash.blake2.Blake2s224, + hash.blake2.Blake2s256, + hash.blake2.Blake2b384, + hash.blake2.Blake2b512, + hash.Gimli, }; inline for (types) |Hasher| { diff --git a/lib/std/crypto/25519/ed25519.zig b/lib/std/crypto/25519/ed25519.zig index 935abaecb39def38927e317f2b9a7b32537b1208..d02fa0a2fd331b6a0c71f8f35b5a43b32d162f6c 100644 --- a/lib/std/crypto/25519/ed25519.zig +++ b/lib/std/crypto/25519/ed25519.zig @@ -6,7 +6,7 @@ const std = @import("std"); const fmt = std.fmt; const mem = std.mem; -const Sha512 = std.crypto.Sha512; +const Sha512 = std.crypto.hash.sha2.Sha512; /// Ed25519 (EdDSA) signatures. pub const Ed25519 = struct { diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig index 5c27f2f4f5374f75e6ad5c603c7911fb741def1e..748d57575159ee5eaa13ed5f42f25a93c05a4e5f 100644 --- a/lib/std/crypto/benchmark.zig +++ b/lib/std/crypto/benchmark.zig @@ -22,16 +22,16 @@ const Crypto = struct { }; const hashes = [_]Crypto{ - Crypto{ .ty = crypto.Md5, .name = "md5" }, - Crypto{ .ty = crypto.Sha1, .name = "sha1" }, - Crypto{ .ty = crypto.Sha256, .name = "sha256" }, - Crypto{ .ty = crypto.Sha512, .name = "sha512" }, - Crypto{ .ty = crypto.Sha3_256, .name = "sha3-256" }, - Crypto{ .ty = crypto.Sha3_512, .name = "sha3-512" }, - Crypto{ .ty = crypto.gimli.Hash, .name = "gimli-hash" }, - Crypto{ .ty = crypto.Blake2s256, .name = "blake2s" }, - Crypto{ .ty = crypto.Blake2b512, .name = "blake2b" }, - Crypto{ .ty = crypto.Blake3, .name = "blake3" }, + Crypto{ .ty = crypto.hash.Md5, .name = "md5" }, + Crypto{ .ty = crypto.hash.Sha1, .name = "sha1" }, + Crypto{ .ty = crypto.hash.sha2.Sha256, .name = "sha256" }, + 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.Gimli, .name = "gimli-hash" }, + Crypto{ .ty = crypto.hash.blake2.Blake2s256, .name = "blake2s" }, + Crypto{ .ty = crypto.hash.blake2.Blake2b512, .name = "blake2b" }, + Crypto{ .ty = crypto.hash.Blake3, .name = "blake3" }, }; pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 { @@ -55,10 +55,11 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 } const macs = [_]Crypto{ - Crypto{ .ty = crypto.Poly1305, .name = "poly1305" }, - Crypto{ .ty = crypto.HmacMd5, .name = "hmac-md5" }, - Crypto{ .ty = crypto.HmacSha1, .name = "hmac-sha1" }, - Crypto{ .ty = crypto.HmacSha256, .name = "hmac-sha256" }, + Crypto{ .ty = crypto.onetimeauth.Poly1305, .name = "poly1305" }, + Crypto{ .ty = crypto.auth.HmacMd5, .name = "hmac-md5" }, + Crypto{ .ty = crypto.auth.HmacSha1, .name = "hmac-sha1" }, + Crypto{ .ty = crypto.auth.sha2.HmacSha256, .name = "hmac-sha256" }, + Crypto{ .ty = crypto.auth.sha2.HmacSha512, .name = "hmac-sha512" }, }; pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 { @@ -84,7 +85,7 @@ pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 { return throughput; } -const exchanges = [_]Crypto{Crypto{ .ty = crypto.X25519, .name = "x25519" }}; +const exchanges = [_]Crypto{Crypto{ .ty = crypto.dh.X25519, .name = "x25519" }}; pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_count: comptime_int) !u64 { std.debug.assert(DhKeyExchange.minimum_key_length >= DhKeyExchange.secret_length); @@ -111,7 +112,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c return throughput; } -const signatures = [_]Crypto{Crypto{ .ty = crypto.Ed25519, .name = "ed25519" }}; +const signatures = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }}; pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 { var seed: [Signature.seed_length]u8 = undefined; diff --git a/lib/std/crypto/chacha20.zig b/lib/std/crypto/chacha20.zig index d402eb67505c855da37c00f8ff1b96d91c55fd03..1a359ecfc75a93045b60a2056320bd6345e94f49 100644 --- a/lib/std/crypto/chacha20.zig +++ b/lib/std/crypto/chacha20.zig @@ -12,7 +12,7 @@ const assert = std.debug.assert; const testing = std.testing; const builtin = @import("builtin"); const maxInt = std.math.maxInt; -const Poly1305 = std.crypto.Poly1305; +const Poly1305 = std.crypto.onetimeauth.Poly1305; const QuarterRound = struct { a: usize, @@ -137,56 +137,60 @@ fn keyToWords(key: [32]u8) [8]u32 { /// /// ChaCha20 is self-reversing. To decrypt just run the cipher with the same /// counter, nonce, and key. -pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void { - assert(in.len >= out.len); - assert((in.len >> 6) + counter <= maxInt(u32)); +pub const ChaCha20IETF = struct { + pub fn xor(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void { + assert(in.len >= out.len); + assert((in.len >> 6) + counter <= maxInt(u32)); - var c: [4]u32 = undefined; - c[0] = counter; - c[1] = mem.readIntLittle(u32, nonce[0..4]); - c[2] = mem.readIntLittle(u32, nonce[4..8]); - c[3] = mem.readIntLittle(u32, nonce[8..12]); - chaCha20_internal(out, in, keyToWords(key), c); -} + var c: [4]u32 = undefined; + c[0] = counter; + c[1] = mem.readIntLittle(u32, nonce[0..4]); + c[2] = mem.readIntLittle(u32, nonce[4..8]); + c[3] = mem.readIntLittle(u32, nonce[8..12]); + chaCha20_internal(out, in, keyToWords(key), c); + } +}; /// This is the original ChaCha20 before RFC 7539, which recommends using the /// orgininal version on applications such as disk or file encryption that might /// exceed the 256 GiB limit of the 96-bit nonce version. -pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]u8, nonce: [8]u8) void { - assert(in.len >= out.len); - assert(counter +% (in.len >> 6) >= counter); +pub const ChaCha20With64BitNonce = struct { + pub fn xor(out: []u8, in: []const u8, counter: u64, key: [32]u8, nonce: [8]u8) void { + assert(in.len >= out.len); + assert(counter +% (in.len >> 6) >= counter); - var cursor: usize = 0; - const k = keyToWords(key); - var c: [4]u32 = undefined; - c[0] = @truncate(u32, counter); - c[1] = @truncate(u32, counter >> 32); - c[2] = mem.readIntLittle(u32, nonce[0..4]); - c[3] = mem.readIntLittle(u32, nonce[4..8]); + var cursor: usize = 0; + const k = keyToWords(key); + var c: [4]u32 = undefined; + c[0] = @truncate(u32, counter); + c[1] = @truncate(u32, counter >> 32); + c[2] = mem.readIntLittle(u32, nonce[0..4]); + c[3] = mem.readIntLittle(u32, nonce[4..8]); - const block_size = (1 << 6); - // The full block size is greater than the address space on a 32bit machine - const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize); + const block_size = (1 << 6); + // The full block size is greater than the address space on a 32bit machine + const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize); - // first partial big block - if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) { - chaCha20_internal(out[cursor..big_block], in[cursor..big_block], k, c); - cursor = big_block - cursor; - c[1] += 1; - if (comptime @sizeOf(usize) > 4) { - // A big block is giant: 256 GiB, but we can avoid this limitation - var remaining_blocks: u32 = @intCast(u32, (in.len / big_block)); - var i: u32 = 0; - while (remaining_blocks > 0) : (remaining_blocks -= 1) { - chaCha20_internal(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c); - c[1] += 1; // upper 32-bit of counter, generic chaCha20_internal() doesn't know about this. - cursor += big_block; + // first partial big block + if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) { + chaCha20_internal(out[cursor..big_block], in[cursor..big_block], k, c); + cursor = big_block - cursor; + c[1] += 1; + if (comptime @sizeOf(usize) > 4) { + // A big block is giant: 256 GiB, but we can avoid this limitation + var remaining_blocks: u32 = @intCast(u32, (in.len / big_block)); + var i: u32 = 0; + while (remaining_blocks > 0) : (remaining_blocks -= 1) { + chaCha20_internal(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c); + c[1] += 1; // upper 32-bit of counter, generic chaCha20_internal() doesn't know about this. + cursor += big_block; + } } } - } - chaCha20_internal(out[cursor..], in[cursor..], k, c); -} + chaCha20_internal(out[cursor..], in[cursor..], k, c); + } +}; // https://tools.ietf.org/html/rfc7539#section-2.4.2 test "crypto.chacha20 test vector sunscreen" { @@ -221,12 +225,12 @@ test "crypto.chacha20 test vector sunscreen" { 0, 0, 0, 0, }; - chaCha20IETF(result[0..], input[0..], 1, key, nonce); + ChaCha20IETF.xor(result[0..], input[0..], 1, key, nonce); testing.expectEqualSlices(u8, &expected_result, &result); // Chacha20 is self-reversing. var plaintext: [114]u8 = undefined; - chaCha20IETF(plaintext[0..], result[0..], 1, key, nonce); + ChaCha20IETF.xor(plaintext[0..], result[0..], 1, key, nonce); testing.expect(mem.order(u8, input, &plaintext) == .eq); } @@ -261,7 +265,7 @@ test "crypto.chacha20 test vector 1" { }; const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0 }; - chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); + ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); testing.expectEqualSlices(u8, &expected_result, &result); } @@ -295,7 +299,7 @@ test "crypto.chacha20 test vector 2" { }; const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0 }; - chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); + ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); testing.expectEqualSlices(u8, &expected_result, &result); } @@ -329,7 +333,7 @@ test "crypto.chacha20 test vector 3" { }; const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 1 }; - chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); + ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); testing.expectEqualSlices(u8, &expected_result, &result); } @@ -363,7 +367,7 @@ test "crypto.chacha20 test vector 4" { }; const nonce = [_]u8{ 1, 0, 0, 0, 0, 0, 0, 0 }; - chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); + ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); testing.expectEqualSlices(u8, &expected_result, &result); } @@ -435,21 +439,21 @@ test "crypto.chacha20 test vector 5" { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, }; - chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); + ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); testing.expectEqualSlices(u8, &expected_result, &result); } pub const chacha20poly1305_tag_size = 16; -pub fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void { +fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void { assert(ciphertext.len >= plaintext.len); // derive poly1305 key var polyKey = [_]u8{0} ** 32; - chaCha20IETF(polyKey[0..], polyKey[0..], 0, key, nonce); + ChaCha20IETF.xor(polyKey[0..], polyKey[0..], 0, key, nonce); // encrypt plaintext - chaCha20IETF(ciphertext[0..plaintext.len], plaintext, 1, key, nonce); + ChaCha20IETF.xor(ciphertext[0..plaintext.len], plaintext, 1, key, nonce); // construct mac var mac = Poly1305.init(polyKey[0..]); @@ -472,18 +476,18 @@ pub fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_ta mac.final(tag); } -pub fn chacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void { +fn chacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void { return chacha20poly1305SealDetached(ciphertextAndTag[0..plaintext.len], ciphertextAndTag[plaintext.len..][0..chacha20poly1305_tag_size], plaintext, data, key, nonce); } /// Verifies and decrypts an authenticated message produced by chacha20poly1305SealDetached. -pub fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void { +fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void { // split ciphertext and tag assert(dst.len >= ciphertext.len); // derive poly1305 key var polyKey = [_]u8{0} ** 32; - chaCha20IETF(polyKey[0..], polyKey[0..], 0, key, nonce); + ChaCha20IETF.xor(polyKey[0..], polyKey[0..], 0, key, nonce); // construct mac var mac = Poly1305.init(polyKey[0..]); @@ -519,11 +523,11 @@ pub fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *con } // decrypt ciphertext - chaCha20IETF(dst[0..ciphertext.len], ciphertext, 1, key, nonce); + ChaCha20IETF.xor(dst[0..ciphertext.len], ciphertext, 1, key, nonce); } /// Verifies and decrypts an authenticated message produced by chacha20poly1305Seal. -pub fn chacha20poly1305Open(dst: []u8, ciphertextAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void { +fn chacha20poly1305Open(dst: []u8, ciphertextAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void { if (ciphertextAndTag.len < chacha20poly1305_tag_size) { return error.InvalidMessage; } @@ -562,31 +566,33 @@ fn extend(key: [32]u8, nonce: [24]u8) struct { key: [32]u8, nonce: [12]u8 } { }; } -pub fn xChaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [24]u8) void { - const extended = extend(key, nonce); - chaCha20IETF(out, in, counter, extended.key, extended.nonce); -} +pub const XChaCha20IETF = struct { + pub fn xor(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [24]u8) void { + const extended = extend(key, nonce); + ChaCha20IETF.xor(out, in, counter, extended.key, extended.nonce); + } +}; pub const xchacha20poly1305_tag_size = 16; -pub fn xchacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void { +fn xchacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void { const extended = extend(key, nonce); return chacha20poly1305SealDetached(ciphertext, tag, plaintext, data, extended.key, extended.nonce); } -pub fn xchacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void { +fn xchacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void { const extended = extend(key, nonce); return chacha20poly1305Seal(ciphertextAndTag, plaintext, data, extended.key, extended.nonce); } /// Verifies and decrypts an authenticated message produced by xchacha20poly1305SealDetached. -pub fn xchacha20poly1305OpenDetached(plaintext: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void { +fn xchacha20poly1305OpenDetached(plaintext: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void { const extended = extend(key, nonce); return try chacha20poly1305OpenDetached(plaintext, ciphertext, tag, data, extended.key, extended.nonce); } /// Verifies and decrypts an authenticated message produced by xchacha20poly1305Seal. -pub fn xchacha20poly1305Open(ciphertextAndTag: []u8, msgAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void { +fn xchacha20poly1305Open(ciphertextAndTag: []u8, msgAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void { const extended = extend(key, nonce); return try chacha20poly1305Open(ciphertextAndTag, msgAndTag, data, extended.key, extended.nonce); } @@ -714,7 +720,7 @@ test "crypto.xchacha20" { const input = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it."; { var ciphertext: [input.len]u8 = undefined; - xChaCha20IETF(ciphertext[0..], input[0..], 0, key, nonce); + XChaCha20IETF.xor(ciphertext[0..], input[0..], 0, key, nonce); var buf: [2 * ciphertext.len]u8 = undefined; testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{ciphertext}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D"); } diff --git a/lib/std/crypto/gimli.zig b/lib/std/crypto/gimli.zig index 33afae5f82c5a311da4f677b18191f214ce0fc8c..77ea74fe0e95c59779578d048c25ecad2fdd2604 100644 --- a/lib/std/crypto/gimli.zig +++ b/lib/std/crypto/gimli.zig @@ -109,17 +109,21 @@ pub const Hash = struct { state: State, buf_off: usize, + pub const block_length = State.RATE; + const Self = @This(); pub fn init() Self { return Self{ - .state = State{ - .data = [_]u32{0} ** (State.BLOCKBYTES / 4), - }, + .state = State{ .data = [_]u32{0} ** (State.BLOCKBYTES / 4) }, .buf_off = 0, }; } + pub fn reset(self: *Self) void { + self.* = init(); + } + /// Also known as 'absorb' pub fn update(self: *Self, data: []const u8) void { const buf = self.state.toSlice(); diff --git a/lib/std/crypto/hmac.zig b/lib/std/crypto/hmac.zig index 984dacc96783e799595e14fb5abc6d6a0e4f1eac..212bc3e7b0500270c03ce38130084e3935d7e172 100644 --- a/lib/std/crypto/hmac.zig +++ b/lib/std/crypto/hmac.zig @@ -8,10 +8,19 @@ const crypto = std.crypto; const debug = std.debug; const mem = std.mem; -pub const HmacMd5 = Hmac(crypto.Md5); -pub const HmacSha1 = Hmac(crypto.Sha1); -pub const HmacSha256 = Hmac(crypto.Sha256); -pub const HmacBlake2s256 = Hmac(crypto.Blake2s256); +pub const HmacMd5 = Hmac(crypto.hash.legacy.Md5); +pub const HmacSha1 = Hmac(crypto.hash.legacy.Sha1); + +pub const sha2 = struct { + pub const HmacSha224 = Hmac(crypto.hash.sha2.Sha224); + pub const HmacSha256 = Hmac(crypto.hash.sha2.Sha256); + pub const HmacSha384 = Hmac(crypto.hash.sha2.Sha384); + pub const HmacSha512 = Hmac(crypto.hash.sha2.Sha512); +}; + +pub const blake2 = struct { + pub const HmacBlake2s256 = Hmac(crypto.hash.blake2.Blake2s256); +}; pub fn Hmac(comptime Hash: type) type { return struct { @@ -95,10 +104,10 @@ test "hmac sha1" { } test "hmac sha256" { - var out: [HmacSha256.mac_length]u8 = undefined; - HmacSha256.create(out[0..], "", ""); + var out: [sha2.HmacSha256.mac_length]u8 = undefined; + sha2.HmacSha256.create(out[0..], "", ""); htest.assertEqual("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", out[0..]); - HmacSha256.create(out[0..], "The quick brown fox jumps over the lazy dog", "key"); + sha2.HmacSha256.create(out[0..], "The quick brown fox jumps over the lazy dog", "key"); htest.assertEqual("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", out[0..]); } diff --git a/lib/std/crypto/md5.zig b/lib/std/crypto/md5.zig index d578ba8b957b6e0dc47358ecc81cdf5251c7e30d..950e52e126ed1ef188bbecfefaf5476fe5dc23b6 100644 --- a/lib/std/crypto/md5.zig +++ b/lib/std/crypto/md5.zig @@ -32,6 +32,9 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundPar }; } +/// The MD5 function is now considered cryptographically broken. +/// Namely, it is trivial to find multiple inputs producing the same hash. +/// For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3. pub const Md5 = struct { const Self = @This(); pub const block_length = 64; @@ -44,18 +47,21 @@ pub const Md5 = struct { total_len: u64, pub fn init() Self { - var d: Self = undefined; - d.reset(); - return d; + return Self{ + .s = [_]u32{ + 0x67452301, + 0xEFCDAB89, + 0x98BADCFE, + 0x10325476, + }, + .buf = undefined, + .buf_len = 0, + .total_len = 0, + }; } - pub fn reset(d: *Self) void { - d.s[0] = 0x67452301; - d.s[1] = 0xEFCDAB89; - d.s[2] = 0x98BADCFE; - d.s[3] = 0x10325476; - d.buf_len = 0; - d.total_len = 0; + pub fn reset(self: *Self) void { + self.* = init(); } pub fn hash(b: []const u8, out: []u8) void { diff --git a/lib/std/crypto/sha1.zig b/lib/std/crypto/sha1.zig index 7cb4fbcf36becff4ae793f2223abd884053c216b..ce18ca5ef7462c7d9ad613b70b10425de9249922 100644 --- a/lib/std/crypto/sha1.zig +++ b/lib/std/crypto/sha1.zig @@ -29,6 +29,9 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam { }; } +/// The SHA-1 function is now considered cryptographically broken. +/// Namely, it is feasible to find multiple inputs producing the same hash. +/// For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3. pub const Sha1 = struct { const Self = @This(); pub const block_length = 64; @@ -41,19 +44,22 @@ pub const Sha1 = struct { total_len: u64, pub fn init() Self { - var d: Self = undefined; - d.reset(); - return d; + return Self{ + .s = [_]u32{ + 0x67452301, + 0xEFCDAB89, + 0x98BADCFE, + 0x10325476, + 0xC3D2E1F0, + }, + .buf = undefined, + .buf_len = 0, + .total_len = 0, + }; } - pub fn reset(d: *Self) void { - d.s[0] = 0x67452301; - d.s[1] = 0xEFCDAB89; - d.s[2] = 0x98BADCFE; - d.s[3] = 0x10325476; - d.s[4] = 0xC3D2E1F0; - d.buf_len = 0; - d.total_len = 0; + pub fn reset(self: *Self) void { + self.* = init(); } pub fn hash(b: []const u8, out: []u8) void { diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig index cac18ca1f7b0f6e2faa90cdc19a3c927ba7002db..e7d0135e81b7281e09666a2e6d17790ed4ae29b3 100644 --- a/lib/std/crypto/sha2.zig +++ b/lib/std/crypto/sha2.zig @@ -93,22 +93,25 @@ fn Sha2_32(comptime params: Sha2Params32) type { total_len: u64, pub fn init() Self { - var d: Self = undefined; - d.reset(); - return d; + return Self{ + .s = [_]u32{ + params.iv0, + params.iv1, + params.iv2, + params.iv3, + params.iv4, + params.iv5, + params.iv6, + params.iv7, + }, + .buf = undefined, + .buf_len = 0, + .total_len = 0, + }; } - pub fn reset(d: *Self) void { - d.s[0] = params.iv0; - d.s[1] = params.iv1; - d.s[2] = params.iv2; - d.s[3] = params.iv3; - d.s[4] = params.iv4; - d.s[5] = params.iv5; - d.s[6] = params.iv6; - d.s[7] = params.iv7; - d.buf_len = 0; - d.total_len = 0; + pub fn reset(self: *Self) void { + self.* = init(); } pub fn hash(b: []const u8, out: []u8) void { diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig index 03635ca55378345371d049f4bbad4f8a23007e5b..630a44fbfb4346ffada8a828444e07f63117e5d8 100644 --- a/lib/std/crypto/sha3.zig +++ b/lib/std/crypto/sha3.zig @@ -27,14 +27,14 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type { pub fn init() Self { var d: Self = undefined; - d.reset(); - return d; - } - - pub fn reset(d: *Self) void { mem.set(u8, d.s[0..], 0); d.offset = 0; d.rate = 200 - (bits / 4); + return d; + } + + pub fn reset(self: *Self) void { + self.* = init(); } pub fn hash(b: []const u8, out: []u8) void { diff --git a/lib/std/rand.zig b/lib/std/rand.zig index 85f11ff44992131bad4ec11ec1fbc2e8c3333256..42726472bf4703ca879cb74bf091ca5ed374e342 100644 --- a/lib/std/rand.zig +++ b/lib/std/rand.zig @@ -737,12 +737,12 @@ test "xoroshiro sequence" { // CSPRNG pub const Gimli = struct { random: Random, - state: std.crypto.gimli.State, + state: std.crypto.core.Gimli, pub fn init(init_s: u64) Gimli { var self = Gimli{ .random = Random{ .fillFn = fill }, - .state = std.crypto.gimli.State{ + .state = std.crypto.core.Gimli{ .data = [_]u32{0} ** (std.crypto.gimli.State.BLOCKBYTES / 4), }, }; diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 34e03eb1648c3e1b99b214f53adca9db5750f0be..c93c22f257fcc36ac48d23bd0e8cf393f4c360d2 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.Blake3.hash(src, &out); + std.crypto.hash.Blake3.hash(src, &out); } return out; } diff --git a/tools/process_headers.zig b/tools/process_headers.zig index d17069401e5cc79f3f15e4dc364945e814761c79..ba9fde6683c16a42fad016c11a565f05f96b7279 100644 --- a/tools/process_headers.zig +++ b/tools/process_headers.zig @@ -313,7 +313,7 @@ pub fn main() !void { var max_bytes_saved: usize = 0; var total_bytes: usize = 0; - var hasher = std.crypto.Sha256.init(); + var hasher = std.crypto.hash.sha2.Sha256.init(); for (libc_targets) |libc_target| { const dest_target = DestTarget{ -- 2.54.0 From 3bed749b1c1285aa340f793fadb6b5b7275529cf Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 20 Aug 2020 12:56:42 +0200 Subject: [PATCH 2/7] Add truncated SHA512 variants --- lib/std/crypto/hmac.zig | 4 ++-- lib/std/crypto/sha2.zig | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/lib/std/crypto/hmac.zig b/lib/std/crypto/hmac.zig index 212bc3e7b0500270c03ce38130084e3935d7e172..3731fca34e0adacd549343803fd9b7ac9ddd6196 100644 --- a/lib/std/crypto/hmac.zig +++ b/lib/std/crypto/hmac.zig @@ -8,8 +8,8 @@ const crypto = std.crypto; const debug = std.debug; const mem = std.mem; -pub const HmacMd5 = Hmac(crypto.hash.legacy.Md5); -pub const HmacSha1 = Hmac(crypto.hash.legacy.Sha1); +pub const HmacMd5 = Hmac(crypto.hash.Md5); +pub const HmacSha1 = Hmac(crypto.hash.Sha1); pub const sha2 = struct { pub const HmacSha224 = Hmac(crypto.hash.sha2.Sha224); diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig index e7d0135e81b7281e09666a2e6d17790ed4ae29b3..1d460934d14e4591a5046c1d2029b26e1c13e432 100644 --- a/lib/std/crypto/sha2.zig +++ b/lib/std/crypto/sha2.zig @@ -77,7 +77,10 @@ const Sha256Params = Sha2Params32{ .out_len = 256, }; +/// SHA-224 pub const Sha224 = Sha2_32(Sha224Params); + +/// SHA-256 pub const Sha256 = Sha2_32(Sha256Params); fn Sha2_32(comptime params: Sha2Params32) type { @@ -421,9 +424,42 @@ const Sha512Params = Sha2Params64{ .out_len = 512, }; +const Sha512256Params = Sha2Params64{ + .iv0 = 0x22312194FC2BF72C, + .iv1 = 0x9F555FA3C84C64C2, + .iv2 = 0x2393B86B6F53B151, + .iv3 = 0x963877195940EABD, + .iv4 = 0x96283EE2A88EFFE3, + .iv5 = 0xBE5E1E2553863992, + .iv6 = 0x2B0199FC2C85B8AA, + .iv7 = 0x0EB72DDC81C52CA2, + .out_len = 256, +}; + +const Sha512T256Params = Sha2Params64{ + .iv0 = 0x6A09E667F3BCC908, + .iv1 = 0xBB67AE8584CAA73B, + .iv2 = 0x3C6EF372FE94F82B, + .iv3 = 0xA54FF53A5F1D36F1, + .iv4 = 0x510E527FADE682D1, + .iv5 = 0x9B05688C2B3E6C1F, + .iv6 = 0x1F83D9ABFB41BD6B, + .iv7 = 0x5BE0CD19137E2179, + .out_len = 256, +}; + +/// SHA-384 pub const Sha384 = Sha2_64(Sha384Params); + +/// SHA-512 pub const Sha512 = Sha2_64(Sha512Params); +/// SHA-512/256 +pub const Sha512256 = Sha2_64(Sha512256Params); + +/// Truncated SHA-512 +pub const Sha512T256 = Sha2_64(Sha512T256Params); + fn Sha2_64(comptime params: Sha2Params64) type { return struct { const Self = @This(); -- 2.54.0 From f92a5d79440402233bd0215e2bb2aeeb4f333931 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 20 Aug 2020 13:06:23 +0200 Subject: [PATCH 3/7] Repair crypto/benchmark; add BLAKE2b256 Some MACs have a 64-bit output --- lib/std/crypto/benchmark.zig | 12 ++++++------ lib/std/crypto/blake2.zig | 3 ++- lib/std/crypto/blake3.zig | 2 +- lib/std/crypto/sha3.zig | 10 +++++----- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig index 748d57575159ee5eaa13ed5f42f25a93c05a4e5f..681739e1bd1a34a1656fc65cfab8c90f1591edf1 100644 --- a/lib/std/crypto/benchmark.zig +++ b/lib/std/crypto/benchmark.zig @@ -56,19 +56,19 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 const macs = [_]Crypto{ Crypto{ .ty = crypto.onetimeauth.Poly1305, .name = "poly1305" }, - Crypto{ .ty = crypto.auth.HmacMd5, .name = "hmac-md5" }, - Crypto{ .ty = crypto.auth.HmacSha1, .name = "hmac-sha1" }, - Crypto{ .ty = crypto.auth.sha2.HmacSha256, .name = "hmac-sha256" }, - Crypto{ .ty = crypto.auth.sha2.HmacSha512, .name = "hmac-sha512" }, + Crypto{ .ty = crypto.auth.hmac.HmacMd5, .name = "hmac-md5" }, + Crypto{ .ty = crypto.auth.hmac.HmacSha1, .name = "hmac-sha1" }, + Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha256, .name = "hmac-sha256" }, + Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha512, .name = "hmac-sha512" }, }; pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 { - std.debug.assert(32 >= Mac.mac_length and 32 >= Mac.minimum_key_length); + std.debug.assert(64 >= Mac.mac_length and 32 >= Mac.minimum_key_length); var in: [1 * MiB]u8 = undefined; prng.random.bytes(in[0..]); - var key: [32]u8 = undefined; + var key: [64]u8 = undefined; prng.random.bytes(key[0..]); var offset: usize = 0; diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index 9f5194994deb73ba9b927db0b7d746185f6589bc..5e39e7aa40e00ccb6c73d8c2ba5da4251297113d 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -74,7 +74,7 @@ pub fn Blake2s(comptime out_len: usize) type { key: []const u8, pub fn init() Self { - return init_keyed(""); + return comptime init_keyed(""); } pub fn init_keyed(key: []const u8) Self { @@ -364,6 +364,7 @@ test "comptime blake2s256" { ///////////////////// // Blake2b +pub const Blake2b256 = Blake2b(256); pub const Blake2b384 = Blake2b(384); pub const Blake2b512 = Blake2b(512); diff --git a/lib/std/crypto/blake3.zig b/lib/std/crypto/blake3.zig index 08986965fc4a58b9d62adefbe23419bcff13ee9a..2428c85d58d2479d26eba05d5efa85c61bfbc670 100644 --- a/lib/std/crypto/blake3.zig +++ b/lib/std/crypto/blake3.zig @@ -298,7 +298,7 @@ pub const Blake3 = struct { /// Construct a new `Blake3` for the regular hash function. pub fn init() Blake3 { - return Blake3.init_internal(IV, 0); + return comptime Blake3.init_internal(IV, 0); } /// Construct a new `Blake3` for the keyed hash function. diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig index 630a44fbfb4346ffada8a828444e07f63117e5d8..d8575290a686b44fb4350af4ece095c81c0f4ff4 100644 --- a/lib/std/crypto/sha3.zig +++ b/lib/std/crypto/sha3.zig @@ -26,11 +26,11 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type { rate: usize, pub fn init() Self { - var d: Self = undefined; - mem.set(u8, d.s[0..], 0); - d.offset = 0; - d.rate = 200 - (bits / 4); - return d; + return comptime Self{ + .s = [_]u8{0} ** 200, + .offset = 0, + .rate = 200 - (bits / 4), + }; } pub fn reset(self: *Self) void { -- 2.54.0 From 446597bd3c935be632287a8ad6cfd72892d674e6 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 20 Aug 2020 22:36:57 +0200 Subject: [PATCH 4/7] Remove the reset() function from hash functions Justification: - reset() is unnecessary; states that have to be reused can be copied - reset() is error-prone. Copying a previous state prevents forgetting struct members. - reset() forces implementation to store sensitive data (key, initial state) in memory even when they are not needed. - reset() is confusing as it has a different meaning elsewhere in Zig. --- lib/std/crypto.zig | 6 ++-- lib/std/crypto/blake2.zig | 74 ++++++++++++++++----------------------- lib/std/crypto/blake3.zig | 13 ++++--- lib/std/crypto/gimli.zig | 4 --- lib/std/crypto/hmac.zig | 8 ++--- lib/std/crypto/md5.zig | 8 ++--- lib/std/crypto/sha1.zig | 17 +++------ lib/std/crypto/sha2.zig | 63 ++++++++++++++------------------- lib/std/crypto/sha3.zig | 26 +++++--------- 9 files changed, 85 insertions(+), 134 deletions(-) diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig index 2a18bd88c78d4f3827ba77aa0455b161fa2ed3b9..bb55f52a4071b916f8b20306d1974d860a1dcca8 100644 --- a/lib/std/crypto.zig +++ b/lib/std/crypto.zig @@ -112,11 +112,11 @@ 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; - - var h = Hasher.init(); + const h0 = Hasher.init(); + var h = h0; h.update(block[0..]); h.final(out1[0..]); - h.reset(); + h = h0; h.update(block[0..1]); h.update(block[1..]); h.final(out2[0..]); diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index 5e39e7aa40e00ccb6c73d8c2ba5da4251297113d..ca310669f6b7dd1ca9c293794e88ceba4c0c6b30 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -71,8 +71,6 @@ pub fn Blake2s(comptime out_len: usize) type { buf: [64]u8, buf_len: u8, - key: []const u8, - pub fn init() Self { return comptime init_keyed(""); } @@ -80,25 +78,20 @@ pub fn Blake2s(comptime out_len: usize) type { pub fn init_keyed(key: []const u8) Self { debug.assert(8 <= out_len and out_len <= 512); - var s: Self = undefined; - s.key = key; - s.reset(); - return s; - } - - pub fn reset(d: *Self) void { + var d: Self = undefined; mem.copy(u32, d.h[0..], iv[0..]); // default parameters - d.h[0] ^= 0x01010000 ^ @truncate(u32, d.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 (d.key.len > 0) { - mem.set(u8, d.buf[d.key.len..], 0); - d.update(d.key); + if (key.len > 0) { + mem.set(u8, d.buf[key.len..], 0); + d.update(key); d.buf_len = 64; } + return d; } pub fn hash(b: []const u8, out: []u8) void { @@ -225,12 +218,12 @@ test "blake2s224 streaming" { const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55"; - h.reset(); + h = Blake2s224.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Blake2s224.init(); h.update("a"); h.update("b"); h.update("c"); @@ -239,13 +232,13 @@ test "blake2s224 streaming" { const h3 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01"; - h.reset(); + h = Blake2s224.init(); h.update("a" ** 32); h.update("b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h.reset(); + h = Blake2s224.init(); h.update("a" ** 32 ++ "b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); @@ -294,12 +287,12 @@ test "blake2s256 streaming" { const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"; - h.reset(); + h = Blake2s256.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Blake2s256.init(); h.update("a"); h.update("b"); h.update("c"); @@ -308,13 +301,13 @@ test "blake2s256 streaming" { const h3 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977"; - h.reset(); + h = Blake2s256.init(); h.update("a" ** 32); h.update("b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h.reset(); + h = Blake2s256.init(); h.update("a" ** 32 ++ "b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); @@ -335,7 +328,7 @@ test "blake2s256 keyed" { htest.assertEqual(h1, out[0..]); - h.reset(); + h = Blake2s256.init_keyed(key); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); @@ -406,8 +399,6 @@ pub fn Blake2b(comptime out_len: usize) type { buf: [128]u8, buf_len: u8, - key: []const u8, - pub fn init() Self { return init_keyed(""); } @@ -415,25 +406,20 @@ pub fn Blake2b(comptime out_len: usize) type { pub fn init_keyed(key: []const u8) Self { debug.assert(8 <= out_len and out_len <= 512); - var s: Self = undefined; - s.key = key; - s.reset(); - return s; - } - - pub fn reset(d: *Self) void { + var d: Self = undefined; mem.copy(u64, d.h[0..], iv[0..]); // default parameters - d.h[0] ^= 0x01010000 ^ (d.key.len << 8) ^ (out_len >> 3); + d.h[0] ^= 0x01010000 ^ (key.len << 8) ^ (out_len >> 3); d.t = 0; d.buf_len = 0; - if (d.key.len > 0) { - mem.set(u8, d.buf[d.key.len..], 0); - d.update(d.key); + if (key.len > 0) { + mem.set(u8, d.buf[key.len..], 0); + d.update(key); d.buf_len = 128; } + return d; } pub fn hash(b: []const u8, out: []u8) void { @@ -558,12 +544,12 @@ test "blake2b384 streaming" { const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4"; - h.reset(); + h = Blake2b384.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Blake2b384.init(); h.update("a"); h.update("b"); h.update("c"); @@ -572,12 +558,12 @@ test "blake2b384 streaming" { const h3 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c"; - h.reset(); + h = Blake2b384.init(); h.update("a" ** 64 ++ "b" ** 64); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h.reset(); + h = Blake2b384.init(); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); @@ -627,12 +613,12 @@ test "blake2b512 streaming" { const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"; - h.reset(); + h = Blake2b512.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Blake2b512.init(); h.update("a"); h.update("b"); h.update("c"); @@ -641,12 +627,12 @@ test "blake2b512 streaming" { const h3 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920"; - h.reset(); + h = Blake2b512.init(); h.update("a" ** 64 ++ "b" ** 64); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h.reset(); + h = Blake2b512.init(); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); @@ -668,7 +654,7 @@ test "blake2b512 keyed" { htest.assertEqual(h1, out[0..]); - h.reset(); + h = Blake2b512.init_keyed(key); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); diff --git a/lib/std/crypto/blake3.zig b/lib/std/crypto/blake3.zig index 2428c85d58d2479d26eba05d5efa85c61bfbc670..056a11be2535e2831685105070ca7ebaec65fd92 100644 --- a/lib/std/crypto/blake3.zig +++ b/lib/std/crypto/blake3.zig @@ -326,12 +326,6 @@ pub const Blake3 = struct { hasher.final(out); } - /// Reset the `Blake3` to its initial state. - pub fn reset(self: *Blake3) void { - self.chunk_state = ChunkState.init(self.key, 0, self.flags); - self.cv_stack_len = 0; - } - fn push_cv(self: *Blake3, cv: [8]u32) void { self.cv_stack[self.cv_stack_len] = cv; self.cv_stack_len += 1; @@ -566,6 +560,9 @@ const reference_test = ReferenceTest{ }; fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void { + // Save initial state + const initial_state = hasher.*; + // Setup input pattern var input_pattern: [251]u8 = undefined; for (input_pattern) |*e, i| e.* = @truncate(u8, i); @@ -581,12 +578,14 @@ fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void { // Read final hash value var actual_bytes: [expected_hex.len / 2]u8 = undefined; hasher.final(actual_bytes[0..]); - hasher.reset(); // Compare to expected value var expected_bytes: [expected_hex.len / 2]u8 = undefined; fmt.hexToBytes(expected_bytes[0..], expected_hex[0..]) catch unreachable; testing.expectEqual(actual_bytes, expected_bytes); + + // Restore initial state + hasher.* = initial_state; } test "BLAKE3 reference test cases" { diff --git a/lib/std/crypto/gimli.zig b/lib/std/crypto/gimli.zig index 77ea74fe0e95c59779578d048c25ecad2fdd2604..b59d06e754175622477f22a9bc5f00d309135c70 100644 --- a/lib/std/crypto/gimli.zig +++ b/lib/std/crypto/gimli.zig @@ -120,10 +120,6 @@ pub const Hash = struct { }; } - pub fn reset(self: *Self) void { - self.* = init(); - } - /// Also known as 'absorb' pub fn update(self: *Self, data: []const u8) void { const buf = self.state.toSlice(); diff --git a/lib/std/crypto/hmac.zig b/lib/std/crypto/hmac.zig index 3731fca34e0adacd549343803fd9b7ac9ddd6196..77db5bcaae099c5435258887c219fad34d2cd681 100644 --- a/lib/std/crypto/hmac.zig +++ b/lib/std/crypto/hmac.zig @@ -75,10 +75,10 @@ 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]); - ctx.hash.reset(); - ctx.hash.update(ctx.o_key_pad[0..]); - ctx.hash.update(ctx.scratch[0..mac_length]); - ctx.hash.final(out[0..mac_length]); + 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 950e52e126ed1ef188bbecfefaf5476fe5dc23b6..c33bee2e562906bd47ae318f294ce230aaede9c9 100644 --- a/lib/std/crypto/md5.zig +++ b/lib/std/crypto/md5.zig @@ -60,10 +60,6 @@ pub const Md5 = struct { }; } - pub fn reset(self: *Self) void { - self.* = init(); - } - pub fn hash(b: []const u8, out: []u8) void { var d = Md5.init(); d.update(b); @@ -267,12 +263,12 @@ test "md5 streaming" { h.final(out[0..]); htest.assertEqual("d41d8cd98f00b204e9800998ecf8427e", out[0..]); - h.reset(); + h = Md5.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]); - h.reset(); + h = Md5.init(); h.update("a"); h.update("b"); h.update("c"); diff --git a/lib/std/crypto/sha1.zig b/lib/std/crypto/sha1.zig index ce18ca5ef7462c7d9ad613b70b10425de9249922..a62343eb7ac5e811e2d91c13b65ee5c18b078601 100644 --- a/lib/std/crypto/sha1.zig +++ b/lib/std/crypto/sha1.zig @@ -39,9 +39,9 @@ pub const Sha1 = struct { s: [5]u32, // Streaming Cache - buf: [64]u8, - buf_len: u8, - total_len: u64, + buf: [64]u8 = undefined, + buf_len: u8 = 0, + total_len: u64 = 0, pub fn init() Self { return Self{ @@ -52,16 +52,9 @@ pub const Sha1 = struct { 0x10325476, 0xC3D2E1F0, }, - .buf = undefined, - .buf_len = 0, - .total_len = 0, }; } - pub fn reset(self: *Self) void { - self.* = init(); - } - pub fn hash(b: []const u8, out: []u8) void { var d = Sha1.init(); d.update(b); @@ -289,12 +282,12 @@ test "sha1 streaming" { h.final(out[0..]); htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]); - h.reset(); + h = Sha1.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]); - h.reset(); + h = Sha1.init(); h.update("a"); h.update("b"); h.update("c"); diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig index 1d460934d14e4591a5046c1d2029b26e1c13e432..851b1dc4050e59ec55cb02a9722fe0e3e7f1c94c 100644 --- a/lib/std/crypto/sha2.zig +++ b/lib/std/crypto/sha2.zig @@ -91,9 +91,9 @@ fn Sha2_32(comptime params: Sha2Params32) type { s: [8]u32, // Streaming Cache - buf: [64]u8, - buf_len: u8, - total_len: u64, + buf: [64]u8 = undefined, + buf_len: u8 = 0, + total_len: u64 = 0, pub fn init() Self { return Self{ @@ -107,16 +107,9 @@ fn Sha2_32(comptime params: Sha2Params32) type { params.iv6, params.iv7, }, - .buf = undefined, - .buf_len = 0, - .total_len = 0, }; } - pub fn reset(self: *Self) void { - self.* = init(); - } - pub fn hash(b: []const u8, out: []u8) void { var d = Self.init(); d.update(b); @@ -309,12 +302,12 @@ test "sha224 streaming" { h.final(out[0..]); htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]); - h.reset(); + h = Sha224.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]); - h.reset(); + h = Sha224.init(); h.update("a"); h.update("b"); h.update("c"); @@ -335,12 +328,12 @@ test "sha256 streaming" { h.final(out[0..]); htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]); - h.reset(); + h = Sha256.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]); - h.reset(); + h = Sha256.init(); h.update("a"); h.update("b"); h.update("c"); @@ -468,27 +461,23 @@ fn Sha2_64(comptime params: Sha2Params64) type { s: [8]u64, // Streaming Cache - buf: [128]u8, - buf_len: u8, - total_len: u128, + buf: [128]u8 = undefined, + buf_len: u8 = 0, + total_len: u128 = 0, pub fn init() Self { - var d: Self = undefined; - d.reset(); - return d; - } - - pub fn reset(d: *Self) void { - d.s[0] = params.iv0; - d.s[1] = params.iv1; - d.s[2] = params.iv2; - d.s[3] = params.iv3; - d.s[4] = params.iv4; - d.s[5] = params.iv5; - d.s[6] = params.iv6; - d.s[7] = params.iv7; - d.buf_len = 0; - d.total_len = 0; + return Self{ + .s = [_]u64{ + params.iv0, + params.iv1, + params.iv2, + params.iv3, + params.iv4, + params.iv5, + params.iv6, + params.iv7, + }, + }; } pub fn hash(b: []const u8, out: []u8) void { @@ -713,12 +702,12 @@ test "sha384 streaming" { const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"; - h.reset(); + h = Sha384.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Sha384.init(); h.update("a"); h.update("b"); h.update("c"); @@ -747,12 +736,12 @@ test "sha512 streaming" { const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; - h.reset(); + h = Sha512.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Sha512.init(); h.update("a"); h.update("b"); h.update("c"); diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig index d8575290a686b44fb4350af4ece095c81c0f4ff4..273e5eea6d924af0f6aeedcb101fc6831f6cfbfe 100644 --- a/lib/std/crypto/sha3.zig +++ b/lib/std/crypto/sha3.zig @@ -26,15 +26,7 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type { rate: usize, pub fn init() Self { - return comptime Self{ - .s = [_]u8{0} ** 200, - .offset = 0, - .rate = 200 - (bits / 4), - }; - } - - pub fn reset(self: *Self) void { - self.* = init(); + return Self{ .s = [_]u8{0} ** 200, .offset = 0, .rate = 200 - (bits / 4) }; } pub fn hash(b: []const u8, out: []u8) void { @@ -189,12 +181,12 @@ test "sha3-224 streaming" { h.final(out[0..]); htest.assertEqual("6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", out[0..]); - h.reset(); + h = Sha3_224.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual("e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", out[0..]); - h.reset(); + h = Sha3_224.init(); h.update("a"); h.update("b"); h.update("c"); @@ -215,12 +207,12 @@ test "sha3-256 streaming" { h.final(out[0..]); htest.assertEqual("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", out[0..]); - h.reset(); + h = Sha3_256.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]); - h.reset(); + h = Sha3_256.init(); h.update("a"); h.update("b"); h.update("c"); @@ -255,12 +247,12 @@ test "sha3-384 streaming" { htest.assertEqual(h1, out[0..]); const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25"; - h.reset(); + h = Sha3_384.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Sha3_384.init(); h.update("a"); h.update("b"); h.update("c"); @@ -286,12 +278,12 @@ test "sha3-512 streaming" { htest.assertEqual(h1, out[0..]); const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"; - h.reset(); + h = Sha3_512.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Sha3_512.init(); h.update("a"); h.update("b"); h.update("c"); -- 2.54.0 From adf3d00e874275557b69ef65164a2b2a0dd88167 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 20 Aug 2020 22:51:19 +0200 Subject: [PATCH 5/7] Remove explicit comptime --- lib/std/crypto/blake2.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index ca310669f6b7dd1ca9c293794e88ceba4c0c6b30..bb07390286515dbb7d6e2889428f8fbcf300e453 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -72,7 +72,7 @@ pub fn Blake2s(comptime out_len: usize) type { buf_len: u8, pub fn init() Self { - return comptime init_keyed(""); + return init_keyed(""); } pub fn init_keyed(key: []const u8) Self { -- 2.54.0 From fc55cd458a7cd72ea876cf747b1ddd43d8dc6e20 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 21 Aug 2020 00:51:14 +0200 Subject: [PATCH 6/7] 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 5ccef8d1408dd584cfd6f6a71c3b83cd8c6d5ec3..0e251f548fff8438d4c9d411295983004c76df94 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 802592934779423d04817824a2b9157843ec8935..edd0ebf12688f6778b062635d38b7a8f5478be20 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 bb55f52a4071b916f8b20306d1974d860a1dcca8..32ab5071c588d769d78031a2b48ecf273da39051 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 d02fa0a2fd331b6a0c71f8f35b5a43b32d162f6c..9993afb6d2dec072bf7df7fe654542b39e7ecd16 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 681739e1bd1a34a1656fc65cfab8c90f1591edf1..70bd30d6bbf6e0a8ecddb22f0b1cbefe3b59ea73 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 bb07390286515dbb7d6e2889428f8fbcf300e453..1cb143811cf3f861035f0ddfa4148105fb46d709 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 056a11be2535e2831685105070ca7ebaec65fd92..163c91b3584bd768801f4f593b36380ee15de6ae 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 b59d06e754175622477f22a9bc5f00d309135c70..9d139d6716f438d13eca733ac638965637d36383 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 77db5bcaae099c5435258887c219fad34d2cd681..700904555d4498c79565cec52f219e4f059eb100 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 c33bee2e562906bd47ae318f294ce230aaede9c9..0d221fabf682a8150e924e6536dbb0ae85b68a6f 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 a62343eb7ac5e811e2d91c13b65ee5c18b078601..03fd55b6a0e1bc82d76dd59960a1b475fcecad63 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 851b1dc4050e59ec55cb02a9722fe0e3e7f1c94c..af2c22fe1ca6237887e59793ae61ecd05b22847e 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 273e5eea6d924af0f6aeedcb101fc6831f6cfbfe..3d6dad1be17078ece1e7459f213778dd10b49936 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 e4e34e543b95f2732df65c61afdbaa3b91757898..2987706b11aa5e2db0481d8ca8c80206bb235e30 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 c93c22f257fcc36ac48d23bd0e8cf393f4c360d2..e86a12884ffce894500740007300a945fbd61e24 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; } -- 2.54.0 From 3edace34d38c95673e56930ccfee1d16d0003359 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 21 Aug 2020 00:57:29 +0200 Subject: [PATCH 7/7] Update tools/process_headers.zig --- tools/process_headers.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/process_headers.zig b/tools/process_headers.zig index ba9fde6683c16a42fad016c11a565f05f96b7279..918802f65d091ffe54b40077b5e359a29e7bd761 100644 --- a/tools/process_headers.zig +++ b/tools/process_headers.zig @@ -313,7 +313,7 @@ pub fn main() !void { var max_bytes_saved: usize = 0; var total_bytes: usize = 0; - var hasher = std.crypto.hash.sha2.Sha256.init(); + var hasher = std.crypto.hash.sha2.Sha256.init(.{}); for (libc_targets) |libc_target| { const dest_target = DestTarget{ -- 2.54.0