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; #[cfg(feature = "oid")] use const_oid::{AssociatedOid, ObjectIdentifier}; /// Wrapper around [`BufferKindUser`]. /// /// It handles data buffering and implements the slice-based traits. #[derive(Clone, Default)] pub struct CoreWrapper<T> where T: BufferKindUser, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { core: T, buffer: BlockBuffer<T::BlockSize, T::BufferKind>, } impl<T> HashMarker for CoreWrapper<T> where T: BufferKindUser + HashMarker, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { } #[cfg(feature = "mac")] #[cfg_attr(docsrs, doc(cfg(feature = "mac")))] impl<T> MacMarker for CoreWrapper<T> where T: BufferKindUser + MacMarker, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { } // this blanket impl is needed for HMAC impl<T> BlockSizeUser for CoreWrapper<T> where T: BufferKindUser + HashMarker, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { type BlockSize = T::BlockSize; } impl<T> CoreWrapper<T> where T: BufferKindUser, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: 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<T>) { let Self { core, buffer } = self; (core, buffer) } } impl<T> KeySizeUser for CoreWrapper<T> where T: BufferKindUser + KeySizeUser, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { type KeySize = T::KeySize; } impl<T> KeyInit for CoreWrapper<T> where T: BufferKindUser + KeyInit, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { #[inline] fn new(key: &Key<Self>) -> Self { Self { core: T::new(key), buffer: Default::default(), } } #[inline] fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> { Ok(Self { core: T::new_from_slice(key)?, buffer: Default::default(), }) } } impl<T> fmt::Debug for CoreWrapper<T> where T: BufferKindUser + AlgorithmName, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { T::write_alg_name(f)?; f.write_str(" { .. }") } } impl<T> Reset for CoreWrapper<T> where T: BufferKindUser + Reset, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { #[inline] fn reset(&mut self) { self.core.reset(); self.buffer.reset(); } } impl<T> Update for CoreWrapper<T> where T: BufferKindUser + UpdateCore, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { #[inline] fn update(&mut self, input: &[u8]) { let Self { core, buffer } = self; buffer.digest_blocks(input, |blocks| core.update_blocks(blocks)); } } impl<T> OutputSizeUser for CoreWrapper<T> where T: BufferKindUser + OutputSizeUser, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { type OutputSize = T::OutputSize; } impl<T> FixedOutput for CoreWrapper<T> where T: FixedOutputCore, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { #[inline] fn finalize_into(mut self, out: &mut Output<Self>) { let Self { core, buffer } = &mut self; core.finalize_fixed_core(buffer, out); } } impl<T> FixedOutputReset for CoreWrapper<T> where T: FixedOutputCore + Reset, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { #[inline] fn finalize_into_reset(&mut self, out: &mut Output<Self>) { let Self { core, buffer } = self; core.finalize_fixed_core(buffer, out); core.reset(); buffer.reset(); } } impl<T> ExtendableOutput for CoreWrapper<T> where T: ExtendableOutputCore, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, <T::ReaderCore as BlockSizeUser>::BlockSize: IsLess<U256>, Le<<T::ReaderCore as BlockSizeUser>::BlockSize, U256>: NonZero, { type Reader = XofReaderCoreWrapper<T::ReaderCore>; #[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<T> ExtendableOutputReset for CoreWrapper<T> where T: ExtendableOutputCore + Reset, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, <T::ReaderCore as BlockSizeUser>::BlockSize: IsLess<U256>, Le<<T::ReaderCore as BlockSizeUser>::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 = "oid")] #[cfg_attr(docsrs, doc(cfg(feature = "oid")))] impl<T> AssociatedOid for CoreWrapper<T> where T: BufferKindUser + AssociatedOid, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { const OID: ObjectIdentifier = T::OID; } #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl<T> std::io::Write for CoreWrapper<T> where T: BufferKindUser + UpdateCore, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { #[inline] fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { 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<T> sealed::Sealed for CoreWrapper<T> where T: BufferKindUser, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { } impl<T> CoreProxy for CoreWrapper<T> where T: BufferKindUser, T::BlockSize: IsLess<U256>, Le<T::BlockSize, U256>: NonZero, { type Core = T; }