authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-02 17:47:06+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-08-02 17:47:06+00:00
log35391f1709bb413e277ede1178d4714473561565
treed3f5b3ebbeaae76d930a11bd18bd978e9a7ddde4
parent6df35c5877c1a1060dcfd28d5d4092638e6e6754
parent1df33936d61c18c40653631d9625f982f8e54dd8
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5968 from haliucinas/blake2

Blake2 improvements

1 files changed, 224 insertions(+), 27 deletions(-)

lib/std/crypto/blake2.zig+224-27
...@@ -1,8 +1,7 @@...@@ -1,8 +1,7 @@
1const mem = @import("../mem.zig");1const mem = @import("../mem.zig");
2const math = @import("../math.zig");
3const endian = @import("../endian.zig");
4const debug = @import("../debug.zig");
5const builtin = @import("builtin");2const builtin = @import("builtin");
3const debug = @import("../debug.zig");
4const math = @import("../math.zig");
6const htest = @import("test.zig");5const htest = @import("test.zig");
76
8const RoundParam = struct {7const RoundParam = struct {
...@@ -31,7 +30,7 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {...@@ -31,7 +30,7 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
31pub const Blake2s224 = Blake2s(224);30pub const Blake2s224 = Blake2s(224);
32pub const Blake2s256 = Blake2s(256);31pub const Blake2s256 = Blake2s(256);
3332
34fn Blake2s(comptime out_len: usize) type {33pub fn Blake2s(comptime out_len: usize) type {
35 return struct {34 return struct {
36 const Self = @This();35 const Self = @This();
37 pub const block_length = 64;36 pub const block_length = 64;
...@@ -67,10 +66,17 @@ fn Blake2s(comptime out_len: usize) type {...@@ -67,10 +66,17 @@ fn Blake2s(comptime out_len: usize) type {
67 buf: [64]u8,66 buf: [64]u8,
68 buf_len: u8,67 buf_len: u8,
6968
69 key: []const u8,
70
70 pub fn init() Self {71 pub fn init() Self {
72 return init_keyed("");
73 }
74
75 pub fn init_keyed(key: []const u8) Self {
71 debug.assert(8 <= out_len and out_len <= 512);76 debug.assert(8 <= out_len and out_len <= 512);
7277
73 var s: Self = undefined;78 var s: Self = undefined;
79 s.key = key;
74 s.reset();80 s.reset();
75 return s;81 return s;
76 }82 }
...@@ -78,14 +84,24 @@ fn Blake2s(comptime out_len: usize) type {...@@ -78,14 +84,24 @@ fn Blake2s(comptime out_len: usize) type {
78 pub fn reset(d: *Self) void {84 pub fn reset(d: *Self) void {
79 mem.copy(u32, d.h[0..], iv[0..]);85 mem.copy(u32, d.h[0..], iv[0..]);
8086
81 // No key plus default parameters87 // default parameters
82 d.h[0] ^= 0x01010000 ^ @intCast(u32, out_len >> 3);88 d.h[0] ^= 0x01010000 ^ @truncate(u32, d.key.len << 8) ^ @intCast(u32, out_len >> 3);
83 d.t = 0;89 d.t = 0;
84 d.buf_len = 0;90 d.buf_len = 0;
91
92 if (d.key.len > 0) {
93 mem.set(u8, d.buf[d.key.len..], 0);
94 d.update(d.key);
95 d.buf_len = 64;
96 }
85 }97 }
8698
87 pub fn hash(b: []const u8, out: []u8) void {99 pub fn hash(b: []const u8, out: []u8) void {
88 var d = Self.init();100 Self.hash_keyed("", b, out);
101 }
102
103 pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void {
104 var d = Self.init_keyed(key);
89 d.update(b);105 d.update(b);
90 d.final(out);106 d.final(out);
91 }107 }
...@@ -94,7 +110,7 @@ fn Blake2s(comptime out_len: usize) type {...@@ -94,7 +110,7 @@ fn Blake2s(comptime out_len: usize) type {
94 var off: usize = 0;110 var off: usize = 0;
95111
96 // Partial buffer exists from previous update. Copy into buffer then hash.112 // Partial buffer exists from previous update. Copy into buffer then hash.
97 if (d.buf_len != 0 and d.buf_len + b.len >= 64) {113 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
98 off += 64 - d.buf_len;114 off += 64 - d.buf_len;
99 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);115 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
100 d.t += 64;116 d.t += 64;
...@@ -103,7 +119,7 @@ fn Blake2s(comptime out_len: usize) type {...@@ -103,7 +119,7 @@ fn Blake2s(comptime out_len: usize) type {
103 }119 }
104120
105 // Full middle blocks.121 // Full middle blocks.
106 while (off + 64 <= b.len) : (off += 64) {122 while (off + 64 < b.len) : (off += 64) {
107 d.t += 64;123 d.t += 64;
108 d.round(b[off .. off + 64], false);124 d.round(b[off .. off + 64], false);
109 }125 }
...@@ -123,7 +139,7 @@ fn Blake2s(comptime out_len: usize) type {...@@ -123,7 +139,7 @@ fn Blake2s(comptime out_len: usize) type {
123 const rr = d.h[0 .. out_len / 32];139 const rr = d.h[0 .. out_len / 32];
124140
125 for (rr) |s, j| {141 for (rr) |s, j| {
126 mem.writeIntLittle(u32, out[4 * j ..][0..4], s);142 mem.writeIntSliceLittle(u32, out[4 * j ..], s);
127 }143 }
128 }144 }
129145
...@@ -188,6 +204,9 @@ test "blake2s224 single" {...@@ -188,6 +204,9 @@ test "blake2s224 single" {
188204
189 const h3 = "e4e5cb6c7cae41982b397bf7b7d2d9d1949823ae78435326e8db4912";205 const h3 = "e4e5cb6c7cae41982b397bf7b7d2d9d1949823ae78435326e8db4912";
190 htest.assertEqualHash(Blake2s224, h3, "The quick brown fox jumps over the lazy dog");206 htest.assertEqualHash(Blake2s224, h3, "The quick brown fox jumps over the lazy dog");
207
208 const h4 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01";
209 htest.assertEqualHash(Blake2s224, h4, "a" ** 32 ++ "b" ** 32);
191}210}
192211
193test "blake2s224 streaming" {212test "blake2s224 streaming" {
...@@ -212,6 +231,37 @@ test "blake2s224 streaming" {...@@ -212,6 +231,37 @@ test "blake2s224 streaming" {
212 h.update("c");231 h.update("c");
213 h.final(out[0..]);232 h.final(out[0..]);
214 htest.assertEqual(h2, out[0..]);233 htest.assertEqual(h2, out[0..]);
234
235 const h3 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01";
236
237 h.reset();
238 h.update("a" ** 32);
239 h.update("b" ** 32);
240 h.final(out[0..]);
241 htest.assertEqual(h3, out[0..]);
242
243 h.reset();
244 h.update("a" ** 32 ++ "b" ** 32);
245 h.final(out[0..]);
246 htest.assertEqual(h3, out[0..]);
247}
248
249test "comptime blake2s224" {
250 comptime {
251 @setEvalBranchQuota(6000);
252 var block = [_]u8{0} ** Blake2s224.block_length;
253 var out: [Blake2s224.digest_length]u8 = undefined;
254
255 const h1 = "86b7611563293f8c73627df7a6d6ba25ca0548c2a6481f7d116ee576";
256
257 htest.assertEqualHash(Blake2s224, h1, block[0..]);
258
259 var h = Blake2s224.init();
260 h.update(&block);
261 h.final(out[0..]);
262
263 htest.assertEqual(h1, out[0..]);
264 }
215}265}
216266
217test "blake2s256 single" {267test "blake2s256 single" {
...@@ -223,6 +273,9 @@ test "blake2s256 single" {...@@ -223,6 +273,9 @@ test "blake2s256 single" {
223273
224 const h3 = "606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812";274 const h3 = "606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812";
225 htest.assertEqualHash(Blake2s256, h3, "The quick brown fox jumps over the lazy dog");275 htest.assertEqualHash(Blake2s256, h3, "The quick brown fox jumps over the lazy dog");
276
277 const h4 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977";
278 htest.assertEqualHash(Blake2s256, h4, "a" ** 32 ++ "b" ** 32);
226}279}
227280
228test "blake2s256 streaming" {281test "blake2s256 streaming" {
...@@ -247,15 +300,60 @@ test "blake2s256 streaming" {...@@ -247,15 +300,60 @@ test "blake2s256 streaming" {
247 h.update("c");300 h.update("c");
248 h.final(out[0..]);301 h.final(out[0..]);
249 htest.assertEqual(h2, out[0..]);302 htest.assertEqual(h2, out[0..]);
303
304 const h3 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977";
305
306 h.reset();
307 h.update("a" ** 32);
308 h.update("b" ** 32);
309 h.final(out[0..]);
310 htest.assertEqual(h3, out[0..]);
311
312 h.reset();
313 h.update("a" ** 32 ++ "b" ** 32);
314 h.final(out[0..]);
315 htest.assertEqual(h3, out[0..]);
250}316}
251317
252test "blake2s256 aligned final" {318test "blake2s256 keyed" {
253 var block = [_]u8{0} ** Blake2s256.block_length;319 var out: [32]u8 = undefined;
254 var out: [Blake2s256.digest_length]u8 = undefined;320
321 const h1 = "10f918da4d74fab3302e48a5d67d03804b1ec95372a62a0f33b7c9fa28ba1ae6";
322 const key = "secret_key";
255323
256 var h = Blake2s256.init();324 Blake2s256.hash_keyed(key, "a" ** 64 ++ "b" ** 64, &out);
257 h.update(&block);325 htest.assertEqual(h1, out[0..]);
326
327 var h = Blake2s256.init_keyed(key);
328 h.update("a" ** 64 ++ "b" ** 64);
329 h.final(out[0..]);
330
331 htest.assertEqual(h1, out[0..]);
332
333 h.reset();
334 h.update("a" ** 64);
335 h.update("b" ** 64);
258 h.final(out[0..]);336 h.final(out[0..]);
337
338 htest.assertEqual(h1, out[0..]);
339}
340
341test "comptime blake2s256" {
342 comptime {
343 @setEvalBranchQuota(6000);
344 var block = [_]u8{0} ** Blake2s256.block_length;
345 var out: [Blake2s256.digest_length]u8 = undefined;
346
347 const h1 = "ae09db7cd54f42b490ef09b6bc541af688e4959bb8c53f359a6f56e38ab454a3";
348
349 htest.assertEqualHash(Blake2s256, h1, block[0..]);
350
351 var h = Blake2s256.init();
352 h.update(&block);
353 h.final(out[0..]);
354
355 htest.assertEqual(h1, out[0..]);
356 }
259}357}
260358
261/////////////////////359/////////////////////
...@@ -264,7 +362,7 @@ test "blake2s256 aligned final" {...@@ -264,7 +362,7 @@ test "blake2s256 aligned final" {
264pub const Blake2b384 = Blake2b(384);362pub const Blake2b384 = Blake2b(384);
265pub const Blake2b512 = Blake2b(512);363pub const Blake2b512 = Blake2b(512);
266364
267fn Blake2b(comptime out_len: usize) type {365pub fn Blake2b(comptime out_len: usize) type {
268 return struct {366 return struct {
269 const Self = @This();367 const Self = @This();
270 pub const block_length = 128;368 pub const block_length = 128;
...@@ -302,10 +400,17 @@ fn Blake2b(comptime out_len: usize) type {...@@ -302,10 +400,17 @@ fn Blake2b(comptime out_len: usize) type {
302 buf: [128]u8,400 buf: [128]u8,
303 buf_len: u8,401 buf_len: u8,
304402
403 key: []const u8,
404
305 pub fn init() Self {405 pub fn init() Self {
406 return init_keyed("");
407 }
408
409 pub fn init_keyed(key: []const u8) Self {
306 debug.assert(8 <= out_len and out_len <= 512);410 debug.assert(8 <= out_len and out_len <= 512);
307411
308 var s: Self = undefined;412 var s: Self = undefined;
413 s.key = key;
309 s.reset();414 s.reset();
310 return s;415 return s;
311 }416 }
...@@ -313,14 +418,24 @@ fn Blake2b(comptime out_len: usize) type {...@@ -313,14 +418,24 @@ fn Blake2b(comptime out_len: usize) type {
313 pub fn reset(d: *Self) void {418 pub fn reset(d: *Self) void {
314 mem.copy(u64, d.h[0..], iv[0..]);419 mem.copy(u64, d.h[0..], iv[0..]);
315420
316 // No key plus default parameters421 // default parameters
317 d.h[0] ^= 0x01010000 ^ (out_len >> 3);422 d.h[0] ^= 0x01010000 ^ (d.key.len << 8) ^ (out_len >> 3);
318 d.t = 0;423 d.t = 0;
319 d.buf_len = 0;424 d.buf_len = 0;
425
426 if (d.key.len > 0) {
427 mem.set(u8, d.buf[d.key.len..], 0);
428 d.update(d.key);
429 d.buf_len = 128;
430 }
320 }431 }
321432
322 pub fn hash(b: []const u8, out: []u8) void {433 pub fn hash(b: []const u8, out: []u8) void {
323 var d = Self.init();434 Self.hash_keyed("", b, out);
435 }
436
437 pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void {
438 var d = Self.init_keyed(key);
324 d.update(b);439 d.update(b);
325 d.final(out);440 d.final(out);
326 }441 }
...@@ -329,7 +444,7 @@ fn Blake2b(comptime out_len: usize) type {...@@ -329,7 +444,7 @@ fn Blake2b(comptime out_len: usize) type {
329 var off: usize = 0;444 var off: usize = 0;
330445
331 // Partial buffer exists from previous update. Copy into buffer then hash.446 // Partial buffer exists from previous update. Copy into buffer then hash.
332 if (d.buf_len != 0 and d.buf_len + b.len >= 128) {447 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
333 off += 128 - d.buf_len;448 off += 128 - d.buf_len;
334 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);449 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
335 d.t += 128;450 d.t += 128;
...@@ -338,7 +453,7 @@ fn Blake2b(comptime out_len: usize) type {...@@ -338,7 +453,7 @@ fn Blake2b(comptime out_len: usize) type {
338 }453 }
339454
340 // Full middle blocks.455 // Full middle blocks.
341 while (off + 128 <= b.len) : (off += 128) {456 while (off + 128 < b.len) : (off += 128) {
342 d.t += 128;457 d.t += 128;
343 d.round(b[off .. off + 128], false);458 d.round(b[off .. off + 128], false);
344 }459 }
...@@ -356,7 +471,7 @@ fn Blake2b(comptime out_len: usize) type {...@@ -356,7 +471,7 @@ fn Blake2b(comptime out_len: usize) type {
356 const rr = d.h[0 .. out_len / 64];471 const rr = d.h[0 .. out_len / 64];
357472
358 for (rr) |s, j| {473 for (rr) |s, j| {
359 mem.writeIntLittle(u64, out[8 * j ..][0..8], s);474 mem.writeIntSliceLittle(u64, out[8 * j ..], s);
360 }475 }
361 }476 }
362477
...@@ -421,6 +536,9 @@ test "blake2b384 single" {...@@ -421,6 +536,9 @@ test "blake2b384 single" {
421536
422 const h3 = "b7c81b228b6bd912930e8f0b5387989691c1cee1e65aade4da3b86a3c9f678fc8018f6ed9e2906720c8d2a3aeda9c03d";537 const h3 = "b7c81b228b6bd912930e8f0b5387989691c1cee1e65aade4da3b86a3c9f678fc8018f6ed9e2906720c8d2a3aeda9c03d";
423 htest.assertEqualHash(Blake2b384, h3, "The quick brown fox jumps over the lazy dog");538 htest.assertEqualHash(Blake2b384, h3, "The quick brown fox jumps over the lazy dog");
539
540 const h4 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c";
541 htest.assertEqualHash(Blake2b384, h4, "a" ** 64 ++ "b" ** 64);
424}542}
425543
426test "blake2b384 streaming" {544test "blake2b384 streaming" {
...@@ -445,6 +563,37 @@ test "blake2b384 streaming" {...@@ -445,6 +563,37 @@ test "blake2b384 streaming" {
445 h.update("c");563 h.update("c");
446 h.final(out[0..]);564 h.final(out[0..]);
447 htest.assertEqual(h2, out[0..]);565 htest.assertEqual(h2, out[0..]);
566
567 const h3 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c";
568
569 h.reset();
570 h.update("a" ** 64 ++ "b" ** 64);
571 h.final(out[0..]);
572 htest.assertEqual(h3, out[0..]);
573
574 h.reset();
575 h.update("a" ** 64);
576 h.update("b" ** 64);
577 h.final(out[0..]);
578 htest.assertEqual(h3, out[0..]);
579}
580
581test "comptime blake2b384" {
582 comptime {
583 @setEvalBranchQuota(7000);
584 var block = [_]u8{0} ** Blake2b384.block_length;
585 var out: [Blake2b384.digest_length]u8 = undefined;
586
587 const h1 = "e8aa1931ea0422e4446fecdd25c16cf35c240b10cb4659dd5c776eddcaa4d922397a589404b46eb2e53d78132d05fd7d";
588
589 htest.assertEqualHash(Blake2b384, h1, block[0..]);
590
591 var h = Blake2b384.init();
592 h.update(&block);
593 h.final(out[0..]);
594
595 htest.assertEqual(h1, out[0..]);
596 }
448}597}
449598
450test "blake2b512 single" {599test "blake2b512 single" {
...@@ -456,6 +605,9 @@ test "blake2b512 single" {...@@ -456,6 +605,9 @@ test "blake2b512 single" {
456605
457 const h3 = "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918";606 const h3 = "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918";
458 htest.assertEqualHash(Blake2b512, h3, "The quick brown fox jumps over the lazy dog");607 htest.assertEqualHash(Blake2b512, h3, "The quick brown fox jumps over the lazy dog");
608
609 const h4 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920";
610 htest.assertEqualHash(Blake2b512, h4, "a" ** 64 ++ "b" ** 64);
459}611}
460612
461test "blake2b512 streaming" {613test "blake2b512 streaming" {
...@@ -480,13 +632,58 @@ test "blake2b512 streaming" {...@@ -480,13 +632,58 @@ test "blake2b512 streaming" {
480 h.update("c");632 h.update("c");
481 h.final(out[0..]);633 h.final(out[0..]);
482 htest.assertEqual(h2, out[0..]);634 htest.assertEqual(h2, out[0..]);
635
636 const h3 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920";
637
638 h.reset();
639 h.update("a" ** 64 ++ "b" ** 64);
640 h.final(out[0..]);
641 htest.assertEqual(h3, out[0..]);
642
643 h.reset();
644 h.update("a" ** 64);
645 h.update("b" ** 64);
646 h.final(out[0..]);
647 htest.assertEqual(h3, out[0..]);
483}648}
484649
485test "blake2b512 aligned final" {650test "blake2b512 keyed" {
486 var block = [_]u8{0} ** Blake2b512.block_length;651 var out: [64]u8 = undefined;
487 var out: [Blake2b512.digest_length]u8 = undefined;
488652
489 var h = Blake2b512.init();653 const h1 = "8a978060ccaf582f388f37454363071ac9a67e3a704585fd879fb8a419a447e389c7c6de790faa20a7a7dccf197de736bc5b40b98a930b36df5bee7555750c4d";
490 h.update(&block);654 const key = "secret_key";
655
656 Blake2b512.hash_keyed(key, "a" ** 64 ++ "b" ** 64, &out);
657 htest.assertEqual(h1, out[0..]);
658
659 var h = Blake2b512.init_keyed(key);
660 h.update("a" ** 64 ++ "b" ** 64);
661 h.final(out[0..]);
662
663 htest.assertEqual(h1, out[0..]);
664
665 h.reset();
666 h.update("a" ** 64);
667 h.update("b" ** 64);
491 h.final(out[0..]);668 h.final(out[0..]);
669
670 htest.assertEqual(h1, out[0..]);
671}
672
673test "comptime blake2b512" {
674 comptime {
675 @setEvalBranchQuota(8000);
676 var block = [_]u8{0} ** Blake2b512.block_length;
677 var out: [Blake2b512.digest_length]u8 = undefined;
678
679 const h1 = "865939e120e6805438478841afb739ae4250cf372653078a065cdcfffca4caf798e6d462b65d658fc165782640eded70963449ae1500fb0f24981d7727e22c41";
680
681 htest.assertEqualHash(Blake2b512, h1, block[0..]);
682
683 var h = Blake2b512.init();
684 h.update(&block);
685 h.final(out[0..]);
686
687 htest.assertEqual(h1, out[0..]);
688 }
492}689}