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}