openvm_circuit/system/poseidon2/
mod.rs

1//! Chip to handle **native kernel** instructions for Poseidon2 `compress` and `permute`.
2//! This chip is put in `intrinsics` for organizational convenience, but
3//! it is used as a system chip for persistent memory and as a native kernel chip for aggregation.
4//!
5//! Note that neither `compress` nor `permute` on its own
6//! is a cryptographic hash. `permute` is a cryptographic permutation, which can be made
7//! into a hash by applying a sponge construction. `compress` can be used as a hash in the
8//! internal leaves of a Merkle tree but **not** as the leaf hash because `compress` does not
9//! add any padding.
10
11use std::sync::Arc;
12
13use openvm_circuit_primitives::Chip;
14use openvm_poseidon2_air::{Poseidon2Config, Poseidon2SubAir};
15use openvm_stark_backend::{
16    config::{StarkGenericConfig, Val},
17    interaction::{BusIndex, LookupBus},
18    AirRef, ChipUsageGetter,
19};
20
21#[cfg(test)]
22pub mod tests;
23
24pub mod air;
25mod chip;
26pub use chip::*;
27
28use crate::{
29    arch::{
30        hasher::{Hasher, HasherChip},
31        VmField,
32    },
33    system::poseidon2::air::Poseidon2PeripheryAir,
34};
35pub mod columns;
36pub mod trace;
37
38pub const PERIPHERY_POSEIDON2_WIDTH: usize = 16;
39pub const PERIPHERY_POSEIDON2_CHUNK_SIZE: usize = 8;
40
41#[derive(Chip)]
42#[chip(where = "F: VmField")]
43pub enum Poseidon2PeripheryChip<F: VmField> {
44    Register0(Poseidon2PeripheryBaseChip<F, 0>),
45    Register1(Poseidon2PeripheryBaseChip<F, 1>),
46}
47impl<F: VmField> Poseidon2PeripheryChip<F> {
48    pub fn new(
49        poseidon2_config: Poseidon2Config<F>,
50        bus_idx: BusIndex,
51        max_constraint_degree: usize,
52    ) -> Self {
53        if max_constraint_degree >= 7 {
54            Self::Register0(Poseidon2PeripheryBaseChip::new(poseidon2_config, bus_idx))
55        } else {
56            Self::Register1(Poseidon2PeripheryBaseChip::new(poseidon2_config, bus_idx))
57        }
58    }
59}
60
61pub fn new_poseidon2_periphery_air<SC>(
62    poseidon2_config: Poseidon2Config<Val<SC>>,
63    direct_bus: LookupBus,
64    max_constraint_degree: usize,
65) -> AirRef<SC>
66where
67    SC: StarkGenericConfig,
68    Val<SC>: VmField,
69{
70    if max_constraint_degree >= 7 {
71        Arc::new(Poseidon2PeripheryAir::<Val<SC>, 0>::new(
72            Arc::new(Poseidon2SubAir::new(poseidon2_config.constants.into())),
73            direct_bus,
74        ))
75    } else {
76        Arc::new(Poseidon2PeripheryAir::<Val<SC>, 1>::new(
77            Arc::new(Poseidon2SubAir::new(poseidon2_config.constants.into())),
78            direct_bus,
79        ))
80    }
81}
82
83impl<F: VmField> ChipUsageGetter for Poseidon2PeripheryChip<F> {
84    fn air_name(&self) -> String {
85        match self {
86            Poseidon2PeripheryChip::Register0(chip) => chip.air_name(),
87            Poseidon2PeripheryChip::Register1(chip) => chip.air_name(),
88        }
89    }
90
91    fn current_trace_height(&self) -> usize {
92        match self {
93            Poseidon2PeripheryChip::Register0(chip) => chip.current_trace_height(),
94            Poseidon2PeripheryChip::Register1(chip) => chip.current_trace_height(),
95        }
96    }
97
98    fn trace_width(&self) -> usize {
99        match self {
100            Poseidon2PeripheryChip::Register0(chip) => chip.trace_width(),
101            Poseidon2PeripheryChip::Register1(chip) => chip.trace_width(),
102        }
103    }
104}
105
106impl<F: VmField> Hasher<PERIPHERY_POSEIDON2_CHUNK_SIZE, F> for Poseidon2PeripheryChip<F> {
107    fn compress(
108        &self,
109        lhs: &[F; PERIPHERY_POSEIDON2_CHUNK_SIZE],
110        rhs: &[F; PERIPHERY_POSEIDON2_CHUNK_SIZE],
111    ) -> [F; PERIPHERY_POSEIDON2_CHUNK_SIZE] {
112        match self {
113            Poseidon2PeripheryChip::Register0(chip) => chip.compress(lhs, rhs),
114            Poseidon2PeripheryChip::Register1(chip) => chip.compress(lhs, rhs),
115        }
116    }
117}
118
119impl<F: VmField> HasherChip<PERIPHERY_POSEIDON2_CHUNK_SIZE, F> for Poseidon2PeripheryChip<F> {
120    fn compress_and_record(
121        &self,
122        lhs: &[F; PERIPHERY_POSEIDON2_CHUNK_SIZE],
123        rhs: &[F; PERIPHERY_POSEIDON2_CHUNK_SIZE],
124    ) -> [F; PERIPHERY_POSEIDON2_CHUNK_SIZE] {
125        match self {
126            Poseidon2PeripheryChip::Register0(chip) => chip.compress_and_record(lhs, rhs),
127            Poseidon2PeripheryChip::Register1(chip) => chip.compress_and_record(lhs, rhs),
128        }
129    }
130}