Commit 8a36a1f913
Changed files (1)
lib
std
crypto
lib/std/crypto/sha2.zig
@@ -1,87 +1,97 @@
+//! Secure Hashing Algorithm 2 (SHA2)
+//!
+//! Published by the National Institue of Standards and Technology (NIST) [1] [2].
+//!
+//! Truncation mitigates length-extension attacks but increases vulnerability to collision
+//! attacks. Collision attacks remain impractical for all types defined here.
+//!
+//! T: original hash function, whose output is simply truncated.
+//! A truncated output is just the first bytes of a longer output.
+//! _: hash function with context separation.
+//! Different lengths produce completely different outputs.
+//!
+//! [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
+//! [2] https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-208.pdf
+
const std = @import("../std.zig");
const builtin = @import("builtin");
const mem = std.mem;
const math = std.math;
const htest = @import("test.zig");
-/////////////////////
-// Sha224 + Sha256
-
-const RoundParam256 = struct {
- a: usize,
- b: usize,
- c: usize,
- d: usize,
- e: usize,
- f: usize,
- g: usize,
- h: usize,
- i: usize,
+pub const Sha224 = Sha2x32(iv224, 224);
+pub const Sha256 = Sha2x32(iv256, 256);
+pub const Sha384 = Sha2x64(iv384, 384);
+pub const Sha512 = Sha2x64(iv512, 512);
+
+/// SHA-256 truncated to leftmost 192 bits.
+pub const Sha256T192 = Sha2x32(iv256, 192);
+
+/// SHA-512 truncated to leftmost 224 bits.
+pub const Sha512T224 = Sha2x64(iv512, 224);
+/// SHA-512 truncated to leftmost 256 bits.
+pub const Sha512T256 = Sha2x64(iv512, 256);
+
+/// SHA-512 with a different initialization vector truncated to leftmost 224 bits.
+pub const Sha512_224 = Sha2x64(truncatedSha512Iv(224), 224);
+/// SHA-512 with a different initialization vector truncated to leftmost 256 bits.
+pub const Sha512_256 = Sha2x64(truncatedSha512Iv(256), 256);
+
+/// Low 32 bits of iv384.
+const iv224 = Iv32{
+ 0xC1059ED8,
+ 0x367CD507,
+ 0x3070DD17,
+ 0xF70E5939,
+ 0xFFC00B31,
+ 0x68581511,
+ 0x64F98FA7,
+ 0xBEFA4FA4,
};
-
-fn roundParam256(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize) RoundParam256 {
- return RoundParam256{
- .a = a,
- .b = b,
- .c = c,
- .d = d,
- .e = e,
- .f = f,
- .g = g,
- .h = h,
- .i = i,
- };
-}
-
-const Sha2Params32 = struct {
- iv0: u32,
- iv1: u32,
- iv2: u32,
- iv3: u32,
- iv4: u32,
- iv5: u32,
- iv6: u32,
- iv7: u32,
- digest_bits: usize,
+/// First thirty-two bits of the fractional parts of the square
+/// roots of the first eight prime numbers.
+const iv256 = Iv32{
+ 0x6A09E667,
+ 0xBB67AE85,
+ 0x3C6EF372,
+ 0xA54FF53A,
+ 0x510E527F,
+ 0x9B05688C,
+ 0x1F83D9AB,
+ 0x5BE0CD19,
};
-const Sha224Params = Sha2Params32{
- .iv0 = 0xC1059ED8,
- .iv1 = 0x367CD507,
- .iv2 = 0x3070DD17,
- .iv3 = 0xF70E5939,
- .iv4 = 0xFFC00B31,
- .iv5 = 0x68581511,
- .iv6 = 0x64F98FA7,
- .iv7 = 0xBEFA4FA4,
- .digest_bits = 224,
+/// First sixty-four bits of the fractional parts of the square
+/// roots of the ninth through sixteenth prime numbers.
+const iv384 = Iv64{
+ 0xCBBB9D5DC1059ED8,
+ 0x629A292A367CD507,
+ 0x9159015A3070DD17,
+ 0x152FECD8F70E5939,
+ 0x67332667FFC00B31,
+ 0x8EB44A8768581511,
+ 0xDB0C2E0D64F98FA7,
+ 0x47B5481DBEFA4FA4,
};
-
-const Sha256Params = Sha2Params32{
- .iv0 = 0x6A09E667,
- .iv1 = 0xBB67AE85,
- .iv2 = 0x3C6EF372,
- .iv3 = 0xA54FF53A,
- .iv4 = 0x510E527F,
- .iv5 = 0x9B05688C,
- .iv6 = 0x1F83D9AB,
- .iv7 = 0x5BE0CD19,
- .digest_bits = 256,
+/// First sixty-four bits of the fractional parts of the square
+/// roots of the first eight prime numbers.
+const iv512 = Iv64{
+ 0x6A09E667F3BCC908,
+ 0xBB67AE8584CAA73B,
+ 0x3C6EF372FE94F82B,
+ 0xA54FF53A5F1D36F1,
+ 0x510E527FADE682D1,
+ 0x9B05688C2B3E6C1F,
+ 0x1F83D9ABFB41BD6B,
+ 0x5BE0CD19137E2179,
};
-const v4u32 = @Vector(4, u32);
-
-/// SHA-224
-pub const Sha224 = Sha2x32(Sha224Params);
-
-/// SHA-256
-pub const Sha256 = Sha2x32(Sha256Params);
-
-fn Sha2x32(comptime params: Sha2Params32) type {
+const Iv32 = [8]u32;
+fn Sha2x32(comptime iv: Iv32, digest_bits: comptime_int) type {
return struct {
const Self = @This();
pub const block_length = 64;
- pub const digest_length = params.digest_bits / 8;
+ pub const digest_length = digest_bits / 8;
pub const Options = struct {};
s: [8]u32 align(16),
@@ -92,18 +102,7 @@ fn Sha2x32(comptime params: Sha2Params32) type {
pub fn init(options: Options) Self {
_ = options;
- return Self{
- .s = [_]u32{
- params.iv0,
- params.iv1,
- params.iv2,
- params.iv3,
- params.iv4,
- params.iv5,
- params.iv6,
- params.iv7,
- },
- };
+ return Self{ .s = iv };
}
pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
@@ -167,8 +166,8 @@ fn Sha2x32(comptime params: Sha2Params32) type {
d.round(&d.buf);
- // May truncate for possible 224 output
- const rr = d.s[0 .. params.digest_bits / 32];
+ // May truncate for possible 224 or 192 output
+ const rr = d.s[0 .. digest_length / 4];
for (rr, 0..) |s, j| {
mem.writeInt(u32, out[4 * j ..][0..4], s, .big);
@@ -199,11 +198,12 @@ fn Sha2x32(comptime params: Sha2Params32) type {
}
if (!@inComptime()) {
+ const V4u32 = @Vector(4, u32);
switch (builtin.cpu.arch) {
.aarch64 => if (builtin.zig_backend != .stage2_c and comptime std.Target.aarch64.featureSetHas(builtin.cpu.features, .sha2)) {
- var x: v4u32 = d.s[0..4].*;
- var y: v4u32 = d.s[4..8].*;
- const s_v = @as(*[16]v4u32, @ptrCast(&s));
+ var x: V4u32 = d.s[0..4].*;
+ var y: V4u32 = d.s[4..8].*;
+ const s_v = @as(*[16]V4u32, @ptrCast(&s));
comptime var k: u8 = 0;
inline while (k < 16) : (k += 1) {
@@ -211,7 +211,7 @@ fn Sha2x32(comptime params: Sha2Params32) type {
s_v[k] = asm (
\\sha256su0.4s %[w0_3], %[w4_7]
\\sha256su1.4s %[w0_3], %[w8_11], %[w12_15]
- : [w0_3] "=w" (-> v4u32),
+ : [w0_3] "=w" (-> V4u32),
: [_] "0" (s_v[k - 4]),
[w4_7] "w" (s_v[k - 3]),
[w8_11] "w" (s_v[k - 2]),
@@ -219,7 +219,7 @@ fn Sha2x32(comptime params: Sha2Params32) type {
);
}
- const w: v4u32 = s_v[k] +% @as(v4u32, W[4 * k ..][0..4].*);
+ const w: V4u32 = s_v[k] +% @as(V4u32, W[4 * k ..][0..4].*);
asm volatile (
\\mov.4s v0, %[x]
\\sha256h.4s %[x], %[y], %[w]
@@ -233,15 +233,15 @@ fn Sha2x32(comptime params: Sha2Params32) type {
);
}
- d.s[0..4].* = x +% @as(v4u32, d.s[0..4].*);
- d.s[4..8].* = y +% @as(v4u32, d.s[4..8].*);
+ d.s[0..4].* = x +% @as(V4u32, d.s[0..4].*);
+ d.s[4..8].* = y +% @as(V4u32, d.s[4..8].*);
return;
},
// C backend doesn't currently support passing vectors to inline asm.
.x86_64 => if (builtin.zig_backend != .stage2_c and comptime std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sha, .avx2 })) {
- var x: v4u32 = [_]u32{ d.s[5], d.s[4], d.s[1], d.s[0] };
- var y: v4u32 = [_]u32{ d.s[7], d.s[6], d.s[3], d.s[2] };
- const s_v = @as(*[16]v4u32, @ptrCast(&s));
+ var x: V4u32 = [_]u32{ d.s[5], d.s[4], d.s[1], d.s[0] };
+ var y: V4u32 = [_]u32{ d.s[7], d.s[6], d.s[3], d.s[2] };
+ const s_v = @as(*[16]V4u32, @ptrCast(&s));
comptime var k: u8 = 0;
inline while (k < 16) : (k += 1) {
@@ -253,7 +253,7 @@ fn Sha2x32(comptime params: Sha2Params32) type {
\\ paddd %[tmp], %[result]
\\ sha256msg2 %[w12_15], %[result]
: [tmp] "=&x" (tmp),
- [result] "=&x" (-> v4u32),
+ [result] "=&x" (-> V4u32),
: [_] "0" (tmp),
[w4_7] "x" (s_v[k + 1]),
[w8_11] "x" (s_v[k + 2]),
@@ -261,19 +261,19 @@ fn Sha2x32(comptime params: Sha2Params32) type {
);
}
- const w: v4u32 = s_v[k] +% @as(v4u32, W[4 * k ..][0..4].*);
+ const w: V4u32 = s_v[k] +% @as(V4u32, W[4 * k ..][0..4].*);
y = asm ("sha256rnds2 %[x], %[y]"
- : [y] "=x" (-> v4u32),
+ : [y] "=x" (-> V4u32),
: [_] "0" (y),
[x] "x" (x),
[_] "{xmm0}" (w),
);
x = asm ("sha256rnds2 %[y], %[x]"
- : [x] "=x" (-> v4u32),
+ : [x] "=x" (-> V4u32),
: [_] "0" (x),
[y] "x" (y),
- [_] "{xmm0}" (@as(v4u32, @bitCast(@as(u128, @bitCast(w)) >> 64))),
+ [_] "{xmm0}" (@as(V4u32, @bitCast(@as(u128, @bitCast(w)) >> 64))),
);
}
@@ -296,16 +296,7 @@ fn Sha2x32(comptime params: Sha2Params32) type {
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));
}
- var v: [8]u32 = [_]u32{
- d.s[0],
- d.s[1],
- d.s[2],
- d.s[3],
- d.s[4],
- d.s[5],
- d.s[6],
- d.s[7],
- };
+ var v: [8]u32 = d.s;
const round0 = comptime [_]RoundParam256{
roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 0),
@@ -381,14 +372,7 @@ fn Sha2x32(comptime params: Sha2Params32) type {
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]));
}
- d.s[0] +%= v[0];
- d.s[1] +%= v[1];
- d.s[2] +%= v[2];
- d.s[3] +%= v[3];
- d.s[4] +%= v[4];
- d.s[5] +%= v[5];
- d.s[6] +%= v[6];
- d.s[7] +%= v[7];
+ for (&d.s, v) |*dv, vv| dv.* +%= vv;
}
pub const Error = error{};
@@ -405,7 +389,33 @@ fn Sha2x32(comptime params: Sha2Params32) type {
};
}
-test "sha224 single" {
+const RoundParam256 = struct {
+ a: usize,
+ b: usize,
+ c: usize,
+ d: usize,
+ e: usize,
+ f: usize,
+ g: usize,
+ h: usize,
+ i: usize,
+};
+
+fn roundParam256(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize) RoundParam256 {
+ return RoundParam256{
+ .a = a,
+ .b = b,
+ .c = c,
+ .d = d,
+ .e = e,
+ .f = f,
+ .g = g,
+ .h = h,
+ .i = i,
+ };
+}
+
+test Sha224 {
try htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "");
try htest.assertEqualHash(Sha224, "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc");
try htest.assertEqualHash(Sha224, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
@@ -431,12 +441,18 @@ test "sha224 streaming" {
try htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
}
-test "sha256 single" {
+test Sha256 {
try htest.assertEqualHash(Sha256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "");
try htest.assertEqualHash(Sha256, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc");
try htest.assertEqualHash(Sha256, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
}
+test Sha256T192 {
+ try htest.assertEqualHash(Sha256T192, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934c", "");
+ try htest.assertEqualHash(Sha256T192, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9c", "abc");
+ try htest.assertEqualHash(Sha256T192, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
+}
+
test "sha256 streaming" {
var h = Sha256.init(.{});
var out: [32]u8 = undefined;
@@ -466,132 +482,15 @@ test "sha256 aligned final" {
h.final(out[0..]);
}
-/////////////////////
-// Sha384 + Sha512
-
-const RoundParam512 = struct {
- a: usize,
- b: usize,
- c: usize,
- d: usize,
- e: usize,
- f: usize,
- g: usize,
- h: usize,
- i: usize,
- k: u64,
-};
-
-fn roundParam512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) RoundParam512 {
- return RoundParam512{
- .a = a,
- .b = b,
- .c = c,
- .d = d,
- .e = e,
- .f = f,
- .g = g,
- .h = h,
- .i = i,
- .k = k,
- };
-}
-
-const Sha2Params64 = struct {
- iv0: u64,
- iv1: u64,
- iv2: u64,
- iv3: u64,
- iv4: u64,
- iv5: u64,
- iv6: u64,
- iv7: u64,
- digest_bits: usize,
-};
-
-const Sha384Params = Sha2Params64{
- .iv0 = 0xCBBB9D5DC1059ED8,
- .iv1 = 0x629A292A367CD507,
- .iv2 = 0x9159015A3070DD17,
- .iv3 = 0x152FECD8F70E5939,
- .iv4 = 0x67332667FFC00B31,
- .iv5 = 0x8EB44A8768581511,
- .iv6 = 0xDB0C2E0D64F98FA7,
- .iv7 = 0x47B5481DBEFA4FA4,
- .digest_bits = 384,
-};
-
-const Sha512Params = Sha2Params64{
- .iv0 = 0x6A09E667F3BCC908,
- .iv1 = 0xBB67AE8584CAA73B,
- .iv2 = 0x3C6EF372FE94F82B,
- .iv3 = 0xA54FF53A5F1D36F1,
- .iv4 = 0x510E527FADE682D1,
- .iv5 = 0x9B05688C2B3E6C1F,
- .iv6 = 0x1F83D9ABFB41BD6B,
- .iv7 = 0x5BE0CD19137E2179,
- .digest_bits = 512,
-};
-
-const Sha512224Params = Sha2Params64{
- .iv0 = 0x8C3D37C819544DA2,
- .iv1 = 0x73E1996689DCD4D6,
- .iv2 = 0x1DFAB7AE32FF9C82,
- .iv3 = 0x679DD514582F9FCF,
- .iv4 = 0x0F6D2B697BD44DA8,
- .iv5 = 0x77E36F7304C48942,
- .iv6 = 0x3F9D85A86A1D36C8,
- .iv7 = 0x1112E6AD91D692A1,
- .digest_bits = 224,
-};
-
-const Sha512256Params = Sha2Params64{
- .iv0 = 0x22312194FC2BF72C,
- .iv1 = 0x9F555FA3C84C64C2,
- .iv2 = 0x2393B86B6F53B151,
- .iv3 = 0x963877195940EABD,
- .iv4 = 0x96283EE2A88EFFE3,
- .iv5 = 0xBE5E1E2553863992,
- .iv6 = 0x2B0199FC2C85B8AA,
- .iv7 = 0x0EB72DDC81C52CA2,
- .digest_bits = 256,
-};
-
-const Sha512T256Params = Sha2Params64{
- .iv0 = 0x6A09E667F3BCC908,
- .iv1 = 0xBB67AE8584CAA73B,
- .iv2 = 0x3C6EF372FE94F82B,
- .iv3 = 0xA54FF53A5F1D36F1,
- .iv4 = 0x510E527FADE682D1,
- .iv5 = 0x9B05688C2B3E6C1F,
- .iv6 = 0x1F83D9ABFB41BD6B,
- .iv7 = 0x5BE0CD19137E2179,
- .digest_bits = 256,
-};
-
-/// SHA-384
-pub const Sha384 = Sha2x64(Sha384Params);
-
-/// SHA-512
-pub const Sha512 = Sha2x64(Sha512Params);
-
-/// SHA-512/224
-pub const Sha512224 = Sha2x64(Sha512224Params);
-
-/// SHA-512/256
-pub const Sha512256 = Sha2x64(Sha512256Params);
-
-/// Truncated SHA-512
-pub const Sha512T256 = Sha2x64(Sha512T256Params);
-
-fn Sha2x64(comptime params: Sha2Params64) type {
+const Iv64 = [8]u64;
+fn Sha2x64(comptime iv: Iv64, digest_bits: comptime_int) type {
return struct {
const Self = @This();
pub const block_length = 128;
- pub const digest_length = params.digest_bits / 8;
+ pub const digest_length = std.math.divCeil(comptime_int, digest_bits, 8) catch unreachable;
pub const Options = struct {};
- s: [8]u64,
+ s: Iv64,
// Streaming Cache
buf: [128]u8 = undefined,
buf_len: u8 = 0,
@@ -599,18 +498,7 @@ fn Sha2x64(comptime params: Sha2Params64) type {
pub fn init(options: Options) Self {
_ = options;
- return Self{
- .s = [_]u64{
- params.iv0,
- params.iv1,
- params.iv2,
- params.iv3,
- params.iv4,
- params.iv5,
- params.iv6,
- params.iv7,
- },
- };
+ return Self{ .s = iv };
}
pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
@@ -675,18 +563,19 @@ fn Sha2x64(comptime params: Sha2Params64) type {
d.round(d.buf[0..]);
// May truncate for possible 384 output
- const rr = d.s[0 .. params.digest_bits / 64];
+ const rr = d.s[0 .. digest_length / 8];
for (rr, 0..) |s, j| {
mem.writeInt(u64, out[8 * j ..][0..8], s, .big);
}
- const bytes_left = params.digest_bits / 8 % 8;
+ if (digest_bits % 8 != 0) @compileError("impl doesn't support non-byte digest_len");
+ const bytes_left = digest_bits / 8 % 8;
if (bytes_left > 0) {
- const rest = d.s[(params.digest_bits / 64)];
+ const rest = d.s[(digest_bits / 64)];
var buf: [8]u8 = undefined;
std.mem.writeInt(u64, &buf, rest, .big);
- @memcpy(out[params.digest_bits / 64 * 8 ..], buf[0..bytes_left]);
+ @memcpy(out[digest_bits / 64 * 8 ..], buf[0..bytes_left]);
}
}
@@ -709,16 +598,7 @@ fn Sha2x64(comptime params: Sha2Params64) type {
(math.rotr(u64, s[i - 2], @as(u64, 19)) ^ math.rotr(u64, s[i - 2], @as(u64, 61)) ^ (s[i - 2] >> 6));
}
- var v: [8]u64 = [_]u64{
- d.s[0],
- d.s[1],
- d.s[2],
- d.s[3],
- d.s[4],
- d.s[5],
- d.s[6],
- d.s[7],
- };
+ var v: [8]u64 = d.s;
const round0 = comptime [_]RoundParam512{
roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22),
@@ -810,19 +690,94 @@ fn Sha2x64(comptime params: Sha2Params64) type {
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]));
}
- d.s[0] +%= v[0];
- d.s[1] +%= v[1];
- d.s[2] +%= v[2];
- d.s[3] +%= v[3];
- d.s[4] +%= v[4];
- d.s[5] +%= v[5];
- d.s[6] +%= v[6];
- d.s[7] +%= v[7];
+ for (&d.s, v) |*dv, vv| dv.* +%= vv;
}
};
}
-test "sha384 single" {
+const RoundParam512 = struct {
+ a: usize,
+ b: usize,
+ c: usize,
+ d: usize,
+ e: usize,
+ f: usize,
+ g: usize,
+ h: usize,
+ i: usize,
+ k: u64,
+};
+
+fn roundParam512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) RoundParam512 {
+ return RoundParam512{
+ .a = a,
+ .b = b,
+ .c = c,
+ .d = d,
+ .e = e,
+ .f = f,
+ .g = g,
+ .h = h,
+ .i = i,
+ .k = k,
+ };
+}
+
+/// Compute the IV for a truncated version of SHA512 per FIPS 180 Section 5.3.6
+fn truncatedSha512Iv(digest_len: comptime_int) Iv64 {
+ const assert = std.debug.assert;
+ comptime assert(digest_len > 1);
+ comptime assert(digest_len <= 512);
+ comptime assert(digest_len != 384); // NIST specially defines this (see `iv384`)
+
+ comptime var gen_params = iv512;
+ inline for (&gen_params) |*iv| {
+ iv.* ^= 0xa5a5a5a5a5a5a5a5;
+ }
+ const GenHash = Sha2x64(gen_params, 512);
+
+ var params: [@sizeOf(Iv64)]u8 = undefined;
+ const algo_str = std.fmt.comptimePrint("SHA-512/{d}", .{digest_len});
+ GenHash.hash(algo_str, ¶ms, .{});
+
+ return Iv64{
+ std.mem.readInt(u64, params[0..8], .big),
+ std.mem.readInt(u64, params[8..16], .big),
+ std.mem.readInt(u64, params[16..24], .big),
+ std.mem.readInt(u64, params[24..32], .big),
+ std.mem.readInt(u64, params[32..40], .big),
+ std.mem.readInt(u64, params[40..48], .big),
+ std.mem.readInt(u64, params[48..56], .big),
+ std.mem.readInt(u64, params[56..64], .big),
+ };
+}
+
+test truncatedSha512Iv {
+ // Section 5.3.6.1
+ try std.testing.expectEqual(Iv64{
+ 0x8C3D37C819544DA2,
+ 0x73E1996689DCD4D6,
+ 0x1DFAB7AE32FF9C82,
+ 0x679DD514582F9FCF,
+ 0x0F6D2B697BD44DA8,
+ 0x77E36F7304C48942,
+ 0x3F9D85A86A1D36C8,
+ 0x1112E6AD91D692A1,
+ }, truncatedSha512Iv(224));
+ // Section 5.3.6.2
+ try std.testing.expectEqual(Iv64{
+ 0x22312194FC2BF72C,
+ 0x9F555FA3C84C64C2,
+ 0x2393B86B6F53B151,
+ 0x963877195940EABD,
+ 0x96283EE2A88EFFE3,
+ 0xBE5E1E2553863992,
+ 0x2B0199FC2C85B8AA,
+ 0x0EB72DDC81C52CA2,
+ }, truncatedSha512Iv(256));
+}
+
+test Sha384 {
const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
try htest.assertEqualHash(Sha384, h1, "");
@@ -856,7 +811,7 @@ test "sha384 streaming" {
try htest.assertEqual(h2, out[0..]);
}
-test "sha512 single" {
+test Sha512 {
const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
try htest.assertEqualHash(Sha512, h1, "");
@@ -899,24 +854,24 @@ test "sha512 aligned final" {
h.final(out[0..]);
}
-test "sha512-224 single" {
+test Sha512_224 {
const h1 = "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4";
- try htest.assertEqualHash(Sha512224, h1, "");
+ try htest.assertEqualHash(Sha512_224, h1, "");
const h2 = "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa";
- try htest.assertEqualHash(Sha512224, h2, "abc");
+ try htest.assertEqualHash(Sha512_224, h2, "abc");
const h3 = "23fec5bb94d60b23308192640b0c453335d664734fe40e7268674af9";
- try htest.assertEqualHash(Sha512224, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
+ try htest.assertEqualHash(Sha512_224, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
}
-test "sha512-256 single" {
+test Sha512_256 {
const h1 = "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a";
- try htest.assertEqualHash(Sha512256, h1, "");
+ try htest.assertEqualHash(Sha512_256, h1, "");
const h2 = "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23";
- try htest.assertEqualHash(Sha512256, h2, "abc");
+ try htest.assertEqualHash(Sha512_256, h2, "abc");
const h3 = "3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a";
- try htest.assertEqualHash(Sha512256, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
+ try htest.assertEqualHash(Sha512_256, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
}