From 2526a6a456fde21cd6c387483cad23acbc202617 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 9 Jun 2020 10:10:43 -0700 Subject: [PATCH] digest: add `FixedOutputDirty` trait + `finalize_into*` Adds a `FixedOutputDirty` trait which writes the digest output to a provided byte array, but does not reset the internal state. This is intended for implementations to use in order to ensure that they are not reset in the event the instance is consumed. Also adds a set of `finalize_into` and `finalize_into_reset` methods to `FixedOutput` whhich also write their input into a provided byte array, and changes the existing `finalize_fixed` (and newly added `finalize_fixed_reset`) methods to have a default implementation which returns a byte array allocated on the stack. Finally, adds a blanket impl of `FixedOutput` for `FixedOutputDirty` + `Reset` types which handles safely invoking the underlying implementation by either consuming the instance (avoiding a reset) or borrowing the hasher, obtaining the output, and resetting. --- digest/src/dyn_digest.rs | 2 +- digest/src/lib.rs | 60 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/digest/src/dyn_digest.rs b/digest/src/dyn_digest.rs index c836ab447..4515c290f 100644 --- a/digest/src/dyn_digest.rs +++ b/digest/src/dyn_digest.rs @@ -34,7 +34,7 @@ impl DynDigest for D { } fn finalize_reset(&mut self) -> Box<[u8]> { - let res = self.clone().finalize_fixed().to_vec().into_boxed_slice(); + let res = self.finalize_fixed_reset().to_vec().into_boxed_slice(); Reset::reset(self); res } diff --git a/digest/src/lib.rs b/digest/src/lib.rs index 79bef801d..72a7e00a9 100644 --- a/digest/src/lib.rs +++ b/digest/src/lib.rs @@ -79,8 +79,64 @@ pub trait FixedOutput { /// Output size for fixed output digest type OutputSize: ArrayLength; - /// Retrieve result and consume hasher instance. - fn finalize_fixed(self) -> GenericArray; + /// 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