diff --git a/digest/CHANGELOG.md b/digest/CHANGELOG.md index 5e2f14e1..22d55f91 100644 --- a/digest/CHANGELOG.md +++ b/digest/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.11.0 (UNRELEASED) ### Added - `CustomizedInit` trait ([#1334]) +- `VariableOutputCoreCustomized` trait ([#1787], [#2043]) - `buffer_fixed`, `buffer_ct_variable`, `buffer_rt_variable`, and `buffer_xof` macros ([#1799]) - `CollisionResistance` trait ([#1820]) @@ -24,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `CoreWrapper`, `RtVariableCoreWrapper`, and `XofReaderCoreWrapper` types ([#1799]) - `HashReader` and `HashWriter` are moved to the `digest-io` crate ([#1809]) - `io::Write/Read` implementations in favor of the `digest_io::IoWrapper` type ([#1809]) +- `VariableOutput` trait ([#2043]) [#1173]: https://github.com/RustCrypto/traits/pull/1173 [#1334]: https://github.com/RustCrypto/traits/pull/1334 @@ -33,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#1820]: https://github.com/RustCrypto/traits/pull/1820 [#1953]: https://github.com/RustCrypto/traits/pull/1953 [#1958]: https://github.com/RustCrypto/traits/pull/1958 +[#2043]: https://github.com/RustCrypto/traits/pull/2043 ## 0.10.7 (2023-05-19) ### Changed diff --git a/digest/src/block_api.rs b/digest/src/block_api.rs index 56dda9cb..472220f0 100644 --- a/digest/src/block_api.rs +++ b/digest/src/block_api.rs @@ -113,6 +113,12 @@ pub trait VariableOutputCore: UpdateCore + OutputSizeUser + BufferKindUser + Siz fn finalize_variable_core(&mut self, buffer: &mut Buffer, out: &mut Output); } +/// Trait adding customization string to hash functions with variable output. +pub trait VariableOutputCoreCustomized: VariableOutputCore { + /// Create new hasher instance with the given customization string and output size. + fn new_customized(customization: &[u8], output_size: usize) -> Self; +} + /// Type which used for defining truncation side in the [`VariableOutputCore`] /// trait. #[derive(Copy, Clone, Debug)] diff --git a/digest/src/block_api/ct_variable.rs b/digest/src/block_api/ct_variable.rs index 0e645993..813a97fe 100644 --- a/digest/src/block_api/ct_variable.rs +++ b/digest/src/block_api/ct_variable.rs @@ -1,10 +1,10 @@ use super::{ AlgorithmName, Buffer, BufferKindUser, FixedOutputCore, Reset, TruncSide, UpdateCore, - VariableOutputCore, + VariableOutputCore, VariableOutputCoreCustomized, }; #[cfg(feature = "mac")] use crate::MacMarker; -use crate::{CollisionResistance, CustomizedInit, HashMarker, VarOutputCustomized}; +use crate::{CollisionResistance, CustomizedInit, HashMarker}; use core::{fmt, marker::PhantomData}; use crypto_common::{ Block, BlockSizeUser, OutputSizeUser, @@ -120,7 +120,7 @@ where impl CustomizedInit for CtOutWrapper where - T: VariableOutputCore + VarOutputCustomized, + T: VariableOutputCoreCustomized, OutSize: ArraySize + IsLessOrEqual, { #[inline] diff --git a/digest/src/buffer_macros.rs b/digest/src/buffer_macros.rs index f03fec8d..b0412f4f 100644 --- a/digest/src/buffer_macros.rs +++ b/digest/src/buffer_macros.rs @@ -1,4 +1,3 @@ mod fixed; -mod variable_ct; -mod variable_rt; +mod variable; mod xof; diff --git a/digest/src/buffer_macros/variable_ct.rs b/digest/src/buffer_macros/variable.rs similarity index 100% rename from digest/src/buffer_macros/variable_ct.rs rename to digest/src/buffer_macros/variable.rs diff --git a/digest/src/buffer_macros/variable_rt.rs b/digest/src/buffer_macros/variable_rt.rs deleted file mode 100644 index e39ff5ad..00000000 --- a/digest/src/buffer_macros/variable_rt.rs +++ /dev/null @@ -1,188 +0,0 @@ -/// Creates a buffered wrapper around block-level "core" type which implements variable output size traits -/// with output size selected at run time. -#[macro_export] -macro_rules! buffer_rt_variable { - ( - $(#[$attr:meta])* - $vis:vis struct $name:ident($core_ty:ty); - exclude: SerializableState; - ) => { - $(#[$attr])* - $vis struct $name { - core: $core_ty, - buffer: $crate::block_api::Buffer<$core_ty>, - output_size: u8, - } - - impl core::fmt::Debug for $name { - #[inline] - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str(concat!(stringify!($name), " { ... }")) - } - } - - impl $crate::crypto_common::AlgorithmName for $name { - #[inline] - fn write_alg_name(f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - <$core_ty as $crate::crypto_common::AlgorithmName>::write_alg_name(f) - } - } - - impl Clone for $name { - #[inline] - fn clone(&self) -> Self { - Self { - core: Clone::clone(&self.core), - buffer: Clone::clone(&self.buffer), - output_size: self.output_size, - } - } - } - - impl $crate::Reset for $name { - #[inline] - fn reset(&mut self) { - let size = self.output_size.into(); - self.core = <$core_ty as $crate::block_api::VariableOutputCore>::new(size).unwrap(); - self.buffer.reset(); - } - } - - impl $crate::block_api::BlockSizeUser for $name { - type BlockSize = <$core_ty as $crate::crypto_common::BlockSizeUser>::BlockSize; - } - - impl $crate::HashMarker for $name {} - - // Verify that `$wrapped_ty` implements `HashMarker` - const _: () = { - fn check(v: &$core_ty) { - v as &dyn $crate::HashMarker; - } - }; - - impl $crate::Update for $name { - #[inline] - fn update(&mut self, data: &[u8]) { - let Self { core, buffer, .. } = self; - buffer.digest_blocks(data, |blocks| { - $crate::block_api::UpdateCore::update_blocks(core, blocks); - }); - } - } - - impl $name { - #[inline] - fn finalize_dirty(&mut self, out: &mut [u8]) -> Result<(), $crate::InvalidBufferSize> { - let Self { - core, - buffer, - output_size, - } = self; - let size_u8 = u8::try_from(out.len()).map_err(|_| $crate::InvalidBufferSize)?; - - let max_size = ::MAX_OUTPUT_SIZE; - if out.len() > max_size || size_u8 != *output_size { - return Err($crate::InvalidBufferSize); - } - let mut full_res = Default::default(); - $crate::block_api::VariableOutputCore::finalize_variable_core(core, buffer, &mut full_res); - let n = out.len(); - let m = full_res.len() - n; - use $crate::block_api::TruncSide::{Left, Right}; - let side = <$core_ty as $crate::block_api::VariableOutputCore>::TRUNC_SIDE; - match side { - Left => out.copy_from_slice(&full_res[..n]), - Right => out.copy_from_slice(&full_res[m..]), - } - Ok(()) - } - } - - impl $crate::VariableOutput for $name { - const MAX_OUTPUT_SIZE: usize = < - <$core_ty as $crate::block_api::OutputSizeUser>::OutputSize - as $crate::typenum::Unsigned - >::USIZE; - - #[inline] - fn new(output_size: usize) -> Result { - let output_size = u8::try_from(output_size).map_err(|_| $crate::InvalidOutputSize)?; - let buffer = Default::default(); - let core = <$core_ty as $crate::block_api::VariableOutputCore>::new(output_size.into())?; - Ok(Self { - core, - buffer, - output_size, - }) - } - - #[inline] - fn output_size(&self) -> usize { - self.output_size.into() - } - - #[inline] - fn finalize_variable(mut self, out: &mut [u8]) -> Result<(), $crate::InvalidBufferSize> { - self.finalize_dirty(out) - } - } - - impl $crate::VariableOutputReset for $name { - #[inline] - fn finalize_variable_reset( - &mut self, - out: &mut [u8], - ) -> Result<(), $crate::InvalidBufferSize> { - self.finalize_dirty(out)?; - $crate::Reset::reset(self); - Ok(()) - } - } - - impl Drop for $name { - #[inline] - fn drop(&mut self) { - #[cfg(feature = "zeroize")] - { - use $crate::zeroize::Zeroize; - self.buffer.zeroize(); - self.output_size.zeroize(); - } - } - } - - #[cfg(feature = "zeroize")] - impl $crate::zeroize::ZeroizeOnDrop for $name {} - }; - - ( - $(#[$attr:meta])* - $vis:vis struct $name:ident($core_ty:ty); - ) => { - $crate::buffer_rt_variable!( - $(#[$attr])* - $vis struct $name($core_ty); - exclude: SerializableState; - ); - - impl $crate::crypto_common::hazmat::SerializableState for $name { - type SerializedStateSize = $crate::typenum::Add1<$crate::typenum::Sum< - <$core_ty as $crate::crypto_common::hazmat::SerializableState>::SerializedStateSize, - <$core_ty as $crate::block_api::BlockSizeUser>::BlockSize, - >>; - - #[inline] - fn serialize(&self) -> $crate::crypto_common::hazmat::SerializedState { - todo!() - } - - #[inline] - fn deserialize( - serialized_state: &$crate::crypto_common::hazmat::SerializedState, - ) -> Result { - todo!() - } - } - }; -} diff --git a/digest/src/dev.rs b/digest/src/dev.rs index da08409d..217bb0f9 100644 --- a/digest/src/dev.rs +++ b/digest/src/dev.rs @@ -6,13 +6,11 @@ mod fixed; #[cfg(feature = "mac")] mod mac; mod rng; -mod variable; mod xof; pub use fixed::*; #[cfg(feature = "mac")] pub use mac::*; -pub use variable::*; pub use xof::*; /// Test vector for hash functions diff --git a/digest/src/lib.rs b/digest/src/lib.rs index 23bb727e..2e5ee6bb 100644 --- a/digest/src/lib.rs +++ b/digest/src/lib.rs @@ -6,10 +6,9 @@ //! - **High-level convenience traits**: [`Digest`], [`DynDigest`], [`Mac`]. //! Wrappers around lower-level traits for most common use-cases. Users should //! usually prefer using these traits. -//! - **Mid-level traits**: [`Update`], [`FixedOutput`], [`FixedOutputReset`], -//! [`ExtendableOutput`], [`ExtendableOutputReset`], [`XofReader`], -//! [`VariableOutput`], [`Reset`], [`KeyInit`], and [`InnerInit`]. These -//! traits atomically describe available functionality of an algorithm. +//! - **Mid-level traits**: [`Update`], [`FixedOutput`], [`FixedOutputReset`], [`ExtendableOutput`], +//! [`ExtendableOutputReset`], [`XofReader`], [`Reset`], [`KeyInit`], and [`InnerInit`]. +//! These traits atomically describe available functionality of an algorithm. //! - **Marker traits**: [`HashMarker`], [`MacMarker`]. Used to distinguish //! different algorithm classes. //! - **Low-level traits** defined in the [`block_api`] module. These traits @@ -207,90 +206,12 @@ pub trait ExtendableOutputReset: ExtendableOutput + Reset { } } -/// Trait for hash functions with variable-size output. -pub trait VariableOutput: Sized + Update { - /// Maximum size of output hash in bytes. - const MAX_OUTPUT_SIZE: usize; - - /// Create new hasher instance with the given output size in bytes. - /// - /// It will return `Err(InvalidOutputSize)` in case if hasher can not return - /// hash of the specified output size. - fn new(output_size: usize) -> Result; - - /// Get output size in bytes of the hasher instance provided to the `new` method - fn output_size(&self) -> usize; - - /// Write result into the output buffer. - /// - /// Returns `Err(InvalidOutputSize)` if `out` size is not equal to - /// `self.output_size()`. - fn finalize_variable(self, out: &mut [u8]) -> Result<(), InvalidBufferSize>; - - /// Compute hash of `data` and write it to `output`. - /// - /// Length of the output hash is determined by `output`. If `output` is - /// bigger than `Self::MAX_OUTPUT_SIZE`, this method returns - /// `InvalidOutputSize`. - fn digest_variable( - input: impl AsRef<[u8]>, - output: &mut [u8], - ) -> Result<(), InvalidOutputSize> { - let mut hasher = Self::new(output.len())?; - hasher.update(input.as_ref()); - hasher - .finalize_variable(output) - .map_err(|_| InvalidOutputSize) - } - - /// Retrieve result into a boxed slice and consume hasher. - /// - /// `Box<[u8]>` is used instead of `Vec` to save stack space, since - /// they have size of 2 and 3 words respectively. - #[cfg(feature = "alloc")] - fn finalize_boxed(self) -> Box<[u8]> { - let n = self.output_size(); - let mut buf = vec![0u8; n].into_boxed_slice(); - self.finalize_variable(&mut buf) - .expect("buf length is equal to output_size"); - buf - } -} - -/// Trait for hash functions with variable-size output able to reset themselves. -pub trait VariableOutputReset: VariableOutput + Reset { - /// Write result into the output buffer and reset the hasher state. - /// - /// Returns `Err(InvalidOutputSize)` if `out` size is not equal to - /// `self.output_size()`. - fn finalize_variable_reset(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize>; - - /// Retrieve result into a boxed slice and reset the hasher state. - /// - /// `Box<[u8]>` is used instead of `Vec` to save stack space, since - /// they have size of 2 and 3 words respectively. - #[cfg(feature = "alloc")] - fn finalize_boxed_reset(&mut self) -> Box<[u8]> { - let n = self.output_size(); - let mut buf = vec![0u8; n].into_boxed_slice(); - self.finalize_variable_reset(&mut buf) - .expect("buf length is equal to output_size"); - buf - } -} - /// Trait for hash functions with customization string for domain separation. pub trait CustomizedInit: Sized { /// Create new hasher instance with the given customization string. fn new_customized(customization: &[u8]) -> Self; } -/// Trait adding customization string to hash functions with variable output. -pub trait VarOutputCustomized: Sized { - /// Create new hasher instance with the given customization string and output size. - fn new_customized(customization: &[u8], output_size: usize) -> Self; -} - /// Types with a certain collision resistance. pub trait CollisionResistance { /// Collision resistance in bytes. This applies to an output size of `CollisionResistance * 2`.