// SPDX-License-Identifier: CC0-1.0 //! SHA1 implementation. use internals::slice::SliceExt; #[cfg(bench)] mod benches; mod crypto; #[cfg(bench)] mod tests; use core::cmp; use crate::{incomplete_block_len, HashEngine as _}; crate::internal_macros::general_hash_type! { 160, false, "Output of the SHA1 hash function." } impl Hash { /// Finalize a hash engine to produce a hash. pub fn from_engine(mut e: HashEngine) -> Self { // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining let n_bytes_hashed = e.bytes_hashed; let zeroes = [0; BLOCK_SIZE - 8]; e.input(&[0x80]); if incomplete_block_len(&e) > zeroes.len() { e.input(&zeroes); } let pad_length = zeroes.len() - incomplete_block_len(&e); e.input(&zeroes[..pad_length]); debug_assert_eq!(incomplete_block_len(&e), zeroes.len()); e.input(&(8 * n_bytes_hashed).to_be_bytes()); debug_assert_eq!(incomplete_block_len(&e), 0); Hash(e.midstate()) } } const BLOCK_SIZE: usize = 64; /// Engine to compute SHA1 hash function. #[derive(Debug, Clone)] pub struct HashEngine { buffer: [u8; BLOCK_SIZE], h: [u32; 5], bytes_hashed: u64, } impl HashEngine { /// Constructs a new SHA1 hash engine. pub const fn new() -> Self { Self { h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0], bytes_hashed: 0, buffer: [0; BLOCK_SIZE], } } #[cfg(not(hashes_fuzz))] pub(crate) fn midstate(&self) -> [u8; 20] { let mut ret = [0; 20]; for (val, ret_bytes) in self.h.iter().zip(ret.bitcoin_as_chunks_mut().0) { *ret_bytes = val.to_be_bytes(); } ret } #[cfg(hashes_fuzz)] pub(crate) fn midstate(&self) -> [u8; 20] { let mut ret = [0; 20]; ret.copy_from_slice(&self.buffer[..20]); ret } } impl Default for HashEngine { fn default() -> Self { Self::new() } } impl crate::HashEngine for HashEngine { type Hash = Hash; type Bytes = [u8; 20]; const BLOCK_SIZE: usize = 64; fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed } crate::internal_macros::engine_input_impl!(); fn finalize(self) -> Self::Hash { Hash::from_engine(self) } }