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};
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 Hasher for Keccak256 {
105 const COLLISION_RESISTANCE: u32 = 128;
107
108 type Digest = Keccak256Digest;
109
110 fn hash(bytes: &[u8]) -> Self::Digest {
111 let mut hasher = sha3::Keccak256::new();
112 hasher.update(bytes);
113
114 Keccak256Digest(hasher.finalize().into())
115 }
116
117 fn merge(values: &[Self::Digest; 2]) -> Self::Digest {
118 Self::hash(prepare_merge(values))
119 }
120
121 fn merge_many(values: &[Self::Digest]) -> Self::Digest {
122 let data = Keccak256Digest::digests_as_bytes(values);
123 let mut hasher = sha3::Keccak256::new();
124 hasher.update(data);
125
126 Keccak256Digest(hasher.finalize().into())
127 }
128
129 fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
130 let mut hasher = sha3::Keccak256::new();
131 hasher.update(seed.0);
132 hasher.update(value.to_le_bytes());
133
134 Keccak256Digest(hasher.finalize().into())
135 }
136}
137
138impl ElementHasher for Keccak256 {
139 type BaseField = Felt;
140
141 fn hash_elements<E>(elements: &[E]) -> Self::Digest
142 where
143 E: FieldElement<BaseField = Self::BaseField>,
144 {
145 Keccak256Digest(hash_elements(elements))
146 }
147}
148
149impl Keccak256 {
150 #[inline(always)]
152 pub fn hash(bytes: &[u8]) -> Keccak256Digest {
153 <Self as Hasher>::hash(bytes)
154 }
155
156 #[inline(always)]
159 pub fn merge(values: &[Keccak256Digest; 2]) -> Keccak256Digest {
160 <Self as Hasher>::merge(values)
161 }
162
163 #[inline(always)]
165 pub fn hash_elements<E>(elements: &[E]) -> Keccak256Digest
166 where
167 E: FieldElement<BaseField = Felt>,
168 {
169 <Self as ElementHasher>::hash_elements(elements)
170 }
171}
172
173fn hash_elements<E>(elements: &[E]) -> [u8; DIGEST_BYTES]
178where
179 E: FieldElement<BaseField = Felt>,
180{
181 let digest = if Felt::IS_CANONICAL {
184 let mut hasher = sha3::Keccak256::new();
185 hasher.update(E::elements_as_bytes(elements));
186 hasher.finalize()
187 } else {
188 let mut hasher = sha3::Keccak256::new();
189 let mut buf = [0_u8; 136];
196 let mut chunk_iter = E::slice_as_base_elements(elements).chunks_exact(17);
197 for chunk in chunk_iter.by_ref() {
198 for i in 0..17 {
199 buf[i * 8..(i + 1) * 8].copy_from_slice(&chunk[i].as_int().to_le_bytes());
200 }
201 hasher.update(buf);
202 }
203
204 for element in chunk_iter.remainder() {
205 hasher.update(element.as_int().to_le_bytes());
206 }
207
208 hasher.finalize()
209 };
210 digest.into()
211}
212
213fn prepare_merge<const N: usize, D>(args: &[D; N]) -> &[u8]
215where
216 D: Deref<Target = [u8]>,
217{
218 assert!(N > 0, "N shouldn't represent an empty slice!");
220 let values = args.as_ptr() as *const u8;
221 let len = size_of::<D>() * N;
222 let bytes = unsafe { from_raw_parts(values, len) };
224 debug_assert_eq!(args[0].deref(), &bytes[..len / N]);
225 bytes
226}