miden_crypto/hash/keccak/
mod.rs1use alloc::string::String;
2use core::{
3 mem::size_of,
4 ops::Deref,
5 slice::{self, from_raw_parts},
6};
7
8use sha3::Digest as Sha3Digest;
9
10use super::{Digest, ElementHasher, Felt, FieldElement, Hasher, HasherExt};
11use crate::utils::{
12 ByteReader, ByteWriter, Deserializable, DeserializationError, HexParseError, Serializable,
13 bytes_to_hex_string, hex_to_bytes,
14};
15
16#[cfg(test)]
17mod tests;
18
19const DIGEST_BYTES: usize = 32;
23
24#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
29pub struct Keccak256Digest([u8; DIGEST_BYTES]);
30
31impl Keccak256Digest {
32 pub fn digests_as_bytes(digests: &[Keccak256Digest]) -> &[u8] {
33 let p = digests.as_ptr();
34 let len = digests.len() * DIGEST_BYTES;
35 unsafe { slice::from_raw_parts(p as *const u8, len) }
36 }
37}
38
39impl Default for Keccak256Digest {
40 fn default() -> Self {
41 Self([0; DIGEST_BYTES])
42 }
43}
44
45impl Deref for Keccak256Digest {
46 type Target = [u8];
47
48 fn deref(&self) -> &Self::Target {
49 &self.0
50 }
51}
52
53impl From<Keccak256Digest> for [u8; DIGEST_BYTES] {
54 fn from(value: Keccak256Digest) -> Self {
55 value.0
56 }
57}
58
59impl From<[u8; DIGEST_BYTES]> for Keccak256Digest {
60 fn from(value: [u8; DIGEST_BYTES]) -> Self {
61 Self(value)
62 }
63}
64
65impl From<Keccak256Digest> for String {
66 fn from(value: Keccak256Digest) -> Self {
67 bytes_to_hex_string(value.as_bytes())
68 }
69}
70
71impl TryFrom<&str> for Keccak256Digest {
72 type Error = HexParseError;
73
74 fn try_from(value: &str) -> Result<Self, Self::Error> {
75 hex_to_bytes(value).map(|v| v.into())
76 }
77}
78
79impl Serializable for Keccak256Digest {
80 fn write_into<W: ByteWriter>(&self, target: &mut W) {
81 target.write_bytes(&self.0);
82 }
83}
84
85impl Deserializable for Keccak256Digest {
86 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
87 source.read_array().map(Self)
88 }
89}
90
91impl Digest for Keccak256Digest {
92 fn as_bytes(&self) -> [u8; 32] {
93 self.0
94 }
95}
96
97#[derive(Debug, Copy, Clone, Eq, PartialEq)]
102pub struct Keccak256;
103
104impl HasherExt for Keccak256 {
105 fn hash_iter<'a>(&self, slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
106 let mut hasher = sha3::Keccak256::new();
107 for slice in slices {
108 hasher.update(slice);
109 }
110 Keccak256Digest(hasher.finalize().into())
111 }
112}
113
114impl Hasher for Keccak256 {
115 const COLLISION_RESISTANCE: u32 = 128;
117
118 type Digest = Keccak256Digest;
119
120 fn hash(bytes: &[u8]) -> Self::Digest {
121 let mut hasher = sha3::Keccak256::new();
122 hasher.update(bytes);
123
124 Keccak256Digest(hasher.finalize().into())
125 }
126
127 fn merge(values: &[Self::Digest; 2]) -> Self::Digest {
128 Self::hash(prepare_merge(values))
129 }
130
131 fn merge_many(values: &[Self::Digest]) -> Self::Digest {
132 let data = Keccak256Digest::digests_as_bytes(values);
133 let mut hasher = sha3::Keccak256::new();
134 hasher.update(data);
135
136 Keccak256Digest(hasher.finalize().into())
137 }
138
139 fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
140 let mut hasher = sha3::Keccak256::new();
141 hasher.update(seed.0);
142 hasher.update(value.to_le_bytes());
143
144 Keccak256Digest(hasher.finalize().into())
145 }
146}
147
148impl ElementHasher for Keccak256 {
149 type BaseField = Felt;
150
151 fn hash_elements<E>(elements: &[E]) -> Self::Digest
152 where
153 E: FieldElement<BaseField = Self::BaseField>,
154 {
155 Keccak256Digest(hash_elements(elements))
156 }
157}
158
159impl Keccak256 {
160 #[inline(always)]
162 pub fn hash(bytes: &[u8]) -> Keccak256Digest {
163 <Self as Hasher>::hash(bytes)
164 }
165
166 #[inline(always)]
169 pub fn merge(values: &[Keccak256Digest; 2]) -> Keccak256Digest {
170 <Self as Hasher>::merge(values)
171 }
172
173 #[inline(always)]
175 pub fn hash_elements<E>(elements: &[E]) -> Keccak256Digest
176 where
177 E: FieldElement<BaseField = Felt>,
178 {
179 <Self as ElementHasher>::hash_elements(elements)
180 }
181
182 #[inline(always)]
184 pub fn hash_iter<'a>(&self, slices: impl Iterator<Item = &'a [u8]>) -> Keccak256Digest {
185 <Self as HasherExt>::hash_iter(self, slices)
186 }
187}
188
189fn hash_elements<E>(elements: &[E]) -> [u8; DIGEST_BYTES]
194where
195 E: FieldElement<BaseField = Felt>,
196{
197 let digest = if Felt::IS_CANONICAL {
200 let mut hasher = sha3::Keccak256::new();
201 hasher.update(E::elements_as_bytes(elements));
202 hasher.finalize()
203 } else {
204 let mut hasher = sha3::Keccak256::new();
205 let mut buf = [0_u8; 136];
212 let mut chunk_iter = E::slice_as_base_elements(elements).chunks_exact(17);
213 for chunk in chunk_iter.by_ref() {
214 for i in 0..17 {
215 buf[i * 8..(i + 1) * 8].copy_from_slice(&chunk[i].as_int().to_le_bytes());
216 }
217 hasher.update(buf);
218 }
219
220 for element in chunk_iter.remainder() {
221 hasher.update(element.as_int().to_le_bytes());
222 }
223
224 hasher.finalize()
225 };
226 digest.into()
227}
228
229fn prepare_merge<const N: usize, D>(args: &[D; N]) -> &[u8]
231where
232 D: Deref<Target = [u8]>,
233{
234 assert!(N > 0, "N shouldn't represent an empty slice!");
236 let values = args.as_ptr() as *const u8;
237 let len = size_of::<D>() * N;
238 let bytes = unsafe { from_raw_parts(values, len) };
240 debug_assert_eq!(args[0].deref(), &bytes[..len / N]);
241 bytes
242}