miden_crypto/hash/keccak/
mod.rs1use core::mem::size_of;
2
3use sha3::Digest as Sha3Digest;
4
5use super::{
6 Felt, HasherExt,
7 digest::{DIGEST256_BYTES, Digest256},
8};
9use crate::field::{BasedVectorSpace, PrimeField64};
10
11#[cfg(test)]
12mod tests;
13
14pub use p3_keccak::{Keccak256Hash, KeccakF, VECTOR_LEN};
19
20pub type Keccak256Digest = Digest256;
27
28#[derive(Debug, Copy, Clone, Eq, PartialEq)]
33pub struct Keccak256;
34
35impl HasherExt for Keccak256 {
36 type Digest = Keccak256Digest;
37
38 fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
39 let mut hasher = sha3::Keccak256::new();
40 for slice in slices {
41 hasher.update(slice);
42 }
43 Keccak256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
44 }
45}
46
47impl Keccak256 {
48 pub const COLLISION_RESISTANCE: u32 = 128;
50
51 pub fn hash(bytes: &[u8]) -> Keccak256Digest {
52 let mut hasher = sha3::Keccak256::new();
53 hasher.update(bytes);
54 Keccak256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
55 }
56
57 pub fn merge(values: &[Keccak256Digest; 2]) -> Keccak256Digest {
58 Self::hash(Keccak256Digest::digests_as_bytes(values))
59 }
60
61 pub fn merge_many(values: &[Keccak256Digest]) -> Keccak256Digest {
62 let data = Keccak256Digest::digests_as_bytes(values);
63 let mut hasher = sha3::Keccak256::new();
64 hasher.update(data);
65 Keccak256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
66 }
67
68 pub fn merge_with_int(seed: Keccak256Digest, value: u64) -> Keccak256Digest {
69 let mut hasher = sha3::Keccak256::new();
70 hasher.update(&*seed);
71 hasher.update(value.to_le_bytes());
72 Keccak256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
73 }
74
75 #[inline(always)]
77 pub fn hash_elements<E>(elements: &[E]) -> Keccak256Digest
78 where
79 E: BasedVectorSpace<Felt>,
80 {
81 hash_elements(elements).into()
82 }
83
84 #[inline(always)]
86 pub fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Keccak256Digest {
87 <Self as HasherExt>::hash_iter(slices)
88 }
89}
90
91fn hash_elements<E>(elements: &[E]) -> [u8; DIGEST256_BYTES]
96where
97 E: BasedVectorSpace<Felt>,
98{
99 let digest = {
101 const FELT_BYTES: usize = size_of::<u64>();
102 const { assert!(FELT_BYTES == 8, "buffer arithmetic assumes 8-byte field elements") };
103
104 let mut hasher = sha3::Keccak256::new();
105 let mut buf = [0_u8; 136];
107 let mut buf_offset = 0;
108
109 for elem in elements.iter() {
110 for &felt in E::as_basis_coefficients_slice(elem) {
111 buf[buf_offset..buf_offset + FELT_BYTES]
112 .copy_from_slice(&felt.as_canonical_u64().to_le_bytes());
113 buf_offset += FELT_BYTES;
114
115 if buf_offset == 136 {
116 hasher.update(buf);
117 buf_offset = 0;
118 }
119 }
120 }
121
122 if buf_offset > 0 {
123 hasher.update(&buf[..buf_offset]);
124 }
125
126 hasher.finalize()
127 };
128 digest.into()
129}