blob: 9373550ca06140166fced2ed36230371f61c196e [file] [log] [blame]
use super::{FixedOutput, FixedOutputReset, InvalidBufferSize, Reset, Update};
use crypto_common::{typenum::Unsigned, Output, OutputSizeUser};
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
/// Marker trait for cryptographic hash functions.
pub trait HashMarker {}
/// Convenience wrapper trait covering functionality of cryptographic hash
/// functions with fixed output size.
///
/// This trait wraps [`Update`], [`FixedOutput`], [`Default`], and
/// [`HashMarker`] traits and provides additional convenience methods.
pub trait Digest: OutputSizeUser {
/// Create new hasher instance.
fn new() -> Self;
/// Create new hasher instance which has processed the provided data.
fn new_with_prefix(data: impl AsRef<[u8]>) -> Self;
/// Process data, updating the internal state.
fn update(&mut self, data: impl AsRef<[u8]>);
/// Process input data in a chained manner.
#[must_use]
fn chain_update(self, data: impl AsRef<[u8]>) -> Self;
/// Retrieve result and consume hasher instance.
fn finalize(self) -> Output<Self>;
/// Write result into provided array and consume the hasher instance.
fn finalize_into(self, out: &mut Output<Self>);
/// Retrieve result and reset hasher instance.
fn finalize_reset(&mut self) -> Output<Self>
where
Self: FixedOutputReset;
/// Write result into provided array and reset the hasher instance.
fn finalize_into_reset(&mut self, out: &mut Output<Self>)
where
Self: FixedOutputReset;
/// Reset hasher instance to its initial state.
fn reset(&mut self)
where
Self: Reset;
/// Get output size of the hasher
fn output_size() -> usize;
/// Compute hash of `data`.
fn digest(data: impl AsRef<[u8]>) -> Output<Self>;
}
impl<D: FixedOutput + Default + Update + HashMarker> Digest for D {
#[inline]
fn new() -> Self {
Self::default()
}
#[inline]
fn new_with_prefix(data: impl AsRef<[u8]>) -> Self
where
Self: Default + Sized,
{
let mut h = Self::default();
h.update(data.as_ref());
h
}
#[inline]
fn update(&mut self, data: impl AsRef<[u8]>) {
Update::update(self, data.as_ref());
}
#[inline]
fn chain_update(mut self, data: impl AsRef<[u8]>) -> Self {
Update::update(&mut self, data.as_ref());
self
}
#[inline]
fn finalize(self) -> Output<Self> {
FixedOutput::finalize_fixed(self)
}
#[inline]
fn finalize_into(self, out: &mut Output<Self>) {
FixedOutput::finalize_into(self, out);
}
#[inline]
fn finalize_reset(&mut self) -> Output<Self>
where
Self: FixedOutputReset,
{
FixedOutputReset::finalize_fixed_reset(self)
}
#[inline]
fn finalize_into_reset(&mut self, out: &mut Output<Self>)
where
Self: FixedOutputReset,
{
FixedOutputReset::finalize_into_reset(self, out);
}
#[inline]
fn reset(&mut self)
where
Self: Reset,
{
Reset::reset(self)
}
#[inline]
fn output_size() -> usize {
Self::OutputSize::to_usize()
}
#[inline]
fn digest(data: impl AsRef<[u8]>) -> Output<Self> {
let mut hasher = Self::default();
hasher.update(data.as_ref());
hasher.finalize()
}
}
/// Modification of the [`Digest`] trait suitable for trait objects.
pub trait DynDigest {
/// Digest input data.
///
/// This method can be called repeatedly for use with streaming messages.
fn update(&mut self, data: &[u8]);
/// Retrieve result and reset hasher instance
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
fn finalize_reset(&mut self) -> Box<[u8]> {
let mut result = vec![0; self.output_size()];
self.finalize_into_reset(&mut result).unwrap();
result.into_boxed_slice()
}
/// Retrieve result and consume boxed hasher instance
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[allow(clippy::boxed_local)]
fn finalize(mut self: Box<Self>) -> Box<[u8]> {
let mut result = vec![0; self.output_size()];
self.finalize_into_reset(&mut result).unwrap();
result.into_boxed_slice()
}
/// Write result into provided array and consume the hasher instance.
///
/// Returns error if buffer length is not equal to `output_size`.
fn finalize_into(self, buf: &mut [u8]) -> Result<(), InvalidBufferSize>;
/// Write result into provided array and reset the hasher instance.
///
/// Returns error if buffer length is not equal to `output_size`.
fn finalize_into_reset(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize>;
/// Reset hasher instance to its initial state.
fn reset(&mut self);
/// Get output size of the hasher
fn output_size(&self) -> usize;
/// Clone hasher state into a boxed trait object
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
fn box_clone(&self) -> Box<dyn DynDigest>;
}
impl<D: Update + FixedOutputReset + Reset + Clone + 'static> DynDigest for D {
fn update(&mut self, data: &[u8]) {
Update::update(self, data);
}
#[cfg(feature = "alloc")]
fn finalize_reset(&mut self) -> Box<[u8]> {
FixedOutputReset::finalize_fixed_reset(self)
.to_vec()
.into_boxed_slice()
}
#[cfg(feature = "alloc")]
fn finalize(self: Box<Self>) -> Box<[u8]> {
FixedOutput::finalize_fixed(*self)
.to_vec()
.into_boxed_slice()
}
fn finalize_into(self, buf: &mut [u8]) -> Result<(), InvalidBufferSize> {
if buf.len() == self.output_size() {
FixedOutput::finalize_into(self, Output::<Self>::from_mut_slice(buf));
Ok(())
} else {
Err(InvalidBufferSize)
}
}
fn finalize_into_reset(&mut self, buf: &mut [u8]) -> Result<(), InvalidBufferSize> {
if buf.len() == self.output_size() {
FixedOutputReset::finalize_into_reset(self, Output::<Self>::from_mut_slice(buf));
Ok(())
} else {
Err(InvalidBufferSize)
}
}
fn reset(&mut self) {
Reset::reset(self);
}
fn output_size(&self) -> usize {
<Self as OutputSizeUser>::OutputSize::to_usize()
}
#[cfg(feature = "alloc")]
fn box_clone(&self) -> Box<dyn DynDigest> {
Box::new(self.clone())
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl Clone for Box<dyn DynDigest> {
fn clone(&self) -> Self {
self.box_clone()
}
}