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