1pub fn md5(data: &[u8]) -> [u8; 16] {
16 const S: [u32; 64] = [
18 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9,
19 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15,
20 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
21 ];
22 const K: [u32; 64] = [
24 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
25 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
26 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
27 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
28 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
29 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
30 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
31 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
32 ];
33
34 let _ = S;
37
38 let mut state: [u32; 4] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476];
39
40 #[inline(always)]
41 fn compress(state: &mut [u32; 4], block: &[u8; 64]) {
42 let mut m = [0u32; 16];
43 for (i, w) in m.iter_mut().enumerate() {
44 *w = u32::from_le_bytes([block[4 * i], block[4 * i + 1], block[4 * i + 2], block[4 * i + 3]]);
45 }
46 let (mut a, mut b, mut c, mut d) = (state[0], state[1], state[2], state[3]);
47 macro_rules! ff { ($a:ident,$b:ident,$c:ident,$d:ident,$g:expr,$s:expr,$t:expr) => {
51 $a = $b.wrapping_add(($a.wrapping_add(($b & $c) | (!$b & $d)).wrapping_add(m[$g]).wrapping_add($t)).rotate_left($s));
52 }}
53 macro_rules! gg { ($a:ident,$b:ident,$c:ident,$d:ident,$g:expr,$s:expr,$t:expr) => {
54 $a = $b.wrapping_add(($a.wrapping_add(($b & $d) | ($c & !$d)).wrapping_add(m[$g]).wrapping_add($t)).rotate_left($s));
55 }}
56 macro_rules! hh { ($a:ident,$b:ident,$c:ident,$d:ident,$g:expr,$s:expr,$t:expr) => {
57 $a = $b.wrapping_add(($a.wrapping_add($b ^ $c ^ $d).wrapping_add(m[$g]).wrapping_add($t)).rotate_left($s));
58 }}
59 macro_rules! ii { ($a:ident,$b:ident,$c:ident,$d:ident,$g:expr,$s:expr,$t:expr) => {
60 $a = $b.wrapping_add(($a.wrapping_add($c ^ ($b | !$d)).wrapping_add(m[$g]).wrapping_add($t)).rotate_left($s));
61 }}
62 ff!(a, b, c, d, 0, 7, K[0]); ff!(d, a, b, c, 1, 12, K[1]); ff!(c, d, a, b, 2, 17, K[2]); ff!(b, c, d, a, 3, 22, K[3]);
64 ff!(a, b, c, d, 4, 7, K[4]); ff!(d, a, b, c, 5, 12, K[5]); ff!(c, d, a, b, 6, 17, K[6]); ff!(b, c, d, a, 7, 22, K[7]);
65 ff!(a, b, c, d, 8, 7, K[8]); ff!(d, a, b, c, 9, 12, K[9]); ff!(c, d, a, b, 10, 17, K[10]); ff!(b, c, d, a, 11, 22, K[11]);
66 ff!(a, b, c, d, 12, 7, K[12]); ff!(d, a, b, c, 13, 12, K[13]); ff!(c, d, a, b, 14, 17, K[14]); ff!(b, c, d, a, 15, 22, K[15]);
67 gg!(a, b, c, d, 1, 5, K[16]); gg!(d, a, b, c, 6, 9, K[17]); gg!(c, d, a, b, 11, 14, K[18]); gg!(b, c, d, a, 0, 20, K[19]);
69 gg!(a, b, c, d, 5, 5, K[20]); gg!(d, a, b, c, 10, 9, K[21]); gg!(c, d, a, b, 15, 14, K[22]); gg!(b, c, d, a, 4, 20, K[23]);
70 gg!(a, b, c, d, 9, 5, K[24]); gg!(d, a, b, c, 14, 9, K[25]); gg!(c, d, a, b, 3, 14, K[26]); gg!(b, c, d, a, 8, 20, K[27]);
71 gg!(a, b, c, d, 13, 5, K[28]); gg!(d, a, b, c, 2, 9, K[29]); gg!(c, d, a, b, 7, 14, K[30]); gg!(b, c, d, a, 12, 20, K[31]);
72 hh!(a, b, c, d, 5, 4, K[32]); hh!(d, a, b, c, 8, 11, K[33]); hh!(c, d, a, b, 11, 16, K[34]); hh!(b, c, d, a, 14, 23, K[35]);
74 hh!(a, b, c, d, 1, 4, K[36]); hh!(d, a, b, c, 4, 11, K[37]); hh!(c, d, a, b, 7, 16, K[38]); hh!(b, c, d, a, 10, 23, K[39]);
75 hh!(a, b, c, d, 13, 4, K[40]); hh!(d, a, b, c, 0, 11, K[41]); hh!(c, d, a, b, 3, 16, K[42]); hh!(b, c, d, a, 6, 23, K[43]);
76 hh!(a, b, c, d, 9, 4, K[44]); hh!(d, a, b, c, 12, 11, K[45]); hh!(c, d, a, b, 15, 16, K[46]); hh!(b, c, d, a, 2, 23, K[47]);
77 ii!(a, b, c, d, 0, 6, K[48]); ii!(d, a, b, c, 7, 10, K[49]); ii!(c, d, a, b, 14, 15, K[50]); ii!(b, c, d, a, 5, 21, K[51]);
79 ii!(a, b, c, d, 12, 6, K[52]); ii!(d, a, b, c, 3, 10, K[53]); ii!(c, d, a, b, 10, 15, K[54]); ii!(b, c, d, a, 1, 21, K[55]);
80 ii!(a, b, c, d, 8, 6, K[56]); ii!(d, a, b, c, 15, 10, K[57]); ii!(c, d, a, b, 6, 15, K[58]); ii!(b, c, d, a, 13, 21, K[59]);
81 ii!(a, b, c, d, 4, 6, K[60]); ii!(d, a, b, c, 11, 10, K[61]); ii!(c, d, a, b, 2, 15, K[62]); ii!(b, c, d, a, 9, 21, K[63]);
82 state[0] = state[0].wrapping_add(a);
83 state[1] = state[1].wrapping_add(b);
84 state[2] = state[2].wrapping_add(c);
85 state[3] = state[3].wrapping_add(d);
86 }
87
88 each_padded_block(data, Endian::Little, |block| compress(&mut state, block));
89
90 let mut out = [0u8; 16];
91 out[0..4].copy_from_slice(&state[0].to_le_bytes());
92 out[4..8].copy_from_slice(&state[1].to_le_bytes());
93 out[8..12].copy_from_slice(&state[2].to_le_bytes());
94 out[12..16].copy_from_slice(&state[3].to_le_bytes());
95 out
96}
97
98const MD5_K: [u32; 64] = [
100 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
101 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
102 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
103 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
104 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
105 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
106 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
107 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
108];
109const MD5_S: [u32; 64] = [
110 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14,
111 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6,
112 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
113];
114
115#[cfg(target_arch = "x86_64")]
120pub fn md5_x4(msgs: [&[u8]; 4]) -> [[u8; 16]; 4] {
121 let len = msgs[0].len();
122 assert!(msgs.iter().all(|m| m.len() == len), "md5_x4 requires equal-length inputs");
123 if std::is_x86_feature_detected!("sse2") {
124 unsafe { md5_x4_sse2(msgs, len) }
126 } else {
127 [md5(msgs[0]), md5(msgs[1]), md5(msgs[2]), md5(msgs[3])]
128 }
129}
130
131#[cfg(target_arch = "x86_64")]
132#[target_feature(enable = "sse2")]
133unsafe fn md5_x4_sse2(msgs: [&[u8]; 4], len: usize) -> [[u8; 16]; 4] {
134 let total = (len + 8) / 64 * 64 + 64;
138 let nb = total / 64;
139 let bitlen = (len as u64).wrapping_mul(8);
140 const CAP: usize = 256;
141 if total <= CAP {
142 let mut pad = [[0u8; CAP]; 4];
143 for (j, p) in pad.iter_mut().enumerate() {
144 p[..len].copy_from_slice(msgs[j]);
145 p[len] = 0x80;
146 p[total - 8..total].copy_from_slice(&bitlen.to_le_bytes());
147 }
148 md5_x4_run([&pad[0][..], &pad[1][..], &pad[2][..], &pad[3][..]], nb)
149 } else {
150 let mut pad = [vec![0u8; total], vec![0u8; total], vec![0u8; total], vec![0u8; total]];
151 for (j, p) in pad.iter_mut().enumerate() {
152 p[..len].copy_from_slice(msgs[j]);
153 p[len] = 0x80;
154 p[total - 8..].copy_from_slice(&bitlen.to_le_bytes());
155 }
156 md5_x4_run([&pad[0][..], &pad[1][..], &pad[2][..], &pad[3][..]], nb)
157 }
158}
159
160#[cfg(target_arch = "x86_64")]
163#[target_feature(enable = "sse2")]
164unsafe fn md5_x4_run(pad: [&[u8]; 4], nb: usize) -> [[u8; 16]; 4] {
165 use core::arch::x86_64::*;
166
167 let rotl = |x: __m128i, s: u32| -> __m128i {
168 _mm_or_si128(
169 _mm_sll_epi32(x, _mm_cvtsi32_si128(s as i32)),
170 _mm_srl_epi32(x, _mm_cvtsi32_si128((32 - s) as i32)),
171 )
172 };
173 let ones = _mm_set1_epi32(-1);
174
175 let mut sa = _mm_set1_epi32(0x67452301u32 as i32);
176 let mut sb = _mm_set1_epi32(0xefcdab89u32 as i32);
177 let mut sc = _mm_set1_epi32(0x98badcfeu32 as i32);
178 let mut sd = _mm_set1_epi32(0x10325476u32 as i32);
179
180 for bi in 0..nb {
181 let mut mw = [_mm_setzero_si128(); 16];
183 for (g, slot) in mw.iter_mut().enumerate() {
184 let o = bi * 64 + g * 4;
185 let w = |p: &[u8]| u32::from_le_bytes([p[o], p[o + 1], p[o + 2], p[o + 3]]) as i32;
186 *slot = _mm_setr_epi32(w(&pad[0]), w(&pad[1]), w(&pad[2]), w(&pad[3]));
187 }
188 let (mut a, mut b, mut c, mut d) = (sa, sb, sc, sd);
189 for i in 0..64 {
190 let (f, g) = match i / 16 {
191 0 => (_mm_or_si128(_mm_and_si128(b, c), _mm_andnot_si128(b, d)), i),
192 1 => (_mm_or_si128(_mm_and_si128(b, d), _mm_andnot_si128(d, c)), (5 * i + 1) % 16),
193 2 => (_mm_xor_si128(_mm_xor_si128(b, c), d), (3 * i + 5) % 16),
194 _ => (_mm_xor_si128(c, _mm_or_si128(b, _mm_xor_si128(d, ones))), (7 * i) % 16),
195 };
196 let t = _mm_add_epi32(
197 _mm_add_epi32(a, f),
198 _mm_add_epi32(mw[g], _mm_set1_epi32(MD5_K[i] as i32)),
199 );
200 a = d;
201 d = c;
202 c = b;
203 b = _mm_add_epi32(b, rotl(t, MD5_S[i]));
204 }
205 sa = _mm_add_epi32(sa, a);
206 sb = _mm_add_epi32(sb, b);
207 sc = _mm_add_epi32(sc, c);
208 sd = _mm_add_epi32(sd, d);
209 }
210
211 let mut a4 = [0u32; 4];
212 let mut b4 = [0u32; 4];
213 let mut c4 = [0u32; 4];
214 let mut d4 = [0u32; 4];
215 _mm_storeu_si128(a4.as_mut_ptr() as *mut __m128i, sa);
216 _mm_storeu_si128(b4.as_mut_ptr() as *mut __m128i, sb);
217 _mm_storeu_si128(c4.as_mut_ptr() as *mut __m128i, sc);
218 _mm_storeu_si128(d4.as_mut_ptr() as *mut __m128i, sd);
219 let mut out = [[0u8; 16]; 4];
220 for (j, o) in out.iter_mut().enumerate() {
221 o[0..4].copy_from_slice(&a4[j].to_le_bytes());
222 o[4..8].copy_from_slice(&b4[j].to_le_bytes());
223 o[8..12].copy_from_slice(&c4[j].to_le_bytes());
224 o[12..16].copy_from_slice(&d4[j].to_le_bytes());
225 }
226 out
227}
228
229#[cfg(target_arch = "x86_64")]
234pub fn md5_x8(msgs: [&[u8]; 8]) -> [[u8; 16]; 8] {
235 let len = msgs[0].len();
236 assert!(msgs.iter().all(|m| m.len() == len), "md5_x8 requires equal-length inputs");
237 if std::is_x86_feature_detected!("avx2") {
238 unsafe { md5_x8_avx2(msgs, len) }
240 } else {
241 let a = md5_x4([msgs[0], msgs[1], msgs[2], msgs[3]]);
242 let b = md5_x4([msgs[4], msgs[5], msgs[6], msgs[7]]);
243 [a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]]
244 }
245}
246
247#[cfg(target_arch = "x86_64")]
248#[target_feature(enable = "avx2")]
249unsafe fn md5_x8_avx2(msgs: [&[u8]; 8], len: usize) -> [[u8; 16]; 8] {
250 let total = (len + 8) / 64 * 64 + 64;
251 let nb = total / 64;
252 let bitlen = (len as u64).wrapping_mul(8);
253 const CAP: usize = 256;
254 if total <= CAP {
255 let mut pad = [[0u8; CAP]; 8];
256 for (j, p) in pad.iter_mut().enumerate() {
257 p[..len].copy_from_slice(msgs[j]);
258 p[len] = 0x80;
259 p[total - 8..total].copy_from_slice(&bitlen.to_le_bytes());
260 }
261 let s: [&[u8]; 8] =
262 [&pad[0], &pad[1], &pad[2], &pad[3], &pad[4], &pad[5], &pad[6], &pad[7]];
263 md5_x8_run(s, nb)
264 } else {
265 let mut pad: Vec<Vec<u8>> = (0..8).map(|_| vec![0u8; total]).collect();
266 for (j, p) in pad.iter_mut().enumerate() {
267 p[..len].copy_from_slice(msgs[j]);
268 p[len] = 0x80;
269 p[total - 8..].copy_from_slice(&bitlen.to_le_bytes());
270 }
271 let s: [&[u8]; 8] = [
272 &pad[0], &pad[1], &pad[2], &pad[3], &pad[4], &pad[5], &pad[6], &pad[7],
273 ];
274 md5_x8_run(s, nb)
275 }
276}
277
278#[cfg(target_arch = "x86_64")]
281#[target_feature(enable = "avx2")]
282unsafe fn transpose8x8(r: [core::arch::x86_64::__m256i; 8]) -> [core::arch::x86_64::__m256i; 8] {
283 use core::arch::x86_64::*;
284 let t0 = _mm256_unpacklo_epi32(r[0], r[1]);
285 let t1 = _mm256_unpackhi_epi32(r[0], r[1]);
286 let t2 = _mm256_unpacklo_epi32(r[2], r[3]);
287 let t3 = _mm256_unpackhi_epi32(r[2], r[3]);
288 let t4 = _mm256_unpacklo_epi32(r[4], r[5]);
289 let t5 = _mm256_unpackhi_epi32(r[4], r[5]);
290 let t6 = _mm256_unpacklo_epi32(r[6], r[7]);
291 let t7 = _mm256_unpackhi_epi32(r[6], r[7]);
292 let s0 = _mm256_unpacklo_epi64(t0, t2);
293 let s1 = _mm256_unpackhi_epi64(t0, t2);
294 let s2 = _mm256_unpacklo_epi64(t1, t3);
295 let s3 = _mm256_unpackhi_epi64(t1, t3);
296 let s4 = _mm256_unpacklo_epi64(t4, t6);
297 let s5 = _mm256_unpackhi_epi64(t4, t6);
298 let s6 = _mm256_unpacklo_epi64(t5, t7);
299 let s7 = _mm256_unpackhi_epi64(t5, t7);
300 [
301 _mm256_permute2x128_si256(s0, s4, 0x20),
302 _mm256_permute2x128_si256(s1, s5, 0x20),
303 _mm256_permute2x128_si256(s2, s6, 0x20),
304 _mm256_permute2x128_si256(s3, s7, 0x20),
305 _mm256_permute2x128_si256(s0, s4, 0x31),
306 _mm256_permute2x128_si256(s1, s5, 0x31),
307 _mm256_permute2x128_si256(s2, s6, 0x31),
308 _mm256_permute2x128_si256(s3, s7, 0x31),
309 ]
310}
311
312#[cfg(target_arch = "x86_64")]
314#[target_feature(enable = "avx2")]
315unsafe fn md5_x8_run(pad: [&[u8]; 8], nb: usize) -> [[u8; 16]; 8] {
316 use core::arch::x86_64::*;
317
318 let rotl = |x: __m256i, s: u32| -> __m256i {
319 _mm256_or_si256(
320 _mm256_sll_epi32(x, _mm_cvtsi32_si128(s as i32)),
321 _mm256_srl_epi32(x, _mm_cvtsi32_si128((32 - s) as i32)),
322 )
323 };
324 let ones = _mm256_set1_epi32(-1);
325
326 let mut sa = _mm256_set1_epi32(0x67452301u32 as i32);
327 let mut sb = _mm256_set1_epi32(0xefcdab89u32 as i32);
328 let mut sc = _mm256_set1_epi32(0x98badcfeu32 as i32);
329 let mut sd = _mm256_set1_epi32(0x10325476u32 as i32);
330
331 for bi in 0..nb {
332 let base = bi * 64;
335 let ld = |p: &[u8], off: usize| _mm256_loadu_si256(p.as_ptr().add(base + off) as *const __m256i);
336 let lo = transpose8x8([
337 ld(pad[0], 0), ld(pad[1], 0), ld(pad[2], 0), ld(pad[3], 0),
338 ld(pad[4], 0), ld(pad[5], 0), ld(pad[6], 0), ld(pad[7], 0),
339 ]);
340 let hi = transpose8x8([
341 ld(pad[0], 32), ld(pad[1], 32), ld(pad[2], 32), ld(pad[3], 32),
342 ld(pad[4], 32), ld(pad[5], 32), ld(pad[6], 32), ld(pad[7], 32),
343 ]);
344 let mut mw = [_mm256_setzero_si256(); 16];
345 mw[..8].copy_from_slice(&lo);
346 mw[8..].copy_from_slice(&hi);
347 let (mut a, mut b, mut c, mut d) = (sa, sb, sc, sd);
348 for i in 0..64 {
349 let (f, g) = match i / 16 {
350 0 => (_mm256_or_si256(_mm256_and_si256(b, c), _mm256_andnot_si256(b, d)), i),
351 1 => (_mm256_or_si256(_mm256_and_si256(b, d), _mm256_andnot_si256(d, c)), (5 * i + 1) % 16),
352 2 => (_mm256_xor_si256(_mm256_xor_si256(b, c), d), (3 * i + 5) % 16),
353 _ => (_mm256_xor_si256(c, _mm256_or_si256(b, _mm256_xor_si256(d, ones))), (7 * i) % 16),
354 };
355 let t = _mm256_add_epi32(
356 _mm256_add_epi32(a, f),
357 _mm256_add_epi32(mw[g], _mm256_set1_epi32(MD5_K[i] as i32)),
358 );
359 a = d;
360 d = c;
361 c = b;
362 b = _mm256_add_epi32(b, rotl(t, MD5_S[i]));
363 }
364 sa = _mm256_add_epi32(sa, a);
365 sb = _mm256_add_epi32(sb, b);
366 sc = _mm256_add_epi32(sc, c);
367 sd = _mm256_add_epi32(sd, d);
368 }
369
370 let mut a8 = [0u32; 8];
371 let mut b8 = [0u32; 8];
372 let mut c8 = [0u32; 8];
373 let mut d8 = [0u32; 8];
374 _mm256_storeu_si256(a8.as_mut_ptr() as *mut __m256i, sa);
375 _mm256_storeu_si256(b8.as_mut_ptr() as *mut __m256i, sb);
376 _mm256_storeu_si256(c8.as_mut_ptr() as *mut __m256i, sc);
377 _mm256_storeu_si256(d8.as_mut_ptr() as *mut __m256i, sd);
378 let mut out = [[0u8; 16]; 8];
379 for (j, o) in out.iter_mut().enumerate() {
380 o[0..4].copy_from_slice(&a8[j].to_le_bytes());
381 o[4..8].copy_from_slice(&b8[j].to_le_bytes());
382 o[8..12].copy_from_slice(&c8[j].to_le_bytes());
383 o[12..16].copy_from_slice(&d8[j].to_le_bytes());
384 }
385 out
386}
387
388pub fn sha1(data: &[u8]) -> [u8; 20] {
390 let mut h: [u32; 5] = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
391
392 #[inline(always)]
393 fn compress(h: &mut [u32; 5], block: &[u8; 64]) {
394 let mut w = [0u32; 80];
396 for (i, word) in w.iter_mut().take(16).enumerate() {
397 *word = u32::from_be_bytes([block[4 * i], block[4 * i + 1], block[4 * i + 2], block[4 * i + 3]]);
398 }
399 for i in 16..80 {
400 w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
401 }
402 let (mut a, mut b, mut c, mut d, mut e) = (h[0], h[1], h[2], h[3], h[4]);
403 for (i, &wi) in w.iter().enumerate() {
404 let (f, k) = match i {
405 0..=19 => ((b & c) | (!b & d), 0x5A827999),
406 20..=39 => (b ^ c ^ d, 0x6ED9EBA1),
407 40..=59 => ((b & c) | (b & d) | (c & d), 0x8F1BBCDC),
408 _ => (b ^ c ^ d, 0xCA62C1D6),
409 };
410 let tmp = a
411 .rotate_left(5)
412 .wrapping_add(f)
413 .wrapping_add(e)
414 .wrapping_add(k)
415 .wrapping_add(wi);
416 e = d;
417 d = c;
418 c = b.rotate_left(30);
419 b = a;
420 a = tmp;
421 }
422 h[0] = h[0].wrapping_add(a);
423 h[1] = h[1].wrapping_add(b);
424 h[2] = h[2].wrapping_add(c);
425 h[3] = h[3].wrapping_add(d);
426 h[4] = h[4].wrapping_add(e);
427 }
428
429 #[cfg(target_arch = "x86_64")]
432 {
433 if x86_sha::available() {
434 unsafe { x86_sha::sha1_blocks(data, &mut h) };
436 let mut out = [0u8; 20];
437 for (i, hi) in h.iter().enumerate() {
438 out[4 * i..4 * i + 4].copy_from_slice(&hi.to_be_bytes());
439 }
440 return out;
441 }
442 }
443
444 each_padded_block(data, Endian::Big, |block| compress(&mut h, block));
445
446 let mut out = [0u8; 20];
447 for (i, hi) in h.iter().enumerate() {
448 out[4 * i..4 * i + 4].copy_from_slice(&hi.to_be_bytes());
449 }
450 out
451}
452
453#[derive(Clone, Copy)]
454enum Endian {
455 Little,
456 Big,
457}
458
459#[inline(always)]
465fn each_padded_block(data: &[u8], endian: Endian, mut compress: impl FnMut(&[u8; 64])) {
466 let mut chunks = data.chunks_exact(64);
467 for chunk in &mut chunks {
468 let mut block = [0u8; 64];
469 block.copy_from_slice(chunk);
470 compress(&block);
471 }
472 let rem = chunks.remainder();
473 let bit_len = (data.len() as u64).wrapping_mul(8);
474 let len_bytes = match endian {
475 Endian::Little => bit_len.to_le_bytes(),
476 Endian::Big => bit_len.to_be_bytes(),
477 };
478
479 let mut tail = [0u8; 128];
480 tail[..rem.len()].copy_from_slice(rem);
481 tail[rem.len()] = 0x80;
482 if rem.len() < 56 {
483 tail[56..64].copy_from_slice(&len_bytes);
485 let mut b = [0u8; 64];
486 b.copy_from_slice(&tail[..64]);
487 compress(&b);
488 } else {
489 tail[120..128].copy_from_slice(&len_bytes);
491 let mut b0 = [0u8; 64];
492 b0.copy_from_slice(&tail[..64]);
493 compress(&b0);
494 let mut b1 = [0u8; 64];
495 b1.copy_from_slice(&tail[64..128]);
496 compress(&b1);
497 }
498}
499
500pub fn to_hex(bytes: &[u8]) -> String {
502 const HEX: &[u8; 16] = b"0123456789abcdef";
503 let mut s = String::with_capacity(bytes.len() * 2);
504 for &b in bytes {
505 s.push(HEX[(b >> 4) as usize] as char);
506 s.push(HEX[(b & 0xf) as usize] as char);
507 }
508 s
509}
510
511#[cfg(target_arch = "x86_64")]
516mod x86_sha {
517 use super::{each_padded_block, Endian};
518
519 #[inline]
522 pub fn available() -> bool {
523 std::is_x86_feature_detected!("sha")
524 && std::is_x86_feature_detected!("ssse3")
525 && std::is_x86_feature_detected!("sse4.1")
526 }
527
528 #[target_feature(enable = "sha,sse2,ssse3,sse4.1")]
530 pub unsafe fn sha1_blocks(data: &[u8], h: &mut [u32; 5]) {
531 each_padded_block(data, Endian::Big, |block| compress(h, block));
532 }
533
534 #[target_feature(enable = "sha,sse2,ssse3,sse4.1")]
536 unsafe fn compress(state: &mut [u32; 5], block: &[u8; 64]) {
537 use core::arch::x86_64::*;
538
539 let mask = _mm_set_epi64x(0x0001_0203_0405_0607, 0x0809_0a0b_0c0d_0e0fu64 as i64);
542 let mut abcd = _mm_shuffle_epi32(_mm_loadu_si128(state.as_ptr() as *const __m128i), 0x1B);
543 let mut e0 = _mm_set_epi32(state[4] as i32, 0, 0, 0);
544 let abcd_save = abcd;
545 let e0_save = e0;
546 let p = block.as_ptr();
547 let mut msg0 = _mm_shuffle_epi8(_mm_loadu_si128(p as *const __m128i), mask);
548 let mut msg1 = _mm_shuffle_epi8(_mm_loadu_si128(p.add(16) as *const __m128i), mask);
549 let mut msg2 = _mm_shuffle_epi8(_mm_loadu_si128(p.add(32) as *const __m128i), mask);
550 let mut msg3 = _mm_shuffle_epi8(_mm_loadu_si128(p.add(48) as *const __m128i), mask);
551 let mut e1;
552
553 e0 = _mm_add_epi32(e0, msg0);
555 e1 = abcd;
556 abcd = _mm_sha1rnds4_epu32(abcd, e0, 0);
557 e1 = _mm_sha1nexte_epu32(e1, msg1);
559 e0 = abcd;
560 abcd = _mm_sha1rnds4_epu32(abcd, e1, 0);
561 msg0 = _mm_sha1msg1_epu32(msg0, msg1);
562 e0 = _mm_sha1nexte_epu32(e0, msg2);
564 e1 = abcd;
565 abcd = _mm_sha1rnds4_epu32(abcd, e0, 0);
566 msg1 = _mm_sha1msg1_epu32(msg1, msg2);
567 msg0 = _mm_xor_si128(msg0, msg2);
568 e1 = _mm_sha1nexte_epu32(e1, msg3);
570 e0 = abcd;
571 msg0 = _mm_sha1msg2_epu32(msg0, msg3);
572 abcd = _mm_sha1rnds4_epu32(abcd, e1, 0);
573 msg2 = _mm_sha1msg1_epu32(msg2, msg3);
574 msg1 = _mm_xor_si128(msg1, msg3);
575 e0 = _mm_sha1nexte_epu32(e0, msg0);
577 e1 = abcd;
578 msg1 = _mm_sha1msg2_epu32(msg1, msg0);
579 abcd = _mm_sha1rnds4_epu32(abcd, e0, 0);
580 msg3 = _mm_sha1msg1_epu32(msg3, msg0);
581 msg2 = _mm_xor_si128(msg2, msg0);
582 e1 = _mm_sha1nexte_epu32(e1, msg1);
584 e0 = abcd;
585 msg2 = _mm_sha1msg2_epu32(msg2, msg1);
586 abcd = _mm_sha1rnds4_epu32(abcd, e1, 1);
587 msg0 = _mm_sha1msg1_epu32(msg0, msg1);
588 msg3 = _mm_xor_si128(msg3, msg1);
589 e0 = _mm_sha1nexte_epu32(e0, msg2);
591 e1 = abcd;
592 msg3 = _mm_sha1msg2_epu32(msg3, msg2);
593 abcd = _mm_sha1rnds4_epu32(abcd, e0, 1);
594 msg1 = _mm_sha1msg1_epu32(msg1, msg2);
595 msg0 = _mm_xor_si128(msg0, msg2);
596 e1 = _mm_sha1nexte_epu32(e1, msg3);
598 e0 = abcd;
599 msg0 = _mm_sha1msg2_epu32(msg0, msg3);
600 abcd = _mm_sha1rnds4_epu32(abcd, e1, 1);
601 msg2 = _mm_sha1msg1_epu32(msg2, msg3);
602 msg1 = _mm_xor_si128(msg1, msg3);
603 e0 = _mm_sha1nexte_epu32(e0, msg0);
605 e1 = abcd;
606 msg1 = _mm_sha1msg2_epu32(msg1, msg0);
607 abcd = _mm_sha1rnds4_epu32(abcd, e0, 1);
608 msg3 = _mm_sha1msg1_epu32(msg3, msg0);
609 msg2 = _mm_xor_si128(msg2, msg0);
610 e1 = _mm_sha1nexte_epu32(e1, msg1);
612 e0 = abcd;
613 msg2 = _mm_sha1msg2_epu32(msg2, msg1);
614 abcd = _mm_sha1rnds4_epu32(abcd, e1, 1);
615 msg0 = _mm_sha1msg1_epu32(msg0, msg1);
616 msg3 = _mm_xor_si128(msg3, msg1);
617 e0 = _mm_sha1nexte_epu32(e0, msg2);
619 e1 = abcd;
620 msg3 = _mm_sha1msg2_epu32(msg3, msg2);
621 abcd = _mm_sha1rnds4_epu32(abcd, e0, 2);
622 msg1 = _mm_sha1msg1_epu32(msg1, msg2);
623 msg0 = _mm_xor_si128(msg0, msg2);
624 e1 = _mm_sha1nexte_epu32(e1, msg3);
626 e0 = abcd;
627 msg0 = _mm_sha1msg2_epu32(msg0, msg3);
628 abcd = _mm_sha1rnds4_epu32(abcd, e1, 2);
629 msg2 = _mm_sha1msg1_epu32(msg2, msg3);
630 msg1 = _mm_xor_si128(msg1, msg3);
631 e0 = _mm_sha1nexte_epu32(e0, msg0);
633 e1 = abcd;
634 msg1 = _mm_sha1msg2_epu32(msg1, msg0);
635 abcd = _mm_sha1rnds4_epu32(abcd, e0, 2);
636 msg3 = _mm_sha1msg1_epu32(msg3, msg0);
637 msg2 = _mm_xor_si128(msg2, msg0);
638 e1 = _mm_sha1nexte_epu32(e1, msg1);
640 e0 = abcd;
641 msg2 = _mm_sha1msg2_epu32(msg2, msg1);
642 abcd = _mm_sha1rnds4_epu32(abcd, e1, 2);
643 msg0 = _mm_sha1msg1_epu32(msg0, msg1);
644 msg3 = _mm_xor_si128(msg3, msg1);
645 e0 = _mm_sha1nexte_epu32(e0, msg2);
647 e1 = abcd;
648 msg3 = _mm_sha1msg2_epu32(msg3, msg2);
649 abcd = _mm_sha1rnds4_epu32(abcd, e0, 2);
650 msg1 = _mm_sha1msg1_epu32(msg1, msg2);
651 msg0 = _mm_xor_si128(msg0, msg2);
652 e1 = _mm_sha1nexte_epu32(e1, msg3);
654 e0 = abcd;
655 msg0 = _mm_sha1msg2_epu32(msg0, msg3);
656 abcd = _mm_sha1rnds4_epu32(abcd, e1, 3);
657 msg2 = _mm_sha1msg1_epu32(msg2, msg3);
658 msg1 = _mm_xor_si128(msg1, msg3);
659 e0 = _mm_sha1nexte_epu32(e0, msg0);
661 e1 = abcd;
662 msg1 = _mm_sha1msg2_epu32(msg1, msg0);
663 abcd = _mm_sha1rnds4_epu32(abcd, e0, 3);
664 msg3 = _mm_sha1msg1_epu32(msg3, msg0);
665 msg2 = _mm_xor_si128(msg2, msg0);
666 e1 = _mm_sha1nexte_epu32(e1, msg1);
668 e0 = abcd;
669 msg2 = _mm_sha1msg2_epu32(msg2, msg1);
670 abcd = _mm_sha1rnds4_epu32(abcd, e1, 3);
671 msg3 = _mm_xor_si128(msg3, msg1);
672 e0 = _mm_sha1nexte_epu32(e0, msg2);
674 e1 = abcd;
675 msg3 = _mm_sha1msg2_epu32(msg3, msg2);
676 abcd = _mm_sha1rnds4_epu32(abcd, e0, 3);
677 e1 = _mm_sha1nexte_epu32(e1, msg3);
679 e0 = abcd;
680 abcd = _mm_sha1rnds4_epu32(abcd, e1, 3);
681
682 e0 = _mm_sha1nexte_epu32(e0, e0_save);
684 abcd = _mm_add_epi32(abcd, abcd_save);
685
686 abcd = _mm_shuffle_epi32(abcd, 0x1B);
687 _mm_storeu_si128(state.as_mut_ptr() as *mut __m128i, abcd);
688 state[4] = _mm_extract_epi32(e0, 3) as u32;
689 }
690}
691
692#[cfg(test)]
693mod tests {
694 use super::*;
695
696 #[test]
697 fn md5_known_rfc_vectors() {
698 assert_eq!(to_hex(&md5(b"")), "d41d8cd98f00b204e9800998ecf8427e");
699 assert_eq!(to_hex(&md5(b"a")), "0cc175b9c0f1b6a831c399e269772661");
700 assert_eq!(to_hex(&md5(b"abc")), "900150983cd24fb0d6963f7d28e17f72");
701 assert_eq!(to_hex(&md5(b"message digest")), "f96b697d7cb7938d525a2f31aaf161d0");
702 assert_eq!(
703 to_hex(&md5(b"abcdefghijklmnopqrstuvwxyz")),
704 "c3fcd3d76192e4007dfb496cca67e13b"
705 );
706 assert_eq!(
707 to_hex(&md5(b"The quick brown fox jumps over the lazy dog")),
708 "9e107d9d372bb6826bd81d3542a419d6"
709 );
710 }
711
712 #[test]
713 fn sha1_known_rfc_vectors() {
714 assert_eq!(to_hex(&sha1(b"")), "da39a3ee5e6b4b0d3255bfef95601890afd80709");
715 assert_eq!(to_hex(&sha1(b"abc")), "a9993e364706816aba3e25717850c26c9cd0d89d");
716 assert_eq!(
717 to_hex(&sha1(b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")),
718 "84983e441c3bd26ebaae4aa1f95129e5e54670f1"
719 );
720 assert_eq!(
721 to_hex(&sha1(b"The quick brown fox jumps over the lazy dog")),
722 "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
723 );
724 }
725
726 #[test]
727 fn md5_block_boundaries_are_exact() {
728 for n in [0usize, 1, 54, 55, 56, 57, 63, 64, 65, 119, 120, 127, 128, 256, 1000] {
730 let data = vec![0xABu8; n];
731 let mut oracle = <md5::Md5 as md5::Digest>::new();
732 md5::Digest::update(&mut oracle, &data);
733 let want: [u8; 16] = md5::Digest::finalize(oracle).into();
734 assert_eq!(md5(&data), want, "md5 mismatch at len {n}");
735 }
736 }
737
738 #[test]
739 #[cfg(target_arch = "x86_64")]
740 fn md5_x4_matches_scalar_over_lengths() {
741 for len in [0usize, 1, 3, 16, 32, 55, 56, 57, 63, 64, 65, 119, 120, 128, 200] {
744 let mut msgs = [Vec::new(), Vec::new(), Vec::new(), Vec::new()];
745 let mut st = 0x1234_5678u64.wrapping_add(len as u64);
746 for m in msgs.iter_mut() {
747 for _ in 0..len {
748 st = st.wrapping_mul(6364136223846793005).wrapping_add(1);
749 m.push((st >> 56) as u8);
750 }
751 }
752 let refs: [&[u8]; 4] = [&msgs[0], &msgs[1], &msgs[2], &msgs[3]];
753 let x4 = md5_x4(refs);
754 for (j, m) in msgs.iter().enumerate() {
755 assert_eq!(x4[j], md5(m), "md5_x4 lane {j} differs at len {len}");
756 }
757 }
758 }
759
760 #[test]
761 #[cfg(target_arch = "x86_64")]
762 fn md5_x8_matches_scalar_over_lengths() {
763 for len in [0usize, 1, 3, 16, 32, 55, 56, 57, 63, 64, 65, 119, 120, 128, 200] {
766 let mut msgs: Vec<Vec<u8>> = (0..8).map(|_| Vec::new()).collect();
767 let mut st = 0x9e37_79b9u64.wrapping_add(len as u64);
768 for m in msgs.iter_mut() {
769 for _ in 0..len {
770 st = st.wrapping_mul(6364136223846793005).wrapping_add(1);
771 m.push((st >> 56) as u8);
772 }
773 }
774 let refs: [&[u8]; 8] = [
775 &msgs[0], &msgs[1], &msgs[2], &msgs[3], &msgs[4], &msgs[5], &msgs[6], &msgs[7],
776 ];
777 let x8 = md5_x8(refs);
778 for (j, m) in msgs.iter().enumerate() {
779 assert_eq!(x8[j], md5(m), "md5_x8 lane {j} differs at len {len}");
780 }
781 }
782 }
783
784 #[test]
785 fn sha1_block_boundaries_are_exact() {
786 for n in [0usize, 1, 54, 55, 56, 57, 63, 64, 65, 119, 120, 127, 128, 256, 1000] {
787 let data = vec![0x5Au8; n];
788 let mut oracle = <sha1::Sha1 as sha1::Digest>::new();
789 sha1::Digest::update(&mut oracle, &data);
790 let want: [u8; 20] = sha1::Digest::finalize(oracle).into();
791 assert_eq!(sha1(&data), want, "sha1 mismatch at len {n}");
792 }
793 }
794
795 #[test]
796 fn differential_fuzz_against_the_reference_crates() {
797 let mut state: u64 = 0x1234_5678_9abc_def0;
800 let mut next = || {
801 state = state.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
802 (state >> 33) as u32
803 };
804 for _ in 0..5000 {
805 let len = (next() % 600) as usize;
806 let data: Vec<u8> = (0..len).map(|_| (next() & 0xff) as u8).collect();
807
808 let mut m = <md5::Md5 as md5::Digest>::new();
809 md5::Digest::update(&mut m, &data);
810 let m_want: [u8; 16] = md5::Digest::finalize(m).into();
811 assert_eq!(md5(&data), m_want, "md5 differs at len {len}");
812
813 let mut s = <sha1::Sha1 as sha1::Digest>::new();
814 sha1::Digest::update(&mut s, &data);
815 let s_want: [u8; 20] = sha1::Digest::finalize(s).into();
816 assert_eq!(sha1(&data), s_want, "sha1 differs at len {len}");
817 }
818 }
819}