1 | use super::{FixedOutput, FixedOutputReset, InvalidBufferSize, Reset, Update}; |
2 | use crypto_common::{typenum::Unsigned, Output, OutputSizeUser}; |
3 | |
4 | #[cfg (feature = "alloc" )] |
5 | use alloc::boxed::Box; |
6 | |
7 | /// Marker trait for cryptographic hash functions. |
8 | pub 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. |
15 | pub 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 | |
57 | impl<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. |
132 | pub 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 | |
179 | impl<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" )))] |
232 | impl Clone for Box<dyn DynDigest> { |
233 | fn clone(&self) -> Self { |
234 | self.box_clone() |
235 | } |
236 | } |
237 | |