diff --git a/hyperplonk/Cargo.toml b/hyperplonk/Cargo.toml index 772b24a..af09f7e 100644 --- a/hyperplonk/Cargo.toml +++ b/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", diff --git a/hyperplonk/src/lib.rs b/hyperplonk/src/lib.rs index a5c9e5f..a0ec86a 100644 --- a/hyperplonk/src/lib.rs +++ b/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], - transcript: &mut Self::Transcript, ) -> Result; - /// 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; + ) -> Result; } impl HyperPlonkSNARK for PolyIOP @@ -109,7 +100,6 @@ where type ProvingKey = HyperPlonkProvingKey; type VerifyingKey = HyperPlonkVerifyingKey; type Proof = HyperPlonkProof; - type SubClaim = HyperPlonkSubClaim; /// 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], - transcript: &mut Self::Transcript, ) -> Result { let start = start_timer!(|| "hyperplonk proving"); + let mut transcript = IOPTranscript::::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 = >::prove(&fx, transcript)?; + let zero_check_proof = >::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 = >::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 { + ) -> Result { let start = start_timer!(|| "hyperplonk verification"); + let mut transcript = IOPTranscript::::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 = >::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:: { @@ -615,18 +724,64 @@ where num_variables: merged_nv, phantom: PhantomData::default(), }; - let mut challenge = >::generate_challenge(transcript)?; + let mut challenge = >::generate_challenge(&mut transcript)?; >::update_challenge( &mut challenge, - transcript, + &mut transcript, &proof.prod_commit, )?; let perm_check_sub_claim = >::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::(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 = [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) = as HyperPlonkSNARK>>::preprocess( ¶ms, &pcs_srs, - &perm, + &s_perm.evaluations, &[q1], )?; // generate a proof and verify - let mut transcript = IOPTranscript::::new(b"test hyperplonk"); let proof = as HyperPlonkSNARK>>::prove( &pk, &pi.0, &[w1, w2], - &mut transcript, )?; - let mut transcript = IOPTranscript::::new(b"test hyperplonk"); let _sub_claim = as HyperPlonkSNARK>>::verify( - &vk, - &pi.0, - &proof, - &mut transcript, + &vk, &pi.0, &proof, )?; Ok(()) diff --git a/hyperplonk/src/structs.rs b/hyperplonk/src/structs.rs index a4833fe..e5e4509 100644 --- a/hyperplonk/src/structs.rs +++ b/hyperplonk/src/structs.rs @@ -34,35 +34,50 @@ pub struct HyperPlonkProof< PC: PermutationCheck, > { // ======================================================================= - // PCS components + // PCS components: common // ======================================================================= /// PCS commit for witnesses // TODO: replace me with a batch commitment pub witness_commits: Vec, 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, + /// prod(x)'s openings + /// sequence: prod(0,x), prod(1, x), prod(x, 0), prod(x, 1) + pub prod_openings: Vec, /// 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, /// 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, /// 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, + /// Evaluates of witnesses on zero check point + pub witness_zero_check_evals: Vec, /// PCS openings for selectors on zero check point // TODO: replace me with a batch opening pub selector_oracle_openings: Vec, /// Evaluates of selectors on zero check point pub selector_oracle_evals: Vec, + // ======================================================================= + // 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 diff --git a/hyperplonk/src/utils.rs b/hyperplonk/src/utils.rs index f73ae83..6700bad 100644 --- a/hyperplonk/src/utils.rs +++ b/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()) } diff --git a/pcs/src/multilinear_kzg/batching.rs b/pcs/src/multilinear_kzg/batching.rs index 44508dc..8d459c9 100644 --- a/pcs/src/multilinear_kzg/batching.rs +++ b/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)] diff --git a/poly-iop/src/perm_check/mod.rs b/poly-iop/src/perm_check/mod.rs index 1c23869..f65531c 100644 --- a/poly-iop/src/perm_check/mod.rs +++ b/poly-iop/src/perm_check/mod.rs @@ -160,9 +160,9 @@ pub struct PermutationCheckSubClaim> { #[derive(Debug, Clone)] pub struct PermutationChallenge { - alpha: Option, - beta: F, - gamma: F, + pub alpha: Option, + pub beta: F, + pub gamma: F, } /// A PermutationCheck is derived from ZeroCheck. diff --git a/poly-iop/src/sum_check/mod.rs b/poly-iop/src/sum_check/mod.rs index fbfa69d..1c43838 100644 --- a/poly-iop/src/sum_check/mod.rs +++ b/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); diff --git a/poly-iop/src/sum_check/verifier.rs b/poly-iop/src/sum_check/verifier.rs index 5033d51..4086dab 100644 --- a/poly-iop/src/sum_check/verifier.rs +++ b/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")] diff --git a/poly-iop/src/zero_check/mod.rs b/poly-iop/src/zero_check/mod.rs index b15d523..290831c 100644 --- a/poly-iop/src/zero_check/mod.rs +++ b/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> { // 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, } @@ -119,9 +123,18 @@ impl ZeroCheck for PolyIOP { let subclaim = >::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, }) }