authorgravatar for clickingbuttons@pm.meclickingbuttons <clickingbuttons@pm.me> 2024-04-28 16:22:09-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-04-28 22:22:09+02:00
log8a36a1f913c729993d53786486b542c0501dc27d
treeb648a1b375e543737e019ba238d56a5d1a6e13d9
parent25f1526fe6424cef156724977b75a5b80a3d5833
signaturebadge-check Signed by PGP key B5690EEEBB952194

std.crypto.hash.sha2: cleanup add add more docs (#19744)

* std.crypto.hash.sha2: generalize sha512 truncation Replace `Sha512224`, `Sha512256`, and `Sha512T224` with `fn Sha512Truncated(digest_bits: comptime_int)`. This required refactoring `Sha2x64(comptime params)` to `Sha2x64(comptime iv: [8]u64, digest_bits: comptime_int)` for user-specified `digest_bits`. I left #19697 alone but added a compile-time check that digest_bits is divisible by 8. Remove docs which restate type name. Add module docs and reference where IVs come from. * std.crypto.sha2: make Sha512_224 and Sha512_256 pub * make generic type implementation detail, add comments * fix iv * address @jedisct1 feedback * fix typo * renaming * add truncation clarifying comment and Sha259T192 tests

1 files changed, 238 insertions(+), 283 deletions(-)

lib/std/crypto/sha2.zig+238-283
......@@ -1,87 +1,97 @@
1//! Secure Hashing Algorithm 2 (SHA2)
2//!
3//! Published by the National Institue of Standards and Technology (NIST) [1] [2].
4//!
5//! Truncation mitigates length-extension attacks but increases vulnerability to collision
6//! attacks. Collision attacks remain impractical for all types defined here.
7//!
8//! T: original hash function, whose output is simply truncated.
9//! A truncated output is just the first bytes of a longer output.
10//! _: hash function with context separation.
11//! Different lengths produce completely different outputs.
12//!
13//! [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
14//! [2] https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-208.pdf
15
116const std = @import("../std.zig");
217const builtin = @import("builtin");
318const mem = std.mem;
419const math = std.math;
520const htest = @import("test.zig");
621
7/////////////////////
8// Sha224 + Sha256
9
10const RoundParam256 = struct {
11 a: usize,
12 b: usize,
13 c: usize,
14 d: usize,
15 e: usize,
16 f: usize,
17 g: usize,
18 h: usize,
19 i: usize,
22pub const Sha224 = Sha2x32(iv224, 224);
23pub const Sha256 = Sha2x32(iv256, 256);
24pub const Sha384 = Sha2x64(iv384, 384);
25pub const Sha512 = Sha2x64(iv512, 512);
26
27/// SHA-256 truncated to leftmost 192 bits.
28pub const Sha256T192 = Sha2x32(iv256, 192);
29
30/// SHA-512 truncated to leftmost 224 bits.
31pub const Sha512T224 = Sha2x64(iv512, 224);
32/// SHA-512 truncated to leftmost 256 bits.
33pub const Sha512T256 = Sha2x64(iv512, 256);
34
35/// SHA-512 with a different initialization vector truncated to leftmost 224 bits.
36pub const Sha512_224 = Sha2x64(truncatedSha512Iv(224), 224);
37/// SHA-512 with a different initialization vector truncated to leftmost 256 bits.
38pub const Sha512_256 = Sha2x64(truncatedSha512Iv(256), 256);
39
40/// Low 32 bits of iv384.
41const iv224 = Iv32{
42 0xC1059ED8,
43 0x367CD507,
44 0x3070DD17,
45 0xF70E5939,
46 0xFFC00B31,
47 0x68581511,
48 0x64F98FA7,
49 0xBEFA4FA4,
2050};
21
22fn roundParam256(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize) RoundParam256 {
23 return RoundParam256{
24 .a = a,
25 .b = b,
26 .c = c,
27 .d = d,
28 .e = e,
29 .f = f,
30 .g = g,
31 .h = h,
32 .i = i,
33 };
34}
35
36const Sha2Params32 = struct {
37 iv0: u32,
38 iv1: u32,
39 iv2: u32,
40 iv3: u32,
41 iv4: u32,
42 iv5: u32,
43 iv6: u32,
44 iv7: u32,
45 digest_bits: usize,
51/// First thirty-two bits of the fractional parts of the square
52/// roots of the first eight prime numbers.
53const iv256 = Iv32{
54 0x6A09E667,
55 0xBB67AE85,
56 0x3C6EF372,
57 0xA54FF53A,
58 0x510E527F,
59 0x9B05688C,
60 0x1F83D9AB,
61 0x5BE0CD19,
4662};
4763
48const Sha224Params = Sha2Params32{
49 .iv0 = 0xC1059ED8,
50 .iv1 = 0x367CD507,
51 .iv2 = 0x3070DD17,
52 .iv3 = 0xF70E5939,
53 .iv4 = 0xFFC00B31,
54 .iv5 = 0x68581511,
55 .iv6 = 0x64F98FA7,
56 .iv7 = 0xBEFA4FA4,
57 .digest_bits = 224,
64/// First sixty-four bits of the fractional parts of the square
65/// roots of the ninth through sixteenth prime numbers.
66const iv384 = Iv64{
67 0xCBBB9D5DC1059ED8,
68 0x629A292A367CD507,
69 0x9159015A3070DD17,
70 0x152FECD8F70E5939,
71 0x67332667FFC00B31,
72 0x8EB44A8768581511,
73 0xDB0C2E0D64F98FA7,
74 0x47B5481DBEFA4FA4,
5875};
59
60const Sha256Params = Sha2Params32{
61 .iv0 = 0x6A09E667,
62 .iv1 = 0xBB67AE85,
63 .iv2 = 0x3C6EF372,
64 .iv3 = 0xA54FF53A,
65 .iv4 = 0x510E527F,
66 .iv5 = 0x9B05688C,
67 .iv6 = 0x1F83D9AB,
68 .iv7 = 0x5BE0CD19,
69 .digest_bits = 256,
76/// First sixty-four bits of the fractional parts of the square
77/// roots of the first eight prime numbers.
78const iv512 = Iv64{
79 0x6A09E667F3BCC908,
80 0xBB67AE8584CAA73B,
81 0x3C6EF372FE94F82B,
82 0xA54FF53A5F1D36F1,
83 0x510E527FADE682D1,
84 0x9B05688C2B3E6C1F,
85 0x1F83D9ABFB41BD6B,
86 0x5BE0CD19137E2179,
7087};
7188
72const v4u32 = @Vector(4, u32);
73
74/// SHA-224
75pub const Sha224 = Sha2x32(Sha224Params);
76
77/// SHA-256
78pub const Sha256 = Sha2x32(Sha256Params);
79
80fn Sha2x32(comptime params: Sha2Params32) type {
89const Iv32 = [8]u32;
90fn Sha2x32(comptime iv: Iv32, digest_bits: comptime_int) type {
8191 return struct {
8292 const Self = @This();
8393 pub const block_length = 64;
84 pub const digest_length = params.digest_bits / 8;
94 pub const digest_length = digest_bits / 8;
8595 pub const Options = struct {};
8696
8797 s: [8]u32 align(16),
......@@ -92,18 +102,7 @@ fn Sha2x32(comptime params: Sha2Params32) type {
92102
93103 pub fn init(options: Options) Self {
94104 _ = options;
95 return Self{
96 .s = [_]u32{
97 params.iv0,
98 params.iv1,
99 params.iv2,
100 params.iv3,
101 params.iv4,
102 params.iv5,
103 params.iv6,
104 params.iv7,
105 },
106 };
105 return Self{ .s = iv };
107106 }
108107
109108 pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
......@@ -167,8 +166,8 @@ fn Sha2x32(comptime params: Sha2Params32) type {
167166
168167 d.round(&d.buf);
169168
170 // May truncate for possible 224 output
171 const rr = d.s[0 .. params.digest_bits / 32];
169 // May truncate for possible 224 or 192 output
170 const rr = d.s[0 .. digest_length / 4];
172171
173172 for (rr, 0..) |s, j| {
174173 mem.writeInt(u32, out[4 * j ..][0..4], s, .big);
......@@ -199,11 +198,12 @@ fn Sha2x32(comptime params: Sha2Params32) type {
199198 }
200199
201200 if (!@inComptime()) {
201 const V4u32 = @Vector(4, u32);
202202 switch (builtin.cpu.arch) {
203203 .aarch64 => if (builtin.zig_backend != .stage2_c and comptime std.Target.aarch64.featureSetHas(builtin.cpu.features, .sha2)) {
204 var x: v4u32 = d.s[0..4].*;
205 var y: v4u32 = d.s[4..8].*;
206 const s_v = @as(*[16]v4u32, @ptrCast(&s));
204 var x: V4u32 = d.s[0..4].*;
205 var y: V4u32 = d.s[4..8].*;
206 const s_v = @as(*[16]V4u32, @ptrCast(&s));
207207
208208 comptime var k: u8 = 0;
209209 inline while (k < 16) : (k += 1) {
......@@ -211,7 +211,7 @@ fn Sha2x32(comptime params: Sha2Params32) type {
211211 s_v[k] = asm (
212212 \\sha256su0.4s %[w0_3], %[w4_7]
213213 \\sha256su1.4s %[w0_3], %[w8_11], %[w12_15]
214 : [w0_3] "=w" (-> v4u32),
214 : [w0_3] "=w" (-> V4u32),
215215 : [_] "0" (s_v[k - 4]),
216216 [w4_7] "w" (s_v[k - 3]),
217217 [w8_11] "w" (s_v[k - 2]),
......@@ -219,7 +219,7 @@ fn Sha2x32(comptime params: Sha2Params32) type {
219219 );
220220 }
221221
222 const w: v4u32 = s_v[k] +% @as(v4u32, W[4 * k ..][0..4].*);
222 const w: V4u32 = s_v[k] +% @as(V4u32, W[4 * k ..][0..4].*);
223223 asm volatile (
224224 \\mov.4s v0, %[x]
225225 \\sha256h.4s %[x], %[y], %[w]
......@@ -233,15 +233,15 @@ fn Sha2x32(comptime params: Sha2Params32) type {
233233 );
234234 }
235235
236 d.s[0..4].* = x +% @as(v4u32, d.s[0..4].*);
237 d.s[4..8].* = y +% @as(v4u32, d.s[4..8].*);
236 d.s[0..4].* = x +% @as(V4u32, d.s[0..4].*);
237 d.s[4..8].* = y +% @as(V4u32, d.s[4..8].*);
238238 return;
239239 },
240240 // C backend doesn't currently support passing vectors to inline asm.
241241 .x86_64 => if (builtin.zig_backend != .stage2_c and comptime std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sha, .avx2 })) {
242 var x: v4u32 = [_]u32{ d.s[5], d.s[4], d.s[1], d.s[0] };
243 var y: v4u32 = [_]u32{ d.s[7], d.s[6], d.s[3], d.s[2] };
244 const s_v = @as(*[16]v4u32, @ptrCast(&s));
242 var x: V4u32 = [_]u32{ d.s[5], d.s[4], d.s[1], d.s[0] };
243 var y: V4u32 = [_]u32{ d.s[7], d.s[6], d.s[3], d.s[2] };
244 const s_v = @as(*[16]V4u32, @ptrCast(&s));
245245
246246 comptime var k: u8 = 0;
247247 inline while (k < 16) : (k += 1) {
......@@ -253,7 +253,7 @@ fn Sha2x32(comptime params: Sha2Params32) type {
253253 \\ paddd %[tmp], %[result]
254254 \\ sha256msg2 %[w12_15], %[result]
255255 : [tmp] "=&x" (tmp),
256 [result] "=&x" (-> v4u32),
256 [result] "=&x" (-> V4u32),
257257 : [_] "0" (tmp),
258258 [w4_7] "x" (s_v[k + 1]),
259259 [w8_11] "x" (s_v[k + 2]),
......@@ -261,19 +261,19 @@ fn Sha2x32(comptime params: Sha2Params32) type {
261261 );
262262 }
263263
264 const w: v4u32 = s_v[k] +% @as(v4u32, W[4 * k ..][0..4].*);
264 const w: V4u32 = s_v[k] +% @as(V4u32, W[4 * k ..][0..4].*);
265265 y = asm ("sha256rnds2 %[x], %[y]"
266 : [y] "=x" (-> v4u32),
266 : [y] "=x" (-> V4u32),
267267 : [_] "0" (y),
268268 [x] "x" (x),
269269 [_] "{xmm0}" (w),
270270 );
271271
272272 x = asm ("sha256rnds2 %[y], %[x]"
273 : [x] "=x" (-> v4u32),
273 : [x] "=x" (-> V4u32),
274274 : [_] "0" (x),
275275 [y] "x" (y),
276 [_] "{xmm0}" (@as(v4u32, @bitCast(@as(u128, @bitCast(w)) >> 64))),
276 [_] "{xmm0}" (@as(V4u32, @bitCast(@as(u128, @bitCast(w)) >> 64))),
277277 );
278278 }
279279
......@@ -296,16 +296,7 @@ fn Sha2x32(comptime params: Sha2Params32) type {
296296 s[i] = s[i - 16] +% s[i - 7] +% (math.rotr(u32, s[i - 15], @as(u32, 7)) ^ math.rotr(u32, s[i - 15], @as(u32, 18)) ^ (s[i - 15] >> 3)) +% (math.rotr(u32, s[i - 2], @as(u32, 17)) ^ math.rotr(u32, s[i - 2], @as(u32, 19)) ^ (s[i - 2] >> 10));
297297 }
298298
299 var v: [8]u32 = [_]u32{
300 d.s[0],
301 d.s[1],
302 d.s[2],
303 d.s[3],
304 d.s[4],
305 d.s[5],
306 d.s[6],
307 d.s[7],
308 };
299 var v: [8]u32 = d.s;
309300
310301 const round0 = comptime [_]RoundParam256{
311302 roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 0),
......@@ -381,14 +372,7 @@ fn Sha2x32(comptime params: Sha2Params32) type {
381372 v[r.h] = v[r.h] +% (math.rotr(u32, v[r.a], @as(u32, 2)) ^ math.rotr(u32, v[r.a], @as(u32, 13)) ^ math.rotr(u32, v[r.a], @as(u32, 22))) +% ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
382373 }
383374
384 d.s[0] +%= v[0];
385 d.s[1] +%= v[1];
386 d.s[2] +%= v[2];
387 d.s[3] +%= v[3];
388 d.s[4] +%= v[4];
389 d.s[5] +%= v[5];
390 d.s[6] +%= v[6];
391 d.s[7] +%= v[7];
375 for (&d.s, v) |*dv, vv| dv.* +%= vv;
392376 }
393377
394378 pub const Error = error{};
......@@ -405,7 +389,33 @@ fn Sha2x32(comptime params: Sha2Params32) type {
405389 };
406390}
407391
408test "sha224 single" {
392const RoundParam256 = struct {
393 a: usize,
394 b: usize,
395 c: usize,
396 d: usize,
397 e: usize,
398 f: usize,
399 g: usize,
400 h: usize,
401 i: usize,
402};
403
404fn roundParam256(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize) RoundParam256 {
405 return RoundParam256{
406 .a = a,
407 .b = b,
408 .c = c,
409 .d = d,
410 .e = e,
411 .f = f,
412 .g = g,
413 .h = h,
414 .i = i,
415 };
416}
417
418test Sha224 {
409419 try htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "");
410420 try htest.assertEqualHash(Sha224, "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc");
411421 try htest.assertEqualHash(Sha224, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
......@@ -431,12 +441,18 @@ test "sha224 streaming" {
431441 try htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
432442}
433443
434test "sha256 single" {
444test Sha256 {
435445 try htest.assertEqualHash(Sha256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "");
436446 try htest.assertEqualHash(Sha256, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc");
437447 try htest.assertEqualHash(Sha256, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
438448}
439449
450test Sha256T192 {
451 try htest.assertEqualHash(Sha256T192, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934c", "");
452 try htest.assertEqualHash(Sha256T192, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9c", "abc");
453 try htest.assertEqualHash(Sha256T192, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
454}
455
440456test "sha256 streaming" {
441457 var h = Sha256.init(.{});
442458 var out: [32]u8 = undefined;
......@@ -466,132 +482,15 @@ test "sha256 aligned final" {
466482 h.final(out[0..]);
467483}
468484
469/////////////////////
470// Sha384 + Sha512
471
472const RoundParam512 = struct {
473 a: usize,
474 b: usize,
475 c: usize,
476 d: usize,
477 e: usize,
478 f: usize,
479 g: usize,
480 h: usize,
481 i: usize,
482 k: u64,
483};
484
485fn roundParam512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) RoundParam512 {
486 return RoundParam512{
487 .a = a,
488 .b = b,
489 .c = c,
490 .d = d,
491 .e = e,
492 .f = f,
493 .g = g,
494 .h = h,
495 .i = i,
496 .k = k,
497 };
498}
499
500const Sha2Params64 = struct {
501 iv0: u64,
502 iv1: u64,
503 iv2: u64,
504 iv3: u64,
505 iv4: u64,
506 iv5: u64,
507 iv6: u64,
508 iv7: u64,
509 digest_bits: usize,
510};
511
512const Sha384Params = Sha2Params64{
513 .iv0 = 0xCBBB9D5DC1059ED8,
514 .iv1 = 0x629A292A367CD507,
515 .iv2 = 0x9159015A3070DD17,
516 .iv3 = 0x152FECD8F70E5939,
517 .iv4 = 0x67332667FFC00B31,
518 .iv5 = 0x8EB44A8768581511,
519 .iv6 = 0xDB0C2E0D64F98FA7,
520 .iv7 = 0x47B5481DBEFA4FA4,
521 .digest_bits = 384,
522};
523
524const Sha512Params = Sha2Params64{
525 .iv0 = 0x6A09E667F3BCC908,
526 .iv1 = 0xBB67AE8584CAA73B,
527 .iv2 = 0x3C6EF372FE94F82B,
528 .iv3 = 0xA54FF53A5F1D36F1,
529 .iv4 = 0x510E527FADE682D1,
530 .iv5 = 0x9B05688C2B3E6C1F,
531 .iv6 = 0x1F83D9ABFB41BD6B,
532 .iv7 = 0x5BE0CD19137E2179,
533 .digest_bits = 512,
534};
535
536const Sha512224Params = Sha2Params64{
537 .iv0 = 0x8C3D37C819544DA2,
538 .iv1 = 0x73E1996689DCD4D6,
539 .iv2 = 0x1DFAB7AE32FF9C82,
540 .iv3 = 0x679DD514582F9FCF,
541 .iv4 = 0x0F6D2B697BD44DA8,
542 .iv5 = 0x77E36F7304C48942,
543 .iv6 = 0x3F9D85A86A1D36C8,
544 .iv7 = 0x1112E6AD91D692A1,
545 .digest_bits = 224,
546};
547
548const Sha512256Params = Sha2Params64{
549 .iv0 = 0x22312194FC2BF72C,
550 .iv1 = 0x9F555FA3C84C64C2,
551 .iv2 = 0x2393B86B6F53B151,
552 .iv3 = 0x963877195940EABD,
553 .iv4 = 0x96283EE2A88EFFE3,
554 .iv5 = 0xBE5E1E2553863992,
555 .iv6 = 0x2B0199FC2C85B8AA,
556 .iv7 = 0x0EB72DDC81C52CA2,
557 .digest_bits = 256,
558};
559
560const Sha512T256Params = Sha2Params64{
561 .iv0 = 0x6A09E667F3BCC908,
562 .iv1 = 0xBB67AE8584CAA73B,
563 .iv2 = 0x3C6EF372FE94F82B,
564 .iv3 = 0xA54FF53A5F1D36F1,
565 .iv4 = 0x510E527FADE682D1,
566 .iv5 = 0x9B05688C2B3E6C1F,
567 .iv6 = 0x1F83D9ABFB41BD6B,
568 .iv7 = 0x5BE0CD19137E2179,
569 .digest_bits = 256,
570};
571
572/// SHA-384
573pub const Sha384 = Sha2x64(Sha384Params);
574
575/// SHA-512
576pub const Sha512 = Sha2x64(Sha512Params);
577
578/// SHA-512/224
579pub const Sha512224 = Sha2x64(Sha512224Params);
580
581/// SHA-512/256
582pub const Sha512256 = Sha2x64(Sha512256Params);
583
584/// Truncated SHA-512
585pub const Sha512T256 = Sha2x64(Sha512T256Params);
586
587fn Sha2x64(comptime params: Sha2Params64) type {
485const Iv64 = [8]u64;
486fn Sha2x64(comptime iv: Iv64, digest_bits: comptime_int) type {
588487 return struct {
589488 const Self = @This();
590489 pub const block_length = 128;
591 pub const digest_length = params.digest_bits / 8;
490 pub const digest_length = std.math.divCeil(comptime_int, digest_bits, 8) catch unreachable;
592491 pub const Options = struct {};
593492
594 s: [8]u64,
493 s: Iv64,
595494 // Streaming Cache
596495 buf: [128]u8 = undefined,
597496 buf_len: u8 = 0,
......@@ -599,18 +498,7 @@ fn Sha2x64(comptime params: Sha2Params64) type {
599498
600499 pub fn init(options: Options) Self {
601500 _ = options;
602 return Self{
603 .s = [_]u64{
604 params.iv0,
605 params.iv1,
606 params.iv2,
607 params.iv3,
608 params.iv4,
609 params.iv5,
610 params.iv6,
611 params.iv7,
612 },
613 };
501 return Self{ .s = iv };
614502 }
615503
616504 pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
......@@ -675,18 +563,19 @@ fn Sha2x64(comptime params: Sha2Params64) type {
675563 d.round(d.buf[0..]);
676564
677565 // May truncate for possible 384 output
678 const rr = d.s[0 .. params.digest_bits / 64];
566 const rr = d.s[0 .. digest_length / 8];
679567
680568 for (rr, 0..) |s, j| {
681569 mem.writeInt(u64, out[8 * j ..][0..8], s, .big);
682570 }
683571
684 const bytes_left = params.digest_bits / 8 % 8;
572 if (digest_bits % 8 != 0) @compileError("impl doesn't support non-byte digest_len");
573 const bytes_left = digest_bits / 8 % 8;
685574 if (bytes_left > 0) {
686 const rest = d.s[(params.digest_bits / 64)];
575 const rest = d.s[(digest_bits / 64)];
687576 var buf: [8]u8 = undefined;
688577 std.mem.writeInt(u64, &buf, rest, .big);
689 @memcpy(out[params.digest_bits / 64 * 8 ..], buf[0..bytes_left]);
578 @memcpy(out[digest_bits / 64 * 8 ..], buf[0..bytes_left]);
690579 }
691580 }
692581
......@@ -709,16 +598,7 @@ fn Sha2x64(comptime params: Sha2Params64) type {
709598 (math.rotr(u64, s[i - 2], @as(u64, 19)) ^ math.rotr(u64, s[i - 2], @as(u64, 61)) ^ (s[i - 2] >> 6));
710599 }
711600
712 var v: [8]u64 = [_]u64{
713 d.s[0],
714 d.s[1],
715 d.s[2],
716 d.s[3],
717 d.s[4],
718 d.s[5],
719 d.s[6],
720 d.s[7],
721 };
601 var v: [8]u64 = d.s;
722602
723603 const round0 = comptime [_]RoundParam512{
724604 roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22),
......@@ -810,19 +690,94 @@ fn Sha2x64(comptime params: Sha2Params64) type {
810690 v[r.h] = v[r.h] +% (math.rotr(u64, v[r.a], @as(u64, 28)) ^ math.rotr(u64, v[r.a], @as(u64, 34)) ^ math.rotr(u64, v[r.a], @as(u64, 39))) +% ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
811691 }
812692
813 d.s[0] +%= v[0];
814 d.s[1] +%= v[1];
815 d.s[2] +%= v[2];
816 d.s[3] +%= v[3];
817 d.s[4] +%= v[4];
818 d.s[5] +%= v[5];
819 d.s[6] +%= v[6];
820 d.s[7] +%= v[7];
693 for (&d.s, v) |*dv, vv| dv.* +%= vv;
821694 }
822695 };
823696}
824697
825test "sha384 single" {
698const RoundParam512 = struct {
699 a: usize,
700 b: usize,
701 c: usize,
702 d: usize,
703 e: usize,
704 f: usize,
705 g: usize,
706 h: usize,
707 i: usize,
708 k: u64,
709};
710
711fn roundParam512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) RoundParam512 {
712 return RoundParam512{
713 .a = a,
714 .b = b,
715 .c = c,
716 .d = d,
717 .e = e,
718 .f = f,
719 .g = g,
720 .h = h,
721 .i = i,
722 .k = k,
723 };
724}
725
726/// Compute the IV for a truncated version of SHA512 per FIPS 180 Section 5.3.6
727fn truncatedSha512Iv(digest_len: comptime_int) Iv64 {
728 const assert = std.debug.assert;
729 comptime assert(digest_len > 1);
730 comptime assert(digest_len <= 512);
731 comptime assert(digest_len != 384); // NIST specially defines this (see `iv384`)
732
733 comptime var gen_params = iv512;
734 inline for (&gen_params) |*iv| {
735 iv.* ^= 0xa5a5a5a5a5a5a5a5;
736 }
737 const GenHash = Sha2x64(gen_params, 512);
738
739 var params: [@sizeOf(Iv64)]u8 = undefined;
740 const algo_str = std.fmt.comptimePrint("SHA-512/{d}", .{digest_len});
741 GenHash.hash(algo_str, &params, .{});
742
743 return Iv64{
744 std.mem.readInt(u64, params[0..8], .big),
745 std.mem.readInt(u64, params[8..16], .big),
746 std.mem.readInt(u64, params[16..24], .big),
747 std.mem.readInt(u64, params[24..32], .big),
748 std.mem.readInt(u64, params[32..40], .big),
749 std.mem.readInt(u64, params[40..48], .big),
750 std.mem.readInt(u64, params[48..56], .big),
751 std.mem.readInt(u64, params[56..64], .big),
752 };
753}
754
755test truncatedSha512Iv {
756 // Section 5.3.6.1
757 try std.testing.expectEqual(Iv64{
758 0x8C3D37C819544DA2,
759 0x73E1996689DCD4D6,
760 0x1DFAB7AE32FF9C82,
761 0x679DD514582F9FCF,
762 0x0F6D2B697BD44DA8,
763 0x77E36F7304C48942,
764 0x3F9D85A86A1D36C8,
765 0x1112E6AD91D692A1,
766 }, truncatedSha512Iv(224));
767 // Section 5.3.6.2
768 try std.testing.expectEqual(Iv64{
769 0x22312194FC2BF72C,
770 0x9F555FA3C84C64C2,
771 0x2393B86B6F53B151,
772 0x963877195940EABD,
773 0x96283EE2A88EFFE3,
774 0xBE5E1E2553863992,
775 0x2B0199FC2C85B8AA,
776 0x0EB72DDC81C52CA2,
777 }, truncatedSha512Iv(256));
778}
779
780test Sha384 {
826781 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
827782 try htest.assertEqualHash(Sha384, h1, "");
828783
......@@ -856,7 +811,7 @@ test "sha384 streaming" {
856811 try htest.assertEqual(h2, out[0..]);
857812}
858813
859test "sha512 single" {
814test Sha512 {
860815 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
861816 try htest.assertEqualHash(Sha512, h1, "");
862817
......@@ -899,24 +854,24 @@ test "sha512 aligned final" {
899854 h.final(out[0..]);
900855}
901856
902test "sha512-224 single" {
857test Sha512_224 {
903858 const h1 = "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4";
904 try htest.assertEqualHash(Sha512224, h1, "");
859 try htest.assertEqualHash(Sha512_224, h1, "");
905860
906861 const h2 = "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa";
907 try htest.assertEqualHash(Sha512224, h2, "abc");
862 try htest.assertEqualHash(Sha512_224, h2, "abc");
908863
909864 const h3 = "23fec5bb94d60b23308192640b0c453335d664734fe40e7268674af9";
910 try htest.assertEqualHash(Sha512224, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
865 try htest.assertEqualHash(Sha512_224, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
911866}
912867
913test "sha512-256 single" {
868test Sha512_256 {
914869 const h1 = "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a";
915 try htest.assertEqualHash(Sha512256, h1, "");
870 try htest.assertEqualHash(Sha512_256, h1, "");
916871
917872 const h2 = "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23";
918 try htest.assertEqualHash(Sha512256, h2, "abc");
873 try htest.assertEqualHash(Sha512_256, h2, "abc");
919874
920875 const h3 = "3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a";
921 try htest.assertEqualHash(Sha512256, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
876 try htest.assertEqualHash(Sha512_256, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
922877}