diff --git a/digest/src/dyn_digest.rs b/digest/src/dyn_digest.rs index 4515c290f..156f9bdbf 100644 --- a/digest/src/dyn_digest.rs +++ b/digest/src/dyn_digest.rs @@ -6,6 +6,7 @@ use generic_array::typenum::Unsigned; /// The `DynDigest` trait is a modification of `Digest` trait suitable /// for trait objects. +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub trait DynDigest { /// Digest input data. /// diff --git a/digest/src/fixed.rs b/digest/src/fixed.rs new file mode 100644 index 000000000..4f0e22098 --- /dev/null +++ b/digest/src/fixed.rs @@ -0,0 +1,69 @@ +//! Fixed-size output digest support + +use crate::Reset; +use generic_array::{ArrayLength, GenericArray}; + +/// Trait for returning digest result with the fixed size +pub trait FixedOutput { + /// Output size for fixed output digest + type OutputSize: ArrayLength; + + /// Write result into provided array and consume the hasher instance. + fn finalize_into(self, out: &mut GenericArray); + + /// Write result into provided array and reset the hasher instance. + fn finalize_into_reset(&mut self, out: &mut GenericArray); + + /// Retrieve result and consume the hasher instance. + #[inline] + fn finalize_fixed(self) -> GenericArray + where + Self: Sized, + { + let mut out = Default::default(); + self.finalize_into(&mut out); + out + } + + /// Retrieve result and reset the hasher instance. + #[inline] + fn finalize_fixed_reset(&mut self) -> GenericArray { + let mut out = Default::default(); + self.finalize_into_reset(&mut out); + out + } +} + +/// Trait for fixed-output digest implementations to use to retrieve the +/// hash output. +/// +/// Usage of this trait in user code is discouraged. Instead use the +/// [`FixedOutput::finalize_fixed`] or [`FixedOutput::finalize_fixed_reset`] +/// methods. +/// +/// Types which impl this trait along with [`Reset`] will receive a blanket +/// impl of [`FixedOutput`]. +pub trait FixedOutputDirty { + /// Output size for fixed output digest + type OutputSize: ArrayLength; + + /// Retrieve result into provided buffer and leave hasher in a dirty state. + /// + /// Implementations should panic if this is called twice without resetting. + fn finalize_into_dirty(&mut self, out: &mut GenericArray); +} + +impl FixedOutput for D { + type OutputSize = D::OutputSize; + + #[inline] + fn finalize_into(mut self, out: &mut GenericArray) { + self.finalize_into_dirty(out); + } + + #[inline] + fn finalize_into_reset(&mut self, out: &mut GenericArray) { + self.finalize_into_dirty(out); + self.reset(); + } +} diff --git a/digest/src/lib.rs b/digest/src/lib.rs index bbdc25e75..094598629 100644 --- a/digest/src/lib.rs +++ b/digest/src/lib.rs @@ -33,19 +33,21 @@ pub mod dev; mod digest; mod dyn_digest; mod errors; +mod fixed; +mod variable; +mod xof; pub use crate::digest::{Digest, Output}; pub use crate::errors::InvalidOutputSize; +pub use crate::fixed::{FixedOutput, FixedOutputDirty}; +pub use crate::variable::{VariableOutput, VariableOutputDirty}; +pub use crate::xof::{ExtendableOutput, ExtendableOutputDirty, XofReader}; pub use generic_array::{self, typenum::consts}; #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub use dyn_digest::DynDigest; -use generic_array::{ArrayLength, GenericArray}; - -#[cfg(feature = "alloc")] -use alloc::boxed::Box; +use generic_array::ArrayLength; /// Trait for updating digest state with input data. pub trait Update { @@ -74,263 +76,6 @@ pub trait BlockInput { type BlockSize: ArrayLength; } -/// Trait for returning digest result with the fixed size -pub trait FixedOutput { - /// Output size for fixed output digest - type OutputSize: ArrayLength; - - /// Write result into provided array and consume the hasher instance. - fn finalize_into(self, out: &mut GenericArray); - - /// Write result into provided array and reset the hasher instance. - fn finalize_into_reset(&mut self, out: &mut GenericArray); - - /// Retrieve result and consume the hasher instance. - #[inline] - fn finalize_fixed(self) -> GenericArray - where - Self: Sized, - { - let mut out = Default::default(); - self.finalize_into(&mut out); - out - } - - /// Retrieve result and reset the hasher instance. - #[inline] - fn finalize_fixed_reset(&mut self) -> GenericArray { - let mut out = Default::default(); - self.finalize_into_reset(&mut out); - out - } -} - -/// Trait for fixed-output digest implementations to use to retrieve the -/// hash output. -/// -/// Usage of this trait in user code is discouraged. Instead use the -/// [`FixedOutput::finalize_fixed`] or [`FixedOutput::finalize_fixed_reset`] -/// methods. -/// -/// Types which impl this trait along with [`Reset`] will receive a blanket -/// impl of [`FixedOutput`]. -pub trait FixedOutputDirty { - /// Output size for fixed output digest - type OutputSize: ArrayLength; - - /// Retrieve result into provided buffer and leave hasher in a dirty state. - /// - /// Implementations should panic if this is called twice without resetting. - fn finalize_into_dirty(&mut self, out: &mut GenericArray); -} - -impl FixedOutput for D { - type OutputSize = D::OutputSize; - - #[inline] - fn finalize_into(mut self, out: &mut GenericArray) { - self.finalize_into_dirty(out); - } - - #[inline] - fn finalize_into_reset(&mut self, out: &mut GenericArray) { - self.finalize_into_dirty(out); - self.reset(); - } -} - -/// Trait for returning digest result with the variable size -pub trait VariableOutput: Sized { - /// Create new hasher instance with the given output size. - /// - /// It will return `Err(InvalidOutputSize)` in case if hasher can not return - /// specified output size. It will always return an error if output size - /// equals to zero. - fn new(output_size: usize) -> Result; - - /// Get output size of the hasher instance provided to the `new` method - fn output_size(&self) -> usize; - - /// Retrieve result via closure and consume hasher. - /// - /// Closure is guaranteed to be called, length of the buffer passed to it - /// will be equal to `output_size`. - fn finalize_variable(self, f: impl FnOnce(&[u8])); - - /// Retrieve result via closure and reset the hasher state. - /// - /// Closure is guaranteed to be called, length of the buffer passed to it - /// will be equal to `output_size`. - fn finalize_variable_reset(&mut self, f: impl FnOnce(&[u8])); - - /// 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")] - #[cfg_attr(docsrs, doc(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(|res| buf.copy_from_slice(res)); - buf - } - - /// Retrieve result into a boxed slice and reset 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")] - #[cfg_attr(docsrs, doc(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(|res| buf.copy_from_slice(res)); - buf - } -} - -/// Trait for variable-sized output digest implementations to use to retrieve -/// the hash output. -/// -/// Usage of this trait in user code is discouraged. Instead use the -/// [`VariableOutput::finalize_variable`] or -/// [`VariableOutput::finalize_variable_reset`] methods. -/// -/// Types which impl this trait along with [`Reset`] will receive a blanket -/// impl of [`VariableOutput`]. -pub trait VariableOutputDirty: Sized { - /// Create new hasher instance with the given output size. - /// - /// It will return `Err(InvalidOutputSize)` in case if hasher can not return - /// specified output size. It will always return an error if output size - /// equals to zero. - fn new(output_size: usize) -> Result; - - /// Get output size of the hasher instance provided to the `new` method - fn output_size(&self) -> usize; - - /// Retrieve result into provided buffer and leave hasher in a dirty state. - /// - /// Implementations should panic if this is called twice without resetting. - fn finalize_variable_dirty(&mut self, f: impl FnOnce(&[u8])); -} - -impl VariableOutput for D { - fn new(output_size: usize) -> Result { - ::new(output_size) - } - - fn output_size(&self) -> usize { - ::output_size(self) - } - - #[inline] - fn finalize_variable(mut self, f: impl FnOnce(&[u8])) { - self.finalize_variable_dirty(f); - } - - #[inline] - fn finalize_variable_reset(&mut self, f: impl FnOnce(&[u8])) { - self.finalize_variable_dirty(f); - self.reset(); - } -} - -/// Trait for describing readers which are used to extract extendable output -/// from XOF (extendable-output function) result. -pub trait XofReader { - /// Read output into the `buffer`. Can be called an unlimited number of times. - fn read(&mut self, buffer: &mut [u8]); - - /// Read output into a boxed slice of the specified size. - /// - /// Can be called an unlimited number of times in combination with `read`. - /// - /// `Box<[u8]>` is used instead of `Vec` to save stack space, since - /// they have size of 2 and 3 words respectively. - #[cfg(feature = "alloc")] - #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] - fn read_boxed(&mut self, n: usize) -> Box<[u8]> { - let mut buf = vec![0u8; n].into_boxed_slice(); - self.read(&mut buf); - buf - } -} - -/// Trait which describes extendable-output functions (XOF). -pub trait ExtendableOutput: Sized { - /// Reader - type Reader: XofReader; - - /// Retrieve XOF reader and consume hasher instance. - fn finalize_xof(self) -> Self::Reader; - - /// Retrieve XOF reader and reset hasher instance state. - fn finalize_xof_reset(&mut self) -> Self::Reader; - - /// Retrieve result into a boxed slice of the specified size and consume - /// the 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")] - #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] - fn finalize_boxed(self, n: usize) -> Box<[u8]> { - let mut buf = vec![0u8; n].into_boxed_slice(); - self.finalize_xof().read(&mut buf); - buf - } - - /// Retrieve result into a boxed slice of the specified size and reset - /// the hasher's 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")] - #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] - fn finalize_boxed_reset(&mut self, n: usize) -> Box<[u8]> { - let mut buf = vec![0u8; n].into_boxed_slice(); - self.finalize_xof_reset().read(&mut buf); - buf - } -} - -/// Trait for extendable-output function (XOF) implementations to use to -/// retrieve the hash output. -/// -/// Usage of this trait in user code is discouraged. Instead use the -/// [`VariableOutput::finalize_variable`] or -/// [`VariableOutput::finalize_variable_reset`] methods. -/// -/// Types which impl this trait along with [`Reset`] will receive a blanket -/// impl of [`VariableOutput`]. -pub trait ExtendableOutputDirty: Sized { - /// Reader - type Reader: XofReader; - - /// Retrieve XOF reader and consume hasher instance. - /// - /// Implementations should panic if this is called twice without resetting. - fn finalize_xof_dirty(&mut self) -> Self::Reader; -} - -impl ExtendableOutput for X { - type Reader = X::Reader; - - #[inline] - fn finalize_xof(mut self) -> Self::Reader { - self.finalize_xof_dirty() - } - - #[inline] - fn finalize_xof_reset(&mut self) -> Self::Reader { - let reader = self.finalize_xof_dirty(); - self.reset(); - reader - } -} - /// Trait for resetting hash instances pub trait Reset { /// Reset hasher instance to its initial state and return current state. diff --git a/digest/src/variable.rs b/digest/src/variable.rs new file mode 100644 index 000000000..42f280ae1 --- /dev/null +++ b/digest/src/variable.rs @@ -0,0 +1,104 @@ +//! Variable-sized output digest support + +use crate::{InvalidOutputSize, Reset}; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +/// Trait for returning digest result with the variable size +pub trait VariableOutput: Sized { + /// Create new hasher instance with the given output size. + /// + /// It will return `Err(InvalidOutputSize)` in case if hasher can not return + /// specified output size. It will always return an error if output size + /// equals to zero. + fn new(output_size: usize) -> Result; + + /// Get output size of the hasher instance provided to the `new` method + fn output_size(&self) -> usize; + + /// Retrieve result via closure and consume hasher. + /// + /// Closure is guaranteed to be called, length of the buffer passed to it + /// will be equal to `output_size`. + fn finalize_variable(self, f: impl FnOnce(&[u8])); + + /// Retrieve result via closure and reset the hasher state. + /// + /// Closure is guaranteed to be called, length of the buffer passed to it + /// will be equal to `output_size`. + fn finalize_variable_reset(&mut self, f: impl FnOnce(&[u8])); + + /// 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")] + #[cfg_attr(docsrs, doc(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(|res| buf.copy_from_slice(res)); + buf + } + + /// Retrieve result into a boxed slice and reset 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")] + #[cfg_attr(docsrs, doc(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(|res| buf.copy_from_slice(res)); + buf + } +} + +/// Trait for variable-sized output digest implementations to use to retrieve +/// the hash output. +/// +/// Usage of this trait in user code is discouraged. Instead use the +/// [`VariableOutput::finalize_variable`] or +/// [`VariableOutput::finalize_variable_reset`] methods. +/// +/// Types which impl this trait along with [`Reset`] will receive a blanket +/// impl of [`VariableOutput`]. +pub trait VariableOutputDirty: Sized { + /// Create new hasher instance with the given output size. + /// + /// It will return `Err(InvalidOutputSize)` in case if hasher can not return + /// specified output size. It will always return an error if output size + /// equals to zero. + fn new(output_size: usize) -> Result; + + /// Get output size of the hasher instance provided to the `new` method + fn output_size(&self) -> usize; + + /// Retrieve result into provided buffer and leave hasher in a dirty state. + /// + /// Implementations should panic if this is called twice without resetting. + fn finalize_variable_dirty(&mut self, f: impl FnOnce(&[u8])); +} + +impl VariableOutput for D { + fn new(output_size: usize) -> Result { + ::new(output_size) + } + + fn output_size(&self) -> usize { + ::output_size(self) + } + + #[inline] + fn finalize_variable(mut self, f: impl FnOnce(&[u8])) { + self.finalize_variable_dirty(f); + } + + #[inline] + fn finalize_variable_reset(&mut self, f: impl FnOnce(&[u8])) { + self.finalize_variable_dirty(f); + self.reset(); + } +} diff --git a/digest/src/xof.rs b/digest/src/xof.rs new file mode 100644 index 000000000..518477860 --- /dev/null +++ b/digest/src/xof.rs @@ -0,0 +1,100 @@ +//! Extendable-Output Function (XOF) support + +use crate::Reset; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +/// Trait for describing readers which are used to extract extendable output +/// from XOF (extendable-output function) result. +pub trait XofReader { + /// Read output into the `buffer`. Can be called an unlimited number of times. + fn read(&mut self, buffer: &mut [u8]); + + /// Read output into a boxed slice of the specified size. + /// + /// Can be called an unlimited number of times in combination with `read`. + /// + /// `Box<[u8]>` is used instead of `Vec` to save stack space, since + /// they have size of 2 and 3 words respectively. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn read_boxed(&mut self, n: usize) -> Box<[u8]> { + let mut buf = vec![0u8; n].into_boxed_slice(); + self.read(&mut buf); + buf + } +} + +/// Trait which describes extendable-output functions (XOF). +pub trait ExtendableOutput: Sized { + /// Reader + type Reader: XofReader; + + /// Retrieve XOF reader and consume hasher instance. + fn finalize_xof(self) -> Self::Reader; + + /// Retrieve XOF reader and reset hasher instance state. + fn finalize_xof_reset(&mut self) -> Self::Reader; + + /// Retrieve result into a boxed slice of the specified size and consume + /// the 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")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn finalize_boxed(self, n: usize) -> Box<[u8]> { + let mut buf = vec![0u8; n].into_boxed_slice(); + self.finalize_xof().read(&mut buf); + buf + } + + /// Retrieve result into a boxed slice of the specified size and reset + /// the hasher's 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")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn finalize_boxed_reset(&mut self, n: usize) -> Box<[u8]> { + let mut buf = vec![0u8; n].into_boxed_slice(); + self.finalize_xof_reset().read(&mut buf); + buf + } +} + +/// Trait for extendable-output function (XOF) implementations to use to +/// retrieve the hash output. +/// +/// Usage of this trait in user code is discouraged. Instead use the +/// [`ExtendableOutput::finalize_xof`] or +/// [`ExtendableOutput::finalize_xof_reset`] methods. +/// +/// Types which impl this trait along with [`Reset`] will receive a blanket +/// impl of [`ExtendableOutput`]. +pub trait ExtendableOutputDirty: Sized { + /// Reader + type Reader: XofReader; + + /// Retrieve XOF reader and consume hasher instance. + /// + /// Implementations should panic if this is called twice without resetting. + fn finalize_xof_dirty(&mut self) -> Self::Reader; +} + +impl ExtendableOutput for X { + type Reader = X::Reader; + + #[inline] + fn finalize_xof(mut self) -> Self::Reader { + self.finalize_xof_dirty() + } + + #[inline] + fn finalize_xof_reset(&mut self) -> Self::Reader { + let reader = self.finalize_xof_dirty(); + self.reset(); + reader + } +}