digest/
digest.rs

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