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.
This commit is contained in:
Frank Denis 2020-08-20 22:36:57 +02:00
parent f92a5d7944
commit 446597bd3c
9 changed files with 85 additions and 134 deletions

View File

@ -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..]);

View File

@ -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..]);

View File

@ -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" {

View File

@ -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();

View File

@ -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]);
}
};
}

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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");