1#![allow(clippy::integer_division_remainder_used)]
6
7use crate::buf::ArrayBuf;
8use crate::buf::FixedU8Buf;
9use crate::hash::HashAlgorithm;
10use crate::hash::HashDigest;
11use core::ops::{BitXorAssign, Not};
12use irox_bits::WriteToLEBits;
13
14macro_rules! g {
15 (
16 $a:expr,
17 $b:expr,
18 $c:expr,
19 $d:expr,
20 $x:expr,
21 $y:expr,
22 $r:expr
23 ) => {
24 *$a = ($a.wrapping_add(*$b).wrapping_add($x));
25 *$d ^= *$a;
26 *$d = ($d.rotate_right($r[0]));
27 *$c = ($c.wrapping_add(*$d));
28 *$b ^= *$c;
29 *$b = ($b.rotate_right($r[1]));
30 *$a = ($a.wrapping_add(*$b).wrapping_add($y));
31 *$d ^= *$a;
32 *$d = ($d.rotate_right($r[2]));
33 *$c = ($c.wrapping_add(*$d));
34 *$b ^= *$c;
35 *$b = ($b.rotate_right($r[3]));
36 };
37}
38static BLAKE2B_R: &[u32; 4] = &[32, 24, 16, 63];
39static BLAKE2S_R: &[u32; 4] = &[16, 12, 8, 7];
40static BLAKE2B_IV: &[u64; 8] = &[
41 0x6A09E667F3BCC908,
42 0xBB67AE8584CAA73B,
43 0x3C6EF372FE94F82B,
44 0xA54FF53A5F1D36F1,
45 0x510E527FADE682D1,
46 0x9B05688C2B3E6C1F,
47 0x1F83D9ABFB41BD6B,
48 0x5BE0CD19137E2179,
49];
50static BLAKE2S_IV: &[u32; 8] = &[
51 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
52];
53static SIGMA: &[&[usize; 16]; 12] = &[
54 &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
55 &[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
56 &[11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
57 &[7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
58 &[9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
59 &[2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
60 &[12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
61 &[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
62 &[6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
63 &[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
64 &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
65 &[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
66];
67
68macro_rules! impl_blake2 {
69 ($name:ident,$prim:ty,$nprim:ty,$nb:literal,$bb:literal,$w:literal, $r:literal, $iv:ident, $RND:ident) => {
70 #[derive(Clone)]
71 pub struct $name<const NN: usize> {
72 h: [$prim; 8],
73 written: $nprim,
74 buf: ArrayBuf<16, $nb, $prim>,
75 }
76 impl<const NN: usize> Default for $name<NN> {
77 fn default() -> Self {
78 Self::new(&[])
79 }
80 }
81 impl<const NN: usize> $name<NN> {
82 pub fn new(key: &[u8]) -> Self {
83 let mut out = Self {
84 h: *$iv,
85 written: 0,
86 buf: Default::default(),
87 };
88 let nn = (NN as $prim) & 0xFF;
89 let kk = ((key.len() as $prim) & 0xFF) << 8;
90 let p = (0x01010000 as $prim) | nn | kk;
91 out.h[0].bitxor_assign(p);
92 if kk > 0 {
93 let mut key = FixedU8Buf::<$bb>::from_slice(key);
94 out.write(key.as_mut_full());
95 }
96
97 out
98 }
99
100 fn chomp(&mut self, last: bool) {
101 if self.buf.is_empty() && self.written > 0 && !last {
102 return;
103 }
104 let m = self.buf.take_le_buf();
105
106 let counter = self.written; let mut v: [$prim; 16] = [0; 16];
108 (v[0..8]).copy_from_slice(&self.h);
109 (v[8..]).copy_from_slice($iv);
110 v[12].bitxor_assign(counter as $prim);
114 v[13].bitxor_assign((counter >> $w) as $prim);
115 if last {
116 v[14] = v[14].not();
117 }
118 for i in 0..$r {
119 let s = SIGMA[i % 10];
120 g!(&mut v[0], &mut v[4], &mut v[8], &mut v[12], m[s[0]], m[s[1]], $RND);
121 g!(&mut v[1], &mut v[5], &mut v[9], &mut v[13], m[s[2]], m[s[3]], $RND);
122 g!(&mut v[2], &mut v[6], &mut v[10], &mut v[14], m[s[4]], m[s[5]], $RND);
123 g!(&mut v[3], &mut v[7], &mut v[11], &mut v[15], m[s[6]], m[s[7]], $RND);
124
125 g!(&mut v[0], &mut v[5], &mut v[10], &mut v[15], m[s[8]], m[s[9]], $RND);
126 g!(&mut v[1], &mut v[6], &mut v[11], &mut v[12], m[s[10]], m[s[11]], $RND);
127 g!(&mut v[2], &mut v[7], &mut v[8], &mut v[13], m[s[12]], m[s[13]], $RND);
128 g!(&mut v[3], &mut v[4], &mut v[9], &mut v[14], m[s[14]], m[s[15]], $RND);
129 }
130 for i in 0..8 {
131 self.h[i].bitxor_assign(v[i]);
132 self.h[i].bitxor_assign(v[i + 8]);
133 }
134 }
135 pub fn write(&mut self, mut v: &[u8]) {
136 let align = self.buf.rem_align();
137 if align < 4 && align < v.len() {
138 let (a, b) = v.split_at(self.buf.rem_align());
139 v = b;
140 for val in a {
141 if self.buf.is_full() {
142 self.chomp(false);
143 }
144 let _ = self.buf.write_le_u8(*val);
145 self.written += 1;
146 }
147 }
148
149 let mut chunks = v.chunks_exact($nb);
150 for c in chunks.by_ref() {
151 if self.buf.is_full() {
152 self.chomp(false);
153 }
154 let _ = self
155 .buf
156 .push_prim(<$prim>::from_le_bytes(c.try_into().unwrap_or_default()));
157 self.written += $nb;
158 }
159 for val in chunks.remainder() {
160 if self.buf.is_full() {
161 self.chomp(false);
162 }
163 let _ = self.buf.write_le_u8(*val);
164 self.written += 1;
165 }
166 }
167 pub fn hash(mut self, v: &[u8]) -> [u8; NN] {
168 self.write(v);
169 self.finish()
170 }
171 pub fn finish(mut self) -> [u8; NN] {
172 self.chomp(true);
173
174 let mut out: FixedU8Buf<NN> = FixedU8Buf::default();
176 for v in self.h {
177 let _ = v.write_le_to(&mut out);
178 }
179 out.take()
181 }
182 }
183 impl<const NN: usize> HashDigest<$bb, NN> for $name<NN> {
184 fn finish(self) -> [u8; NN] {
185 Self::finish(self)
186 }
187 fn hash(self, v: &[u8]) -> [u8; NN] {
188 Self::hash(self, v)
189 }
190 fn write(&mut self, v: &[u8]) {
191 Self::write(self, v)
192 }
193 fn algorithm() -> HashAlgorithm {
194 todo!()
195 }
196 }
197 };
198}
199
200impl_blake2!(BLAKE2s, u32, u64, 4, 64, 32, 10, BLAKE2S_IV, BLAKE2S_R);
201impl_blake2!(BLAKE2b, u64, u128, 8, 128, 64, 12, BLAKE2B_IV, BLAKE2B_R);
202pub type BLAKE2s128 = BLAKE2s<16>;
203pub type BLAKE2s160 = BLAKE2s<20>;
204pub type BLAKE2s224 = BLAKE2s<28>;
205pub type BLAKE2s256 = BLAKE2s<32>;
206pub type BLAKE2b160 = BLAKE2b<20>;
207pub type BLAKE2b224 = BLAKE2b<28>;
208pub type BLAKE2b256 = BLAKE2b<32>;
209pub type BLAKE2b384 = BLAKE2b<48>;
210pub type BLAKE2b512 = BLAKE2b<64>;
211
212#[cfg(test)]
213mod tests {
214 use crate::hash::{BLAKE2b384, BLAKE2b512, BLAKE2s224, BLAKE2s256};
215 use crate::hex;
216
217 #[test]
218 pub fn test0() {
219 let h = BLAKE2s224::default().hash(b"");
220 let exp = hex!("1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4");
221 assert_eq_hex_slice!(exp, h);
222 let h = BLAKE2s256::default().hash(b"");
223 let exp = hex!("69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9");
224 assert_eq_hex_slice!(exp, h);
225 let h = BLAKE2b384::default().hash(b"");
226 let exp = hex!("b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100");
227 assert_eq_hex_slice!(exp, h);
228 let h = BLAKE2b512::default().hash(b"");
229 let exp = hex!("786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce");
230 assert_eq_hex_slice!(exp, h);
231 }
232 #[test]
233 pub fn test_qbf() {
234 let h = BLAKE2b512::default().hash(b"The quick brown fox jumps over the lazy dog");
235 let exp = hex!("a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918");
236 assert_eq_hex_slice!(exp, h);
237 let h = BLAKE2b512::default().hash(b"The quick brown fox jumps over the lazy dof");
238 let exp = hex!("ab6b007747d8068c02e25a6008db8a77c218d94f3b40d2291a7dc8a62090a744c082ea27af01521a102e42f480a31e9844053f456b4b41e8aa78bbe5c12957bb");
239 assert_eq_hex_slice!(exp, h);
240 }
241
242 #[test]
243 pub fn test_abc() {
244 let h = BLAKE2s256::default().hash(b"abc");
245 let exp = hex!("508C5E8C327C14E2E1A72BA34EEB452F37458B209ED63A294D999B4C86675982");
246 assert_eq_hex_slice!(exp, h);
247 let h = BLAKE2b512::default().hash(b"abc");
248 let exp = hex!("BA80A53F981C4D0D6A2797B69F12F6E94C212F14685AC4B74B12BB6FDBFFA2D17D87C5392AAB792DC252D5DE4533CC9518D38AA8DBF1925AB92386EDD4009923");
249 assert_eq_hex_slice!(exp, h);
250 }
251}