miden_crypto/hash/keccak/
mod.rs

1use 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
19// CONSTANTS
20// ================================================================================================
21
22const DIGEST_BYTES: usize = 32;
23
24// DIGEST
25// ================================================================================================
26
27/// Keccak digest
28#[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// KECCAK256 HASHER
98// ================================================================================================
99
100/// Keccak256 hash function
101#[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    /// Keccak256 collision resistance is 128-bits for 32-bytes output.
116    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    /// Returns a hash of the provided sequence of bytes.
161    #[inline(always)]
162    pub fn hash(bytes: &[u8]) -> Keccak256Digest {
163        <Self as Hasher>::hash(bytes)
164    }
165
166    /// Returns a hash of two digests. This method is intended for use in construction of
167    /// Merkle trees and verification of Merkle paths.
168    #[inline(always)]
169    pub fn merge(values: &[Keccak256Digest; 2]) -> Keccak256Digest {
170        <Self as Hasher>::merge(values)
171    }
172
173    /// Returns a hash of the provided field elements.
174    #[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    /// Hashes an iterator of byte slices.
183    #[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
189// HELPER FUNCTIONS
190// ================================================================================================
191
192/// Hash the elements into bytes and shrink the output.
193fn hash_elements<E>(elements: &[E]) -> [u8; DIGEST_BYTES]
194where
195    E: FieldElement<BaseField = Felt>,
196{
197    // don't leak assumptions from felt and check its actual implementation.
198    // this is a compile-time branch so it is for free
199    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        // The Keccak-p permutation has a state of size 1600 bits. For Keccak256, the capacity
206        // is set to 512 bits and the rate is thus of size 1088 bits.
207        // This means that we can absorb 136 bytes into the rate portion of the state per invocation
208        // of the permutation function.
209        // we move the elements into the hasher via the buffer to give the CPU a chance to process
210        // multiple element-to-byte conversions in parallel
211        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
229// Cast the slice into contiguous bytes.
230fn prepare_merge<const N: usize, D>(args: &[D; N]) -> &[u8]
231where
232    D: Deref<Target = [u8]>,
233{
234    // compile-time assertion
235    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    // safety: the values are tested to be contiguous
239    let bytes = unsafe { from_raw_parts(values, len) };
240    debug_assert_eq!(args[0].deref(), &bytes[..len / N]);
241    bytes
242}