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