mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
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
This commit is contained in:
parent
25f1526fe6
commit
8a36a1f913
@ -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
|
||||
pub const Sha224 = Sha2x32(iv224, 224);
|
||||
pub const Sha256 = Sha2x32(iv256, 256);
|
||||
pub const Sha384 = Sha2x64(iv384, 384);
|
||||
pub const Sha512 = Sha2x64(iv512, 512);
|
||||
|
||||
const RoundParam256 = struct {
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
d: usize,
|
||||
e: usize,
|
||||
f: usize,
|
||||
g: usize,
|
||||
h: usize,
|
||||
i: usize,
|
||||
/// 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,
|
||||
};
|
||||
/// 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,
|
||||
};
|
||||
|
||||
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 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,
|
||||
};
|
||||
/// 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 Sha224Params = Sha2Params32{
|
||||
.iv0 = 0xC1059ED8,
|
||||
.iv1 = 0x367CD507,
|
||||
.iv2 = 0x3070DD17,
|
||||
.iv3 = 0xF70E5939,
|
||||
.iv4 = 0xFFC00B31,
|
||||
.iv5 = 0x68581511,
|
||||
.iv6 = 0x64F98FA7,
|
||||
.iv7 = 0xBEFA4FA4,
|
||||
.digest_bits = 224,
|
||||
};
|
||||
|
||||
const Sha256Params = Sha2Params32{
|
||||
.iv0 = 0x6A09E667,
|
||||
.iv1 = 0xBB67AE85,
|
||||
.iv2 = 0x3C6EF372,
|
||||
.iv3 = 0xA54FF53A,
|
||||
.iv4 = 0x510E527F,
|
||||
.iv5 = 0x9B05688C,
|
||||
.iv6 = 0x1F83D9AB,
|
||||
.iv7 = 0x5BE0CD19,
|
||||
.digest_bits = 256,
|
||||
};
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user