You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

235 lines
7.9 KiB

use arithmetic::identity_permutation_mle;
use ark_ff::PrimeField;
use ark_poly::MultilinearExtension;
use ark_std::{log2, test_rng};
use crate::{
custom_gate::CustomizedGates,
selectors::SelectorColumn,
structs::{HyperPlonkIndex, HyperPlonkParams},
witness::WitnessColumn,
};
pub struct MockCircuit<F: PrimeField> {
pub witnesses: Vec<WitnessColumn<F>>,
pub index: HyperPlonkIndex<F>,
}
impl<F: PrimeField> MockCircuit<F> {
/// Number of variables in a multilinear system
pub fn num_variables(&self) -> usize {
self.index.num_variables()
}
/// number of selector columns
pub fn num_selector_columns(&self) -> usize {
self.index.num_selector_columns()
}
/// number of witness columns
pub fn num_witness_columns(&self) -> usize {
self.index.num_witness_columns()
}
}
impl<F: PrimeField> MockCircuit<F> {
/// Generate a mock plonk circuit for the input constraint size.
pub fn new(num_constraints: usize, gate: &CustomizedGates) -> MockCircuit<F> {
let mut rng = test_rng();
let nv = log2(num_constraints);
let num_selectors = gate.num_selector_columns();
let num_witnesses = gate.num_witness_columns();
let log_n_wires = log2(num_witnesses);
let merged_nv = nv + log_n_wires;
let mut selectors: Vec<SelectorColumn<F>> = vec![SelectorColumn::default(); num_selectors];
let mut witnesses: Vec<WitnessColumn<F>> = vec![WitnessColumn::default(); num_witnesses];
for _cs_counter in 0..num_constraints {
let mut cur_selectors: Vec<F> = (0..(num_selectors - 1))
.map(|_| F::rand(&mut rng))
.collect();
let cur_witness: Vec<F> = (0..num_witnesses).map(|_| F::rand(&mut rng)).collect();
let mut last_selector = F::zero();
for (index, (coeff, q, wit)) in gate.gates.iter().enumerate() {
if index != num_selectors - 1 {
let mut cur_monomial = if *coeff < 0 {
-F::from((-coeff) as u64)
} else {
F::from(*coeff as u64)
};
cur_monomial = match q {
Some(p) => cur_monomial * cur_selectors[*p],
None => cur_monomial,
};
for wit_index in wit.iter() {
cur_monomial *= cur_witness[*wit_index];
}
last_selector += cur_monomial;
} else {
let mut cur_monomial = if *coeff < 0 {
-F::from((-coeff) as u64)
} else {
F::from(*coeff as u64)
};
for wit_index in wit.iter() {
cur_monomial *= cur_witness[*wit_index];
}
last_selector /= -cur_monomial;
}
}
cur_selectors.push(last_selector);
for i in 0..num_selectors {
selectors[i].append(cur_selectors[i]);
}
for i in 0..num_witnesses {
witnesses[i].append(cur_witness[i]);
}
}
let params = HyperPlonkParams {
num_constraints,
num_pub_input: num_constraints,
gate_func: gate.clone(),
};
let permutation = identity_permutation_mle(merged_nv as usize).to_evaluations();
let index = HyperPlonkIndex {
params,
permutation,
selectors,
};
Self { witnesses, index }
}
pub fn is_satisfied(&self) -> bool {
for current_row in 0..self.num_variables() {
let mut cur = F::zero();
for (coeff, q, wit) in self.index.params.gate_func.gates.iter() {
let mut cur_monomial = if *coeff < 0 {
-F::from((-coeff) as u64)
} else {
F::from(*coeff as u64)
};
cur_monomial = match q {
Some(p) => cur_monomial * self.index.selectors[*p].0[current_row],
None => cur_monomial,
};
for wit_index in wit.iter() {
cur_monomial *= self.witnesses[*wit_index].0[current_row];
}
cur += cur_monomial;
}
if !cur.is_zero() {
return false;
}
}
true
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{errors::HyperPlonkErrors, HyperPlonkSNARK};
use ark_bls12_381::{Bls12_381, Fr};
use pcs::{
prelude::{MultilinearKzgPCS, MultilinearUniversalParams, UnivariateUniversalParams},
PolynomialCommitmentScheme,
};
use poly_iop::PolyIOP;
#[test]
fn test_mock_circuit_sat() {
for i in 1..10 {
let vanilla_gate = CustomizedGates::vanilla_plonk_gate();
let circuit = MockCircuit::<Fr>::new(1 << i, &vanilla_gate);
assert!(circuit.is_satisfied());
let jf_gate = CustomizedGates::jellyfish_turbo_plonk_gate();
let circuit = MockCircuit::<Fr>::new(1 << i, &jf_gate);
assert!(circuit.is_satisfied());
for num_witness in 2..10 {
for degree in 1..10 {
let mock_gate = CustomizedGates::mock_gate(num_witness, degree);
let circuit = MockCircuit::<Fr>::new(1 << i, &mock_gate);
assert!(circuit.is_satisfied());
}
}
}
}
fn test_mock_circuit_zkp_helper(
nv: usize,
gate: &CustomizedGates,
pcs_srs: &(
MultilinearUniversalParams<Bls12_381>,
UnivariateUniversalParams<Bls12_381>,
),
) -> Result<(), HyperPlonkErrors> {
let circuit = MockCircuit::<Fr>::new(1 << nv, gate);
assert!(circuit.is_satisfied());
let index = circuit.index;
// generate pk and vks
let (pk, vk) =
<PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::preprocess(
&index, &pcs_srs,
)?;
// generate a proof and verify
let proof =
<PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::prove(
&pk,
&circuit.witnesses[0].0,
&circuit.witnesses,
)?;
let verify =
<PolyIOP<Fr> as HyperPlonkSNARK<Bls12_381, MultilinearKzgPCS<Bls12_381>>>::verify(
&vk,
&circuit.witnesses[0].0,
&proof,
)?;
assert!(verify);
Ok(())
}
#[test]
fn test_mock_circuit_zkp() -> Result<(), HyperPlonkErrors> {
let mut rng = test_rng();
let pcs_srs = MultilinearKzgPCS::<Bls12_381>::gen_srs_for_testing(&mut rng, 16)?;
for nv in 1..10 {
let vanilla_gate = CustomizedGates::vanilla_plonk_gate();
test_mock_circuit_zkp_helper(nv, &vanilla_gate, &pcs_srs)?;
}
for nv in 1..10 {
let tubro_gate = CustomizedGates::jellyfish_turbo_plonk_gate();
test_mock_circuit_zkp_helper(nv, &tubro_gate, &pcs_srs)?;
}
let nv = 5;
for num_witness in 2..10 {
for degree in [1, 2, 4, 8, 16] {
let mock_gate = CustomizedGates::mock_gate(num_witness, degree);
test_mock_circuit_zkp_helper(nv, &mock_gate, &pcs_srs)?;
}
}
Ok(())
}
#[test]
fn test_mock_circuit_e2e() -> Result<(), HyperPlonkErrors> {
let mut rng = test_rng();
let pcs_srs = MultilinearKzgPCS::<Bls12_381>::gen_srs_for_testing(&mut rng, 23)?;
let nv = 18;
let vanilla_gate = CustomizedGates::vanilla_plonk_gate();
test_mock_circuit_zkp_helper(nv, &vanilla_gate, &pcs_srs)?;
Ok(())
}
}