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 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}