Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

digest: factor out fixed, variable, and xof modules #184

Merged
merged 1 commit into from Jun 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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