arnaucube
arnaucube/hyperplonkPublic Self-hosted repository
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}