Coverage Report

Created: 2026-05-16 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/sha1_smol-1.0.1/src/lib.rs
Line
Count
Source
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
37
use core::cmp;
38
use core::fmt;
39
use core::hash;
40
use core::str;
41
42
mod simd;
43
use crate::simd::*;
44
45
#[cfg(feature = "alloc")]
46
extern crate alloc;
47
48
#[cfg(feature = "std")]
49
extern crate std;
50
51
/// The length of a SHA1 digest in bytes
52
pub const DIGEST_LENGTH: usize = 20;
53
54
/// Represents a Sha1 hash object in memory.
55
#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
56
pub struct Sha1 {
57
    state: Sha1State,
58
    blocks: Blocks,
59
    len: u64,
60
}
61
62
struct Blocks {
63
    len: u32,
64
    block: [u8; 64],
65
}
66
67
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Default)]
68
struct 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)]
83
pub struct Digest {
84
    data: Sha1State,
85
}
86
87
const DEFAULT_STATE: Sha1State = Sha1State {
88
    state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0],
89
};
90
91
#[inline(always)]
92
0
fn as_block(input: &[u8]) -> &[u8; 64] {
93
    unsafe {
94
0
        assert!(input.len() == 64);
95
0
        let arr: &[u8; 64] = &*(input.as_ptr() as *const [u8; 64]);
96
0
        arr
97
    }
98
0
}
99
100
impl Default for Sha1 {
101
0
    fn default() -> Sha1 {
102
0
        Sha1::new()
103
0
    }
104
}
105
106
impl Sha1 {
107
    /// Creates an fresh sha1 hash object.
108
    ///
109
    /// This is equivalent to creating a hash with `Default::default`.
110
0
    pub fn new() -> Sha1 {
111
0
        Sha1 {
112
0
            state: DEFAULT_STATE,
113
0
            len: 0,
114
0
            blocks: Blocks {
115
0
                len: 0,
116
0
                block: [0; 64],
117
0
            },
118
0
        }
119
0
    }
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
0
    pub fn from<D: AsRef<[u8]>>(data: D) -> Sha1 {
126
0
        let mut rv = Sha1::new();
127
0
        rv.update(data.as_ref());
128
0
        rv
129
0
    }
130
131
    /// Resets the hash object to it's initial state.
132
0
    pub fn reset(&mut self) {
133
0
        self.state = DEFAULT_STATE;
134
0
        self.len = 0;
135
0
        self.blocks.len = 0;
136
0
    }
137
138
    /// Update hash with input data.
139
0
    pub fn update(&mut self, data: &[u8]) {
140
0
        let len = &mut self.len;
141
0
        let state = &mut self.state;
142
0
        self.blocks.input(data, |block| {
143
0
            *len += block.len() as u64;
144
0
            state.process(block);
145
0
        })
146
0
    }
147
148
    /// Retrieve digest result.
149
0
    pub fn digest(&self) -> Digest {
150
0
        let mut state = self.state;
151
0
        let bits = (self.len + (self.blocks.len as u64)) * 8;
152
0
        let extra = [
153
0
            (bits >> 56) as u8,
154
0
            (bits >> 48) as u8,
155
0
            (bits >> 40) as u8,
156
0
            (bits >> 32) as u8,
157
0
            (bits >> 24) as u8,
158
0
            (bits >> 16) as u8,
159
0
            (bits >> 8) as u8,
160
0
            (bits >> 0) as u8,
161
0
        ];
162
0
        let mut last = [0; 128];
163
0
        let blocklen = self.blocks.len as usize;
164
0
        last[..blocklen].clone_from_slice(&self.blocks.block[..blocklen]);
165
0
        last[blocklen] = 0x80;
166
167
0
        if blocklen < 56 {
168
0
            last[56..64].clone_from_slice(&extra);
169
0
            state.process(as_block(&last[0..64]));
170
0
        } else {
171
0
            last[120..128].clone_from_slice(&extra);
172
0
            state.process(as_block(&last[0..64]));
173
0
            state.process(as_block(&last[64..128]));
174
0
        }
175
176
0
        Digest { data: state }
177
0
    }
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
189
impl Digest {
190
    /// Returns the 160 bit (20 byte) digest as a byte array.
191
0
    pub fn bytes(&self) -> [u8; DIGEST_LENGTH] {
192
0
        [
193
0
            (self.data.state[0] >> 24) as u8,
194
0
            (self.data.state[0] >> 16) as u8,
195
0
            (self.data.state[0] >> 8) as u8,
196
0
            (self.data.state[0] >> 0) as u8,
197
0
            (self.data.state[1] >> 24) as u8,
198
0
            (self.data.state[1] >> 16) as u8,
199
0
            (self.data.state[1] >> 8) as u8,
200
0
            (self.data.state[1] >> 0) as u8,
201
0
            (self.data.state[2] >> 24) as u8,
202
0
            (self.data.state[2] >> 16) as u8,
203
0
            (self.data.state[2] >> 8) as u8,
204
0
            (self.data.state[2] >> 0) as u8,
205
0
            (self.data.state[3] >> 24) as u8,
206
0
            (self.data.state[3] >> 16) as u8,
207
0
            (self.data.state[3] >> 8) as u8,
208
0
            (self.data.state[3] >> 0) as u8,
209
0
            (self.data.state[4] >> 24) as u8,
210
0
            (self.data.state[4] >> 16) as u8,
211
0
            (self.data.state[4] >> 8) as u8,
212
0
            (self.data.state[4] >> 0) as u8,
213
0
        ]
214
0
    }
215
}
216
217
impl Blocks {
218
0
    fn input<F>(&mut self, mut input: &[u8], mut f: F)
219
0
    where
220
0
        F: FnMut(&[u8; 64]),
221
    {
222
0
        if self.len > 0 {
223
0
            let len = self.len as usize;
224
0
            let amt = cmp::min(input.len(), self.block.len() - len);
225
0
            self.block[len..len + amt].clone_from_slice(&input[..amt]);
226
0
            if len + amt == self.block.len() {
227
0
                f(&self.block);
228
0
                self.len = 0;
229
0
                input = &input[amt..];
230
0
            } else {
231
0
                self.len += amt as u32;
232
0
                return;
233
            }
234
0
        }
235
0
        assert_eq!(self.len, 0);
236
0
        for chunk in input.chunks(64) {
237
0
            if chunk.len() == 64 {
238
0
                f(as_block(chunk))
239
0
            } else {
240
0
                self.block[..chunk.len()].clone_from_slice(chunk);
241
0
                self.len = chunk.len() as u32;
242
0
            }
243
        }
244
0
    }
245
}
246
247
// Round key constants
248
const K0: u32 = 0x5A827999u32;
249
const K1: u32 = 0x6ED9EBA1u32;
250
const K2: u32 = 0x8F1BBCDCu32;
251
const K3: u32 = 0xCA62C1D6u32;
252
253
/// Not an intrinsic, but gets the first element of a vector.
254
#[inline]
255
0
fn sha1_first(w0: u32x4) -> u32 {
256
0
    w0.0
257
0
}
258
259
/// Not an intrinsic, but adds a word to the first element of a vector.
260
#[inline]
261
0
fn sha1_first_add(e: u32, w0: u32x4) -> u32x4 {
262
0
    let u32x4(a, b, c, d) = w0;
263
0
    u32x4(e.wrapping_add(a), b, c, d)
264
0
}
265
266
/// Emulates `llvm.x86.sha1msg1` intrinsic.
267
0
fn sha1msg1(a: u32x4, b: u32x4) -> u32x4 {
268
0
    let u32x4(_, _, w2, w3) = a;
269
0
    let u32x4(w4, w5, _, _) = b;
270
0
    a ^ u32x4(w2, w3, w4, w5)
271
0
}
272
273
/// Emulates `llvm.x86.sha1msg2` intrinsic.
274
0
fn sha1msg2(a: u32x4, b: u32x4) -> u32x4 {
275
0
    let u32x4(x0, x1, x2, x3) = a;
276
0
    let u32x4(_, w13, w14, w15) = b;
277
278
0
    let w16 = (x0 ^ w13).rotate_left(1);
279
0
    let w17 = (x1 ^ w14).rotate_left(1);
280
0
    let w18 = (x2 ^ w15).rotate_left(1);
281
0
    let w19 = (x3 ^ w16).rotate_left(1);
282
283
0
    u32x4(w16, w17, w18, w19)
284
0
}
285
286
/// Emulates `llvm.x86.sha1nexte` intrinsic.
287
#[inline]
288
0
fn sha1_first_half(abcd: u32x4, msg: u32x4) -> u32x4 {
289
0
    sha1_first_add(sha1_first(abcd).rotate_left(30), msg)
290
0
}
291
292
/// Emulates `llvm.x86.sha1rnds4` intrinsic.
293
/// Performs 4 rounds of the message block digest.
294
0
fn 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
0
    match i {
301
0
        0 => sha1rnds4c(abcd, work + K0V),
302
0
        1 => sha1rnds4p(abcd, work + K1V),
303
0
        2 => sha1rnds4m(abcd, work + K2V),
304
0
        3 => sha1rnds4p(abcd, work + K3V),
305
0
        _ => panic!("unknown icosaround index"),
306
    }
307
0
}
308
309
/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
310
0
fn sha1rnds4c(abcd: u32x4, msg: u32x4) -> u32x4 {
311
0
    let u32x4(mut a, mut b, mut c, mut d) = abcd;
312
0
    let u32x4(t, u, v, w) = msg;
313
0
    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
0
    e = e
322
0
        .wrapping_add(a.rotate_left(5))
323
0
        .wrapping_add(bool3ary_202!(b, c, d))
324
0
        .wrapping_add(t);
325
0
    b = b.rotate_left(30);
326
327
0
    d = d
328
0
        .wrapping_add(e.rotate_left(5))
329
0
        .wrapping_add(bool3ary_202!(a, b, c))
330
0
        .wrapping_add(u);
331
0
    a = a.rotate_left(30);
332
333
0
    c = c
334
0
        .wrapping_add(d.rotate_left(5))
335
0
        .wrapping_add(bool3ary_202!(e, a, b))
336
0
        .wrapping_add(v);
337
0
    e = e.rotate_left(30);
338
339
0
    b = b
340
0
        .wrapping_add(c.rotate_left(5))
341
0
        .wrapping_add(bool3ary_202!(d, e, a))
342
0
        .wrapping_add(w);
343
0
    d = d.rotate_left(30);
344
345
0
    u32x4(b, c, d, e)
346
0
}
347
348
/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
349
0
fn sha1rnds4p(abcd: u32x4, msg: u32x4) -> u32x4 {
350
0
    let u32x4(mut a, mut b, mut c, mut d) = abcd;
351
0
    let u32x4(t, u, v, w) = msg;
352
0
    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
0
    e = e
361
0
        .wrapping_add(a.rotate_left(5))
362
0
        .wrapping_add(bool3ary_150!(b, c, d))
363
0
        .wrapping_add(t);
364
0
    b = b.rotate_left(30);
365
366
0
    d = d
367
0
        .wrapping_add(e.rotate_left(5))
368
0
        .wrapping_add(bool3ary_150!(a, b, c))
369
0
        .wrapping_add(u);
370
0
    a = a.rotate_left(30);
371
372
0
    c = c
373
0
        .wrapping_add(d.rotate_left(5))
374
0
        .wrapping_add(bool3ary_150!(e, a, b))
375
0
        .wrapping_add(v);
376
0
    e = e.rotate_left(30);
377
378
0
    b = b
379
0
        .wrapping_add(c.rotate_left(5))
380
0
        .wrapping_add(bool3ary_150!(d, e, a))
381
0
        .wrapping_add(w);
382
0
    d = d.rotate_left(30);
383
384
0
    u32x4(b, c, d, e)
385
0
}
386
387
/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
388
0
fn sha1rnds4m(abcd: u32x4, msg: u32x4) -> u32x4 {
389
0
    let u32x4(mut a, mut b, mut c, mut d) = abcd;
390
0
    let u32x4(t, u, v, w) = msg;
391
0
    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
0
    e = e
400
0
        .wrapping_add(a.rotate_left(5))
401
0
        .wrapping_add(bool3ary_232!(b, c, d))
402
0
        .wrapping_add(t);
403
0
    b = b.rotate_left(30);
404
405
0
    d = d
406
0
        .wrapping_add(e.rotate_left(5))
407
0
        .wrapping_add(bool3ary_232!(a, b, c))
408
0
        .wrapping_add(u);
409
0
    a = a.rotate_left(30);
410
411
0
    c = c
412
0
        .wrapping_add(d.rotate_left(5))
413
0
        .wrapping_add(bool3ary_232!(e, a, b))
414
0
        .wrapping_add(v);
415
0
    e = e.rotate_left(30);
416
417
0
    b = b
418
0
        .wrapping_add(c.rotate_left(5))
419
0
        .wrapping_add(bool3ary_232!(d, e, a))
420
0
        .wrapping_add(w);
421
0
    d = d.rotate_left(30);
422
423
0
    u32x4(b, c, d, e)
424
0
}
425
426
impl Sha1State {
427
0
    fn process(&mut self, block: &[u8; 64]) {
428
0
        let mut words = [0u32; 16];
429
0
        for (i, word) in words.iter_mut().enumerate() {
430
0
            let off = i * 4;
431
0
            *word = (block[off + 3] as u32)
432
0
                | ((block[off + 2] as u32) << 8)
433
0
                | ((block[off + 1] as u32) << 16)
434
0
                | ((block[off] as u32) << 24);
435
0
        }
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
0
        let mut h0 = u32x4(self.state[0], self.state[1], self.state[2], self.state[3]);
450
0
        let mut w0 = u32x4(words[0], words[1], words[2], words[3]);
451
0
        let mut h1 = sha1_digest_round_x4(h0, sha1_first_add(self.state[4], w0), 0);
452
0
        let mut w1 = u32x4(words[4], words[5], words[6], words[7]);
453
0
        h0 = rounds4!(h1, h0, w1, 0);
454
0
        let mut w2 = u32x4(words[8], words[9], words[10], words[11]);
455
0
        h1 = rounds4!(h0, h1, w2, 0);
456
0
        let mut w3 = u32x4(words[12], words[13], words[14], words[15]);
457
0
        h0 = rounds4!(h1, h0, w3, 0);
458
0
        let mut w4 = schedule!(w0, w1, w2, w3);
459
0
        h1 = rounds4!(h0, h1, w4, 0);
460
461
        // Rounds 20..40
462
0
        w0 = schedule!(w1, w2, w3, w4);
463
0
        h0 = rounds4!(h1, h0, w0, 1);
464
0
        w1 = schedule!(w2, w3, w4, w0);
465
0
        h1 = rounds4!(h0, h1, w1, 1);
466
0
        w2 = schedule!(w3, w4, w0, w1);
467
0
        h0 = rounds4!(h1, h0, w2, 1);
468
0
        w3 = schedule!(w4, w0, w1, w2);
469
0
        h1 = rounds4!(h0, h1, w3, 1);
470
0
        w4 = schedule!(w0, w1, w2, w3);
471
0
        h0 = rounds4!(h1, h0, w4, 1);
472
473
        // Rounds 40..60
474
0
        w0 = schedule!(w1, w2, w3, w4);
475
0
        h1 = rounds4!(h0, h1, w0, 2);
476
0
        w1 = schedule!(w2, w3, w4, w0);
477
0
        h0 = rounds4!(h1, h0, w1, 2);
478
0
        w2 = schedule!(w3, w4, w0, w1);
479
0
        h1 = rounds4!(h0, h1, w2, 2);
480
0
        w3 = schedule!(w4, w0, w1, w2);
481
0
        h0 = rounds4!(h1, h0, w3, 2);
482
0
        w4 = schedule!(w0, w1, w2, w3);
483
0
        h1 = rounds4!(h0, h1, w4, 2);
484
485
        // Rounds 60..80
486
0
        w0 = schedule!(w1, w2, w3, w4);
487
0
        h0 = rounds4!(h1, h0, w0, 3);
488
0
        w1 = schedule!(w2, w3, w4, w0);
489
0
        h1 = rounds4!(h0, h1, w1, 3);
490
0
        w2 = schedule!(w3, w4, w0, w1);
491
0
        h0 = rounds4!(h1, h0, w2, 3);
492
0
        w3 = schedule!(w4, w0, w1, w2);
493
0
        h1 = rounds4!(h0, h1, w3, 3);
494
0
        w4 = schedule!(w0, w1, w2, w3);
495
0
        h0 = rounds4!(h1, h0, w4, 3);
496
497
0
        let e = sha1_first(h1).rotate_left(30);
498
0
        let u32x4(a, b, c, d) = h0;
499
500
0
        self.state[0] = self.state[0].wrapping_add(a);
501
0
        self.state[1] = self.state[1].wrapping_add(b);
502
0
        self.state[2] = self.state[2].wrapping_add(c);
503
0
        self.state[3] = self.state[3].wrapping_add(d);
504
0
        self.state[4] = self.state[4].wrapping_add(e);
505
0
    }
506
}
507
508
impl PartialEq for Blocks {
509
0
    fn eq(&self, other: &Blocks) -> bool {
510
0
        (self.len, &self.block[..]).eq(&(other.len, &other.block[..]))
511
0
    }
512
}
513
514
impl Ord for Blocks {
515
0
    fn cmp(&self, other: &Blocks) -> cmp::Ordering {
516
0
        (self.len, &self.block[..]).cmp(&(other.len, &other.block[..]))
517
0
    }
518
}
519
520
impl PartialOrd for Blocks {
521
0
    fn partial_cmp(&self, other: &Blocks) -> Option<cmp::Ordering> {
522
0
        Some(self.cmp(other))
523
0
    }
524
}
525
526
impl Eq for Blocks {}
527
528
impl hash::Hash for Blocks {
529
0
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
530
0
        self.len.hash(state);
531
0
        self.block.hash(state);
532
0
    }
533
}
534
535
impl Clone for Blocks {
536
0
    fn clone(&self) -> Blocks {
537
0
        Blocks { ..*self }
538
0
    }
539
}
540
541
/// Indicates that a digest couldn't be parsed.
542
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
543
pub struct DigestParseError(());
544
545
impl fmt::Display for DigestParseError {
546
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
547
0
        write!(f, "not a valid sha1 hash")
548
0
    }
549
}
550
551
#[cfg(feature = "std")]
552
impl std::error::Error for DigestParseError {
553
    fn description(&self) -> &str {
554
        "not a valid sha1 hash"
555
    }
556
}
557
558
impl str::FromStr for Digest {
559
    type Err = DigestParseError;
560
561
0
    fn from_str(s: &str) -> Result<Digest, DigestParseError> {
562
0
        if s.len() != 40 {
563
0
            return Err(DigestParseError(()));
564
0
        }
565
0
        let mut rv: Digest = Default::default();
566
0
        for idx in 0..5 {
567
0
            rv.data.state[idx] =
568
0
                r#try!(u32::from_str_radix(&s[idx * 8..idx * 8 + 8], 16)
569
0
                    .map_err(|_| DigestParseError(())));
570
        }
571
0
        Ok(rv)
572
0
    }
573
}
574
575
impl fmt::Display for Digest {
576
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
577
0
        for i in self.data.state.iter() {
578
0
            r#try!(write!(f, "{:08x}", i));
579
        }
580
0
        Ok(())
581
0
    }
582
}
583
584
impl fmt::Debug for Digest {
585
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
586
0
        write!(f, "Digest {{ \"{}\" }}", self)
587
0
    }
588
}
589
590
#[cfg(feature = "serde")]
591
impl 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")]
615
impl<'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)]
645
mod 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"))]
769
mod 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
}