bitcoin_hashes/
sha1.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! SHA1 implementation.
4
5use core::cmp;
6
7use crate::{incomplete_block_len, HashEngine as _};
8
9crate::internal_macros::general_hash_type! {
10    160,
11    false,
12    "Output of the SHA1 hash function."
13}
14
15fn from_engine(mut e: HashEngine) -> Hash {
16    // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining
17    let n_bytes_hashed = e.bytes_hashed;
18
19    let zeroes = [0; BLOCK_SIZE - 8];
20    e.input(&[0x80]);
21    if incomplete_block_len(&e) > zeroes.len() {
22        e.input(&zeroes);
23    }
24    let pad_length = zeroes.len() - incomplete_block_len(&e);
25    e.input(&zeroes[..pad_length]);
26    debug_assert_eq!(incomplete_block_len(&e), zeroes.len());
27
28    e.input(&(8 * n_bytes_hashed).to_be_bytes());
29    debug_assert_eq!(incomplete_block_len(&e), 0);
30
31    Hash(e.midstate())
32}
33
34const BLOCK_SIZE: usize = 64;
35
36/// Engine to compute SHA1 hash function.
37#[derive(Clone)]
38pub struct HashEngine {
39    buffer: [u8; BLOCK_SIZE],
40    h: [u32; 5],
41    bytes_hashed: u64,
42}
43
44impl HashEngine {
45    /// Constructs a new SHA1 hash engine.
46    pub const fn new() -> Self {
47        Self {
48            h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0],
49            bytes_hashed: 0,
50            buffer: [0; BLOCK_SIZE],
51        }
52    }
53
54    #[cfg(not(hashes_fuzz))]
55    pub(crate) fn midstate(&self) -> [u8; 20] {
56        let mut ret = [0; 20];
57        for (val, ret_bytes) in self.h.iter().zip(ret.chunks_exact_mut(4)) {
58            ret_bytes.copy_from_slice(&val.to_be_bytes())
59        }
60        ret
61    }
62
63    #[cfg(hashes_fuzz)]
64    pub(crate) fn midstate(&self) -> [u8; 20] {
65        let mut ret = [0; 20];
66        ret.copy_from_slice(&self.buffer[..20]);
67        ret
68    }
69}
70
71impl Default for HashEngine {
72    fn default() -> Self { Self::new() }
73}
74
75impl crate::HashEngine for HashEngine {
76    const BLOCK_SIZE: usize = 64;
77
78    fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }
79
80    crate::internal_macros::engine_input_impl!();
81}
82
83impl HashEngine {
84    // Basic unoptimized algorithm from Wikipedia
85    fn process_block(&mut self) {
86        debug_assert_eq!(self.buffer.len(), BLOCK_SIZE);
87
88        let mut w = [0u32; 80];
89        for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.chunks_exact(4)) {
90            *w_val = u32::from_be_bytes(buff_bytes.try_into().expect("4 bytes slice"))
91        }
92        for i in 16..80 {
93            w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
94        }
95
96        let mut a = self.h[0];
97        let mut b = self.h[1];
98        let mut c = self.h[2];
99        let mut d = self.h[3];
100        let mut e = self.h[4];
101
102        for (i, &wi) in w.iter().enumerate() {
103            let (f, k) = match i {
104                0..=19 => ((b & c) | (!b & d), 0x5a827999),
105                20..=39 => (b ^ c ^ d, 0x6ed9eba1),
106                40..=59 => ((b & c) | (b & d) | (c & d), 0x8f1bbcdc),
107                60..=79 => (b ^ c ^ d, 0xca62c1d6),
108                _ => unreachable!(),
109            };
110
111            let new_a =
112                a.rotate_left(5).wrapping_add(f).wrapping_add(e).wrapping_add(k).wrapping_add(wi);
113            e = d;
114            d = c;
115            c = b.rotate_left(30);
116            b = a;
117            a = new_a;
118        }
119
120        self.h[0] = self.h[0].wrapping_add(a);
121        self.h[1] = self.h[1].wrapping_add(b);
122        self.h[2] = self.h[2].wrapping_add(c);
123        self.h[3] = self.h[3].wrapping_add(d);
124        self.h[4] = self.h[4].wrapping_add(e);
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    #[test]
131    #[cfg(feature = "alloc")]
132    fn test() {
133        use alloc::string::ToString;
134
135        use crate::{sha1, HashEngine};
136
137        #[derive(Clone)]
138        struct Test {
139            input: &'static str,
140            output: [u8; 20],
141            output_str: &'static str,
142        }
143
144        #[rustfmt::skip]
145        let tests = [
146            // Examples from wikipedia
147            Test {
148                input: "",
149                output: [
150                    0xda, 0x39, 0xa3, 0xee,
151                    0x5e, 0x6b, 0x4b, 0x0d,
152                    0x32, 0x55, 0xbf, 0xef,
153                    0x95, 0x60, 0x18, 0x90,
154                    0xaf, 0xd8, 0x07, 0x09,
155                ],
156                output_str: "da39a3ee5e6b4b0d3255bfef95601890afd80709"
157            },
158            Test {
159                input: "The quick brown fox jumps over the lazy dog",
160                output: [
161                    0x2f, 0xd4, 0xe1, 0xc6,
162                    0x7a, 0x2d, 0x28, 0xfc,
163                    0xed, 0x84, 0x9e, 0xe1,
164                    0xbb, 0x76, 0xe7, 0x39,
165                    0x1b, 0x93, 0xeb, 0x12,
166                ],
167                output_str: "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
168            },
169            Test {
170                input: "The quick brown fox jumps over the lazy cog",
171                output: [
172                    0xde, 0x9f, 0x2c, 0x7f,
173                    0xd2, 0x5e, 0x1b, 0x3a,
174                    0xfa, 0xd3, 0xe8, 0x5a,
175                    0x0b, 0xd1, 0x7d, 0x9b,
176                    0x10, 0x0d, 0xb4, 0xb3,
177                ],
178                output_str: "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3",
179            },
180        ];
181
182        for test in tests {
183            // Hash through high-level API, check hex encoding/decoding
184            let hash = sha1::Hash::hash(test.input.as_bytes());
185            assert_eq!(hash, test.output_str.parse::<sha1::Hash>().expect("parse hex"));
186            assert_eq!(hash.as_byte_array(), &test.output);
187            assert_eq!(hash.to_string(), test.output_str);
188
189            // Hash through engine, checking that we can input byte by byte
190            let mut engine = sha1::Hash::engine();
191            for ch in test.input.as_bytes() {
192                engine.input(&[*ch]);
193            }
194            let manual_hash = sha1::Hash::from_engine(engine);
195            assert_eq!(hash, manual_hash);
196            assert_eq!(hash.to_byte_array(), test.output);
197        }
198    }
199
200    #[test]
201    #[cfg(feature = "serde")]
202    fn sha1_serde() {
203        use serde_test::{assert_tokens, Configure, Token};
204
205        use crate::sha1;
206
207        #[rustfmt::skip]
208        static HASH_BYTES: [u8; 20] = [
209            0x13, 0x20, 0x72, 0xdf,
210            0x69, 0x09, 0x33, 0x83,
211            0x5e, 0xb8, 0xb6, 0xad,
212            0x0b, 0x77, 0xe7, 0xb6,
213            0xf1, 0x4a, 0xca, 0xd7,
214        ];
215
216        let hash = sha1::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
217        assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
218        assert_tokens(&hash.readable(), &[Token::Str("132072df690933835eb8b6ad0b77e7b6f14acad7")]);
219    }
220}
221
222#[cfg(bench)]
223mod benches {
224    use test::Bencher;
225
226    use crate::{sha1, Hash, HashEngine};
227
228    #[bench]
229    pub fn sha1_10(bh: &mut Bencher) {
230        let mut engine = sha1::Hash::engine();
231        let bytes = [1u8; 10];
232        bh.iter(|| {
233            engine.input(&bytes);
234        });
235        bh.bytes = bytes.len() as u64;
236    }
237
238    #[bench]
239    pub fn sha1_1k(bh: &mut Bencher) {
240        let mut engine = sha1::Hash::engine();
241        let bytes = [1u8; 1024];
242        bh.iter(|| {
243            engine.input(&bytes);
244        });
245        bh.bytes = bytes.len() as u64;
246    }
247
248    #[bench]
249    pub fn sha1_64k(bh: &mut Bencher) {
250        let mut engine = sha1::Hash::engine();
251        let bytes = [1u8; 65536];
252        bh.iter(|| {
253            engine.input(&bytes);
254        });
255        bh.bytes = bytes.len() as u64;
256    }
257}