1pub fn buffer_size(n: usize) -> usize {
15 (n + 9).next_multiple_of(64)
16}
17
18#[inline]
19pub fn hash(buffer: &mut [u8], size: usize) -> [u32; 4] {
20 let end = buffer.len() - 8;
21 let bits = size * 8;
22
23 buffer[size] = 0x80;
24 buffer[end..].copy_from_slice(&bits.to_le_bytes());
25
26 let mut m = [0; 16];
27 let [mut a0, mut b0, mut c0, mut d0] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476];
28
29 for block in buffer.chunks_exact(64) {
30 for (i, chunk) in block.chunks_exact(4).enumerate() {
31 m[i] = u32::from_le_bytes(chunk.try_into().unwrap());
32 }
33
34 let [mut a, mut b, mut c, mut d] = [a0, b0, c0, d0];
35
36 a = round1(a, b, c, d, m[0], 7, 0xd76aa478);
37 d = round1(d, a, b, c, m[1], 12, 0xe8c7b756);
38 c = round1(c, d, a, b, m[2], 17, 0x242070db);
39 b = round1(b, c, d, a, m[3], 22, 0xc1bdceee);
40 a = round1(a, b, c, d, m[4], 7, 0xf57c0faf);
41 d = round1(d, a, b, c, m[5], 12, 0x4787c62a);
42 c = round1(c, d, a, b, m[6], 17, 0xa8304613);
43 b = round1(b, c, d, a, m[7], 22, 0xfd469501);
44 a = round1(a, b, c, d, m[8], 7, 0x698098d8);
45 d = round1(d, a, b, c, m[9], 12, 0x8b44f7af);
46 c = round1(c, d, a, b, m[10], 17, 0xffff5bb1);
47 b = round1(b, c, d, a, m[11], 22, 0x895cd7be);
48 a = round1(a, b, c, d, m[12], 7, 0x6b901122);
49 d = round1(d, a, b, c, m[13], 12, 0xfd987193);
50 c = round1(c, d, a, b, m[14], 17, 0xa679438e);
51 b = round1(b, c, d, a, m[15], 22, 0x49b40821);
52
53 a = round2(a, b, c, d, m[1], 5, 0xf61e2562);
54 d = round2(d, a, b, c, m[6], 9, 0xc040b340);
55 c = round2(c, d, a, b, m[11], 14, 0x265e5a51);
56 b = round2(b, c, d, a, m[0], 20, 0xe9b6c7aa);
57 a = round2(a, b, c, d, m[5], 5, 0xd62f105d);
58 d = round2(d, a, b, c, m[10], 9, 0x02441453);
59 c = round2(c, d, a, b, m[15], 14, 0xd8a1e681);
60 b = round2(b, c, d, a, m[4], 20, 0xe7d3fbc8);
61 a = round2(a, b, c, d, m[9], 5, 0x21e1cde6);
62 d = round2(d, a, b, c, m[14], 9, 0xc33707d6);
63 c = round2(c, d, a, b, m[3], 14, 0xf4d50d87);
64 b = round2(b, c, d, a, m[8], 20, 0x455a14ed);
65 a = round2(a, b, c, d, m[13], 5, 0xa9e3e905);
66 d = round2(d, a, b, c, m[2], 9, 0xfcefa3f8);
67 c = round2(c, d, a, b, m[7], 14, 0x676f02d9);
68 b = round2(b, c, d, a, m[12], 20, 0x8d2a4c8a);
69
70 a = round3(a, b, c, d, m[5], 4, 0xfffa3942);
71 d = round3(d, a, b, c, m[8], 11, 0x8771f681);
72 c = round3(c, d, a, b, m[11], 16, 0x6d9d6122);
73 b = round3(b, c, d, a, m[14], 23, 0xfde5380c);
74 a = round3(a, b, c, d, m[1], 4, 0xa4beea44);
75 d = round3(d, a, b, c, m[4], 11, 0x4bdecfa9);
76 c = round3(c, d, a, b, m[7], 16, 0xf6bb4b60);
77 b = round3(b, c, d, a, m[10], 23, 0xbebfbc70);
78 a = round3(a, b, c, d, m[13], 4, 0x289b7ec6);
79 d = round3(d, a, b, c, m[0], 11, 0xeaa127fa);
80 c = round3(c, d, a, b, m[3], 16, 0xd4ef3085);
81 b = round3(b, c, d, a, m[6], 23, 0x04881d05);
82 a = round3(a, b, c, d, m[9], 4, 0xd9d4d039);
83 d = round3(d, a, b, c, m[12], 11, 0xe6db99e5);
84 c = round3(c, d, a, b, m[15], 16, 0x1fa27cf8);
85 b = round3(b, c, d, a, m[2], 23, 0xc4ac5665);
86
87 a = round4(a, b, c, d, m[0], 6, 0xf4292244);
88 d = round4(d, a, b, c, m[7], 10, 0x432aff97);
89 c = round4(c, d, a, b, m[14], 15, 0xab9423a7);
90 b = round4(b, c, d, a, m[5], 21, 0xfc93a039);
91 a = round4(a, b, c, d, m[12], 6, 0x655b59c3);
92 d = round4(d, a, b, c, m[3], 10, 0x8f0ccc92);
93 c = round4(c, d, a, b, m[10], 15, 0xffeff47d);
94 b = round4(b, c, d, a, m[1], 21, 0x85845dd1);
95 a = round4(a, b, c, d, m[8], 6, 0x6fa87e4f);
96 d = round4(d, a, b, c, m[15], 10, 0xfe2ce6e0);
97 c = round4(c, d, a, b, m[6], 15, 0xa3014314);
98 b = round4(b, c, d, a, m[13], 21, 0x4e0811a1);
99 a = round4(a, b, c, d, m[4], 6, 0xf7537e82);
100 d = round4(d, a, b, c, m[11], 10, 0xbd3af235);
101 c = round4(c, d, a, b, m[2], 15, 0x2ad7d2bb);
102 b = round4(b, c, d, a, m[9], 21, 0xeb86d391);
103
104 [a0, b0, c0, d0] =
105 [a0.wrapping_add(a), b0.wrapping_add(b), c0.wrapping_add(c), d0.wrapping_add(d)];
106 }
107
108 [a0.to_be(), b0.to_be(), c0.to_be(), d0.to_be()]
109}
110
111#[inline]
112fn round1(a: u32, b: u32, c: u32, d: u32, m: u32, s: u32, k: u32) -> u32 {
113 let f = (b & c) | (!b & d);
114 common(f, a, b, m, s, k)
115}
116
117#[inline]
118fn round2(a: u32, b: u32, c: u32, d: u32, m: u32, s: u32, k: u32) -> u32 {
119 let f = (b & d) | (c & !d);
120 common(f, a, b, m, s, k)
121}
122
123#[inline]
124fn round3(a: u32, b: u32, c: u32, d: u32, m: u32, s: u32, k: u32) -> u32 {
125 let f = b ^ c ^ d;
126 common(f, a, b, m, s, k)
127}
128
129#[inline]
130fn round4(a: u32, b: u32, c: u32, d: u32, m: u32, s: u32, k: u32) -> u32 {
131 let f = c ^ (b | !d);
132 common(f, a, b, m, s, k)
133}
134
135#[inline]
136fn common(f: u32, a: u32, b: u32, m: u32, s: u32, k: u32) -> u32 {
137 f.wrapping_add(a).wrapping_add(k).wrapping_add(m).rotate_left(s).wrapping_add(b)
138}
139
140#[cfg(feature = "simd")]
141pub mod simd {
142 use std::array::from_fn;
143 use std::simd::prelude::*;
144
145 #[inline]
146 pub fn hash_fixed<const N: usize>(
147 buffers: &mut [[u8; 64]; N],
148 size: usize,
149 ) -> [Simd<u32, N>; 4] {
150 for buffer in buffers.iter_mut() {
152 buffer[size] = 0x80;
153 }
154
155 let [a0, b0, c0, d0] = [
156 Simd::splat(0x67452301),
157 Simd::splat(0xefcdab89),
158 Simd::splat(0x98badcfe),
159 Simd::splat(0x10325476),
160 ];
161 let [mut a, mut b, mut c, mut d] = [a0, b0, c0, d0];
162
163 let m0 = message(buffers, 0, size);
164 a = round1(a, b, c, d, m0, 7, 0xd76aa478);
165 let m1 = message(buffers, 4, size);
166 d = round1(d, a, b, c, m1, 12, 0xe8c7b756);
167 let m2 = message(buffers, 8, size);
168 c = round1(c, d, a, b, m2, 17, 0x242070db);
169 let m3 = message(buffers, 12, size);
170 b = round1(b, c, d, a, m3, 22, 0xc1bdceee);
171 let m4 = message(buffers, 16, size);
172 a = round1(a, b, c, d, m4, 7, 0xf57c0faf);
173 let m5 = message(buffers, 20, size);
174 d = round1(d, a, b, c, m5, 12, 0x4787c62a);
175 let m6 = message(buffers, 24, size);
176 c = round1(c, d, a, b, m6, 17, 0xa8304613);
177 let m7 = message(buffers, 28, size);
178 b = round1(b, c, d, a, m7, 22, 0xfd469501);
179 let m8 = message(buffers, 32, size);
180 a = round1(a, b, c, d, m8, 7, 0x698098d8);
181 let m9 = message(buffers, 36, size);
182 d = round1(d, a, b, c, m9, 12, 0x8b44f7af);
183 let m10 = message(buffers, 40, size);
184 c = round1(c, d, a, b, m10, 17, 0xffff5bb1);
185 let m11 = message(buffers, 44, size);
186 b = round1(b, c, d, a, m11, 22, 0x895cd7be);
187 let m12 = message(buffers, 48, size);
188 a = round1(a, b, c, d, m12, 7, 0x6b901122);
189 let m13 = message(buffers, 52, size);
190 d = round1(d, a, b, c, m13, 12, 0xfd987193);
191 let m14 = Simd::splat(size as u32 * 8);
192 c = round1(c, d, a, b, m14, 17, 0xa679438e);
193 let m15 = Simd::splat(0);
194 b = round1(b, c, d, a, m15, 22, 0x49b40821);
195
196 a = round2(a, b, c, d, m1, 5, 0xf61e2562);
197 d = round2(d, a, b, c, m6, 9, 0xc040b340);
198 c = round2(c, d, a, b, m11, 14, 0x265e5a51);
199 b = round2(b, c, d, a, m0, 20, 0xe9b6c7aa);
200 a = round2(a, b, c, d, m5, 5, 0xd62f105d);
201 d = round2(d, a, b, c, m10, 9, 0x02441453);
202 c = round2(c, d, a, b, m15, 14, 0xd8a1e681);
203 b = round2(b, c, d, a, m4, 20, 0xe7d3fbc8);
204 a = round2(a, b, c, d, m9, 5, 0x21e1cde6);
205 d = round2(d, a, b, c, m14, 9, 0xc33707d6);
206 c = round2(c, d, a, b, m3, 14, 0xf4d50d87);
207 b = round2(b, c, d, a, m8, 20, 0x455a14ed);
208 a = round2(a, b, c, d, m13, 5, 0xa9e3e905);
209 d = round2(d, a, b, c, m2, 9, 0xfcefa3f8);
210 c = round2(c, d, a, b, m7, 14, 0x676f02d9);
211 b = round2(b, c, d, a, m12, 20, 0x8d2a4c8a);
212
213 a = round3(a, b, c, d, m5, 4, 0xfffa3942);
214 d = round3(d, a, b, c, m8, 11, 0x8771f681);
215 c = round3(c, d, a, b, m11, 16, 0x6d9d6122);
216 b = round3(b, c, d, a, m14, 23, 0xfde5380c);
217 a = round3(a, b, c, d, m1, 4, 0xa4beea44);
218 d = round3(d, a, b, c, m4, 11, 0x4bdecfa9);
219 c = round3(c, d, a, b, m7, 16, 0xf6bb4b60);
220 b = round3(b, c, d, a, m10, 23, 0xbebfbc70);
221 a = round3(a, b, c, d, m13, 4, 0x289b7ec6);
222 d = round3(d, a, b, c, m0, 11, 0xeaa127fa);
223 c = round3(c, d, a, b, m3, 16, 0xd4ef3085);
224 b = round3(b, c, d, a, m6, 23, 0x04881d05);
225 a = round3(a, b, c, d, m9, 4, 0xd9d4d039);
226 d = round3(d, a, b, c, m12, 11, 0xe6db99e5);
227 c = round3(c, d, a, b, m15, 16, 0x1fa27cf8);
228 b = round3(b, c, d, a, m2, 23, 0xc4ac5665);
229
230 a = round4(a, b, c, d, m0, 6, 0xf4292244);
231 d = round4(d, a, b, c, m7, 10, 0x432aff97);
232 c = round4(c, d, a, b, m14, 15, 0xab9423a7);
233 b = round4(b, c, d, a, m5, 21, 0xfc93a039);
234 a = round4(a, b, c, d, m12, 6, 0x655b59c3);
235 d = round4(d, a, b, c, m3, 10, 0x8f0ccc92);
236 c = round4(c, d, a, b, m10, 15, 0xffeff47d);
237 b = round4(b, c, d, a, m1, 21, 0x85845dd1);
238 a = round4(a, b, c, d, m8, 6, 0x6fa87e4f);
239 d = round4(d, a, b, c, m15, 10, 0xfe2ce6e0);
240 c = round4(c, d, a, b, m6, 15, 0xa3014314);
241 b = round4(b, c, d, a, m13, 21, 0x4e0811a1);
242 a = round4(a, b, c, d, m4, 6, 0xf7537e82);
243 d = round4(d, a, b, c, m11, 10, 0xbd3af235);
244 c = round4(c, d, a, b, m2, 15, 0x2ad7d2bb);
245 b = round4(b, c, d, a, m9, 21, 0xeb86d391);
246
247 [(a0 + a).swap_bytes(), (b0 + b).swap_bytes(), (c0 + c).swap_bytes(), (d0 + d).swap_bytes()]
248 }
249
250 #[inline]
251 fn message<const N: usize>(buffers: &[[u8; 64]; N], i: usize, size: usize) -> Simd<u32, N> {
252 if i > size {
253 Simd::splat(0)
254 } else {
255 Simd::from_array(from_fn(|lane| {
256 let slice = &buffers[lane][i..i + 4];
257 u32::from_le_bytes(slice.try_into().unwrap())
258 }))
259 }
260 }
261
262 #[inline]
263 fn round1<const N: usize>(
264 a: Simd<u32, N>,
265 b: Simd<u32, N>,
266 c: Simd<u32, N>,
267 d: Simd<u32, N>,
268 m: Simd<u32, N>,
269 s: u32,
270 k: u32,
271 ) -> Simd<u32, N> {
272 let f = (b & c) | (!b & d);
273 common(f, a, b, m, s, k)
274 }
275
276 #[inline]
277 fn round2<const N: usize>(
278 a: Simd<u32, N>,
279 b: Simd<u32, N>,
280 c: Simd<u32, N>,
281 d: Simd<u32, N>,
282 m: Simd<u32, N>,
283 s: u32,
284 k: u32,
285 ) -> Simd<u32, N> {
286 let f = (b & d) | (c & !d);
287 common(f, a, b, m, s, k)
288 }
289
290 #[inline]
291 fn round3<const N: usize>(
292 a: Simd<u32, N>,
293 b: Simd<u32, N>,
294 c: Simd<u32, N>,
295 d: Simd<u32, N>,
296 m: Simd<u32, N>,
297 s: u32,
298 k: u32,
299 ) -> Simd<u32, N> {
300 let f = b ^ c ^ d;
301 common(f, a, b, m, s, k)
302 }
303
304 #[inline]
305 fn round4<const N: usize>(
306 a: Simd<u32, N>,
307 b: Simd<u32, N>,
308 c: Simd<u32, N>,
309 d: Simd<u32, N>,
310 m: Simd<u32, N>,
311 s: u32,
312 k: u32,
313 ) -> Simd<u32, N> {
314 let f = c ^ (b | !d);
315 common(f, a, b, m, s, k)
316 }
317
318 #[inline]
319 fn common<const N: usize>(
320 f: Simd<u32, N>,
321 a: Simd<u32, N>,
322 b: Simd<u32, N>,
323 m: Simd<u32, N>,
324 s: u32,
325 k: u32,
326 ) -> Simd<u32, N> {
327 let k = Simd::splat(k);
328 let first = f + a + k + m;
329 let second = (first << s) | (first >> (32 - s));
330 second + b
331 }
332}