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 mut input = [0u32; 16];
122 let k = ((self.count >> 3) & 0x3f) as usize;
123 input[14] = self.count as u32;
124 input[15] = (self.count >> 32) as u32;
125 consume(
126 &mut self,
127 &PADDING[..(if k < 56 { 56 - k } else { 120 - k })],
128 );
129 let mut j = 0;
130 for i in 0..14 {
131 input[i] = ((self.buffer[j + 3] as u32) << 24) |
132 ((self.buffer[j + 2] as u32) << 16) |
133 ((self.buffer[j + 1] as u32) << 8) |
134 ((self.buffer[j ] as u32) );
135 j += 4;
136 }
137 transform(&mut self.state, &input);
138 let mut digest = [0u8; 16];
139 let mut j = 0;
140 for i in 0..4 {
141 digest[j ] = ((self.state[i] ) & 0xff) as u8;
142 digest[j + 1] = ((self.state[i] >> 8) & 0xff) as u8;
143 digest[j + 2] = ((self.state[i] >> 16) & 0xff) as u8;
144 digest[j + 3] = ((self.state[i] >> 24) & 0xff) as u8;
145 j += 4;
146 }
147 Digest(digest)
148 }
149
150 #[deprecated(since = "0.8.0", note = "Use `finalize`.")]
152 #[inline]
153 pub fn compute(self) -> Digest {
154 self.finalize()
155 }
156}
157
158impl Default for Context {
159 #[inline]
160 fn default() -> Self {
161 Self::new()
162 }
163}
164
165impl core::convert::From<Context> for Digest {
166 #[inline]
167 fn from(context: Context) -> Digest {
168 context.finalize()
169 }
170}
171
172#[cfg(feature = "std")]
173impl core::io::Write for Context {
174 #[inline]
175 fn write(&mut self, data: &[u8]) -> core::io::Result<usize> {
176 self.consume(data);
177 Ok(data.len())
178 }
179
180 #[inline]
181 fn flush(&mut self) -> core::io::Result<()> {
182 Ok(())
183 }
184}
185
186#[inline]
188pub fn compute<T: AsRef<[u8]>>(data: T) -> Digest {
189 let mut context = Context::new();
190 context.consume(data);
191 context.finalize()
192}
193
194#[rustfmt::skip]
195#[allow(clippy::double_parens, clippy::needless_range_loop)]
196fn consume(
197 Context {
198 buffer,
199 count,
200 state,
201 }: &mut Context,
202 data: &[u8],
203) {
204 let mut input = [0u32; 16];
205 let mut k = ((*count >> 3) & 0x3f) as usize;
206 *count = count.wrapping_add((data.len() as u64) << 3);
207 for &value in data {
208 buffer[k] = value;
209 k += 1;
210 if k == 0x40 {
211 let mut j = 0;
212 for i in 0..16 {
213 input[i] = ((buffer[j + 3] as u32) << 24) |
214 ((buffer[j + 2] as u32) << 16) |
215 ((buffer[j + 1] as u32) << 8) |
216 ((buffer[j ] as u32) );
217 j += 4;
218 }
219 transform(state, &input);
220 k = 0;
221 }
222 }
223}
224
225#[rustfmt::skip]
226fn transform(state: &mut [u32; 4], input: &[u32; 16]) {
227 let (mut a, mut b, mut c, mut d) = (state[0], state[1], state[2], state[3]);
228 macro_rules! add(
229 ($a:expr, $b:expr) => ($a.wrapping_add($b));
230 );
231 macro_rules! rotate(
232 ($x:expr, $n:expr) => ($x.rotate_left($n));
233 );
234 {
235 macro_rules! F(
236 ($x:expr, $y:expr, $z:expr) => (($x & $y) | (!$x & $z));
237 );
238 macro_rules! T(
239 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
240 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
241 $a = rotate!($a, $s);
242 $a = add!($a, $b);
243 });
244 );
245 const S1: u32 = 7;
246 const S2: u32 = 12;
247 const S3: u32 = 17;
248 const S4: u32 = 22;
249 T!(a, b, c, d, input[ 0], S1, 3614090360);
250 T!(d, a, b, c, input[ 1], S2, 3905402710);
251 T!(c, d, a, b, input[ 2], S3, 606105819);
252 T!(b, c, d, a, input[ 3], S4, 3250441966);
253 T!(a, b, c, d, input[ 4], S1, 4118548399);
254 T!(d, a, b, c, input[ 5], S2, 1200080426);
255 T!(c, d, a, b, input[ 6], S3, 2821735955);
256 T!(b, c, d, a, input[ 7], S4, 4249261313);
257 T!(a, b, c, d, input[ 8], S1, 1770035416);
258 T!(d, a, b, c, input[ 9], S2, 2336552879);
259 T!(c, d, a, b, input[10], S3, 4294925233);
260 T!(b, c, d, a, input[11], S4, 2304563134);
261 T!(a, b, c, d, input[12], S1, 1804603682);
262 T!(d, a, b, c, input[13], S2, 4254626195);
263 T!(c, d, a, b, input[14], S3, 2792965006);
264 T!(b, c, d, a, input[15], S4, 1236535329);
265 }
266 {
267 macro_rules! F(
268 ($x:expr, $y:expr, $z:expr) => (($x & $z) | ($y & !$z));
269 );
270 macro_rules! T(
271 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
272 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
273 $a = rotate!($a, $s);
274 $a = add!($a, $b);
275 });
276 );
277 const S1: u32 = 5;
278 const S2: u32 = 9;
279 const S3: u32 = 14;
280 const S4: u32 = 20;
281 T!(a, b, c, d, input[ 1], S1, 4129170786);
282 T!(d, a, b, c, input[ 6], S2, 3225465664);
283 T!(c, d, a, b, input[11], S3, 643717713);
284 T!(b, c, d, a, input[ 0], S4, 3921069994);
285 T!(a, b, c, d, input[ 5], S1, 3593408605);
286 T!(d, a, b, c, input[10], S2, 38016083);
287 T!(c, d, a, b, input[15], S3, 3634488961);
288 T!(b, c, d, a, input[ 4], S4, 3889429448);
289 T!(a, b, c, d, input[ 9], S1, 568446438);
290 T!(d, a, b, c, input[14], S2, 3275163606);
291 T!(c, d, a, b, input[ 3], S3, 4107603335);
292 T!(b, c, d, a, input[ 8], S4, 1163531501);
293 T!(a, b, c, d, input[13], S1, 2850285829);
294 T!(d, a, b, c, input[ 2], S2, 4243563512);
295 T!(c, d, a, b, input[ 7], S3, 1735328473);
296 T!(b, c, d, a, input[12], S4, 2368359562);
297 }
298 {
299 macro_rules! F(
300 ($x:expr, $y:expr, $z:expr) => ($x ^ $y ^ $z);
301 );
302 macro_rules! T(
303 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
304 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
305 $a = rotate!($a, $s);
306 $a = add!($a, $b);
307 });
308 );
309 const S1: u32 = 4;
310 const S2: u32 = 11;
311 const S3: u32 = 16;
312 const S4: u32 = 23;
313 T!(a, b, c, d, input[ 5], S1, 4294588738);
314 T!(d, a, b, c, input[ 8], S2, 2272392833);
315 T!(c, d, a, b, input[11], S3, 1839030562);
316 T!(b, c, d, a, input[14], S4, 4259657740);
317 T!(a, b, c, d, input[ 1], S1, 2763975236);
318 T!(d, a, b, c, input[ 4], S2, 1272893353);
319 T!(c, d, a, b, input[ 7], S3, 4139469664);
320 T!(b, c, d, a, input[10], S4, 3200236656);
321 T!(a, b, c, d, input[13], S1, 681279174);
322 T!(d, a, b, c, input[ 0], S2, 3936430074);
323 T!(c, d, a, b, input[ 3], S3, 3572445317);
324 T!(b, c, d, a, input[ 6], S4, 76029189);
325 T!(a, b, c, d, input[ 9], S1, 3654602809);
326 T!(d, a, b, c, input[12], S2, 3873151461);
327 T!(c, d, a, b, input[15], S3, 530742520);
328 T!(b, c, d, a, input[ 2], S4, 3299628645);
329 }
330 {
331 macro_rules! F(
332 ($x:expr, $y:expr, $z:expr) => ($y ^ ($x | !$z));
333 );
334 macro_rules! T(
335 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
336 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
337 $a = rotate!($a, $s);
338 $a = add!($a, $b);
339 });
340 );
341 const S1: u32 = 6;
342 const S2: u32 = 10;
343 const S3: u32 = 15;
344 const S4: u32 = 21;
345 T!(a, b, c, d, input[ 0], S1, 4096336452);
346 T!(d, a, b, c, input[ 7], S2, 1126891415);
347 T!(c, d, a, b, input[14], S3, 2878612391);
348 T!(b, c, d, a, input[ 5], S4, 4237533241);
349 T!(a, b, c, d, input[12], S1, 1700485571);
350 T!(d, a, b, c, input[ 3], S2, 2399980690);
351 T!(c, d, a, b, input[10], S3, 4293915773);
352 T!(b, c, d, a, input[ 1], S4, 2240044497);
353 T!(a, b, c, d, input[ 8], S1, 1873313359);
354 T!(d, a, b, c, input[15], S2, 4264355552);
355 T!(c, d, a, b, input[ 6], S3, 2734768916);
356 T!(b, c, d, a, input[13], S4, 1309151649);
357 T!(a, b, c, d, input[ 4], S1, 4149444226);
358 T!(d, a, b, c, input[11], S2, 3174756917);
359 T!(c, d, a, b, input[ 2], S3, 718787259);
360 T!(b, c, d, a, input[ 9], S4, 3951481745);
361 }
362 state[0] = add!(state[0], a);
363 state[1] = add!(state[1], b);
364 state[2] = add!(state[2], c);
365 state[3] = add!(state[3], d);
366}
367
368#[cfg(test)]
369mod tests {
370 use std::io::prelude::Write;
371
372 use super::Context;
373
374 #[test]
375 fn compute() {
376 let inputs = [
377 "",
378 "a",
379 "abc",
380 "message digest",
381 "abcdefghijklmnopqrstuvwxyz",
382 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
383 "0123456789012345678901234567890123456789012345678901234567890123",
384 "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
385 ];
386 let outputs = [
387 "d41d8cd98f00b204e9800998ecf8427e",
388 "0cc175b9c0f1b6a831c399e269772661",
389 "900150983cd24fb0d6963f7d28e17f72",
390 "f96b697d7cb7938d525a2f31aaf161d0",
391 "c3fcd3d76192e4007dfb496cca67e13b",
392 "d174ab98d277d9f5a5611c2c9f419d9f",
393 "7f7bfd348709deeaace19e3f535f8c54",
394 "57edf4a22be3c955ac49da2e2107b67a",
395 ];
396 for (input, &output) in inputs.iter().zip(outputs.iter()) {
397 let digest = super::compute(input);
398 assert_eq!(format!("{digest:x}"), output);
399
400 let mut context = Context::new();
401 context.consume(input);
402 let digest = context.finalize();
403 assert_eq!(format!("{digest:x}"), output);
404 }
405 }
406
407 #[test]
408 fn index() {
409 let mut digest = super::compute(b"abc");
410 assert_eq!(digest[0], 0x90);
411 assert_eq!(&digest[0], &0x90);
412 assert_eq!(&mut digest[0], &mut 0x90);
413 }
414
415 #[test]
416 fn write_29() {
417 let data = vec![0; 8 * 1024 * 1024];
418 let mut context = Context::new();
419 for _ in 0..64 {
420 context.write(&data).unwrap();
421 }
422 assert_eq!(
423 format!("{:x}", context.finalize()),
424 "aa559b4e3523a6c931f08f4df52d58f2",
425 );
426 }
427
428 #[test]
429 fn write_32() {
430 let data = vec![0; std::u32::MAX as usize + 1];
431 let mut context = Context::new();
432 context.write(&data).unwrap();
433 assert_eq!(
434 format!("{:x}", context.finalize()),
435 "c9a5a6878d97b48cc965c1e41859f034",
436 );
437 }
438}