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 pub fn merge_with_int(seed: Sha256Digest, value: u64) -> Sha256Digest {
65 let mut hasher = sha2::Sha256::new();
66 hasher.update(&*seed);
67 hasher.update(value.to_le_bytes());
68 Sha256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
69 }
70
71 #[inline(always)]
73 pub fn hash_elements<E: BasedVectorSpace<Felt>>(elements: &[E]) -> Sha256Digest {
74 Sha256Digest::from(hash_elements_256(elements))
75 }
76
77 #[inline(always)]
79 pub fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Sha256Digest {
80 <Self as HasherExt>::hash_iter(slices)
81 }
82}
83
84pub type Sha512Digest = Digest512;
91
92#[derive(Debug, Copy, Clone, Eq, PartialEq)]
97pub struct Sha512;
98
99impl HasherExt for Sha512 {
100 type Digest = Sha512Digest;
101
102 fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
103 let mut hasher = sha2::Sha512::new();
104 for slice in slices {
105 hasher.update(slice);
106 }
107 Sha512Digest::from(<[u8; DIGEST512_BYTES]>::from(hasher.finalize()))
108 }
109}
110
111impl Sha512 {
112 #[inline(always)]
114 pub fn hash(bytes: &[u8]) -> Sha512Digest {
115 let mut hasher = sha2::Sha512::new();
116 hasher.update(bytes);
117 Sha512Digest::from(<[u8; DIGEST512_BYTES]>::from(hasher.finalize()))
118 }
119
120 #[inline(always)]
123 pub fn merge(values: &[Sha512Digest; 2]) -> Sha512Digest {
124 Self::hash(Sha512Digest::digests_as_bytes(values))
125 }
126
127 #[inline(always)]
129 pub fn merge_many(values: &[Sha512Digest]) -> Sha512Digest {
130 let data = Sha512Digest::digests_as_bytes(values);
131 let mut hasher = sha2::Sha512::new();
132 hasher.update(data);
133 Sha512Digest::from(<[u8; DIGEST512_BYTES]>::from(hasher.finalize()))
134 }
135
136 #[inline(always)]
138 pub fn hash_elements<E>(elements: &[E]) -> Sha512Digest
139 where
140 E: BasedVectorSpace<Felt>,
141 {
142 Sha512Digest::from(hash_elements_512(elements))
143 }
144
145 #[inline(always)]
147 pub fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Sha512Digest {
148 <Self as HasherExt>::hash_iter(slices)
149 }
150}
151
152fn hash_elements_256<E>(elements: &[E]) -> [u8; DIGEST256_BYTES]
157where
158 E: BasedVectorSpace<Felt>,
159{
160 let digest = {
161 const FELT_BYTES: usize = size_of::<u64>();
162 const { assert!(FELT_BYTES == 8, "buffer arithmetic assumes 8-byte field elements") };
163
164 let mut hasher = sha2::Sha256::new();
165
166 for elem in elements.iter() {
167 for &felt in E::as_basis_coefficients_slice(elem) {
168 let felt_bytes = felt.as_canonical_u64().to_le_bytes();
169 hasher.update(felt_bytes);
170 }
171 }
172
173 hasher.finalize()
174 };
175 digest.into()
176}
177
178fn hash_elements_512<E>(elements: &[E]) -> [u8; DIGEST512_BYTES]
180where
181 E: BasedVectorSpace<Felt>,
182{
183 let digest = {
184 const FELT_BYTES: usize = size_of::<u64>();
185 const { assert!(FELT_BYTES == 8, "buffer arithmetic assumes 8-byte field elements") };
186
187 let mut hasher = sha2::Sha512::new();
188
189 for elem in elements.iter() {
190 for &felt in E::as_basis_coefficients_slice(elem) {
191 let felt_bytes = felt.as_canonical_u64().to_le_bytes();
192 hasher.update(felt_bytes);
193 }
194 }
195
196 hasher.finalize()
197 };
198 digest.into()
199}