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