| ... | @@ -0,0 +1,660 @@ |
| 1 | const mem = @import("../mem.zig"); |
| 2 | const math = @import("../math/index.zig"); |
| 3 | const endian = @import("../endian.zig"); |
| 4 | const debug = @import("../debug/index.zig"); |
| 5 | |
| 6 | ///////////////////// |
| 7 | // Sha224 + Sha256 |
| 8 | |
| 9 | const RoundParam256 = struct { |
| 10 | a: u32, b: u32, c: u32, d: u32, e: u32, f: u32, g: u32, h: u32, |
| 11 | i: u32, k: u32, |
| 12 | }; |
| 13 | |
| 14 | fn Rp256(a: u32, b: u32, c: u32, d: u32, e: u32, f: u32, g: u32, h: u32, i: u32, k: u32) -> RoundParam256 { |
| 15 | return RoundParam256 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k }; |
| 16 | } |
| 17 | |
| 18 | const Sha2Params32 = struct { |
| 19 | iv0: u32, |
| 20 | iv1: u32, |
| 21 | iv2: u32, |
| 22 | iv3: u32, |
| 23 | iv4: u32, |
| 24 | iv5: u32, |
| 25 | iv6: u32, |
| 26 | iv7: u32, |
| 27 | out_len: u32, |
| 28 | }; |
| 29 | |
| 30 | const Sha224Params = Sha2Params32 { |
| 31 | .iv0 = 0xC1059ED8, |
| 32 | .iv1 = 0x367CD507, |
| 33 | .iv2 = 0x3070DD17, |
| 34 | .iv3 = 0xF70E5939, |
| 35 | .iv4 = 0xFFC00B31, |
| 36 | .iv5 = 0x68581511, |
| 37 | .iv6 = 0x64F98FA7, |
| 38 | .iv7 = 0xBEFA4FA4, |
| 39 | .out_len = 224, |
| 40 | }; |
| 41 | |
| 42 | const Sha256Params = Sha2Params32 { |
| 43 | .iv0 = 0x6A09E667, |
| 44 | .iv1 = 0xBB67AE85, |
| 45 | .iv2 = 0x3C6EF372, |
| 46 | .iv3 = 0xA54FF53A, |
| 47 | .iv4 = 0x510E527F, |
| 48 | .iv5 = 0x9B05688C, |
| 49 | .iv6 = 0x1F83D9AB, |
| 50 | .iv7 = 0x5BE0CD19, |
| 51 | .out_len = 256, |
| 52 | }; |
| 53 | |
| 54 | pub const Sha224 = Sha2_32(Sha224Params); |
| 55 | pub const Sha256 = Sha2_32(Sha256Params); |
| 56 | |
| 57 | fn Sha2_32(comptime params: Sha2Params32) -> type { return struct { |
| 58 | const Self = this; |
| 59 | const ReturnType = @IntType(false, params.out_len); |
| 60 | |
| 61 | s: [8]u32, |
| 62 | // Streaming Cache |
| 63 | buf: [64]u8, |
| 64 | buf_len: u8, |
| 65 | total_len: u64, |
| 66 | |
| 67 | pub fn init() -> Self { |
| 68 | var d: Self = undefined; |
| 69 | d.reset(); |
| 70 | return d; |
| 71 | } |
| 72 | |
| 73 | pub fn reset(d: &Self) { |
| 74 | d.s[0] = params.iv0; |
| 75 | d.s[1] = params.iv1; |
| 76 | d.s[2] = params.iv2; |
| 77 | d.s[3] = params.iv3; |
| 78 | d.s[4] = params.iv4; |
| 79 | d.s[5] = params.iv5; |
| 80 | d.s[6] = params.iv6; |
| 81 | d.s[7] = params.iv7; |
| 82 | d.buf_len = 0; |
| 83 | d.total_len = 0; |
| 84 | } |
| 85 | |
| 86 | pub fn hash(b: []const u8) -> ReturnType { |
| 87 | var d = Self.init(); |
| 88 | d.update(b); |
| 89 | return d.final(); |
| 90 | } |
| 91 | |
| 92 | pub fn update(d: &Self, b: []const u8) { |
| 93 | var off: usize = 0; |
| 94 | |
| 95 | // Partial buffer exists from previous update. Copy into buffer then hash. |
| 96 | if (d.buf_len != 0 and d.buf_len + b.len > 64) { |
| 97 | off += 64 - d.buf_len; |
| 98 | mem.copy(u8, d.buf[d.buf_len..], b[0..off]); |
| 99 | |
| 100 | d.round(d.buf[0..]); |
| 101 | d.buf_len = 0; |
| 102 | } |
| 103 | |
| 104 | // Full middle blocks. |
| 105 | while (off + 64 < b.len) : (off += 64) { |
| 106 | d.round(b[off..off + 64]); |
| 107 | } |
| 108 | |
| 109 | // Copy any remainder for next pass. |
| 110 | mem.copy(u8, d.buf[d.buf_len..], b[off..]); |
| 111 | d.buf_len += u8(b[off..].len); |
| 112 | |
| 113 | d.total_len += b.len; |
| 114 | } |
| 115 | |
| 116 | pub fn final(d: &Self) -> ReturnType { |
| 117 | // The buffer here will never be completely full. |
| 118 | mem.set(u8, d.buf[d.buf_len..], 0); |
| 119 | |
| 120 | // Append padding bits. |
| 121 | d.buf[d.buf_len] = 0x80; |
| 122 | d.buf_len += 1; |
| 123 | |
| 124 | // > 448 mod 512 so need to add an extra round to wrap around. |
| 125 | if (64 - d.buf_len < 8) { |
| 126 | d.round(d.buf[0..]); |
| 127 | mem.set(u8, d.buf[0..], 0); |
| 128 | } |
| 129 | |
| 130 | // Append message length. |
| 131 | var i: usize = 1; |
| 132 | var len = d.total_len >> 5; |
| 133 | d.buf[63] = u8(d.total_len & 0x1f) << 3; |
| 134 | while (i < 8) : (i += 1) { |
| 135 | d.buf[63 - i] = u8(len & 0xff); |
| 136 | len >>= 8; |
| 137 | } |
| 138 | |
| 139 | d.round(d.buf[0..]); |
| 140 | |
| 141 | // May truncate for possible 224 output |
| 142 | const rr = d.s[0 .. params.out_len / 32]; |
| 143 | |
| 144 | var j: u8 = u8(rr.len - 1) * 32; |
| 145 | var r: ReturnType = 0; |
| 146 | for (rr) |p| { |
| 147 | r |= ReturnType(p) << j; |
| 148 | j -%= 32; |
| 149 | } |
| 150 | |
| 151 | return endian.swapIfBe(ReturnType, r); |
| 152 | } |
| 153 | |
| 154 | fn round(d: &Self, b: []const u8) { |
| 155 | debug.assert(b.len == 64); |
| 156 | |
| 157 | var s: [64]u32 = undefined; |
| 158 | |
| 159 | // ERROR: Cannot unroll at compile-time. |
| 160 | var i: usize = 0; |
| 161 | while (i < 16) : (i += 1) { |
| 162 | s[i] = 0; |
| 163 | s[i] |= u32(b[i*4+0]) << 24; |
| 164 | s[i] |= u32(b[i*4+1]) << 16; |
| 165 | s[i] |= u32(b[i*4+2]) << 8; |
| 166 | s[i] |= u32(b[i*4+3]) << 0; |
| 167 | } |
| 168 | while (i < 64) : (i += 1) { |
| 169 | s[i] = |
| 170 | s[i-16] +% s[i-7] +% |
| 171 | (math.rotr(u32, s[i-15], u32(7)) ^ math.rotr(u32, s[i-15], u32(18)) ^ (s[i-15] >> 3)) +% |
| 172 | (math.rotr(u32, s[i-2], u32(17)) ^ math.rotr(u32, s[i-2], u32(19)) ^ (s[i-2] >> 10)); |
| 173 | } |
| 174 | |
| 175 | var v: [8]u32 = []u32 { |
| 176 | d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7], |
| 177 | }; |
| 178 | |
| 179 | const round0 = comptime []RoundParam256 { |
| 180 | Rp256(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98), |
| 181 | Rp256(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x71374491), |
| 182 | Rp256(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCF), |
| 183 | Rp256(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA5), |
| 184 | Rp256(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25B), |
| 185 | Rp256(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1), |
| 186 | Rp256(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4), |
| 187 | Rp256(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5), |
| 188 | Rp256(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98), |
| 189 | Rp256(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B01), |
| 190 | Rp256(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE), |
| 191 | Rp256(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3), |
| 192 | Rp256(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74), |
| 193 | Rp256(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE), |
| 194 | Rp256(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A7), |
| 195 | Rp256(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174), |
| 196 | Rp256(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C1), |
| 197 | Rp256(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786), |
| 198 | Rp256(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC6), |
| 199 | Rp256(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC), |
| 200 | Rp256(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F), |
| 201 | Rp256(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA), |
| 202 | Rp256(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DC), |
| 203 | Rp256(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA), |
| 204 | Rp256(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152), |
| 205 | Rp256(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D), |
| 206 | Rp256(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C8), |
| 207 | Rp256(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7), |
| 208 | Rp256(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF3), |
| 209 | Rp256(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147), |
| 210 | Rp256(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351), |
| 211 | Rp256(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x14292967), |
| 212 | Rp256(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A85), |
| 213 | Rp256(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B2138), |
| 214 | Rp256(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC), |
| 215 | Rp256(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D13), |
| 216 | Rp256(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A7354), |
| 217 | Rp256(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB), |
| 218 | Rp256(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E), |
| 219 | Rp256(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C85), |
| 220 | Rp256(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A1), |
| 221 | Rp256(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664B), |
| 222 | Rp256(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70), |
| 223 | Rp256(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A3), |
| 224 | Rp256(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819), |
| 225 | Rp256(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD6990624), |
| 226 | Rp256(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E3585), |
| 227 | Rp256(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA070), |
| 228 | Rp256(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116), |
| 229 | Rp256(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C08), |
| 230 | Rp256(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774C), |
| 231 | Rp256(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5), |
| 232 | Rp256(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3), |
| 233 | Rp256(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4A), |
| 234 | Rp256(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F), |
| 235 | Rp256(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3), |
| 236 | Rp256(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE), |
| 237 | Rp256(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F), |
| 238 | Rp256(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814), |
| 239 | Rp256(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC70208), |
| 240 | Rp256(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA), |
| 241 | Rp256(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEB), |
| 242 | Rp256(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7), |
| 243 | Rp256(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2), |
| 244 | }; |
| 245 | inline for (round0) |r| { |
| 246 | v[r.h] = |
| 247 | v[r.h] +% |
| 248 | (math.rotr(u32, v[r.e], u32(6)) ^ math.rotr(u32, v[r.e], u32(11)) ^ math.rotr(u32, v[r.e], u32(25))) +% |
| 249 | (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +% |
| 250 | r.k +% s[r.i]; |
| 251 | |
| 252 | v[r.d] = v[r.d] +% v[r.h]; |
| 253 | |
| 254 | v[r.h] = |
| 255 | v[r.h] +% |
| 256 | (math.rotr(u32, v[r.a], u32(2)) ^ math.rotr(u32, v[r.a], u32(13)) ^ math.rotr(u32, v[r.a], u32(22))) +% |
| 257 | ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c])); |
| 258 | } |
| 259 | |
| 260 | d.s[0] +%= v[0]; |
| 261 | d.s[1] +%= v[1]; |
| 262 | d.s[2] +%= v[2]; |
| 263 | d.s[3] +%= v[3]; |
| 264 | d.s[4] +%= v[4]; |
| 265 | d.s[5] +%= v[5]; |
| 266 | d.s[6] +%= v[6]; |
| 267 | d.s[7] +%= v[7]; |
| 268 | } |
| 269 | };} |
| 270 | |
| 271 | test "sha224 single" { |
| 272 | debug.assert(0xd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f == Sha224.hash("")); |
| 273 | debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == Sha224.hash("abc")); |
| 274 | debug.assert(0xc97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3 == Sha224.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")); |
| 275 | } |
| 276 | |
| 277 | test "sha224 streaming" { |
| 278 | var h = Sha224.init(); |
| 279 | |
| 280 | debug.assert(0xd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f == h.final()); |
| 281 | |
| 282 | h.reset(); |
| 283 | h.update("abc"); |
| 284 | debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == h.final()); |
| 285 | |
| 286 | h.reset(); |
| 287 | h.update("a"); |
| 288 | h.update("b"); |
| 289 | h.update("c"); |
| 290 | debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == h.final()); |
| 291 | } |
| 292 | |
| 293 | test "sha256 single" { |
| 294 | debug.assert(0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 == Sha256.hash("")); |
| 295 | debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == Sha256.hash("abc")); |
| 296 | debug.assert(0xcf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1 == Sha256.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")); |
| 297 | } |
| 298 | |
| 299 | test "sha256 streaming" { |
| 300 | var h = Sha256.init(); |
| 301 | |
| 302 | debug.assert(0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 == h.final()); |
| 303 | |
| 304 | h.reset(); |
| 305 | h.update("abc"); |
| 306 | debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == h.final()); |
| 307 | |
| 308 | h.reset(); |
| 309 | h.update("a"); |
| 310 | h.update("b"); |
| 311 | h.update("c"); |
| 312 | debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == h.final()); |
| 313 | } |
| 314 | |
| 315 | |
| 316 | ///////////////////// |
| 317 | // Sha384 + Sha512 |
| 318 | |
| 319 | const RoundParam512 = struct { |
| 320 | a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, |
| 321 | i: usize, k: u64, |
| 322 | }; |
| 323 | |
| 324 | fn Rp512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) -> RoundParam512 { |
| 325 | return RoundParam512 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k }; |
| 326 | } |
| 327 | |
| 328 | const Sha2Params64 = struct { |
| 329 | iv0: u64, |
| 330 | iv1: u64, |
| 331 | iv2: u64, |
| 332 | iv3: u64, |
| 333 | iv4: u64, |
| 334 | iv5: u64, |
| 335 | iv6: u64, |
| 336 | iv7: u64, |
| 337 | out_len: usize, |
| 338 | }; |
| 339 | |
| 340 | const Sha384Params = Sha2Params64 { |
| 341 | .iv0 = 0xCBBB9D5DC1059ED8, |
| 342 | .iv1 = 0x629A292A367CD507, |
| 343 | .iv2 = 0x9159015A3070DD17, |
| 344 | .iv3 = 0x152FECD8F70E5939, |
| 345 | .iv4 = 0x67332667FFC00B31, |
| 346 | .iv5 = 0x8EB44A8768581511, |
| 347 | .iv6 = 0xDB0C2E0D64F98FA7, |
| 348 | .iv7 = 0x47B5481DBEFA4FA4, |
| 349 | .out_len = 384, |
| 350 | }; |
| 351 | |
| 352 | const Sha512Params = Sha2Params64 { |
| 353 | .iv0 = 0x6A09E667F3BCC908, |
| 354 | .iv1 = 0xBB67AE8584CAA73B, |
| 355 | .iv2 = 0x3C6EF372FE94F82B, |
| 356 | .iv3 = 0xA54FF53A5F1D36F1, |
| 357 | .iv4 = 0x510E527FADE682D1, |
| 358 | .iv5 = 0x9B05688C2B3E6C1F, |
| 359 | .iv6 = 0x1F83D9ABFB41BD6B, |
| 360 | .iv7 = 0x5BE0CD19137E2179, |
| 361 | .out_len = 512 |
| 362 | }; |
| 363 | |
| 364 | pub const Sha384 = Sha2_64(Sha384Params); |
| 365 | pub const Sha512 = Sha2_64(Sha512Params); |
| 366 | |
| 367 | fn Sha2_64(comptime params: Sha2Params64) -> type { return struct { |
| 368 | const Self = this; |
| 369 | const ReturnType = @IntType(false, params.out_len); |
| 370 | const u9 = @IntType(false, 9); |
| 371 | |
| 372 | s: [8]u64, |
| 373 | // Streaming Cache |
| 374 | buf: [128]u8, |
| 375 | buf_len: u8, |
| 376 | total_len: u64, |
| 377 | |
| 378 | pub fn init() -> Self { |
| 379 | var d: Self = undefined; |
| 380 | d.reset(); |
| 381 | return d; |
| 382 | } |
| 383 | |
| 384 | pub fn reset(d: &Self) { |
| 385 | d.s[0] = params.iv0; |
| 386 | d.s[1] = params.iv1; |
| 387 | d.s[2] = params.iv2; |
| 388 | d.s[3] = params.iv3; |
| 389 | d.s[4] = params.iv4; |
| 390 | d.s[5] = params.iv5; |
| 391 | d.s[6] = params.iv6; |
| 392 | d.s[7] = params.iv7; |
| 393 | d.buf_len = 0; |
| 394 | d.total_len = 0; |
| 395 | } |
| 396 | |
| 397 | pub fn hash(b: []const u8) -> ReturnType { |
| 398 | var d = Self.init(); |
| 399 | d.update(b); |
| 400 | return d.final(); |
| 401 | } |
| 402 | |
| 403 | pub fn update(d: &Self, b: []const u8) { |
| 404 | var off: usize = 0; |
| 405 | |
| 406 | // Partial buffer exists from previous update. Copy into buffer then hash. |
| 407 | if (d.buf_len != 0 and d.buf_len + b.len > 128) { |
| 408 | off += 128 - d.buf_len; |
| 409 | mem.copy(u8, d.buf[d.buf_len..], b[0..off]); |
| 410 | |
| 411 | d.round(d.buf[0..]); |
| 412 | d.buf_len = 0; |
| 413 | } |
| 414 | |
| 415 | // Full middle blocks. |
| 416 | while (off + 128 < b.len) : (off += 128) { |
| 417 | d.round(b[off..off + 128]); |
| 418 | } |
| 419 | |
| 420 | // Copy any remainder for next pass. |
| 421 | mem.copy(u8, d.buf[d.buf_len..], b[off..]); |
| 422 | d.buf_len += u8(b[off..].len); |
| 423 | |
| 424 | d.total_len += b.len; |
| 425 | } |
| 426 | |
| 427 | pub fn final(d: &Self) -> ReturnType { |
| 428 | // The buffer here will never be completely full. |
| 429 | mem.set(u8, d.buf[d.buf_len..], 0); |
| 430 | |
| 431 | // Append padding bits. |
| 432 | d.buf[d.buf_len] = 0x80; |
| 433 | d.buf_len += 1; |
| 434 | |
| 435 | // > 896 mod 1024 so need to add an extra round to wrap around. |
| 436 | if (128 - d.buf_len < 16) { |
| 437 | d.round(d.buf[0..]); |
| 438 | mem.set(u8, d.buf[0..], 0); |
| 439 | } |
| 440 | |
| 441 | // Append message length. |
| 442 | var i: usize = 1; |
| 443 | var len = d.total_len >> 5; |
| 444 | d.buf[127] = u8(d.total_len & 0x1f) << 3; |
| 445 | while (i < 16) : (i += 1) { |
| 446 | d.buf[127 - i] = u8(len & 0xff); |
| 447 | len >>= 8; |
| 448 | } |
| 449 | |
| 450 | d.round(d.buf[0..]); |
| 451 | |
| 452 | // May truncate for possible 384 output |
| 453 | const rr = d.s[0 .. params.out_len / 64]; |
| 454 | |
| 455 | var j: u9 = u9(rr.len - 1) * 64; |
| 456 | var r: ReturnType = 0; |
| 457 | for (rr) |p| { |
| 458 | r |= ReturnType(p) << j; |
| 459 | j -%= 64; |
| 460 | } |
| 461 | |
| 462 | return endian.swapIfBe(ReturnType, r); |
| 463 | } |
| 464 | |
| 465 | fn round(d: &Self, b: []const u8) { |
| 466 | debug.assert(b.len == 128); |
| 467 | |
| 468 | var s: [80]u64 = undefined; |
| 469 | |
| 470 | // ERROR: Cannot unroll at compile-time. |
| 471 | var i: usize = 0; |
| 472 | while (i < 16) : (i += 1) { |
| 473 | s[i] = 0; |
| 474 | s[i] |= u64(b[i*8+0]) << 56; |
| 475 | s[i] |= u64(b[i*8+1]) << 48; |
| 476 | s[i] |= u64(b[i*8+2]) << 40; |
| 477 | s[i] |= u64(b[i*8+3]) << 32; |
| 478 | s[i] |= u64(b[i*8+4]) << 24; |
| 479 | s[i] |= u64(b[i*8+5]) << 16; |
| 480 | s[i] |= u64(b[i*8+6]) << 8; |
| 481 | s[i] |= u64(b[i*8+7]) << 0; |
| 482 | } |
| 483 | while (i < 80) : (i += 1) { |
| 484 | s[i] = |
| 485 | s[i-16] +% s[i-7] +% |
| 486 | (math.rotr(u64, s[i-15], u64(1)) ^ math.rotr(u64, s[i-15], u64(8)) ^ (s[i-15] >> 7)) +% |
| 487 | (math.rotr(u64, s[i-2], u64(19)) ^ math.rotr(u64, s[i-2], u64(61)) ^ (s[i-2] >> 6)); |
| 488 | } |
| 489 | |
| 490 | var v: [8]u64 = []u64 { |
| 491 | d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7], |
| 492 | }; |
| 493 | |
| 494 | const round0 = comptime []RoundParam512 { |
| 495 | Rp512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22), |
| 496 | Rp512(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x7137449123EF65CD), |
| 497 | Rp512(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCFEC4D3B2F), |
| 498 | Rp512(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA58189DBBC), |
| 499 | Rp512(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25BF348B538), |
| 500 | Rp512(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1B605D019), |
| 501 | Rp512(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4AF194F9B), |
| 502 | Rp512(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5DA6D8118), |
| 503 | Rp512(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98A3030242), |
| 504 | Rp512(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B0145706FBE), |
| 505 | Rp512(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE4EE4B28C), |
| 506 | Rp512(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3D5FFB4E2), |
| 507 | Rp512(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74F27B896F), |
| 508 | Rp512(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE3B1696B1), |
| 509 | Rp512(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A725C71235), |
| 510 | Rp512(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174CF692694), |
| 511 | Rp512(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C19EF14AD2), |
| 512 | Rp512(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786384F25E3), |
| 513 | Rp512(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC68B8CD5B5), |
| 514 | Rp512(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC77AC9C65), |
| 515 | Rp512(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F592B0275), |
| 516 | Rp512(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA6EA6E483), |
| 517 | Rp512(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DCBD41FBD4), |
| 518 | Rp512(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA831153B5), |
| 519 | Rp512(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152EE66DFAB), |
| 520 | Rp512(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D2DB43210), |
| 521 | Rp512(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C898FB213F), |
| 522 | Rp512(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7BEEF0EE4), |
| 523 | Rp512(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF33DA88FC2), |
| 524 | Rp512(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147930AA725), |
| 525 | Rp512(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351E003826F), |
| 526 | Rp512(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x142929670A0E6E70), |
| 527 | Rp512(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A8546D22FFC), |
| 528 | Rp512(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B21385C26C926), |
| 529 | Rp512(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC5AC42AED), |
| 530 | Rp512(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D139D95B3DF), |
| 531 | Rp512(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A73548BAF63DE), |
| 532 | Rp512(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB3C77B2A8), |
| 533 | Rp512(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E47EDAEE6), |
| 534 | Rp512(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C851482353B), |
| 535 | Rp512(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A14CF10364), |
| 536 | Rp512(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664BBC423001), |
| 537 | Rp512(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70D0F89791), |
| 538 | Rp512(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A30654BE30), |
| 539 | Rp512(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819D6EF5218), |
| 540 | Rp512(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD69906245565A910), |
| 541 | Rp512(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E35855771202A), |
| 542 | Rp512(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA07032BBD1B8), |
| 543 | Rp512(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116B8D2D0C8), |
| 544 | Rp512(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C085141AB53), |
| 545 | Rp512(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774CDF8EEB99), |
| 546 | Rp512(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5E19B48A8), |
| 547 | Rp512(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3C5C95A63), |
| 548 | Rp512(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4AE3418ACB), |
| 549 | Rp512(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F7763E373), |
| 550 | Rp512(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3D6B2B8A3), |
| 551 | Rp512(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE5DEFB2FC), |
| 552 | Rp512(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F43172F60), |
| 553 | Rp512(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814A1F0AB72), |
| 554 | Rp512(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC702081A6439EC), |
| 555 | Rp512(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA23631E28), |
| 556 | Rp512(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEBDE82BDE9), |
| 557 | Rp512(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7B2C67915), |
| 558 | Rp512(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2E372532B), |
| 559 | Rp512(0, 1, 2, 3, 4, 5, 6, 7, 64, 0xCA273ECEEA26619C), |
| 560 | Rp512(7, 0, 1, 2, 3, 4, 5, 6, 65, 0xD186B8C721C0C207), |
| 561 | Rp512(6, 7, 0, 1, 2, 3, 4, 5, 66, 0xEADA7DD6CDE0EB1E), |
| 562 | Rp512(5, 6, 7, 0, 1, 2, 3, 4, 67, 0xF57D4F7FEE6ED178), |
| 563 | Rp512(4, 5, 6, 7, 0, 1, 2, 3, 68, 0x06F067AA72176FBA), |
| 564 | Rp512(3, 4, 5, 6, 7, 0, 1, 2, 69, 0x0A637DC5A2C898A6), |
| 565 | Rp512(2, 3, 4, 5, 6, 7, 0, 1, 70, 0x113F9804BEF90DAE), |
| 566 | Rp512(1, 2, 3, 4, 5, 6, 7, 0, 71, 0x1B710B35131C471B), |
| 567 | Rp512(0, 1, 2, 3, 4, 5, 6, 7, 72, 0x28DB77F523047D84), |
| 568 | Rp512(7, 0, 1, 2, 3, 4, 5, 6, 73, 0x32CAAB7B40C72493), |
| 569 | Rp512(6, 7, 0, 1, 2, 3, 4, 5, 74, 0x3C9EBE0A15C9BEBC), |
| 570 | Rp512(5, 6, 7, 0, 1, 2, 3, 4, 75, 0x431D67C49C100D4C), |
| 571 | Rp512(4, 5, 6, 7, 0, 1, 2, 3, 76, 0x4CC5D4BECB3E42B6), |
| 572 | Rp512(3, 4, 5, 6, 7, 0, 1, 2, 77, 0x597F299CFC657E2A), |
| 573 | Rp512(2, 3, 4, 5, 6, 7, 0, 1, 78, 0x5FCB6FAB3AD6FAEC), |
| 574 | Rp512(1, 2, 3, 4, 5, 6, 7, 0, 79, 0x6C44198C4A475817), |
| 575 | }; |
| 576 | inline for (round0) |r| { |
| 577 | v[r.h] = |
| 578 | v[r.h] +% |
| 579 | (math.rotr(u64, v[r.e], u64(14)) ^ math.rotr(u64, v[r.e], u64(18)) ^ math.rotr(u64, v[r.e], u64(41))) +% |
| 580 | (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +% |
| 581 | r.k +% s[r.i]; |
| 582 | |
| 583 | v[r.d] = v[r.d] +% v[r.h]; |
| 584 | |
| 585 | v[r.h] = |
| 586 | v[r.h] +% |
| 587 | (math.rotr(u64, v[r.a], u64(28)) ^ math.rotr(u64, v[r.a], u64(34)) ^ math.rotr(u64, v[r.a], u64(39))) +% |
| 588 | ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c])); |
| 589 | } |
| 590 | |
| 591 | d.s[0] +%= v[0]; |
| 592 | d.s[1] +%= v[1]; |
| 593 | d.s[2] +%= v[2]; |
| 594 | d.s[3] +%= v[3]; |
| 595 | d.s[4] +%= v[4]; |
| 596 | d.s[5] +%= v[5]; |
| 597 | d.s[6] +%= v[6]; |
| 598 | d.s[7] +%= v[7]; |
| 599 | } |
| 600 | };} |
| 601 | |
| 602 | test "sha384 single" { |
| 603 | const h1 = 0x38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b; |
| 604 | debug.assert(h1 == Sha384.hash("")); |
| 605 | |
| 606 | const h2 = 0xcb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7; |
| 607 | debug.assert(h2 == Sha384.hash("abc")); |
| 608 | |
| 609 | const h3 = 0x09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039; |
| 610 | debug.assert(h3 == Sha384.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")); |
| 611 | } |
| 612 | |
| 613 | test "sha384 streaming" { |
| 614 | var h = Sha384.init(); |
| 615 | |
| 616 | const h1 = 0x38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b; |
| 617 | debug.assert(h1 == h.final()); |
| 618 | |
| 619 | const h2 = 0xcb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7; |
| 620 | |
| 621 | h.reset(); |
| 622 | h.update("abc"); |
| 623 | debug.assert(h2 == h.final()); |
| 624 | |
| 625 | h.reset(); |
| 626 | h.update("a"); |
| 627 | h.update("b"); |
| 628 | h.update("c"); |
| 629 | debug.assert(h2 == h.final()); |
| 630 | } |
| 631 | |
| 632 | test "sha512 single" { |
| 633 | const h1 = 0xcf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e; |
| 634 | debug.assert(h1 == Sha512.hash("")); |
| 635 | |
| 636 | const h2 = 0xddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f; |
| 637 | debug.assert(h2 == Sha512.hash("abc")); |
| 638 | |
| 639 | const h3 = 0x8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909; |
| 640 | debug.assert(h3 == Sha512.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")); |
| 641 | } |
| 642 | |
| 643 | test "sha512 streaming" { |
| 644 | var h = Sha512.init(); |
| 645 | |
| 646 | const h1 = 0xcf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e; |
| 647 | debug.assert(h1 == h.final()); |
| 648 | |
| 649 | const h2 = 0xddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f; |
| 650 | |
| 651 | h.reset(); |
| 652 | h.update("abc"); |
| 653 | debug.assert(h2 == h.final()); |
| 654 | |
| 655 | h.reset(); |
| 656 | h.update("a"); |
| 657 | h.update("b"); |
| 658 | h.update("c"); |
| 659 | debug.assert(h2 == h.final()); |
| 660 | } |