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//! let mut m = sha1_smol::Sha1::new();
14//! m.update(b"Hello World!");
15//! assert_eq!(m.digest().to_string(),
16//!            "2ef7bde608ce5404e97d5f042f95f89f1c232871");
17//! ```
18//!
19//! The sha1 object can be updated multiple times.  If you only need to use
20//! it once you can also use shortcuts (requires std):
21//!
22//! ```
23//! # trait X { fn hexdigest(&self) -> &'static str { "2ef7bde608ce5404e97d5f042f95f89f1c232871" }}
24//! # impl X for sha1_smol::Sha1 {}
25//! # fn main() {
26//! assert_eq!(sha1_smol::Sha1::from("Hello World!").hexdigest(),
27//!            "2ef7bde608ce5404e97d5f042f95f89f1c232871");
28//! # }
29//! ```
30
31#![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
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 `alloc` feature is enabled)
182    #[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    /// 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 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}