Browse Source

49 verify validity of subclaims in plonk verification (#51)

main
zhenfei 2 years ago
committed by GitHub
parent
commit
066c370b3c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 342 additions and 144 deletions
  1. +5
    -2
      hyperplonk/Cargo.toml
  2. +294
    -119
      hyperplonk/src/lib.rs
  3. +21
    -6
      hyperplonk/src/structs.rs
  4. +3
    -4
      hyperplonk/src/utils.rs
  5. +1
    -1
      pcs/src/multilinear_kzg/batching.rs
  6. +3
    -3
      poly-iop/src/perm_check/mod.rs
  7. +2
    -3
      poly-iop/src/sum_check/mod.rs
  8. +0
    -6
      poly-iop/src/sum_check/verifier.rs
  9. +13
    -0
      poly-iop/src/zero_check/mod.rs

+ 5
- 2
hyperplonk/Cargo.toml

@ -25,8 +25,11 @@ ark-bls12-381 = { version = "0.3.0", default-features = false, features = [ "cur
[features]
default = [ "parallel", "print-trace" ]
# default = [ "parallel" ]
# default = [ "parallel", "print-trace", "extensive_sanity_checks" ]
default = [ "parallel", "extensive_sanity_checks" ]
# extensive sanity checks that are useful for debugging
extensive_sanity_checks = [ ]
parallel = [
"ark-std/parallel",
"ark-ff/parallel",

+ 294
- 119
hyperplonk/src/lib.rs

@ -1,5 +1,6 @@
//! Main module for the HyperPlonk PolyIOP.
use crate::utils::eval_f;
use arithmetic::VPAuxInfo;
use ark_ec::PairingEngine;
use ark_poly::{DenseMultilinearExtension, MultilinearExtension};
@ -7,15 +8,14 @@ use ark_std::{end_timer, log2, start_timer, One, Zero};
use errors::HyperPlonkErrors;
use pcs::prelude::{compute_qx_degree, merge_polynomials, PCSErrors, PolynomialCommitmentScheme};
use poly_iop::{
identity_permutation_mle,
prelude::{PermutationCheck, SumCheck, ZeroCheck},
PolyIOP,
};
use selectors::SelectorColumn;
use std::{marker::PhantomData, rc::Rc};
use structs::{
HyperPlonkParams, HyperPlonkProof, HyperPlonkProvingKey, HyperPlonkSubClaim,
HyperPlonkVerifyingKey,
};
use structs::{HyperPlonkParams, HyperPlonkProof, HyperPlonkProvingKey, HyperPlonkVerifyingKey};
use transcript::IOPTranscript;
use utils::build_f;
use witness::WitnessColumn;
@ -37,7 +37,6 @@ where
type ProvingKey;
type VerifyingKey;
type Proof;
type SubClaim;
/// Generate the preprocessed polynomials output by the indexer.
///
@ -61,35 +60,27 @@ where
/// - `pk`: circuit proving key
/// - `pub_input`: online public input
/// - `witness`: witness assignment
/// - `transcript`: the transcript used for generating pseudorandom
/// challenges
/// Outputs:
/// - The HyperPlonk SNARK proof.
fn prove(
pk: &Self::ProvingKey,
pub_input: &[E::Fr],
witnesses: &[WitnessColumn<E::Fr>],
transcript: &mut Self::Transcript,
) -> Result<Self::Proof, HyperPlonkErrors>;
/// Verify the HyperPlonk proof and generate the evaluation subclaims to be
/// checked later by the SNARK verifier.
/// Verify the HyperPlonk proof.
///
/// Inputs:
/// - `params`: instance parameter
/// - `pub_input`: online public input
/// - `proof`: HyperPlonk SNARK proof
/// - `transcript`: the transcript used for generating pseudorandom
/// challenges
/// - `proof`: HyperPlonk SNARK proof challenges
/// Outputs:
/// - Return error if the verification fails, otherwise return the
/// evaluation subclaim
/// - Return a boolean on whether the verification is successful
fn verify(
params: &Self::VerifyingKey,
pub_input: &[E::Fr],
proof: &Self::Proof,
transcript: &mut Self::Transcript,
) -> Result<Self::SubClaim, HyperPlonkErrors>;
) -> Result<bool, HyperPlonkErrors>;
}
impl<E, PCS> HyperPlonkSNARK<E, PCS> for PolyIOP<E::Fr>
@ -109,7 +100,6 @@ where
type ProvingKey = HyperPlonkProvingKey<E, PCS>;
type VerifyingKey = HyperPlonkVerifyingKey<E, PCS>;
type Proof = HyperPlonkProof<E, PCS, Self, Self>;
type SubClaim = HyperPlonkSubClaim<E::Fr, Self, Self>;
/// Generate the preprocessed polynomials output by the indexer.
///
@ -143,11 +133,9 @@ where
// build permutation oracles
let permutation_oracles = Rc::new(DenseMultilinearExtension::from_evaluations_slice(
// num_vars = merged_nv + 1 because this oracle encodes both s_id and s_perm
merged_nv + 1,
merged_nv,
permutation,
));
let perm_com = PCS::commit(&pcs_prover_param, &permutation_oracles)?;
// build selector oracles and commit to it
@ -183,8 +171,6 @@ where
/// - `pk`: circuit proving key
/// - `pub_input`: online public input of length 2^\ell
/// - `witness`: witness assignment of length 2^n
/// - `transcript`: the transcript used for generating pseudorandom
/// challenges
/// Outputs:
/// - The HyperPlonk SNARK proof.
///
@ -211,13 +197,15 @@ where
/// - permutation check evaluations and proofs
/// - zero check evaluations and proofs
/// - public input consistency checks
///
/// TODO: this function is gigantic -- refactor it to smaller ones
fn prove(
pk: &Self::ProvingKey,
pub_input: &[E::Fr],
witnesses: &[WitnessColumn<E::Fr>],
transcript: &mut Self::Transcript,
) -> Result<Self::Proof, HyperPlonkErrors> {
let start = start_timer!(|| "hyperplonk proving");
let mut transcript = IOPTranscript::<E::Fr>::new(b"hyperplonk");
// witness assignment of length 2^n
let num_vars = pk.params.nv;
@ -315,7 +303,7 @@ where
&witness_polys,
)?;
let zero_check_proof = <Self as ZeroCheck<E::Fr>>::prove(&fx, transcript)?;
let zero_check_proof = <Self as ZeroCheck<E::Fr>>::prove(&fx, &mut transcript)?;
end_timer!(step);
// =======================================================================
@ -327,36 +315,112 @@ where
// 3.3. push a commitment of `prod(x)` to the transcript
// 3.4. `update_challenge` with the updated transcript
// 3.5. `prove` to generate the proof
// 3.6. open `prod(0,x)`, `prod(1, x)`, `prod(x, 0)`, `prod(x, 1)` at
// zero_check.point
// =======================================================================
let step = start_timer!(|| "Permutation check on w_i(x)");
// 3.1 `generate_challenge` from current transcript (generate beta, gamma)
let mut permutation_challenge = Self::generate_challenge(transcript)?;
let mut permutation_challenge = Self::generate_challenge(&mut transcript)?;
// 3.2. `compute_product` to build `prod(x)` etc. from f, g and s_perm
// s_perm is the second half of permutation oracle
let s_perm = pk.permutation_oracles.fix_variables(&[E::Fr::one()]);
// This function returns 3 MLEs:
// - prod(x)
// - numerator
// - denominator
// See function signature for details.
let prod_x_and_aux_info =
Self::compute_prod_evals(&permutation_challenge, &w_merged, &w_merged, &s_perm)?;
let prod_x_and_aux_info = Self::compute_prod_evals(
&permutation_challenge,
&w_merged,
&w_merged,
&pk.permutation_oracles,
)?;
let prod_x = Rc::new(prod_x_and_aux_info[0].clone());
// 3.3 push a commitment of `prod(x)` to the transcript
let prod_com = PCS::commit(&pk.pcs_param, &Rc::new(prod_x_and_aux_info[0].clone()))?;
let prod_com = PCS::commit(&pk.pcs_param, &prod_x)?;
// 3.4. `update_challenge` with the updated transcript
Self::update_challenge(&mut permutation_challenge, transcript, &prod_com)?;
Self::update_challenge(&mut permutation_challenge, &mut transcript, &prod_com)?;
// 3.5. `prove` to generate the proof
let perm_check_proof = <Self as PermutationCheck<E::Fr>>::prove(
&prod_x_and_aux_info,
&permutation_challenge,
transcript,
&mut transcript,
)?;
// 3.6 open prod(0,x), prod(1, x), prod(x, 0), prod(x, 1) at zero_check.point
// prod(0, x)
let tmp_point = [perm_check_proof.point.as_slice(), &[E::Fr::zero()]].concat();
let (prod_0_x_opening, prod_0_x_eval) = PCS::open(&pk.pcs_param, &prod_x, &tmp_point)?;
#[cfg(feature = "extensive_sanity_checks")]
{
// sanity check
let eval = prod_x.evaluate(&tmp_point).ok_or_else(|| {
HyperPlonkErrors::InvalidParameters(
"evaluation dimension does not match".to_string(),
)
})?;
if eval != prod_0_x_eval {
return Err(HyperPlonkErrors::InvalidProver(
"Evaluation is different from PCS opening".to_string(),
));
}
}
// prod(1, x)
let tmp_point = [perm_check_proof.point.as_slice(), &[E::Fr::one()]].concat();
let (prod_1_x_opening, prod_1_x_eval) = PCS::open(&pk.pcs_param, &prod_x, &tmp_point)?;
#[cfg(feature = "extensive_sanity_checks")]
{
// sanity check
let eval = prod_x.evaluate(&tmp_point).ok_or_else(|| {
HyperPlonkErrors::InvalidParameters(
"evaluation dimension does not match".to_string(),
)
})?;
if eval != prod_1_x_eval {
return Err(HyperPlonkErrors::InvalidProver(
"Evaluation is different from PCS opening".to_string(),
));
}
}
// prod(x, 0)
let tmp_point = [&[E::Fr::zero()], perm_check_proof.point.as_slice()].concat();
let (prod_x_0_opening, prod_x_0_eval) = PCS::open(&pk.pcs_param, &prod_x, &tmp_point)?;
#[cfg(feature = "extensive_sanity_checks")]
{
// sanity check
let eval = prod_x.evaluate(&tmp_point).ok_or_else(|| {
HyperPlonkErrors::InvalidParameters(
"evaluation dimension does not match".to_string(),
)
})?;
if eval != prod_x_0_eval {
return Err(HyperPlonkErrors::InvalidProver(
"Evaluation is different from PCS opening".to_string(),
));
}
}
// prod(x, 1)
let tmp_point = [&[E::Fr::one()], perm_check_proof.point.as_slice()].concat();
let (prod_x_1_opening, prod_x_1_eval) = PCS::open(&pk.pcs_param, &prod_x, &tmp_point)?;
#[cfg(feature = "extensive_sanity_checks")]
{
// sanity check
let eval = prod_x.evaluate(&tmp_point).ok_or_else(|| {
HyperPlonkErrors::InvalidParameters(
"evaluation dimension does not match".to_string(),
)
})?;
if eval != prod_x_1_eval {
return Err(HyperPlonkErrors::InvalidProver(
"Evaluation is different from PCS opening".to_string(),
));
}
}
end_timer!(step);
// =======================================================================
@ -386,14 +450,20 @@ where
&Rc::new(w_merged.clone()),
&perm_check_proof.point,
)?;
// sanity checks
if w_merged.evaluate(&perm_check_proof.point).ok_or_else(|| {
HyperPlonkErrors::InvalidParameters("evaluation dimension does not match".to_string())
})? != witness_perm_check_eval
#[cfg(feature = "extensive_sanity_checks")]
{
return Err(HyperPlonkErrors::InvalidProver(
"Evaluation is different from PCS opening".to_string(),
));
// sanity checks
let eval = w_merged.evaluate(&perm_check_proof.point).ok_or_else(|| {
HyperPlonkErrors::InvalidParameters(
"evaluation dimension does not match".to_string(),
)
})?;
if eval != witness_perm_check_eval {
return Err(HyperPlonkErrors::InvalidProver(
"Evaluation is different from PCS opening".to_string(),
));
}
}
// 4.2 open zero check proof
@ -403,12 +473,12 @@ where
let (zero_proof, zero_eval) =
PCS::open(&pk.pcs_param, &wire_poly, &zero_check_proof.point)?;
{
if wire_poly.evaluate(&zero_check_proof.point).ok_or_else(|| {
let eval = wire_poly.evaluate(&zero_check_proof.point).ok_or_else(|| {
HyperPlonkErrors::InvalidParameters(
"evaluation dimension does not match".to_string(),
)
})? != zero_eval
{
})?;
if eval != zero_eval {
return Err(HyperPlonkErrors::InvalidProver(
"Evaluation is different from PCS opening".to_string(),
));
@ -418,26 +488,32 @@ where
witness_zero_check_openings.push(zero_proof);
}
// Open permutation check proof
let (perm_oracle_opening, perm_oracle_eval) = PCS::open(
// Open permutation polynomial at perm_check_point
let (s_perm_opening, s_perm_eval) = PCS::open(
&pk.pcs_param,
&pk.permutation_oracles,
&[&[E::Fr::one()], perm_check_proof.point.as_slice()].concat(),
&perm_check_proof.point,
)?;
#[cfg(feature = "extensive_sanity_checks")]
{
// sanity check
if s_perm.evaluate(&perm_check_proof.point).ok_or_else(|| {
HyperPlonkErrors::InvalidParameters(
"evaluation dimension does not match".to_string(),
)
})? != perm_oracle_eval
{
let eval = pk
.permutation_oracles
.evaluate(&perm_check_proof.point)
.ok_or_else(|| {
HyperPlonkErrors::InvalidParameters(
"evaluation dimension does not match".to_string(),
)
})?;
if eval != s_perm_eval {
return Err(HyperPlonkErrors::InvalidProver(
"Evaluation is different from PCS opening".to_string(),
));
}
}
// Open selector polynomial at zero_check_point
let mut selector_oracle_openings = vec![];
let mut selector_oracle_evals = vec![];
@ -447,20 +523,19 @@ where
// during verification, use this eval against subclaim
let (zero_proof, zero_eval) =
PCS::open(&pk.pcs_param, selector_poly, &zero_check_proof.point)?;
#[cfg(feature = "extensive_sanity_checks")]
{
if selector_poly
let eval = selector_poly
.evaluate(&zero_check_proof.point)
.ok_or_else(|| {
HyperPlonkErrors::InvalidParameters(
"evaluation dimension does not match".to_string(),
)
})?
!= zero_eval
{
})?;
if eval != zero_eval {
return Err(HyperPlonkErrors::InvalidProver(
"Evaluation is different from PCS
opening"
.to_string(),
"Evaluation is different from PCS opening".to_string(),
));
}
}
@ -472,14 +547,16 @@ where
let r_pi = transcript.get_and_append_challenge_vectors(b"r_pi", ell)?;
let (pi_opening, pi_eval) = PCS::open(&pk.pcs_param, &pi_in_w0, &r_pi)?;
#[cfg(feature = "extensive_sanity_checks")]
{
// sanity check
if pi_poly.evaluate(&r_pi).ok_or_else(|| {
let eval = pi_poly.evaluate(&r_pi).ok_or_else(|| {
HyperPlonkErrors::InvalidParameters(
"evaluation dimension does not match".to_string(),
)
})? != pi_eval
{
})?;
if eval != pi_eval {
return Err(HyperPlonkErrors::InvalidProver(
"Evaluation is different from PCS opening".to_string(),
));
@ -490,39 +567,55 @@ where
end_timer!(start);
Ok(HyperPlonkProof {
// PCS components
// =======================================================================
// PCS components: common
// =======================================================================
witness_commits,
w_merged_com,
// =======================================================================
// PCS components: permutation check
// =======================================================================
// We do not validate prod(x), this is checked by subclaim
prod_commit: prod_com,
prod_evals: vec![prod_0_x_eval, prod_1_x_eval, prod_x_0_eval, prod_x_1_eval],
prod_openings: vec![
prod_0_x_opening,
prod_1_x_opening,
prod_x_0_opening,
prod_x_1_opening,
],
witness_perm_check_opening,
witness_zero_check_openings,
witness_perm_check_eval,
perm_oracle_opening: s_perm_opening,
perm_oracle_eval: s_perm_eval,
// =======================================================================
// PCS components: zero check
// =======================================================================
witness_zero_check_openings,
witness_zero_check_evals,
perm_oracle_opening,
perm_oracle_eval,
selector_oracle_openings,
selector_oracle_evals,
// =======================================================================
// PCS components: public inputs
// =======================================================================
pi_eval,
pi_opening,
// =======================================================================
// IOP components
// =======================================================================
zero_check_proof,
perm_check_proof,
})
}
/// Verify the HyperPlonk proof and generate the evaluation subclaims to be
/// checked later by the SNARK verifier.
/// Verify the HyperPlonk proof.
///
/// Inputs:
/// - `params`: instance parameter
/// - `vk`: verification key
/// - `pub_input`: online public input
/// - `proof`: HyperPlonk SNARK proof
/// - `transcript`: the transcript used for generating pseudorandom
/// challenges
/// Outputs:
/// - Return error if the verification fails, otherwise return the
/// evaluation subclaim
/// - Return a boolean on whether the verification is successful
///
/// 1. Verify zero_check_proof on
///
@ -546,10 +639,10 @@ where
vk: &Self::VerifyingKey,
pub_input: &[E::Fr],
proof: &Self::Proof,
transcript: &mut Self::Transcript,
) -> Result<Self::SubClaim, HyperPlonkErrors> {
) -> Result<bool, HyperPlonkErrors> {
let start = start_timer!(|| "hyperplonk verification");
let mut transcript = IOPTranscript::<E::Fr>::new(b"hyperplonk");
// witness assignment of length 2^n
let num_var = vk.params.nv;
let log_num_witness_polys = vk.params.log_n_wires;
@ -600,12 +693,28 @@ where
let zero_check_sub_claim = <Self as ZeroCheck<E::Fr>>::verify(
&proof.zero_check_proof,
&zero_check_aux_info,
transcript,
&mut transcript,
)?;
let zero_check_point = &zero_check_sub_claim.sum_check_sub_claim.point;
// check zero check subclaim
let f_eval = eval_f(
&vk.params.gate_func,
&proof.selector_oracle_evals,
&proof.witness_zero_check_evals,
)?;
if f_eval != zero_check_sub_claim.expected_evaluation {
return Err(HyperPlonkErrors::InvalidProof(
"zero check evaluation failed".to_string(),
));
}
end_timer!(step);
// =======================================================================
// 2. Verify perm_check_proof on `\{w_i(x)\}` and `permutation_oracles`
// =======================================================================
let step = start_timer!(|| "verify permutation check");
// Zero check and sum check have different AuxInfo because `w_merged` and
// `Prod(x)` have degree and num_vars
let perm_check_aux_info = VPAuxInfo::<E::Fr> {
@ -615,18 +724,64 @@ where
num_variables: merged_nv,
phantom: PhantomData::default(),
};
let mut challenge = <Self as PermutationCheck<E::Fr>>::generate_challenge(transcript)?;
let mut challenge = <Self as PermutationCheck<E::Fr>>::generate_challenge(&mut transcript)?;
<Self as PermutationCheck<E::Fr>>::update_challenge(
&mut challenge,
transcript,
&mut transcript,
&proof.prod_commit,
)?;
let perm_check_sub_claim = <Self as PermutationCheck<E::Fr>>::verify(
&proof.perm_check_proof,
&perm_check_aux_info,
transcript,
&mut transcript,
)?;
let perm_check_point = &perm_check_sub_claim
.zero_check_sub_claim
.sum_check_sub_claim
.point;
// check perm check subclaim:
// proof.witness_perm_check_eval ?= perm_check_sub_claim.expected_eval
//
// Q(x) := prod(1,x) - prod(x, 0) * prod(x, 1)
// + alpha * (
// (g(x) + beta * s_perm(x) + gamma) * prod(0, x)
// - (f(x) + beta * s_id(x) + gamma))
// where
// - Q(x) is perm_check_sub_claim.zero_check.exp_eval
// - prod(1, x) ... from prod(x) evaluated over (1, zero_point)
// - g(x), f(x) are both w_merged over (zero_point)
// - s_perm(x) and s_id(x) from vk_param.perm_oracle
// - alpha, beta, gamma from challenge
let alpha = challenge
.alpha
.ok_or_else(|| HyperPlonkErrors::InvalidVerifier("alpha is not set".to_string()))?;
let s_id = identity_permutation_mle::<E::Fr>(perm_check_point.len());
let s_id_eval = s_id.evaluate(perm_check_point).ok_or_else(|| {
HyperPlonkErrors::InvalidVerifier("unable to evaluate s_id(x)".to_string())
})?;
let q_x_rec = proof.prod_evals[1] - proof.prod_evals[2] * proof.prod_evals[3]
+ alpha
* ((proof.witness_perm_check_eval
+ challenge.beta * proof.perm_oracle_eval
+ challenge.gamma)
* proof.prod_evals[0]
- (proof.witness_perm_check_eval
+ challenge.beta * s_id_eval
+ challenge.gamma));
if q_x_rec
!= perm_check_sub_claim
.zero_check_sub_claim
.expected_evaluation
{
return Err(HyperPlonkErrors::InvalidVerifier(
"evaluation failed".to_string(),
));
}
end_timer!(step);
// =======================================================================
@ -634,12 +789,6 @@ where
// =======================================================================
let step = start_timer!(|| "verify commitments");
let perm_point = &perm_check_sub_claim
.zero_check_sub_claim
.sum_check_sub_claim
.point;
let zero_point = &zero_check_sub_claim.sum_check_sub_claim.point;
// =======================================================================
// 3.1 check permutation check evaluations
// =======================================================================
@ -647,7 +796,7 @@ where
if !PCS::verify(
&vk.pcs_param,
&proof.w_merged_com,
perm_point,
perm_check_point,
&proof.witness_perm_check_eval,
&proof.witness_perm_check_opening,
)? {
@ -656,11 +805,10 @@ where
));
}
// perm for permutation check
if !PCS::verify(
&vk.pcs_param,
&vk.perm_com,
&[&[E::Fr::one()], perm_point.as_slice()].concat(),
perm_check_point,
&proof.perm_oracle_eval,
&proof.perm_oracle_opening,
)? {
@ -669,6 +817,58 @@ where
));
}
// prod(x) for permutation check
// TODO: batch verification
// prod(0, x)
if !PCS::verify(
&vk.pcs_param,
&proof.prod_commit,
&[perm_check_point.as_slice(), &[E::Fr::zero()]].concat(),
&proof.prod_evals[0],
&proof.prod_openings[0],
)? {
return Err(HyperPlonkErrors::InvalidProof(
"pcs verification failed".to_string(),
));
}
// prod(1, x)
if !PCS::verify(
&vk.pcs_param,
&proof.prod_commit,
&[perm_check_point.as_slice(), &[E::Fr::one()]].concat(),
&proof.prod_evals[1],
&proof.prod_openings[1],
)? {
return Err(HyperPlonkErrors::InvalidProof(
"pcs verification failed".to_string(),
));
}
// prod(x, 0)
if !PCS::verify(
&vk.pcs_param,
&proof.prod_commit,
&[&[E::Fr::zero()], perm_check_point.as_slice()].concat(),
&proof.prod_evals[2],
&proof.prod_openings[2],
)? {
return Err(HyperPlonkErrors::InvalidProof(
"pcs verification failed".to_string(),
));
}
// prod(x, 1)
if !PCS::verify(
&vk.pcs_param,
&proof.prod_commit,
&[&[E::Fr::one()], perm_check_point.as_slice()].concat(),
&proof.prod_evals[3],
&proof.prod_openings[3],
)? {
return Err(HyperPlonkErrors::InvalidProof(
"pcs verification failed".to_string(),
));
}
// =======================================================================
// 3.2 check zero check evaluations
// =======================================================================
@ -680,7 +880,7 @@ where
.iter()
.zip(proof.witness_zero_check_evals.iter()),
) {
if !PCS::verify(&vk.pcs_param, commitment, zero_point, eval, opening)? {
if !PCS::verify(&vk.pcs_param, commitment, zero_check_point, eval, opening)? {
return Err(HyperPlonkErrors::InvalidProof(
"pcs verification failed".to_string(),
));
@ -697,7 +897,7 @@ where
if !PCS::verify(
&vk.pcs_param,
&vk.selector_com[0],
perm_point,
perm_check_point,
eval,
opening,
)? {
@ -707,17 +907,6 @@ where
}
}
// let f_eval = eval_f(
// &vk.params.gate_func,
// &proof.selector_oracle_evals,
// &proof.witness_zero_check_evals,
// )?;
// if f_eval != zero_check_sub_claim.sum_check_sub_claim.expected_evaluation {
// return Err(HyperPlonkErrors::InvalidProof(
// "zero check evaluation failed".to_string(),
// ));
// }
// =======================================================================
// 3.3 public input consistency checks
// =======================================================================
@ -740,12 +929,7 @@ where
end_timer!(step);
end_timer!(start);
// todo: verify the subclaim within snark
Ok(HyperPlonkSubClaim {
zero_check_sub_claim,
perm_check_sub_claim,
pub_input_sub_claim: (vec![], E::Fr::default()), // FIXME
})
Ok(true)
}
}
@ -756,8 +940,7 @@ mod tests {
use ark_bls12_381::Bls12_381;
use ark_std::test_rng;
use pcs::prelude::KZGMultilinearPCS;
use poly_iop::{identity_permutation_mle, random_permutation_mle};
use transcript::IOPTranscript;
use poly_iop::random_permutation_mle;
#[test]
fn test_hyperplonk_e2e() -> Result<(), HyperPlonkErrors> {
@ -800,8 +983,6 @@ mod tests {
let merged_nv = nv + log_n_wires;
let s_perm = random_permutation_mle(merged_nv, &mut rng);
let s_id = identity_permutation_mle(merged_nv);
let perm: Vec<E::Fr> = [s_id.evaluations, s_perm.evaluations].concat();
let q1 = SelectorColumn(vec![E::Fr::one(), E::Fr::one(), E::Fr::one(), E::Fr::one()]);
// w1 := [0, 1, 2, 3]
@ -825,25 +1006,19 @@ mod tests {
let (pk, vk) = <PolyIOP<E::Fr> as HyperPlonkSNARK<E, KZGMultilinearPCS<E>>>::preprocess(
&params,
&pcs_srs,
&perm,
&s_perm.evaluations,
&[q1],
)?;
// generate a proof and verify
let mut transcript = IOPTranscript::<E::Fr>::new(b"test hyperplonk");
let proof = <PolyIOP<E::Fr> as HyperPlonkSNARK<E, KZGMultilinearPCS<E>>>::prove(
&pk,
&pi.0,
&[w1, w2],
&mut transcript,
)?;
let mut transcript = IOPTranscript::<E::Fr>::new(b"test hyperplonk");
let _sub_claim = <PolyIOP<E::Fr> as HyperPlonkSNARK<E, KZGMultilinearPCS<E>>>::verify(
&vk,
&pi.0,
&proof,
&mut transcript,
&vk, &pi.0, &proof,
)?;
Ok(())

+ 21
- 6
hyperplonk/src/structs.rs

@ -34,35 +34,50 @@ pub struct HyperPlonkProof<
PC: PermutationCheck<E::Fr>,
> {
// =======================================================================
// PCS components
// PCS components: common
// =======================================================================
/// PCS commit for witnesses
// TODO: replace me with a batch commitment
pub witness_commits: Vec<PCS::Commitment>,
pub w_merged_com: PCS::Commitment,
// =======================================================================
// PCS components: permutation check
// =======================================================================
/// PCS commit for prod(x)
// TODO: replace me with a batch commitment
pub prod_commit: PCS::Commitment,
/// prod(x)'s evaluations
/// sequence: prod(0,x), prod(1, x), prod(x, 0), prod(x, 1)
pub prod_evals: Vec<E::Fr>,
/// prod(x)'s openings
/// sequence: prod(0,x), prod(1, x), prod(x, 0), prod(x, 1)
pub prod_openings: Vec<PCS::Proof>,
/// PCS openings for witness on permutation check point
// TODO: replace me with a batch opening
pub witness_perm_check_opening: PCS::Proof,
/// PCS openings for witness on zero check point
// TODO: replace me with a batch opening
pub witness_zero_check_openings: Vec<PCS::Proof>,
/// Evaluates of witnesses on permutation check point
pub witness_perm_check_eval: E::Fr,
/// Evaluates of witnesses on zero check point
pub witness_zero_check_evals: Vec<E::Fr>,
/// PCS openings for selectors on permutation check point
// TODO: replace me with a batch opening
pub perm_oracle_opening: PCS::Proof,
/// Evaluates of selectors on permutation check point
pub perm_oracle_eval: E::Fr,
// =======================================================================
// PCS components: zero check
// =======================================================================
/// PCS openings for witness on zero check point
// TODO: replace me with a batch opening
pub witness_zero_check_openings: Vec<PCS::Proof>,
/// Evaluates of witnesses on zero check point
pub witness_zero_check_evals: Vec<E::Fr>,
/// PCS openings for selectors on zero check point
// TODO: replace me with a batch opening
pub selector_oracle_openings: Vec<PCS::Proof>,
/// Evaluates of selectors on zero check point
pub selector_oracle_evals: Vec<E::Fr>,
// =======================================================================
// PCS components: public inputs
// =======================================================================
/// Evaluates of public inputs on r_pi from transcript
pub pi_eval: E::Fr,
/// Opening of public inputs on r_pi from transcript

+ 3
- 4
hyperplonk/src/utils.rs

@ -74,10 +74,9 @@ pub(crate) fn build_f(
F::from(*coeff as u64)
};
let mut mle_list = vec![];
match *selector {
Some(s) => mle_list.push(selector_mles[s].clone()),
None => (),
};
if let Some(s) = *selector {
mle_list.push(selector_mles[s].clone())
}
for &witness in witnesses.iter() {
mle_list.push(witness_mles[witness].clone())
}

+ 1
- 1
pcs/src/multilinear_kzg/batching.rs

@ -242,7 +242,7 @@ pub(super) fn batch_verify_internal(
uni_verifier_param,
&batch_proof.q_x_commit,
&domain.element(i),
&value,
value,
&batch_proof.q_x_opens[i],
)? {
#[cfg(debug_assertion)]

+ 3
- 3
poly-iop/src/perm_check/mod.rs

@ -160,9 +160,9 @@ pub struct PermutationCheckSubClaim> {
#[derive(Debug, Clone)]
pub struct PermutationChallenge<F: PrimeField> {
alpha: Option<F>,
beta: F,
gamma: F,
pub alpha: Option<F>,
pub beta: F,
pub gamma: F,
}
/// A PermutationCheck is derived from ZeroCheck.

+ 2
- 3
poly-iop/src/sum_check/mod.rs

@ -173,9 +173,8 @@ impl SumCheck for PolyIOP {
challenge = Some(transcript.get_and_append_challenge(b"Internal round")?);
}
// pushing the last challenge point to the state
match challenge {
Some(p) => prover_state.challenges.push(p),
None => (),
if let Some(p) = challenge {
prover_state.challenges.push(p)
};
end_timer!(start);

+ 0
- 6
poly-iop/src/sum_check/verifier.rs

@ -105,12 +105,6 @@ impl SumCheckVerifier for IOPVerifierState {
));
}
println!(
"eval len {} max degree {}",
self.polynomials_received[0].len(),
self.max_degree + 1
);
// the deferred check during the interactive phase:
// 2. set `expected` to P(r)`
#[cfg(feature = "parallel")]

+ 13
- 0
poly-iop/src/zero_check/mod.rs

@ -1,7 +1,9 @@
//! Main module for the ZeroCheck protocol.
use crate::{errors::PolyIOPErrors, sum_check::SumCheck, PolyIOP};
use arithmetic::build_eq_x_r;
use ark_ff::PrimeField;
use ark_poly::MultilinearExtension;
use ark_std::{end_timer, start_timer};
use transcript::IOPTranscript;
@ -12,6 +14,8 @@ use transcript::IOPTranscript;
pub struct ZeroCheckSubClaim<F: PrimeField, SC: SumCheck<F>> {
// the SubClaim from the SumCheck
pub sum_check_sub_claim: SC::SumCheckSubClaim,
/// the expected evaluation
pub expected_evaluation: F,
// the initial challenge r which is used to build eq(x, r)
pub init_challenge: Vec<F>,
}
@ -119,9 +123,18 @@ impl ZeroCheck for PolyIOP {
let subclaim =
<Self as SumCheck<F>>::verify(F::zero(), proof, &hat_fx_aux_info, transcript)?;
// expected_eval = sumcheck.expect_eval/eq(x, r)
// where x = sum_check_sub_claim.point
let eq_x_r = build_eq_x_r(&r)?;
let expected_evaluation = subclaim.expected_evaluation
/ eq_x_r.evaluate(&subclaim.point).ok_or_else(|| {
PolyIOPErrors::InvalidParameters("evaluation dimension does not match".to_string())
})?;
end_timer!(start);
Ok(ZeroCheckSubClaim {
sum_check_sub_claim: subclaim,
expected_evaluation,
init_challenge: r,
})
}

Loading…
Cancel
Save