use super::{AlgorithmName, TruncSide, UpdateCore, VariableOutputCore}; #[cfg(feature = "mac")] use crate::MacMarker; use crate::{HashMarker, InvalidBufferSize}; use crate::{InvalidOutputSize, Reset, Update, VariableOutput, VariableOutputReset}; use block_buffer::BlockBuffer; use core::fmt; use crypto_common::typenum::{IsLess, Le, NonZero, Unsigned, U256}; /// Wrapper around [`VariableOutputCore`] which selects output size /// at run time. #[derive(Clone)] pub struct RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore, T::BlockSize: IsLess, Le: NonZero, { core: T, buffer: BlockBuffer, output_size: usize, } impl RtVariableCoreWrapper where T: VariableOutputCore, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn finalize_dirty(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize> { let Self { core, buffer, output_size, } = self; if out.len() != *output_size || out.len() > Self::MAX_OUTPUT_SIZE { return Err(InvalidBufferSize); } let mut full_res = Default::default(); core.finalize_variable_core(buffer, &mut full_res); let n = out.len(); let m = full_res.len() - n; match T::TRUNC_SIDE { TruncSide::Left => out.copy_from_slice(&full_res[..n]), TruncSide::Right => out.copy_from_slice(&full_res[m..]), } Ok(()) } } impl HashMarker for RtVariableCoreWrapper where T: VariableOutputCore + HashMarker, T::BlockSize: IsLess, Le: NonZero, { } #[cfg(feature = "mac")] #[cfg_attr(docsrs, doc(cfg(feature = "mac")))] impl MacMarker for RtVariableCoreWrapper where T: VariableOutputCore + MacMarker, T::BlockSize: IsLess, Le: NonZero, { } impl Reset for RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore + Reset, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn reset(&mut self) { self.buffer.reset(); self.core.reset(); } } impl Update for RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn update(&mut self, input: &[u8]) { let Self { core, buffer, .. } = self; buffer.digest_blocks(input, |blocks| core.update_blocks(blocks)); } } impl VariableOutput for RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore, T::BlockSize: IsLess, Le: NonZero, { const MAX_OUTPUT_SIZE: usize = T::OutputSize::USIZE; fn new(output_size: usize) -> Result { let buffer = Default::default(); T::new(output_size).map(|core| Self { core, buffer, output_size, }) } fn output_size(&self) -> usize { self.output_size } fn finalize_variable(mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize> { self.finalize_dirty(out) } } impl VariableOutputReset for RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore + Reset, T::BlockSize: IsLess, Le: NonZero, { fn finalize_variable_reset(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize> { self.finalize_dirty(out)?; self.core.reset(); self.buffer.reset(); Ok(()) } } impl fmt::Debug for RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore + AlgorithmName, T::BlockSize: IsLess, Le: NonZero, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { T::write_alg_name(f)?; f.write_str(" { .. }") } } #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl std::io::Write for RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn write(&mut self, buf: &[u8]) -> std::io::Result { Update::update(self, buf); Ok(buf.len()) } #[inline] fn flush(&mut self) -> std::io::Result<()> { Ok(()) } }