| 1 | // Copyright (c) 2023 Kim Shrier. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license |
| 3 | // that can be found in the LICENSE file. |
| 4 | // Package blake2b implements the Blake2b 512, 384, 256, and |
| 5 | // 160 bit hash algorithms |
| 6 | // as defined in IETF RFC 7693. |
| 7 | // Based off: https://datatracker.ietf.org/doc/html/rfc7693 |
| 8 | // Last updated: November 2015 |
| 9 | module blake2b |
| 10 | |
| 11 | import math.bits |
| 12 | |
| 13 | // mixing function g |
| 14 | @[direct_array_access; inline] |
| 15 | fn g(mut v [16]u64, a u8, b u8, c u8, d u8, x u64, y u64) { |
| 16 | v[a] = v[a] + v[b] + x |
| 17 | v[d] = bits.rotate_left_64((v[d] ^ v[a]), nr1) |
| 18 | v[c] = v[c] + v[d] |
| 19 | v[b] = bits.rotate_left_64((v[b] ^ v[c]), nr2) |
| 20 | v[a] = v[a] + v[b] + y |
| 21 | v[d] = bits.rotate_left_64((v[d] ^ v[a]), nr3) |
| 22 | v[c] = v[c] + v[d] |
| 23 | v[b] = bits.rotate_left_64((v[b] ^ v[c]), nr4) |
| 24 | } |
| 25 | |
| 26 | // one complete mixing round with the function g |
| 27 | @[direct_array_access; inline] |
| 28 | fn (d Digest) mixing_round(mut v [16]u64, s [16]u8) { |
| 29 | g(mut v, 0, 4, 8, 12, d.m[s[0]], d.m[s[1]]) |
| 30 | g(mut v, 1, 5, 9, 13, d.m[s[2]], d.m[s[3]]) |
| 31 | g(mut v, 2, 6, 10, 14, d.m[s[4]], d.m[s[5]]) |
| 32 | g(mut v, 3, 7, 11, 15, d.m[s[6]], d.m[s[7]]) |
| 33 | |
| 34 | g(mut v, 0, 5, 10, 15, d.m[s[8]], d.m[s[9]]) |
| 35 | g(mut v, 1, 6, 11, 12, d.m[s[10]], d.m[s[11]]) |
| 36 | g(mut v, 2, 7, 8, 13, d.m[s[12]], d.m[s[13]]) |
| 37 | g(mut v, 3, 4, 9, 14, d.m[s[14]], d.m[s[15]]) |
| 38 | } |
| 39 | |
| 40 | // compression function f |
| 41 | @[direct_array_access] |
| 42 | fn (mut d Digest) f(f bool) { |
| 43 | // initialize the working vector |
| 44 | mut v := [16]u64{} |
| 45 | for i in 0 .. 8 { |
| 46 | v[i] = d.h[i] |
| 47 | v[i + 8] = iv[i] |
| 48 | } |
| 49 | |
| 50 | v[12] ^= d.t.lo |
| 51 | v[13] ^= d.t.hi |
| 52 | |
| 53 | if f { |
| 54 | v[14] = ~v[14] |
| 55 | } |
| 56 | |
| 57 | // go 12 rounds of cryptographic mixing |
| 58 | d.mixing_round(mut v, sigma[0]) |
| 59 | d.mixing_round(mut v, sigma[1]) |
| 60 | d.mixing_round(mut v, sigma[2]) |
| 61 | d.mixing_round(mut v, sigma[3]) |
| 62 | d.mixing_round(mut v, sigma[4]) |
| 63 | d.mixing_round(mut v, sigma[5]) |
| 64 | d.mixing_round(mut v, sigma[6]) |
| 65 | d.mixing_round(mut v, sigma[7]) |
| 66 | d.mixing_round(mut v, sigma[8]) |
| 67 | d.mixing_round(mut v, sigma[9]) |
| 68 | d.mixing_round(mut v, sigma[0]) |
| 69 | d.mixing_round(mut v, sigma[1]) |
| 70 | |
| 71 | // combine internal hash state with both halves of the working vector |
| 72 | |
| 73 | d.h[0] = d.h[0] ^ v[0] ^ v[8] |
| 74 | d.h[1] = d.h[1] ^ v[1] ^ v[9] |
| 75 | d.h[2] = d.h[2] ^ v[2] ^ v[10] |
| 76 | d.h[3] = d.h[3] ^ v[3] ^ v[11] |
| 77 | d.h[4] = d.h[4] ^ v[4] ^ v[12] |
| 78 | d.h[5] = d.h[5] ^ v[5] ^ v[13] |
| 79 | d.h[6] = d.h[6] ^ v[6] ^ v[14] |
| 80 | d.h[7] = d.h[7] ^ v[7] ^ v[15] |
| 81 | } |
| 82 | |