1#![allow(clippy::needless_range_loop)]
14
15use std::convert::TryInto;
16
17#[derive(Clone)]
19pub struct Blake2b {
20 h: [u64; 8],
21 t: [u64; 2],
22 f: [u64; 2],
23 buf: [u8; 128],
24 buf_len: usize,
25 out_len: usize,
26}
27
28const IV: [u64; 8] = [
29 0x6a09e667f3bcc908,
30 0xbb67ae8584caa73b,
31 0x3c6ef372fe94f82b,
32 0xa54ff53a5f1d36f1,
33 0x510e527fade682d1,
34 0x9b05688c2b3e6c1f,
35 0x1f83d9abfb41bd6b,
36 0x5be0cd19137e2179,
37];
38
39const SIGMA: [[usize; 16]; 12] = [
40 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
41 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
42 [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
43 [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
44 [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
45 [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
46 [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
47 [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
48 [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
49 [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
50 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], ];
53
54impl Blake2b {
55 pub fn new(out_len: usize) -> Self {
57 Self::new_keyed(out_len, &[])
58 }
59
60 pub fn new_keyed(out_len: usize, key: &[u8]) -> Self {
62 assert!(out_len > 0 && out_len <= 64);
63 assert!(key.len() <= 64);
64
65 let mut h = IV;
66 h[0] ^= 0x01010000 ^ ((key.len() as u64) << 8) ^ (out_len as u64);
67
68 let mut state = Self {
69 h,
70 t: [0, 0],
71 f: [0, 0],
72 buf: [0; 128],
73 buf_len: 0,
74 out_len,
75 };
76
77 if !key.is_empty() {
78 state.update(key);
79 state.buf_len = 128; }
81
82 state
83 }
84
85 pub fn update(&mut self, data: &[u8]) {
87 let mut offset = 0;
88 let mut len = data.len();
89
90 while len > 0 {
91 if self.buf_len == 128 {
92 self.t[0] = self.t[0].wrapping_add(128);
93 if self.t[0] < 128 {
94 self.t[1] = self.t[1].wrapping_add(1);
95 }
96 self.compress();
97 self.buf_len = 0;
98 }
99
100 let space = 128 - self.buf_len;
101 let chunk = if len < space { len } else { space };
102
103 self.buf[self.buf_len..self.buf_len + chunk]
104 .copy_from_slice(&data[offset..offset + chunk]);
105
106 self.buf_len += chunk;
107 offset += chunk;
108 len -= chunk;
109 }
110 }
111
112 pub fn finalize(mut self) -> Vec<u8> {
114 self.t[0] = self.t[0].wrapping_add(self.buf_len as u64);
115 if self.t[0] < self.buf_len as u64 {
116 self.t[1] = self.t[1].wrapping_add(1);
117 }
118
119 self.f[0] = !0; for i in self.buf_len..128 {
123 self.buf[i] = 0;
124 }
125
126 self.compress();
127
128 let mut out = Vec::with_capacity(self.out_len);
129 for i in 0..8 {
130 let bytes = self.h[i].to_le_bytes();
131 out.extend_from_slice(&bytes);
132 }
133
134 out.truncate(self.out_len);
135 out
136 }
137
138 fn compress(&mut self) {
139 let mut v = [0u64; 16];
140 let mut m = [0u64; 16];
141
142 for i in 0..16 {
144 m[i] = u64::from_le_bytes(self.buf[i * 8..(i + 1) * 8].try_into().unwrap());
145 }
146
147 v[0..8].copy_from_slice(&self.h);
149 v[8..16].copy_from_slice(&IV);
150
151 v[12] ^= self.t[0];
152 v[13] ^= self.t[1];
153 v[14] ^= self.f[0];
154 v[15] ^= self.f[1];
155
156 for i in 0..12 {
158 mix(&mut v, 0, 4, 8, 12, m[SIGMA[i][0]], m[SIGMA[i][1]]);
160 mix(&mut v, 1, 5, 9, 13, m[SIGMA[i][2]], m[SIGMA[i][3]]);
161 mix(&mut v, 2, 6, 10, 14, m[SIGMA[i][4]], m[SIGMA[i][5]]);
162 mix(&mut v, 3, 7, 11, 15, m[SIGMA[i][6]], m[SIGMA[i][7]]);
163
164 mix(&mut v, 0, 5, 10, 15, m[SIGMA[i][8]], m[SIGMA[i][9]]);
166 mix(&mut v, 1, 6, 11, 12, m[SIGMA[i][10]], m[SIGMA[i][11]]);
167 mix(&mut v, 2, 7, 8, 13, m[SIGMA[i][12]], m[SIGMA[i][13]]);
168 mix(&mut v, 3, 4, 9, 14, m[SIGMA[i][14]], m[SIGMA[i][15]]);
169 }
170
171 for i in 0..8 {
173 self.h[i] ^= v[i] ^ v[i + 8];
174 }
175 }
176}
177
178#[inline(always)]
179fn mix(v: &mut [u64; 16], a: usize, b: usize, c: usize, d: usize, x: u64, y: u64) {
180 v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
181 v[d] = (v[d] ^ v[a]).rotate_right(32);
182 v[c] = v[c].wrapping_add(v[d]);
183 v[b] = (v[b] ^ v[c]).rotate_right(24);
184
185 v[a] = v[a].wrapping_add(v[b]).wrapping_add(y);
186 v[d] = (v[d] ^ v[a]).rotate_right(16);
187 v[c] = v[c].wrapping_add(v[d]);
188 v[b] = (v[b] ^ v[c]).rotate_right(63);
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194
195 #[test]
196 fn test_blake2b_empty() {
197 let mut hasher = Blake2b::new(64);
198 hasher.update(b"");
199 let hash = hasher.finalize();
200
201 let expected = hex::decode("786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce").unwrap();
202 assert_eq!(hash, expected);
203 }
204
205 #[test]
206 fn test_blake2b_hello() {
207 let mut hasher = Blake2b::new(64);
208 hasher.update(b"Hello, world!");
209 let hash = hasher.finalize();
210
211 let expected = hex::decode("a2764d133a16816b5847a737a786f2ece4c148095c5faa73e24b4cc5d666c3e45ec271504e14dc6127ddfce4e144fb23b91a6f7b04b53d695502290722953b0f").unwrap();
213 assert_eq!(hash, expected);
214 }
215
216 #[test]
217 fn test_blake2b_keyed() {
218 let key = b"secret key";
219 let mut hasher = Blake2b::new_keyed(64, key);
220 hasher.update(b"Hello, world!");
221 let hash = hasher.finalize();
222
223 let mut unkeyed = Blake2b::new(64);
226 unkeyed.update(b"Hello, world!");
227 assert_ne!(hash, unkeyed.finalize());
228 }
229}