1use super::{FixedOutput, FixedOutputReset, InvalidBufferSize, Reset, Update};
2use crypto_common::{typenum::Unsigned, Output, OutputSizeUser};
3
4#[cfg(feature = "alloc")]
5use alloc::boxed::Box;
6
7pub trait HashMarker {}
9
10pub trait Digest: OutputSizeUser {
16    fn new() -> Self;
18
19    fn new_with_prefix(data: impl AsRef<[u8]>) -> Self;
21
22    fn update(&mut self, data: impl AsRef<[u8]>);
24
25    #[must_use]
27    fn chain_update(self, data: impl AsRef<[u8]>) -> Self;
28
29    fn finalize(self) -> Output<Self>;
31
32    fn finalize_into(self, out: &mut Output<Self>);
34
35    fn finalize_reset(&mut self) -> Output<Self>
37    where
38        Self: FixedOutputReset;
39
40    fn finalize_into_reset(&mut self, out: &mut Output<Self>)
42    where
43        Self: FixedOutputReset;
44
45    fn reset(&mut self)
47    where
48        Self: Reset;
49
50    fn output_size() -> usize;
52
53    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
131pub trait DynDigest {
133    fn update(&mut self, data: &[u8]);
137
138    #[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    #[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    fn finalize_into(self, buf: &mut [u8]) -> Result<(), InvalidBufferSize>;
161
162    fn finalize_into_reset(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize>;
166
167    fn reset(&mut self);
169
170    fn output_size(&self) -> usize;
172
173    #[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}