Skip to main content
This is unreleased documentation for the main (development) branch of crypto-glue.

digest/
digest.rs

1use super::{FixedOutput, FixedOutputReset, InvalidBufferSize, Reset, Update};
2use common::{Output, OutputSizeUser, typenum::Unsigned};
3
4#[cfg(feature = "alloc")]
5use alloc::boxed::Box;
6#[cfg(feature = "const-oid")]
7use const_oid::DynAssociatedOid;
8
9/// Marker trait for cryptographic hash functions.
10pub trait HashMarker {}
11
12/// Convenience wrapper trait covering functionality of cryptographic hash
13/// functions with fixed output size.
14///
15/// This trait wraps [`Update`], [`FixedOutput`], [`Default`], and
16/// [`HashMarker`] traits and provides additional convenience methods.
17pub trait Digest: OutputSizeUser {
18    /// Create new hasher instance.
19    fn new() -> Self;
20
21    /// Create new hasher instance which has processed the provided data.
22    fn new_with_prefix(data: impl AsRef<[u8]>) -> Self;
23
24    /// Process data, updating the internal state.
25    fn update(&mut self, data: impl AsRef<[u8]>);
26
27    /// Process input data in a chained manner.
28    #[must_use]
29    fn chain_update(self, data: impl AsRef<[u8]>) -> Self;
30
31    /// Retrieve result and consume hasher instance.
32    fn finalize(self) -> Output<Self>;
33
34    /// Write result into provided array and consume the hasher instance.
35    fn finalize_into(self, out: &mut Output<Self>);
36
37    /// Retrieve result and reset hasher instance.
38    fn finalize_reset(&mut self) -> Output<Self>
39    where
40        Self: FixedOutputReset;
41
42    /// Write result into provided array and reset the hasher instance.
43    fn finalize_into_reset(&mut self, out: &mut Output<Self>)
44    where
45        Self: FixedOutputReset;
46
47    /// Reset hasher instance to its initial state.
48    fn reset(&mut self)
49    where
50        Self: Reset;
51
52    /// Get output size of the hasher
53    fn output_size() -> usize;
54
55    /// Compute hash of `data`.
56    fn digest(data: impl AsRef<[u8]>) -> Output<Self>;
57}
58
59impl<D: FixedOutput + Default + Update + HashMarker> Digest for D {
60    #[inline]
61    fn new() -> Self {
62        Self::default()
63    }
64
65    #[inline]
66    fn new_with_prefix(data: impl AsRef<[u8]>) -> Self
67    where
68        Self: Default + Sized,
69    {
70        let mut h = Self::default();
71        h.update(data.as_ref());
72        h
73    }
74
75    #[inline]
76    fn update(&mut self, data: impl AsRef<[u8]>) {
77        Update::update(self, data.as_ref());
78    }
79
80    #[inline]
81    fn chain_update(mut self, data: impl AsRef<[u8]>) -> Self {
82        Update::update(&mut self, data.as_ref());
83        self
84    }
85
86    #[inline]
87    fn finalize(self) -> Output<Self> {
88        FixedOutput::finalize_fixed(self)
89    }
90
91    #[inline]
92    fn finalize_into(self, out: &mut Output<Self>) {
93        FixedOutput::finalize_into(self, out);
94    }
95
96    #[inline]
97    fn finalize_reset(&mut self) -> Output<Self>
98    where
99        Self: FixedOutputReset,
100    {
101        FixedOutputReset::finalize_fixed_reset(self)
102    }
103
104    #[inline]
105    fn finalize_into_reset(&mut self, out: &mut Output<Self>)
106    where
107        Self: FixedOutputReset,
108    {
109        FixedOutputReset::finalize_into_reset(self, out);
110    }
111
112    #[inline]
113    fn reset(&mut self)
114    where
115        Self: Reset,
116    {
117        Reset::reset(self)
118    }
119
120    #[inline]
121    fn output_size() -> usize {
122        Self::OutputSize::to_usize()
123    }
124
125    #[inline]
126    fn digest(data: impl AsRef<[u8]>) -> Output<Self> {
127        let mut hasher = Self::default();
128        hasher.update(data.as_ref());
129        hasher.finalize()
130    }
131}
132
133/// Modification of the [`Digest`] trait suitable for trait objects.
134pub trait DynDigest {
135    /// Digest input data.
136    ///
137    /// This method can be called repeatedly for use with streaming messages.
138    fn update(&mut self, data: &[u8]);
139
140    /// Retrieve result and reset hasher instance
141    #[cfg(feature = "alloc")]
142    fn finalize_reset(&mut self) -> Box<[u8]> {
143        let mut result = vec![0; self.output_size()];
144        self.finalize_into_reset(&mut result).unwrap();
145        result.into_boxed_slice()
146    }
147
148    /// Retrieve result and consume boxed hasher instance
149    #[cfg(feature = "alloc")]
150    #[allow(clippy::boxed_local)]
151    fn finalize(mut self: Box<Self>) -> Box<[u8]> {
152        let mut result = vec![0; self.output_size()];
153        self.finalize_into_reset(&mut result).unwrap();
154        result.into_boxed_slice()
155    }
156
157    /// Write result into provided array and consume the hasher instance.
158    ///
159    /// Returns error if buffer length is not equal to `output_size`.
160    fn finalize_into(self, buf: &mut [u8]) -> Result<(), InvalidBufferSize>;
161
162    /// Write result into provided array and reset the hasher instance.
163    ///
164    /// Returns error if buffer length is not equal to `output_size`.
165    fn finalize_into_reset(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize>;
166
167    /// Reset hasher instance to its initial state.
168    fn reset(&mut self);
169
170    /// Get output size of the hasher
171    fn output_size(&self) -> usize;
172
173    /// Clone hasher state into a boxed trait object
174    #[cfg(feature = "alloc")]
175    fn box_clone(&self) -> Box<dyn DynDigest>;
176}
177
178impl<D: Update + FixedOutputReset + Reset + Clone + 'static> DynDigest for D {
179    fn update(&mut self, data: &[u8]) {
180        Update::update(self, data);
181    }
182
183    #[cfg(feature = "alloc")]
184    fn finalize_reset(&mut self) -> Box<[u8]> {
185        FixedOutputReset::finalize_fixed_reset(self)
186            .to_vec()
187            .into_boxed_slice()
188    }
189
190    #[cfg(feature = "alloc")]
191    fn finalize(self: Box<Self>) -> Box<[u8]> {
192        FixedOutput::finalize_fixed(*self)
193            .to_vec()
194            .into_boxed_slice()
195    }
196
197    fn finalize_into(self, buf: &mut [u8]) -> Result<(), InvalidBufferSize> {
198        buf.try_into()
199            .map_err(|_| InvalidBufferSize)
200            .map(|buf| FixedOutput::finalize_into(self, buf))
201    }
202
203    fn finalize_into_reset(&mut self, buf: &mut [u8]) -> Result<(), InvalidBufferSize> {
204        let buf = <&mut Output<Self>>::try_from(buf).map_err(|_| InvalidBufferSize)?;
205        FixedOutputReset::finalize_into_reset(self, buf);
206        Ok(())
207    }
208
209    fn reset(&mut self) {
210        Reset::reset(self);
211    }
212
213    fn output_size(&self) -> usize {
214        <Self as OutputSizeUser>::OutputSize::to_usize()
215    }
216
217    #[cfg(feature = "alloc")]
218    fn box_clone(&self) -> Box<dyn DynDigest> {
219        Box::new(self.clone())
220    }
221}
222
223#[cfg(feature = "alloc")]
224impl Clone for Box<dyn DynDigest> {
225    fn clone(&self) -> Self {
226        self.box_clone()
227    }
228}
229
230/// Convenience wrapper trait around [DynDigest] and [DynAssociatedOid].
231#[cfg(feature = "const-oid")]
232pub trait DynDigestWithOid: DynDigest + DynAssociatedOid {}
233
234#[cfg(feature = "const-oid")]
235impl<T: DynDigest + DynAssociatedOid> DynDigestWithOid for T {}