1#![no_std]
32#![deny(missing_docs)]
33#![allow(deprecated)]
34#![allow(clippy::double_parens)]
35#![allow(clippy::identity_op)]
36
37use core::cmp;
38use core::fmt;
39use core::hash;
40use core::str;
41
42mod simd;
43use crate::simd::*;
44
45#[cfg(feature = "alloc")]
46extern crate alloc;
47
48#[cfg(feature = "std")]
49extern crate std;
50
51pub const DIGEST_LENGTH: usize = 20;
53
54#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
56pub struct Sha1 {
57 state: Sha1State,
58 blocks: Blocks,
59 len: u64,
60}
61
62struct Blocks {
63 len: u32,
64 block: [u8; 64],
65}
66
67#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Default)]
68struct Sha1State {
69 state: [u32; 5],
70}
71
72#[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Copy, Default)]
83pub struct Digest {
84 data: Sha1State,
85}
86
87const DEFAULT_STATE: Sha1State = Sha1State {
88 state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0],
89};
90
91#[inline(always)]
92fn as_block(input: &[u8]) -> &[u8; 64] {
93 unsafe {
94 assert!(input.len() == 64);
95 let arr: &[u8; 64] = &*(input.as_ptr() as *const [u8; 64]);
96 arr
97 }
98}
99
100impl Default for Sha1 {
101 fn default() -> Sha1 {
102 Sha1::new()
103 }
104}
105
106impl Sha1 {
107 pub fn new() -> Sha1 {
111 Sha1 {
112 state: DEFAULT_STATE,
113 len: 0,
114 blocks: Blocks {
115 len: 0,
116 block: [0; 64],
117 },
118 }
119 }
120
121 pub fn from<D: AsRef<[u8]>>(data: D) -> Sha1 {
126 let mut rv = Sha1::new();
127 rv.update(data.as_ref());
128 rv
129 }
130
131 pub fn reset(&mut self) {
133 self.state = DEFAULT_STATE;
134 self.len = 0;
135 self.blocks.len = 0;
136 }
137
138 pub fn update(&mut self, data: &[u8]) {
140 let len = &mut self.len;
141 let state = &mut self.state;
142 self.blocks.input(data, |block| {
143 *len += block.len() as u64;
144 state.process(block);
145 })
146 }
147
148 pub fn digest(&self) -> Digest {
150 let mut state = self.state;
151 let bits = (self.len + (self.blocks.len as u64)) * 8;
152 let extra = [
153 (bits >> 56) as u8,
154 (bits >> 48) as u8,
155 (bits >> 40) as u8,
156 (bits >> 32) as u8,
157 (bits >> 24) as u8,
158 (bits >> 16) as u8,
159 (bits >> 8) as u8,
160 (bits >> 0) as u8,
161 ];
162 let mut last = [0; 128];
163 let blocklen = self.blocks.len as usize;
164 last[..blocklen].clone_from_slice(&self.blocks.block[..blocklen]);
165 last[blocklen] = 0x80;
166
167 if blocklen < 56 {
168 last[56..64].clone_from_slice(&extra);
169 state.process(as_block(&last[0..64]));
170 } else {
171 last[120..128].clone_from_slice(&extra);
172 state.process(as_block(&last[0..64]));
173 state.process(as_block(&last[64..128]));
174 }
175
176 Digest { data: state }
177 }
178
179 #[cfg(feature = "alloc")]
183 pub fn hexdigest(&self) -> std::string::String {
184 use std::string::ToString;
185 self.digest().to_string()
186 }
187}
188
189impl Digest {
190 pub fn bytes(&self) -> [u8; DIGEST_LENGTH] {
192 [
193 (self.data.state[0] >> 24) as u8,
194 (self.data.state[0] >> 16) as u8,
195 (self.data.state[0] >> 8) as u8,
196 (self.data.state[0] >> 0) as u8,
197 (self.data.state[1] >> 24) as u8,
198 (self.data.state[1] >> 16) as u8,
199 (self.data.state[1] >> 8) as u8,
200 (self.data.state[1] >> 0) as u8,
201 (self.data.state[2] >> 24) as u8,
202 (self.data.state[2] >> 16) as u8,
203 (self.data.state[2] >> 8) as u8,
204 (self.data.state[2] >> 0) as u8,
205 (self.data.state[3] >> 24) as u8,
206 (self.data.state[3] >> 16) as u8,
207 (self.data.state[3] >> 8) as u8,
208 (self.data.state[3] >> 0) as u8,
209 (self.data.state[4] >> 24) as u8,
210 (self.data.state[4] >> 16) as u8,
211 (self.data.state[4] >> 8) as u8,
212 (self.data.state[4] >> 0) as u8,
213 ]
214 }
215}
216
217impl Blocks {
218 fn input<F>(&mut self, mut input: &[u8], mut f: F)
219 where
220 F: FnMut(&[u8; 64]),
221 {
222 if self.len > 0 {
223 let len = self.len as usize;
224 let amt = cmp::min(input.len(), self.block.len() - len);
225 self.block[len..len + amt].clone_from_slice(&input[..amt]);
226 if len + amt == self.block.len() {
227 f(&self.block);
228 self.len = 0;
229 input = &input[amt..];
230 } else {
231 self.len += amt as u32;
232 return;
233 }
234 }
235 assert_eq!(self.len, 0);
236 for chunk in input.chunks(64) {
237 if chunk.len() == 64 {
238 f(as_block(chunk))
239 } else {
240 self.block[..chunk.len()].clone_from_slice(chunk);
241 self.len = chunk.len() as u32;
242 }
243 }
244 }
245}
246
247const K0: u32 = 0x5A827999u32;
249const K1: u32 = 0x6ED9EBA1u32;
250const K2: u32 = 0x8F1BBCDCu32;
251const K3: u32 = 0xCA62C1D6u32;
252
253#[inline]
255fn sha1_first(w0: u32x4) -> u32 {
256 w0.0
257}
258
259#[inline]
261fn sha1_first_add(e: u32, w0: u32x4) -> u32x4 {
262 let u32x4(a, b, c, d) = w0;
263 u32x4(e.wrapping_add(a), b, c, d)
264}
265
266fn sha1msg1(a: u32x4, b: u32x4) -> u32x4 {
268 let u32x4(_, _, w2, w3) = a;
269 let u32x4(w4, w5, _, _) = b;
270 a ^ u32x4(w2, w3, w4, w5)
271}
272
273fn sha1msg2(a: u32x4, b: u32x4) -> u32x4 {
275 let u32x4(x0, x1, x2, x3) = a;
276 let u32x4(_, w13, w14, w15) = b;
277
278 let w16 = (x0 ^ w13).rotate_left(1);
279 let w17 = (x1 ^ w14).rotate_left(1);
280 let w18 = (x2 ^ w15).rotate_left(1);
281 let w19 = (x3 ^ w16).rotate_left(1);
282
283 u32x4(w16, w17, w18, w19)
284}
285
286#[inline]
288fn sha1_first_half(abcd: u32x4, msg: u32x4) -> u32x4 {
289 sha1_first_add(sha1_first(abcd).rotate_left(30), msg)
290}
291
292fn sha1_digest_round_x4(abcd: u32x4, work: u32x4, i: i8) -> u32x4 {
295 const K0V: u32x4 = u32x4(K0, K0, K0, K0);
296 const K1V: u32x4 = u32x4(K1, K1, K1, K1);
297 const K2V: u32x4 = u32x4(K2, K2, K2, K2);
298 const K3V: u32x4 = u32x4(K3, K3, K3, K3);
299
300 match i {
301 0 => sha1rnds4c(abcd, work + K0V),
302 1 => sha1rnds4p(abcd, work + K1V),
303 2 => sha1rnds4m(abcd, work + K2V),
304 3 => sha1rnds4p(abcd, work + K3V),
305 _ => panic!("unknown icosaround index"),
306 }
307}
308
309fn sha1rnds4c(abcd: u32x4, msg: u32x4) -> u32x4 {
311 let u32x4(mut a, mut b, mut c, mut d) = abcd;
312 let u32x4(t, u, v, w) = msg;
313 let mut e = 0u32;
314
315 macro_rules! bool3ary_202 {
316 ($a:expr, $b:expr, $c:expr) => {
317 ($c ^ ($a & ($b ^ $c)))
318 };
319 } e = e
322 .wrapping_add(a.rotate_left(5))
323 .wrapping_add(bool3ary_202!(b, c, d))
324 .wrapping_add(t);
325 b = b.rotate_left(30);
326
327 d = d
328 .wrapping_add(e.rotate_left(5))
329 .wrapping_add(bool3ary_202!(a, b, c))
330 .wrapping_add(u);
331 a = a.rotate_left(30);
332
333 c = c
334 .wrapping_add(d.rotate_left(5))
335 .wrapping_add(bool3ary_202!(e, a, b))
336 .wrapping_add(v);
337 e = e.rotate_left(30);
338
339 b = b
340 .wrapping_add(c.rotate_left(5))
341 .wrapping_add(bool3ary_202!(d, e, a))
342 .wrapping_add(w);
343 d = d.rotate_left(30);
344
345 u32x4(b, c, d, e)
346}
347
348fn sha1rnds4p(abcd: u32x4, msg: u32x4) -> u32x4 {
350 let u32x4(mut a, mut b, mut c, mut d) = abcd;
351 let u32x4(t, u, v, w) = msg;
352 let mut e = 0u32;
353
354 macro_rules! bool3ary_150 {
355 ($a:expr, $b:expr, $c:expr) => {
356 ($a ^ $b ^ $c)
357 };
358 } e = e
361 .wrapping_add(a.rotate_left(5))
362 .wrapping_add(bool3ary_150!(b, c, d))
363 .wrapping_add(t);
364 b = b.rotate_left(30);
365
366 d = d
367 .wrapping_add(e.rotate_left(5))
368 .wrapping_add(bool3ary_150!(a, b, c))
369 .wrapping_add(u);
370 a = a.rotate_left(30);
371
372 c = c
373 .wrapping_add(d.rotate_left(5))
374 .wrapping_add(bool3ary_150!(e, a, b))
375 .wrapping_add(v);
376 e = e.rotate_left(30);
377
378 b = b
379 .wrapping_add(c.rotate_left(5))
380 .wrapping_add(bool3ary_150!(d, e, a))
381 .wrapping_add(w);
382 d = d.rotate_left(30);
383
384 u32x4(b, c, d, e)
385}
386
387fn sha1rnds4m(abcd: u32x4, msg: u32x4) -> u32x4 {
389 let u32x4(mut a, mut b, mut c, mut d) = abcd;
390 let u32x4(t, u, v, w) = msg;
391 let mut e = 0u32;
392
393 macro_rules! bool3ary_232 {
394 ($a:expr, $b:expr, $c:expr) => {
395 ($a & $b) ^ ($a & $c) ^ ($b & $c)
396 };
397 } e = e
400 .wrapping_add(a.rotate_left(5))
401 .wrapping_add(bool3ary_232!(b, c, d))
402 .wrapping_add(t);
403 b = b.rotate_left(30);
404
405 d = d
406 .wrapping_add(e.rotate_left(5))
407 .wrapping_add(bool3ary_232!(a, b, c))
408 .wrapping_add(u);
409 a = a.rotate_left(30);
410
411 c = c
412 .wrapping_add(d.rotate_left(5))
413 .wrapping_add(bool3ary_232!(e, a, b))
414 .wrapping_add(v);
415 e = e.rotate_left(30);
416
417 b = b
418 .wrapping_add(c.rotate_left(5))
419 .wrapping_add(bool3ary_232!(d, e, a))
420 .wrapping_add(w);
421 d = d.rotate_left(30);
422
423 u32x4(b, c, d, e)
424}
425
426impl Sha1State {
427 fn process(&mut self, block: &[u8; 64]) {
428 let mut words = [0u32; 16];
429 for (i, word) in words.iter_mut().enumerate() {
430 let off = i * 4;
431 *word = (block[off + 3] as u32)
432 | ((block[off + 2] as u32) << 8)
433 | ((block[off + 1] as u32) << 16)
434 | ((block[off] as u32) << 24);
435 }
436 macro_rules! schedule {
437 ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {
438 sha1msg2(sha1msg1($v0, $v1) ^ $v2, $v3)
439 };
440 }
441
442 macro_rules! rounds4 {
443 ($h0:ident, $h1:ident, $wk:expr, $i:expr) => {
444 sha1_digest_round_x4($h0, sha1_first_half($h1, $wk), $i)
445 };
446 }
447
448 let mut h0 = u32x4(self.state[0], self.state[1], self.state[2], self.state[3]);
450 let mut w0 = u32x4(words[0], words[1], words[2], words[3]);
451 let mut h1 = sha1_digest_round_x4(h0, sha1_first_add(self.state[4], w0), 0);
452 let mut w1 = u32x4(words[4], words[5], words[6], words[7]);
453 h0 = rounds4!(h1, h0, w1, 0);
454 let mut w2 = u32x4(words[8], words[9], words[10], words[11]);
455 h1 = rounds4!(h0, h1, w2, 0);
456 let mut w3 = u32x4(words[12], words[13], words[14], words[15]);
457 h0 = rounds4!(h1, h0, w3, 0);
458 let mut w4 = schedule!(w0, w1, w2, w3);
459 h1 = rounds4!(h0, h1, w4, 0);
460
461 w0 = schedule!(w1, w2, w3, w4);
463 h0 = rounds4!(h1, h0, w0, 1);
464 w1 = schedule!(w2, w3, w4, w0);
465 h1 = rounds4!(h0, h1, w1, 1);
466 w2 = schedule!(w3, w4, w0, w1);
467 h0 = rounds4!(h1, h0, w2, 1);
468 w3 = schedule!(w4, w0, w1, w2);
469 h1 = rounds4!(h0, h1, w3, 1);
470 w4 = schedule!(w0, w1, w2, w3);
471 h0 = rounds4!(h1, h0, w4, 1);
472
473 w0 = schedule!(w1, w2, w3, w4);
475 h1 = rounds4!(h0, h1, w0, 2);
476 w1 = schedule!(w2, w3, w4, w0);
477 h0 = rounds4!(h1, h0, w1, 2);
478 w2 = schedule!(w3, w4, w0, w1);
479 h1 = rounds4!(h0, h1, w2, 2);
480 w3 = schedule!(w4, w0, w1, w2);
481 h0 = rounds4!(h1, h0, w3, 2);
482 w4 = schedule!(w0, w1, w2, w3);
483 h1 = rounds4!(h0, h1, w4, 2);
484
485 w0 = schedule!(w1, w2, w3, w4);
487 h0 = rounds4!(h1, h0, w0, 3);
488 w1 = schedule!(w2, w3, w4, w0);
489 h1 = rounds4!(h0, h1, w1, 3);
490 w2 = schedule!(w3, w4, w0, w1);
491 h0 = rounds4!(h1, h0, w2, 3);
492 w3 = schedule!(w4, w0, w1, w2);
493 h1 = rounds4!(h0, h1, w3, 3);
494 w4 = schedule!(w0, w1, w2, w3);
495 h0 = rounds4!(h1, h0, w4, 3);
496
497 let e = sha1_first(h1).rotate_left(30);
498 let u32x4(a, b, c, d) = h0;
499
500 self.state[0] = self.state[0].wrapping_add(a);
501 self.state[1] = self.state[1].wrapping_add(b);
502 self.state[2] = self.state[2].wrapping_add(c);
503 self.state[3] = self.state[3].wrapping_add(d);
504 self.state[4] = self.state[4].wrapping_add(e);
505 }
506}
507
508impl PartialEq for Blocks {
509 fn eq(&self, other: &Blocks) -> bool {
510 (self.len, &self.block[..]).eq(&(other.len, &other.block[..]))
511 }
512}
513
514impl Ord for Blocks {
515 fn cmp(&self, other: &Blocks) -> cmp::Ordering {
516 (self.len, &self.block[..]).cmp(&(other.len, &other.block[..]))
517 }
518}
519
520impl PartialOrd for Blocks {
521 fn partial_cmp(&self, other: &Blocks) -> Option<cmp::Ordering> {
522 Some(self.cmp(other))
523 }
524}
525
526impl Eq for Blocks {}
527
528impl hash::Hash for Blocks {
529 fn hash<H: hash::Hasher>(&self, state: &mut H) {
530 self.len.hash(state);
531 self.block.hash(state);
532 }
533}
534
535impl Clone for Blocks {
536 fn clone(&self) -> Blocks {
537 Blocks { ..*self }
538 }
539}
540
541#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
543pub struct DigestParseError(());
544
545impl fmt::Display for DigestParseError {
546 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
547 write!(f, "not a valid sha1 hash")
548 }
549}
550
551#[cfg(feature = "std")]
552impl std::error::Error for DigestParseError {
553 fn description(&self) -> &str {
554 "not a valid sha1 hash"
555 }
556}
557
558impl str::FromStr for Digest {
559 type Err = DigestParseError;
560
561 fn from_str(s: &str) -> Result<Digest, DigestParseError> {
562 if s.len() != 40 {
563 return Err(DigestParseError(()));
564 }
565 let mut rv: Digest = Default::default();
566 for idx in 0..5 {
567 rv.data.state[idx] =
568 r#try!(u32::from_str_radix(&s[idx * 8..idx * 8 + 8], 16)
569 .map_err(|_| DigestParseError(())));
570 }
571 Ok(rv)
572 }
573}
574
575impl fmt::Display for Digest {
576 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
577 for i in self.data.state.iter() {
578 r#try!(write!(f, "{:08x}", i));
579 }
580 Ok(())
581 }
582}
583
584impl fmt::Debug for Digest {
585 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
586 write!(f, "Digest {{ \"{}\" }}", self)
587 }
588}
589
590#[cfg(feature = "serde")]
591impl serde::ser::Serialize for Digest {
592 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
593 where
594 S: serde::ser::Serializer,
595 {
596 fn to_hex(num: u8) -> u8 {
597 b"0123456789abcdef"[num as usize]
598 }
599
600 let mut hex_str = [0u8; 40];
601 let mut c = 0;
602 for state in self.data.state.iter() {
603 for off in 0..4 {
604 let byte = (state >> (8 * (3 - off))) as u8;
605 hex_str[c] = to_hex(byte >> 4);
606 hex_str[c + 1] = to_hex(byte & 0xf);
607 c += 2;
608 }
609 }
610 serializer.serialize_str(unsafe { str::from_utf8_unchecked(&hex_str[..]) })
611 }
612}
613
614#[cfg(feature = "serde")]
615impl<'de> serde::de::Deserialize<'de> for Digest {
616 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
617 where
618 D: serde::de::Deserializer<'de>,
619 {
620 struct V;
621
622 impl<'de> serde::de::Visitor<'de> for V {
623 type Value = Digest;
624
625 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
626 formatter.write_str("SHA-1 hash")
627 }
628
629 fn visit_str<E>(self, value: &str) -> Result<Digest, E>
630 where
631 E: serde::de::Error,
632 {
633 value.parse().map_err(|_| {
634 serde::de::Error::invalid_value(serde::de::Unexpected::Str(value), &self)
635 })
636 }
637 }
638
639 deserializer.deserialize_str(V)
640 }
641}
642
643#[rustfmt::skip]
644#[cfg(test)]
645mod tests {
646 extern crate std;
647 extern crate alloc;
648 extern crate rand;
649 extern crate openssl;
650
651 use self::std::prelude::v1::*;
652
653 use crate::Sha1;
654
655 #[test]
656 fn test_simple() {
657 let mut m = Sha1::new();
658
659 let tests = [
660 ("The quick brown fox jumps over the lazy dog",
661 "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"),
662 ("The quick brown fox jumps over the lazy cog",
663 "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"),
664 ("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"),
665 ("testing\n", "9801739daae44ec5293d4e1f53d3f4d2d426d91c"),
666 ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
667 "025ecbd5d70f8fb3c5457cd96bab13fda305dc59"),
668 ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
669 "4300320394f7ee239bcdce7d3b8bcee173a0cd5c"),
670 ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
671 "cef734ba81a024479e09eb5a75b6ddae62e6abf1"),
672 ];
673
674 for &(s, ref h) in tests.iter() {
675 let data = s.as_bytes();
676
677 m.reset();
678 m.update(data);
679 let hh = m.digest().to_string();
680
681 assert_eq!(hh.len(), h.len());
682 assert_eq!(hh, *h);
683 }
684 }
685
686 #[test]
687 fn test_shortcuts() {
688 let s = Sha1::from("The quick brown fox jumps over the lazy dog");
689 assert_eq!(s.digest().to_string(), "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12");
690
691 let s = Sha1::from(&b"The quick brown fox jumps over the lazy dog"[..]);
692 assert_eq!(s.digest().to_string(), "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12");
693
694 #[cfg(feature="alloc")] {
695 let s = Sha1::from("The quick brown fox jumps over the lazy dog");
696 assert_eq!(s.hexdigest(), "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12");
697 }
698 }
699
700 #[test]
701 fn test_multiple_updates() {
702 let mut m = Sha1::new();
703
704 m.reset();
705 m.update("The quick brown ".as_bytes());
706 m.update("fox jumps over ".as_bytes());
707 m.update("the lazy dog".as_bytes());
708 let hh = m.digest().to_string();
709
710
711 let h = "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12";
712 assert_eq!(hh.len(), h.len());
713 assert_eq!(hh, &*h);
714 }
715
716 #[test]
717 fn test_sha1_loop() {
718 let mut m = Sha1::new();
719 let s = "The quick brown fox jumps over the lazy dog.";
720 let n = 1000u64;
721
722 for _ in 0..3 {
723 m.reset();
724 for _ in 0..n {
725 m.update(s.as_bytes());
726 }
727 assert_eq!(m.digest().to_string(),
728 "7ca27655f67fceaa78ed2e645a81c7f1d6e249d2");
729 }
730 }
731
732 #[test]
733 fn spray_and_pray() {
734 use self::rand::Rng;
735
736 let mut rng = rand::thread_rng();
737 let mut m = Sha1::new();
738 let mut bytes = [0; 512];
739
740 for _ in 0..20 {
741 let ty = openssl::hash::MessageDigest::sha1();
742 let mut r = openssl::hash::Hasher::new(ty).unwrap();
743 m.reset();
744 for _ in 0..50 {
745 let len = rng.gen::<usize>() % bytes.len();
746 rng.fill_bytes(&mut bytes[..len]);
747 m.update(&bytes[..len]);
748 r.update(&bytes[..len]).unwrap();
749 }
750 assert_eq!(r.finish().unwrap().as_ref(), &m.digest().bytes());
751 }
752 }
753
754 #[test]
755 #[cfg(feature="std")]
756 fn test_parse() {
757 use crate::Digest;
758 use std::error::Error;
759 let y: Digest = "2ef7bde608ce5404e97d5f042f95f89f1c232871".parse().unwrap();
760 assert_eq!(y.to_string(), "2ef7bde608ce5404e97d5f042f95f89f1c232871");
761 assert!("asdfasdf".parse::<Digest>().is_err());
762 assert_eq!("asdfasdf".parse::<Digest>()
763 .map_err(|x| x.description().to_string()).unwrap_err(), "not a valid sha1 hash");
764 }
765}
766
767#[rustfmt::skip]
768#[cfg(all(test, feature="serde"))]
769mod serde_tests {
770 extern crate std;
771 extern crate serde_json;
772
773 use self::std::prelude::v1::*;
774
775 use crate::{Sha1, Digest};
776
777 #[test]
778 fn test_to_json() {
779 let mut s = Sha1::new();
780 s.update(b"Hello World!");
781 let x = s.digest();
782 let y = serde_json::to_vec(&x).unwrap();
783 assert_eq!(y, &b"\"2ef7bde608ce5404e97d5f042f95f89f1c232871\""[..]);
784 }
785
786 #[test]
787 fn test_from_json() {
788 let y: Digest = serde_json::from_str("\"2ef7bde608ce5404e97d5f042f95f89f1c232871\"").unwrap();
789 assert_eq!(y.to_string(), "2ef7bde608ce5404e97d5f042f95f89f1c232871");
790 }
791}