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