hyperplonk/hyperplonk/src/mock.rs
hyperplonk/src/mock.rsRaw
1use arithmetic::identity_permutation_mle;
2use ark_ff::PrimeField;
3use ark_poly::MultilinearExtension;
4use ark_std::{log2, test_rng};
5
6use crate::{
7 custom_gate::CustomizedGates,
8 selectors::SelectorColumn,
9 structs::{HyperPlonkIndex, HyperPlonkParams},
10 witness::WitnessColumn,
11};
12
13pub struct MockCircuit<F: PrimeField> {
14 pub witnesses: Vec<WitnessColumn<F>>,
15 pub index: HyperPlonkIndex<F>,
16}
17
18impl<F: PrimeField> MockCircuit<F> {
19 /// Number of variables in a multilinear system
20 pub fn num_variables(&self) -> usize {
21 self.index.num_variables()
22 }
23
24 /// number of selector columns
25 pub fn num_selector_columns(&self) -> usize {
26 self.index.num_selector_columns()
27 }
28
29 /// number of witness columns
30 pub fn num_witness_columns(&self) -> usize {
31 self.index.num_witness_columns()
32 }
33}
34
35impl<F: PrimeField> MockCircuit<F> {
36 /// Generate a mock plonk circuit for the input constraint size.
37 pub fn new(num_constraints: usize, gate: &CustomizedGates) -> MockCircuit<F> {
38 let mut rng = test_rng();
39 let nv = log2(num_constraints);
40 let num_selectors = gate.num_selector_columns();
41 let num_witnesses = gate.num_witness_columns();
42 let log_n_wires = log2(num_witnesses);
43 let merged_nv = nv + log_n_wires;
44
45 let mut selectors: Vec<SelectorColumn<F>> = vec![SelectorColumn::default(); num_selectors];
46 let mut witnesses: Vec<WitnessColumn<F>> = vec![WitnessColumn::default(); num_witnesses];
47
48 for _cs_counter in 0..num_constraints {
49 let mut cur_selectors: Vec<F> = (0..(num_selectors - 1))
50 .map(|_| F::rand(&mut rng))
51 .collect();
52 let cur_witness: Vec<F> = (0..num_witnesses).map(|_| F::rand(&mut rng)).collect();
53 let mut last_selector = F::zero();
54 for (index, (coeff, q, wit)) in gate.gates.iter().enumerate() {
55 if index != num_selectors - 1 {
56 let mut cur_monomial = if *coeff < 0 {
57 -F::from((-coeff) as u64)
58 } else {
59 F::from(*coeff as u64)
60 };
61 cur_monomial = match q {
62 Some(p) => cur_monomial * cur_selectors[*p],
63 None => cur_monomial,
64 };
65 for wit_index in wit.iter() {
66 cur_monomial *= cur_witness[*wit_index];
67 }
68 last_selector += cur_monomial;
69 } else {
70 let mut cur_monomial = if *coeff < 0 {
71 -F::from((-coeff) as u64)
72 } else {
73 F::from(*coeff as u64)
74 };
75 for wit_index in wit.iter() {
76 cur_monomial *= cur_witness[*wit_index];
77 }
78 last_selector /= -cur_monomial;
79 }
80 }
81 cur_selectors.push(last_selector);
82 for i in 0..num_selectors {
83 selectors[i].append(cur_selectors[i]);
84 }
85 for i in 0..num_witnesses {
86 witnesses[i].append(cur_witness[i]);
87 }
88 }
89
90 let params = HyperPlonkParams {
91 num_constraints,
92 num_pub_input: num_constraints,
93 gate_func: gate.clone(),
94 };
95
96 let permutation = identity_permutation_mle(merged_nv as usize).to_evaluations();
97 let index = HyperPlonkIndex {
98 params,
99 permutation,
100 selectors,
101 };
102
103 Self { witnesses, index }
104 }
105
106 pub fn is_satisfied(&self) -> bool {
107 for current_row in 0..self.num_variables() {
108 let mut cur = F::zero();
109 for (coeff, q, wit) in self.index.params.gate_func.gates.iter() {
110 let mut cur_monomial = if *coeff < 0 {
111 -F::from((-coeff) as u64)
112 } else {
113 F::from(*coeff as u64)
114 };
115 cur_monomial = match q {
116 Some(p) => cur_monomial * self.index.selectors[*p].0[current_row],
117 None => cur_monomial,
118 };
119 for wit_index in wit.iter() {
120 cur_monomial *= self.witnesses[*wit_index].0[current_row];
121 }
122 cur += cur_monomial;
123 }
124 if !cur.is_zero() {
125 return false;
126 }
127 }
128
129 true
130 }
131}
132
133#[cfg(test)]
134mod test {
135 use super::*;
136 use crate::{errors::HyperPlonkErrors, HyperPlonkSNARK};
137 use ark_bls12_381::{Bls12_381, Fr};
138 use subroutines::{
139 pcs::{
140 prelude::{MultilinearKzgPCS, MultilinearUniversalParams},
141 PolynomialCommitmentScheme,
142 },
143 poly_iop::PolyIOP,
144 };
145
146 const SUPPORTED_SIZE: usize = 20;
147 const MIN_NUM_VARS: usize = 8;
148 const MAX_NUM_VARS: usize = 15;
149 const CUSTOM_DEGREE: [usize; 6] = [1, 2, 4, 8, 16, 32];
150
151 #[test]
152 fn test_mock_circuit_sat() {
153 for i in 1..10 {
154 let vanilla_gate = CustomizedGates::vanilla_plonk_gate();
155 let circuit = MockCircuit::<Fr>::new(1 << i, &vanilla_gate);
156 assert!(circuit.is_satisfied());
157
158 let jf_gate = CustomizedGates::jellyfish_turbo_plonk_gate();
159 let circuit = MockCircuit::<Fr>::new(1 << i, &jf_gate);
160 assert!(circuit.is_satisfied());
161
162 for num_witness in 2..10 {
163 for degree in CUSTOM_DEGREE {
164 let mock_gate = CustomizedGates::mock_gate(num_witness, degree);
165 let circuit = MockCircuit::<Fr>::new(1 << i, &mock_gate);
166 assert!(circuit.is_satisfied());
167 }
168 }
169 }
170 }
171
172 fn test_mock_circuit_zkp_helper(
173 nv: usize,
174 gate: &CustomizedGates,
175 pcs_srs: &MultilinearUniversalParams<Bls12_381>,
176 ) -> Result<(), HyperPlonkErrors> {
177 let circuit = MockCircuit::<Fr>::new(1 << nv, gate);
178 assert!(circuit.is_satisfied());
179
180 let index = circuit.index;
181
182 // generate pk and vks
183 let (pk, vk) =
184 <PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::preprocess(
185 &index, &pcs_srs,
186 )?;
187 // generate a proof and verify
188 let proof =
189 <PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::prove(
190 &pk,
191 &circuit.witnesses[0].0,
192 &circuit.witnesses,
193 )?;
194
195 let verify =
196 <PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::verify(
197 &vk,
198 &circuit.witnesses[0].0,
199 &proof,
200 )?;
201 assert!(verify);
202 Ok(())
203 }
204
205 #[test]
206 fn test_mock_circuit_zkp() -> Result<(), HyperPlonkErrors> {
207 let mut rng = test_rng();
208 let pcs_srs =
209 MultilinearKzgPCS::<Bls12_381>::gen_srs_for_testing(&mut rng, SUPPORTED_SIZE)?;
210 for nv in MIN_NUM_VARS..MAX_NUM_VARS {
211 let vanilla_gate = CustomizedGates::vanilla_plonk_gate();
212 test_mock_circuit_zkp_helper(nv, &vanilla_gate, &pcs_srs)?;
213 }
214 for nv in MIN_NUM_VARS..MAX_NUM_VARS {
215 let tubro_gate = CustomizedGates::jellyfish_turbo_plonk_gate();
216 test_mock_circuit_zkp_helper(nv, &tubro_gate, &pcs_srs)?;
217 }
218 let nv = 5;
219 for num_witness in 2..10 {
220 for degree in CUSTOM_DEGREE {
221 let mock_gate = CustomizedGates::mock_gate(num_witness, degree);
222 test_mock_circuit_zkp_helper(nv, &mock_gate, &pcs_srs)?;
223 }
224 }
225
226 Ok(())
227 }
228
229 #[test]
230 fn test_mock_circuit_e2e() -> Result<(), HyperPlonkErrors> {
231 let mut rng = test_rng();
232 let pcs_srs =
233 MultilinearKzgPCS::<Bls12_381>::gen_srs_for_testing(&mut rng, SUPPORTED_SIZE)?;
234 let nv = MAX_NUM_VARS;
235
236 let vanilla_gate = CustomizedGates::vanilla_plonk_gate();
237 test_mock_circuit_zkp_helper(nv, &vanilla_gate, &pcs_srs)?;
238
239 Ok(())
240 }
241
242 #[test]
243 fn test_mock_long_selector_e2e() -> Result<(), HyperPlonkErrors> {
244 let mut rng = test_rng();
245 let pcs_srs =
246 MultilinearKzgPCS::<Bls12_381>::gen_srs_for_testing(&mut rng, SUPPORTED_SIZE)?;
247 let nv = MAX_NUM_VARS;
248
249 let long_selector_gate = CustomizedGates::super_long_selector_gate();
250 test_mock_circuit_zkp_helper(nv, &long_selector_gate, &pcs_srs)?;
251
252 Ok(())
253 }
254}