| 1 | //! Secure Hashing Algorithm 2 (SHA2) |
| 2 | //! |
| 3 | //! Published by the National Institute 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 | |
| 16 | const std = @import("../std.zig"); |
| 17 | const builtin = @import("builtin"); |
| 18 | const mem = std.mem; |
| 19 | const math = std.math; |
| 20 | const htest = @import("test.zig"); |
| 21 | |
| 22 | pub const Sha224 = Sha2x32(iv224, 224); |
| 23 | pub const Sha256 = Sha2x32(iv256, 256); |
| 24 | pub const Sha384 = Sha2x64(iv384, 384); |
| 25 | pub const Sha512 = Sha2x64(iv512, 512); |
| 26 | |
| 27 | /// SHA-256 truncated to leftmost 192 bits. |
| 28 | pub const Sha256T192 = Sha2x32(iv256, 192); |
| 29 | |
| 30 | /// SHA-512 truncated to leftmost 224 bits. |
| 31 | pub const Sha512T224 = Sha2x64(iv512, 224); |
| 32 | /// SHA-512 truncated to leftmost 256 bits. |
| 33 | pub const Sha512T256 = Sha2x64(iv512, 256); |
| 34 | |
| 35 | /// SHA-512 with a different initialization vector truncated to leftmost 224 bits. |
| 36 | pub const Sha512_224 = Sha2x64(truncatedSha512Iv(224), 224); |
| 37 | /// SHA-512 with a different initialization vector truncated to leftmost 256 bits. |
| 38 | pub const Sha512_256 = Sha2x64(truncatedSha512Iv(256), 256); |
| 39 | |
| 40 | /// Low 32 bits of iv384. |
| 41 | const iv224 = Iv32{ |
| 42 | 0xC1059ED8, |
| 43 | 0x367CD507, |
| 44 | 0x3070DD17, |
| 45 | 0xF70E5939, |
| 46 | 0xFFC00B31, |
| 47 | 0x68581511, |
| 48 | 0x64F98FA7, |
| 49 | 0xBEFA4FA4, |
| 50 | }; |
| 51 | /// First thirty-two bits of the fractional parts of the square |
| 52 | /// roots of the first eight prime numbers. |
| 53 | const iv256 = Iv32{ |
| 54 | 0x6A09E667, |
| 55 | 0xBB67AE85, |
| 56 | 0x3C6EF372, |
| 57 | 0xA54FF53A, |
| 58 | 0x510E527F, |
| 59 | 0x9B05688C, |
| 60 | 0x1F83D9AB, |
| 61 | 0x5BE0CD19, |
| 62 | }; |
| 63 | |
| 64 | /// First sixty-four bits of the fractional parts of the square |
| 65 | /// roots of the ninth through sixteenth prime numbers. |
| 66 | const iv384 = Iv64{ |
| 67 | 0xCBBB9D5DC1059ED8, |
| 68 | 0x629A292A367CD507, |
| 69 | 0x9159015A3070DD17, |
| 70 | 0x152FECD8F70E5939, |
| 71 | 0x67332667FFC00B31, |
| 72 | 0x8EB44A8768581511, |
| 73 | 0xDB0C2E0D64F98FA7, |
| 74 | 0x47B5481DBEFA4FA4, |
| 75 | }; |
| 76 | /// First sixty-four bits of the fractional parts of the square |
| 77 | /// roots of the first eight prime numbers. |
| 78 | const iv512 = Iv64{ |
| 79 | 0x6A09E667F3BCC908, |
| 80 | 0xBB67AE8584CAA73B, |
| 81 | 0x3C6EF372FE94F82B, |
| 82 | 0xA54FF53A5F1D36F1, |
| 83 | 0x510E527FADE682D1, |
| 84 | 0x9B05688C2B3E6C1F, |
| 85 | 0x1F83D9ABFB41BD6B, |
| 86 | 0x5BE0CD19137E2179, |
| 87 | }; |
| 88 | |
| 89 | const Iv32 = [8]u32; |
| 90 | fn Sha2x32(comptime iv: Iv32, digest_bits: comptime_int) type { |
| 91 | return struct { |
| 92 | const Self = @This(); |
| 93 | pub const block_length = 64; |
| 94 | pub const digest_length = digest_bits / 8; |
| 95 | pub const Options = struct {}; |
| 96 | |
| 97 | s: [8]u32 align(16), |
| 98 | // Streaming Cache |
| 99 | buf: [64]u8 = undefined, |
| 100 | buf_len: u8 = 0, |
| 101 | total_len: u64 = 0, |
| 102 | |
| 103 | pub fn init(options: Options) Self { |
| 104 | _ = options; |
| 105 | return Self{ .s = iv }; |
| 106 | } |
| 107 | |
| 108 | pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void { |
| 109 | var d = Self.init(options); |
| 110 | d.update(b); |
| 111 | d.final(out); |
| 112 | } |
| 113 | |
| 114 | pub fn update(d: *Self, b: []const u8) void { |
| 115 | var off: usize = 0; |
| 116 | |
| 117 | // Partial buffer exists from previous update. Copy into buffer then hash. |
| 118 | if (d.buf_len != 0 and d.buf_len + b.len >= 64) { |
| 119 | off += 64 - d.buf_len; |
| 120 | @memcpy(d.buf[d.buf_len..][0..off], b[0..off]); |
| 121 | |
| 122 | d.round(&d.buf); |
| 123 | d.buf_len = 0; |
| 124 | } |
| 125 | |
| 126 | // Full middle blocks. |
| 127 | while (off + 64 <= b.len) : (off += 64) { |
| 128 | d.round(b[off..][0..64]); |
| 129 | } |
| 130 | |
| 131 | // Copy any remainder for next pass. |
| 132 | const b_slice = b[off..]; |
| 133 | @memcpy(d.buf[d.buf_len..][0..b_slice.len], b_slice); |
| 134 | d.buf_len += @as(u8, @intCast(b[off..].len)); |
| 135 | |
| 136 | d.total_len += b.len; |
| 137 | } |
| 138 | |
| 139 | pub fn peek(d: Self) [digest_length]u8 { |
| 140 | var copy = d; |
| 141 | return copy.finalResult(); |
| 142 | } |
| 143 | |
| 144 | pub fn final(d: *Self, out: *[digest_length]u8) void { |
| 145 | // The buffer here will never be completely full. |
| 146 | @memset(d.buf[d.buf_len..], 0); |
| 147 | |
| 148 | // Append padding bits. |
| 149 | d.buf[d.buf_len] = 0x80; |
| 150 | d.buf_len += 1; |
| 151 | |
| 152 | // > 448 mod 512 so need to add an extra round to wrap around. |
| 153 | if (64 - d.buf_len < 8) { |
| 154 | d.round(&d.buf); |
| 155 | @memset(d.buf[0..], 0); |
| 156 | } |
| 157 | |
| 158 | // Append message length. |
| 159 | var i: usize = 1; |
| 160 | var len = d.total_len >> 5; |
| 161 | d.buf[63] = @as(u8, @intCast(d.total_len & 0x1f)) << 3; |
| 162 | while (i < 8) : (i += 1) { |
| 163 | d.buf[63 - i] = @as(u8, @intCast(len & 0xff)); |
| 164 | len >>= 8; |
| 165 | } |
| 166 | |
| 167 | d.round(&d.buf); |
| 168 | |
| 169 | // May truncate for possible 224 or 192 output |
| 170 | const rr = d.s[0 .. digest_length / 4]; |
| 171 | |
| 172 | for (rr, 0..) |s, j| { |
| 173 | mem.writeInt(u32, out[4 * j ..][0..4], s, .big); |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | pub fn finalResult(d: *Self) [digest_length]u8 { |
| 178 | var result: [digest_length]u8 = undefined; |
| 179 | d.final(&result); |
| 180 | return result; |
| 181 | } |
| 182 | |
| 183 | const W = [64]u32{ |
| 184 | 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, |
| 185 | 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, |
| 186 | 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, |
| 187 | 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, |
| 188 | 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, |
| 189 | 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, |
| 190 | 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, |
| 191 | 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, |
| 192 | }; |
| 193 | |
| 194 | fn round(d: *Self, b: *const [64]u8) void { |
| 195 | var s: [64]u32 align(16) = undefined; |
| 196 | for (@as(*align(1) const [16]u32, @ptrCast(b)), 0..) |*elem, i| { |
| 197 | s[i] = mem.readInt(u32, mem.asBytes(elem), .big); |
| 198 | } |
| 199 | |
| 200 | if (!@inComptime()) { |
| 201 | const V4u32 = @Vector(4, u32); |
| 202 | switch (builtin.cpu.arch) { |
| 203 | .aarch64 => if (builtin.zig_backend != .stage2_c and comptime builtin.cpu.has(.aarch64, .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)); |
| 207 | |
| 208 | comptime var k: u8 = 0; |
| 209 | inline while (k < 16) : (k += 1) { |
| 210 | if (k > 3) { |
| 211 | s_v[k] = asm ( |
| 212 | \\sha256su0.4s %[w0_3], %[w4_7] |
| 213 | \\sha256su1.4s %[w0_3], %[w8_11], %[w12_15] |
| 214 | : [w0_3] "=&w" (-> V4u32), |
| 215 | : [_] "0" (s_v[k - 4]), |
| 216 | [w4_7] "w" (s_v[k - 3]), |
| 217 | [w8_11] "w" (s_v[k - 2]), |
| 218 | [w12_15] "w" (s_v[k - 1]), |
| 219 | ); |
| 220 | } |
| 221 | |
| 222 | const w: V4u32 = s_v[k] +% @as(V4u32, W[4 * k ..][0..4].*); |
| 223 | asm volatile ( |
| 224 | \\mov.4s v0, %[x] |
| 225 | \\sha256h.4s %[x], %[y], %[w] |
| 226 | \\sha256h2.4s %[y], v0, %[w] |
| 227 | : [x] "=w" (x), |
| 228 | [y] "=w" (y), |
| 229 | : [_] "0" (x), |
| 230 | [_] "1" (y), |
| 231 | [w] "w" (w), |
| 232 | : .{ .v0 = true }); |
| 233 | } |
| 234 | |
| 235 | d.s[0..4].* = x +% @as(V4u32, d.s[0..4].*); |
| 236 | d.s[4..8].* = y +% @as(V4u32, d.s[4..8].*); |
| 237 | return; |
| 238 | }, |
| 239 | // C backend doesn't currently support passing vectors to inline asm. |
| 240 | .x86_64 => if (builtin.zig_backend != .stage2_c and comptime builtin.cpu.hasAll(.x86, &.{ .sha, .avx2 })) { |
| 241 | var x: V4u32 = [_]u32{ d.s[5], d.s[4], d.s[1], d.s[0] }; |
| 242 | var y: V4u32 = [_]u32{ d.s[7], d.s[6], d.s[3], d.s[2] }; |
| 243 | const s_v = @as(*[16]V4u32, @ptrCast(&s)); |
| 244 | |
| 245 | comptime var k: u8 = 0; |
| 246 | inline while (k < 16) : (k += 1) { |
| 247 | if (k < 12) { |
| 248 | var tmp = s_v[k]; |
| 249 | s_v[k + 4] = asm ( |
| 250 | \\ sha256msg1 %[w4_7], %[tmp] |
| 251 | \\ vpalignr $0x4, %[w8_11], %[w12_15], %[result] |
| 252 | \\ paddd %[tmp], %[result] |
| 253 | \\ sha256msg2 %[w12_15], %[result] |
| 254 | : [tmp] "=&x" (tmp), |
| 255 | [result] "=&x" (-> V4u32), |
| 256 | : [_] "0" (tmp), |
| 257 | [w4_7] "x" (s_v[k + 1]), |
| 258 | [w8_11] "x" (s_v[k + 2]), |
| 259 | [w12_15] "x" (s_v[k + 3]), |
| 260 | ); |
| 261 | } |
| 262 | |
| 263 | const w: V4u32 = s_v[k] +% @as(V4u32, W[4 * k ..][0..4].*); |
| 264 | y = asm ("sha256rnds2 %[x], %[y]" |
| 265 | : [y] "=x" (-> V4u32), |
| 266 | : [_] "0" (y), |
| 267 | [x] "x" (x), |
| 268 | [_] "{xmm0}" (w), |
| 269 | ); |
| 270 | |
| 271 | x = asm ("sha256rnds2 %[y], %[x]" |
| 272 | : [x] "=x" (-> V4u32), |
| 273 | : [_] "0" (x), |
| 274 | [y] "x" (y), |
| 275 | [_] "{xmm0}" (@as(V4u32, @bitCast(@as(u128, @bitCast(w)) >> 64))), |
| 276 | ); |
| 277 | } |
| 278 | |
| 279 | d.s[0] +%= x[3]; |
| 280 | d.s[1] +%= x[2]; |
| 281 | d.s[4] +%= x[1]; |
| 282 | d.s[5] +%= x[0]; |
| 283 | d.s[2] +%= y[3]; |
| 284 | d.s[3] +%= y[2]; |
| 285 | d.s[6] +%= y[1]; |
| 286 | d.s[7] +%= y[0]; |
| 287 | return; |
| 288 | }, |
| 289 | else => {}, |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | var i: usize = 16; |
| 294 | while (i < 64) : (i += 1) { |
| 295 | 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)); |
| 296 | } |
| 297 | |
| 298 | var v: [8]u32 = d.s; |
| 299 | |
| 300 | const round0 = comptime [_]RoundParam256{ |
| 301 | roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 0), |
| 302 | roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 1), |
| 303 | roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 2), |
| 304 | roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 3), |
| 305 | roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 4), |
| 306 | roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 5), |
| 307 | roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 6), |
| 308 | roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 7), |
| 309 | roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 8), |
| 310 | roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 9), |
| 311 | roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 10), |
| 312 | roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 11), |
| 313 | roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 12), |
| 314 | roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 13), |
| 315 | roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 14), |
| 316 | roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 15), |
| 317 | roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 16), |
| 318 | roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 17), |
| 319 | roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 18), |
| 320 | roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 19), |
| 321 | roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 20), |
| 322 | roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 21), |
| 323 | roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 22), |
| 324 | roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 23), |
| 325 | roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 24), |
| 326 | roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 25), |
| 327 | roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 26), |
| 328 | roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 27), |
| 329 | roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 28), |
| 330 | roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 29), |
| 331 | roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 30), |
| 332 | roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 31), |
| 333 | roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 32), |
| 334 | roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 33), |
| 335 | roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 34), |
| 336 | roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 35), |
| 337 | roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 36), |
| 338 | roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 37), |
| 339 | roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 38), |
| 340 | roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 39), |
| 341 | roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 40), |
| 342 | roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 41), |
| 343 | roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 42), |
| 344 | roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 43), |
| 345 | roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 44), |
| 346 | roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 45), |
| 347 | roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 46), |
| 348 | roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 47), |
| 349 | roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 48), |
| 350 | roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 49), |
| 351 | roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 50), |
| 352 | roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 51), |
| 353 | roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 52), |
| 354 | roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 53), |
| 355 | roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 54), |
| 356 | roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 55), |
| 357 | roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 56), |
| 358 | roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 57), |
| 359 | roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 58), |
| 360 | roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 59), |
| 361 | roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 60), |
| 362 | roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 61), |
| 363 | roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 62), |
| 364 | roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 63), |
| 365 | }; |
| 366 | inline for (round0) |r| { |
| 367 | v[r.h] = v[r.h] +% (math.rotr(u32, v[r.e], @as(u32, 6)) ^ math.rotr(u32, v[r.e], @as(u32, 11)) ^ math.rotr(u32, v[r.e], @as(u32, 25))) +% (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +% W[r.i] +% s[r.i]; |
| 368 | |
| 369 | v[r.d] = v[r.d] +% v[r.h]; |
| 370 | |
| 371 | 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])); |
| 372 | } |
| 373 | |
| 374 | for (&d.s, v) |*dv, vv| dv.* +%= vv; |
| 375 | } |
| 376 | }; |
| 377 | } |
| 378 | |
| 379 | const RoundParam256 = struct { |
| 380 | a: usize, |
| 381 | b: usize, |
| 382 | c: usize, |
| 383 | d: usize, |
| 384 | e: usize, |
| 385 | f: usize, |
| 386 | g: usize, |
| 387 | h: usize, |
| 388 | i: usize, |
| 389 | }; |
| 390 | |
| 391 | fn roundParam256(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize) RoundParam256 { |
| 392 | return RoundParam256{ |
| 393 | .a = a, |
| 394 | .b = b, |
| 395 | .c = c, |
| 396 | .d = d, |
| 397 | .e = e, |
| 398 | .f = f, |
| 399 | .g = g, |
| 400 | .h = h, |
| 401 | .i = i, |
| 402 | }; |
| 403 | } |
| 404 | |
| 405 | test Sha224 { |
| 406 | try htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""); |
| 407 | try htest.assertEqualHash(Sha224, "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"); |
| 408 | try htest.assertEqualHash(Sha224, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); |
| 409 | } |
| 410 | |
| 411 | test "sha224 streaming" { |
| 412 | var h = Sha224.init(.{}); |
| 413 | var out: [28]u8 = undefined; |
| 414 | |
| 415 | h.final(out[0..]); |
| 416 | try htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]); |
| 417 | |
| 418 | h = Sha224.init(.{}); |
| 419 | h.update("abc"); |
| 420 | h.final(out[0..]); |
| 421 | try htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]); |
| 422 | |
| 423 | h = Sha224.init(.{}); |
| 424 | h.update("a"); |
| 425 | h.update("b"); |
| 426 | h.update("c"); |
| 427 | h.final(out[0..]); |
| 428 | try htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]); |
| 429 | } |
| 430 | |
| 431 | test Sha256 { |
| 432 | try htest.assertEqualHash(Sha256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""); |
| 433 | try htest.assertEqualHash(Sha256, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"); |
| 434 | try htest.assertEqualHash(Sha256, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); |
| 435 | } |
| 436 | |
| 437 | test Sha256T192 { |
| 438 | try htest.assertEqualHash(Sha256T192, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934c", ""); |
| 439 | try htest.assertEqualHash(Sha256T192, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9c", "abc"); |
| 440 | try htest.assertEqualHash(Sha256T192, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); |
| 441 | } |
| 442 | |
| 443 | test "sha256 streaming" { |
| 444 | var h = Sha256.init(.{}); |
| 445 | var out: [32]u8 = undefined; |
| 446 | |
| 447 | h.final(out[0..]); |
| 448 | try htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]); |
| 449 | |
| 450 | h = Sha256.init(.{}); |
| 451 | h.update("abc"); |
| 452 | h.final(out[0..]); |
| 453 | try htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]); |
| 454 | |
| 455 | h = Sha256.init(.{}); |
| 456 | h.update("a"); |
| 457 | h.update("b"); |
| 458 | h.update("c"); |
| 459 | h.final(out[0..]); |
| 460 | try htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]); |
| 461 | } |
| 462 | |
| 463 | test "sha256 aligned final" { |
| 464 | var block: [Sha256.block_length]u8 = @splat(0); |
| 465 | var out: [Sha256.digest_length]u8 = undefined; |
| 466 | |
| 467 | var h = Sha256.init(.{}); |
| 468 | h.update(&block); |
| 469 | h.final(out[0..]); |
| 470 | } |
| 471 | |
| 472 | const Iv64 = [8]u64; |
| 473 | fn Sha2x64(comptime iv: Iv64, digest_bits: comptime_int) type { |
| 474 | return struct { |
| 475 | const Self = @This(); |
| 476 | pub const block_length = 128; |
| 477 | pub const digest_length = @divCeil(digest_bits, 8); |
| 478 | pub const Options = struct {}; |
| 479 | |
| 480 | s: Iv64, |
| 481 | // Streaming Cache |
| 482 | buf: [128]u8 = undefined, |
| 483 | buf_len: u8 = 0, |
| 484 | total_len: u128 = 0, |
| 485 | |
| 486 | pub fn init(options: Options) Self { |
| 487 | _ = options; |
| 488 | return Self{ .s = iv }; |
| 489 | } |
| 490 | |
| 491 | pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void { |
| 492 | var d = Self.init(options); |
| 493 | d.update(b); |
| 494 | d.final(out); |
| 495 | } |
| 496 | |
| 497 | pub fn update(d: *Self, b: []const u8) void { |
| 498 | var off: usize = 0; |
| 499 | |
| 500 | // Partial buffer exists from previous update. Copy into buffer then hash. |
| 501 | if (d.buf_len != 0 and d.buf_len + b.len >= 128) { |
| 502 | off += 128 - d.buf_len; |
| 503 | @memcpy(d.buf[d.buf_len..][0..off], b[0..off]); |
| 504 | |
| 505 | d.round(&d.buf); |
| 506 | d.buf_len = 0; |
| 507 | } |
| 508 | |
| 509 | // Full middle blocks. |
| 510 | while (off + 128 <= b.len) : (off += 128) { |
| 511 | d.round(b[off..][0..128]); |
| 512 | } |
| 513 | |
| 514 | // Copy any remainder for next pass. |
| 515 | const b_slice = b[off..]; |
| 516 | @memcpy(d.buf[d.buf_len..][0..b_slice.len], b_slice); |
| 517 | d.buf_len += @as(u8, @intCast(b[off..].len)); |
| 518 | |
| 519 | d.total_len += b.len; |
| 520 | } |
| 521 | |
| 522 | pub fn peek(d: Self) [digest_length]u8 { |
| 523 | var copy = d; |
| 524 | return copy.finalResult(); |
| 525 | } |
| 526 | |
| 527 | pub fn final(d: *Self, out: *[digest_length]u8) void { |
| 528 | // The buffer here will never be completely full. |
| 529 | @memset(d.buf[d.buf_len..], 0); |
| 530 | |
| 531 | // Append padding bits. |
| 532 | d.buf[d.buf_len] = 0x80; |
| 533 | d.buf_len += 1; |
| 534 | |
| 535 | // > 896 mod 1024 so need to add an extra round to wrap around. |
| 536 | if (128 - d.buf_len < 16) { |
| 537 | d.round(d.buf[0..]); |
| 538 | @memset(d.buf[0..], 0); |
| 539 | } |
| 540 | |
| 541 | // Append message length. |
| 542 | var i: usize = 1; |
| 543 | var len = d.total_len >> 5; |
| 544 | d.buf[127] = @as(u8, @intCast(d.total_len & 0x1f)) << 3; |
| 545 | while (i < 16) : (i += 1) { |
| 546 | d.buf[127 - i] = @as(u8, @intCast(len & 0xff)); |
| 547 | len >>= 8; |
| 548 | } |
| 549 | |
| 550 | d.round(d.buf[0..]); |
| 551 | |
| 552 | // May truncate for possible 384 output |
| 553 | const rr = d.s[0 .. digest_length / 8]; |
| 554 | |
| 555 | for (rr, 0..) |s, j| { |
| 556 | mem.writeInt(u64, out[8 * j ..][0..8], s, .big); |
| 557 | } |
| 558 | |
| 559 | if (digest_bits % 8 != 0) @compileError("impl doesn't support non-byte digest_len"); |
| 560 | const bytes_left = digest_bits / 8 % 8; |
| 561 | if (bytes_left > 0) { |
| 562 | const rest = d.s[(digest_bits / 64)]; |
| 563 | var buf: [8]u8 = undefined; |
| 564 | std.mem.writeInt(u64, &buf, rest, .big); |
| 565 | @memcpy(out[digest_bits / 64 * 8 ..], buf[0..bytes_left]); |
| 566 | } |
| 567 | } |
| 568 | |
| 569 | pub fn finalResult(d: *Self) [digest_length]u8 { |
| 570 | var result: [digest_length]u8 = undefined; |
| 571 | d.final(&result); |
| 572 | return result; |
| 573 | } |
| 574 | |
| 575 | fn round(d: *Self, b: *const [128]u8) void { |
| 576 | var s: [80]u64 = undefined; |
| 577 | |
| 578 | var i: usize = 0; |
| 579 | while (i < 16) : (i += 1) { |
| 580 | s[i] = mem.readInt(u64, b[i * 8 ..][0..8], .big); |
| 581 | } |
| 582 | while (i < 80) : (i += 1) { |
| 583 | s[i] = s[i - 16] +% s[i - 7] +% |
| 584 | (math.rotr(u64, s[i - 15], @as(u64, 1)) ^ math.rotr(u64, s[i - 15], @as(u64, 8)) ^ (s[i - 15] >> 7)) +% |
| 585 | (math.rotr(u64, s[i - 2], @as(u64, 19)) ^ math.rotr(u64, s[i - 2], @as(u64, 61)) ^ (s[i - 2] >> 6)); |
| 586 | } |
| 587 | |
| 588 | var v: [8]u64 = d.s; |
| 589 | |
| 590 | const round0 = comptime [_]RoundParam512{ |
| 591 | roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22), |
| 592 | roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x7137449123EF65CD), |
| 593 | roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCFEC4D3B2F), |
| 594 | roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA58189DBBC), |
| 595 | roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25BF348B538), |
| 596 | roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1B605D019), |
| 597 | roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4AF194F9B), |
| 598 | roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5DA6D8118), |
| 599 | roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98A3030242), |
| 600 | roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B0145706FBE), |
| 601 | roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE4EE4B28C), |
| 602 | roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3D5FFB4E2), |
| 603 | roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74F27B896F), |
| 604 | roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE3B1696B1), |
| 605 | roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A725C71235), |
| 606 | roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174CF692694), |
| 607 | roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C19EF14AD2), |
| 608 | roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786384F25E3), |
| 609 | roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC68B8CD5B5), |
| 610 | roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC77AC9C65), |
| 611 | roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F592B0275), |
| 612 | roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA6EA6E483), |
| 613 | roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DCBD41FBD4), |
| 614 | roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA831153B5), |
| 615 | roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152EE66DFAB), |
| 616 | roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D2DB43210), |
| 617 | roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C898FB213F), |
| 618 | roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7BEEF0EE4), |
| 619 | roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF33DA88FC2), |
| 620 | roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147930AA725), |
| 621 | roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351E003826F), |
| 622 | roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x142929670A0E6E70), |
| 623 | roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A8546D22FFC), |
| 624 | roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B21385C26C926), |
| 625 | roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC5AC42AED), |
| 626 | roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D139D95B3DF), |
| 627 | roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A73548BAF63DE), |
| 628 | roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB3C77B2A8), |
| 629 | roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E47EDAEE6), |
| 630 | roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C851482353B), |
| 631 | roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A14CF10364), |
| 632 | roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664BBC423001), |
| 633 | roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70D0F89791), |
| 634 | roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A30654BE30), |
| 635 | roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819D6EF5218), |
| 636 | roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD69906245565A910), |
| 637 | roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E35855771202A), |
| 638 | roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA07032BBD1B8), |
| 639 | roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116B8D2D0C8), |
| 640 | roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C085141AB53), |
| 641 | roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774CDF8EEB99), |
| 642 | roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5E19B48A8), |
| 643 | roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3C5C95A63), |
| 644 | roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4AE3418ACB), |
| 645 | roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F7763E373), |
| 646 | roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3D6B2B8A3), |
| 647 | roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE5DEFB2FC), |
| 648 | roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F43172F60), |
| 649 | roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814A1F0AB72), |
| 650 | roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC702081A6439EC), |
| 651 | roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA23631E28), |
| 652 | roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEBDE82BDE9), |
| 653 | roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7B2C67915), |
| 654 | roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2E372532B), |
| 655 | roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 64, 0xCA273ECEEA26619C), |
| 656 | roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 65, 0xD186B8C721C0C207), |
| 657 | roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 66, 0xEADA7DD6CDE0EB1E), |
| 658 | roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 67, 0xF57D4F7FEE6ED178), |
| 659 | roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 68, 0x06F067AA72176FBA), |
| 660 | roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 69, 0x0A637DC5A2C898A6), |
| 661 | roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 70, 0x113F9804BEF90DAE), |
| 662 | roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 71, 0x1B710B35131C471B), |
| 663 | roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 72, 0x28DB77F523047D84), |
| 664 | roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 73, 0x32CAAB7B40C72493), |
| 665 | roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 74, 0x3C9EBE0A15C9BEBC), |
| 666 | roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 75, 0x431D67C49C100D4C), |
| 667 | roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 76, 0x4CC5D4BECB3E42B6), |
| 668 | roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 77, 0x597F299CFC657E2A), |
| 669 | roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 78, 0x5FCB6FAB3AD6FAEC), |
| 670 | roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 79, 0x6C44198C4A475817), |
| 671 | }; |
| 672 | inline for (round0) |r| { |
| 673 | v[r.h] = v[r.h] +% (math.rotr(u64, v[r.e], @as(u64, 14)) ^ math.rotr(u64, v[r.e], @as(u64, 18)) ^ math.rotr(u64, v[r.e], @as(u64, 41))) +% (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +% r.k +% s[r.i]; |
| 674 | |
| 675 | v[r.d] = v[r.d] +% v[r.h]; |
| 676 | |
| 677 | 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])); |
| 678 | } |
| 679 | |
| 680 | for (&d.s, v) |*dv, vv| dv.* +%= vv; |
| 681 | } |
| 682 | }; |
| 683 | } |
| 684 | |
| 685 | const RoundParam512 = struct { |
| 686 | a: usize, |
| 687 | b: usize, |
| 688 | c: usize, |
| 689 | d: usize, |
| 690 | e: usize, |
| 691 | f: usize, |
| 692 | g: usize, |
| 693 | h: usize, |
| 694 | i: usize, |
| 695 | k: u64, |
| 696 | }; |
| 697 | |
| 698 | fn roundParam512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) RoundParam512 { |
| 699 | return RoundParam512{ |
| 700 | .a = a, |
| 701 | .b = b, |
| 702 | .c = c, |
| 703 | .d = d, |
| 704 | .e = e, |
| 705 | .f = f, |
| 706 | .g = g, |
| 707 | .h = h, |
| 708 | .i = i, |
| 709 | .k = k, |
| 710 | }; |
| 711 | } |
| 712 | |
| 713 | /// Compute the IV for a truncated version of SHA512 per FIPS 180 Section 5.3.6 |
| 714 | fn truncatedSha512Iv(digest_len: comptime_int) Iv64 { |
| 715 | const assert = std.debug.assert; |
| 716 | comptime assert(digest_len > 1); |
| 717 | comptime assert(digest_len <= 512); |
| 718 | comptime assert(digest_len != 384); // NIST specially defines this (see `iv384`) |
| 719 | |
| 720 | comptime var gen_params = iv512; |
| 721 | inline for (&gen_params) |*iv| { |
| 722 | iv.* ^= 0xa5a5a5a5a5a5a5a5; |
| 723 | } |
| 724 | const GenHash = Sha2x64(gen_params, 512); |
| 725 | |
| 726 | var params: [@sizeOf(Iv64)]u8 = undefined; |
| 727 | const algo_str = std.fmt.comptimePrint("SHA-512/{d}", .{digest_len}); |
| 728 | GenHash.hash(algo_str, &params, .{}); |
| 729 | |
| 730 | return Iv64{ |
| 731 | std.mem.readInt(u64, params[0..8], .big), |
| 732 | std.mem.readInt(u64, params[8..16], .big), |
| 733 | std.mem.readInt(u64, params[16..24], .big), |
| 734 | std.mem.readInt(u64, params[24..32], .big), |
| 735 | std.mem.readInt(u64, params[32..40], .big), |
| 736 | std.mem.readInt(u64, params[40..48], .big), |
| 737 | std.mem.readInt(u64, params[48..56], .big), |
| 738 | std.mem.readInt(u64, params[56..64], .big), |
| 739 | }; |
| 740 | } |
| 741 | |
| 742 | test truncatedSha512Iv { |
| 743 | // Section 5.3.6.1 |
| 744 | try std.testing.expectEqual(Iv64{ |
| 745 | 0x8C3D37C819544DA2, |
| 746 | 0x73E1996689DCD4D6, |
| 747 | 0x1DFAB7AE32FF9C82, |
| 748 | 0x679DD514582F9FCF, |
| 749 | 0x0F6D2B697BD44DA8, |
| 750 | 0x77E36F7304C48942, |
| 751 | 0x3F9D85A86A1D36C8, |
| 752 | 0x1112E6AD91D692A1, |
| 753 | }, truncatedSha512Iv(224)); |
| 754 | // Section 5.3.6.2 |
| 755 | try std.testing.expectEqual(Iv64{ |
| 756 | 0x22312194FC2BF72C, |
| 757 | 0x9F555FA3C84C64C2, |
| 758 | 0x2393B86B6F53B151, |
| 759 | 0x963877195940EABD, |
| 760 | 0x96283EE2A88EFFE3, |
| 761 | 0xBE5E1E2553863992, |
| 762 | 0x2B0199FC2C85B8AA, |
| 763 | 0x0EB72DDC81C52CA2, |
| 764 | }, truncatedSha512Iv(256)); |
| 765 | } |
| 766 | |
| 767 | test Sha384 { |
| 768 | const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"; |
| 769 | try htest.assertEqualHash(Sha384, h1, ""); |
| 770 | |
| 771 | const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"; |
| 772 | try htest.assertEqualHash(Sha384, h2, "abc"); |
| 773 | |
| 774 | const h3 = "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039"; |
| 775 | try htest.assertEqualHash(Sha384, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); |
| 776 | } |
| 777 | |
| 778 | test "sha384 streaming" { |
| 779 | var h = Sha384.init(.{}); |
| 780 | var out: [48]u8 = undefined; |
| 781 | |
| 782 | const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"; |
| 783 | h.final(out[0..]); |
| 784 | try htest.assertEqual(h1, out[0..]); |
| 785 | |
| 786 | const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"; |
| 787 | |
| 788 | h = Sha384.init(.{}); |
| 789 | h.update("abc"); |
| 790 | h.final(out[0..]); |
| 791 | try htest.assertEqual(h2, out[0..]); |
| 792 | |
| 793 | h = Sha384.init(.{}); |
| 794 | h.update("a"); |
| 795 | h.update("b"); |
| 796 | h.update("c"); |
| 797 | h.final(out[0..]); |
| 798 | try htest.assertEqual(h2, out[0..]); |
| 799 | } |
| 800 | |
| 801 | test Sha512 { |
| 802 | const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"; |
| 803 | try htest.assertEqualHash(Sha512, h1, ""); |
| 804 | |
| 805 | const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; |
| 806 | try htest.assertEqualHash(Sha512, h2, "abc"); |
| 807 | |
| 808 | const h3 = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909"; |
| 809 | try htest.assertEqualHash(Sha512, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); |
| 810 | } |
| 811 | |
| 812 | test "sha512 streaming" { |
| 813 | var h = Sha512.init(.{}); |
| 814 | var out: [64]u8 = undefined; |
| 815 | |
| 816 | const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"; |
| 817 | h.final(out[0..]); |
| 818 | try htest.assertEqual(h1, out[0..]); |
| 819 | |
| 820 | const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; |
| 821 | |
| 822 | h = Sha512.init(.{}); |
| 823 | h.update("abc"); |
| 824 | h.final(out[0..]); |
| 825 | try htest.assertEqual(h2, out[0..]); |
| 826 | |
| 827 | h = Sha512.init(.{}); |
| 828 | h.update("a"); |
| 829 | h.update("b"); |
| 830 | h.update("c"); |
| 831 | h.final(out[0..]); |
| 832 | try htest.assertEqual(h2, out[0..]); |
| 833 | } |
| 834 | |
| 835 | test "sha512 aligned final" { |
| 836 | var block: [Sha512.block_length]u8 = @splat(0); |
| 837 | var out: [Sha512.digest_length]u8 = undefined; |
| 838 | |
| 839 | var h = Sha512.init(.{}); |
| 840 | h.update(&block); |
| 841 | h.final(out[0..]); |
| 842 | } |
| 843 | |
| 844 | test Sha512_224 { |
| 845 | const h1 = "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4"; |
| 846 | try htest.assertEqualHash(Sha512_224, h1, ""); |
| 847 | |
| 848 | const h2 = "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa"; |
| 849 | try htest.assertEqualHash(Sha512_224, h2, "abc"); |
| 850 | |
| 851 | const h3 = "23fec5bb94d60b23308192640b0c453335d664734fe40e7268674af9"; |
| 852 | try htest.assertEqualHash(Sha512_224, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); |
| 853 | } |
| 854 | |
| 855 | test Sha512_256 { |
| 856 | const h1 = "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"; |
| 857 | try htest.assertEqualHash(Sha512_256, h1, ""); |
| 858 | |
| 859 | const h2 = "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"; |
| 860 | try htest.assertEqualHash(Sha512_256, h2, "abc"); |
| 861 | |
| 862 | const h3 = "3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a"; |
| 863 | try htest.assertEqualHash(Sha512_256, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); |
| 864 | } |