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