Merge pull request #5968 from haliucinas/blake2

Blake2 improvements
This commit is contained in:
Andrew Kelley 2020-08-02 17:47:06 +00:00 committed by GitHub
commit 35391f1709
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,8 +1,7 @@
const mem = @import("../mem.zig");
const math = @import("../math.zig");
const endian = @import("../endian.zig");
const debug = @import("../debug.zig");
const builtin = @import("builtin");
const debug = @import("../debug.zig");
const math = @import("../math.zig");
const htest = @import("test.zig");
const RoundParam = struct {
@ -31,7 +30,7 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
pub const Blake2s224 = Blake2s(224);
pub const Blake2s256 = Blake2s(256);
fn Blake2s(comptime out_len: usize) type {
pub fn Blake2s(comptime out_len: usize) type {
return struct {
const Self = @This();
pub const block_length = 64;
@ -67,10 +66,17 @@ fn Blake2s(comptime out_len: usize) type {
buf: [64]u8,
buf_len: u8,
key: []const u8,
pub fn init() Self {
return init_keyed("");
}
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;
}
@ -78,14 +84,24 @@ fn Blake2s(comptime out_len: usize) type {
pub fn reset(d: *Self) void {
mem.copy(u32, d.h[0..], iv[0..]);
// No key plus default parameters
d.h[0] ^= 0x01010000 ^ @intCast(u32, out_len >> 3);
// default parameters
d.h[0] ^= 0x01010000 ^ @truncate(u32, d.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);
d.buf_len = 64;
}
}
pub fn hash(b: []const u8, out: []u8) void {
var d = Self.init();
Self.hash_keyed("", b, out);
}
pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void {
var d = Self.init_keyed(key);
d.update(b);
d.final(out);
}
@ -94,7 +110,7 @@ fn Blake2s(comptime out_len: usize) type {
var off: usize = 0;
// Partial buffer exists from previous update. Copy into buffer then hash.
if (d.buf_len != 0 and d.buf_len + b.len >= 64) {
if (d.buf_len != 0 and d.buf_len + b.len > 64) {
off += 64 - d.buf_len;
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
d.t += 64;
@ -103,7 +119,7 @@ fn Blake2s(comptime out_len: usize) type {
}
// Full middle blocks.
while (off + 64 <= b.len) : (off += 64) {
while (off + 64 < b.len) : (off += 64) {
d.t += 64;
d.round(b[off .. off + 64], false);
}
@ -123,7 +139,7 @@ fn Blake2s(comptime out_len: usize) type {
const rr = d.h[0 .. out_len / 32];
for (rr) |s, j| {
mem.writeIntLittle(u32, out[4 * j ..][0..4], s);
mem.writeIntSliceLittle(u32, out[4 * j ..], s);
}
}
@ -188,6 +204,9 @@ test "blake2s224 single" {
const h3 = "e4e5cb6c7cae41982b397bf7b7d2d9d1949823ae78435326e8db4912";
htest.assertEqualHash(Blake2s224, h3, "The quick brown fox jumps over the lazy dog");
const h4 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01";
htest.assertEqualHash(Blake2s224, h4, "a" ** 32 ++ "b" ** 32);
}
test "blake2s224 streaming" {
@ -212,6 +231,37 @@ test "blake2s224 streaming" {
h.update("c");
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
const h3 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01";
h.reset();
h.update("a" ** 32);
h.update("b" ** 32);
h.final(out[0..]);
htest.assertEqual(h3, out[0..]);
h.reset();
h.update("a" ** 32 ++ "b" ** 32);
h.final(out[0..]);
htest.assertEqual(h3, out[0..]);
}
test "comptime blake2s224" {
comptime {
@setEvalBranchQuota(6000);
var block = [_]u8{0} ** Blake2s224.block_length;
var out: [Blake2s224.digest_length]u8 = undefined;
const h1 = "86b7611563293f8c73627df7a6d6ba25ca0548c2a6481f7d116ee576";
htest.assertEqualHash(Blake2s224, h1, block[0..]);
var h = Blake2s224.init();
h.update(&block);
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
}
}
test "blake2s256 single" {
@ -223,6 +273,9 @@ test "blake2s256 single" {
const h3 = "606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812";
htest.assertEqualHash(Blake2s256, h3, "The quick brown fox jumps over the lazy dog");
const h4 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977";
htest.assertEqualHash(Blake2s256, h4, "a" ** 32 ++ "b" ** 32);
}
test "blake2s256 streaming" {
@ -247,15 +300,60 @@ test "blake2s256 streaming" {
h.update("c");
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
const h3 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977";
h.reset();
h.update("a" ** 32);
h.update("b" ** 32);
h.final(out[0..]);
htest.assertEqual(h3, out[0..]);
h.reset();
h.update("a" ** 32 ++ "b" ** 32);
h.final(out[0..]);
htest.assertEqual(h3, out[0..]);
}
test "blake2s256 aligned final" {
var block = [_]u8{0} ** Blake2s256.block_length;
var out: [Blake2s256.digest_length]u8 = undefined;
test "blake2s256 keyed" {
var out: [32]u8 = undefined;
var h = Blake2s256.init();
h.update(&block);
const h1 = "10f918da4d74fab3302e48a5d67d03804b1ec95372a62a0f33b7c9fa28ba1ae6";
const key = "secret_key";
Blake2s256.hash_keyed(key, "a" ** 64 ++ "b" ** 64, &out);
htest.assertEqual(h1, out[0..]);
var h = Blake2s256.init_keyed(key);
h.update("a" ** 64 ++ "b" ** 64);
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
h.reset();
h.update("a" ** 64);
h.update("b" ** 64);
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
}
test "comptime blake2s256" {
comptime {
@setEvalBranchQuota(6000);
var block = [_]u8{0} ** Blake2s256.block_length;
var out: [Blake2s256.digest_length]u8 = undefined;
const h1 = "ae09db7cd54f42b490ef09b6bc541af688e4959bb8c53f359a6f56e38ab454a3";
htest.assertEqualHash(Blake2s256, h1, block[0..]);
var h = Blake2s256.init();
h.update(&block);
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
}
}
/////////////////////
@ -264,7 +362,7 @@ test "blake2s256 aligned final" {
pub const Blake2b384 = Blake2b(384);
pub const Blake2b512 = Blake2b(512);
fn Blake2b(comptime out_len: usize) type {
pub fn Blake2b(comptime out_len: usize) type {
return struct {
const Self = @This();
pub const block_length = 128;
@ -302,10 +400,17 @@ fn Blake2b(comptime out_len: usize) type {
buf: [128]u8,
buf_len: u8,
key: []const u8,
pub fn init() Self {
return init_keyed("");
}
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;
}
@ -313,14 +418,24 @@ fn Blake2b(comptime out_len: usize) type {
pub fn reset(d: *Self) void {
mem.copy(u64, d.h[0..], iv[0..]);
// No key plus default parameters
d.h[0] ^= 0x01010000 ^ (out_len >> 3);
// default parameters
d.h[0] ^= 0x01010000 ^ (d.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);
d.buf_len = 128;
}
}
pub fn hash(b: []const u8, out: []u8) void {
var d = Self.init();
Self.hash_keyed("", b, out);
}
pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void {
var d = Self.init_keyed(key);
d.update(b);
d.final(out);
}
@ -329,7 +444,7 @@ fn Blake2b(comptime out_len: usize) type {
var off: usize = 0;
// Partial buffer exists from previous update. Copy into buffer then hash.
if (d.buf_len != 0 and d.buf_len + b.len >= 128) {
if (d.buf_len != 0 and d.buf_len + b.len > 128) {
off += 128 - d.buf_len;
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
d.t += 128;
@ -338,7 +453,7 @@ fn Blake2b(comptime out_len: usize) type {
}
// Full middle blocks.
while (off + 128 <= b.len) : (off += 128) {
while (off + 128 < b.len) : (off += 128) {
d.t += 128;
d.round(b[off .. off + 128], false);
}
@ -356,7 +471,7 @@ fn Blake2b(comptime out_len: usize) type {
const rr = d.h[0 .. out_len / 64];
for (rr) |s, j| {
mem.writeIntLittle(u64, out[8 * j ..][0..8], s);
mem.writeIntSliceLittle(u64, out[8 * j ..], s);
}
}
@ -421,6 +536,9 @@ test "blake2b384 single" {
const h3 = "b7c81b228b6bd912930e8f0b5387989691c1cee1e65aade4da3b86a3c9f678fc8018f6ed9e2906720c8d2a3aeda9c03d";
htest.assertEqualHash(Blake2b384, h3, "The quick brown fox jumps over the lazy dog");
const h4 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c";
htest.assertEqualHash(Blake2b384, h4, "a" ** 64 ++ "b" ** 64);
}
test "blake2b384 streaming" {
@ -445,6 +563,37 @@ test "blake2b384 streaming" {
h.update("c");
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
const h3 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c";
h.reset();
h.update("a" ** 64 ++ "b" ** 64);
h.final(out[0..]);
htest.assertEqual(h3, out[0..]);
h.reset();
h.update("a" ** 64);
h.update("b" ** 64);
h.final(out[0..]);
htest.assertEqual(h3, out[0..]);
}
test "comptime blake2b384" {
comptime {
@setEvalBranchQuota(7000);
var block = [_]u8{0} ** Blake2b384.block_length;
var out: [Blake2b384.digest_length]u8 = undefined;
const h1 = "e8aa1931ea0422e4446fecdd25c16cf35c240b10cb4659dd5c776eddcaa4d922397a589404b46eb2e53d78132d05fd7d";
htest.assertEqualHash(Blake2b384, h1, block[0..]);
var h = Blake2b384.init();
h.update(&block);
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
}
}
test "blake2b512 single" {
@ -456,6 +605,9 @@ test "blake2b512 single" {
const h3 = "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918";
htest.assertEqualHash(Blake2b512, h3, "The quick brown fox jumps over the lazy dog");
const h4 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920";
htest.assertEqualHash(Blake2b512, h4, "a" ** 64 ++ "b" ** 64);
}
test "blake2b512 streaming" {
@ -480,13 +632,58 @@ test "blake2b512 streaming" {
h.update("c");
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
}
test "blake2b512 aligned final" {
var block = [_]u8{0} ** Blake2b512.block_length;
var out: [Blake2b512.digest_length]u8 = undefined;
const h3 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920";
var h = Blake2b512.init();
h.update(&block);
h.reset();
h.update("a" ** 64 ++ "b" ** 64);
h.final(out[0..]);
htest.assertEqual(h3, out[0..]);
h.reset();
h.update("a" ** 64);
h.update("b" ** 64);
h.final(out[0..]);
htest.assertEqual(h3, out[0..]);
}
test "blake2b512 keyed" {
var out: [64]u8 = undefined;
const h1 = "8a978060ccaf582f388f37454363071ac9a67e3a704585fd879fb8a419a447e389c7c6de790faa20a7a7dccf197de736bc5b40b98a930b36df5bee7555750c4d";
const key = "secret_key";
Blake2b512.hash_keyed(key, "a" ** 64 ++ "b" ** 64, &out);
htest.assertEqual(h1, out[0..]);
var h = Blake2b512.init_keyed(key);
h.update("a" ** 64 ++ "b" ** 64);
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
h.reset();
h.update("a" ** 64);
h.update("b" ** 64);
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
}
test "comptime blake2b512" {
comptime {
@setEvalBranchQuota(8000);
var block = [_]u8{0} ** Blake2b512.block_length;
var out: [Blake2b512.digest_length]u8 = undefined;
const h1 = "865939e120e6805438478841afb739ae4250cf372653078a065cdcfffca4caf798e6d462b65d658fc165782640eded70963449ae1500fb0f24981d7727e22c41";
htest.assertEqualHash(Blake2b512, h1, block[0..]);
var h = Blake2b512.init();
h.update(&block);
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
}
}