| 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 blake3 implements the Blake3 cryptographic hash |
| 5 | // as described in: |
| 6 | // https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf |
| 7 | // Version 20211102173700 |
| 8 | |
| 9 | module blake3 |
| 10 | |
| 11 | import math.bits |
| 12 | |
| 13 | // mixing function g |
| 14 | @[direct_array_access; inline] |
| 15 | fn g(mut v [16]u32, a u8, b u8, c u8, d u8, x u32, y u32) { |
| 16 | v[a] = v[a] + v[b] + x |
| 17 | v[d] = bits.rotate_left_32((v[d] ^ v[a]), nr1) |
| 18 | v[c] = v[c] + v[d] |
| 19 | v[b] = bits.rotate_left_32((v[b] ^ v[c]), nr2) |
| 20 | v[a] = v[a] + v[b] + y |
| 21 | v[d] = bits.rotate_left_32((v[d] ^ v[a]), nr3) |
| 22 | v[c] = v[c] + v[d] |
| 23 | v[b] = bits.rotate_left_32((v[b] ^ v[c]), nr4) |
| 24 | } |
| 25 | |
| 26 | // one complete mixing round with the function g |
| 27 | @[direct_array_access; inline] |
| 28 | fn mixing_round(mut v [16]u32, m []u32, s [16]u8) { |
| 29 | g(mut v, 0, 4, 8, 12, m[s[0]], m[s[1]]) |
| 30 | g(mut v, 1, 5, 9, 13, m[s[2]], m[s[3]]) |
| 31 | g(mut v, 2, 6, 10, 14, m[s[4]], m[s[5]]) |
| 32 | g(mut v, 3, 7, 11, 15, m[s[6]], m[s[7]]) |
| 33 | |
| 34 | g(mut v, 0, 5, 10, 15, m[s[8]], m[s[9]]) |
| 35 | g(mut v, 1, 6, 11, 12, m[s[10]], m[s[11]]) |
| 36 | g(mut v, 2, 7, 8, 13, m[s[12]], m[s[13]]) |
| 37 | g(mut v, 3, 4, 9, 14, m[s[14]], m[s[15]]) |
| 38 | } |
| 39 | |
| 40 | // compression function f |
| 41 | @[direct_array_access] |
| 42 | fn f(h []u32, m []u32, counter u64, input_bytes u32, flags u32) []u32 { |
| 43 | mut v := [16]u32{} |
| 44 | |
| 45 | // initialize the working vector |
| 46 | for i in 0 .. 8 { |
| 47 | v[i] = h[i] |
| 48 | } |
| 49 | for i in 0 .. 4 { |
| 50 | v[i + 8] = iv[i] |
| 51 | } |
| 52 | v[12] = u32(counter) |
| 53 | v[13] = u32(counter >> 32) |
| 54 | v[14] = input_bytes |
| 55 | v[15] = flags |
| 56 | |
| 57 | // go 7 rounds of cryptographic mixing |
| 58 | // |
| 59 | // These could potentially be spawned in concurrent tasks |
| 60 | // to see if there is any real speed improvement. |
| 61 | mixing_round(mut v, m, sigma[0]) |
| 62 | mixing_round(mut v, m, sigma[1]) |
| 63 | mixing_round(mut v, m, sigma[2]) |
| 64 | mixing_round(mut v, m, sigma[3]) |
| 65 | mixing_round(mut v, m, sigma[4]) |
| 66 | mixing_round(mut v, m, sigma[5]) |
| 67 | mixing_round(mut v, m, sigma[6]) |
| 68 | |
| 69 | // combine internal hash state with both halves of the working vector |
| 70 | |
| 71 | for i in 0 .. 8 { |
| 72 | v[i] ^= v[i + 8] |
| 73 | v[i + 8] ^= h[i] |
| 74 | } |
| 75 | |
| 76 | return v[..] |
| 77 | } |
| 78 | |