1use core::convert::TryInto;
7use core::ops::Index;
8use core::slice::SliceIndex;
9use core::{cmp, str};
10
11use crate::{FromSliceError, HashEngine as _};
12
13crate::internal_macros::hash_type! {
14 160,
15 false,
16 "Output of the SHA1 hash function.",
17 "crate::util::json_hex_string::len_20"
18}
19
20fn from_engine(mut e: HashEngine) -> Hash {
21 let data_len = e.length as u64;
23
24 let zeroes = [0; BLOCK_SIZE - 8];
25 e.input(&[0x80]);
26 if e.length % BLOCK_SIZE > zeroes.len() {
27 e.input(&zeroes);
28 }
29 let pad_length = zeroes.len() - (e.length % BLOCK_SIZE);
30 e.input(&zeroes[..pad_length]);
31 debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len());
32
33 e.input(&(8 * data_len).to_be_bytes());
34 debug_assert_eq!(e.length % BLOCK_SIZE, 0);
35
36 Hash(e.midstate())
37}
38
39const BLOCK_SIZE: usize = 64;
40
41#[derive(Clone)]
43pub struct HashEngine {
44 buffer: [u8; BLOCK_SIZE],
45 h: [u32; 5],
46 length: usize,
47}
48
49impl Default for HashEngine {
50 fn default() -> Self {
51 HashEngine {
52 h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0],
53 length: 0,
54 buffer: [0; BLOCK_SIZE],
55 }
56 }
57}
58
59impl crate::HashEngine for HashEngine {
60 type MidState = [u8; 20];
61
62 #[cfg(not(hashes_fuzz))]
63 fn midstate(&self) -> [u8; 20] {
64 let mut ret = [0; 20];
65 for (val, ret_bytes) in self.h.iter().zip(ret.chunks_exact_mut(4)) {
66 ret_bytes.copy_from_slice(&val.to_be_bytes())
67 }
68 ret
69 }
70
71 #[cfg(hashes_fuzz)]
72 fn midstate(&self) -> [u8; 20] {
73 let mut ret = [0; 20];
74 ret.copy_from_slice(&self.buffer[..20]);
75 ret
76 }
77
78 const BLOCK_SIZE: usize = 64;
79
80 fn n_bytes_hashed(&self) -> usize { self.length }
81
82 engine_input_impl!();
83}
84
85impl HashEngine {
86 fn process_block(&mut self) {
88 debug_assert_eq!(self.buffer.len(), BLOCK_SIZE);
89
90 let mut w = [0u32; 80];
91 for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.chunks_exact(4)) {
92 *w_val = u32::from_be_bytes(buff_bytes.try_into().expect("4 bytes slice"))
93 }
94 for i in 16..80 {
95 w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
96 }
97
98 let mut a = self.h[0];
99 let mut b = self.h[1];
100 let mut c = self.h[2];
101 let mut d = self.h[3];
102 let mut e = self.h[4];
103
104 for (i, &wi) in w.iter().enumerate() {
105 let (f, k) = match i {
106 0...19 => ((b & c) | (!b & d), 0x5a827999),
107 20...39 => (b ^ c ^ d, 0x6ed9eba1),
108 40...59 => ((b & c) | (b & d) | (c & d), 0x8f1bbcdc),
109 60...79 => (b ^ c ^ d, 0xca62c1d6),
110 _ => unreachable!(),
111 };
112
113 let new_a =
114 a.rotate_left(5).wrapping_add(f).wrapping_add(e).wrapping_add(k).wrapping_add(wi);
115 e = d;
116 d = c;
117 c = b.rotate_left(30);
118 b = a;
119 a = new_a;
120 }
121
122 self.h[0] = self.h[0].wrapping_add(a);
123 self.h[1] = self.h[1].wrapping_add(b);
124 self.h[2] = self.h[2].wrapping_add(c);
125 self.h[3] = self.h[3].wrapping_add(d);
126 self.h[4] = self.h[4].wrapping_add(e);
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 #[test]
133 #[cfg(feature = "alloc")]
134 fn test() {
135 use crate::{sha1, Hash, HashEngine};
136
137 #[derive(Clone)]
138 struct Test {
139 input: &'static str,
140 output: Vec<u8>,
141 output_str: &'static str,
142 }
143
144 #[rustfmt::skip]
145 let tests = vec![
146 Test {
148 input: "",
149 output: vec![
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: vec![
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: vec![
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 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[..], &test.output[..]);
187 assert_eq!(&hash.to_string(), &test.output_str);
188
189 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.as_byte_array(), test.output.as_slice());
197 }
198 }
199
200 #[cfg(feature = "serde")]
201 #[test]
202 fn sha1_serde() {
203 use serde_test::{assert_tokens, Configure, Token};
204
205 use crate::{sha1, Hash};
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}