ivc/poseidon_55_0_7_3_2/
mod.rs1pub mod columns;
4pub mod interpreter;
5
6#[cfg(test)]
7mod tests {
8 use crate::{
9 poseidon_55_0_7_3_2::{columns::PoseidonColumn, interpreter, interpreter::PoseidonParams},
10 poseidon_params_55_0_7_3,
11 poseidon_params_55_0_7_3::PlonkSpongeConstantsIVC,
12 };
13 use ark_ff::{UniformRand, Zero};
14 use kimchi_msm::{
15 circuit_design::{ColAccessCap, ConstraintBuilderEnv, WitnessBuilderEnv},
16 columns::ColumnIndexer,
17 lookups::DummyLookupTable,
18 Fp,
19 };
20 use mina_poseidon::permutation::poseidon_block_cipher;
21
22 pub struct PoseidonBN254Parameters;
23
24 pub const STATE_SIZE: usize = 3;
25 pub const NB_FULL_ROUND: usize = 55;
26 type TestPoseidonColumn = PoseidonColumn<STATE_SIZE, NB_FULL_ROUND>;
27 pub const N_COL: usize = TestPoseidonColumn::N_COL;
28 pub const N_DSEL: usize = 0;
29 pub const N_FSEL: usize = 165;
30
31 impl PoseidonParams<Fp, STATE_SIZE, NB_FULL_ROUND> for PoseidonBN254Parameters {
32 fn constants(&self) -> [[Fp; STATE_SIZE]; NB_FULL_ROUND] {
33 let rc = &poseidon_params_55_0_7_3::static_params().round_constants;
34 core::array::from_fn(|i| core::array::from_fn(|j| Fp::from(rc[i][j])))
35 }
36
37 fn mds(&self) -> [[Fp; STATE_SIZE]; STATE_SIZE] {
38 let mds = &poseidon_params_55_0_7_3::static_params().mds;
39 core::array::from_fn(|i| core::array::from_fn(|j| Fp::from(mds[i][j])))
40 }
41 }
42
43 type PoseidonWitnessBuilderEnv = WitnessBuilderEnv<
44 Fp,
45 TestPoseidonColumn,
46 { <TestPoseidonColumn as ColumnIndexer<usize>>::N_COL },
47 { <TestPoseidonColumn as ColumnIndexer<usize>>::N_COL },
48 N_DSEL,
49 N_FSEL,
50 DummyLookupTable,
51 >;
52
53 #[test]
54 pub fn test_poseidon_circuit() {
59 let mut rng = o1_utils::tests::make_test_rng(None);
60 let domain_size = 1 << 4;
61
62 let mut witness_env: PoseidonWitnessBuilderEnv = WitnessBuilderEnv::create();
63
64 {
66 let rc = PoseidonBN254Parameters.constants();
67 rc.iter().enumerate().for_each(|(round, rcs)| {
68 rcs.iter().enumerate().for_each(|(state_index, rc)| {
69 let rc = vec![*rc; domain_size];
70 witness_env.set_fixed_selector_cix(
71 PoseidonColumn::RoundConstant(round, state_index),
72 rc,
73 )
74 });
75 });
76 }
77
78 for _row in 0..domain_size {
80 let x: Fp = Fp::rand(&mut rng);
81 let y: Fp = Fp::rand(&mut rng);
82 let z: Fp = Fp::rand(&mut rng);
83
84 interpreter::poseidon_circuit(&mut witness_env, &PoseidonBN254Parameters, [x, y, z]);
85
86 {
90 let exp_output: Vec<Fp> = {
91 let mut state: Vec<Fp> = vec![x, y, z];
92 poseidon_block_cipher::<Fp, PlonkSpongeConstantsIVC>(
93 poseidon_params_55_0_7_3::static_params(),
94 &mut state,
95 );
96 state
97 };
98 let x_col: PoseidonColumn<STATE_SIZE, NB_FULL_ROUND> =
99 PoseidonColumn::Round(NB_FULL_ROUND - 1, 4);
100 let y_col: PoseidonColumn<STATE_SIZE, NB_FULL_ROUND> =
101 PoseidonColumn::Round(NB_FULL_ROUND - 1, 9);
102 let z_col: PoseidonColumn<STATE_SIZE, NB_FULL_ROUND> =
103 PoseidonColumn::Round(NB_FULL_ROUND - 1, 14);
104 assert_eq!(witness_env.read_column(x_col), exp_output[0]);
105 assert_eq!(witness_env.read_column(y_col), exp_output[1]);
106 assert_eq!(witness_env.read_column(z_col), exp_output[2]);
107 }
108
109 witness_env.next_row();
110 }
111 }
112
113 #[test]
114 pub fn heavy_test_completeness() {
116 let mut rng = o1_utils::tests::make_test_rng(None);
117 let domain_size: usize = 1 << 15;
118
119 let (relation_witness, fixed_selectors) = {
120 let mut witness_env: PoseidonWitnessBuilderEnv = WitnessBuilderEnv::create();
121
122 let mut fixed_selectors: [Vec<Fp>; N_FSEL] =
123 core::array::from_fn(|_| vec![Fp::zero(); 1]);
124 {
126 let rc = PoseidonBN254Parameters.constants();
127 rc.iter().enumerate().for_each(|(round, rcs)| {
128 rcs.iter().enumerate().for_each(|(state_index, rc)| {
129 witness_env.set_fixed_selector_cix(
130 PoseidonColumn::RoundConstant(round, state_index),
131 vec![*rc; domain_size],
132 );
133 fixed_selectors[round * STATE_SIZE + state_index] = vec![*rc; domain_size];
134 });
135 });
136 }
137
138 for _row in 0..domain_size {
140 let x: Fp = Fp::rand(&mut rng);
141 let y: Fp = Fp::rand(&mut rng);
142 let z: Fp = Fp::rand(&mut rng);
143
144 interpreter::poseidon_circuit(
145 &mut witness_env,
146 &PoseidonBN254Parameters,
147 [x, y, z],
148 );
149
150 witness_env.next_row();
151 }
152
153 (
154 witness_env.get_relation_witness(domain_size),
155 fixed_selectors,
156 )
157 };
158
159 let constraints = {
160 let mut constraint_env = ConstraintBuilderEnv::<Fp, DummyLookupTable>::create();
161 interpreter::apply_permutation(&mut constraint_env, &PoseidonBN254Parameters);
162 let constraints = constraint_env.get_constraints();
163
164 assert_eq!(constraints.len(), 5 * STATE_SIZE * NB_FULL_ROUND);
166 assert_eq!(constraints.iter().map(|c| c.degree(1, 0)).max().unwrap(), 2);
168
169 constraints
170 };
171
172 kimchi_msm::test::test_completeness_generic_no_lookups::<N_COL, N_COL, N_DSEL, N_FSEL, _>(
173 constraints,
174 Box::new(fixed_selectors),
175 relation_witness,
176 domain_size,
177 &mut rng,
178 );
179 }
180}