1const SIGMA: [[usize; 16]; 10] = [
21 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
22 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
23 [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
24 [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
25 [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
26 [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
27 [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
28 [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
29 [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
30 [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
31];
32
33const IV: [u64; 8] = [
36 0x6a09e667f3bcc908,
37 0xbb67ae8584caa73b,
38 0x3c6ef372fe94f82b,
39 0xa54ff53a5f1d36f1,
40 0x510e527fade682d1,
41 0x9b05688c2b3e6c1f,
42 0x1f83d9abfb41bd6b,
43 0x5be0cd19137e2179,
44];
45
46#[inline(always)]
47fn g(v: &mut [u64], a: usize, b: usize, c: usize, d: usize, x: u64, y: u64) {
49 v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
50 v[d] = (v[d] ^ v[a]).rotate_right(32);
51 v[c] = v[c].wrapping_add(v[d]);
52 v[b] = (v[b] ^ v[c]).rotate_right(24);
53 v[a] = v[a].wrapping_add(v[b]).wrapping_add(y);
54 v[d] = (v[d] ^ v[a]).rotate_right(16);
55 v[c] = v[c].wrapping_add(v[d]);
56 v[b] = (v[b] ^ v[c]).rotate_right(63);
57}
58
59pub fn compress(
65 h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool, rounds: usize,
66) {
67 let mut v = [0u64; 16];
68 v[..h.len()].copy_from_slice(h); v[h.len()..].copy_from_slice(&IV); v[12] ^= t[0];
72 v[13] ^= t[1];
73
74 if f {
75 v[14] = !v[14] }
77 for i in 0..rounds {
78 let s = &SIGMA[i % 10];
80 g(&mut v, 0, 4, 8, 12, m[s[0]], m[s[1]]);
81 g(&mut v, 1, 5, 9, 13, m[s[2]], m[s[3]]);
82 g(&mut v, 2, 6, 10, 14, m[s[4]], m[s[5]]);
83 g(&mut v, 3, 7, 11, 15, m[s[6]], m[s[7]]);
84
85 g(&mut v, 0, 5, 10, 15, m[s[8]], m[s[9]]);
86 g(&mut v, 1, 6, 11, 12, m[s[10]], m[s[11]]);
87 g(&mut v, 2, 7, 8, 13, m[s[12]], m[s[13]]);
88 g(&mut v, 3, 4, 9, 14, m[s[14]], m[s[15]]);
89 }
90
91 for i in 0..8 {
92 h[i] ^= v[i] ^ v[i + 8];
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::compress;
99 use rustc_hex::FromHex;
100
101 #[test]
102 fn test_blake2_f() {
103 let mut h_in = [
105 0x6a09e667f2bdc948_u64,
106 0xbb67ae8584caa73b_u64,
107 0x3c6ef372fe94f82b_u64,
108 0xa54ff53a5f1d36f1_u64,
109 0x510e527fade682d1_u64,
110 0x9b05688c2b3e6c1f_u64,
111 0x1f83d9abfb41bd6b_u64,
112 0x5be0cd19137e2179_u64,
113 ];
114
115 let m = [
116 0x0000000000636261_u64,
117 0x0000000000000000_u64,
118 0x0000000000000000_u64,
119 0x0000000000000000_u64,
120 0x0000000000000000_u64,
121 0x0000000000000000_u64,
122 0x0000000000000000_u64,
123 0x0000000000000000_u64,
124 0x0000000000000000_u64,
125 0x0000000000000000_u64,
126 0x0000000000000000_u64,
127 0x0000000000000000_u64,
128 0x0000000000000000_u64,
129 0x0000000000000000_u64,
130 0x0000000000000000_u64,
131 0x0000000000000000_u64,
132 ];
133 let c = [3, 0];
134 let f = true;
135 let rounds = 12;
136 let h_out: [u64; 8] = [
137 0x0D4D1C983FA580BA_u64,
138 0xE9F6129FB697276A_u64,
139 0xB7C45A68142F214C_u64,
140 0xD1A2FFDB6FBB124B_u64,
141 0x2D79AB2A39C5877D_u64,
142 0x95CC3345DED552C2_u64,
143 0x5A92F1DBA88AD318_u64,
144 0x239900D4ED8623B9_u64,
145 ];
146
147 compress(&mut h_in, m, c, f, rounds);
148
149 assert_eq!(h_in, h_out);
150 }
151
152 fn to_u64_slice(vec: &[u8], slice: &mut [u64]) {
153 vec.chunks(8).enumerate().for_each(|(index, val)| {
154 slice[index] = u64::from_le_bytes([
155 val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7],
156 ])
157 })
158 }
159
160 #[test]
161 fn test_vectors_from_eip() {
162 let vec = vec![
163 (
164 "0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
166 "08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b",
167 ),
168 ( "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
170 "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923",
171 ),
172 (
173 "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000",
175 "75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735",
176 ),
177 (
178 "0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
180 "b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421",
181 ),
182 ];
188 for (hex, output) in vec {
189 let hex = hex;
190 let bytes: Vec<u8> = hex.from_hex().unwrap();
191
192 assert_eq!(bytes.len(), 213);
193
194 let mut h = [0u64; 8];
195 let mut m = [0u64; 16];
196 let mut t = [0u64; 2];
197
198 let rounds =
199 u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
200 let f = match bytes[212] {
201 1 => true,
202 0 => false,
203 _ => unreachable!(),
204 };
205
206 to_u64_slice(&bytes[4..68], &mut h);
207 to_u64_slice(&bytes[68..196], &mut m);
208 to_u64_slice(&bytes[196..212], &mut t);
209
210 compress(&mut h, m, t, f, rounds as usize);
211
212 let output: Vec<u8> = output.from_hex().unwrap();
213
214 let mut out = [0u64; 8];
215 to_u64_slice(&output[..], &mut out);
216
217 assert_eq!(out, h);
218 }
219 }
220}