Skip to content

Commit

Permalink
digest: factor out fixed, variable, and xof modules
Browse files Browse the repository at this point in the history
Each of these now defines two traits and a blanket impl, so `lib.rs` was
getting rather bloated.

This commit factors each of them into their own modules.
  • Loading branch information
tarcieri committed Jun 9, 2020
1 parent 4ce01a5 commit 5b4b533
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 262 deletions.
1 change: 1 addition & 0 deletions digest/src/dyn_digest.rs
Expand Up @@ -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.
///
Expand Down
69 changes: 69 additions & 0 deletions 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<u8>;

/// Write result into provided array and consume the hasher instance.
fn finalize_into(self, out: &mut GenericArray<u8, Self::OutputSize>);

/// Write result into provided array and reset the hasher instance.
fn finalize_into_reset(&mut self, out: &mut GenericArray<u8, Self::OutputSize>);

/// Retrieve result and consume the hasher instance.
#[inline]
fn finalize_fixed(self) -> GenericArray<u8, Self::OutputSize>
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<u8, Self::OutputSize> {
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<u8>;

/// 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<u8, Self::OutputSize>);
}

impl<D: FixedOutputDirty + Reset> FixedOutput for D {
type OutputSize = D::OutputSize;

#[inline]
fn finalize_into(mut self, out: &mut GenericArray<u8, Self::OutputSize>) {
self.finalize_into_dirty(out);
}

#[inline]
fn finalize_into_reset(&mut self, out: &mut GenericArray<u8, Self::OutputSize>) {
self.finalize_into_dirty(out);
self.reset();
}
}
269 changes: 7 additions & 262 deletions digest/src/lib.rs
Expand Up @@ -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 {
Expand Down Expand Up @@ -74,263 +76,6 @@ pub trait BlockInput {
type BlockSize: ArrayLength<u8>;
}

/// Trait for returning digest result with the fixed size
pub trait FixedOutput {
/// Output size for fixed output digest
type OutputSize: ArrayLength<u8>;

/// Write result into provided array and consume the hasher instance.
fn finalize_into(self, out: &mut GenericArray<u8, Self::OutputSize>);

/// Write result into provided array and reset the hasher instance.
fn finalize_into_reset(&mut self, out: &mut GenericArray<u8, Self::OutputSize>);

/// Retrieve result and consume the hasher instance.
#[inline]
fn finalize_fixed(self) -> GenericArray<u8, Self::OutputSize>
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<u8, Self::OutputSize> {
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<u8>;

/// 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<u8, Self::OutputSize>);
}

impl<D: FixedOutputDirty + Reset> FixedOutput for D {
type OutputSize = D::OutputSize;

#[inline]
fn finalize_into(mut self, out: &mut GenericArray<u8, Self::OutputSize>) {
self.finalize_into_dirty(out);
}

#[inline]
fn finalize_into_reset(&mut self, out: &mut GenericArray<u8, Self::OutputSize>) {
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<Self, InvalidOutputSize>;

/// 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<u8>` 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<u8>` 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<Self, InvalidOutputSize>;

/// 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<D: VariableOutputDirty + Reset> VariableOutput for D {
fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
<Self as VariableOutputDirty>::new(output_size)
}

fn output_size(&self) -> usize {
<Self as VariableOutputDirty>::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<u8>` 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<u8>` 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<u8>` 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<X: ExtendableOutputDirty + Reset> 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.
Expand Down

0 comments on commit 5b4b533

Please sign in to comment.