blake2b.ha (4551B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use bytes; 5 use crypto::math; 6 use endian; 7 use hash; 8 use io; 9 10 def R1: int = 32; 11 def R2: int = 24; 12 def R3: int = 16; 13 def R4: int = 63; 14 def r: u64 = 12; 15 def BSZ: size = 128; 16 17 const iv: [8]u64 = [ 18 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, 19 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1, 20 0x510E527FADE682D1, 0x9B05688C2B3E6C1F, 21 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179, 22 ]; 23 24 const sigma: [12][16]u8 = [ 25 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 26 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], 27 [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], 28 [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], 29 [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], 30 [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], 31 [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], 32 [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], 33 [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], 34 [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], 35 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 36 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], 37 ]; 38 39 export type digest = struct { 40 hash::hash, 41 h: [8]u64, 42 tlow: u64, 43 thigh: u64, 44 block: [BSZ]u8, 45 blocklen: size, 46 }; 47 48 const blake2b_vtable: io::vtable = io::vtable { 49 writer = &write, 50 closer = &close, 51 ... 52 }; 53 54 // Creates a [[hash::hash]] which computes a BLAKE2b hash with a given key and a 55 // given hash size. The size must be between 1 and 64, inclusive. If this 56 // function is used to hash sensitive information, the caller should call 57 // [[hash::close]] to erase sensitive data from memory after use; if not, the 58 // use of [[hash::close]] is optional. This function does not provide reset 59 // functionality and calling [[hash::reset]] on it will terminate execution. 60 export fn blake2b(key: []u8, sz: size) digest = { 61 assert(1 <= sz); 62 assert(sz <= 64); 63 assert(len(key) <= 64); 64 let h = iv; 65 h[0] ^= 0x01010000 ^ (len(key) << 8) ^ sz; 66 let keyblock: [BSZ]u8 = [0...]; 67 keyblock[..len(key)] = key; 68 return digest { 69 stream = &blake2b_vtable, 70 sum = &sum, 71 sz = sz, 72 h = h, 73 tlow = 0, 74 thigh = 0, 75 block = keyblock, 76 blocklen = if (len(key) > 0) BSZ else 0, 77 ... 78 }; 79 }; 80 81 fn write(st: *io::stream, buf: const []u8) (size | io::error) = { 82 if (len(buf) == 0) return 0z; 83 let h = st: *digest; 84 let length = len(buf); 85 let buf = buf[..]; 86 87 for (h.blocklen + len(buf) > BSZ) { 88 const n = BSZ - h.blocklen; 89 h.block[h.blocklen..h.blocklen + n] = buf[..n]; 90 buf = buf[n..]; 91 92 h.tlow += BSZ; 93 if (h.tlow < n: u64) h.thigh += 1; 94 95 compress(&h.h, &h.block, h.tlow, h.thigh, false); 96 h.blocklen = 0; 97 }; 98 h.block[h.blocklen..h.blocklen + len(buf)] = buf; 99 h.blocklen += len(buf); 100 return length; 101 }; 102 103 fn sum(h: *hash::hash, buf: []u8) void = { 104 let h = h: *digest; 105 let copy = *h; 106 let h = © 107 defer hash::close(h); 108 109 h.tlow += h.blocklen; 110 if (h.tlow < h.blocklen: u64) h.thigh += 1; 111 112 // Padding 113 let tmp: [BSZ]u8 = [0...]; 114 h.block[h.blocklen..BSZ] = tmp[..BSZ - h.blocklen]; 115 h.blocklen = BSZ; 116 117 compress(&h.h, &h.block, h.tlow, h.thigh, true); 118 119 for (let i = 0z; i < h.sz / 8; i += 1) { 120 endian::leputu64(buf[i * 8..i * 8 + 8], h.h[i]); 121 }; 122 }; 123 124 // Compression function F 125 fn compress(h: *[8]u64, b: *[BSZ]u8, tlow: u64, thigh: u64, f: bool) void = { 126 let v: [16]u64 = [0...]; 127 v[..8] = h[..]; 128 v[8..] = iv; 129 v[12] ^= tlow; 130 v[13] ^= thigh; 131 if (f) v[14] = ~v[14]; 132 let m: [16]u64 = [0...]; 133 for (let i = 0z; i < len(m); i += 1) { 134 m[i] = endian::legetu64(b[i * 8..i * 8 + 8]); 135 }; 136 for (let i = 0u64; i < r; i += 1) { 137 const s = &sigma[i]; 138 mix(&v, 0, 4, 8, 12, m[s[0]], m[s[1]]); 139 mix(&v, 1, 5, 9, 13, m[s[2]], m[s[3]]); 140 mix(&v, 2, 6, 10, 14, m[s[4]], m[s[5]]); 141 mix(&v, 3, 7, 11, 15, m[s[6]], m[s[7]]); 142 143 mix(&v, 0, 5, 10, 15, m[s[8]], m[s[9]]); 144 mix(&v, 1, 6, 11, 12, m[s[10]], m[s[11]]); 145 mix(&v, 2, 7, 8, 13, m[s[12]], m[s[13]]); 146 mix(&v, 3, 4, 9, 14, m[s[14]], m[s[15]]); 147 }; 148 149 for (let i = 0; i < 8; i += 1) { 150 h[i] ^= v[i] ^ v[i + 8]; 151 }; 152 }; 153 154 // Mixing function G 155 fn mix(v: *[16]u64, a: size, b: size, c: size, d: size, x: u64, y: u64) void = { 156 v[a] = v[a] + v[b] + x; 157 v[d] = math::rotr64(v[d] ^ v[a], R1); 158 v[c] = v[c] + v[d]; 159 v[b] = math::rotr64(v[b] ^ v[c], R2); 160 v[a] = v[a] + v[b] + y; 161 v[d] = math::rotr64(v[d] ^ v[a], R3); 162 v[c] = v[c] + v[d]; 163 v[b] = math::rotr64(v[b] ^ v[c], R4); 164 }; 165 166 fn close(stream: *io::stream) (void | io::error) = { 167 let s = stream: *digest; 168 bytes::zero((s.h[..]: *[*]u8)[..len(s.h) * size(u32)]); 169 bytes::zero(s.block); 170 };