sha1_smol/
lib.rs

1//! A minimal implementation of SHA1 for rust.
2//!
3//! This implementation supports no_std which is the default mode.  The
4//! following features are available and can be optionally enabled:
5//!
6//! * ``serde``: when enabled the `Digest` type can be serialized.
7//! * ``std``: when enabled errors from this library implement `std::error::Error`
8//!   and the `hexdigest` shortcut becomes available.
9//!
10//! ## Example
11//!
12//! ```rust
13//! # fn main() {
14//!
15//! let mut m = sha1_smol::Sha1::new();
16//! m.update(b"Hello World!");
17//! assert_eq!(m.digest().to_string(),
18//!            "2ef7bde608ce5404e97d5f042f95f89f1c232871");
19//! # }
20//! ```
21//!
22//! The sha1 object can be updated multiple times.  If you only need to use
23//! it once you can also use shortcuts (requires std):
24//!
25//! ```
26//! # trait X { fn hexdigest(&self) -> &'static str { "2ef7bde608ce5404e97d5f042f95f89f1c232871" }}
27//! # impl X for sha1_smol::Sha1 {}
28//! # fn main() {
29//! assert_eq!(sha1_smol::Sha1::from("Hello World!").hexdigest(),
30//!            "2ef7bde608ce5404e97d5f042f95f89f1c232871");
31//! # }
32//! ```
33
34#![no_std]
35#![deny(missing_docs)]
36#![allow(deprecated)]
37#![allow(clippy::double_parens)]
38#![allow(clippy::identity_op)]
39
40use core::cmp;
41use core::fmt;
42use core::hash;
43use core::str;
44
45mod simd;
46use crate::simd::*;
47
48#[cfg(feature = "std")]
49extern crate std;
50
51/// The length of a SHA1 digest in bytes
52pub const DIGEST_LENGTH: usize = 20;
53
54/// Represents a Sha1 hash object in memory.
55#[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/// Digest generated from a `Sha1` instance.
73///
74/// A digest can be formatted to view the digest as a hex string, or the bytes
75/// can be extracted for later processing.
76///
77/// To retrieve a hex string result call `to_string` on it (requires that std
78/// is available).
79///
80/// If the `serde` feature is enabled a digest can also be serialized and
81/// deserialized.  Likewise a digest can be parsed from a hex string.
82#[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    /// Creates an fresh sha1 hash object.
108    ///
109    /// This is equivalent to creating a hash with `Default::default`.
110    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    /// Shortcut to create a sha1 from some bytes.
122    ///
123    /// This also lets you create a hash from a utf-8 string.  This is equivalent
124    /// to making a new Sha1 object and calling `update` on it once.
125    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    /// Resets the hash object to it's initial state.
132    pub fn reset(&mut self) {
133        self.state = DEFAULT_STATE;
134        self.len = 0;
135        self.blocks.len = 0;
136    }
137
138    /// Update hash with input data.
139    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    /// Retrieve digest result.
149    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    /// Retrieve the digest result as hex string directly.
180    ///
181    /// (The function is only available if the `std` feature is enabled)
182    #[cfg(feature = "std")]
183    pub fn hexdigest(&self) -> std::string::String {
184        use std::string::ToString;
185        self.digest().to_string()
186    }
187}
188
189impl Digest {
190    /// Returns the 160 bit (20 byte) digest as a byte array.
191    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
247// Round key constants
248const K0: u32 = 0x5A827999u32;
249const K1: u32 = 0x6ED9EBA1u32;
250const K2: u32 = 0x8F1BBCDCu32;
251const K3: u32 = 0xCA62C1D6u32;
252
253/// Not an intrinsic, but gets the first element of a vector.
254#[inline]
255fn sha1_first(w0: u32x4) -> u32 {
256    w0.0
257}
258
259/// Not an intrinsic, but adds a word to the first element of a vector.
260#[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
266/// Emulates `llvm.x86.sha1msg1` intrinsic.
267fn 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
273/// Emulates `llvm.x86.sha1msg2` intrinsic.
274fn 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/// Emulates `llvm.x86.sha1nexte` intrinsic.
287#[inline]
288fn sha1_first_half(abcd: u32x4, msg: u32x4) -> u32x4 {
289    sha1_first_add(sha1_first(abcd).rotate_left(30), msg)
290}
291
292/// Emulates `llvm.x86.sha1rnds4` intrinsic.
293/// Performs 4 rounds of the message block digest.
294fn 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
309/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
310fn 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    } // Choose, MD5F, SHA1C
320
321    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
348/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
349fn 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    } // Parity, XOR, MD5H, SHA1P
359
360    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
387/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
388fn 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    } // Majority, SHA1M
398
399    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        // Rounds 0..20
449        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        // Rounds 20..40
462        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        // Rounds 40..60
474        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        // Rounds 60..80
486        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/// Indicates that a digest couldn't be parsed.
542#[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 rand;
648    extern crate openssl;
649
650    use self::std::prelude::v1::*;
651
652    use crate::Sha1;
653
654    #[test]
655    fn test_simple() {
656        let mut m = Sha1::new();
657
658        let tests = [
659            ("The quick brown fox jumps over the lazy dog",
660             "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"),
661            ("The quick brown fox jumps over the lazy cog",
662             "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"),
663            ("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"),
664            ("testing\n", "9801739daae44ec5293d4e1f53d3f4d2d426d91c"),
665            ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
666             "025ecbd5d70f8fb3c5457cd96bab13fda305dc59"),
667            ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
668             "4300320394f7ee239bcdce7d3b8bcee173a0cd5c"),
669            ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
670             "cef734ba81a024479e09eb5a75b6ddae62e6abf1"),
671        ];
672
673        for &(s, ref h) in tests.iter() {
674            let data = s.as_bytes();
675
676            m.reset();
677            m.update(data);
678            let hh = m.digest().to_string();
679
680            assert_eq!(hh.len(), h.len());
681            assert_eq!(hh, *h);
682        }
683    }
684
685    #[test]
686    fn test_shortcuts() {
687        let s = Sha1::from("The quick brown fox jumps over the lazy dog");
688        assert_eq!(s.digest().to_string(), "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12");
689
690        let s = Sha1::from(&b"The quick brown fox jumps over the lazy dog"[..]);
691        assert_eq!(s.digest().to_string(), "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12");
692
693        #[cfg(feature="std")] {
694            let s = Sha1::from("The quick brown fox jumps over the lazy dog");
695            assert_eq!(s.hexdigest(), "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12");
696        }
697    }
698
699    #[test]
700    fn test_multiple_updates() {
701        let mut m = Sha1::new();
702
703        m.reset();
704        m.update("The quick brown ".as_bytes());
705        m.update("fox jumps over ".as_bytes());
706        m.update("the lazy dog".as_bytes());
707        let hh = m.digest().to_string();
708
709
710        let h = "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12";
711        assert_eq!(hh.len(), h.len());
712        assert_eq!(hh, &*h);
713    }
714
715    #[test]
716    fn test_sha1_loop() {
717        let mut m = Sha1::new();
718        let s = "The quick brown fox jumps over the lazy dog.";
719        let n = 1000u64;
720
721        for _ in 0..3 {
722            m.reset();
723            for _ in 0..n {
724                m.update(s.as_bytes());
725            }
726            assert_eq!(m.digest().to_string(),
727                       "7ca27655f67fceaa78ed2e645a81c7f1d6e249d2");
728        }
729    }
730
731    #[test]
732    fn spray_and_pray() {
733        use self::rand::Rng;
734
735        let mut rng = rand::thread_rng();
736        let mut m = Sha1::new();
737        let mut bytes = [0; 512];
738
739        for _ in 0..20 {
740            let ty = openssl::hash::MessageDigest::sha1();
741            let mut r = openssl::hash::Hasher::new(ty).unwrap();
742            m.reset();
743            for _ in 0..50 {
744                let len = rng.gen::<usize>() % bytes.len();
745                rng.fill_bytes(&mut bytes[..len]);
746                m.update(&bytes[..len]);
747                r.update(&bytes[..len]).unwrap();
748            }
749            assert_eq!(r.finish().unwrap().as_ref(), &m.digest().bytes());
750        }
751    }
752
753    #[test]
754    #[cfg(feature="std")]
755    fn test_parse() {
756        use crate::Digest;
757        use std::error::Error;
758        let y: Digest = "2ef7bde608ce5404e97d5f042f95f89f1c232871".parse().unwrap();
759        assert_eq!(y.to_string(), "2ef7bde608ce5404e97d5f042f95f89f1c232871");
760        assert!("asdfasdf".parse::<Digest>().is_err());
761        assert_eq!("asdfasdf".parse::<Digest>()
762            .map_err(|x| x.description().to_string()).unwrap_err(), "not a valid sha1 hash");
763    }
764}
765
766#[rustfmt::skip]
767#[cfg(all(test, feature="serde"))]
768mod serde_tests {
769    extern crate std;
770    extern crate serde_json;
771
772    use self::std::prelude::v1::*;
773
774    use crate::{Sha1, Digest};
775
776    #[test]
777    fn test_to_json() {
778        let mut s = Sha1::new();
779        s.update(b"Hello World!");
780        let x = s.digest();
781        let y = serde_json::to_vec(&x).unwrap();
782        assert_eq!(y, &b"\"2ef7bde608ce5404e97d5f042f95f89f1c232871\""[..]);
783    }
784
785    #[test]
786    fn test_from_json() {
787        let y: Digest = serde_json::from_str("\"2ef7bde608ce5404e97d5f042f95f89f1c232871\"").unwrap();
788        assert_eq!(y.to_string(), "2ef7bde608ce5404e97d5f042f95f89f1c232871");
789    }
790}