use crate::{consts, sha256::compress256, sha512::compress512}; use core::{fmt, slice::from_ref}; use digest::{ block_buffer::Eager, core_api::{ AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, OutputSizeUser, TruncSide, UpdateCore, VariableOutputCore, }, typenum::{Unsigned, U128, U32, U64}, HashMarker, InvalidOutputSize, Output, }; /// Core block-level SHA-256 hasher with variable output size. /// /// Supports initialization only for 28 and 32 byte output sizes, /// i.e. 224 and 256 bits respectively. #[derive(Clone)] pub struct Sha256VarCore { state: consts::State256, block_len: u64, } impl HashMarker for Sha256VarCore {} impl BlockSizeUser for Sha256VarCore { type BlockSize = U64; } impl BufferKindUser for Sha256VarCore { type BufferKind = Eager; } impl UpdateCore for Sha256VarCore { #[inline] fn update_blocks(&mut self, blocks: &[Block]) { self.block_len += blocks.len() as u64; compress256(&mut self.state, blocks); } } impl OutputSizeUser for Sha256VarCore { type OutputSize = U32; } impl VariableOutputCore for Sha256VarCore { const TRUNC_SIDE: TruncSide = TruncSide::Left; #[inline] fn new(output_size: usize) -> Result { let state = match output_size { 28 => consts::H256_224, 32 => consts::H256_256, _ => return Err(InvalidOutputSize), }; let block_len = 0; Ok(Self { state, block_len }) } #[inline] fn finalize_variable_core(&mut self, buffer: &mut Buffer, out: &mut Output) { let bs = Self::BlockSize::U64; let bit_len = 8 * (buffer.get_pos() as u64 + bs * self.block_len); buffer.len64_padding_be(bit_len, |b| compress256(&mut self.state, from_ref(b))); for (chunk, v) in out.chunks_exact_mut(4).zip(self.state.iter()) { chunk.copy_from_slice(&v.to_be_bytes()); } } } impl AlgorithmName for Sha256VarCore { #[inline] fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Sha256") } } impl fmt::Debug for Sha256VarCore { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Sha256VarCore { ... }") } } /// Core block-level SHA-512 hasher with variable output size. /// /// Supports initialization only for 28, 32, 48, and 64 byte output sizes, /// i.e. 224, 256, 384, and 512 bits respectively. #[derive(Clone)] pub struct Sha512VarCore { state: consts::State512, block_len: u128, } impl HashMarker for Sha512VarCore {} impl BlockSizeUser for Sha512VarCore { type BlockSize = U128; } impl BufferKindUser for Sha512VarCore { type BufferKind = Eager; } impl UpdateCore for Sha512VarCore { #[inline] fn update_blocks(&mut self, blocks: &[Block]) { self.block_len += blocks.len() as u128; compress512(&mut self.state, blocks); } } impl OutputSizeUser for Sha512VarCore { type OutputSize = U64; } impl VariableOutputCore for Sha512VarCore { const TRUNC_SIDE: TruncSide = TruncSide::Left; #[inline] fn new(output_size: usize) -> Result { let state = match output_size { 28 => consts::H512_224, 32 => consts::H512_256, 48 => consts::H512_384, 64 => consts::H512_512, _ => return Err(InvalidOutputSize), }; let block_len = 0; Ok(Self { state, block_len }) } #[inline] fn finalize_variable_core(&mut self, buffer: &mut Buffer, out: &mut Output) { let bs = Self::BlockSize::U64 as u128; let bit_len = 8 * (buffer.get_pos() as u128 + bs * self.block_len); buffer.len128_padding_be(bit_len, |b| compress512(&mut self.state, from_ref(b))); for (chunk, v) in out.chunks_exact_mut(8).zip(self.state.iter()) { chunk.copy_from_slice(&v.to_be_bytes()); } } } impl AlgorithmName for Sha512VarCore { #[inline] fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Sha512") } } impl fmt::Debug for Sha512VarCore { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Sha512VarCore { ... }") } }