openvm_circuit/arch/hasher/
mod.rs

1pub mod poseidon2;
2
3use openvm_stark_backend::p3_field::Field;
4
5pub trait Hasher<const CHUNK: usize, F: Field> {
6    /// Statelessly compresses two chunks of data into a single chunk.
7    fn compress(&self, left: &[F; CHUNK], right: &[F; CHUNK]) -> [F; CHUNK];
8    fn hash(&self, values: &[F; CHUNK]) -> [F; CHUNK] {
9        self.compress(values, &[F::ZERO; CHUNK])
10    }
11    /// Chunk a list of fields. Use chunks as leaves to computes the root of the Merkle tree.
12    /// Assumption: the number of public values is a power of two * CHUNK.
13    fn merkle_root(&self, values: &[F]) -> [F; CHUNK] {
14        let mut leaves: Vec<_> = chunk_public_values(values)
15            .into_iter()
16            .map(|c| self.hash(&c))
17            .collect();
18        while leaves.len() > 1 {
19            leaves = leaves
20                .chunks_exact(2)
21                .map(|c| self.compress(&c[0], &c[1]))
22                .collect();
23        }
24        leaves[0]
25    }
26}
27pub trait HasherChip<const CHUNK: usize, F: Field>: Hasher<CHUNK, F> {
28    /// Stateful version of `hash` for recording the event in the chip.
29    fn compress_and_record(&mut self, left: &[F; CHUNK], right: &[F; CHUNK]) -> [F; CHUNK];
30    fn hash_and_record(&mut self, values: &[F; CHUNK]) -> [F; CHUNK] {
31        self.compress_and_record(values, &[F::ZERO; CHUNK])
32    }
33}
34
35fn chunk_public_values<const CHUNK: usize, F: Field>(public_values: &[F]) -> Vec<[F; CHUNK]> {
36    public_values
37        .chunks_exact(CHUNK)
38        .map(|c| c.try_into().unwrap())
39        .collect()
40}