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    p3_field::{Field, PrimeField32},
19    AirRef, ChipUsageGetter,
20};
21
22#[cfg(test)]
23pub mod tests;
24
25pub mod air;
26mod chip;
27pub use chip::*;
28
29use crate::{
30    arch::hasher::{Hasher, HasherChip},
31    system::poseidon2::air::Poseidon2PeripheryAir,
32};
33pub mod columns;
34pub mod trace;
35
36pub const PERIPHERY_POSEIDON2_WIDTH: usize = 16;
37pub const PERIPHERY_POSEIDON2_CHUNK_SIZE: usize = 8;
38
39#[derive(Chip)]
40#[chip(where = "F: Field")]
41pub enum Poseidon2PeripheryChip<F: Field> {
42    Register0(Poseidon2PeripheryBaseChip<F, 0>),
43    Register1(Poseidon2PeripheryBaseChip<F, 1>),
44}
45impl<F: PrimeField32> Poseidon2PeripheryChip<F> {
46    pub fn new(
47        poseidon2_config: Poseidon2Config<F>,
48        bus_idx: BusIndex,
49        max_constraint_degree: usize,
50    ) -> Self {
51        if max_constraint_degree >= 7 {
52            Self::Register0(Poseidon2PeripheryBaseChip::new(poseidon2_config, bus_idx))
53        } else {
54            Self::Register1(Poseidon2PeripheryBaseChip::new(poseidon2_config, bus_idx))
55        }
56    }
57}
58
59pub fn new_poseidon2_periphery_air<SC: StarkGenericConfig>(
60    poseidon2_config: Poseidon2Config<Val<SC>>,
61    direct_bus: LookupBus,
62    max_constraint_degree: usize,
63) -> AirRef<SC> {
64    if max_constraint_degree >= 7 {
65        Arc::new(Poseidon2PeripheryAir::<Val<SC>, 0>::new(
66            Arc::new(Poseidon2SubAir::new(poseidon2_config.constants.into())),
67            direct_bus,
68        ))
69    } else {
70        Arc::new(Poseidon2PeripheryAir::<Val<SC>, 1>::new(
71            Arc::new(Poseidon2SubAir::new(poseidon2_config.constants.into())),
72            direct_bus,
73        ))
74    }
75}
76
77impl<F: PrimeField32> ChipUsageGetter for Poseidon2PeripheryChip<F> {
78    fn air_name(&self) -> String {
79        match self {
80            Poseidon2PeripheryChip::Register0(chip) => chip.air_name(),
81            Poseidon2PeripheryChip::Register1(chip) => chip.air_name(),
82        }
83    }
84
85    fn current_trace_height(&self) -> usize {
86        match self {
87            Poseidon2PeripheryChip::Register0(chip) => chip.current_trace_height(),
88            Poseidon2PeripheryChip::Register1(chip) => chip.current_trace_height(),
89        }
90    }
91
92    fn trace_width(&self) -> usize {
93        match self {
94            Poseidon2PeripheryChip::Register0(chip) => chip.trace_width(),
95            Poseidon2PeripheryChip::Register1(chip) => chip.trace_width(),
96        }
97    }
98}
99
100impl<F: PrimeField32> Hasher<PERIPHERY_POSEIDON2_CHUNK_SIZE, F> for Poseidon2PeripheryChip<F> {
101    fn compress(
102        &self,
103        lhs: &[F; PERIPHERY_POSEIDON2_CHUNK_SIZE],
104        rhs: &[F; PERIPHERY_POSEIDON2_CHUNK_SIZE],
105    ) -> [F; PERIPHERY_POSEIDON2_CHUNK_SIZE] {
106        match self {
107            Poseidon2PeripheryChip::Register0(chip) => chip.compress(lhs, rhs),
108            Poseidon2PeripheryChip::Register1(chip) => chip.compress(lhs, rhs),
109        }
110    }
111}
112
113impl<F: PrimeField32> HasherChip<PERIPHERY_POSEIDON2_CHUNK_SIZE, F> for Poseidon2PeripheryChip<F> {
114    fn compress_and_record(
115        &self,
116        lhs: &[F; PERIPHERY_POSEIDON2_CHUNK_SIZE],
117        rhs: &[F; PERIPHERY_POSEIDON2_CHUNK_SIZE],
118    ) -> [F; PERIPHERY_POSEIDON2_CHUNK_SIZE] {
119        match self {
120            Poseidon2PeripheryChip::Register0(chip) => chip.compress_and_record(lhs, rhs),
121            Poseidon2PeripheryChip::Register1(chip) => chip.compress_and_record(lhs, rhs),
122        }
123    }
124}