]>
Commit | Line | Data |
---|---|---|
353b0b11 FG |
1 | #![allow(clippy::many_single_char_names)] |
2 | ||
3 | pub const fn sha1(data: &ConstBuffer) -> Digest { | |
4 | let state: [u32; 5] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; | |
5 | let len: u64 = 0; | |
6 | let blocks = Blocks { len: 0, data: [0; 64] }; | |
7 | let (blocks, len, state) = process_blocks(blocks, data, len, state); | |
8 | digest(state, len, blocks) | |
9 | } | |
10 | ||
11 | const BUFFER_SIZE: usize = 1024; | |
12 | ||
13 | pub struct ConstBuffer { | |
14 | data: [u8; BUFFER_SIZE], | |
15 | head: usize, | |
16 | } | |
17 | ||
18 | impl ConstBuffer { | |
19 | pub const fn from_slice(slice: &[u8]) -> Self { | |
20 | let s = Self::new(); | |
21 | s.push_slice(slice) | |
22 | } | |
23 | ||
24 | pub const fn new() -> Self { | |
25 | Self { data: [0; BUFFER_SIZE], head: 0 } | |
26 | } | |
27 | ||
28 | pub const fn push_slice(self, slice: &[u8]) -> Self { | |
29 | self.push_amount(slice, slice.len()) | |
30 | } | |
31 | ||
32 | const fn get(&self, index: usize) -> u8 { | |
33 | self.data[index] | |
34 | } | |
35 | ||
36 | const fn len(&self) -> usize { | |
37 | self.head | |
38 | } | |
39 | ||
40 | const fn as_slice(&self) -> &[u8] { | |
41 | &self.data | |
42 | } | |
43 | ||
44 | pub const fn push_other(self, other: Self) -> Self { | |
45 | self.push_amount(other.as_slice(), other.len()) | |
46 | } | |
47 | ||
48 | const fn push_amount(mut self, slice: &[u8], amount: usize) -> Self { | |
49 | let mut i = 0; | |
50 | while i < amount { | |
51 | self.data[self.head + i] = slice[i]; | |
52 | i += 1; | |
53 | } | |
54 | self.head += i; | |
55 | self | |
56 | } | |
57 | } | |
58 | ||
59 | struct Blocks { | |
60 | len: u32, | |
61 | data: [u8; 64], | |
62 | } | |
63 | ||
64 | const fn process_blocks(mut blocks: Blocks, data: &ConstBuffer, mut len: u64, mut state: [u32; 5]) -> (Blocks, u64, [u32; 5]) { | |
65 | const fn as_block(input: &ConstBuffer, offset: usize) -> [u32; 16] { | |
66 | let mut result = [0u32; 16]; | |
67 | ||
68 | let mut i = 0; | |
69 | while i != 16 { | |
70 | let off = offset + (i * 4); | |
71 | result[i] = (input.get(off + 3) as u32) | ((input.get(off + 2) as u32) << 8) | ((input.get(off + 1) as u32) << 16) | ((input.get(off) as u32) << 24); | |
72 | i += 1; | |
73 | } | |
74 | result | |
75 | } | |
76 | ||
77 | const fn clone_from_slice_64(mut data: [u8; 64], slice: &[u8], offset: usize, num_elems: usize) -> [u8; 64] { | |
78 | let mut i = 0; | |
79 | while i < num_elems { | |
80 | data[i] = slice[offset + i]; | |
81 | i += 1; | |
82 | } | |
83 | data | |
84 | } | |
85 | ||
86 | let mut i = 0; | |
87 | while i < data.len() { | |
88 | if data.len() - i >= 64 { | |
89 | let chunk_block = as_block(data, i); | |
90 | len += 64; | |
91 | state = process_state(state, chunk_block); | |
92 | i += 64; | |
93 | } else { | |
94 | let num_elems = data.len() - i; | |
95 | blocks.data = clone_from_slice_64(blocks.data, data.as_slice(), i, num_elems); | |
96 | blocks.len = num_elems as u32; | |
97 | break; | |
98 | } | |
99 | } | |
100 | (blocks, len, state) | |
101 | } | |
102 | ||
103 | const fn process_state(mut state: [u32; 5], block: [u32; 16]) -> [u32; 5] { | |
104 | let a = state[0]; | |
105 | let b = state[1]; | |
106 | let c = state[2]; | |
107 | let d = state[3]; | |
108 | let e = state[4]; | |
109 | let (block, b, e) = r0(block, a, b, c, d, e, 0); | |
110 | let (block, a, d) = r0(block, e, a, b, c, d, 1); | |
111 | let (block, e, c) = r0(block, d, e, a, b, c, 2); | |
112 | let (block, d, b) = r0(block, c, d, e, a, b, 3); | |
113 | let (block, c, a) = r0(block, b, c, d, e, a, 4); | |
114 | let (block, b, e) = r0(block, a, b, c, d, e, 5); | |
115 | let (block, a, d) = r0(block, e, a, b, c, d, 6); | |
116 | let (block, e, c) = r0(block, d, e, a, b, c, 7); | |
117 | let (block, d, b) = r0(block, c, d, e, a, b, 8); | |
118 | let (block, c, a) = r0(block, b, c, d, e, a, 9); | |
119 | let (block, b, e) = r0(block, a, b, c, d, e, 10); | |
120 | let (block, a, d) = r0(block, e, a, b, c, d, 11); | |
121 | let (block, e, c) = r0(block, d, e, a, b, c, 12); | |
122 | let (block, d, b) = r0(block, c, d, e, a, b, 13); | |
123 | let (block, c, a) = r0(block, b, c, d, e, a, 14); | |
124 | let (block, b, e) = r0(block, a, b, c, d, e, 15); | |
125 | let (block, a, d) = r1(block, e, a, b, c, d, 0); | |
126 | let (block, e, c) = r1(block, d, e, a, b, c, 1); | |
127 | let (block, d, b) = r1(block, c, d, e, a, b, 2); | |
128 | let (block, c, a) = r1(block, b, c, d, e, a, 3); | |
129 | let (block, b, e) = r2(block, a, b, c, d, e, 4); | |
130 | let (block, a, d) = r2(block, e, a, b, c, d, 5); | |
131 | let (block, e, c) = r2(block, d, e, a, b, c, 6); | |
132 | let (block, d, b) = r2(block, c, d, e, a, b, 7); | |
133 | let (block, c, a) = r2(block, b, c, d, e, a, 8); | |
134 | let (block, b, e) = r2(block, a, b, c, d, e, 9); | |
135 | let (block, a, d) = r2(block, e, a, b, c, d, 10); | |
136 | let (block, e, c) = r2(block, d, e, a, b, c, 11); | |
137 | let (block, d, b) = r2(block, c, d, e, a, b, 12); | |
138 | let (block, c, a) = r2(block, b, c, d, e, a, 13); | |
139 | let (block, b, e) = r2(block, a, b, c, d, e, 14); | |
140 | let (block, a, d) = r2(block, e, a, b, c, d, 15); | |
141 | let (block, e, c) = r2(block, d, e, a, b, c, 0); | |
142 | let (block, d, b) = r2(block, c, d, e, a, b, 1); | |
143 | let (block, c, a) = r2(block, b, c, d, e, a, 2); | |
144 | let (block, b, e) = r2(block, a, b, c, d, e, 3); | |
145 | let (block, a, d) = r2(block, e, a, b, c, d, 4); | |
146 | let (block, e, c) = r2(block, d, e, a, b, c, 5); | |
147 | let (block, d, b) = r2(block, c, d, e, a, b, 6); | |
148 | let (block, c, a) = r2(block, b, c, d, e, a, 7); | |
149 | let (block, b, e) = r3(block, a, b, c, d, e, 8); | |
150 | let (block, a, d) = r3(block, e, a, b, c, d, 9); | |
151 | let (block, e, c) = r3(block, d, e, a, b, c, 10); | |
152 | let (block, d, b) = r3(block, c, d, e, a, b, 11); | |
153 | let (block, c, a) = r3(block, b, c, d, e, a, 12); | |
154 | let (block, b, e) = r3(block, a, b, c, d, e, 13); | |
155 | let (block, a, d) = r3(block, e, a, b, c, d, 14); | |
156 | let (block, e, c) = r3(block, d, e, a, b, c, 15); | |
157 | let (block, d, b) = r3(block, c, d, e, a, b, 0); | |
158 | let (block, c, a) = r3(block, b, c, d, e, a, 1); | |
159 | let (block, b, e) = r3(block, a, b, c, d, e, 2); | |
160 | let (block, a, d) = r3(block, e, a, b, c, d, 3); | |
161 | let (block, e, c) = r3(block, d, e, a, b, c, 4); | |
162 | let (block, d, b) = r3(block, c, d, e, a, b, 5); | |
163 | let (block, c, a) = r3(block, b, c, d, e, a, 6); | |
164 | let (block, b, e) = r3(block, a, b, c, d, e, 7); | |
165 | let (block, a, d) = r3(block, e, a, b, c, d, 8); | |
166 | let (block, e, c) = r3(block, d, e, a, b, c, 9); | |
167 | let (block, d, b) = r3(block, c, d, e, a, b, 10); | |
168 | let (block, c, a) = r3(block, b, c, d, e, a, 11); | |
169 | let (block, b, e) = r4(block, a, b, c, d, e, 12); | |
170 | let (block, a, d) = r4(block, e, a, b, c, d, 13); | |
171 | let (block, e, c) = r4(block, d, e, a, b, c, 14); | |
172 | let (block, d, b) = r4(block, c, d, e, a, b, 15); | |
173 | let (block, c, a) = r4(block, b, c, d, e, a, 0); | |
174 | let (block, b, e) = r4(block, a, b, c, d, e, 1); | |
175 | let (block, a, d) = r4(block, e, a, b, c, d, 2); | |
176 | let (block, e, c) = r4(block, d, e, a, b, c, 3); | |
177 | let (block, d, b) = r4(block, c, d, e, a, b, 4); | |
178 | let (block, c, a) = r4(block, b, c, d, e, a, 5); | |
179 | let (block, b, e) = r4(block, a, b, c, d, e, 6); | |
180 | let (block, a, d) = r4(block, e, a, b, c, d, 7); | |
181 | let (block, e, c) = r4(block, d, e, a, b, c, 8); | |
182 | let (block, d, b) = r4(block, c, d, e, a, b, 9); | |
183 | let (block, c, a) = r4(block, b, c, d, e, a, 10); | |
184 | let (block, b, e) = r4(block, a, b, c, d, e, 11); | |
185 | let (block, a, d) = r4(block, e, a, b, c, d, 12); | |
186 | let (block, e, c) = r4(block, d, e, a, b, c, 13); | |
187 | let (block, d, b) = r4(block, c, d, e, a, b, 14); | |
188 | let (_, c, a) = r4(block, b, c, d, e, a, 15); | |
189 | ||
190 | state[0] = state[0].wrapping_add(a); | |
191 | state[1] = state[1].wrapping_add(b); | |
192 | state[2] = state[2].wrapping_add(c); | |
193 | state[3] = state[3].wrapping_add(d); | |
194 | state[4] = state[4].wrapping_add(e); | |
195 | state | |
196 | } | |
197 | ||
198 | const fn digest(mut state: [u32; 5], len: u64, blocks: Blocks) -> Digest { | |
199 | const fn clone_from_slice_128(mut data: [u8; 128], slice: &[u8], offset: usize, num_elems: usize) -> [u8; 128] { | |
200 | let mut i = 0; | |
201 | while i < num_elems { | |
202 | data[i] = slice[offset + i]; | |
203 | i += 1; | |
204 | } | |
205 | data | |
206 | } | |
207 | ||
208 | const fn clone_slice_128(mut data: [u8; 128], slice: &[u8], _offset: usize) -> [u8; 128] { | |
209 | let mut i = 0; | |
210 | while i < slice.len() { | |
211 | data[_offset + i] = slice[i]; | |
212 | i += 1; | |
213 | } | |
214 | data | |
215 | } | |
216 | ||
217 | const fn as_block(input: &[u8], offset: usize) -> [u32; 16] { | |
218 | let mut result = [0u32; 16]; | |
219 | ||
220 | let mut i = 0; | |
221 | while i != 16 { | |
222 | let off = offset + (i * 4); | |
223 | result[i] = (input[off + 3] as u32) | ((input[off + 2] as u32) << 8) | ((input[off + 1] as u32) << 16) | ((input[off] as u32) << 24); | |
224 | i += 1; | |
225 | } | |
226 | result | |
227 | } | |
228 | ||
229 | let bits = (len + (blocks.len as u64)) * 8; | |
230 | let extra = [(bits >> 56) as u8, (bits >> 48) as u8, (bits >> 40) as u8, (bits >> 32) as u8, (bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]; | |
231 | let mut last = [0; 128]; | |
232 | let blocklen = blocks.len as usize; | |
233 | last = clone_from_slice_128(last, &blocks.data, 0, blocklen); | |
234 | last[blocklen] = 0x80; | |
235 | ||
236 | if blocklen < 56 { | |
237 | last = clone_slice_128(last, &extra, 56); | |
238 | state = process_state(state, as_block(&last, 0)); | |
239 | } else { | |
240 | last = clone_slice_128(last, &extra, 120); | |
241 | state = process_state(state, as_block(&last, 0)); | |
242 | state = process_state(state, as_block(&last, 64)); | |
243 | } | |
244 | Digest { data: state } | |
245 | } | |
246 | ||
247 | const fn rol(value: u32, bits: usize) -> u32 { | |
248 | (value << bits) | (value >> (32 - bits)) | |
249 | } | |
250 | ||
251 | const fn blk(block: &[u32], i: usize) -> u32 { | |
252 | let value = block[(i + 13) & 15] ^ block[(i + 8) & 15] ^ block[(i + 2) & 15] ^ block[i]; | |
253 | rol(value, 1) | |
254 | } | |
255 | ||
256 | const fn r0(block: [u32; 16], v: u32, mut w: u32, x: u32, y: u32, mut z: u32, i: usize) -> ([u32; 16], u32, u32) { | |
257 | let n = ((w & (x ^ y)) ^ y).wrapping_add(block[i]).wrapping_add(0x5a82_7999).wrapping_add(rol(v, 5)); | |
258 | z = z.wrapping_add(n); | |
259 | w = rol(w, 30); | |
260 | (block, w, z) | |
261 | } | |
262 | ||
263 | const fn r1(mut block: [u32; 16], v: u32, mut w: u32, x: u32, y: u32, mut z: u32, i: usize) -> ([u32; 16], u32, u32) { | |
264 | block[i] = blk(&block, i); | |
265 | let n = ((w & (x ^ y)) ^ y).wrapping_add(block[i]).wrapping_add(0x5a82_7999).wrapping_add(rol(v, 5)); | |
266 | z = z.wrapping_add(n); | |
267 | w = rol(w, 30); | |
268 | (block, w, z) | |
269 | } | |
270 | ||
271 | const fn r2(mut block: [u32; 16], v: u32, mut w: u32, x: u32, y: u32, mut z: u32, i: usize) -> ([u32; 16], u32, u32) { | |
272 | block[i] = blk(&block, i); | |
273 | let n = (w ^ x ^ y).wrapping_add(block[i]).wrapping_add(0x6ed9_eba1).wrapping_add(rol(v, 5)); | |
274 | z = z.wrapping_add(n); | |
275 | w = rol(w, 30); | |
276 | (block, w, z) | |
277 | } | |
278 | ||
279 | const fn r3(mut block: [u32; 16], v: u32, mut w: u32, x: u32, y: u32, mut z: u32, i: usize) -> ([u32; 16], u32, u32) { | |
280 | block[i] = blk(&block, i); | |
281 | let n = (((w | x) & y) | (w & x)).wrapping_add(block[i]).wrapping_add(0x8f1b_bcdc).wrapping_add(rol(v, 5)); | |
282 | z = z.wrapping_add(n); | |
283 | w = rol(w, 30); | |
284 | (block, w, z) | |
285 | } | |
286 | ||
287 | const fn r4(mut block: [u32; 16], v: u32, mut w: u32, x: u32, y: u32, mut z: u32, i: usize) -> ([u32; 16], u32, u32) { | |
288 | block[i] = blk(&block, i); | |
289 | let n = (w ^ x ^ y).wrapping_add(block[i]).wrapping_add(0xca62_c1d6).wrapping_add(rol(v, 5)); | |
290 | z = z.wrapping_add(n); | |
291 | w = rol(w, 30); | |
292 | (block, w, z) | |
293 | } | |
294 | ||
295 | pub struct Digest { | |
296 | data: [u32; 5], | |
297 | } | |
298 | ||
299 | impl Digest { | |
300 | pub const fn bytes(&self) -> [u8; 20] { | |
301 | [ | |
302 | (self.data[0] >> 24) as u8, | |
303 | (self.data[0] >> 16) as u8, | |
304 | (self.data[0] >> 8) as u8, | |
305 | self.data[0] as u8, | |
306 | (self.data[1] >> 24) as u8, | |
307 | (self.data[1] >> 16) as u8, | |
308 | (self.data[1] >> 8) as u8, | |
309 | self.data[1] as u8, | |
310 | (self.data[2] >> 24) as u8, | |
311 | (self.data[2] >> 16) as u8, | |
312 | (self.data[2] >> 8) as u8, | |
313 | self.data[2] as u8, | |
314 | (self.data[3] >> 24) as u8, | |
315 | (self.data[3] >> 16) as u8, | |
316 | (self.data[3] >> 8) as u8, | |
317 | self.data[3] as u8, | |
318 | (self.data[4] >> 24) as u8, | |
319 | (self.data[4] >> 16) as u8, | |
320 | (self.data[4] >> 8) as u8, | |
321 | self.data[4] as u8, | |
322 | ] | |
323 | } | |
324 | } | |
325 | ||
326 | impl std::fmt::Display for Digest { | |
327 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | |
328 | for i in self.data.iter() { | |
329 | write!(f, "{:08x}", i)?; | |
330 | } | |
331 | Ok(()) | |
332 | } | |
333 | } |