arnaucube
arnaucube/hyperplonkPublic Self-hosted repository
hyperplonk/hyperplonk/src/mock.rs
hyperplonk/src/mock.rsRaw
  1// Copyright (c) 2023 Espresso Systems (espressosys.com)
  2// This file is part of the HyperPlonk library.
  3
  4// You should have received a copy of the MIT License
  5// along with the HyperPlonk library. If not, see <https://mit-license.org/>.
  6
  7use arithmetic::identity_permutation;
  8use ark_ff::PrimeField;
  9use ark_std::{log2, test_rng};
 10
 11use crate::{
 12    custom_gate::CustomizedGates,
 13    selectors::SelectorColumn,
 14    structs::{HyperPlonkIndex, HyperPlonkParams},
 15    witness::WitnessColumn,
 16};
 17
 18pub struct MockCircuit<F: PrimeField> {
 19    pub public_inputs: Vec<F>,
 20    pub witnesses: Vec<WitnessColumn<F>>,
 21    pub index: HyperPlonkIndex<F>,
 22}
 23
 24impl<F: PrimeField> MockCircuit<F> {
 25    /// Number of variables in a multilinear system
 26    pub fn num_variables(&self) -> usize {
 27        self.index.num_variables()
 28    }
 29
 30    /// number of selector columns
 31    pub fn num_selector_columns(&self) -> usize {
 32        self.index.num_selector_columns()
 33    }
 34
 35    /// number of witness columns
 36    pub fn num_witness_columns(&self) -> usize {
 37        self.index.num_witness_columns()
 38    }
 39}
 40
 41impl<F: PrimeField> MockCircuit<F> {
 42    /// Generate a mock plonk circuit for the input constraint size.
 43    pub fn new(num_constraints: usize, gate: &CustomizedGates) -> MockCircuit<F> {
 44        let mut rng = test_rng();
 45        let nv = log2(num_constraints);
 46        let num_selectors = gate.num_selector_columns();
 47        let num_witnesses = gate.num_witness_columns();
 48        let log_n_wires = log2(num_witnesses);
 49        let merged_nv = nv + log_n_wires;
 50
 51        let mut selectors: Vec<SelectorColumn<F>> = vec![SelectorColumn::default(); num_selectors];
 52        let mut witnesses: Vec<WitnessColumn<F>> = vec![WitnessColumn::default(); num_witnesses];
 53
 54        for _cs_counter in 0..num_constraints {
 55            let mut cur_selectors: Vec<F> = (0..(num_selectors - 1))
 56                .map(|_| F::rand(&mut rng))
 57                .collect();
 58            let cur_witness: Vec<F> = (0..num_witnesses).map(|_| F::rand(&mut rng)).collect();
 59            let mut last_selector = F::zero();
 60            for (index, (coeff, q, wit)) in gate.gates.iter().enumerate() {
 61                if index != num_selectors - 1 {
 62                    let mut cur_monomial = if *coeff < 0 {
 63                        -F::from((-coeff) as u64)
 64                    } else {
 65                        F::from(*coeff as u64)
 66                    };
 67                    cur_monomial = match q {
 68                        Some(p) => cur_monomial * cur_selectors[*p],
 69                        None => cur_monomial,
 70                    };
 71                    for wit_index in wit.iter() {
 72                        cur_monomial *= cur_witness[*wit_index];
 73                    }
 74                    last_selector += cur_monomial;
 75                } else {
 76                    let mut cur_monomial = if *coeff < 0 {
 77                        -F::from((-coeff) as u64)
 78                    } else {
 79                        F::from(*coeff as u64)
 80                    };
 81                    for wit_index in wit.iter() {
 82                        cur_monomial *= cur_witness[*wit_index];
 83                    }
 84                    last_selector /= -cur_monomial;
 85                }
 86            }
 87            cur_selectors.push(last_selector);
 88            for i in 0..num_selectors {
 89                selectors[i].append(cur_selectors[i]);
 90            }
 91            for i in 0..num_witnesses {
 92                witnesses[i].append(cur_witness[i]);
 93            }
 94        }
 95        let pub_input_len = ark_std::cmp::min(4, num_constraints);
 96        let public_inputs = witnesses[0].0[0..pub_input_len].to_vec();
 97
 98        let params = HyperPlonkParams {
 99            num_constraints,
100            num_pub_input: public_inputs.len(),
101            gate_func: gate.clone(),
102        };
103
104        let permutation = identity_permutation(merged_nv as usize, 1);
105        let index = HyperPlonkIndex {
106            params,
107            permutation,
108            selectors,
109        };
110
111        Self {
112            public_inputs,
113            witnesses,
114            index,
115        }
116    }
117
118    pub fn is_satisfied(&self) -> bool {
119        for current_row in 0..self.num_variables() {
120            let mut cur = F::zero();
121            for (coeff, q, wit) in self.index.params.gate_func.gates.iter() {
122                let mut cur_monomial = if *coeff < 0 {
123                    -F::from((-coeff) as u64)
124                } else {
125                    F::from(*coeff as u64)
126                };
127                cur_monomial = match q {
128                    Some(p) => cur_monomial * self.index.selectors[*p].0[current_row],
129                    None => cur_monomial,
130                };
131                for wit_index in wit.iter() {
132                    cur_monomial *= self.witnesses[*wit_index].0[current_row];
133                }
134                cur += cur_monomial;
135            }
136            if !cur.is_zero() {
137                return false;
138            }
139        }
140
141        true
142    }
143}
144
145#[cfg(test)]
146mod test {
147    use super::*;
148    use crate::{errors::HyperPlonkErrors, HyperPlonkSNARK};
149    use ark_bls12_381::{Bls12_381, Fr};
150    use subroutines::{
151        pcs::{
152            prelude::{MultilinearKzgPCS, MultilinearUniversalParams},
153            PolynomialCommitmentScheme,
154        },
155        poly_iop::PolyIOP,
156    };
157
158    const SUPPORTED_SIZE: usize = 20;
159    const MIN_NUM_VARS: usize = 8;
160    const MAX_NUM_VARS: usize = 15;
161    const CUSTOM_DEGREE: [usize; 6] = [1, 2, 4, 8, 16, 32];
162
163    #[test]
164    fn test_mock_circuit_sat() {
165        for i in 1..10 {
166            let vanilla_gate = CustomizedGates::vanilla_plonk_gate();
167            let circuit = MockCircuit::<Fr>::new(1 << i, &vanilla_gate);
168            assert!(circuit.is_satisfied());
169
170            let jf_gate = CustomizedGates::jellyfish_turbo_plonk_gate();
171            let circuit = MockCircuit::<Fr>::new(1 << i, &jf_gate);
172            assert!(circuit.is_satisfied());
173
174            for num_witness in 2..10 {
175                for degree in CUSTOM_DEGREE {
176                    let mock_gate = CustomizedGates::mock_gate(num_witness, degree);
177                    let circuit = MockCircuit::<Fr>::new(1 << i, &mock_gate);
178                    assert!(circuit.is_satisfied());
179                }
180            }
181        }
182    }
183
184    fn test_mock_circuit_zkp_helper(
185        nv: usize,
186        gate: &CustomizedGates,
187        pcs_srs: &MultilinearUniversalParams<Bls12_381>,
188    ) -> Result<(), HyperPlonkErrors> {
189        let circuit = MockCircuit::<Fr>::new(1 << nv, gate);
190        assert!(circuit.is_satisfied());
191
192        let index = circuit.index;
193        // generate pk and vks
194        let (pk, vk) =
195            <PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::preprocess(
196                &index, pcs_srs,
197            )?;
198        // generate a proof and verify
199        let proof =
200            <PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::prove(
201                &pk,
202                &circuit.public_inputs,
203                &circuit.witnesses,
204            )?;
205
206        let verify =
207            <PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::verify(
208                &vk,
209                &circuit.public_inputs,
210                &proof,
211            )?;
212        assert!(verify);
213        Ok(())
214    }
215
216    #[test]
217    fn test_mock_circuit_zkp() -> Result<(), HyperPlonkErrors> {
218        let mut rng = test_rng();
219        let pcs_srs =
220            MultilinearKzgPCS::<Bls12_381>::gen_srs_for_testing(&mut rng, SUPPORTED_SIZE)?;
221        for nv in MIN_NUM_VARS..MAX_NUM_VARS {
222            let vanilla_gate = CustomizedGates::vanilla_plonk_gate();
223            test_mock_circuit_zkp_helper(nv, &vanilla_gate, &pcs_srs)?;
224        }
225        for nv in MIN_NUM_VARS..MAX_NUM_VARS {
226            let tubro_gate = CustomizedGates::jellyfish_turbo_plonk_gate();
227            test_mock_circuit_zkp_helper(nv, &tubro_gate, &pcs_srs)?;
228        }
229        let nv = 5;
230        for num_witness in 2..10 {
231            for degree in CUSTOM_DEGREE {
232                let mock_gate = CustomizedGates::mock_gate(num_witness, degree);
233                test_mock_circuit_zkp_helper(nv, &mock_gate, &pcs_srs)?;
234            }
235        }
236
237        Ok(())
238    }
239
240    #[test]
241    fn test_mock_circuit_e2e() -> Result<(), HyperPlonkErrors> {
242        let mut rng = test_rng();
243        let pcs_srs =
244            MultilinearKzgPCS::<Bls12_381>::gen_srs_for_testing(&mut rng, SUPPORTED_SIZE)?;
245        let nv = MAX_NUM_VARS;
246
247        let turboplonk_gate = CustomizedGates::jellyfish_turbo_plonk_gate();
248        test_mock_circuit_zkp_helper(nv, &turboplonk_gate, &pcs_srs)?;
249
250        Ok(())
251    }
252
253    #[test]
254    fn test_mock_long_selector_e2e() -> Result<(), HyperPlonkErrors> {
255        let mut rng = test_rng();
256        let pcs_srs =
257            MultilinearKzgPCS::<Bls12_381>::gen_srs_for_testing(&mut rng, SUPPORTED_SIZE)?;
258        let nv = MAX_NUM_VARS;
259
260        let long_selector_gate = CustomizedGates::super_long_selector_gate();
261        test_mock_circuit_zkp_helper(nv, &long_selector_gate, &pcs_srs)?;
262
263        Ok(())
264    }
265}