arnaucube
arnaucube/hyperplonkPublic Self-hosted repository
hyperplonk/hyperplonk/src/mock.rs
hyperplonk/src/mock.rsRaw
  1use arithmetic::identity_permutation_mles;
  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_mles(merged_nv as usize, 1)[0].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}