mirror of
https://github.com/arnaucube/hyperplonk.git
synced 2026-01-11 16:41:28 +01:00
49 verify validity of subclaims in plonk verification (#51)
This commit is contained in:
@@ -25,8 +25,11 @@ ark-bls12-381 = { version = "0.3.0", default-features = false, features = [ "cur
|
|||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "parallel", "print-trace" ]
|
# default = [ "parallel", "print-trace", "extensive_sanity_checks" ]
|
||||||
# default = [ "parallel" ]
|
default = [ "parallel", "extensive_sanity_checks" ]
|
||||||
|
|
||||||
|
# extensive sanity checks that are useful for debugging
|
||||||
|
extensive_sanity_checks = [ ]
|
||||||
parallel = [
|
parallel = [
|
||||||
"ark-std/parallel",
|
"ark-std/parallel",
|
||||||
"ark-ff/parallel",
|
"ark-ff/parallel",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
//! Main module for the HyperPlonk PolyIOP.
|
//! Main module for the HyperPlonk PolyIOP.
|
||||||
|
|
||||||
|
use crate::utils::eval_f;
|
||||||
use arithmetic::VPAuxInfo;
|
use arithmetic::VPAuxInfo;
|
||||||
use ark_ec::PairingEngine;
|
use ark_ec::PairingEngine;
|
||||||
use ark_poly::{DenseMultilinearExtension, MultilinearExtension};
|
use ark_poly::{DenseMultilinearExtension, MultilinearExtension};
|
||||||
@@ -7,15 +8,14 @@ use ark_std::{end_timer, log2, start_timer, One, Zero};
|
|||||||
use errors::HyperPlonkErrors;
|
use errors::HyperPlonkErrors;
|
||||||
use pcs::prelude::{compute_qx_degree, merge_polynomials, PCSErrors, PolynomialCommitmentScheme};
|
use pcs::prelude::{compute_qx_degree, merge_polynomials, PCSErrors, PolynomialCommitmentScheme};
|
||||||
use poly_iop::{
|
use poly_iop::{
|
||||||
|
identity_permutation_mle,
|
||||||
prelude::{PermutationCheck, SumCheck, ZeroCheck},
|
prelude::{PermutationCheck, SumCheck, ZeroCheck},
|
||||||
PolyIOP,
|
PolyIOP,
|
||||||
};
|
};
|
||||||
use selectors::SelectorColumn;
|
use selectors::SelectorColumn;
|
||||||
use std::{marker::PhantomData, rc::Rc};
|
use std::{marker::PhantomData, rc::Rc};
|
||||||
use structs::{
|
use structs::{HyperPlonkParams, HyperPlonkProof, HyperPlonkProvingKey, HyperPlonkVerifyingKey};
|
||||||
HyperPlonkParams, HyperPlonkProof, HyperPlonkProvingKey, HyperPlonkSubClaim,
|
use transcript::IOPTranscript;
|
||||||
HyperPlonkVerifyingKey,
|
|
||||||
};
|
|
||||||
use utils::build_f;
|
use utils::build_f;
|
||||||
use witness::WitnessColumn;
|
use witness::WitnessColumn;
|
||||||
|
|
||||||
@@ -37,7 +37,6 @@ where
|
|||||||
type ProvingKey;
|
type ProvingKey;
|
||||||
type VerifyingKey;
|
type VerifyingKey;
|
||||||
type Proof;
|
type Proof;
|
||||||
type SubClaim;
|
|
||||||
|
|
||||||
/// Generate the preprocessed polynomials output by the indexer.
|
/// Generate the preprocessed polynomials output by the indexer.
|
||||||
///
|
///
|
||||||
@@ -61,35 +60,27 @@ where
|
|||||||
/// - `pk`: circuit proving key
|
/// - `pk`: circuit proving key
|
||||||
/// - `pub_input`: online public input
|
/// - `pub_input`: online public input
|
||||||
/// - `witness`: witness assignment
|
/// - `witness`: witness assignment
|
||||||
/// - `transcript`: the transcript used for generating pseudorandom
|
|
||||||
/// challenges
|
|
||||||
/// Outputs:
|
/// Outputs:
|
||||||
/// - The HyperPlonk SNARK proof.
|
/// - The HyperPlonk SNARK proof.
|
||||||
fn prove(
|
fn prove(
|
||||||
pk: &Self::ProvingKey,
|
pk: &Self::ProvingKey,
|
||||||
pub_input: &[E::Fr],
|
pub_input: &[E::Fr],
|
||||||
witnesses: &[WitnessColumn<E::Fr>],
|
witnesses: &[WitnessColumn<E::Fr>],
|
||||||
transcript: &mut Self::Transcript,
|
|
||||||
) -> Result<Self::Proof, HyperPlonkErrors>;
|
) -> Result<Self::Proof, HyperPlonkErrors>;
|
||||||
|
|
||||||
/// Verify the HyperPlonk proof and generate the evaluation subclaims to be
|
/// Verify the HyperPlonk proof.
|
||||||
/// checked later by the SNARK verifier.
|
|
||||||
///
|
///
|
||||||
/// Inputs:
|
/// Inputs:
|
||||||
/// - `params`: instance parameter
|
/// - `params`: instance parameter
|
||||||
/// - `pub_input`: online public input
|
/// - `pub_input`: online public input
|
||||||
/// - `proof`: HyperPlonk SNARK proof
|
/// - `proof`: HyperPlonk SNARK proof challenges
|
||||||
/// - `transcript`: the transcript used for generating pseudorandom
|
|
||||||
/// challenges
|
|
||||||
/// Outputs:
|
/// Outputs:
|
||||||
/// - Return error if the verification fails, otherwise return the
|
/// - Return a boolean on whether the verification is successful
|
||||||
/// evaluation subclaim
|
|
||||||
fn verify(
|
fn verify(
|
||||||
params: &Self::VerifyingKey,
|
params: &Self::VerifyingKey,
|
||||||
pub_input: &[E::Fr],
|
pub_input: &[E::Fr],
|
||||||
proof: &Self::Proof,
|
proof: &Self::Proof,
|
||||||
transcript: &mut Self::Transcript,
|
) -> Result<bool, HyperPlonkErrors>;
|
||||||
) -> Result<Self::SubClaim, HyperPlonkErrors>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, PCS> HyperPlonkSNARK<E, PCS> for PolyIOP<E::Fr>
|
impl<E, PCS> HyperPlonkSNARK<E, PCS> for PolyIOP<E::Fr>
|
||||||
@@ -109,7 +100,6 @@ where
|
|||||||
type ProvingKey = HyperPlonkProvingKey<E, PCS>;
|
type ProvingKey = HyperPlonkProvingKey<E, PCS>;
|
||||||
type VerifyingKey = HyperPlonkVerifyingKey<E, PCS>;
|
type VerifyingKey = HyperPlonkVerifyingKey<E, PCS>;
|
||||||
type Proof = HyperPlonkProof<E, PCS, Self, Self>;
|
type Proof = HyperPlonkProof<E, PCS, Self, Self>;
|
||||||
type SubClaim = HyperPlonkSubClaim<E::Fr, Self, Self>;
|
|
||||||
|
|
||||||
/// Generate the preprocessed polynomials output by the indexer.
|
/// Generate the preprocessed polynomials output by the indexer.
|
||||||
///
|
///
|
||||||
@@ -143,11 +133,9 @@ where
|
|||||||
|
|
||||||
// build permutation oracles
|
// build permutation oracles
|
||||||
let permutation_oracles = Rc::new(DenseMultilinearExtension::from_evaluations_slice(
|
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,
|
||||||
merged_nv + 1,
|
|
||||||
permutation,
|
permutation,
|
||||||
));
|
));
|
||||||
|
|
||||||
let perm_com = PCS::commit(&pcs_prover_param, &permutation_oracles)?;
|
let perm_com = PCS::commit(&pcs_prover_param, &permutation_oracles)?;
|
||||||
|
|
||||||
// build selector oracles and commit to it
|
// build selector oracles and commit to it
|
||||||
@@ -183,8 +171,6 @@ where
|
|||||||
/// - `pk`: circuit proving key
|
/// - `pk`: circuit proving key
|
||||||
/// - `pub_input`: online public input of length 2^\ell
|
/// - `pub_input`: online public input of length 2^\ell
|
||||||
/// - `witness`: witness assignment of length 2^n
|
/// - `witness`: witness assignment of length 2^n
|
||||||
/// - `transcript`: the transcript used for generating pseudorandom
|
|
||||||
/// challenges
|
|
||||||
/// Outputs:
|
/// Outputs:
|
||||||
/// - The HyperPlonk SNARK proof.
|
/// - The HyperPlonk SNARK proof.
|
||||||
///
|
///
|
||||||
@@ -211,13 +197,15 @@ where
|
|||||||
/// - permutation check evaluations and proofs
|
/// - permutation check evaluations and proofs
|
||||||
/// - zero check evaluations and proofs
|
/// - zero check evaluations and proofs
|
||||||
/// - public input consistency checks
|
/// - public input consistency checks
|
||||||
|
///
|
||||||
|
/// TODO: this function is gigantic -- refactor it to smaller ones
|
||||||
fn prove(
|
fn prove(
|
||||||
pk: &Self::ProvingKey,
|
pk: &Self::ProvingKey,
|
||||||
pub_input: &[E::Fr],
|
pub_input: &[E::Fr],
|
||||||
witnesses: &[WitnessColumn<E::Fr>],
|
witnesses: &[WitnessColumn<E::Fr>],
|
||||||
transcript: &mut Self::Transcript,
|
|
||||||
) -> Result<Self::Proof, HyperPlonkErrors> {
|
) -> Result<Self::Proof, HyperPlonkErrors> {
|
||||||
let start = start_timer!(|| "hyperplonk proving");
|
let start = start_timer!(|| "hyperplonk proving");
|
||||||
|
let mut transcript = IOPTranscript::<E::Fr>::new(b"hyperplonk");
|
||||||
|
|
||||||
// witness assignment of length 2^n
|
// witness assignment of length 2^n
|
||||||
let num_vars = pk.params.nv;
|
let num_vars = pk.params.nv;
|
||||||
@@ -315,7 +303,7 @@ where
|
|||||||
&witness_polys,
|
&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);
|
end_timer!(step);
|
||||||
|
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
@@ -327,36 +315,112 @@ where
|
|||||||
// 3.3. push a commitment of `prod(x)` to the transcript
|
// 3.3. push a commitment of `prod(x)` to the transcript
|
||||||
// 3.4. `update_challenge` with the updated transcript
|
// 3.4. `update_challenge` with the updated transcript
|
||||||
// 3.5. `prove` to generate the proof
|
// 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)");
|
let step = start_timer!(|| "Permutation check on w_i(x)");
|
||||||
|
|
||||||
// 3.1 `generate_challenge` from current transcript (generate beta, gamma)
|
// 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
|
// 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:
|
// This function returns 3 MLEs:
|
||||||
// - prod(x)
|
// - prod(x)
|
||||||
// - numerator
|
// - numerator
|
||||||
// - denominator
|
// - denominator
|
||||||
// See function signature for details.
|
// See function signature for details.
|
||||||
let prod_x_and_aux_info =
|
let prod_x_and_aux_info = Self::compute_prod_evals(
|
||||||
Self::compute_prod_evals(&permutation_challenge, &w_merged, &w_merged, &s_perm)?;
|
&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
|
// 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
|
// 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
|
// 3.5. `prove` to generate the proof
|
||||||
let perm_check_proof = <Self as PermutationCheck<E::Fr>>::prove(
|
let perm_check_proof = <Self as PermutationCheck<E::Fr>>::prove(
|
||||||
&prod_x_and_aux_info,
|
&prod_x_and_aux_info,
|
||||||
&permutation_challenge,
|
&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);
|
end_timer!(step);
|
||||||
|
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
@@ -386,14 +450,20 @@ where
|
|||||||
&Rc::new(w_merged.clone()),
|
&Rc::new(w_merged.clone()),
|
||||||
&perm_check_proof.point,
|
&perm_check_proof.point,
|
||||||
)?;
|
)?;
|
||||||
// sanity checks
|
|
||||||
if w_merged.evaluate(&perm_check_proof.point).ok_or_else(|| {
|
#[cfg(feature = "extensive_sanity_checks")]
|
||||||
HyperPlonkErrors::InvalidParameters("evaluation dimension does not match".to_string())
|
|
||||||
})? != witness_perm_check_eval
|
|
||||||
{
|
{
|
||||||
return Err(HyperPlonkErrors::InvalidProver(
|
// sanity checks
|
||||||
"Evaluation is different from PCS opening".to_string(),
|
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
|
// 4.2 open zero check proof
|
||||||
@@ -403,12 +473,12 @@ where
|
|||||||
let (zero_proof, zero_eval) =
|
let (zero_proof, zero_eval) =
|
||||||
PCS::open(&pk.pcs_param, &wire_poly, &zero_check_proof.point)?;
|
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(
|
HyperPlonkErrors::InvalidParameters(
|
||||||
"evaluation dimension does not match".to_string(),
|
"evaluation dimension does not match".to_string(),
|
||||||
)
|
)
|
||||||
})? != zero_eval
|
})?;
|
||||||
{
|
if eval != zero_eval {
|
||||||
return Err(HyperPlonkErrors::InvalidProver(
|
return Err(HyperPlonkErrors::InvalidProver(
|
||||||
"Evaluation is different from PCS opening".to_string(),
|
"Evaluation is different from PCS opening".to_string(),
|
||||||
));
|
));
|
||||||
@@ -418,26 +488,32 @@ where
|
|||||||
witness_zero_check_openings.push(zero_proof);
|
witness_zero_check_openings.push(zero_proof);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open permutation check proof
|
// Open permutation polynomial at perm_check_point
|
||||||
let (perm_oracle_opening, perm_oracle_eval) = PCS::open(
|
let (s_perm_opening, s_perm_eval) = PCS::open(
|
||||||
&pk.pcs_param,
|
&pk.pcs_param,
|
||||||
&pk.permutation_oracles,
|
&pk.permutation_oracles,
|
||||||
&[&[E::Fr::one()], perm_check_proof.point.as_slice()].concat(),
|
&perm_check_proof.point,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "extensive_sanity_checks")]
|
||||||
{
|
{
|
||||||
// sanity check
|
// sanity check
|
||||||
if s_perm.evaluate(&perm_check_proof.point).ok_or_else(|| {
|
let eval = pk
|
||||||
HyperPlonkErrors::InvalidParameters(
|
.permutation_oracles
|
||||||
"evaluation dimension does not match".to_string(),
|
.evaluate(&perm_check_proof.point)
|
||||||
)
|
.ok_or_else(|| {
|
||||||
})? != perm_oracle_eval
|
HyperPlonkErrors::InvalidParameters(
|
||||||
{
|
"evaluation dimension does not match".to_string(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
if eval != s_perm_eval {
|
||||||
return Err(HyperPlonkErrors::InvalidProver(
|
return Err(HyperPlonkErrors::InvalidProver(
|
||||||
"Evaluation is different from PCS opening".to_string(),
|
"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_openings = vec![];
|
||||||
let mut selector_oracle_evals = vec![];
|
let mut selector_oracle_evals = vec![];
|
||||||
|
|
||||||
@@ -447,20 +523,19 @@ where
|
|||||||
// during verification, use this eval against subclaim
|
// during verification, use this eval against subclaim
|
||||||
let (zero_proof, zero_eval) =
|
let (zero_proof, zero_eval) =
|
||||||
PCS::open(&pk.pcs_param, selector_poly, &zero_check_proof.point)?;
|
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)
|
.evaluate(&zero_check_proof.point)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
HyperPlonkErrors::InvalidParameters(
|
HyperPlonkErrors::InvalidParameters(
|
||||||
"evaluation dimension does not match".to_string(),
|
"evaluation dimension does not match".to_string(),
|
||||||
)
|
)
|
||||||
})?
|
})?;
|
||||||
!= zero_eval
|
if eval != zero_eval {
|
||||||
{
|
|
||||||
return Err(HyperPlonkErrors::InvalidProver(
|
return Err(HyperPlonkErrors::InvalidProver(
|
||||||
"Evaluation is different from PCS
|
"Evaluation is different from PCS opening".to_string(),
|
||||||
opening"
|
|
||||||
.to_string(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -472,14 +547,16 @@ where
|
|||||||
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 (pi_opening, pi_eval) = PCS::open(&pk.pcs_param, &pi_in_w0, &r_pi)?;
|
let (pi_opening, pi_eval) = PCS::open(&pk.pcs_param, &pi_in_w0, &r_pi)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "extensive_sanity_checks")]
|
||||||
{
|
{
|
||||||
// sanity check
|
// sanity check
|
||||||
if pi_poly.evaluate(&r_pi).ok_or_else(|| {
|
let eval = pi_poly.evaluate(&r_pi).ok_or_else(|| {
|
||||||
HyperPlonkErrors::InvalidParameters(
|
HyperPlonkErrors::InvalidParameters(
|
||||||
"evaluation dimension does not match".to_string(),
|
"evaluation dimension does not match".to_string(),
|
||||||
)
|
)
|
||||||
})? != pi_eval
|
})?;
|
||||||
{
|
if eval != pi_eval {
|
||||||
return Err(HyperPlonkErrors::InvalidProver(
|
return Err(HyperPlonkErrors::InvalidProver(
|
||||||
"Evaluation is different from PCS opening".to_string(),
|
"Evaluation is different from PCS opening".to_string(),
|
||||||
));
|
));
|
||||||
@@ -490,39 +567,55 @@ where
|
|||||||
end_timer!(start);
|
end_timer!(start);
|
||||||
|
|
||||||
Ok(HyperPlonkProof {
|
Ok(HyperPlonkProof {
|
||||||
// PCS components
|
// =======================================================================
|
||||||
|
// PCS components: common
|
||||||
|
// =======================================================================
|
||||||
witness_commits,
|
witness_commits,
|
||||||
w_merged_com,
|
w_merged_com,
|
||||||
|
// =======================================================================
|
||||||
|
// PCS components: permutation check
|
||||||
|
// =======================================================================
|
||||||
// We do not validate prod(x), this is checked by subclaim
|
// We do not validate prod(x), this is checked by subclaim
|
||||||
prod_commit: prod_com,
|
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_perm_check_opening,
|
||||||
witness_zero_check_openings,
|
|
||||||
witness_perm_check_eval,
|
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,
|
witness_zero_check_evals,
|
||||||
perm_oracle_opening,
|
|
||||||
perm_oracle_eval,
|
|
||||||
selector_oracle_openings,
|
selector_oracle_openings,
|
||||||
selector_oracle_evals,
|
selector_oracle_evals,
|
||||||
|
// =======================================================================
|
||||||
|
// PCS components: public inputs
|
||||||
|
// =======================================================================
|
||||||
pi_eval,
|
pi_eval,
|
||||||
pi_opening,
|
pi_opening,
|
||||||
|
// =======================================================================
|
||||||
// IOP components
|
// IOP components
|
||||||
|
// =======================================================================
|
||||||
zero_check_proof,
|
zero_check_proof,
|
||||||
perm_check_proof,
|
perm_check_proof,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify the HyperPlonk proof and generate the evaluation subclaims to be
|
/// Verify the HyperPlonk proof.
|
||||||
/// checked later by the SNARK verifier.
|
|
||||||
///
|
///
|
||||||
/// Inputs:
|
/// Inputs:
|
||||||
/// - `params`: instance parameter
|
/// - `vk`: verification key
|
||||||
/// - `pub_input`: online public input
|
/// - `pub_input`: online public input
|
||||||
/// - `proof`: HyperPlonk SNARK proof
|
/// - `proof`: HyperPlonk SNARK proof
|
||||||
/// - `transcript`: the transcript used for generating pseudorandom
|
|
||||||
/// challenges
|
|
||||||
/// Outputs:
|
/// Outputs:
|
||||||
/// - Return error if the verification fails, otherwise return the
|
/// - Return a boolean on whether the verification is successful
|
||||||
/// evaluation subclaim
|
|
||||||
///
|
///
|
||||||
/// 1. Verify zero_check_proof on
|
/// 1. Verify zero_check_proof on
|
||||||
///
|
///
|
||||||
@@ -546,10 +639,10 @@ where
|
|||||||
vk: &Self::VerifyingKey,
|
vk: &Self::VerifyingKey,
|
||||||
pub_input: &[E::Fr],
|
pub_input: &[E::Fr],
|
||||||
proof: &Self::Proof,
|
proof: &Self::Proof,
|
||||||
transcript: &mut Self::Transcript,
|
) -> Result<bool, HyperPlonkErrors> {
|
||||||
) -> Result<Self::SubClaim, HyperPlonkErrors> {
|
|
||||||
let start = start_timer!(|| "hyperplonk verification");
|
let start = start_timer!(|| "hyperplonk verification");
|
||||||
|
|
||||||
|
let mut transcript = IOPTranscript::<E::Fr>::new(b"hyperplonk");
|
||||||
// witness assignment of length 2^n
|
// witness assignment of length 2^n
|
||||||
let num_var = vk.params.nv;
|
let num_var = vk.params.nv;
|
||||||
let log_num_witness_polys = vk.params.log_n_wires;
|
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(
|
let zero_check_sub_claim = <Self as ZeroCheck<E::Fr>>::verify(
|
||||||
&proof.zero_check_proof,
|
&proof.zero_check_proof,
|
||||||
&zero_check_aux_info,
|
&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);
|
end_timer!(step);
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
// 2. Verify perm_check_proof on `\{w_i(x)\}` and `permutation_oracles`
|
// 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
|
// Zero check and sum check have different AuxInfo because `w_merged` and
|
||||||
// `Prod(x)` have degree and num_vars
|
// `Prod(x)` have degree and num_vars
|
||||||
let perm_check_aux_info = VPAuxInfo::<E::Fr> {
|
let perm_check_aux_info = VPAuxInfo::<E::Fr> {
|
||||||
@@ -615,18 +724,64 @@ where
|
|||||||
num_variables: merged_nv,
|
num_variables: merged_nv,
|
||||||
phantom: PhantomData::default(),
|
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(
|
<Self as PermutationCheck<E::Fr>>::update_challenge(
|
||||||
&mut challenge,
|
&mut challenge,
|
||||||
transcript,
|
&mut transcript,
|
||||||
&proof.prod_commit,
|
&proof.prod_commit,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let perm_check_sub_claim = <Self as PermutationCheck<E::Fr>>::verify(
|
let perm_check_sub_claim = <Self as PermutationCheck<E::Fr>>::verify(
|
||||||
&proof.perm_check_proof,
|
&proof.perm_check_proof,
|
||||||
&perm_check_aux_info,
|
&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);
|
end_timer!(step);
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
@@ -634,12 +789,6 @@ where
|
|||||||
// =======================================================================
|
// =======================================================================
|
||||||
let step = start_timer!(|| "verify commitments");
|
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
|
// 3.1 check permutation check evaluations
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
@@ -647,7 +796,7 @@ where
|
|||||||
if !PCS::verify(
|
if !PCS::verify(
|
||||||
&vk.pcs_param,
|
&vk.pcs_param,
|
||||||
&proof.w_merged_com,
|
&proof.w_merged_com,
|
||||||
perm_point,
|
perm_check_point,
|
||||||
&proof.witness_perm_check_eval,
|
&proof.witness_perm_check_eval,
|
||||||
&proof.witness_perm_check_opening,
|
&proof.witness_perm_check_opening,
|
||||||
)? {
|
)? {
|
||||||
@@ -656,11 +805,10 @@ where
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// perm for permutation check
|
|
||||||
if !PCS::verify(
|
if !PCS::verify(
|
||||||
&vk.pcs_param,
|
&vk.pcs_param,
|
||||||
&vk.perm_com,
|
&vk.perm_com,
|
||||||
&[&[E::Fr::one()], perm_point.as_slice()].concat(),
|
perm_check_point,
|
||||||
&proof.perm_oracle_eval,
|
&proof.perm_oracle_eval,
|
||||||
&proof.perm_oracle_opening,
|
&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
|
// 3.2 check zero check evaluations
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
@@ -680,7 +880,7 @@ where
|
|||||||
.iter()
|
.iter()
|
||||||
.zip(proof.witness_zero_check_evals.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(
|
return Err(HyperPlonkErrors::InvalidProof(
|
||||||
"pcs verification failed".to_string(),
|
"pcs verification failed".to_string(),
|
||||||
));
|
));
|
||||||
@@ -697,7 +897,7 @@ where
|
|||||||
if !PCS::verify(
|
if !PCS::verify(
|
||||||
&vk.pcs_param,
|
&vk.pcs_param,
|
||||||
&vk.selector_com[0],
|
&vk.selector_com[0],
|
||||||
perm_point,
|
perm_check_point,
|
||||||
eval,
|
eval,
|
||||||
opening,
|
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
|
// 3.3 public input consistency checks
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
@@ -740,12 +929,7 @@ where
|
|||||||
|
|
||||||
end_timer!(step);
|
end_timer!(step);
|
||||||
end_timer!(start);
|
end_timer!(start);
|
||||||
// todo: verify the subclaim within snark
|
Ok(true)
|
||||||
Ok(HyperPlonkSubClaim {
|
|
||||||
zero_check_sub_claim,
|
|
||||||
perm_check_sub_claim,
|
|
||||||
pub_input_sub_claim: (vec![], E::Fr::default()), // FIXME
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -756,8 +940,7 @@ mod tests {
|
|||||||
use ark_bls12_381::Bls12_381;
|
use ark_bls12_381::Bls12_381;
|
||||||
use ark_std::test_rng;
|
use ark_std::test_rng;
|
||||||
use pcs::prelude::KZGMultilinearPCS;
|
use pcs::prelude::KZGMultilinearPCS;
|
||||||
use poly_iop::{identity_permutation_mle, random_permutation_mle};
|
use poly_iop::random_permutation_mle;
|
||||||
use transcript::IOPTranscript;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hyperplonk_e2e() -> Result<(), HyperPlonkErrors> {
|
fn test_hyperplonk_e2e() -> Result<(), HyperPlonkErrors> {
|
||||||
@@ -800,8 +983,6 @@ mod tests {
|
|||||||
let merged_nv = nv + log_n_wires;
|
let merged_nv = nv + log_n_wires;
|
||||||
|
|
||||||
let s_perm = random_permutation_mle(merged_nv, &mut rng);
|
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()]);
|
let q1 = SelectorColumn(vec![E::Fr::one(), E::Fr::one(), E::Fr::one(), E::Fr::one()]);
|
||||||
// w1 := [0, 1, 2, 3]
|
// w1 := [0, 1, 2, 3]
|
||||||
@@ -825,25 +1006,19 @@ mod tests {
|
|||||||
let (pk, vk) = <PolyIOP<E::Fr> as HyperPlonkSNARK<E, KZGMultilinearPCS<E>>>::preprocess(
|
let (pk, vk) = <PolyIOP<E::Fr> as HyperPlonkSNARK<E, KZGMultilinearPCS<E>>>::preprocess(
|
||||||
¶ms,
|
¶ms,
|
||||||
&pcs_srs,
|
&pcs_srs,
|
||||||
&perm,
|
&s_perm.evaluations,
|
||||||
&[q1],
|
&[q1],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// generate a proof and verify
|
// 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(
|
let proof = <PolyIOP<E::Fr> as HyperPlonkSNARK<E, KZGMultilinearPCS<E>>>::prove(
|
||||||
&pk,
|
&pk,
|
||||||
&pi.0,
|
&pi.0,
|
||||||
&[w1, w2],
|
&[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(
|
let _sub_claim = <PolyIOP<E::Fr> as HyperPlonkSNARK<E, KZGMultilinearPCS<E>>>::verify(
|
||||||
&vk,
|
&vk, &pi.0, &proof,
|
||||||
&pi.0,
|
|
||||||
&proof,
|
|
||||||
&mut transcript,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -34,35 +34,50 @@ pub struct HyperPlonkProof<
|
|||||||
PC: PermutationCheck<E::Fr>,
|
PC: PermutationCheck<E::Fr>,
|
||||||
> {
|
> {
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
// PCS components
|
// PCS components: common
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
/// PCS commit for witnesses
|
/// PCS commit for witnesses
|
||||||
// TODO: replace me with a batch commitment
|
// TODO: replace me with a batch commitment
|
||||||
pub witness_commits: Vec<PCS::Commitment>,
|
pub witness_commits: Vec<PCS::Commitment>,
|
||||||
pub w_merged_com: PCS::Commitment,
|
pub w_merged_com: PCS::Commitment,
|
||||||
|
// =======================================================================
|
||||||
|
// PCS components: permutation check
|
||||||
|
// =======================================================================
|
||||||
/// PCS commit for prod(x)
|
/// PCS commit for prod(x)
|
||||||
// TODO: replace me with a batch commitment
|
// TODO: replace me with a batch commitment
|
||||||
pub prod_commit: PCS::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
|
/// PCS openings for witness on permutation check point
|
||||||
// TODO: replace me with a batch opening
|
// TODO: replace me with a batch opening
|
||||||
pub witness_perm_check_opening: PCS::Proof,
|
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
|
/// Evaluates of witnesses on permutation check point
|
||||||
pub witness_perm_check_eval: E::Fr,
|
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
|
/// PCS openings for selectors on permutation check point
|
||||||
// TODO: replace me with a batch opening
|
// TODO: replace me with a batch opening
|
||||||
pub perm_oracle_opening: PCS::Proof,
|
pub perm_oracle_opening: PCS::Proof,
|
||||||
/// Evaluates of selectors on permutation check point
|
/// Evaluates of selectors on permutation check point
|
||||||
pub perm_oracle_eval: E::Fr,
|
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
|
/// PCS openings for selectors on zero check point
|
||||||
// TODO: replace me with a batch opening
|
// TODO: replace me with a batch opening
|
||||||
pub selector_oracle_openings: Vec<PCS::Proof>,
|
pub selector_oracle_openings: Vec<PCS::Proof>,
|
||||||
/// Evaluates of selectors on zero check point
|
/// Evaluates of selectors on zero check point
|
||||||
pub selector_oracle_evals: Vec<E::Fr>,
|
pub selector_oracle_evals: Vec<E::Fr>,
|
||||||
|
// =======================================================================
|
||||||
|
// PCS components: public inputs
|
||||||
|
// =======================================================================
|
||||||
/// Evaluates of public inputs on r_pi from transcript
|
/// Evaluates of public inputs on r_pi from transcript
|
||||||
pub pi_eval: E::Fr,
|
pub pi_eval: E::Fr,
|
||||||
/// Opening of public inputs on r_pi from transcript
|
/// Opening of public inputs on r_pi from transcript
|
||||||
|
|||||||
@@ -74,10 +74,9 @@ pub(crate) fn build_f<F: PrimeField>(
|
|||||||
F::from(*coeff as u64)
|
F::from(*coeff as u64)
|
||||||
};
|
};
|
||||||
let mut mle_list = vec![];
|
let mut mle_list = vec![];
|
||||||
match *selector {
|
if let Some(s) = *selector {
|
||||||
Some(s) => mle_list.push(selector_mles[s].clone()),
|
mle_list.push(selector_mles[s].clone())
|
||||||
None => (),
|
}
|
||||||
};
|
|
||||||
for &witness in witnesses.iter() {
|
for &witness in witnesses.iter() {
|
||||||
mle_list.push(witness_mles[witness].clone())
|
mle_list.push(witness_mles[witness].clone())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ pub(super) fn batch_verify_internal<E: PairingEngine>(
|
|||||||
uni_verifier_param,
|
uni_verifier_param,
|
||||||
&batch_proof.q_x_commit,
|
&batch_proof.q_x_commit,
|
||||||
&domain.element(i),
|
&domain.element(i),
|
||||||
&value,
|
value,
|
||||||
&batch_proof.q_x_opens[i],
|
&batch_proof.q_x_opens[i],
|
||||||
)? {
|
)? {
|
||||||
#[cfg(debug_assertion)]
|
#[cfg(debug_assertion)]
|
||||||
|
|||||||
@@ -160,9 +160,9 @@ pub struct PermutationCheckSubClaim<F: PrimeField, ZC: ZeroCheck<F>> {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PermutationChallenge<F: PrimeField> {
|
pub struct PermutationChallenge<F: PrimeField> {
|
||||||
alpha: Option<F>,
|
pub alpha: Option<F>,
|
||||||
beta: F,
|
pub beta: F,
|
||||||
gamma: F,
|
pub gamma: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A PermutationCheck is derived from ZeroCheck.
|
/// A PermutationCheck is derived from ZeroCheck.
|
||||||
|
|||||||
@@ -173,9 +173,8 @@ impl<F: PrimeField> SumCheck<F> for PolyIOP<F> {
|
|||||||
challenge = Some(transcript.get_and_append_challenge(b"Internal round")?);
|
challenge = Some(transcript.get_and_append_challenge(b"Internal round")?);
|
||||||
}
|
}
|
||||||
// pushing the last challenge point to the state
|
// pushing the last challenge point to the state
|
||||||
match challenge {
|
if let Some(p) = challenge {
|
||||||
Some(p) => prover_state.challenges.push(p),
|
prover_state.challenges.push(p)
|
||||||
None => (),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
end_timer!(start);
|
end_timer!(start);
|
||||||
|
|||||||
@@ -105,12 +105,6 @@ impl<F: PrimeField> SumCheckVerifier<F> for IOPVerifierState<F> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(
|
|
||||||
"eval len {} max degree {}",
|
|
||||||
self.polynomials_received[0].len(),
|
|
||||||
self.max_degree + 1
|
|
||||||
);
|
|
||||||
|
|
||||||
// the deferred check during the interactive phase:
|
// the deferred check during the interactive phase:
|
||||||
// 2. set `expected` to P(r)`
|
// 2. set `expected` to P(r)`
|
||||||
#[cfg(feature = "parallel")]
|
#[cfg(feature = "parallel")]
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
//! Main module for the ZeroCheck protocol.
|
//! Main module for the ZeroCheck protocol.
|
||||||
|
|
||||||
use crate::{errors::PolyIOPErrors, sum_check::SumCheck, PolyIOP};
|
use crate::{errors::PolyIOPErrors, sum_check::SumCheck, PolyIOP};
|
||||||
|
use arithmetic::build_eq_x_r;
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
|
use ark_poly::MultilinearExtension;
|
||||||
use ark_std::{end_timer, start_timer};
|
use ark_std::{end_timer, start_timer};
|
||||||
use transcript::IOPTranscript;
|
use transcript::IOPTranscript;
|
||||||
|
|
||||||
@@ -12,6 +14,8 @@ use transcript::IOPTranscript;
|
|||||||
pub struct ZeroCheckSubClaim<F: PrimeField, SC: SumCheck<F>> {
|
pub struct ZeroCheckSubClaim<F: PrimeField, SC: SumCheck<F>> {
|
||||||
// the SubClaim from the SumCheck
|
// the SubClaim from the SumCheck
|
||||||
pub sum_check_sub_claim: SC::SumCheckSubClaim,
|
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)
|
// the initial challenge r which is used to build eq(x, r)
|
||||||
pub init_challenge: Vec<F>,
|
pub init_challenge: Vec<F>,
|
||||||
}
|
}
|
||||||
@@ -119,9 +123,18 @@ impl<F: PrimeField> ZeroCheck<F> for PolyIOP<F> {
|
|||||||
let subclaim =
|
let subclaim =
|
||||||
<Self as SumCheck<F>>::verify(F::zero(), proof, &hat_fx_aux_info, transcript)?;
|
<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);
|
end_timer!(start);
|
||||||
Ok(ZeroCheckSubClaim {
|
Ok(ZeroCheckSubClaim {
|
||||||
sum_check_sub_claim: subclaim,
|
sum_check_sub_claim: subclaim,
|
||||||
|
expected_evaluation,
|
||||||
init_challenge: r,
|
init_challenge: r,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user