Skip to main content

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 = "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    #[must_use]
152    fn finalize(mut self: Box<Self>) -> Box<[u8]> {
153        let mut result = vec![0; self.output_size()];
154        self.finalize_into_reset(&mut result).unwrap();
155        result.into_boxed_slice()
156    }
157
158    /// Write result into provided array and consume the hasher instance.
159    ///
160    /// # Errors
161    /// If buffer length is not equal to `output_size`.
162    fn finalize_into(self, buf: &mut [u8]) -> Result<(), InvalidBufferSize>;
163
164    /// Write result into provided array and reset the hasher instance.
165    ///
166    /// # Errors
167    /// If buffer length is not equal to `output_size`.
168    fn finalize_into_reset(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize>;
169
170    /// Reset hasher instance to its initial state.
171    fn reset(&mut self);
172
173    /// Get output size of the hasher
174    fn output_size(&self) -> usize;
175
176    /// Clone hasher state into a boxed trait object
177    #[cfg(feature = "alloc")]
178    fn box_clone(&self) -> Box<dyn DynDigest>;
179}
180
181impl<D: Update + FixedOutputReset + Reset + Clone + 'static> DynDigest for D {
182    fn update(&mut self, data: &[u8]) {
183        Update::update(self, data);
184    }
185
186    #[cfg(feature = "alloc")]
187    fn finalize_reset(&mut self) -> Box<[u8]> {
188        FixedOutputReset::finalize_fixed_reset(self)
189            .to_vec()
190            .into_boxed_slice()
191    }
192
193    #[cfg(feature = "alloc")]
194    fn finalize(self: Box<Self>) -> Box<[u8]> {
195        FixedOutput::finalize_fixed(*self)
196            .to_vec()
197            .into_boxed_slice()
198    }
199
200    fn finalize_into(self, buf: &mut [u8]) -> Result<(), InvalidBufferSize> {
201        buf.try_into()
202            .map_err(|_| InvalidBufferSize)
203            .map(|buf| FixedOutput::finalize_into(self, buf))
204    }
205
206    fn finalize_into_reset(&mut self, buf: &mut [u8]) -> Result<(), InvalidBufferSize> {
207        let buf = <&mut Output<Self>>::try_from(buf).map_err(|_| InvalidBufferSize)?;
208        FixedOutputReset::finalize_into_reset(self, buf);
209        Ok(())
210    }
211
212    fn reset(&mut self) {
213        Reset::reset(self);
214    }
215
216    fn output_size(&self) -> usize {
217        <Self as OutputSizeUser>::OutputSize::to_usize()
218    }
219
220    #[cfg(feature = "alloc")]
221    fn box_clone(&self) -> Box<dyn DynDigest> {
222        Box::new(self.clone())
223    }
224}
225
226#[cfg(feature = "alloc")]
227impl Clone for Box<dyn DynDigest> {
228    fn clone(&self) -> Self {
229        self.box_clone()
230    }
231}
232
233/// Convenience wrapper trait around [DynDigest] and [DynAssociatedOid].
234#[cfg(feature = "oid")]
235pub trait DynDigestWithOid: DynDigest + DynAssociatedOid {}
236
237#[cfg(feature = "oid")]
238impl<T: DynDigest + DynAssociatedOid> DynDigestWithOid for T {}