diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/rust/digest/src/digest.rs | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/third_party/rust/digest/src/digest.rs b/third_party/rust/digest/src/digest.rs new file mode 100644 index 0000000000..9373550ca0 --- /dev/null +++ b/third_party/rust/digest/src/digest.rs @@ -0,0 +1,236 @@ +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() + } +} |