miden_crypto/hash/sha2/
mod.rs1use alloc::string::String;
14use core::{
15 mem::size_of,
16 ops::Deref,
17 slice::{self, from_raw_parts},
18};
19
20use p3_field::{BasedVectorSpace, PrimeField64};
21use sha2::Digest as Sha2Digest;
22
23use super::{Felt, HasherExt};
24use crate::utils::{
25 ByteReader, ByteWriter, Deserializable, DeserializationError, HexParseError, Serializable,
26 bytes_to_hex_string, hex_to_bytes,
27};
28
29#[cfg(test)]
30mod tests;
31
32const DIGEST256_BYTES: usize = 32;
36const DIGEST512_BYTES: usize = 64;
37
38#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
43#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
44#[cfg_attr(feature = "serde", serde(into = "String", try_from = "&str"))]
45#[repr(transparent)]
46pub struct Sha256Digest([u8; DIGEST256_BYTES]);
47
48impl Sha256Digest {
49 pub fn as_bytes(&self) -> &[u8; DIGEST256_BYTES] {
50 &self.0
51 }
52
53 pub fn digests_as_bytes(digests: &[Sha256Digest]) -> &[u8] {
54 let p = digests.as_ptr();
55 let len = digests.len() * DIGEST256_BYTES;
56 unsafe { slice::from_raw_parts(p as *const u8, len) }
57 }
58}
59
60impl Default for Sha256Digest {
61 fn default() -> Self {
62 Self([0; DIGEST256_BYTES])
63 }
64}
65
66impl Deref for Sha256Digest {
67 type Target = [u8];
68
69 fn deref(&self) -> &Self::Target {
70 &self.0
71 }
72}
73
74impl From<Sha256Digest> for [u8; DIGEST256_BYTES] {
75 fn from(value: Sha256Digest) -> Self {
76 value.0
77 }
78}
79
80impl From<[u8; DIGEST256_BYTES]> for Sha256Digest {
81 fn from(value: [u8; DIGEST256_BYTES]) -> Self {
82 Self(value)
83 }
84}
85
86impl From<Sha256Digest> for String {
87 fn from(value: Sha256Digest) -> Self {
88 bytes_to_hex_string(*value.as_bytes())
89 }
90}
91
92impl TryFrom<&str> for Sha256Digest {
93 type Error = HexParseError;
94
95 fn try_from(value: &str) -> Result<Self, Self::Error> {
96 hex_to_bytes(value).map(|v| v.into())
97 }
98}
99
100impl Serializable for Sha256Digest {
101 fn write_into<W: ByteWriter>(&self, target: &mut W) {
102 target.write_bytes(&self.0);
103 }
104}
105
106impl Deserializable for Sha256Digest {
107 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
108 source.read_array().map(Self)
109 }
110}
111
112#[derive(Debug, Copy, Clone, Eq, PartialEq)]
117pub struct Sha256;
118
119impl HasherExt for Sha256 {
120 type Digest = Sha256Digest;
121
122 fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
123 let mut hasher = sha2::Sha256::new();
124 for slice in slices {
125 hasher.update(slice);
126 }
127 Sha256Digest(hasher.finalize().into())
128 }
129}
130
131impl Sha256 {
132 pub const COLLISION_RESISTANCE: u32 = 128;
134
135 pub fn hash(bytes: &[u8]) -> Sha256Digest {
136 let mut hasher = sha2::Sha256::new();
137 hasher.update(bytes);
138
139 Sha256Digest(hasher.finalize().into())
140 }
141
142 pub fn merge(values: &[Sha256Digest; 2]) -> Sha256Digest {
143 Self::hash(prepare_merge(values))
144 }
145
146 pub fn merge_many(values: &[Sha256Digest]) -> Sha256Digest {
147 let data = Sha256Digest::digests_as_bytes(values);
148 let mut hasher = sha2::Sha256::new();
149 hasher.update(data);
150
151 Sha256Digest(hasher.finalize().into())
152 }
153
154 pub fn merge_with_int(seed: Sha256Digest, value: u64) -> Sha256Digest {
155 let mut hasher = sha2::Sha256::new();
156 hasher.update(seed.0);
157 hasher.update(value.to_le_bytes());
158
159 Sha256Digest(hasher.finalize().into())
160 }
161
162 #[inline(always)]
164 pub fn hash_elements<E: BasedVectorSpace<Felt>>(elements: &[E]) -> Sha256Digest {
165 Sha256Digest(hash_elements_256(elements))
166 }
167
168 #[inline(always)]
170 pub fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Sha256Digest {
171 <Self as HasherExt>::hash_iter(slices)
172 }
173}
174
175#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
180#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
181#[cfg_attr(feature = "serde", serde(into = "String", try_from = "&str"))]
182#[repr(transparent)]
183pub struct Sha512Digest([u8; DIGEST512_BYTES]);
184
185impl Sha512Digest {
186 pub fn digests_as_bytes(digests: &[Sha512Digest]) -> &[u8] {
187 let p = digests.as_ptr();
188 let len = digests.len() * DIGEST512_BYTES;
189 unsafe { slice::from_raw_parts(p as *const u8, len) }
190 }
191}
192
193impl Default for Sha512Digest {
194 fn default() -> Self {
195 Self([0; DIGEST512_BYTES])
196 }
197}
198
199impl Deref for Sha512Digest {
200 type Target = [u8];
201
202 fn deref(&self) -> &Self::Target {
203 &self.0
204 }
205}
206
207impl From<Sha512Digest> for [u8; DIGEST512_BYTES] {
208 fn from(value: Sha512Digest) -> Self {
209 value.0
210 }
211}
212
213impl From<[u8; DIGEST512_BYTES]> for Sha512Digest {
214 fn from(value: [u8; DIGEST512_BYTES]) -> Self {
215 Self(value)
216 }
217}
218
219impl From<Sha512Digest> for String {
220 fn from(value: Sha512Digest) -> Self {
221 bytes_to_hex_string(value.0)
222 }
223}
224
225impl TryFrom<&str> for Sha512Digest {
226 type Error = HexParseError;
227
228 fn try_from(value: &str) -> Result<Self, Self::Error> {
229 hex_to_bytes(value).map(|v| v.into())
230 }
231}
232
233impl Serializable for Sha512Digest {
234 fn write_into<W: ByteWriter>(&self, target: &mut W) {
235 target.write_bytes(&self.0);
236 }
237}
238
239impl Deserializable for Sha512Digest {
240 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
241 source.read_array().map(Self)
242 }
243}
244
245#[derive(Debug, Copy, Clone, Eq, PartialEq)]
257pub struct Sha512;
258
259impl Sha512 {
260 #[inline(always)]
262 pub fn hash(bytes: &[u8]) -> Sha512Digest {
263 let mut hasher = sha2::Sha512::new();
264 hasher.update(bytes);
265 Sha512Digest(hasher.finalize().into())
266 }
267
268 #[inline(always)]
271 pub fn merge(values: &[Sha512Digest; 2]) -> Sha512Digest {
272 Self::hash(prepare_merge(values))
273 }
274
275 #[inline(always)]
277 pub fn merge_many(values: &[Sha512Digest]) -> Sha512Digest {
278 let data = Sha512Digest::digests_as_bytes(values);
279 let mut hasher = sha2::Sha512::new();
280 hasher.update(data);
281 Sha512Digest(hasher.finalize().into())
282 }
283
284 #[inline(always)]
286 pub fn hash_elements<E>(elements: &[E]) -> Sha512Digest
287 where
288 E: BasedVectorSpace<Felt>,
289 {
290 Sha512Digest(hash_elements_512(elements))
291 }
292
293 #[inline(always)]
295 pub fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Sha512Digest {
296 let mut hasher = sha2::Sha512::new();
297 for slice in slices {
298 hasher.update(slice);
299 }
300 Sha512Digest(hasher.finalize().into())
301 }
302}
303
304fn hash_elements_256<E>(elements: &[E]) -> [u8; DIGEST256_BYTES]
309where
310 E: BasedVectorSpace<Felt>,
311{
312 let digest = {
313 const FELT_BYTES: usize = size_of::<u64>();
314 const { assert!(FELT_BYTES == 8, "buffer arithmetic assumes 8-byte field elements") };
315
316 let mut hasher = sha2::Sha256::new();
317 let mut buf = [0_u8; 64];
319 let mut buf_offset = 0;
320
321 for elem in elements.iter() {
322 for &felt in E::as_basis_coefficients_slice(elem) {
323 buf[buf_offset..buf_offset + FELT_BYTES]
324 .copy_from_slice(&felt.as_canonical_u64().to_le_bytes());
325 buf_offset += FELT_BYTES;
326
327 if buf_offset == 64 {
328 hasher.update(buf);
329 buf_offset = 0;
330 }
331 }
332 }
333
334 if buf_offset > 0 {
335 hasher.update(&buf[..buf_offset]);
336 }
337
338 hasher.finalize()
339 };
340 digest.into()
341}
342
343fn hash_elements_512<E>(elements: &[E]) -> [u8; DIGEST512_BYTES]
345where
346 E: BasedVectorSpace<Felt>,
347{
348 let digest = {
349 const FELT_BYTES: usize = size_of::<u64>();
350 const { assert!(FELT_BYTES == 8, "buffer arithmetic assumes 8-byte field elements") };
351
352 let mut hasher = sha2::Sha512::new();
353 let mut buf = [0_u8; 128];
355 let mut buf_offset = 0;
356
357 for elem in elements.iter() {
358 for &felt in E::as_basis_coefficients_slice(elem) {
359 buf[buf_offset..buf_offset + FELT_BYTES]
360 .copy_from_slice(&felt.as_canonical_u64().to_le_bytes());
361 buf_offset += FELT_BYTES;
362
363 if buf_offset == 128 {
364 hasher.update(buf);
365 buf_offset = 0;
366 }
367 }
368 }
369
370 if buf_offset > 0 {
371 hasher.update(&buf[..buf_offset]);
372 }
373
374 hasher.finalize()
375 };
376 digest.into()
377}
378
379fn prepare_merge<const N: usize, D>(args: &[D; N]) -> &[u8]
381where
382 D: Deref<Target = [u8]>,
383{
384 assert!(N > 0, "N shouldn't represent an empty slice!");
386 let values = args.as_ptr() as *const u8;
387 let len = size_of::<D>() * N;
388 let bytes = unsafe { from_raw_parts(values, len) };
390 debug_assert_eq!(args[0].deref(), &bytes[..len / N]);
391 bytes
392}