| #![allow(clippy::many_single_char_names)] |
| |
| pub const fn sha1(data: &ConstBuffer) -> Digest { |
| let state: [u32; 5] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; |
| let len: u64 = 0; |
| let blocks = Blocks { len: 0, data: [0; 64] }; |
| let (blocks, len, state) = process_blocks(blocks, data, len, state); |
| digest(state, len, blocks) |
| } |
| |
| const BUFFER_SIZE: usize = 1024; |
| |
| pub struct ConstBuffer { |
| data: [u8; BUFFER_SIZE], |
| head: usize, |
| } |
| |
| impl ConstBuffer { |
| pub const fn from_slice(slice: &[u8]) -> Self { |
| let s = Self::new(); |
| s.push_slice(slice) |
| } |
| |
| pub const fn new() -> Self { |
| Self { data: [0; BUFFER_SIZE], head: 0 } |
| } |
| |
| pub const fn push_slice(self, slice: &[u8]) -> Self { |
| self.push_amount(slice, slice.len()) |
| } |
| |
| const fn get(&self, index: usize) -> u8 { |
| self.data[index] |
| } |
| |
| const fn len(&self) -> usize { |
| self.head |
| } |
| |
| const fn as_slice(&self) -> &[u8] { |
| &self.data |
| } |
| |
| pub const fn push_other(self, other: Self) -> Self { |
| self.push_amount(other.as_slice(), other.len()) |
| } |
| |
| const fn push_amount(mut self, slice: &[u8], amount: usize) -> Self { |
| let mut i = 0; |
| while i < amount { |
| self.data[self.head + i] = slice[i]; |
| i += 1; |
| } |
| self.head += i; |
| self |
| } |
| } |
| |
| struct Blocks { |
| len: u32, |
| data: [u8; 64], |
| } |
| |
| const fn process_blocks(mut blocks: Blocks, data: &ConstBuffer, mut len: u64, mut state: [u32; 5]) -> (Blocks, u64, [u32; 5]) { |
| const fn as_block(input: &ConstBuffer, offset: usize) -> [u32; 16] { |
| let mut result = [0u32; 16]; |
| |
| let mut i = 0; |
| while i != 16 { |
| let off = offset + (i * 4); |
| 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); |
| i += 1; |
| } |
| result |
| } |
| |
| const fn clone_from_slice_64(mut data: [u8; 64], slice: &[u8], offset: usize, num_elems: usize) -> [u8; 64] { |
| let mut i = 0; |
| while i < num_elems { |
| data[i] = slice[offset + i]; |
| i += 1; |
| } |
| data |
| } |
| |
| let mut i = 0; |
| while i < data.len() { |
| if data.len() - i >= 64 { |
| let chunk_block = as_block(data, i); |
| len += 64; |
| state = process_state(state, chunk_block); |
| i += 64; |
| } else { |
| let num_elems = data.len() - i; |
| blocks.data = clone_from_slice_64(blocks.data, data.as_slice(), i, num_elems); |
| blocks.len = num_elems as u32; |
| break; |
| } |
| } |
| (blocks, len, state) |
| } |
| |
| const fn process_state(mut state: [u32; 5], block: [u32; 16]) -> [u32; 5] { |
| let a = state[0]; |
| let b = state[1]; |
| let c = state[2]; |
| let d = state[3]; |
| let e = state[4]; |
| let (block, b, e) = r0(block, a, b, c, d, e, 0); |
| let (block, a, d) = r0(block, e, a, b, c, d, 1); |
| let (block, e, c) = r0(block, d, e, a, b, c, 2); |
| let (block, d, b) = r0(block, c, d, e, a, b, 3); |
| let (block, c, a) = r0(block, b, c, d, e, a, 4); |
| let (block, b, e) = r0(block, a, b, c, d, e, 5); |
| let (block, a, d) = r0(block, e, a, b, c, d, 6); |
| let (block, e, c) = r0(block, d, e, a, b, c, 7); |
| let (block, d, b) = r0(block, c, d, e, a, b, 8); |
| let (block, c, a) = r0(block, b, c, d, e, a, 9); |
| let (block, b, e) = r0(block, a, b, c, d, e, 10); |
| let (block, a, d) = r0(block, e, a, b, c, d, 11); |
| let (block, e, c) = r0(block, d, e, a, b, c, 12); |
| let (block, d, b) = r0(block, c, d, e, a, b, 13); |
| let (block, c, a) = r0(block, b, c, d, e, a, 14); |
| let (block, b, e) = r0(block, a, b, c, d, e, 15); |
| let (block, a, d) = r1(block, e, a, b, c, d, 0); |
| let (block, e, c) = r1(block, d, e, a, b, c, 1); |
| let (block, d, b) = r1(block, c, d, e, a, b, 2); |
| let (block, c, a) = r1(block, b, c, d, e, a, 3); |
| let (block, b, e) = r2(block, a, b, c, d, e, 4); |
| let (block, a, d) = r2(block, e, a, b, c, d, 5); |
| let (block, e, c) = r2(block, d, e, a, b, c, 6); |
| let (block, d, b) = r2(block, c, d, e, a, b, 7); |
| let (block, c, a) = r2(block, b, c, d, e, a, 8); |
| let (block, b, e) = r2(block, a, b, c, d, e, 9); |
| let (block, a, d) = r2(block, e, a, b, c, d, 10); |
| let (block, e, c) = r2(block, d, e, a, b, c, 11); |
| let (block, d, b) = r2(block, c, d, e, a, b, 12); |
| let (block, c, a) = r2(block, b, c, d, e, a, 13); |
| let (block, b, e) = r2(block, a, b, c, d, e, 14); |
| let (block, a, d) = r2(block, e, a, b, c, d, 15); |
| let (block, e, c) = r2(block, d, e, a, b, c, 0); |
| let (block, d, b) = r2(block, c, d, e, a, b, 1); |
| let (block, c, a) = r2(block, b, c, d, e, a, 2); |
| let (block, b, e) = r2(block, a, b, c, d, e, 3); |
| let (block, a, d) = r2(block, e, a, b, c, d, 4); |
| let (block, e, c) = r2(block, d, e, a, b, c, 5); |
| let (block, d, b) = r2(block, c, d, e, a, b, 6); |
| let (block, c, a) = r2(block, b, c, d, e, a, 7); |
| let (block, b, e) = r3(block, a, b, c, d, e, 8); |
| let (block, a, d) = r3(block, e, a, b, c, d, 9); |
| let (block, e, c) = r3(block, d, e, a, b, c, 10); |
| let (block, d, b) = r3(block, c, d, e, a, b, 11); |
| let (block, c, a) = r3(block, b, c, d, e, a, 12); |
| let (block, b, e) = r3(block, a, b, c, d, e, 13); |
| let (block, a, d) = r3(block, e, a, b, c, d, 14); |
| let (block, e, c) = r3(block, d, e, a, b, c, 15); |
| let (block, d, b) = r3(block, c, d, e, a, b, 0); |
| let (block, c, a) = r3(block, b, c, d, e, a, 1); |
| let (block, b, e) = r3(block, a, b, c, d, e, 2); |
| let (block, a, d) = r3(block, e, a, b, c, d, 3); |
| let (block, e, c) = r3(block, d, e, a, b, c, 4); |
| let (block, d, b) = r3(block, c, d, e, a, b, 5); |
| let (block, c, a) = r3(block, b, c, d, e, a, 6); |
| let (block, b, e) = r3(block, a, b, c, d, e, 7); |
| let (block, a, d) = r3(block, e, a, b, c, d, 8); |
| let (block, e, c) = r3(block, d, e, a, b, c, 9); |
| let (block, d, b) = r3(block, c, d, e, a, b, 10); |
| let (block, c, a) = r3(block, b, c, d, e, a, 11); |
| let (block, b, e) = r4(block, a, b, c, d, e, 12); |
| let (block, a, d) = r4(block, e, a, b, c, d, 13); |
| let (block, e, c) = r4(block, d, e, a, b, c, 14); |
| let (block, d, b) = r4(block, c, d, e, a, b, 15); |
| let (block, c, a) = r4(block, b, c, d, e, a, 0); |
| let (block, b, e) = r4(block, a, b, c, d, e, 1); |
| let (block, a, d) = r4(block, e, a, b, c, d, 2); |
| let (block, e, c) = r4(block, d, e, a, b, c, 3); |
| let (block, d, b) = r4(block, c, d, e, a, b, 4); |
| let (block, c, a) = r4(block, b, c, d, e, a, 5); |
| let (block, b, e) = r4(block, a, b, c, d, e, 6); |
| let (block, a, d) = r4(block, e, a, b, c, d, 7); |
| let (block, e, c) = r4(block, d, e, a, b, c, 8); |
| let (block, d, b) = r4(block, c, d, e, a, b, 9); |
| let (block, c, a) = r4(block, b, c, d, e, a, 10); |
| let (block, b, e) = r4(block, a, b, c, d, e, 11); |
| let (block, a, d) = r4(block, e, a, b, c, d, 12); |
| let (block, e, c) = r4(block, d, e, a, b, c, 13); |
| let (block, d, b) = r4(block, c, d, e, a, b, 14); |
| let (_, c, a) = r4(block, b, c, d, e, a, 15); |
| |
| state[0] = state[0].wrapping_add(a); |
| state[1] = state[1].wrapping_add(b); |
| state[2] = state[2].wrapping_add(c); |
| state[3] = state[3].wrapping_add(d); |
| state[4] = state[4].wrapping_add(e); |
| state |
| } |
| |
| const fn digest(mut state: [u32; 5], len: u64, blocks: Blocks) -> Digest { |
| const fn clone_from_slice_128(mut data: [u8; 128], slice: &[u8], offset: usize, num_elems: usize) -> [u8; 128] { |
| let mut i = 0; |
| while i < num_elems { |
| data[i] = slice[offset + i]; |
| i += 1; |
| } |
| data |
| } |
| |
| const fn clone_slice_128(mut data: [u8; 128], slice: &[u8], _offset: usize) -> [u8; 128] { |
| let mut i = 0; |
| while i < slice.len() { |
| data[_offset + i] = slice[i]; |
| i += 1; |
| } |
| data |
| } |
| |
| const fn as_block(input: &[u8], offset: usize) -> [u32; 16] { |
| let mut result = [0u32; 16]; |
| |
| let mut i = 0; |
| while i != 16 { |
| let off = offset + (i * 4); |
| result[i] = (input[off + 3] as u32) | ((input[off + 2] as u32) << 8) | ((input[off + 1] as u32) << 16) | ((input[off] as u32) << 24); |
| i += 1; |
| } |
| result |
| } |
| |
| let bits = (len + (blocks.len as u64)) * 8; |
| 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]; |
| let mut last = [0; 128]; |
| let blocklen = blocks.len as usize; |
| last = clone_from_slice_128(last, &blocks.data, 0, blocklen); |
| last[blocklen] = 0x80; |
| |
| if blocklen < 56 { |
| last = clone_slice_128(last, &extra, 56); |
| state = process_state(state, as_block(&last, 0)); |
| } else { |
| last = clone_slice_128(last, &extra, 120); |
| state = process_state(state, as_block(&last, 0)); |
| state = process_state(state, as_block(&last, 64)); |
| } |
| Digest { data: state } |
| } |
| |
| const fn rol(value: u32, bits: usize) -> u32 { |
| (value << bits) | (value >> (32 - bits)) |
| } |
| |
| const fn blk(block: &[u32], i: usize) -> u32 { |
| let value = block[(i + 13) & 15] ^ block[(i + 8) & 15] ^ block[(i + 2) & 15] ^ block[i]; |
| rol(value, 1) |
| } |
| |
| const fn r0(block: [u32; 16], v: u32, mut w: u32, x: u32, y: u32, mut z: u32, i: usize) -> ([u32; 16], u32, u32) { |
| let n = ((w & (x ^ y)) ^ y).wrapping_add(block[i]).wrapping_add(0x5a82_7999).wrapping_add(rol(v, 5)); |
| z = z.wrapping_add(n); |
| w = rol(w, 30); |
| (block, w, z) |
| } |
| |
| 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) { |
| block[i] = blk(&block, i); |
| let n = ((w & (x ^ y)) ^ y).wrapping_add(block[i]).wrapping_add(0x5a82_7999).wrapping_add(rol(v, 5)); |
| z = z.wrapping_add(n); |
| w = rol(w, 30); |
| (block, w, z) |
| } |
| |
| 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) { |
| block[i] = blk(&block, i); |
| let n = (w ^ x ^ y).wrapping_add(block[i]).wrapping_add(0x6ed9_eba1).wrapping_add(rol(v, 5)); |
| z = z.wrapping_add(n); |
| w = rol(w, 30); |
| (block, w, z) |
| } |
| |
| 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) { |
| block[i] = blk(&block, i); |
| let n = (((w | x) & y) | (w & x)).wrapping_add(block[i]).wrapping_add(0x8f1b_bcdc).wrapping_add(rol(v, 5)); |
| z = z.wrapping_add(n); |
| w = rol(w, 30); |
| (block, w, z) |
| } |
| |
| 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) { |
| block[i] = blk(&block, i); |
| let n = (w ^ x ^ y).wrapping_add(block[i]).wrapping_add(0xca62_c1d6).wrapping_add(rol(v, 5)); |
| z = z.wrapping_add(n); |
| w = rol(w, 30); |
| (block, w, z) |
| } |
| |
| pub struct Digest { |
| data: [u32; 5], |
| } |
| |
| impl Digest { |
| pub const fn bytes(&self) -> [u8; 20] { |
| [ |
| (self.data[0] >> 24) as u8, |
| (self.data[0] >> 16) as u8, |
| (self.data[0] >> 8) as u8, |
| self.data[0] as u8, |
| (self.data[1] >> 24) as u8, |
| (self.data[1] >> 16) as u8, |
| (self.data[1] >> 8) as u8, |
| self.data[1] as u8, |
| (self.data[2] >> 24) as u8, |
| (self.data[2] >> 16) as u8, |
| (self.data[2] >> 8) as u8, |
| self.data[2] as u8, |
| (self.data[3] >> 24) as u8, |
| (self.data[3] >> 16) as u8, |
| (self.data[3] >> 8) as u8, |
| self.data[3] as u8, |
| (self.data[4] >> 24) as u8, |
| (self.data[4] >> 16) as u8, |
| (self.data[4] >> 8) as u8, |
| self.data[4] as u8, |
| ] |
| } |
| } |
| |
| impl std::fmt::Display for Digest { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| for i in self.data.iter() { |
| write!(f, "{:08x}", i)?; |
| } |
| Ok(()) |
| } |
| } |