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 pcs::{
139 prelude::{MultilinearKzgPCS, MultilinearUniversalParams, UnivariateUniversalParams},
140 PolynomialCommitmentScheme,
141 };
142 use poly_iop::PolyIOP;
143
144 #[test]
145 fn test_mock_circuit_sat() {
146 for i in 1..10 {
147 let vanilla_gate = CustomizedGates::vanilla_plonk_gate();
148 let circuit = MockCircuit::<Fr>::new(1 << i, &vanilla_gate);
149 assert!(circuit.is_satisfied());
150
151 let jf_gate = CustomizedGates::jellyfish_turbo_plonk_gate();
152 let circuit = MockCircuit::<Fr>::new(1 << i, &jf_gate);
153 assert!(circuit.is_satisfied());
154
155 for num_witness in 2..10 {
156 for degree in 1..10 {
157 let mock_gate = CustomizedGates::mock_gate(num_witness, degree);
158 let circuit = MockCircuit::<Fr>::new(1 << i, &mock_gate);
159 assert!(circuit.is_satisfied());
160 }
161 }
162 }
163 }
164
165 fn test_mock_circuit_zkp_helper(
166 nv: usize,
167 gate: &CustomizedGates,
168 pcs_srs: &(
169 MultilinearUniversalParams<Bls12_381>,
170 UnivariateUniversalParams<Bls12_381>,
171 ),
172 ) -> Result<(), HyperPlonkErrors> {
173 let circuit = MockCircuit::<Fr>::new(1 << nv, gate);
174 assert!(circuit.is_satisfied());
175
176 let index = circuit.index;
177
178 // generate pk and vks
179 let (pk, vk) =
180 <PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::preprocess(
181 &index, &pcs_srs,
182 )?;
183 // generate a proof and verify
184 let proof =
185 <PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::prove(
186 &pk,
187 &circuit.witnesses[0].0,
188 &circuit.witnesses,
189 )?;
190
191 let verify =
192 <PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::verify(
193 &vk,
194 &circuit.witnesses[0].0,
195 &proof,
196 )?;
197 assert!(verify);
198 Ok(())
199 }
200
201 #[test]
202 fn test_mock_circuit_zkp() -> Result<(), HyperPlonkErrors> {
203 let mut rng = test_rng();
204 let pcs_srs = MultilinearKzgPCS::<Bls12_381>::gen_srs_for_testing(&mut rng, 16)?;
205 for nv in 1..10 {
206 let vanilla_gate = CustomizedGates::vanilla_plonk_gate();
207 test_mock_circuit_zkp_helper(nv, &vanilla_gate, &pcs_srs)?;
208 }
209 for nv in 1..10 {
210 let tubro_gate = CustomizedGates::jellyfish_turbo_plonk_gate();
211 test_mock_circuit_zkp_helper(nv, &tubro_gate, &pcs_srs)?;
212 }
213 let nv = 5;
214 for num_witness in 2..10 {
215 for degree in [1, 2, 4, 8, 16] {
216 let mock_gate = CustomizedGates::mock_gate(num_witness, degree);
217 test_mock_circuit_zkp_helper(nv, &mock_gate, &pcs_srs)?;
218 }
219 }
220
221 Ok(())
222 }
223
224 #[test]
225 fn test_mock_circuit_e2e() -> Result<(), HyperPlonkErrors> {
226 let mut rng = test_rng();
227 let pcs_srs = MultilinearKzgPCS::<Bls12_381>::gen_srs_for_testing(&mut rng, 23)?;
228 let nv = 18;
229
230 let vanilla_gate = CustomizedGates::vanilla_plonk_gate();
231 test_mock_circuit_zkp_helper(nv, &vanilla_gate, &pcs_srs)?;
232
233 Ok(())
234 }
235}