miden_crypto/hash/sha2/
mod.rs1use core::mem::size_of;
4
5use sha2::Digest as Sha2Digest;
6
7use super::{
8 Felt, HasherExt,
9 digest::{DIGEST256_BYTES, DIGEST512_BYTES, Digest256, Digest512},
10};
11use crate::field::BasedVectorSpace;
12
13#[cfg(test)]
14mod tests;
15
16pub type Sha256Digest = Digest256;
23
24#[derive(Debug, Copy, Clone, Eq, PartialEq)]
29pub struct Sha256;
30
31impl HasherExt for Sha256 {
32 type Digest = Sha256Digest;
33
34 fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
35 let mut hasher = sha2::Sha256::new();
36 for slice in slices {
37 hasher.update(slice);
38 }
39 Sha256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
40 }
41}
42
43impl Sha256 {
44 pub const COLLISION_RESISTANCE: u32 = 128;
46
47 pub fn hash(bytes: &[u8]) -> Sha256Digest {
48 let mut hasher = sha2::Sha256::new();
49 hasher.update(bytes);
50 Sha256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
51 }
52
53 pub fn merge(values: &[Sha256Digest; 2]) -> Sha256Digest {
54 Self::hash(Sha256Digest::digests_as_bytes(values))
55 }
56
57 pub fn merge_many(values: &[Sha256Digest]) -> Sha256Digest {
58 let data = Sha256Digest::digests_as_bytes(values);
59 let mut hasher = sha2::Sha256::new();
60 hasher.update(data);
61 Sha256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
62 }
63
64 #[inline(always)]
66 pub fn hash_elements<E: BasedVectorSpace<Felt>>(elements: &[E]) -> Sha256Digest {
67 Sha256Digest::from(hash_elements_256(elements))
68 }
69
70 #[inline(always)]
72 pub fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Sha256Digest {
73 <Self as HasherExt>::hash_iter(slices)
74 }
75}
76
77pub type Sha512Digest = Digest512;
84
85#[derive(Debug, Copy, Clone, Eq, PartialEq)]
90pub struct Sha512;
91
92impl HasherExt for Sha512 {
93 type Digest = Sha512Digest;
94
95 fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
96 let mut hasher = sha2::Sha512::new();
97 for slice in slices {
98 hasher.update(slice);
99 }
100 Sha512Digest::from(<[u8; DIGEST512_BYTES]>::from(hasher.finalize()))
101 }
102}
103
104impl Sha512 {
105 #[inline(always)]
107 pub fn hash(bytes: &[u8]) -> Sha512Digest {
108 let mut hasher = sha2::Sha512::new();
109 hasher.update(bytes);
110 Sha512Digest::from(<[u8; DIGEST512_BYTES]>::from(hasher.finalize()))
111 }
112
113 #[inline(always)]
116 pub fn merge(values: &[Sha512Digest; 2]) -> Sha512Digest {
117 Self::hash(Sha512Digest::digests_as_bytes(values))
118 }
119
120 #[inline(always)]
122 pub fn merge_many(values: &[Sha512Digest]) -> Sha512Digest {
123 let data = Sha512Digest::digests_as_bytes(values);
124 let mut hasher = sha2::Sha512::new();
125 hasher.update(data);
126 Sha512Digest::from(<[u8; DIGEST512_BYTES]>::from(hasher.finalize()))
127 }
128
129 #[inline(always)]
131 pub fn hash_elements<E>(elements: &[E]) -> Sha512Digest
132 where
133 E: BasedVectorSpace<Felt>,
134 {
135 Sha512Digest::from(hash_elements_512(elements))
136 }
137
138 #[inline(always)]
140 pub fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Sha512Digest {
141 <Self as HasherExt>::hash_iter(slices)
142 }
143}
144
145fn hash_elements_256<E>(elements: &[E]) -> [u8; DIGEST256_BYTES]
150where
151 E: BasedVectorSpace<Felt>,
152{
153 let digest = {
154 const FELT_BYTES: usize = size_of::<u64>();
155 const { assert!(FELT_BYTES == 8, "buffer arithmetic assumes 8-byte field elements") };
156
157 let mut hasher = sha2::Sha256::new();
158
159 for elem in elements.iter() {
160 for &felt in E::as_basis_coefficients_slice(elem) {
161 let felt_bytes = felt.as_canonical_u64().to_le_bytes();
162 hasher.update(felt_bytes);
163 }
164 }
165
166 hasher.finalize()
167 };
168 digest.into()
169}
170
171fn hash_elements_512<E>(elements: &[E]) -> [u8; DIGEST512_BYTES]
173where
174 E: BasedVectorSpace<Felt>,
175{
176 let digest = {
177 const FELT_BYTES: usize = size_of::<u64>();
178 const { assert!(FELT_BYTES == 8, "buffer arithmetic assumes 8-byte field elements") };
179
180 let mut hasher = sha2::Sha512::new();
181
182 for elem in elements.iter() {
183 for &felt in E::as_basis_coefficients_slice(elem) {
184 let felt_bytes = felt.as_canonical_u64().to_le_bytes();
185 hasher.update(felt_bytes);
186 }
187 }
188
189 hasher.finalize()
190 };
191 digest.into()
192}