1use crate::Hasher;
7
8const H0: [u32; 5] = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
9
10#[derive(Clone)]
17pub struct Sha1 {
18 state: [u32; 5],
19 buf: [u8; 64],
20 buf_len: usize,
21 total_len: u64,
22}
23
24fn compress(state: &mut [u32; 5], block: &[u8]) {
25 let mut w = [0u32; 80];
26 for i in 0..16 {
27 w[i] = u32::from_be_bytes([block[4 * i], block[4 * i + 1], block[4 * i + 2], block[4 * i + 3]]);
28 }
29 for i in 16..80 {
30 w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
31 }
32
33 let mut a = state[0];
34 let mut b = state[1];
35 let mut c = state[2];
36 let mut d = state[3];
37 let mut e = state[4];
38
39 for i in 0..80 {
40 let (f, k) = match i {
41 0..=19 => ((b & c) | ((!b) & d), 0x5A827999u32),
42 20..=39 => (b ^ c ^ d, 0x6ED9EBA1u32),
43 40..=59 => ((b & c) | (b & d) | (c & d), 0x8F1BBCDCu32),
44 _ => (b ^ c ^ d, 0xCA62C1D6u32),
45 };
46 let temp = a
47 .rotate_left(5)
48 .wrapping_add(f)
49 .wrapping_add(e)
50 .wrapping_add(k)
51 .wrapping_add(w[i]);
52 e = d;
53 d = c;
54 c = b.rotate_left(30);
55 b = a;
56 a = temp;
57 }
58
59 state[0] = state[0].wrapping_add(a);
60 state[1] = state[1].wrapping_add(b);
61 state[2] = state[2].wrapping_add(c);
62 state[3] = state[3].wrapping_add(d);
63 state[4] = state[4].wrapping_add(e);
64}
65
66impl Hasher for Sha1 {
67 const OUTPUT_LEN: usize = 20;
68 const BLOCK_LEN: usize = 64;
69
70 fn new() -> Self {
71 Self {
72 state: H0,
73 buf: [0u8; 64],
74 buf_len: 0,
75 total_len: 0,
76 }
77 }
78
79 fn update(&mut self, data: &[u8]) {
80 let mut pos = 0;
81 self.total_len += data.len() as u64;
82
83 if self.buf_len > 0 {
84 let need = 64 - self.buf_len;
85 let take = need.min(data.len());
86 self.buf[self.buf_len..self.buf_len + take].copy_from_slice(&data[..take]);
87 self.buf_len += take;
88 pos = take;
89 if self.buf_len == 64 {
90 let block = self.buf;
91 compress(&mut self.state, &block);
92 self.buf_len = 0;
93 }
94 }
95
96 while pos + 64 <= data.len() {
97 compress(&mut self.state, &data[pos..pos + 64]);
98 pos += 64;
99 }
100
101 if pos < data.len() {
102 let remaining = data.len() - pos;
103 self.buf[..remaining].copy_from_slice(&data[pos..]);
104 self.buf_len = remaining;
105 }
106 }
107
108 fn finalize(self) -> Vec<u8> {
109 let mut out = vec![0u8; 20];
110 self.finalize_into(&mut out);
111 out
112 }
113
114 fn finalize_into(mut self, out: &mut [u8]) {
115 let bit_len = self.total_len * 8;
116 let mut pad = [0u8; 72]; pad[0] = 0x80;
119 let pad_len = if self.buf_len < 56 {
120 56 - self.buf_len
121 } else {
122 120 - self.buf_len
123 };
124 self.update(&pad[..pad_len]);
125 self.update(&bit_len.to_be_bytes());
126
127 for (i, word) in self.state.iter().enumerate() {
128 let bytes = word.to_be_bytes();
129 let start = i * 4;
130 if start + 4 <= out.len() {
131 out[start..start + 4].copy_from_slice(&bytes);
132 } else if start < out.len() {
133 let end = out.len() - start;
134 out[start..].copy_from_slice(&bytes[..end]);
135 }
136 }
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143 use crate::Hasher;
144
145 #[test]
146 fn test_sha1_empty() {
147 let digest = Sha1::hash(b"");
148 let expected: [u8; 20] = [
149 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8,
150 0x07, 0x09,
151 ];
152 assert_eq!(&digest[..], &expected[..]);
153 }
154
155 #[test]
156 fn test_sha1_abc() {
157 let digest = Sha1::hash(b"abc");
158 let expected: [u8; 20] = [
159 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0,
160 0xd8, 0x9d,
161 ];
162 assert_eq!(&digest[..], &expected[..]);
163 }
164}