master
1const std = @import("../std.zig");
2const mem = std.mem;
3const math = std.math;
4const debug = std.debug;
5const htest = @import("test.zig");
6
7const RoundParam = struct {
8 a: usize,
9 b: usize,
10 c: usize,
11 d: usize,
12 x: usize,
13 y: usize,
14};
15
16fn roundParam(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
17 return RoundParam{
18 .a = a,
19 .b = b,
20 .c = c,
21 .d = d,
22 .x = x,
23 .y = y,
24 };
25}
26
27/////////////////////
28// Blake2s
29
30pub const Blake2s128 = Blake2s(128);
31pub const Blake2s160 = Blake2s(160);
32pub const Blake2s224 = Blake2s(224);
33pub const Blake2s256 = Blake2s(256);
34
35pub fn Blake2s(comptime out_bits: usize) type {
36 return struct {
37 const Self = @This();
38 pub const block_length = 64;
39 pub const digest_length = out_bits / 8;
40 pub const key_length_min = 0;
41 pub const key_length_max = 32;
42 pub const key_length = 32; // recommended key length
43 pub const Options = struct { key: ?[]const u8 = null, salt: ?[8]u8 = null, context: ?[8]u8 = null, expected_out_bits: usize = out_bits };
44
45 const iv = [8]u32{
46 0x6A09E667,
47 0xBB67AE85,
48 0x3C6EF372,
49 0xA54FF53A,
50 0x510E527F,
51 0x9B05688C,
52 0x1F83D9AB,
53 0x5BE0CD19,
54 };
55
56 const sigma = [10][16]u8{
57 [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
58 [_]u8{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
59 [_]u8{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
60 [_]u8{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
61 [_]u8{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
62 [_]u8{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
63 [_]u8{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
64 [_]u8{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
65 [_]u8{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
66 [_]u8{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
67 };
68
69 h: [8]u32,
70 t: u64,
71 // Streaming cache
72 buf: [64]u8,
73 buf_len: u8,
74
75 pub fn init(options: Options) Self {
76 comptime debug.assert(8 <= out_bits and out_bits <= 256);
77
78 var d: Self = undefined;
79 d.h = iv;
80
81 const key_len = if (options.key) |key| key.len else 0;
82 // default parameters
83 d.h[0] ^= 0x01010000 ^ @as(u32, @truncate(key_len << 8)) ^ @as(u32, @intCast(options.expected_out_bits >> 3));
84 d.t = 0;
85 d.buf_len = 0;
86
87 if (options.salt) |salt| {
88 d.h[4] ^= mem.readInt(u32, salt[0..4], .little);
89 d.h[5] ^= mem.readInt(u32, salt[4..8], .little);
90 }
91 if (options.context) |context| {
92 d.h[6] ^= mem.readInt(u32, context[0..4], .little);
93 d.h[7] ^= mem.readInt(u32, context[4..8], .little);
94 }
95 if (key_len > 0) {
96 @memset(d.buf[key_len..], 0);
97 d.update(options.key.?);
98 d.buf_len = 64;
99 }
100 return d;
101 }
102
103 pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
104 var d = Self.init(options);
105 d.update(b);
106 d.final(out);
107 }
108
109 pub fn update(d: *Self, b: []const u8) void {
110 var off: usize = 0;
111
112 // Partial buffer exists from previous update. Copy into buffer then hash.
113 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
114 off += 64 - d.buf_len;
115 @memcpy(d.buf[d.buf_len..][0..off], b[0..off]);
116 d.t += 64;
117 d.round(d.buf[0..], false);
118 d.buf_len = 0;
119 }
120
121 // Full middle blocks.
122 while (off + 64 < b.len) : (off += 64) {
123 d.t += 64;
124 d.round(b[off..][0..64], false);
125 }
126
127 // Copy any remainder for next pass.
128 const b_slice = b[off..];
129 @memcpy(d.buf[d.buf_len..][0..b_slice.len], b_slice);
130 d.buf_len += @as(u8, @intCast(b_slice.len));
131 }
132
133 pub fn final(d: *Self, out: *[digest_length]u8) void {
134 @memset(d.buf[d.buf_len..], 0);
135 d.t += d.buf_len;
136 d.round(d.buf[0..], true);
137 for (&d.h) |*x| x.* = mem.nativeToLittle(u32, x.*);
138 out.* = @as(*[digest_length]u8, @ptrCast(&d.h)).*;
139 }
140
141 fn round(d: *Self, b: *const [64]u8, last: bool) void {
142 var m: [16]u32 = undefined;
143 var v: [16]u32 = undefined;
144
145 for (&m, 0..) |*r, i| {
146 r.* = mem.readInt(u32, b[4 * i ..][0..4], .little);
147 }
148
149 var k: usize = 0;
150 while (k < 8) : (k += 1) {
151 v[k] = d.h[k];
152 v[k + 8] = iv[k];
153 }
154
155 v[12] ^= @as(u32, @truncate(d.t));
156 v[13] ^= @as(u32, @intCast(d.t >> 32));
157 if (last) v[14] = ~v[14];
158
159 const rounds = comptime [_]RoundParam{
160 roundParam(0, 4, 8, 12, 0, 1),
161 roundParam(1, 5, 9, 13, 2, 3),
162 roundParam(2, 6, 10, 14, 4, 5),
163 roundParam(3, 7, 11, 15, 6, 7),
164 roundParam(0, 5, 10, 15, 8, 9),
165 roundParam(1, 6, 11, 12, 10, 11),
166 roundParam(2, 7, 8, 13, 12, 13),
167 roundParam(3, 4, 9, 14, 14, 15),
168 };
169
170 comptime var j: usize = 0;
171 inline while (j < 10) : (j += 1) {
172 inline for (rounds) |r| {
173 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
174 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], @as(usize, 16));
175 v[r.c] = v[r.c] +% v[r.d];
176 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], @as(usize, 12));
177 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
178 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], @as(usize, 8));
179 v[r.c] = v[r.c] +% v[r.d];
180 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], @as(usize, 7));
181 }
182 }
183
184 for (&d.h, 0..) |*r, i| {
185 r.* ^= v[i] ^ v[i + 8];
186 }
187 }
188 };
189}
190
191test "blake2s160 single" {
192 const h1 = "354c9c33f735962418bdacb9479873429c34916f";
193 try htest.assertEqualHash(Blake2s160, h1, "");
194
195 const h2 = "5ae3b99be29b01834c3b508521ede60438f8de17";
196 try htest.assertEqualHash(Blake2s160, h2, "abc");
197
198 const h3 = "5a604fec9713c369e84b0ed68daed7d7504ef240";
199 try htest.assertEqualHash(Blake2s160, h3, "The quick brown fox jumps over the lazy dog");
200
201 const h4 = "b60c4dc60e2681e58fbc24e77f07e02c69e72ed0";
202 try htest.assertEqualHash(Blake2s160, h4, "a" ** 32 ++ "b" ** 32);
203}
204
205test "blake2s160 streaming" {
206 var h = Blake2s160.init(.{});
207 var out: [20]u8 = undefined;
208
209 const h1 = "354c9c33f735962418bdacb9479873429c34916f";
210
211 h.final(out[0..]);
212 try htest.assertEqual(h1, out[0..]);
213
214 const h2 = "5ae3b99be29b01834c3b508521ede60438f8de17";
215
216 h = Blake2s160.init(.{});
217 h.update("abc");
218 h.final(out[0..]);
219 try htest.assertEqual(h2, out[0..]);
220
221 h = Blake2s160.init(.{});
222 h.update("a");
223 h.update("b");
224 h.update("c");
225 h.final(out[0..]);
226 try htest.assertEqual(h2, out[0..]);
227
228 const h3 = "b60c4dc60e2681e58fbc24e77f07e02c69e72ed0";
229
230 h = Blake2s160.init(.{});
231 h.update("a" ** 32);
232 h.update("b" ** 32);
233 h.final(out[0..]);
234 try htest.assertEqual(h3, out[0..]);
235
236 h = Blake2s160.init(.{});
237 h.update("a" ** 32 ++ "b" ** 32);
238 h.final(out[0..]);
239 try htest.assertEqual(h3, out[0..]);
240
241 const h4 = "4667fd60791a7fe41f939bca646b4529e296bd68";
242
243 h = Blake2s160.init(.{ .context = [_]u8{0x69} ** 8, .salt = [_]u8{0x42} ** 8 });
244 h.update("a" ** 32);
245 h.update("b" ** 32);
246 h.final(out[0..]);
247 try htest.assertEqual(h4, out[0..]);
248
249 h = Blake2s160.init(.{ .context = [_]u8{0x69} ** 8, .salt = [_]u8{0x42} ** 8 });
250 h.update("a" ** 32 ++ "b" ** 32);
251 h.final(out[0..]);
252 try htest.assertEqual(h4, out[0..]);
253}
254
255test "comptime blake2s160" {
256 //comptime
257 {
258 @setEvalBranchQuota(10000);
259 var block = [_]u8{0} ** Blake2s160.block_length;
260 var out: [Blake2s160.digest_length]u8 = undefined;
261
262 const h1 = "2c56ad9d0b2c8b474aafa93ab307db2f0940105f";
263
264 try htest.assertEqualHash(Blake2s160, h1, block[0..]);
265
266 var h = Blake2s160.init(.{});
267 h.update(&block);
268 h.final(out[0..]);
269
270 try htest.assertEqual(h1, out[0..]);
271 }
272}
273
274test "blake2s224 single" {
275 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
276 try htest.assertEqualHash(Blake2s224, h1, "");
277
278 const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55";
279 try htest.assertEqualHash(Blake2s224, h2, "abc");
280
281 const h3 = "e4e5cb6c7cae41982b397bf7b7d2d9d1949823ae78435326e8db4912";
282 try htest.assertEqualHash(Blake2s224, h3, "The quick brown fox jumps over the lazy dog");
283
284 const h4 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01";
285 try htest.assertEqualHash(Blake2s224, h4, "a" ** 32 ++ "b" ** 32);
286}
287
288test "blake2s224 streaming" {
289 var h = Blake2s224.init(.{});
290 var out: [28]u8 = undefined;
291
292 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
293
294 h.final(out[0..]);
295 try htest.assertEqual(h1, out[0..]);
296
297 const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55";
298
299 h = Blake2s224.init(.{});
300 h.update("abc");
301 h.final(out[0..]);
302 try htest.assertEqual(h2, out[0..]);
303
304 h = Blake2s224.init(.{});
305 h.update("a");
306 h.update("b");
307 h.update("c");
308 h.final(out[0..]);
309 try htest.assertEqual(h2, out[0..]);
310
311 const h3 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01";
312
313 h = Blake2s224.init(.{});
314 h.update("a" ** 32);
315 h.update("b" ** 32);
316 h.final(out[0..]);
317 try htest.assertEqual(h3, out[0..]);
318
319 h = Blake2s224.init(.{});
320 h.update("a" ** 32 ++ "b" ** 32);
321 h.final(out[0..]);
322 try htest.assertEqual(h3, out[0..]);
323
324 const h4 = "a4d6a9d253441b80e5dfd60a04db169ffab77aec56a2855c402828c3";
325
326 h = Blake2s224.init(.{ .context = [_]u8{0x69} ** 8, .salt = [_]u8{0x42} ** 8 });
327 h.update("a" ** 32);
328 h.update("b" ** 32);
329 h.final(out[0..]);
330 try htest.assertEqual(h4, out[0..]);
331
332 h = Blake2s224.init(.{ .context = [_]u8{0x69} ** 8, .salt = [_]u8{0x42} ** 8 });
333 h.update("a" ** 32 ++ "b" ** 32);
334 h.final(out[0..]);
335 try htest.assertEqual(h4, out[0..]);
336}
337
338test "comptime blake2s224" {
339 comptime {
340 @setEvalBranchQuota(10000);
341 var block = [_]u8{0} ** Blake2s224.block_length;
342 var out: [Blake2s224.digest_length]u8 = undefined;
343
344 const h1 = "86b7611563293f8c73627df7a6d6ba25ca0548c2a6481f7d116ee576";
345
346 try htest.assertEqualHash(Blake2s224, h1, block[0..]);
347
348 var h = Blake2s224.init(.{});
349 h.update(&block);
350 h.final(out[0..]);
351
352 try htest.assertEqual(h1, out[0..]);
353 }
354}
355
356test "blake2s256 single" {
357 const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9";
358 try htest.assertEqualHash(Blake2s256, h1, "");
359
360 const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982";
361 try htest.assertEqualHash(Blake2s256, h2, "abc");
362
363 const h3 = "606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812";
364 try htest.assertEqualHash(Blake2s256, h3, "The quick brown fox jumps over the lazy dog");
365
366 const h4 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977";
367 try htest.assertEqualHash(Blake2s256, h4, "a" ** 32 ++ "b" ** 32);
368}
369
370test "blake2s256 streaming" {
371 var h = Blake2s256.init(.{});
372 var out: [32]u8 = undefined;
373
374 const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9";
375
376 h.final(out[0..]);
377 try htest.assertEqual(h1, out[0..]);
378
379 const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982";
380
381 h = Blake2s256.init(.{});
382 h.update("abc");
383 h.final(out[0..]);
384 try htest.assertEqual(h2, out[0..]);
385
386 h = Blake2s256.init(.{});
387 h.update("a");
388 h.update("b");
389 h.update("c");
390 h.final(out[0..]);
391 try htest.assertEqual(h2, out[0..]);
392
393 const h3 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977";
394
395 h = Blake2s256.init(.{});
396 h.update("a" ** 32);
397 h.update("b" ** 32);
398 h.final(out[0..]);
399 try htest.assertEqual(h3, out[0..]);
400
401 h = Blake2s256.init(.{});
402 h.update("a" ** 32 ++ "b" ** 32);
403 h.final(out[0..]);
404 try htest.assertEqual(h3, out[0..]);
405}
406
407test "blake2s256 keyed" {
408 var out: [32]u8 = undefined;
409
410 const h1 = "10f918da4d74fab3302e48a5d67d03804b1ec95372a62a0f33b7c9fa28ba1ae6";
411 const key = "secret_key";
412
413 Blake2s256.hash("a" ** 64 ++ "b" ** 64, &out, .{ .key = key });
414 try htest.assertEqual(h1, out[0..]);
415
416 var h = Blake2s256.init(.{ .key = key });
417 h.update("a" ** 64 ++ "b" ** 64);
418 h.final(out[0..]);
419
420 try htest.assertEqual(h1, out[0..]);
421
422 h = Blake2s256.init(.{ .key = key });
423 h.update("a" ** 64);
424 h.update("b" ** 64);
425 h.final(out[0..]);
426
427 try htest.assertEqual(h1, out[0..]);
428}
429
430test "comptime blake2s256" {
431 comptime {
432 @setEvalBranchQuota(10000);
433 var block = [_]u8{0} ** Blake2s256.block_length;
434 var out: [Blake2s256.digest_length]u8 = undefined;
435
436 const h1 = "ae09db7cd54f42b490ef09b6bc541af688e4959bb8c53f359a6f56e38ab454a3";
437
438 try htest.assertEqualHash(Blake2s256, h1, block[0..]);
439
440 var h = Blake2s256.init(.{});
441 h.update(&block);
442 h.final(out[0..]);
443
444 try htest.assertEqual(h1, out[0..]);
445 }
446}
447
448/////////////////////
449// Blake2b
450
451pub const Blake2b128 = Blake2b(128);
452pub const Blake2b160 = Blake2b(160);
453pub const Blake2b256 = Blake2b(256);
454pub const Blake2b384 = Blake2b(384);
455pub const Blake2b512 = Blake2b(512);
456
457pub fn Blake2b(comptime out_bits: usize) type {
458 return struct {
459 const Self = @This();
460 pub const block_length = 128;
461 pub const digest_length = out_bits / 8;
462 pub const key_length_min = 0;
463 pub const key_length_max = 64;
464 pub const key_length = 32; // recommended key length
465 pub const Options = struct { key: ?[]const u8 = null, salt: ?[16]u8 = null, context: ?[16]u8 = null, expected_out_bits: usize = out_bits };
466
467 const iv = [8]u64{
468 0x6a09e667f3bcc908,
469 0xbb67ae8584caa73b,
470 0x3c6ef372fe94f82b,
471 0xa54ff53a5f1d36f1,
472 0x510e527fade682d1,
473 0x9b05688c2b3e6c1f,
474 0x1f83d9abfb41bd6b,
475 0x5be0cd19137e2179,
476 };
477
478 const sigma = [12][16]u8{
479 [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
480 [_]u8{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
481 [_]u8{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
482 [_]u8{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
483 [_]u8{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
484 [_]u8{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
485 [_]u8{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
486 [_]u8{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
487 [_]u8{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
488 [_]u8{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
489 [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
490 [_]u8{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
491 };
492
493 h: [8]u64,
494 t: u128,
495 // Streaming cache
496 buf: [128]u8,
497 buf_len: u8,
498
499 pub fn init(options: Options) Self {
500 comptime debug.assert(8 <= out_bits and out_bits <= 512);
501
502 var d: Self = undefined;
503 d.h = iv;
504
505 const key_len = if (options.key) |key| key.len else 0;
506 // default parameters
507 d.h[0] ^= 0x01010000 ^ (key_len << 8) ^ (options.expected_out_bits >> 3);
508 d.t = 0;
509 d.buf_len = 0;
510
511 if (options.salt) |salt| {
512 d.h[4] ^= mem.readInt(u64, salt[0..8], .little);
513 d.h[5] ^= mem.readInt(u64, salt[8..16], .little);
514 }
515 if (options.context) |context| {
516 d.h[6] ^= mem.readInt(u64, context[0..8], .little);
517 d.h[7] ^= mem.readInt(u64, context[8..16], .little);
518 }
519 if (key_len > 0) {
520 @memset(d.buf[key_len..], 0);
521 d.update(options.key.?);
522 d.buf_len = 128;
523 }
524 return d;
525 }
526
527 pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
528 var d = Self.init(options);
529 d.update(b);
530 d.final(out);
531 }
532
533 pub fn update(d: *Self, b: []const u8) void {
534 var off: usize = 0;
535
536 // Partial buffer exists from previous update. Copy into buffer then hash.
537 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
538 off += 128 - d.buf_len;
539 @memcpy(d.buf[d.buf_len..][0..off], b[0..off]);
540 d.t += 128;
541 d.round(d.buf[0..], false);
542 d.buf_len = 0;
543 }
544
545 // Full middle blocks.
546 while (off + 128 < b.len) : (off += 128) {
547 d.t += 128;
548 d.round(b[off..][0..128], false);
549 }
550
551 // Copy any remainder for next pass.
552 const b_slice = b[off..];
553 @memcpy(d.buf[d.buf_len..][0..b_slice.len], b_slice);
554 d.buf_len += @as(u8, @intCast(b_slice.len));
555 }
556
557 pub fn final(d: *Self, out: *[digest_length]u8) void {
558 @memset(d.buf[d.buf_len..], 0);
559 d.t += d.buf_len;
560 d.round(d.buf[0..], true);
561 for (&d.h) |*x| x.* = mem.nativeToLittle(u64, x.*);
562 out.* = @as(*[digest_length]u8, @ptrCast(&d.h)).*;
563 }
564
565 fn round(d: *Self, b: *const [128]u8, last: bool) void {
566 var m: [16]u64 = undefined;
567 var v: [16]u64 = undefined;
568
569 for (&m, 0..) |*r, i| {
570 r.* = mem.readInt(u64, b[8 * i ..][0..8], .little);
571 }
572
573 var k: usize = 0;
574 while (k < 8) : (k += 1) {
575 v[k] = d.h[k];
576 v[k + 8] = iv[k];
577 }
578
579 v[12] ^= @as(u64, @truncate(d.t));
580 v[13] ^= @as(u64, @intCast(d.t >> 64));
581 if (last) v[14] = ~v[14];
582
583 const rounds = comptime [_]RoundParam{
584 roundParam(0, 4, 8, 12, 0, 1),
585 roundParam(1, 5, 9, 13, 2, 3),
586 roundParam(2, 6, 10, 14, 4, 5),
587 roundParam(3, 7, 11, 15, 6, 7),
588 roundParam(0, 5, 10, 15, 8, 9),
589 roundParam(1, 6, 11, 12, 10, 11),
590 roundParam(2, 7, 8, 13, 12, 13),
591 roundParam(3, 4, 9, 14, 14, 15),
592 };
593
594 comptime var j: usize = 0;
595 inline while (j < 12) : (j += 1) {
596 inline for (rounds) |r| {
597 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
598 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], @as(usize, 32));
599 v[r.c] = v[r.c] +% v[r.d];
600 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], @as(usize, 24));
601 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
602 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], @as(usize, 16));
603 v[r.c] = v[r.c] +% v[r.d];
604 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], @as(usize, 63));
605 }
606 }
607
608 for (&d.h, 0..) |*r, i| {
609 r.* ^= v[i] ^ v[i + 8];
610 }
611 }
612 };
613}
614
615test "blake2b160 single" {
616 const h1 = "3345524abf6bbe1809449224b5972c41790b6cf2";
617 try htest.assertEqualHash(Blake2b160, h1, "");
618
619 const h2 = "384264f676f39536840523f284921cdc68b6846b";
620 try htest.assertEqualHash(Blake2b160, h2, "abc");
621
622 const h3 = "3c523ed102ab45a37d54f5610d5a983162fde84f";
623 try htest.assertEqualHash(Blake2b160, h3, "The quick brown fox jumps over the lazy dog");
624
625 const h4 = "43758f5de1740f651f1ae39de92260fe8bd5a11f";
626 try htest.assertEqualHash(Blake2b160, h4, "a" ** 64 ++ "b" ** 64);
627}
628
629test "blake2b160 streaming" {
630 var h = Blake2b160.init(.{});
631 var out: [20]u8 = undefined;
632
633 const h1 = "3345524abf6bbe1809449224b5972c41790b6cf2";
634
635 h.final(out[0..]);
636 try htest.assertEqual(h1, out[0..]);
637
638 const h2 = "384264f676f39536840523f284921cdc68b6846b";
639
640 h = Blake2b160.init(.{});
641 h.update("abc");
642 h.final(out[0..]);
643 try htest.assertEqual(h2, out[0..]);
644
645 h = Blake2b160.init(.{});
646 h.update("a");
647 h.update("b");
648 h.update("c");
649 h.final(out[0..]);
650 try htest.assertEqual(h2, out[0..]);
651
652 const h3 = "43758f5de1740f651f1ae39de92260fe8bd5a11f";
653
654 h = Blake2b160.init(.{});
655 h.update("a" ** 64 ++ "b" ** 64);
656 h.final(out[0..]);
657 try htest.assertEqual(h3, out[0..]);
658
659 h = Blake2b160.init(.{});
660 h.update("a" ** 64);
661 h.update("b" ** 64);
662 h.final(out[0..]);
663 try htest.assertEqual(h3, out[0..]);
664
665 h = Blake2b160.init(.{});
666 h.update("a" ** 64);
667 h.update("b" ** 64);
668 h.final(out[0..]);
669 try htest.assertEqual(h3, out[0..]);
670
671 const h4 = "72328f8a8200663752fc302d372b5dd9b49dd8dc";
672
673 h = Blake2b160.init(.{ .context = [_]u8{0x69} ** 16, .salt = [_]u8{0x42} ** 16 });
674 h.update("a" ** 64);
675 h.update("b" ** 64);
676 h.final(out[0..]);
677 try htest.assertEqual(h4, out[0..]);
678
679 h = Blake2b160.init(.{ .context = [_]u8{0x69} ** 16, .salt = [_]u8{0x42} ** 16 });
680 h.update("a" ** 64);
681 h.update("b" ** 64);
682 h.final(out[0..]);
683 try htest.assertEqual(h4, out[0..]);
684}
685
686test "comptime blake2b160" {
687 comptime {
688 @setEvalBranchQuota(10000);
689 var block = [_]u8{0} ** Blake2b160.block_length;
690 var out: [Blake2b160.digest_length]u8 = undefined;
691
692 const h1 = "8d26f158f564e3293b42f5e3d34263cb173aa9c9";
693
694 try htest.assertEqualHash(Blake2b160, h1, block[0..]);
695
696 var h = Blake2b160.init(.{});
697 h.update(&block);
698 h.final(out[0..]);
699
700 try htest.assertEqual(h1, out[0..]);
701 }
702}
703
704test "blake2b384 single" {
705 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
706 try htest.assertEqualHash(Blake2b384, h1, "");
707
708 const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4";
709 try htest.assertEqualHash(Blake2b384, h2, "abc");
710
711 const h3 = "b7c81b228b6bd912930e8f0b5387989691c1cee1e65aade4da3b86a3c9f678fc8018f6ed9e2906720c8d2a3aeda9c03d";
712 try htest.assertEqualHash(Blake2b384, h3, "The quick brown fox jumps over the lazy dog");
713
714 const h4 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c";
715 try htest.assertEqualHash(Blake2b384, h4, "a" ** 64 ++ "b" ** 64);
716}
717
718test "blake2b384 streaming" {
719 var h = Blake2b384.init(.{});
720 var out: [48]u8 = undefined;
721
722 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
723
724 h.final(out[0..]);
725 try htest.assertEqual(h1, out[0..]);
726
727 const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4";
728
729 h = Blake2b384.init(.{});
730 h.update("abc");
731 h.final(out[0..]);
732 try htest.assertEqual(h2, out[0..]);
733
734 h = Blake2b384.init(.{});
735 h.update("a");
736 h.update("b");
737 h.update("c");
738 h.final(out[0..]);
739 try htest.assertEqual(h2, out[0..]);
740
741 const h3 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c";
742
743 h = Blake2b384.init(.{});
744 h.update("a" ** 64 ++ "b" ** 64);
745 h.final(out[0..]);
746 try htest.assertEqual(h3, out[0..]);
747
748 h = Blake2b384.init(.{});
749 h.update("a" ** 64);
750 h.update("b" ** 64);
751 h.final(out[0..]);
752 try htest.assertEqual(h3, out[0..]);
753
754 h = Blake2b384.init(.{});
755 h.update("a" ** 64);
756 h.update("b" ** 64);
757 h.final(out[0..]);
758 try htest.assertEqual(h3, out[0..]);
759
760 const h4 = "934c48fcb197031c71f583d92f98703510805e72142e0b46f5752d1e971bc86c355d556035613ff7a4154b4de09dac5c";
761
762 h = Blake2b384.init(.{ .context = [_]u8{0x69} ** 16, .salt = [_]u8{0x42} ** 16 });
763 h.update("a" ** 64);
764 h.update("b" ** 64);
765 h.final(out[0..]);
766 try htest.assertEqual(h4, out[0..]);
767
768 h = Blake2b384.init(.{ .context = [_]u8{0x69} ** 16, .salt = [_]u8{0x42} ** 16 });
769 h.update("a" ** 64);
770 h.update("b" ** 64);
771 h.final(out[0..]);
772 try htest.assertEqual(h4, out[0..]);
773}
774
775test "comptime blake2b384" {
776 comptime {
777 @setEvalBranchQuota(20000);
778 var block = [_]u8{0} ** Blake2b384.block_length;
779 var out: [Blake2b384.digest_length]u8 = undefined;
780
781 const h1 = "e8aa1931ea0422e4446fecdd25c16cf35c240b10cb4659dd5c776eddcaa4d922397a589404b46eb2e53d78132d05fd7d";
782
783 try htest.assertEqualHash(Blake2b384, h1, block[0..]);
784
785 var h = Blake2b384.init(.{});
786 h.update(&block);
787 h.final(out[0..]);
788
789 try htest.assertEqual(h1, out[0..]);
790 }
791}
792
793test "blake2b512 single" {
794 const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
795 try htest.assertEqualHash(Blake2b512, h1, "");
796
797 const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
798 try htest.assertEqualHash(Blake2b512, h2, "abc");
799
800 const h3 = "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918";
801 try htest.assertEqualHash(Blake2b512, h3, "The quick brown fox jumps over the lazy dog");
802
803 const h4 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920";
804 try htest.assertEqualHash(Blake2b512, h4, "a" ** 64 ++ "b" ** 64);
805}
806
807test "blake2b512 streaming" {
808 var h = Blake2b512.init(.{});
809 var out: [64]u8 = undefined;
810
811 const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
812
813 h.final(out[0..]);
814 try htest.assertEqual(h1, out[0..]);
815
816 const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
817
818 h = Blake2b512.init(.{});
819 h.update("abc");
820 h.final(out[0..]);
821 try htest.assertEqual(h2, out[0..]);
822
823 h = Blake2b512.init(.{});
824 h.update("a");
825 h.update("b");
826 h.update("c");
827 h.final(out[0..]);
828 try htest.assertEqual(h2, out[0..]);
829
830 const h3 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920";
831
832 h = Blake2b512.init(.{});
833 h.update("a" ** 64 ++ "b" ** 64);
834 h.final(out[0..]);
835 try htest.assertEqual(h3, out[0..]);
836
837 h = Blake2b512.init(.{});
838 h.update("a" ** 64);
839 h.update("b" ** 64);
840 h.final(out[0..]);
841 try htest.assertEqual(h3, out[0..]);
842}
843
844test "blake2b512 keyed" {
845 var out: [64]u8 = undefined;
846
847 const h1 = "8a978060ccaf582f388f37454363071ac9a67e3a704585fd879fb8a419a447e389c7c6de790faa20a7a7dccf197de736bc5b40b98a930b36df5bee7555750c4d";
848 const key = "secret_key";
849
850 Blake2b512.hash("a" ** 64 ++ "b" ** 64, &out, .{ .key = key });
851 try htest.assertEqual(h1, out[0..]);
852
853 var h = Blake2b512.init(.{ .key = key });
854 h.update("a" ** 64 ++ "b" ** 64);
855 h.final(out[0..]);
856
857 try htest.assertEqual(h1, out[0..]);
858
859 h = Blake2b512.init(.{ .key = key });
860 h.update("a" ** 64);
861 h.update("b" ** 64);
862 h.final(out[0..]);
863
864 try htest.assertEqual(h1, out[0..]);
865}
866
867test "comptime blake2b512" {
868 comptime {
869 @setEvalBranchQuota(12000);
870 var block = [_]u8{0} ** Blake2b512.block_length;
871 var out: [Blake2b512.digest_length]u8 = undefined;
872
873 const h1 = "865939e120e6805438478841afb739ae4250cf372653078a065cdcfffca4caf798e6d462b65d658fc165782640eded70963449ae1500fb0f24981d7727e22c41";
874
875 try htest.assertEqualHash(Blake2b512, h1, block[0..]);
876
877 var h = Blake2b512.init(.{});
878 h.update(&block);
879 h.final(out[0..]);
880
881 try htest.assertEqual(h1, out[0..]);
882 }
883}