1#![cfg_attr(not(feature = "std"), no_std)]
31
32#[cfg(feature = "std")]
33use std as core;
34
35#[derive(Clone, Copy, Eq, Hash, PartialEq)]
37pub struct Digest(pub [u8; 16]);
38
39impl core::convert::From<Digest> for [u8; 16] {
40 #[inline]
41 fn from(digest: Digest) -> Self {
42 digest.0
43 }
44}
45
46impl core::fmt::Debug for Digest {
47 #[inline]
48 fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
49 core::fmt::LowerHex::fmt(self, formatter)
50 }
51}
52
53impl core::ops::Deref for Digest {
54 type Target = [u8; 16];
55
56 #[inline]
57 fn deref(&self) -> &Self::Target {
58 &self.0
59 }
60}
61
62impl core::ops::DerefMut for Digest {
63 #[inline]
64 fn deref_mut(&mut self) -> &mut Self::Target {
65 &mut self.0
66 }
67}
68
69macro_rules! implement {
70 ($kind:ident, $format:expr) => {
71 impl core::fmt::$kind for Digest {
72 fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
73 for value in &self.0 {
74 write!(formatter, $format, value)?;
75 }
76 Ok(())
77 }
78 }
79 };
80}
81
82implement!(LowerHex, "{:02x}");
83implement!(UpperHex, "{:02X}");
84
85#[derive(Clone)]
87pub struct Context {
88 buffer: [u8; 64],
89 count: u64,
90 state: [u32; 4],
91}
92
93const PADDING: [u8; 64] = [
94 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98];
99
100impl Context {
101 #[inline]
103 pub fn new() -> Context {
104 Context {
105 buffer: [0; 64],
106 count: 0,
107 state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476],
108 }
109 }
110
111 #[inline]
113 pub fn consume<T: AsRef<[u8]>>(&mut self, data: T) {
114 consume(self, data.as_ref());
115 }
116
117 #[rustfmt::skip]
119 #[allow(clippy::double_parens, clippy::needless_range_loop)]
120 pub fn finalize(mut self) -> Digest {
121 let k = ((self.count >> 3) & 0x3f) as usize;
122 let length = self.count.to_le_bytes();
123 consume(
124 &mut self,
125 &PADDING[..(if k < 56 { 56 - k } else { 120 - k })],
126 );
127 self.buffer[56..64].copy_from_slice(&length);
128 transform(&mut self.state, &self.buffer);
129 let mut digest = [0u8; 16];
130 let mut j = 0;
131 for i in 0..4 {
132 digest[j ] = ((self.state[i] ) & 0xff) as u8;
133 digest[j + 1] = ((self.state[i] >> 8) & 0xff) as u8;
134 digest[j + 2] = ((self.state[i] >> 16) & 0xff) as u8;
135 digest[j + 3] = ((self.state[i] >> 24) & 0xff) as u8;
136 j += 4;
137 }
138 Digest(digest)
139 }
140
141 #[deprecated(since = "0.8.0", note = "Use `finalize`.")]
143 #[inline]
144 pub fn compute(self) -> Digest {
145 self.finalize()
146 }
147}
148
149impl Default for Context {
150 #[inline]
151 fn default() -> Self {
152 Self::new()
153 }
154}
155
156impl core::convert::From<Context> for Digest {
157 #[inline]
158 fn from(context: Context) -> Digest {
159 context.finalize()
160 }
161}
162
163#[cfg(feature = "std")]
164impl core::io::Write for Context {
165 #[inline]
166 fn write(&mut self, data: &[u8]) -> core::io::Result<usize> {
167 self.consume(data);
168 Ok(data.len())
169 }
170
171 #[inline]
172 fn flush(&mut self) -> core::io::Result<()> {
173 Ok(())
174 }
175}
176
177#[inline]
179pub fn compute<T: AsRef<[u8]>>(data: T) -> Digest {
180 let mut context = Context::new();
181 context.consume(data);
182 context.finalize()
183}
184
185#[rustfmt::skip]
186#[inline(always)]
187fn consume(context: &mut Context, mut data: &[u8]) {
188 let k = ((context.count >> 3) & 0x3f) as usize;
189 context.count = context.count.wrapping_add((data.len() as u64) << 3);
190 if k != 0 {
191 let n = core::cmp::min(64 - k, data.len());
192 context.buffer[k..k + n].copy_from_slice(&data[..n]);
193 data = &data[n..];
194 if k + n != 64 {
195 return;
196 }
197 transform(&mut context.state, &context.buffer);
198 }
199 while data.len() >= 64 {
200 let block = <&[u8; 64]>::try_from(&data[..64]).unwrap();
201 transform(&mut context.state, block);
202 data = &data[64..];
203 }
204 context.buffer[..data.len()].copy_from_slice(data);
205}
206
207#[rustfmt::skip]
208#[inline(always)]
209fn transform(state: &mut [u32; 4], block: &[u8; 64]) {
210 macro_rules! decode(
211 ($i:expr) => (u32::from_le_bytes([block[$i], block[$i + 1], block[$i + 2], block[$i + 3]]));
212 );
213 let input = [
214 decode!( 0), decode!( 4), decode!( 8), decode!(12),
215 decode!(16), decode!(20), decode!(24), decode!(28),
216 decode!(32), decode!(36), decode!(40), decode!(44),
217 decode!(48), decode!(52), decode!(56), decode!(60),
218 ];
219 let (mut a, mut b, mut c, mut d) = (state[0], state[1], state[2], state[3]);
220 macro_rules! add(
221 ($a:expr, $b:expr) => ($a.wrapping_add($b));
222 );
223 macro_rules! rotate(
224 ($x:expr, $n:expr) => ($x.rotate_left($n));
225 );
226 {
227 macro_rules! F(
228 ($x:expr, $y:expr, $z:expr) => ($z ^ ($x & ($y ^ $z)));
229 );
230 macro_rules! T(
231 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
232 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
233 $a = rotate!($a, $s);
234 $a = add!($a, $b);
235 });
236 );
237 const S1: u32 = 7;
238 const S2: u32 = 12;
239 const S3: u32 = 17;
240 const S4: u32 = 22;
241 T!(a, b, c, d, input[ 0], S1, 3614090360);
242 T!(d, a, b, c, input[ 1], S2, 3905402710);
243 T!(c, d, a, b, input[ 2], S3, 606105819);
244 T!(b, c, d, a, input[ 3], S4, 3250441966);
245 T!(a, b, c, d, input[ 4], S1, 4118548399);
246 T!(d, a, b, c, input[ 5], S2, 1200080426);
247 T!(c, d, a, b, input[ 6], S3, 2821735955);
248 T!(b, c, d, a, input[ 7], S4, 4249261313);
249 T!(a, b, c, d, input[ 8], S1, 1770035416);
250 T!(d, a, b, c, input[ 9], S2, 2336552879);
251 T!(c, d, a, b, input[10], S3, 4294925233);
252 T!(b, c, d, a, input[11], S4, 2304563134);
253 T!(a, b, c, d, input[12], S1, 1804603682);
254 T!(d, a, b, c, input[13], S2, 4254626195);
255 T!(c, d, a, b, input[14], S3, 2792965006);
256 T!(b, c, d, a, input[15], S4, 1236535329);
257 }
258 {
259 macro_rules! F(
260 ($x:expr, $y:expr, $z:expr) => ($y ^ ($z & ($x ^ $y)));
261 );
262 macro_rules! T(
263 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
264 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
265 $a = rotate!($a, $s);
266 $a = add!($a, $b);
267 });
268 );
269 const S1: u32 = 5;
270 const S2: u32 = 9;
271 const S3: u32 = 14;
272 const S4: u32 = 20;
273 T!(a, b, c, d, input[ 1], S1, 4129170786);
274 T!(d, a, b, c, input[ 6], S2, 3225465664);
275 T!(c, d, a, b, input[11], S3, 643717713);
276 T!(b, c, d, a, input[ 0], S4, 3921069994);
277 T!(a, b, c, d, input[ 5], S1, 3593408605);
278 T!(d, a, b, c, input[10], S2, 38016083);
279 T!(c, d, a, b, input[15], S3, 3634488961);
280 T!(b, c, d, a, input[ 4], S4, 3889429448);
281 T!(a, b, c, d, input[ 9], S1, 568446438);
282 T!(d, a, b, c, input[14], S2, 3275163606);
283 T!(c, d, a, b, input[ 3], S3, 4107603335);
284 T!(b, c, d, a, input[ 8], S4, 1163531501);
285 T!(a, b, c, d, input[13], S1, 2850285829);
286 T!(d, a, b, c, input[ 2], S2, 4243563512);
287 T!(c, d, a, b, input[ 7], S3, 1735328473);
288 T!(b, c, d, a, input[12], S4, 2368359562);
289 }
290 {
291 macro_rules! F(
292 ($x:expr, $y:expr, $z:expr) => ($x ^ $y ^ $z);
293 );
294 macro_rules! T(
295 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
296 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
297 $a = rotate!($a, $s);
298 $a = add!($a, $b);
299 });
300 );
301 const S1: u32 = 4;
302 const S2: u32 = 11;
303 const S3: u32 = 16;
304 const S4: u32 = 23;
305 T!(a, b, c, d, input[ 5], S1, 4294588738);
306 T!(d, a, b, c, input[ 8], S2, 2272392833);
307 T!(c, d, a, b, input[11], S3, 1839030562);
308 T!(b, c, d, a, input[14], S4, 4259657740);
309 T!(a, b, c, d, input[ 1], S1, 2763975236);
310 T!(d, a, b, c, input[ 4], S2, 1272893353);
311 T!(c, d, a, b, input[ 7], S3, 4139469664);
312 T!(b, c, d, a, input[10], S4, 3200236656);
313 T!(a, b, c, d, input[13], S1, 681279174);
314 T!(d, a, b, c, input[ 0], S2, 3936430074);
315 T!(c, d, a, b, input[ 3], S3, 3572445317);
316 T!(b, c, d, a, input[ 6], S4, 76029189);
317 T!(a, b, c, d, input[ 9], S1, 3654602809);
318 T!(d, a, b, c, input[12], S2, 3873151461);
319 T!(c, d, a, b, input[15], S3, 530742520);
320 T!(b, c, d, a, input[ 2], S4, 3299628645);
321 }
322 {
323 macro_rules! F(
324 ($x:expr, $y:expr, $z:expr) => ($y ^ ($x | !$z));
325 );
326 macro_rules! T(
327 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
328 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
329 $a = rotate!($a, $s);
330 $a = add!($a, $b);
331 });
332 );
333 const S1: u32 = 6;
334 const S2: u32 = 10;
335 const S3: u32 = 15;
336 const S4: u32 = 21;
337 T!(a, b, c, d, input[ 0], S1, 4096336452);
338 T!(d, a, b, c, input[ 7], S2, 1126891415);
339 T!(c, d, a, b, input[14], S3, 2878612391);
340 T!(b, c, d, a, input[ 5], S4, 4237533241);
341 T!(a, b, c, d, input[12], S1, 1700485571);
342 T!(d, a, b, c, input[ 3], S2, 2399980690);
343 T!(c, d, a, b, input[10], S3, 4293915773);
344 T!(b, c, d, a, input[ 1], S4, 2240044497);
345 T!(a, b, c, d, input[ 8], S1, 1873313359);
346 T!(d, a, b, c, input[15], S2, 4264355552);
347 T!(c, d, a, b, input[ 6], S3, 2734768916);
348 T!(b, c, d, a, input[13], S4, 1309151649);
349 T!(a, b, c, d, input[ 4], S1, 4149444226);
350 T!(d, a, b, c, input[11], S2, 3174756917);
351 T!(c, d, a, b, input[ 2], S3, 718787259);
352 T!(b, c, d, a, input[ 9], S4, 3951481745);
353 }
354 state[0] = add!(state[0], a);
355 state[1] = add!(state[1], b);
356 state[2] = add!(state[2], c);
357 state[3] = add!(state[3], d);
358}
359
360#[cfg(test)]
361mod tests {
362 use std::io::prelude::Write;
363
364 use super::Context;
365
366 #[test]
367 fn compute() {
368 let inputs = [
369 "",
370 "a",
371 "abc",
372 "message digest",
373 "abcdefghijklmnopqrstuvwxyz",
374 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
375 "0123456789012345678901234567890123456789012345678901234567890123",
376 "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
377 ];
378 let outputs = [
379 "d41d8cd98f00b204e9800998ecf8427e",
380 "0cc175b9c0f1b6a831c399e269772661",
381 "900150983cd24fb0d6963f7d28e17f72",
382 "f96b697d7cb7938d525a2f31aaf161d0",
383 "c3fcd3d76192e4007dfb496cca67e13b",
384 "d174ab98d277d9f5a5611c2c9f419d9f",
385 "7f7bfd348709deeaace19e3f535f8c54",
386 "57edf4a22be3c955ac49da2e2107b67a",
387 ];
388 for (input, &output) in inputs.iter().zip(outputs.iter()) {
389 let digest = super::compute(input);
390 assert_eq!(format!("{digest:x}"), output);
391
392 let mut context = Context::new();
393 context.consume(input);
394 let digest = context.finalize();
395 assert_eq!(format!("{digest:x}"), output);
396 }
397 }
398
399 #[test]
400 fn consume() {
401 for len in [0, 1, 55, 56, 57, 63, 64, 65, 119, 120, 121, 1024] {
402 let data: Vec<_> = (0..len).map(|i| (i % 251) as u8).collect();
403 let expected = super::compute(&data);
404 for chunk_size in [1, 7, 63, 64, 65, 128] {
405 let mut context = Context::new();
406 for chunk in data.chunks(chunk_size) {
407 context.consume(chunk);
408 }
409 assert_eq!(context.finalize(), expected);
410 }
411 }
412 }
413
414 #[test]
415 fn index() {
416 let mut digest = super::compute(b"abc");
417 assert_eq!(digest[0], 0x90);
418 assert_eq!(&digest[0], &0x90);
419 assert_eq!(&mut digest[0], &mut 0x90);
420 }
421
422 #[test]
423 fn write_29() {
424 let data = vec![0; 8 * 1024 * 1024];
425 let mut context = Context::new();
426 for _ in 0..64 {
427 context.write(&data).unwrap();
428 }
429 assert_eq!(
430 format!("{:x}", context.finalize()),
431 "aa559b4e3523a6c931f08f4df52d58f2",
432 );
433 }
434
435 #[cfg(target_pointer_width = "64")]
436 #[test]
437 fn write_32() {
438 let data = vec![0; std::u32::MAX as usize + 1];
439 let mut context = Context::new();
440 context.write(&data).unwrap();
441 assert_eq!(
442 format!("{:x}", context.finalize()),
443 "c9a5a6878d97b48cc965c1e41859f034",
444 );
445 }
446}