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