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}
237