openvm_circuit/system/poseidon2/
chip.rs
1use std::{
2 array,
3 sync::{atomic::AtomicU32, Arc},
4};
5
6use openvm_poseidon2_air::{Poseidon2Config, Poseidon2SubChip};
7use openvm_stark_backend::{
8 interaction::{BusIndex, LookupBus},
9 p3_field::PrimeField32,
10};
11use rustc_hash::FxHashMap;
12
13use super::{
14 air::Poseidon2PeripheryAir, PERIPHERY_POSEIDON2_CHUNK_SIZE, PERIPHERY_POSEIDON2_WIDTH,
15};
16use crate::arch::hasher::{Hasher, HasherChip};
17
18#[derive(Debug)]
19pub struct Poseidon2PeripheryBaseChip<F: PrimeField32, const SBOX_REGISTERS: usize> {
20 pub air: Arc<Poseidon2PeripheryAir<F, SBOX_REGISTERS>>,
21 pub subchip: Poseidon2SubChip<F, SBOX_REGISTERS>,
22 pub records: FxHashMap<[F; PERIPHERY_POSEIDON2_WIDTH], AtomicU32>,
23}
24
25impl<F: PrimeField32, const SBOX_REGISTERS: usize> Poseidon2PeripheryBaseChip<F, SBOX_REGISTERS> {
26 pub fn new(poseidon2_config: Poseidon2Config<F>, bus_idx: BusIndex) -> Self {
27 let subchip = Poseidon2SubChip::new(poseidon2_config.constants);
28 Self {
29 air: Arc::new(Poseidon2PeripheryAir::new(
30 subchip.air.clone(),
31 LookupBus::new(bus_idx),
32 )),
33 subchip,
34 records: FxHashMap::default(),
35 }
36 }
37}
38
39impl<F: PrimeField32, const SBOX_REGISTERS: usize> Hasher<PERIPHERY_POSEIDON2_CHUNK_SIZE, F>
40 for Poseidon2PeripheryBaseChip<F, SBOX_REGISTERS>
41{
42 fn compress(
43 &self,
44 lhs: &[F; PERIPHERY_POSEIDON2_CHUNK_SIZE],
45 rhs: &[F; PERIPHERY_POSEIDON2_CHUNK_SIZE],
46 ) -> [F; PERIPHERY_POSEIDON2_CHUNK_SIZE] {
47 let mut input_state = [F::ZERO; PERIPHERY_POSEIDON2_WIDTH];
48 input_state[..PERIPHERY_POSEIDON2_CHUNK_SIZE].copy_from_slice(lhs);
49 input_state[PERIPHERY_POSEIDON2_CHUNK_SIZE..].copy_from_slice(rhs);
50
51 let output = self.subchip.permute(input_state);
52 array::from_fn(|i| output[i])
53 }
54}
55
56impl<F: PrimeField32, const SBOX_REGISTERS: usize> HasherChip<PERIPHERY_POSEIDON2_CHUNK_SIZE, F>
57 for Poseidon2PeripheryBaseChip<F, SBOX_REGISTERS>
58{
59 fn compress_and_record(
65 &mut self,
66 lhs: &[F; PERIPHERY_POSEIDON2_CHUNK_SIZE],
67 rhs: &[F; PERIPHERY_POSEIDON2_CHUNK_SIZE],
68 ) -> [F; PERIPHERY_POSEIDON2_CHUNK_SIZE] {
69 let mut input = [F::ZERO; PERIPHERY_POSEIDON2_WIDTH];
70 input[..PERIPHERY_POSEIDON2_CHUNK_SIZE].copy_from_slice(lhs);
71 input[PERIPHERY_POSEIDON2_CHUNK_SIZE..].copy_from_slice(rhs);
72
73 let count = self.records.entry(input).or_insert(AtomicU32::new(0));
74 count.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
75
76 let output = self.subchip.permute(input);
77 array::from_fn(|i| output[i])
78 }
79}