From fad87bef9af8948a475fd4577b44082fdde303cd Mon Sep 17 00:00:00 2001 From: Mantas Jonytis Date: Sat, 1 Aug 2020 15:15:04 +0300 Subject: [PATCH 1/8] add more blake2s tests --- lib/std/crypto/blake2.zig | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index fc1d59290e..366f6ec2cd 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -188,6 +188,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 +215,34 @@ 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 "blake2s224 aligned final" { + 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 +254,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 +281,34 @@ 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; + 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..]); } ///////////////////// From b1cf0196dfc434c425b02512072553e6cbd4c09a Mon Sep 17 00:00:00 2001 From: Mantas Jonytis Date: Sat, 1 Aug 2020 15:15:45 +0300 Subject: [PATCH 2/8] blake2s: off-by-one on update --- lib/std/crypto/blake2.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index 366f6ec2cd..0afb520b0c 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -94,7 +94,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 +103,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); } From eee9abe1b48c06e2a56cc955c0a773dc7a8de514 Mon Sep 17 00:00:00 2001 From: Mantas Jonytis Date: Sat, 1 Aug 2020 15:31:36 +0300 Subject: [PATCH 3/8] add more blake2b test cases --- lib/std/crypto/blake2.zig | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index 0afb520b0c..2b7769c3f7 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -474,6 +474,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" { @@ -498,6 +501,34 @@ 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 "blake2b384 aligned final" { + 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" { @@ -509,6 +540,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" { @@ -533,13 +567,32 @@ test "blake2b512 streaming" { h.update("c"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); + + const h3 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920"; + + 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 aligned final" { 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..]); } From 1ae40146e68720047190f3c5cbd693669bbb1d87 Mon Sep 17 00:00:00 2001 From: Mantas Jonytis Date: Sat, 1 Aug 2020 15:31:46 +0300 Subject: [PATCH 4/8] blake2b: off-by-one on update --- lib/std/crypto/blake2.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index 2b7769c3f7..444dd601e3 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -382,7 +382,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; @@ -391,7 +391,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); } From 42dd737c9e23292464f368889d7301bc82c3e648 Mon Sep 17 00:00:00 2001 From: Mantas Jonytis Date: Sat, 1 Aug 2020 16:00:22 +0300 Subject: [PATCH 5/8] compute blake2 at compile time --- lib/std/crypto/blake2.zig | 46 ++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index 444dd601e3..5ad53e9844 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -123,7 +123,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); } } @@ -296,19 +296,22 @@ test "blake2s256 streaming" { htest.assertEqual(h3, out[0..]); } -test "blake2s256 aligned final" { - var block = [_]u8{0} ** Blake2s256.block_length; - var out: [Blake2s256.digest_length]u8 = undefined; +test "comptime blake2s256" { + comptime { + @setEvalBranchQuota(8000); + var block = [_]u8{0} ** Blake2s256.block_length; + var out: [Blake2s256.digest_length]u8 = undefined; - const h1 = "ae09db7cd54f42b490ef09b6bc541af688e4959bb8c53f359a6f56e38ab454a3"; + const h1 = "ae09db7cd54f42b490ef09b6bc541af688e4959bb8c53f359a6f56e38ab454a3"; - htest.assertEqualHash(Blake2s256, h1, block[0..]); + htest.assertEqualHash(Blake2s256, h1, block[0..]); - var h = Blake2s256.init(); - h.update(&block); - h.final(out[0..]); + var h = Blake2s256.init(); + h.update(&block); + h.final(out[0..]); - htest.assertEqual(h1, out[0..]); + htest.assertEqual(h1, out[0..]); + } } ///////////////////// @@ -409,7 +412,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); } } @@ -582,17 +585,20 @@ test "blake2b512 streaming" { htest.assertEqual(h3, out[0..]); } -test "blake2b512 aligned final" { - var block = [_]u8{0} ** Blake2b512.block_length; - var out: [Blake2b512.digest_length]u8 = undefined; +test "comptime blake2b512" { + comptime { + @setEvalBranchQuota(8000); + var block = [_]u8{0} ** Blake2b512.block_length; + var out: [Blake2b512.digest_length]u8 = undefined; - const h1 = "865939e120e6805438478841afb739ae4250cf372653078a065cdcfffca4caf798e6d462b65d658fc165782640eded70963449ae1500fb0f24981d7727e22c41"; + const h1 = "865939e120e6805438478841afb739ae4250cf372653078a065cdcfffca4caf798e6d462b65d658fc165782640eded70963449ae1500fb0f24981d7727e22c41"; - htest.assertEqualHash(Blake2b512, h1, block[0..]); + htest.assertEqualHash(Blake2b512, h1, block[0..]); - var h = Blake2b512.init(); - h.update(&block); - h.final(out[0..]); + var h = Blake2b512.init(); + h.update(&block); + h.final(out[0..]); - htest.assertEqual(h1, out[0..]); + htest.assertEqual(h1, out[0..]); + } } From 36ed4623a8355cd06be84e015142d81ae4429e4f Mon Sep 17 00:00:00 2001 From: Mantas Jonytis Date: Sat, 1 Aug 2020 16:05:20 +0300 Subject: [PATCH 6/8] make blake2 public --- lib/std/crypto/blake2.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index 5ad53e9844..ec504145f3 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -31,7 +31,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; @@ -320,7 +320,7 @@ test "comptime blake2s256" { 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; From 8286cc77f8fdd33d7b2426b385375f94f04fdae0 Mon Sep 17 00:00:00 2001 From: Mantas Jonytis Date: Sat, 1 Aug 2020 16:56:11 +0300 Subject: [PATCH 7/8] implement keyed blake2 --- lib/std/crypto/blake2.zig | 141 ++++++++++++++++++++++++++++++-------- 1 file changed, 113 insertions(+), 28 deletions(-) diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index ec504145f3..a4ab64bda5 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -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 { @@ -67,10 +66,17 @@ pub 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 @@ pub 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); } @@ -230,19 +246,22 @@ test "blake2s224 streaming" { htest.assertEqual(h3, out[0..]); } -test "blake2s224 aligned final" { - var block = [_]u8{0} ** Blake2s224.block_length; - var out: [Blake2s224.digest_length]u8 = undefined; +test "comptime blake2s224" { + comptime { + @setEvalBranchQuota(6000); + var block = [_]u8{0} ** Blake2s224.block_length; + var out: [Blake2s224.digest_length]u8 = undefined; - const h1 = "86b7611563293f8c73627df7a6d6ba25ca0548c2a6481f7d116ee576"; + const h1 = "86b7611563293f8c73627df7a6d6ba25ca0548c2a6481f7d116ee576"; - htest.assertEqualHash(Blake2s224, h1, block[0..]); + htest.assertEqualHash(Blake2s224, h1, block[0..]); - var h = Blake2s224.init(); - h.update(&block); - h.final(out[0..]); + var h = Blake2s224.init(); + h.update(&block); + h.final(out[0..]); - htest.assertEqual(h1, out[0..]); + htest.assertEqual(h1, out[0..]); + } } test "blake2s256 single" { @@ -296,9 +315,32 @@ test "blake2s256 streaming" { htest.assertEqual(h3, out[0..]); } +test "blake2s256 keyed" { + var out: [32]u8 = undefined; + + 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(8000); + @setEvalBranchQuota(6000); var block = [_]u8{0} ** Blake2s256.block_length; var out: [Blake2s256.digest_length]u8 = undefined; @@ -358,10 +400,17 @@ pub 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; } @@ -369,14 +418,24 @@ pub 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 ^ @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 = 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); } @@ -519,19 +578,22 @@ test "blake2b384 streaming" { htest.assertEqual(h3, out[0..]); } -test "blake2b384 aligned final" { - var block = [_]u8{0} ** Blake2b384.block_length; - var out: [Blake2b384.digest_length]u8 = undefined; +test "comptime blake2b384" { + comptime { + @setEvalBranchQuota(7000); + var block = [_]u8{0} ** Blake2b384.block_length; + var out: [Blake2b384.digest_length]u8 = undefined; - const h1 = "e8aa1931ea0422e4446fecdd25c16cf35c240b10cb4659dd5c776eddcaa4d922397a589404b46eb2e53d78132d05fd7d"; + const h1 = "e8aa1931ea0422e4446fecdd25c16cf35c240b10cb4659dd5c776eddcaa4d922397a589404b46eb2e53d78132d05fd7d"; - htest.assertEqualHash(Blake2b384, h1, block[0..]); + htest.assertEqualHash(Blake2b384, h1, block[0..]); - var h = Blake2b384.init(); - h.update(&block); - h.final(out[0..]); + var h = Blake2b384.init(); + h.update(&block); + h.final(out[0..]); - htest.assertEqual(h1, out[0..]); + htest.assertEqual(h1, out[0..]); + } } test "blake2b512 single" { @@ -585,6 +647,29 @@ test "blake2b512 streaming" { 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); From 1df33936d61c18c40653631d9625f982f8e54dd8 Mon Sep 17 00:00:00 2001 From: Mantas Jonytis Date: Sat, 1 Aug 2020 17:15:53 +0300 Subject: [PATCH 8/8] remove unnecessary operations --- 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 a4ab64bda5..ab44ca5298 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -419,7 +419,7 @@ pub fn Blake2b(comptime out_len: usize) type { mem.copy(u64, 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 ^ (d.key.len << 8) ^ (out_len >> 3); d.t = 0; d.buf_len = 0;