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 public_inputs: Vec<F>,
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 let pub_input_len = ark_std::cmp::min(4, num_constraints);
90 let public_inputs = witnesses[0].0[0..pub_input_len].to_vec();
91
92 let params = HyperPlonkParams {
93 num_constraints,
94 num_pub_input: public_inputs.len(),
95 gate_func: gate.clone(),
96 };
97
98 let permutation = identity_permutation(merged_nv as usize, 1);
99 let index = HyperPlonkIndex {
100 params,
101 permutation,
102 selectors,
103 };
104
105 Self {
106 public_inputs,
107 witnesses,
108 index,
109 }
110 }
111
112 pub fn is_satisfied(&self) -> bool {
113 for current_row in 0..self.num_variables() {
114 let mut cur = F::zero();
115 for (coeff, q, wit) in self.index.params.gate_func.gates.iter() {
116 let mut cur_monomial = if *coeff < 0 {
117 -F::from((-coeff) as u64)
118 } else {
119 F::from(*coeff as u64)
120 };
121 cur_monomial = match q {
122 Some(p) => cur_monomial * self.index.selectors[*p].0[current_row],
123 None => cur_monomial,
124 };
125 for wit_index in wit.iter() {
126 cur_monomial *= self.witnesses[*wit_index].0[current_row];
127 }
128 cur += cur_monomial;
129 }
130 if !cur.is_zero() {
131 return false;
132 }
133 }
134
135 true
136 }
137}
138
139#[cfg(test)]
140mod test {
141 use super::*;
142 use crate::{errors::HyperPlonkErrors, HyperPlonkSNARK};
143 use ark_bls12_381::{Bls12_381, Fr};
144 use subroutines::{
145 pcs::{
146 prelude::{MultilinearKzgPCS, MultilinearUniversalParams},
147 PolynomialCommitmentScheme,
148 },
149 poly_iop::PolyIOP,
150 };
151
152 const SUPPORTED_SIZE: usize = 20;
153 const MIN_NUM_VARS: usize = 8;
154 const MAX_NUM_VARS: usize = 15;
155 const CUSTOM_DEGREE: [usize; 6] = [1, 2, 4, 8, 16, 32];
156
157 #[test]
158 fn test_mock_circuit_sat() {
159 for i in 1..10 {
160 let vanilla_gate = CustomizedGates::vanilla_plonk_gate();
161 let circuit = MockCircuit::<Fr>::new(1 << i, &vanilla_gate);
162 assert!(circuit.is_satisfied());
163
164 let jf_gate = CustomizedGates::jellyfish_turbo_plonk_gate();
165 let circuit = MockCircuit::<Fr>::new(1 << i, &jf_gate);
166 assert!(circuit.is_satisfied());
167
168 for num_witness in 2..10 {
169 for degree in CUSTOM_DEGREE {
170 let mock_gate = CustomizedGates::mock_gate(num_witness, degree);
171 let circuit = MockCircuit::<Fr>::new(1 << i, &mock_gate);
172 assert!(circuit.is_satisfied());
173 }
174 }
175 }
176 }
177
178 fn test_mock_circuit_zkp_helper(
179 nv: usize,
180 gate: &CustomizedGates,
181 pcs_srs: &MultilinearUniversalParams<Bls12_381>,
182 ) -> Result<(), HyperPlonkErrors> {
183 let circuit = MockCircuit::<Fr>::new(1 << nv, gate);
184 assert!(circuit.is_satisfied());
185
186 let index = circuit.index;
187 // generate pk and vks
188 let (pk, vk) =
189 <PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::preprocess(
190 &index, &pcs_srs,
191 )?;
192 // generate a proof and verify
193 let proof =
194 <PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::prove(
195 &pk,
196 &circuit.public_inputs,
197 &circuit.witnesses,
198 )?;
199
200 let verify =
201 <PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::verify(
202 &vk,
203 &circuit.public_inputs,
204 &proof,
205 )?;
206 assert!(verify);
207 Ok(())
208 }
209
210 #[test]
211 fn test_mock_circuit_zkp() -> Result<(), HyperPlonkErrors> {
212 let mut rng = test_rng();
213 let pcs_srs =
214 MultilinearKzgPCS::<Bls12_381>::gen_srs_for_testing(&mut rng, SUPPORTED_SIZE)?;
215 for nv in MIN_NUM_VARS..MAX_NUM_VARS {
216 let vanilla_gate = CustomizedGates::vanilla_plonk_gate();
217 test_mock_circuit_zkp_helper(nv, &vanilla_gate, &pcs_srs)?;
218 }
219 for nv in MIN_NUM_VARS..MAX_NUM_VARS {
220 let tubro_gate = CustomizedGates::jellyfish_turbo_plonk_gate();
221 test_mock_circuit_zkp_helper(nv, &tubro_gate, &pcs_srs)?;
222 }
223 let nv = 5;
224 for num_witness in 2..10 {
225 for degree in CUSTOM_DEGREE {
226 let mock_gate = CustomizedGates::mock_gate(num_witness, degree);
227 test_mock_circuit_zkp_helper(nv, &mock_gate, &pcs_srs)?;
228 }
229 }
230
231 Ok(())
232 }
233
234 #[test]
235 fn test_mock_circuit_e2e() -> Result<(), HyperPlonkErrors> {
236 let mut rng = test_rng();
237 let pcs_srs =
238 MultilinearKzgPCS::<Bls12_381>::gen_srs_for_testing(&mut rng, SUPPORTED_SIZE)?;
239 let nv = MAX_NUM_VARS;
240
241 let turboplonk_gate = CustomizedGates::jellyfish_turbo_plonk_gate();
242 test_mock_circuit_zkp_helper(nv, &turboplonk_gate, &pcs_srs)?;
243
244 Ok(())
245 }
246
247 #[test]
248 fn test_mock_long_selector_e2e() -> Result<(), HyperPlonkErrors> {
249 let mut rng = test_rng();
250 let pcs_srs =
251 MultilinearKzgPCS::<Bls12_381>::gen_srs_for_testing(&mut rng, SUPPORTED_SIZE)?;
252 let nv = MAX_NUM_VARS;
253
254 let long_selector_gate = CustomizedGates::super_long_selector_gate();
255 test_mock_circuit_zkp_helper(nv, &long_selector_gate, &pcs_srs)?;
256
257 Ok(())
258 }
259}