use super::{ AlgorithmName, Buffer, BufferKindUser, ExtendableOutputCore, FixedOutputCore, OutputSizeUser, Reset, UpdateCore, XofReaderCoreWrapper, }; use crate::{ ExtendableOutput, ExtendableOutputReset, FixedOutput, FixedOutputReset, HashMarker, Update, }; use block_buffer::BlockBuffer; use core::fmt; use crypto_common::{ typenum::{IsLess, Le, NonZero, U256}, BlockSizeUser, InvalidLength, Key, KeyInit, KeySizeUser, Output, }; #[cfg(feature = "mac")] use crate::MacMarker; /// Wrapper around [`BufferKindUser`]. /// /// It handles data buffering and implements the slice-based traits. #[derive(Clone, Default)] pub struct CoreWrapper where T: BufferKindUser, T::BlockSize: IsLess, Le: NonZero, { core: T, buffer: BlockBuffer, } impl HashMarker for CoreWrapper where T: BufferKindUser + HashMarker, T::BlockSize: IsLess, Le: NonZero, { } #[cfg(feature = "mac")] #[cfg_attr(docsrs, doc(cfg(feature = "mac")))] impl MacMarker for CoreWrapper where T: BufferKindUser + MacMarker, T::BlockSize: IsLess, Le: NonZero, { } // this blanket impl is needed for HMAC impl BlockSizeUser for CoreWrapper where T: BufferKindUser + HashMarker, T::BlockSize: IsLess, Le: NonZero, { type BlockSize = T::BlockSize; } impl CoreWrapper where T: BufferKindUser, T::BlockSize: IsLess, Le: NonZero, { /// Create new wrapper from `core`. #[inline] pub fn from_core(core: T) -> Self { let buffer = Default::default(); Self { core, buffer } } /// Decompose wrapper into inner parts. #[inline] pub fn decompose(self) -> (T, Buffer) { let Self { core, buffer } = self; (core, buffer) } } impl KeySizeUser for CoreWrapper where T: BufferKindUser + KeySizeUser, T::BlockSize: IsLess, Le: NonZero, { type KeySize = T::KeySize; } impl KeyInit for CoreWrapper where T: BufferKindUser + KeyInit, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn new(key: &Key) -> Self { Self { core: T::new(key), buffer: Default::default(), } } #[inline] fn new_from_slice(key: &[u8]) -> Result { Ok(Self { core: T::new_from_slice(key)?, buffer: Default::default(), }) } } impl fmt::Debug for CoreWrapper where T: BufferKindUser + AlgorithmName, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { T::write_alg_name(f)?; f.write_str(" { .. }") } } impl Reset for CoreWrapper where T: BufferKindUser + Reset, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn reset(&mut self) { self.core.reset(); self.buffer.reset(); } } impl Update for CoreWrapper where T: BufferKindUser + 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 OutputSizeUser for CoreWrapper where T: BufferKindUser + OutputSizeUser, T::BlockSize: IsLess, Le: NonZero, { type OutputSize = T::OutputSize; } impl FixedOutput for CoreWrapper where T: FixedOutputCore, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn finalize_into(mut self, out: &mut Output) { let Self { core, buffer } = &mut self; core.finalize_fixed_core(buffer, out); } } impl FixedOutputReset for CoreWrapper where T: FixedOutputCore + Reset, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn finalize_into_reset(&mut self, out: &mut Output) { let Self { core, buffer } = self; core.finalize_fixed_core(buffer, out); core.reset(); buffer.reset(); } } impl ExtendableOutput for CoreWrapper where T: ExtendableOutputCore, T::BlockSize: IsLess, Le: NonZero, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { type Reader = XofReaderCoreWrapper; #[inline] fn finalize_xof(self) -> Self::Reader { let (mut core, mut buffer) = self.decompose(); let core = core.finalize_xof_core(&mut buffer); let buffer = Default::default(); Self::Reader { core, buffer } } } impl ExtendableOutputReset for CoreWrapper where T: ExtendableOutputCore + Reset, T::BlockSize: IsLess, Le: NonZero, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { #[inline] fn finalize_xof_reset(&mut self) -> Self::Reader { let Self { core, buffer } = self; let reader_core = core.finalize_xof_core(buffer); core.reset(); buffer.reset(); let buffer = Default::default(); Self::Reader { core: reader_core, buffer, } } } #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl std::io::Write for CoreWrapper where T: BufferKindUser + 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(()) } } /// A proxy trait to a core type implemented by [`CoreWrapper`] // TODO: replace with an inherent associated type on stabilization: // https://github.com/rust-lang/rust/issues/8995 pub trait CoreProxy: sealed::Sealed { /// Type wrapped by [`CoreWrapper`]. type Core; } mod sealed { pub trait Sealed {} } impl sealed::Sealed for CoreWrapper where T: BufferKindUser, T::BlockSize: IsLess, Le: NonZero, { } impl CoreProxy for CoreWrapper where T: BufferKindUser, T::BlockSize: IsLess, Le: NonZero, { type Core = T; }