mirror of
https://github.com/arnaucube/hyperplonk.git
synced 2026-01-10 16:11:29 +01:00
refactor snark
This commit is contained in:
committed by
chancharles92
parent
bee67686d0
commit
bd1fc9897e
@@ -7,8 +7,8 @@ mod virtual_polynomial;
|
|||||||
pub use errors::ArithErrors;
|
pub use errors::ArithErrors;
|
||||||
pub use multilinear_polynomial::{
|
pub use multilinear_polynomial::{
|
||||||
evaluate_no_par, evaluate_opt, fix_last_variables, fix_last_variables_no_par, fix_variables,
|
evaluate_no_par, evaluate_opt, fix_last_variables, fix_last_variables_no_par, fix_variables,
|
||||||
identity_permutation_mles, merge_polynomials, random_mle_list, random_permutation_mles,
|
identity_permutation, identity_permutation_mles, merge_polynomials, random_mle_list,
|
||||||
random_zero_mle_list, DenseMultilinearExtension,
|
random_permutation, random_permutation_mles, random_zero_mle_list, DenseMultilinearExtension,
|
||||||
};
|
};
|
||||||
pub use univariate_polynomial::{build_l, get_uni_domain};
|
pub use univariate_polynomial::{build_l, get_uni_domain};
|
||||||
pub use util::{bit_decompose, gen_eval_point, get_batched_nv, get_index};
|
pub use util::{bit_decompose, gen_eval_point, get_batched_nv, get_index};
|
||||||
|
|||||||
@@ -72,6 +72,11 @@ pub fn random_zero_mle_list<F: PrimeField, R: RngCore>(
|
|||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn identity_permutation<F: PrimeField>(num_vars: usize, num_chunks: usize) -> Vec<F> {
|
||||||
|
let len = (num_chunks as u64) * (1u64 << num_vars);
|
||||||
|
(0..len).map(F::from).collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// A list of MLEs that represents an identity permutation
|
/// A list of MLEs that represents an identity permutation
|
||||||
pub fn identity_permutation_mles<F: PrimeField>(
|
pub fn identity_permutation_mles<F: PrimeField>(
|
||||||
num_vars: usize,
|
num_vars: usize,
|
||||||
@@ -88,12 +93,11 @@ pub fn identity_permutation_mles<F: PrimeField>(
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A list of MLEs that represent a random permutation
|
pub fn random_permutation<F: PrimeField, R: RngCore>(
|
||||||
pub fn random_permutation_mles<F: PrimeField, R: RngCore>(
|
|
||||||
num_vars: usize,
|
num_vars: usize,
|
||||||
num_chunks: usize,
|
num_chunks: usize,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Vec<Rc<DenseMultilinearExtension<F>>> {
|
) -> Vec<F> {
|
||||||
let len = (num_chunks as u64) * (1u64 << num_vars);
|
let len = (num_chunks as u64) * (1u64 << num_vars);
|
||||||
let mut s_id_vec: Vec<F> = (0..len).map(F::from).collect();
|
let mut s_id_vec: Vec<F> = (0..len).map(F::from).collect();
|
||||||
let mut s_perm_vec = vec![];
|
let mut s_perm_vec = vec![];
|
||||||
@@ -101,6 +105,16 @@ pub fn random_permutation_mles<F: PrimeField, R: RngCore>(
|
|||||||
let index = rng.next_u64() as usize % s_id_vec.len();
|
let index = rng.next_u64() as usize % s_id_vec.len();
|
||||||
s_perm_vec.push(s_id_vec.remove(index));
|
s_perm_vec.push(s_id_vec.remove(index));
|
||||||
}
|
}
|
||||||
|
s_perm_vec
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A list of MLEs that represent a random permutation
|
||||||
|
pub fn random_permutation_mles<F: PrimeField, R: RngCore>(
|
||||||
|
num_vars: usize,
|
||||||
|
num_chunks: usize,
|
||||||
|
rng: &mut R,
|
||||||
|
) -> Vec<Rc<DenseMultilinearExtension<F>>> {
|
||||||
|
let s_perm_vec = random_permutation(num_vars, num_chunks, rng);
|
||||||
let mut res = vec![];
|
let mut res = vec![];
|
||||||
let n = 1 << num_vars;
|
let n = 1 << num_vars;
|
||||||
for i in 0..num_chunks {
|
for i in 0..num_chunks {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use arithmetic::identity_permutation_mles;
|
use arithmetic::identity_permutation;
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
use ark_poly::MultilinearExtension;
|
|
||||||
use ark_std::{log2, test_rng};
|
use ark_std::{log2, test_rng};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -93,7 +92,7 @@ impl<F: PrimeField> MockCircuit<F> {
|
|||||||
gate_func: gate.clone(),
|
gate_func: gate.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let permutation = identity_permutation_mles(merged_nv as usize, 1)[0].to_evaluations();
|
let permutation = identity_permutation(merged_nv as usize, 1);
|
||||||
let index = HyperPlonkIndex {
|
let index = HyperPlonkIndex {
|
||||||
params,
|
params,
|
||||||
permutation,
|
permutation,
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
errors::HyperPlonkErrors,
|
errors::HyperPlonkErrors,
|
||||||
structs::{HyperPlonkIndex, HyperPlonkProof, HyperPlonkProvingKey, HyperPlonkVerifyingKey},
|
structs::{HyperPlonkIndex, HyperPlonkProof, HyperPlonkProvingKey, HyperPlonkVerifyingKey},
|
||||||
utils::{build_f, eval_f, prover_sanity_check, PcsAccumulator},
|
utils::{build_f, eval_f, eval_perm_gate, prover_sanity_check, PcsAccumulator},
|
||||||
witness::WitnessColumn,
|
witness::WitnessColumn,
|
||||||
HyperPlonkSNARK,
|
HyperPlonkSNARK,
|
||||||
};
|
};
|
||||||
use arithmetic::{evaluate_opt, identity_permutation_mles, merge_polynomials, VPAuxInfo};
|
use arithmetic::{evaluate_opt, identity_permutation_mles, VPAuxInfo};
|
||||||
use ark_ec::PairingEngine;
|
use ark_ec::PairingEngine;
|
||||||
use ark_poly::DenseMultilinearExtension;
|
use ark_poly::DenseMultilinearExtension;
|
||||||
use ark_std::{end_timer, log2, start_timer, One, Zero};
|
use ark_std::{end_timer, log2, println, start_timer, One, Zero};
|
||||||
use std::{marker::PhantomData, rc::Rc};
|
use std::{marker::PhantomData, rc::Rc};
|
||||||
use subroutines::{
|
use subroutines::{
|
||||||
pcs::prelude::{Commitment, PolynomialCommitmentScheme},
|
pcs::prelude::{Commitment, PolynomialCommitmentScheme},
|
||||||
@@ -45,25 +45,32 @@ where
|
|||||||
pcs_srs: &PCS::SRS,
|
pcs_srs: &PCS::SRS,
|
||||||
) -> Result<(Self::ProvingKey, Self::VerifyingKey), HyperPlonkErrors> {
|
) -> Result<(Self::ProvingKey, Self::VerifyingKey), HyperPlonkErrors> {
|
||||||
let num_vars = index.num_variables();
|
let num_vars = index.num_variables();
|
||||||
|
let supported_ml_degree = num_vars;
|
||||||
let log_num_witness_polys = log2(index.num_witness_columns()) as usize;
|
|
||||||
let witness_merged_nv = num_vars + log_num_witness_polys;
|
|
||||||
|
|
||||||
let log_chunk_size = log_num_witness_polys + 1;
|
|
||||||
let prod_x_nv = num_vars + log_chunk_size;
|
|
||||||
|
|
||||||
let supported_ml_degree = prod_x_nv;
|
|
||||||
|
|
||||||
// extract PCS prover and verifier keys from SRS
|
// extract PCS prover and verifier keys from SRS
|
||||||
let (pcs_prover_param, pcs_verifier_param) =
|
let (pcs_prover_param, pcs_verifier_param) =
|
||||||
PCS::trim(pcs_srs, None, Some(supported_ml_degree))?;
|
PCS::trim(pcs_srs, None, Some(supported_ml_degree))?;
|
||||||
|
|
||||||
|
// build identity oracles
|
||||||
|
let id_oracles = identity_permutation_mles(num_vars, index.num_witness_columns());
|
||||||
|
let mut id_comms = vec![];
|
||||||
|
for id_oracle in id_oracles.iter() {
|
||||||
|
id_comms.push(PCS::commit(&pcs_prover_param, id_oracle)?);
|
||||||
|
}
|
||||||
|
|
||||||
// build permutation oracles
|
// build permutation oracles
|
||||||
let permutation_oracle = Rc::new(DenseMultilinearExtension::from_evaluations_slice(
|
let mut permutation_oracles = vec![];
|
||||||
witness_merged_nv,
|
let mut perm_comms = vec![];
|
||||||
&index.permutation,
|
let chunk_size = 1 << num_vars;
|
||||||
));
|
for i in 0..index.num_witness_columns() {
|
||||||
let perm_com = PCS::commit(&pcs_prover_param, &permutation_oracle)?;
|
let perm_oracle = Rc::new(DenseMultilinearExtension::from_evaluations_slice(
|
||||||
|
num_vars,
|
||||||
|
&index.permutation[i * chunk_size..(i + 1) * chunk_size],
|
||||||
|
));
|
||||||
|
let perm_comm = PCS::commit(&pcs_prover_param, &perm_oracle)?;
|
||||||
|
permutation_oracles.push(perm_oracle);
|
||||||
|
perm_comms.push(perm_comm);
|
||||||
|
}
|
||||||
|
|
||||||
// build selector oracles and commit to it
|
// build selector oracles and commit to it
|
||||||
let selector_oracles: Vec<Rc<DenseMultilinearExtension<E::Fr>>> = index
|
let selector_oracles: Vec<Rc<DenseMultilinearExtension<E::Fr>>> = index
|
||||||
@@ -77,23 +84,23 @@ where
|
|||||||
.map(|poly| PCS::commit(&pcs_prover_param, poly))
|
.map(|poly| PCS::commit(&pcs_prover_param, poly))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
// let selector_merged = merge_polynomials(&selector_oracles)?;
|
|
||||||
// let selector_com = PCS::commit(&pcs_prover_param, &selector_merged)?;
|
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
Self::ProvingKey {
|
Self::ProvingKey {
|
||||||
params: index.params.clone(),
|
params: index.params.clone(),
|
||||||
permutation_oracle: permutation_oracle.clone(),
|
id_oracles,
|
||||||
|
permutation_oracles,
|
||||||
selector_oracles,
|
selector_oracles,
|
||||||
selector_commitments: selector_commitments.clone(),
|
selector_commitments: selector_commitments.clone(),
|
||||||
|
permutation_commitments: perm_comms.clone(),
|
||||||
|
id_commitments: id_comms.clone(),
|
||||||
pcs_param: pcs_prover_param,
|
pcs_param: pcs_prover_param,
|
||||||
},
|
},
|
||||||
Self::VerifyingKey {
|
Self::VerifyingKey {
|
||||||
params: index.params.clone(),
|
params: index.params.clone(),
|
||||||
permutation_oracle,
|
|
||||||
pcs_param: pcs_verifier_param,
|
pcs_param: pcs_verifier_param,
|
||||||
selector_commitments,
|
selector_commitments,
|
||||||
perm_com,
|
perm_commitments: perm_comms,
|
||||||
|
id_commitments: id_comms,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -157,30 +164,13 @@ where
|
|||||||
|
|
||||||
// witness assignment of length 2^n
|
// witness assignment of length 2^n
|
||||||
let num_vars = pk.params.num_variables();
|
let num_vars = pk.params.num_variables();
|
||||||
let log_num_witness_polys = log2(pk.params.num_witness_columns()) as usize;
|
|
||||||
let merged_nv = num_vars + log_num_witness_polys;
|
|
||||||
|
|
||||||
// number of nv in prod(x) which is supposed to be the cap
|
|
||||||
// so each chunk we we store maximum 1 << (prod_x_nv - num_var) selectors
|
|
||||||
let log_chunk_size = log_num_witness_polys + 1;
|
|
||||||
let prod_x_nv = num_vars + log_chunk_size;
|
|
||||||
|
|
||||||
// online public input of length 2^\ell
|
// online public input of length 2^\ell
|
||||||
let ell = log2(pk.params.num_pub_input) as usize;
|
let ell = log2(pk.params.num_pub_input) as usize;
|
||||||
|
|
||||||
// We use accumulators to store the polynomials and their eval points.
|
// We use accumulators to store the polynomials and their eval points.
|
||||||
// They are batch opened at a later stage.
|
// They are batch opened at a later stage.
|
||||||
// This includes
|
let mut pcs_acc = PcsAccumulator::<E, PCS>::new(num_vars);
|
||||||
// - witnesses
|
|
||||||
// - prod(x)
|
|
||||||
// - selectors
|
|
||||||
//
|
|
||||||
// Accumulator's nv is bounded by prod(x) that means
|
|
||||||
// we need to split the selectors into multiple chunks if
|
|
||||||
// #selectors > chunk_size
|
|
||||||
// let mut pcs_acc = PcsAccumulator::<E, PCS>::new(prod_x_nv);
|
|
||||||
let mut prod_x_pcs_acc = PcsAccumulator::<E, PCS>::new(prod_x_nv);
|
|
||||||
let mut witness_and_selector_x_pcs_acc = PcsAccumulator::<E, PCS>::new(num_vars);
|
|
||||||
|
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
// 1. Commit Witness polynomials `w_i(x)` and append commitment to
|
// 1. Commit Witness polynomials `w_i(x)` and append commitment to
|
||||||
@@ -197,21 +187,10 @@ where
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|x| PCS::commit(&pk.pcs_param, x).unwrap())
|
.map(|x| PCS::commit(&pk.pcs_param, x).unwrap())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
for w_com in witness_commits.iter() {
|
||||||
// merge all witness into a single MLE - we will run perm check on it
|
transcript.append_serializable_element(b"w", w_com)?;
|
||||||
// to obtain prod(x)
|
|
||||||
let w_merged = merge_polynomials(&witness_polys)?;
|
|
||||||
if w_merged.num_vars != merged_nv {
|
|
||||||
return Err(HyperPlonkErrors::InvalidParameters(format!(
|
|
||||||
"merged witness poly has a different num_vars ({}) from expected ({})",
|
|
||||||
w_merged.num_vars, merged_nv
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we'll remove one of witness_merged_commit and witness_commits later.
|
|
||||||
let witness_merged_commit = PCS::commit(&pk.pcs_param, &w_merged)?;
|
|
||||||
transcript.append_serializable_element(b"w", &witness_merged_commit)?;
|
|
||||||
|
|
||||||
end_timer!(step);
|
end_timer!(step);
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
// 2 Run ZeroCheck on
|
// 2 Run ZeroCheck on
|
||||||
@@ -242,11 +221,11 @@ where
|
|||||||
// =======================================================================
|
// =======================================================================
|
||||||
let step = start_timer!(|| "Permutation check on w_i(x)");
|
let step = start_timer!(|| "Permutation check on w_i(x)");
|
||||||
|
|
||||||
let (perm_check_proof, prod_x) = <Self as PermutationCheck<E, PCS>>::prove(
|
let (perm_check_proof, prod_x, frac_poly) = <Self as PermutationCheck<E, PCS>>::prove(
|
||||||
&pk.pcs_param,
|
&pk.pcs_param,
|
||||||
&[w_merged.clone()],
|
&witness_polys,
|
||||||
&[w_merged.clone()],
|
&witness_polys,
|
||||||
&[pk.permutation_oracle.clone()],
|
&pk.permutation_oracles,
|
||||||
&mut transcript,
|
&mut transcript,
|
||||||
)?;
|
)?;
|
||||||
let perm_check_point = &perm_check_proof.zero_check_proof.point;
|
let perm_check_point = &perm_check_proof.zero_check_proof.point;
|
||||||
@@ -254,17 +233,24 @@ where
|
|||||||
end_timer!(step);
|
end_timer!(step);
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
// 4. Generate evaluations and corresponding proofs
|
// 4. Generate evaluations and corresponding proofs
|
||||||
// - 4.1. (deferred) batch opening prod(x) at
|
// - permcheck
|
||||||
// - [0, perm_check_point]
|
// 1. (deferred) batch opening prod(x) at
|
||||||
// - [1, perm_check_point]
|
// - [perm_check_point]
|
||||||
// - [perm_check_point, 0]
|
// - [perm_check_point[2..n], 0]
|
||||||
// - [perm_check_point, 1]
|
// - [perm_check_point[2..n], 1]
|
||||||
// - [1,...1, 0]
|
// - [1,...1, 0]
|
||||||
|
// 2. (deferred) batch opening frac(x) at
|
||||||
|
// - [perm_check_point]
|
||||||
|
// - [perm_check_point[2..n], 0]
|
||||||
|
// - [perm_check_point[2..n], 1]
|
||||||
|
// 3. (deferred) batch opening s_id(x) at
|
||||||
|
// - [perm_check_point]
|
||||||
|
// 4. (deferred) batch opening perms(x) at
|
||||||
|
// - [perm_check_point]
|
||||||
|
// 5. (deferred) batch opening witness_i(x) at
|
||||||
|
// - [perm_check_point]
|
||||||
//
|
//
|
||||||
// - 4.2. permutation check evaluations and proofs
|
// - zero check evaluations and proofs
|
||||||
// - 4.2.1. (deferred) wi_poly(perm_check_point)
|
|
||||||
//
|
|
||||||
// - 4.3. zero check evaluations and proofs
|
|
||||||
// - 4.3.1. (deferred) wi_poly(zero_check_point)
|
// - 4.3.1. (deferred) wi_poly(zero_check_point)
|
||||||
// - 4.3.2. (deferred) selector_poly(zero_check_point)
|
// - 4.3.2. (deferred) selector_poly(zero_check_point)
|
||||||
//
|
//
|
||||||
@@ -273,38 +259,58 @@ where
|
|||||||
// =======================================================================
|
// =======================================================================
|
||||||
let step = start_timer!(|| "opening and evaluations");
|
let step = start_timer!(|| "opening and evaluations");
|
||||||
|
|
||||||
// 4.1 (deferred) open prod(0,x), prod(1, x), prod(x, 0), prod(x, 1)
|
// (perm_check_point[2..n], 0)
|
||||||
// perm_check_point
|
let perm_check_point_0 = [&[E::Fr::zero()], &perm_check_point[0..num_vars - 1]].concat();
|
||||||
// prod(0, x)
|
// (perm_check_point[2..n], 1)
|
||||||
let tmp_point1 = [perm_check_point.as_slice(), &[E::Fr::zero()]].concat();
|
let perm_check_point_1 = [&[E::Fr::one()], &perm_check_point[0..num_vars - 1]].concat();
|
||||||
// prod(1, x)
|
// (1, ..., 1, 0)
|
||||||
let tmp_point2 = [perm_check_point.as_slice(), &[E::Fr::one()]].concat();
|
let prod_final_query_point =
|
||||||
// prod(x, 0)
|
[vec![E::Fr::zero()], vec![E::Fr::one(); num_vars - 1]].concat();
|
||||||
let tmp_point3 = [&[E::Fr::zero()], perm_check_point.as_slice()].concat();
|
|
||||||
// prod(x, 1)
|
|
||||||
let tmp_point4 = [&[E::Fr::one()], perm_check_point.as_slice()].concat();
|
|
||||||
// // prod(1, ..., 1, 0)
|
|
||||||
// let tmp_point5 = [vec![E::Fr::zero()], vec![E::Fr::one();
|
|
||||||
// merged_nv]].concat();
|
|
||||||
|
|
||||||
prod_x_pcs_acc.insert_poly_and_points(&prod_x, &perm_check_proof.prod_x_comm, &tmp_point1);
|
// prod(x)'s points
|
||||||
prod_x_pcs_acc.insert_poly_and_points(&prod_x, &perm_check_proof.prod_x_comm, &tmp_point2);
|
pcs_acc.insert_poly_and_points(&prod_x, &perm_check_proof.prod_x_comm, perm_check_point);
|
||||||
prod_x_pcs_acc.insert_poly_and_points(&prod_x, &perm_check_proof.prod_x_comm, &tmp_point3);
|
pcs_acc.insert_poly_and_points(&prod_x, &perm_check_proof.prod_x_comm, &perm_check_point_0);
|
||||||
prod_x_pcs_acc.insert_poly_and_points(&prod_x, &perm_check_proof.prod_x_comm, &tmp_point4);
|
pcs_acc.insert_poly_and_points(&prod_x, &perm_check_proof.prod_x_comm, &perm_check_point_1);
|
||||||
|
pcs_acc.insert_poly_and_points(
|
||||||
|
&prod_x,
|
||||||
|
&perm_check_proof.prod_x_comm,
|
||||||
|
&prod_final_query_point,
|
||||||
|
);
|
||||||
|
|
||||||
// 4.2 permutation check
|
// frac(x)'s points
|
||||||
// - 4.2.1. wi_poly(perm_check_point)
|
pcs_acc.insert_poly_and_points(&frac_poly, &perm_check_proof.frac_comm, perm_check_point);
|
||||||
let (perm_check_opening, perm_check_eval) =
|
pcs_acc.insert_poly_and_points(
|
||||||
PCS::open(&pk.pcs_param, &w_merged, perm_check_point)?;
|
&frac_poly,
|
||||||
|
&perm_check_proof.frac_comm,
|
||||||
|
&perm_check_point_0,
|
||||||
|
);
|
||||||
|
pcs_acc.insert_poly_and_points(
|
||||||
|
&frac_poly,
|
||||||
|
&perm_check_proof.frac_comm,
|
||||||
|
&perm_check_point_1,
|
||||||
|
);
|
||||||
|
|
||||||
// - 4.3. zero check evaluations and proofs
|
// s_id(x)'s points
|
||||||
// - 4.3.1 (deferred) wi_poly(zero_check_point)
|
for (s_id, s_com) in pk.id_oracles.iter().zip(pk.id_commitments.iter()) {
|
||||||
for i in 0..witness_polys.len() {
|
pcs_acc.insert_poly_and_points(s_id, s_com, perm_check_point);
|
||||||
witness_and_selector_x_pcs_acc.insert_poly_and_points(
|
}
|
||||||
&witness_polys[i],
|
|
||||||
&witness_commits[i],
|
// perms(x)'s points
|
||||||
&zero_check_proof.point,
|
for (perm, pcom) in pk
|
||||||
);
|
.permutation_oracles
|
||||||
|
.iter()
|
||||||
|
.zip(pk.permutation_commitments.iter())
|
||||||
|
{
|
||||||
|
pcs_acc.insert_poly_and_points(perm, pcom, perm_check_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
// witnesses' points
|
||||||
|
// TODO: refactor so it remains correct even if the order changed
|
||||||
|
for (wpoly, wcom) in witness_polys.iter().zip(witness_commits.iter()) {
|
||||||
|
pcs_acc.insert_poly_and_points(wpoly, wcom, perm_check_point);
|
||||||
|
}
|
||||||
|
for (wpoly, wcom) in witness_polys.iter().zip(witness_commits.iter()) {
|
||||||
|
pcs_acc.insert_poly_and_points(wpoly, wcom, &zero_check_proof.point);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - 4.3.2. (deferred) selector_poly(zero_check_point)
|
// - 4.3.2. (deferred) selector_poly(zero_check_point)
|
||||||
@@ -312,48 +318,30 @@ where
|
|||||||
.iter()
|
.iter()
|
||||||
.zip(pk.selector_commitments.iter())
|
.zip(pk.selector_commitments.iter())
|
||||||
.for_each(|(poly, com)| {
|
.for_each(|(poly, com)| {
|
||||||
witness_and_selector_x_pcs_acc.insert_poly_and_points(
|
pcs_acc.insert_poly_and_points(poly, com, &zero_check_proof.point)
|
||||||
poly,
|
|
||||||
com,
|
|
||||||
&zero_check_proof.point,
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// - 4.4. public input consistency checks
|
// - 4.4. public input consistency checks
|
||||||
// - pi_poly(r_pi) where r_pi is sampled from transcript
|
// - pi_poly(r_pi) where r_pi is sampled from transcript
|
||||||
let r_pi = transcript.get_and_append_challenge_vectors(b"r_pi", ell)?;
|
let r_pi = transcript.get_and_append_challenge_vectors(b"r_pi", ell)?;
|
||||||
let tmp_point = [vec![E::Fr::zero(); num_vars - ell], r_pi].concat();
|
let tmp_point = [vec![E::Fr::zero(); num_vars - ell], r_pi].concat();
|
||||||
witness_and_selector_x_pcs_acc.insert_poly_and_points(
|
pcs_acc.insert_poly_and_points(&witness_polys[0], &witness_commits[0], &tmp_point);
|
||||||
&witness_polys[0],
|
|
||||||
&witness_commits[0],
|
|
||||||
&tmp_point,
|
|
||||||
);
|
|
||||||
end_timer!(step);
|
end_timer!(step);
|
||||||
|
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
// 5. deferred batch opening
|
// 5. deferred batch opening
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
let step = start_timer!(|| "deferred batch openings prod(x)");
|
let step = start_timer!(|| "deferred batch openings prod(x)");
|
||||||
let batch_prod_x_openings = prod_x_pcs_acc.multi_open(&pk.pcs_param, &mut transcript)?;
|
let batch_openings = pcs_acc.multi_open(&pk.pcs_param, &mut transcript)?;
|
||||||
end_timer!(step);
|
|
||||||
|
|
||||||
let step = start_timer!(|| "deferred batch openings witness and selectors");
|
|
||||||
let batch_witness_and_selector_openings =
|
|
||||||
witness_and_selector_x_pcs_acc.multi_open(&pk.pcs_param, &mut transcript)?;
|
|
||||||
end_timer!(step);
|
end_timer!(step);
|
||||||
|
|
||||||
end_timer!(start);
|
end_timer!(start);
|
||||||
|
|
||||||
Ok(HyperPlonkProof {
|
Ok(HyperPlonkProof {
|
||||||
// PCS commit for witnesses
|
// PCS commit for witnesses
|
||||||
witness_merged_commit,
|
|
||||||
witness_commits,
|
witness_commits,
|
||||||
// batch_openings,
|
// batch_openings,
|
||||||
batch_prod_x_openings,
|
batch_openings,
|
||||||
batch_witness_and_selector_openings,
|
|
||||||
// perm check openings
|
|
||||||
perm_check_opening,
|
|
||||||
perm_check_eval,
|
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
// IOP proofs
|
// IOP proofs
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
@@ -384,7 +372,7 @@ where
|
|||||||
/// ```
|
/// ```
|
||||||
/// in vanilla plonk, and obtain a ZeroCheckSubClaim
|
/// in vanilla plonk, and obtain a ZeroCheckSubClaim
|
||||||
///
|
///
|
||||||
/// 2. Verify perm_check_proof on `\{w_i(x)\}` and `permutation_oracle`
|
/// 2. Verify perm_check_proof on `\{w_i(x)\}` and `permutation_oracles`
|
||||||
///
|
///
|
||||||
/// 3. check subclaim validity
|
/// 3. check subclaim validity
|
||||||
///
|
///
|
||||||
@@ -403,37 +391,11 @@ where
|
|||||||
|
|
||||||
let num_selectors = vk.params.num_selector_columns();
|
let num_selectors = vk.params.num_selector_columns();
|
||||||
let num_witnesses = vk.params.num_witness_columns();
|
let num_witnesses = vk.params.num_witness_columns();
|
||||||
|
|
||||||
// witness assignment of length 2^n
|
|
||||||
let log_num_witness_polys = log2(num_witnesses) as usize;
|
|
||||||
let num_vars = vk.params.num_variables();
|
let num_vars = vk.params.num_variables();
|
||||||
// number of variables in merged polynomial for Multilinear-KZG
|
|
||||||
let merged_nv = num_vars + log_num_witness_polys;
|
|
||||||
|
|
||||||
// online public input of length 2^\ell
|
// online public input of length 2^\ell
|
||||||
let ell = log2(vk.params.num_pub_input) as usize;
|
let ell = log2(vk.params.num_pub_input) as usize;
|
||||||
|
|
||||||
// sequence:
|
|
||||||
// - prod(x) at 5 points
|
|
||||||
// - w_merged at perm check point
|
|
||||||
// - w_merged at zero check points (#witness points)
|
|
||||||
// - selector_merged at zero check points (#selector points)
|
|
||||||
// - w[0] at r_pi
|
|
||||||
let selector_evals = &proof
|
|
||||||
.batch_witness_and_selector_openings
|
|
||||||
.f_i_eval_at_point_i[num_witnesses..num_witnesses + num_selectors];
|
|
||||||
let witness_evals = &proof
|
|
||||||
.batch_witness_and_selector_openings
|
|
||||||
.f_i_eval_at_point_i[..num_witnesses];
|
|
||||||
let prod_evals = &proof.batch_prod_x_openings.f_i_eval_at_point_i[0..4];
|
|
||||||
let pi_eval = proof
|
|
||||||
.batch_witness_and_selector_openings
|
|
||||||
.f_i_eval_at_point_i
|
|
||||||
.last()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let pi_poly = DenseMultilinearExtension::from_evaluations_slice(ell as usize, pub_input);
|
|
||||||
|
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
// 0. sanity checks
|
// 0. sanity checks
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
@@ -446,6 +408,20 @@ where
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract evaluations from openings
|
||||||
|
let prod_evals = &proof.batch_openings.f_i_eval_at_point_i[0..4];
|
||||||
|
let frac_evals = &proof.batch_openings.f_i_eval_at_point_i[4..7];
|
||||||
|
let id_evals = &proof.batch_openings.f_i_eval_at_point_i[7..7 + num_witnesses];
|
||||||
|
let perm_evals =
|
||||||
|
&proof.batch_openings.f_i_eval_at_point_i[7 + num_witnesses..7 + 2 * num_witnesses];
|
||||||
|
let witness_perm_evals =
|
||||||
|
&proof.batch_openings.f_i_eval_at_point_i[7 + 2 * num_witnesses..7 + 3 * num_witnesses];
|
||||||
|
let witness_gate_evals =
|
||||||
|
&proof.batch_openings.f_i_eval_at_point_i[7 + 3 * num_witnesses..7 + 4 * num_witnesses];
|
||||||
|
let selector_evals = &proof.batch_openings.f_i_eval_at_point_i
|
||||||
|
[7 + 4 * num_witnesses..7 + 4 * num_witnesses + num_selectors];
|
||||||
|
let pi_eval = proof.batch_openings.f_i_eval_at_point_i.last().unwrap();
|
||||||
|
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
// 1. Verify zero_check_proof on
|
// 1. Verify zero_check_proof on
|
||||||
// `f(q_0(x),...q_l(x), w_0(x),...w_d(x))`
|
// `f(q_0(x),...q_l(x), w_0(x),...w_d(x))`
|
||||||
@@ -464,7 +440,9 @@ where
|
|||||||
phantom: PhantomData::default(),
|
phantom: PhantomData::default(),
|
||||||
};
|
};
|
||||||
// push witness to transcript
|
// push witness to transcript
|
||||||
transcript.append_serializable_element(b"w", &proof.witness_merged_commit)?;
|
for w_com in proof.witness_commits.iter() {
|
||||||
|
transcript.append_serializable_element(b"w", w_com)?;
|
||||||
|
}
|
||||||
|
|
||||||
let zero_check_sub_claim = <Self as ZeroCheck<E::Fr>>::verify(
|
let zero_check_sub_claim = <Self as ZeroCheck<E::Fr>>::verify(
|
||||||
&proof.zero_check_proof,
|
&proof.zero_check_proof,
|
||||||
@@ -472,10 +450,10 @@ where
|
|||||||
&mut transcript,
|
&mut transcript,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let zero_check_point = &zero_check_sub_claim.point;
|
let zero_check_point = zero_check_sub_claim.point.clone();
|
||||||
|
|
||||||
// check zero check subclaim
|
// check zero check subclaim
|
||||||
let f_eval = eval_f(&vk.params.gate_func, selector_evals, witness_evals)?;
|
let f_eval = eval_f(&vk.params.gate_func, selector_evals, witness_gate_evals)?;
|
||||||
if f_eval != zero_check_sub_claim.expected_evaluation {
|
if f_eval != zero_check_sub_claim.expected_evaluation {
|
||||||
return Err(HyperPlonkErrors::InvalidProof(
|
return Err(HyperPlonkErrors::InvalidProof(
|
||||||
"zero check evaluation failed".to_string(),
|
"zero check evaluation failed".to_string(),
|
||||||
@@ -490,10 +468,9 @@ where
|
|||||||
|
|
||||||
// Zero check and perm check have different AuxInfo
|
// Zero check and perm check have different AuxInfo
|
||||||
let perm_check_aux_info = VPAuxInfo::<E::Fr> {
|
let perm_check_aux_info = VPAuxInfo::<E::Fr> {
|
||||||
// Prod(x) has a max degree of 2
|
// Prod(x) has a max degree of witnesses.len() + 1
|
||||||
max_degree: 2,
|
max_degree: proof.witness_commits.len() + 1,
|
||||||
// degree of merged poly
|
num_variables: num_vars,
|
||||||
num_variables: merged_nv,
|
|
||||||
phantom: PhantomData::default(),
|
phantom: PhantomData::default(),
|
||||||
};
|
};
|
||||||
let perm_check_sub_claim = <Self as PermutationCheck<E, PCS>>::verify(
|
let perm_check_sub_claim = <Self as PermutationCheck<E, PCS>>::verify(
|
||||||
@@ -502,40 +479,28 @@ where
|
|||||||
&mut transcript,
|
&mut transcript,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let perm_check_point = &perm_check_sub_claim
|
let perm_check_point = perm_check_sub_claim
|
||||||
.product_check_sub_claim
|
.product_check_sub_claim
|
||||||
.zero_check_sub_claim
|
.zero_check_sub_claim
|
||||||
.point;
|
.point
|
||||||
|
.clone();
|
||||||
|
|
||||||
let alpha = perm_check_sub_claim.product_check_sub_claim.alpha;
|
let alpha = perm_check_sub_claim.product_check_sub_claim.alpha;
|
||||||
let (beta, gamma) = perm_check_sub_claim.challenges;
|
let (beta, gamma) = perm_check_sub_claim.challenges;
|
||||||
|
|
||||||
// check perm check subclaim:
|
// check evaluation subclaim
|
||||||
// proof.witness_perm_check_eval ?= perm_check_sub_claim.expected_eval
|
let perm_gate_eval = eval_perm_gate(
|
||||||
//
|
prod_evals,
|
||||||
// Q(x) := prod(1,x) - prod(x, 0) * prod(x, 1)
|
frac_evals,
|
||||||
// + alpha * (
|
witness_perm_evals,
|
||||||
// (g(x) + beta * s_perm(x) + gamma) * prod(0, x)
|
id_evals,
|
||||||
// - (f(x) + beta * s_id(x) + gamma))
|
perm_evals,
|
||||||
// where
|
alpha,
|
||||||
// - Q(x) is perm_check_sub_claim.zero_check.exp_eval
|
beta,
|
||||||
// - prod(1, x) ... from prod(x) evaluated over (1, zero_point)
|
gamma,
|
||||||
// - g(x), f(x) are both w_merged over (zero_point)
|
*perm_check_point.last().unwrap(),
|
||||||
// - s_perm(x) and s_id(x) from vk_param.perm_oracle
|
)?;
|
||||||
// - alpha, beta, gamma from challenge
|
if perm_gate_eval
|
||||||
|
|
||||||
// we evaluate MLE directly instead of using s_id/s_perm PCS verify
|
|
||||||
// Verification takes n pairings while evaluate takes 2^n field ops.
|
|
||||||
let s_ids = identity_permutation_mles::<E::Fr>(perm_check_point.len(), 1);
|
|
||||||
let s_id_eval = evaluate_opt(&s_ids[0], perm_check_point);
|
|
||||||
let s_perm_eval = evaluate_opt(&vk.permutation_oracle, perm_check_point);
|
|
||||||
|
|
||||||
let q_x_rec = prod_evals[1] - prod_evals[2] * prod_evals[3]
|
|
||||||
+ alpha
|
|
||||||
* ((prod_evals[0] + beta * s_perm_eval + gamma) * prod_evals[0]
|
|
||||||
- (prod_evals[0] + beta * s_id_eval + gamma));
|
|
||||||
|
|
||||||
if q_x_rec
|
|
||||||
!= perm_check_sub_claim
|
!= perm_check_sub_claim
|
||||||
.product_check_sub_claim
|
.product_check_sub_claim
|
||||||
.zero_check_sub_claim
|
.zero_check_sub_claim
|
||||||
@@ -552,73 +517,92 @@ where
|
|||||||
// =======================================================================
|
// =======================================================================
|
||||||
let step = start_timer!(|| "verify commitments");
|
let step = start_timer!(|| "verify commitments");
|
||||||
|
|
||||||
// =======================================================================
|
// generate evaluation points and commitments
|
||||||
// 3.1 open prod(x)' evaluations
|
let mut comms = vec![];
|
||||||
// =======================================================================
|
let mut points = vec![];
|
||||||
// TODO: Check prod(x) at (1,...,1,0)
|
|
||||||
let _prod_final_query = perm_check_sub_claim.product_check_sub_claim.final_query;
|
|
||||||
let prod_points = [
|
|
||||||
[perm_check_point.as_slice(), &[E::Fr::zero()]].concat(),
|
|
||||||
[perm_check_point.as_slice(), &[E::Fr::one()]].concat(),
|
|
||||||
[&[E::Fr::zero()], perm_check_point.as_slice()].concat(),
|
|
||||||
[&[E::Fr::one()], perm_check_point.as_slice()].concat(),
|
|
||||||
// prod_final_query.0,
|
|
||||||
];
|
|
||||||
|
|
||||||
let mut r_pi = transcript.get_and_append_challenge_vectors(b"r_pi", ell)?;
|
let perm_check_point_0 = [&[E::Fr::zero()], &perm_check_point[0..num_vars - 1]].concat();
|
||||||
|
let perm_check_point_1 = [&[E::Fr::one()], &perm_check_point[0..num_vars - 1]].concat();
|
||||||
|
let prod_final_query_point =
|
||||||
|
[vec![E::Fr::zero()], vec![E::Fr::one(); num_vars - 1]].concat();
|
||||||
|
|
||||||
|
// prod(x)'s points
|
||||||
|
comms.push(proof.perm_check_proof.prod_x_comm);
|
||||||
|
comms.push(proof.perm_check_proof.prod_x_comm);
|
||||||
|
comms.push(proof.perm_check_proof.prod_x_comm);
|
||||||
|
comms.push(proof.perm_check_proof.prod_x_comm);
|
||||||
|
points.push(perm_check_point.clone());
|
||||||
|
points.push(perm_check_point_0.clone());
|
||||||
|
points.push(perm_check_point_1.clone());
|
||||||
|
points.push(prod_final_query_point);
|
||||||
|
|
||||||
|
// frac(x)'s points
|
||||||
|
comms.push(proof.perm_check_proof.frac_comm);
|
||||||
|
comms.push(proof.perm_check_proof.frac_comm);
|
||||||
|
comms.push(proof.perm_check_proof.frac_comm);
|
||||||
|
points.push(perm_check_point.clone());
|
||||||
|
points.push(perm_check_point_0);
|
||||||
|
points.push(perm_check_point_1);
|
||||||
|
|
||||||
|
// s_id's points
|
||||||
|
for &id_com in vk.id_commitments.iter() {
|
||||||
|
comms.push(id_com);
|
||||||
|
points.push(perm_check_point.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// perms' points
|
||||||
|
for &pcom in vk.perm_commitments.iter() {
|
||||||
|
comms.push(pcom);
|
||||||
|
points.push(perm_check_point.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// witnesses' points
|
||||||
|
for &wcom in proof.witness_commits.iter() {
|
||||||
|
comms.push(wcom);
|
||||||
|
points.push(perm_check_point.clone());
|
||||||
|
}
|
||||||
|
for &wcom in proof.witness_commits.iter() {
|
||||||
|
comms.push(wcom);
|
||||||
|
points.push(zero_check_point.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// selector_poly(zero_check_point)
|
||||||
|
for &com in vk.selector_commitments.iter() {
|
||||||
|
comms.push(com);
|
||||||
|
points.push(zero_check_point.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// - 4.4. public input consistency checks
|
||||||
|
// - pi_poly(r_pi) where r_pi is sampled from transcript
|
||||||
|
let r_pi = transcript.get_and_append_challenge_vectors(b"r_pi", ell)?;
|
||||||
|
let tmp_point = [vec![E::Fr::zero(); num_vars - ell], r_pi].concat();
|
||||||
|
// check public evaluation
|
||||||
|
let pi_poly = DenseMultilinearExtension::from_evaluations_slice(ell as usize, pub_input);
|
||||||
|
let expect_pi_eval = evaluate_opt(&pi_poly, &tmp_point[..]);
|
||||||
|
if expect_pi_eval != *pi_eval {
|
||||||
|
return Err(HyperPlonkErrors::InvalidProver(format!(
|
||||||
|
"Public input eval mismatch: got {}, expect {}",
|
||||||
|
pi_eval, expect_pi_eval,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
comms.push(proof.witness_commits[0]);
|
||||||
|
points.push(tmp_point);
|
||||||
|
|
||||||
|
assert_eq!(comms.len(), proof.batch_openings.f_i_eval_at_point_i.len());
|
||||||
|
|
||||||
|
// check proof
|
||||||
|
println!("last step!!!");
|
||||||
let res = PCS::batch_verify(
|
let res = PCS::batch_verify(
|
||||||
&vk.pcs_param,
|
&vk.pcs_param,
|
||||||
[proof.perm_check_proof.prod_x_comm; 4].as_ref(),
|
&comms,
|
||||||
prod_points.as_ref(),
|
&points,
|
||||||
&proof.batch_prod_x_openings,
|
&proof.batch_openings,
|
||||||
&mut transcript,
|
&mut transcript,
|
||||||
)?;
|
)?;
|
||||||
assert!(res);
|
|
||||||
|
|
||||||
// =======================================================================
|
|
||||||
// 3.3 open witnesses' and selectors evaluations
|
|
||||||
// =======================================================================
|
|
||||||
|
|
||||||
let res = PCS::verify(
|
|
||||||
&vk.pcs_param,
|
|
||||||
&proof.witness_merged_commit,
|
|
||||||
perm_check_point,
|
|
||||||
&proof.perm_check_eval,
|
|
||||||
&proof.perm_check_opening,
|
|
||||||
)?;
|
|
||||||
assert!(res);
|
|
||||||
|
|
||||||
let pi_eval_rec = evaluate_opt(&pi_poly, &r_pi);
|
|
||||||
assert_eq!(&pi_eval_rec, pi_eval);
|
|
||||||
|
|
||||||
r_pi = [vec![E::Fr::zero(); num_vars - ell], r_pi].concat();
|
|
||||||
let commitments = [
|
|
||||||
proof.witness_commits.as_slice(),
|
|
||||||
vk.selector_commitments.as_slice(),
|
|
||||||
&[proof.witness_commits[0]],
|
|
||||||
]
|
|
||||||
.concat();
|
|
||||||
|
|
||||||
let points = [
|
|
||||||
vec![zero_check_point.clone(); num_witnesses + num_selectors].as_slice(),
|
|
||||||
&[r_pi],
|
|
||||||
]
|
|
||||||
.concat();
|
|
||||||
|
|
||||||
let res = PCS::batch_verify(
|
|
||||||
&vk.pcs_param,
|
|
||||||
commitments.as_ref(),
|
|
||||||
points.as_ref(),
|
|
||||||
&proof.batch_witness_and_selector_openings,
|
|
||||||
&mut transcript,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
assert!(res);
|
|
||||||
|
|
||||||
end_timer!(step);
|
end_timer!(step);
|
||||||
end_timer!(start);
|
end_timer!(start);
|
||||||
Ok(true)
|
Ok(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,7 +613,7 @@ mod tests {
|
|||||||
custom_gate::CustomizedGates, selectors::SelectorColumn, structs::HyperPlonkParams,
|
custom_gate::CustomizedGates, selectors::SelectorColumn, structs::HyperPlonkParams,
|
||||||
witness::WitnessColumn,
|
witness::WitnessColumn,
|
||||||
};
|
};
|
||||||
use arithmetic::random_permutation_mles;
|
use arithmetic::{identity_permutation, random_permutation};
|
||||||
use ark_bls12_381::Bls12_381;
|
use ark_bls12_381::Bls12_381;
|
||||||
use ark_std::test_rng;
|
use ark_std::test_rng;
|
||||||
use subroutines::pcs::prelude::MultilinearKzgPCS;
|
use subroutines::pcs::prelude::MultilinearKzgPCS;
|
||||||
@@ -664,7 +648,7 @@ mod tests {
|
|||||||
let num_constraints = 4;
|
let num_constraints = 4;
|
||||||
let num_pub_input = 4;
|
let num_pub_input = 4;
|
||||||
let nv = log2(num_constraints) as usize;
|
let nv = log2(num_constraints) as usize;
|
||||||
let merged_nv = nv + log2(gate_func.num_witness_columns()) as usize;
|
let num_witnesses = 2;
|
||||||
|
|
||||||
// generate index
|
// generate index
|
||||||
let params = HyperPlonkParams {
|
let params = HyperPlonkParams {
|
||||||
@@ -672,9 +656,7 @@ mod tests {
|
|||||||
num_pub_input,
|
num_pub_input,
|
||||||
gate_func,
|
gate_func,
|
||||||
};
|
};
|
||||||
let permutation = identity_permutation_mles(merged_nv, 1)[0]
|
let permutation = identity_permutation(nv, num_witnesses);
|
||||||
.evaluations
|
|
||||||
.clone();
|
|
||||||
let q1 = SelectorColumn(vec![E::Fr::one(), E::Fr::one(), E::Fr::one(), E::Fr::one()]);
|
let q1 = SelectorColumn(vec![E::Fr::one(), E::Fr::one(), E::Fr::one(), E::Fr::one()]);
|
||||||
let index = HyperPlonkIndex {
|
let index = HyperPlonkIndex {
|
||||||
params,
|
params,
|
||||||
@@ -716,20 +698,18 @@ mod tests {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
// bad path 1: wrong permutation
|
// bad path 1: wrong permutation
|
||||||
let rand_perm: Vec<E::Fr> = random_permutation_mles(merged_nv, 1, &mut rng)[0]
|
let rand_perm: Vec<E::Fr> = random_permutation(nv, num_witnesses, &mut rng);
|
||||||
.evaluations
|
|
||||||
.clone();
|
|
||||||
let mut bad_index = index.clone();
|
let mut bad_index = index.clone();
|
||||||
bad_index.permutation = rand_perm;
|
bad_index.permutation = rand_perm;
|
||||||
// generate pk and vks
|
// generate pk and vks
|
||||||
let (_, bad_vk) = <PolyIOP<E::Fr> as HyperPlonkSNARK<E, MultilinearKzgPCS<E>>>::preprocess(
|
let (_, bad_vk) = <PolyIOP<E::Fr> as HyperPlonkSNARK<E, MultilinearKzgPCS<E>>>::preprocess(
|
||||||
&bad_index, &pcs_srs,
|
&bad_index, &pcs_srs,
|
||||||
)?;
|
)?;
|
||||||
assert!(
|
assert_eq!(
|
||||||
<PolyIOP<E::Fr> as HyperPlonkSNARK<E, MultilinearKzgPCS<E>>>::verify(
|
<PolyIOP<E::Fr> as HyperPlonkSNARK<E, MultilinearKzgPCS<E>>>::verify(
|
||||||
&bad_vk, &pi.0, &proof,
|
&bad_vk, &pi.0, &proof,
|
||||||
)
|
)?,
|
||||||
.is_err()
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
// bad path 2: wrong witness
|
// bad path 2: wrong witness
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use subroutines::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// The proof for the HyperPlonk PolyIOP, consists of the following:
|
/// The proof for the HyperPlonk PolyIOP, consists of the following:
|
||||||
/// - a batch commitment to all the witness MLEs
|
/// - the commitments to all witness MLEs
|
||||||
/// - a batch opening to all the MLEs at certain index
|
/// - a batch opening to all the MLEs at certain index
|
||||||
/// - the zero-check proof for checking custom gate-satisfiability
|
/// - the zero-check proof for checking custom gate-satisfiability
|
||||||
/// - the permutation-check proof for checking the copy constraints
|
/// - the permutation-check proof for checking the copy constraints
|
||||||
@@ -24,12 +24,8 @@ where
|
|||||||
PCS: PolynomialCommitmentScheme<E>,
|
PCS: PolynomialCommitmentScheme<E>,
|
||||||
{
|
{
|
||||||
// PCS commit for witnesses
|
// PCS commit for witnesses
|
||||||
pub witness_merged_commit: PCS::Commitment,
|
|
||||||
pub witness_commits: Vec<PCS::Commitment>,
|
pub witness_commits: Vec<PCS::Commitment>,
|
||||||
pub batch_prod_x_openings: PCS::BatchProof,
|
pub batch_openings: PCS::BatchProof,
|
||||||
pub batch_witness_and_selector_openings: PCS::BatchProof,
|
|
||||||
pub perm_check_opening: PCS::Proof,
|
|
||||||
pub perm_check_eval: PCS::Evaluation,
|
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
// IOP proofs
|
// IOP proofs
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
@@ -103,18 +99,24 @@ impl<F: PrimeField> HyperPlonkIndex<F> {
|
|||||||
/// The HyperPlonk proving key, consists of the following:
|
/// The HyperPlonk proving key, consists of the following:
|
||||||
/// - the hyperplonk instance parameters
|
/// - the hyperplonk instance parameters
|
||||||
/// - the preprocessed polynomials output by the indexer
|
/// - the preprocessed polynomials output by the indexer
|
||||||
/// - the commitment to the selectors
|
/// - the commitment to the selectors and permutations
|
||||||
/// - the parameters for polynomial commitment
|
/// - the parameters for polynomial commitment
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
pub struct HyperPlonkProvingKey<E: PairingEngine, PCS: PolynomialCommitmentScheme<E>> {
|
pub struct HyperPlonkProvingKey<E: PairingEngine, PCS: PolynomialCommitmentScheme<E>> {
|
||||||
/// Hyperplonk instance parameters
|
/// Hyperplonk instance parameters
|
||||||
pub params: HyperPlonkParams,
|
pub params: HyperPlonkParams,
|
||||||
/// The preprocessed permutation polynomials
|
/// The preprocessed permutation polynomials
|
||||||
pub permutation_oracle: Rc<DenseMultilinearExtension<E::Fr>>,
|
pub permutation_oracles: Vec<Rc<DenseMultilinearExtension<E::Fr>>>,
|
||||||
|
/// The preprocessed identity polynomials
|
||||||
|
pub id_oracles: Vec<Rc<DenseMultilinearExtension<E::Fr>>>,
|
||||||
/// The preprocessed selector polynomials
|
/// The preprocessed selector polynomials
|
||||||
pub selector_oracles: Vec<Rc<DenseMultilinearExtension<E::Fr>>>,
|
pub selector_oracles: Vec<Rc<DenseMultilinearExtension<E::Fr>>>,
|
||||||
/// A commitment to the preprocessed selector polynomials
|
/// Commitments to the preprocessed selector polynomials
|
||||||
pub selector_commitments: Vec<PCS::Commitment>,
|
pub selector_commitments: Vec<PCS::Commitment>,
|
||||||
|
/// Commitments to the preprocessed permutation polynomials
|
||||||
|
pub permutation_commitments: Vec<PCS::Commitment>,
|
||||||
|
/// Commitments to the preprocessed identity polynomials
|
||||||
|
pub id_commitments: Vec<PCS::Commitment>,
|
||||||
/// The parameters for PCS commitment
|
/// The parameters for PCS commitment
|
||||||
pub pcs_param: PCS::ProverParam,
|
pub pcs_param: PCS::ProverParam,
|
||||||
}
|
}
|
||||||
@@ -127,12 +129,12 @@ pub struct HyperPlonkProvingKey<E: PairingEngine, PCS: PolynomialCommitmentSchem
|
|||||||
pub struct HyperPlonkVerifyingKey<E: PairingEngine, PCS: PolynomialCommitmentScheme<E>> {
|
pub struct HyperPlonkVerifyingKey<E: PairingEngine, PCS: PolynomialCommitmentScheme<E>> {
|
||||||
/// Hyperplonk instance parameters
|
/// Hyperplonk instance parameters
|
||||||
pub params: HyperPlonkParams,
|
pub params: HyperPlonkParams,
|
||||||
/// The preprocessed permutation polynomials
|
|
||||||
pub permutation_oracle: Rc<DenseMultilinearExtension<E::Fr>>,
|
|
||||||
/// The parameters for PCS commitment
|
/// The parameters for PCS commitment
|
||||||
pub pcs_param: PCS::VerifierParam,
|
pub pcs_param: PCS::VerifierParam,
|
||||||
/// A commitment to the preprocessed selector polynomials
|
/// A commitment to the preprocessed selector polynomials
|
||||||
pub selector_commitments: Vec<PCS::Commitment>,
|
pub selector_commitments: Vec<PCS::Commitment>,
|
||||||
/// Permutation oracle's commitment
|
/// Permutation oracles' commitments
|
||||||
pub perm_com: PCS::Commitment,
|
pub perm_commitments: Vec<PCS::Commitment>,
|
||||||
|
/// Commitments to the preprocessed identity polynomials
|
||||||
|
pub id_commitments: Vec<PCS::Commitment>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,6 +240,45 @@ pub(crate) fn eval_f<F: PrimeField>(
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check perm check subclaim:
|
||||||
|
// proof.witness_perm_check_eval ?= perm_check_sub_claim.expected_eval
|
||||||
|
// Q(x) := prod(x) - p1(x) * p2(x)
|
||||||
|
// + alpha * frac(x) * g1(x) * ... * gk(x)
|
||||||
|
// - alpha * f1(x) * ... * fk(x)
|
||||||
|
//
|
||||||
|
// where p1(x) = (1-x1) * frac(x2, ..., xn, 0)
|
||||||
|
// + x1 * prod(x2, ..., xn, 0),
|
||||||
|
// and p2(x) = (1-x1) * frac(x2, ..., xn, 1)
|
||||||
|
// + x1 * prod(x2, ..., xn, 1)
|
||||||
|
// and gi(x) = (wi(x) + beta * perms_i(x) + gamma)
|
||||||
|
// and fi(x) = (wi(x) + beta * s_id_i(x) + gamma)
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub(crate) fn eval_perm_gate<F: PrimeField>(
|
||||||
|
prod_evals: &[F],
|
||||||
|
frac_evals: &[F],
|
||||||
|
witness_perm_evals: &[F],
|
||||||
|
id_evals: &[F],
|
||||||
|
perm_evals: &[F],
|
||||||
|
alpha: F,
|
||||||
|
beta: F,
|
||||||
|
gamma: F,
|
||||||
|
x1: F,
|
||||||
|
) -> Result<F, HyperPlonkErrors> {
|
||||||
|
let p1_eval = frac_evals[1] + x1 * (prod_evals[1] - frac_evals[1]);
|
||||||
|
let p2_eval = frac_evals[2] + x1 * (prod_evals[2] - frac_evals[2]);
|
||||||
|
let mut f_prod_eval = F::one();
|
||||||
|
for (&w_eval, &id_eval) in witness_perm_evals.iter().zip(id_evals.iter()) {
|
||||||
|
f_prod_eval *= w_eval + beta * id_eval + gamma;
|
||||||
|
}
|
||||||
|
let mut g_prod_eval = F::one();
|
||||||
|
for (&w_eval, &p_eval) in witness_perm_evals.iter().zip(perm_evals.iter()) {
|
||||||
|
g_prod_eval *= w_eval + beta * p_eval + gamma;
|
||||||
|
}
|
||||||
|
let res =
|
||||||
|
prod_evals[0] - p1_eval * p2_eval + alpha * (frac_evals[0] * g_prod_eval - f_prod_eval);
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -149,27 +149,27 @@ fn bench_permutation_check() -> Result<(), PolyIOPErrors> {
|
|||||||
// identity map
|
// identity map
|
||||||
let perms = identity_permutation_mles(nv, 1);
|
let perms = identity_permutation_mles(nv, 1);
|
||||||
|
|
||||||
let proof = {
|
let proof =
|
||||||
let start = Instant::now();
|
{
|
||||||
let mut transcript =
|
let start = Instant::now();
|
||||||
<PolyIOP<Fr> as PermutationCheck<Bls12_381, KZG>>::init_transcript();
|
let mut transcript =
|
||||||
transcript.append_message(b"testing", b"initializing transcript for testing")?;
|
<PolyIOP<Fr> as PermutationCheck<Bls12_381, KZG>>::init_transcript();
|
||||||
|
transcript.append_message(b"testing", b"initializing transcript for testing")?;
|
||||||
|
|
||||||
let (proof, _q_x) = <PolyIOP<Fr> as PermutationCheck<Bls12_381, KZG>>::prove(
|
let (proof, _q_x, _frac_poly) = <PolyIOP<Fr> as PermutationCheck<
|
||||||
&pcs_param,
|
Bls12_381,
|
||||||
&ws,
|
KZG,
|
||||||
&ws,
|
>>::prove(
|
||||||
&perms,
|
&pcs_param, &ws, &ws, &perms, &mut transcript
|
||||||
&mut transcript,
|
)?;
|
||||||
)?;
|
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"permutation check proving time for {} variables: {} ns",
|
"permutation check proving time for {} variables: {} ns",
|
||||||
nv,
|
nv,
|
||||||
start.elapsed().as_nanos() / repetition as u128
|
start.elapsed().as_nanos() / repetition as u128
|
||||||
);
|
);
|
||||||
proof
|
proof
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
let poly_info = VPAuxInfo {
|
let poly_info = VPAuxInfo {
|
||||||
|
|||||||
@@ -63,16 +63,25 @@ where
|
|||||||
/// Outputs:
|
/// Outputs:
|
||||||
/// - a permutation check proof proving that gs is a permutation of fs under
|
/// - a permutation check proof proving that gs is a permutation of fs under
|
||||||
/// permutation
|
/// permutation
|
||||||
/// - the product polynomial build during product check (for testing)
|
/// - the product polynomial built during product check
|
||||||
|
/// - the fractional polynomial built during product check
|
||||||
///
|
///
|
||||||
/// Cost: O(N)
|
/// Cost: O(N)
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
fn prove(
|
fn prove(
|
||||||
pcs_param: &PCS::ProverParam,
|
pcs_param: &PCS::ProverParam,
|
||||||
fxs: &[Self::MultilinearExtension],
|
fxs: &[Self::MultilinearExtension],
|
||||||
gxs: &[Self::MultilinearExtension],
|
gxs: &[Self::MultilinearExtension],
|
||||||
perms: &[Self::MultilinearExtension],
|
perms: &[Self::MultilinearExtension],
|
||||||
transcript: &mut IOPTranscript<E::Fr>,
|
transcript: &mut IOPTranscript<E::Fr>,
|
||||||
) -> Result<(Self::PermutationProof, Self::MultilinearExtension), PolyIOPErrors>;
|
) -> Result<
|
||||||
|
(
|
||||||
|
Self::PermutationProof,
|
||||||
|
Self::MultilinearExtension,
|
||||||
|
Self::MultilinearExtension,
|
||||||
|
),
|
||||||
|
PolyIOPErrors,
|
||||||
|
>;
|
||||||
|
|
||||||
/// Verify that (g1, ..., gk) is a permutation of
|
/// Verify that (g1, ..., gk) is a permutation of
|
||||||
/// (f1, ..., fk) over the permutation oracles (perm1, ..., permk)
|
/// (f1, ..., fk) over the permutation oracles (perm1, ..., permk)
|
||||||
@@ -101,7 +110,14 @@ where
|
|||||||
gxs: &[Self::MultilinearExtension],
|
gxs: &[Self::MultilinearExtension],
|
||||||
perms: &[Self::MultilinearExtension],
|
perms: &[Self::MultilinearExtension],
|
||||||
transcript: &mut IOPTranscript<E::Fr>,
|
transcript: &mut IOPTranscript<E::Fr>,
|
||||||
) -> Result<(Self::PermutationProof, Self::MultilinearExtension), PolyIOPErrors> {
|
) -> Result<
|
||||||
|
(
|
||||||
|
Self::PermutationProof,
|
||||||
|
Self::MultilinearExtension,
|
||||||
|
Self::MultilinearExtension,
|
||||||
|
),
|
||||||
|
PolyIOPErrors,
|
||||||
|
> {
|
||||||
let start = start_timer!(|| "Permutation check prove");
|
let start = start_timer!(|| "Permutation check prove");
|
||||||
if fxs.is_empty() {
|
if fxs.is_empty() {
|
||||||
return Err(PolyIOPErrors::InvalidParameters("fxs is empty".to_string()));
|
return Err(PolyIOPErrors::InvalidParameters("fxs is empty".to_string()));
|
||||||
@@ -131,7 +147,7 @@ where
|
|||||||
let (numerators, denominators) = computer_nums_and_denoms(&beta, &gamma, fxs, gxs, perms)?;
|
let (numerators, denominators) = computer_nums_and_denoms(&beta, &gamma, fxs, gxs, perms)?;
|
||||||
|
|
||||||
// invoke product check on numerator and denominator
|
// invoke product check on numerator and denominator
|
||||||
let (proof, prod_poly, _) = <Self as ProductCheck<E, PCS>>::prove(
|
let (proof, prod_poly, frac_poly) = <Self as ProductCheck<E, PCS>>::prove(
|
||||||
pcs_param,
|
pcs_param,
|
||||||
&numerators,
|
&numerators,
|
||||||
&denominators,
|
&denominators,
|
||||||
@@ -139,7 +155,7 @@ where
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
end_timer!(start);
|
end_timer!(start);
|
||||||
Ok((proof, prod_poly))
|
Ok((proof, prod_poly, frac_poly))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify(
|
fn verify(
|
||||||
@@ -201,7 +217,7 @@ mod test {
|
|||||||
// prover
|
// prover
|
||||||
let mut transcript = <PolyIOP<E::Fr> as PermutationCheck<E, PCS>>::init_transcript();
|
let mut transcript = <PolyIOP<E::Fr> as PermutationCheck<E, PCS>>::init_transcript();
|
||||||
transcript.append_message(b"testing", b"initializing transcript for testing")?;
|
transcript.append_message(b"testing", b"initializing transcript for testing")?;
|
||||||
let (proof, prod_x) = <PolyIOP<E::Fr> as PermutationCheck<E, PCS>>::prove(
|
let (proof, prod_x, _frac_poly) = <PolyIOP<E::Fr> as PermutationCheck<E, PCS>>::prove(
|
||||||
pcs_param,
|
pcs_param,
|
||||||
fxs,
|
fxs,
|
||||||
gxs,
|
gxs,
|
||||||
|
|||||||
Reference in New Issue
Block a user