Browse Source

refactoring building block PIOPs (#71)

main
chancharles92 2 years ago
committed by GitHub
parent
commit
2af479ee84
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 124 additions and 351 deletions
  1. +2
    -3
      hyperplonk/src/lib.rs
  2. +76
    -5
      poly-iop/benches/bench.rs
  3. +15
    -105
      poly-iop/src/perm_check/mod.rs
  4. +0
    -169
      poly-iop/src/perm_check/util.rs
  5. +10
    -12
      poly-iop/src/prod_check/mod.rs
  6. +0
    -11
      poly-iop/src/sum_check/mod.rs
  7. +21
    -46
      poly-iop/src/zero_check/mod.rs

+ 2
- 3
hyperplonk/src/lib.rs

@ -680,7 +680,7 @@ where
&mut transcript,
)?;
let zero_check_point = &zero_check_sub_claim.sum_check_sub_claim.point;
let zero_check_point = &zero_check_sub_claim.point;
// check zero check subclaim
let f_eval = eval_f(
@ -718,10 +718,9 @@ where
let perm_check_point = &perm_check_sub_claim
.product_check_sub_claim
.zero_check_sub_claim
.sum_check_sub_claim
.point;
let alpha = perm_check_sub_claim.product_check_sub_claim.challenge;
let alpha = perm_check_sub_claim.product_check_sub_claim.alpha;
let (beta, gamma) = perm_check_sub_claim.challenges;
// check perm check subclaim:

+ 76
- 5
poly-iop/benches/bench.rs

@ -4,7 +4,8 @@ use ark_poly::{DenseMultilinearExtension, MultilinearExtension};
use ark_std::test_rng;
use pcs::{prelude::KZGMultilinearPCS, PolynomialCommitmentScheme};
use poly_iop::prelude::{
identity_permutation_mle, PermutationCheck, PolyIOP, PolyIOPErrors, SumCheck, ZeroCheck,
identity_permutation_mle, PermutationCheck, PolyIOP, PolyIOPErrors, ProductCheck, SumCheck,
ZeroCheck,
};
use std::{marker::PhantomData, rc::Rc, time::Instant};
@ -15,6 +16,8 @@ fn main() -> Result<(), PolyIOPErrors> {
println!("\n\n");
bench_sum_check()?;
println!("\n\n");
bench_prod_check()?;
println!("\n\n");
bench_zero_check()
}
@ -113,11 +116,10 @@ fn bench_zero_check() -> Result<(), PolyIOPErrors> {
let start = Instant::now();
let mut transcript = <PolyIOP<Fr> as ZeroCheck<Fr>>::init_transcript();
transcript.append_message(b"testing", b"initializing transcript for testing")?;
let subclaim =
<PolyIOP<Fr> as ZeroCheck<Fr>>::verify(&proof, &poly_info, &mut transcript)?
.sum_check_sub_claim;
let zero_subclaim =
<PolyIOP<Fr> as ZeroCheck<Fr>>::verify(&proof, &poly_info, &mut transcript)?;
assert!(
poly.evaluate(&subclaim.point)? == subclaim.expected_evaluation,
poly.evaluate(&zero_subclaim.point)? == zero_subclaim.expected_evaluation,
"wrong subclaim"
);
println!(
@ -204,3 +206,72 @@ fn bench_permutation_check() -> Result<(), PolyIOPErrors> {
Ok(())
}
fn bench_prod_check() -> Result<(), PolyIOPErrors> {
let mut rng = test_rng();
for nv in 4..20 {
let srs = KZG::gen_srs_for_testing(&mut rng, nv + 1)?;
let (pcs_param, _) = KZG::trim(&srs, nv + 1, Some(nv + 1))?;
let repetition = if nv < 10 {
100
} else if nv < 20 {
50
} else {
10
};
let f: DenseMultilinearExtension<Fr> = DenseMultilinearExtension::rand(nv, &mut rng);
let mut g = f.clone();
g.evaluations.reverse();
let f = Rc::new(f);
let g = Rc::new(g);
let proof = {
let start = Instant::now();
let mut transcript = <PolyIOP<Fr> as ProductCheck<Bls12_381, KZG>>::init_transcript();
transcript.append_message(b"testing", b"initializing transcript for testing")?;
let (proof, _prod_x) = <PolyIOP<Fr> as ProductCheck<Bls12_381, KZG>>::prove(
&pcs_param,
&f,
&g,
&mut transcript,
)?;
println!(
"product check proving time for {} variables: {} ns",
nv,
start.elapsed().as_nanos() / repetition as u128
);
proof
};
{
let poly_info = VPAuxInfo {
max_degree: 2,
num_variables: nv,
phantom: PhantomData::default(),
};
let start = Instant::now();
let mut transcript = <PolyIOP<Fr> as ProductCheck<Bls12_381, KZG>>::init_transcript();
transcript.append_message(b"testing", b"initializing transcript for testing")?;
let _perm_check_sum_claim = <PolyIOP<Fr> as ProductCheck<Bls12_381, KZG>>::verify(
&proof,
&poly_info,
&mut transcript,
)?;
println!(
"product check verification time for {} variables: {} ns",
nv,
start.elapsed().as_nanos() / repetition as u128
);
}
println!("====================================");
}
Ok(())
}

+ 15
- 105
poly-iop/src/perm_check/mod.rs

@ -27,7 +27,10 @@ where
pub mod util;
/// A PermutationCheck is derived from ZeroCheck.
/// A PermutationCheck w.r.t. `(f, g, perm)`
/// proves that g is a permutation of f under
/// permutation `perm`
/// It is derived from ProductCheck.
///
/// A Permutation Check IOP takes the following steps:
///
@ -58,7 +61,7 @@ where
/// Outputs:
/// - a permutation check proof proving that g is a permutation of f under
/// s_perm
/// - the Q(x) polynomial build during product check
/// - the product polynomial build during product check
///
/// Cost: O(N)
fn prove(
@ -78,53 +81,18 @@ where
) -> Result<Self::PermutationCheckSubClaim, PolyIOPErrors>;
}
/// A PermutationCheck is derived from ZeroCheck.
///
/// A Permutation Check IOP takes the following steps:
///
/// Inputs:
/// - f(x)
/// - g(x)
/// - permutation s_perm(x)
///
/// Steps:
/// 1. `generate_challenge` from current transcript (generate beta, gamma)
/// 2. `compute_product` to build `prod(x)` etc. from f, g and s_perm
/// 3. push a commitment of `prod(x)` to the transcript (done by the snark
/// caller)
/// 4. `update_challenge` with the updated transcript (generate alpha)
/// 5. `prove` to generate the proof
impl<E, PCS> PermutationCheck<E, PCS> for PolyIOP<E::Fr>
where
E: PairingEngine,
PCS: PolynomialCommitmentScheme<E, Polynomial = Rc<DenseMultilinearExtension<E::Fr>>>,
{
/// A Permutation SubClaim is indeed a ZeroCheck SubClaim that consists of
/// - the SubClaim from the SumCheck
/// - the initial challenge r which is used to build eq(x, r)
type PermutationCheckSubClaim = PermutationCheckSubClaim<E, PCS, Self>;
type PermutationProof = Self::ProductCheckProof;
/// Initialize the system with a transcript
///
/// This function is optional -- in the case where a PermutationCheck is
/// an building block for a more complex protocol, the transcript
/// may be initialized by this complex protocol, and passed to the
/// PermutationCheck prover/verifier.
fn init_transcript() -> Self::Transcript {
IOPTranscript::<E::Fr>::new(b"Initializing PermutationCheck transcript")
}
/// Inputs:
/// - f(x)
/// - g(x)
/// - permutation s_perm(x)
/// Outputs:
/// - a permutation check proof proving that g is a permutation of f under
/// s_perm
/// - the Q(x) polynomial build during product check
///
/// Cost: O(N)
fn prove(
pcs_param: &PCS::ProverParam,
fx: &Self::MultilinearExtension,
@ -151,11 +119,11 @@ where
let (numerator, denominator) = computer_num_and_denom(&beta, &gamma, fx, gx, s_perm)?;
// invoke product check on numerator and denominator
let (proof, poly) =
let (proof, prod_poly) =
<Self as ProductCheck<E, PCS>>::prove(pcs_param, &numerator, &denominator, transcript)?;
end_timer!(start);
Ok((proof, poly))
Ok((proof, prod_poly))
}
/// Verify that an MLE g(x) is a permutation of an
@ -184,18 +152,15 @@ where
#[cfg(test)]
mod test {
use super::{util::build_prod_partial_eval, PermutationCheck};
use super::PermutationCheck;
use crate::{
errors::PolyIOPErrors,
perm_check::util::computer_num_and_denom,
prelude::{identity_permutation_mle, random_permutation_mle},
utils::bit_decompose,
PolyIOP,
};
use arithmetic::{VPAuxInfo, VirtualPolynomial};
use arithmetic::VPAuxInfo;
use ark_bls12_381::Bls12_381;
use ark_ec::PairingEngine;
use ark_ff::{One, Zero};
use ark_poly::{DenseMultilinearExtension, MultilinearExtension};
use ark_std::test_rng;
use pcs::{prelude::KZGMultilinearPCS, PolynomialCommitmentScheme};
@ -223,7 +188,7 @@ mod test {
// prover
let mut transcript = <PolyIOP<E::Fr> as PermutationCheck<E, PCS>>::init_transcript();
transcript.append_message(b"testing", b"initializing transcript for testing")?;
let (proof, q_x) = <PolyIOP<E::Fr> as PermutationCheck<E, PCS>>::prove(
let (proof, prod_x) = <PolyIOP<E::Fr> as PermutationCheck<E, PCS>>::prove(
pcs_param,
fx,
gx,
@ -234,76 +199,21 @@ mod test {
// verifier
let mut transcript = <PolyIOP<E::Fr> as PermutationCheck<E, PCS>>::init_transcript();
transcript.append_message(b"testing", b"initializing transcript for testing")?;
let perm_check_sum_claim = <PolyIOP<E::Fr> as PermutationCheck<E, PCS>>::verify(
let perm_check_sub_claim = <PolyIOP<E::Fr> as PermutationCheck<E, PCS>>::verify(
&proof,
&poly_info,
&mut transcript,
)?;
let prod_partial_evals = build_prod_partial_eval(&q_x)?;
let prod_0x = prod_partial_evals[0].clone();
let prod_1x = prod_partial_evals[1].clone();
let prod_x0 = prod_partial_evals[2].clone();
let prod_x1 = prod_partial_evals[3].clone();
let (numerator, denominator) = computer_num_and_denom(
&perm_check_sum_claim.challenges.0,
&perm_check_sum_claim.challenges.1,
fx,
gx,
&s_perm,
)?;
// compute (g(x) + beta * s_perm(x) + gamma) * prod(0, x) * alpha
// which is prods[6] * prod[1] * alpha
let mut q_x = VirtualPolynomial::new_from_mle(&denominator, E::Fr::one());
q_x.mul_by_mle(
prod_0x,
perm_check_sum_claim.product_check_sub_claim.challenge,
)?;
// (g(x) + beta * s_perm(x) + gamma) * prod(0, x) * alpha
// - (f(x) + beta * s_id(x) + gamma) * alpha
q_x.add_mle_list(
[numerator],
-perm_check_sum_claim.product_check_sub_claim.challenge,
)?;
// 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))
q_x.add_mle_list([prod_x0, prod_x1], -E::Fr::one())?;
q_x.add_mle_list([prod_1x], E::Fr::one())?;
if q_x
.evaluate(
&perm_check_sum_claim
.product_check_sub_claim
.zero_check_sub_claim
.sum_check_sub_claim
.point,
)
// check product subclaim
if prod_x
.evaluate(&perm_check_sub_claim.product_check_sub_claim.final_query.0)
.unwrap()
!= perm_check_sum_claim
.product_check_sub_claim
.zero_check_sub_claim
.sum_check_sub_claim
.expected_evaluation
!= perm_check_sub_claim.product_check_sub_claim.final_query.1
{
return Err(PolyIOPErrors::InvalidVerifier("wrong subclaim".to_string()));
};
// test q_x is a 0 over boolean hypercube
for i in 0..1 << nv {
let bit_sequence = bit_decompose(i, nv);
let eval: Vec<E::Fr> = bit_sequence
.iter()
.map(|x| E::Fr::from(*x as u64))
.collect();
let res = q_x.evaluate(&eval).unwrap();
if !res.is_zero() {}
}
Ok(())
}

+ 0
- 169
poly-iop/src/perm_check/util.rs

@ -6,60 +6,6 @@ use ark_poly::DenseMultilinearExtension;
use ark_std::{end_timer, rand::RngCore, start_timer};
use std::rc::Rc;
/// Returns the evaluations of three MLEs:
/// - prod(0,x)
/// - numerator
/// - denominator
///
/// where
/// - `prod(0,x) := prod(0, x1, …, xn)` which is the MLE over the
/// evaluations of the following polynomial on the boolean hypercube {0,1}^n:
///
/// (f(x) + \beta s_id(x) + \gamma)/(g(x) + \beta s_perm(x) + \gamma)
///
/// where
/// - beta and gamma are challenges
/// - f(x), g(x), s_id(x), s_perm(x) are mle-s
///
/// - numerator is the MLE for `f(x) + \beta s_id(x) + \gamma`
/// - denominator is the MLE for `g(x) + \beta s_perm(x) + \gamma`
///
/// The caller needs to check num_vars matches in f/g/s_id/s_perm
/// Cost: linear in N.
#[cfg(test)]
#[allow(clippy::type_complexity)]
pub(super) fn compute_prod_0<F: PrimeField>(
beta: &F,
gamma: &F,
fx: &DenseMultilinearExtension<F>,
gx: &DenseMultilinearExtension<F>,
s_perm: &DenseMultilinearExtension<F>,
) -> Result<(Vec<F>, Vec<F>, Vec<F>), PolyIOPErrors> {
let start = start_timer!(|| "compute prod(1,x)");
let num_vars = fx.num_vars;
let mut prod_0x_evals = vec![];
let mut numerator_evals = vec![];
let mut denominator_evals = vec![];
// TODO: remove this line after replacing `s_perm` with `s`.
let s_id = identity_permutation_mle::<F>(num_vars);
for (&fi, (&gi, (&s_id_i, &s_perm_i))) in
fx.iter().zip(gx.iter().zip(s_id.iter().zip(s_perm.iter())))
{
let numerator = fi + *beta * s_id_i + gamma;
let denominator = gi + *beta * s_perm_i + gamma;
prod_0x_evals.push(numerator / denominator);
numerator_evals.push(numerator);
denominator_evals.push(denominator);
}
end_timer!(start);
Ok((prod_0x_evals, numerator_evals, denominator_evals))
}
/// Returns the evaluations of two MLEs:
/// - numerator
/// - denominator
@ -139,118 +85,3 @@ pub fn random_permutation_mle(
num_vars, s_perm_vec,
))
}
/// Helper function of the IOP.
///
/// Input:
/// - prod(x)
///
/// Output: the following 4 polynomials
/// - prod(0, x)
/// - prod(1, x)
/// - prod(x, 0)
/// - prod(x, 1)
#[cfg(test)]
pub(super) fn build_prod_partial_eval<F: PrimeField>(
prod_x: &Rc<DenseMultilinearExtension<F>>,
) -> Result<[Rc<DenseMultilinearExtension<F>>; 4], PolyIOPErrors> {
let start = start_timer!(|| "build prod polynomial");
let prod_x_eval = &prod_x.evaluations;
let num_vars = prod_x.num_vars - 1;
// prod(0, x)
let prod_0_x = Rc::new(DenseMultilinearExtension::from_evaluations_slice(
num_vars,
&prod_x_eval[0..1 << num_vars],
));
// prod(1, x)
let prod_1_x = Rc::new(DenseMultilinearExtension::from_evaluations_slice(
num_vars,
&prod_x_eval[1 << num_vars..1 << (num_vars + 1)],
));
// ===================================
// prod(x, 0) and prod(x, 1)
// ===================================
//
// now we compute eval_x0 and eval_x1
// eval_0x will be the odd coefficients of eval
// and eval_1x will be the even coefficients of eval
let mut eval_x0 = vec![];
let mut eval_x1 = vec![];
for (x, &prod_x) in prod_x_eval.iter().enumerate() {
if x & 1 == 0 {
eval_x0.push(prod_x);
} else {
eval_x1.push(prod_x);
}
}
let prod_x_0 = Rc::new(DenseMultilinearExtension::from_evaluations_vec(
num_vars, eval_x0,
));
let prod_x_1 = Rc::new(DenseMultilinearExtension::from_evaluations_vec(
num_vars, eval_x1,
));
end_timer!(start);
Ok([prod_0_x, prod_1_x, prod_x_0, prod_x_1])
}
#[cfg(test)]
mod test {
use super::*;
use crate::utils::bit_decompose;
use ark_bls12_381::Fr;
use ark_ff::UniformRand;
use ark_poly::MultilinearExtension;
use ark_std::test_rng;
#[test]
fn test_compute_prod_0() -> Result<(), PolyIOPErrors> {
let mut rng = test_rng();
for num_vars in 2..6 {
let f = DenseMultilinearExtension::rand(num_vars, &mut rng);
let g = DenseMultilinearExtension::rand(num_vars, &mut rng);
let s_id = identity_permutation_mle::<Fr>(num_vars);
let s_perm = random_permutation_mle(num_vars, &mut rng);
let beta = Fr::rand(&mut rng);
let gamma = Fr::rand(&mut rng);
let (prod_0, numerator, denominator) = compute_prod_0(&beta, &gamma, &f, &g, &s_perm)?;
let prod_0 = DenseMultilinearExtension::from_evaluations_vec(num_vars, prod_0);
let numerator = DenseMultilinearExtension::from_evaluations_vec(num_vars, numerator);
let denominator =
DenseMultilinearExtension::from_evaluations_vec(num_vars, denominator);
for i in 0..1 << num_vars {
let r: Vec<Fr> = bit_decompose(i, num_vars)
.iter()
.map(|&x| Fr::from(x))
.collect();
let prod_0_eval = prod_0.evaluate(&r).unwrap();
let numerator_eval = numerator.evaluate(&r).unwrap();
let denominator_eval = denominator.evaluate(&r).unwrap();
let f_eval = f.evaluate(&r).unwrap();
let g_eval = g.evaluate(&r).unwrap();
let s_id_eval = s_id.evaluate(&r).unwrap();
let s_perm_eval = s_perm.evaluate(&r).unwrap();
let numerator_eval_rec = f_eval + beta * s_id_eval + gamma;
let denominator_eval_rec = g_eval + beta * s_perm_eval + gamma;
let prod_0_eval_rec = numerator_eval_rec / denominator_eval_rec;
assert_eq!(numerator_eval, numerator_eval_rec);
assert_eq!(denominator_eval, denominator_eval_rec);
assert_eq!(prod_0_eval, prod_0_eval_rec);
}
}
Ok(())
}
}

+ 10
- 12
poly-iop/src/prod_check/mod.rs

@ -86,12 +86,10 @@ where
/// A product check subclaim consists of
/// - A zero check IOP subclaim for
/// `Q(x) = prod(1, x) - prod(x, 0) * prod(x, 1) + challenge * (f(x) - prod(0,
/// x) * g(x))` is 0, consists of the following:
/// - the SubClaim from the SumCheck
/// - the initial challenge r which is used to build eq(x, r) in ZeroCheck
/// - The challenge `challenge`
/// - A final query for `prod(1, ..., 1, 0) = claimed_product`.
/// `Q(x) = prod(1, x) - prod(x, 0) * prod(x, 1) + alpha * (f(x) - prod(0,
/// x) * g(x)) = 0`
/// - The random challenge `alpha`
/// - A final query for `prod(1, ..., 1, 0) = 1`.
// Note that this final query is in fact a constant that
// is independent from the proof. So we should avoid
// (de)serialize it.
@ -103,8 +101,8 @@ pub struct ProductCheckSubClaim> {
// - the vector `(1, ..., 1, 0)` (needs to be reversed because Arkwork's MLE uses big-endian
// format for points)
// The expected final query evaluation is 1
final_query: (Vec<F>, F),
pub challenge: F,
pub final_query: (Vec<F>, F),
pub alpha: F,
}
/// A product check proof consists of
@ -195,7 +193,7 @@ where
Ok(ProductCheckSubClaim {
zero_check_sub_claim,
final_query: (final_query, final_eval),
challenge: alpha,
alpha,
})
}
}
@ -240,11 +238,11 @@ mod test {
num_variables: f.num_vars,
phantom: PhantomData::default(),
};
let subclaim =
let prod_subclaim =
<PolyIOP<E::Fr> as ProductCheck<E, PCS>>::verify(&proof, &aux_info, &mut transcript)?;
assert_eq!(
prod_x.evaluate(&subclaim.final_query.0).unwrap(),
subclaim.final_query.1,
prod_x.evaluate(&prod_subclaim.final_query.0).unwrap(),
prod_subclaim.final_query.1,
"different product"
);

+ 0
- 11
poly-iop/src/sum_check/mod.rs

@ -131,7 +131,6 @@ impl SumCheck for PolyIOP {
type SumCheckSubClaim = SumCheckSubClaim<F>;
type Transcript = IOPTranscript<F>;
/// Extract sum from the proof
fn extract_sum(proof: &Self::SumCheckProof) -> F {
let start = start_timer!(|| "extract sum");
let res = proof.proofs[0].evaluations[0] + proof.proofs[0].evaluations[1];
@ -139,12 +138,6 @@ impl SumCheck for PolyIOP {
res
}
/// Initialize the system with a transcript
///
/// This function is optional -- in the case where a SumCheck is
/// an building block for a more complex protocol, the transcript
/// may be initialized by this complex protocol, and passed to the
/// SumCheck prover/verifier.
fn init_transcript() -> Self::Transcript {
let start = start_timer!(|| "init transcript");
let res = IOPTranscript::<F>::new(b"Initializing SumCheck transcript");
@ -152,9 +145,6 @@ impl SumCheck for PolyIOP {
res
}
/// Generate proof of the sum of polynomial over {0,1}^`num_vars`
///
/// The polynomial is represented in the form of a VirtualPolynomial.
fn prove(
poly: &Self::VirtualPolynomial,
transcript: &mut Self::Transcript,
@ -185,7 +175,6 @@ impl SumCheck for PolyIOP {
})
}
/// Verify the claimed sum using the proof
fn verify(
claimed_sum: F,
proof: &Self::SumCheckProof,

+ 21
- 46
poly-iop/src/zero_check/mod.rs

@ -9,20 +9,23 @@ use ark_poly::MultilinearExtension;
use ark_std::{end_timer, start_timer};
use transcript::IOPTranscript;
/// A zero check IOP subclaim for \hat f(x) is 0, consists of the following:
/// - the SubClaim from the SumCheck
/// - the initial challenge r which is used to build eq(x, r) in ZeroCheck
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ZeroCheckSubClaim<F: PrimeField, SC: SumCheck<F>> {
// the SubClaim from the SumCheck
pub sum_check_sub_claim: SC::SumCheckSubClaim,
/// A zero check IOP subclaim for `f(x)` consists of the following:
/// - the initial challenge vector r which is used to build eq(x, r) in
/// SumCheck
/// - the random vector `v` to be evaluated
/// - the claimed evaluation of `f(v)`
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct ZeroCheckSubClaim<F: PrimeField> {
// the evaluation point
pub point: Vec<F>,
/// the expected evaluation
pub expected_evaluation: F,
// the initial challenge r which is used to build eq(x, r)
pub init_challenge: Vec<F>,
}
/// A ZeroCheck is derived from SumCheck.
/// A ZeroCheck for `f(x)` proves that `f(x) = 0` for all `x \in {0,1}^num_vars`
/// It is derived from SumCheck.
pub trait ZeroCheck<F: PrimeField>: SumCheck<F> {
type ZeroCheckSubClaim: Clone + Debug + Default + PartialEq;
type ZeroCheckProof: Clone + Debug + Default + PartialEq;
@ -51,31 +54,13 @@ pub trait ZeroCheck: SumCheck {
}
impl<F: PrimeField> ZeroCheck<F> for PolyIOP<F> {
/// A ZeroCheck SubClaim consists of
/// - the SubClaim from the SumCheck
/// - the initial challenge r which is used to build eq(x, r)
type ZeroCheckSubClaim = ZeroCheckSubClaim<F, Self>;
/// A ZeroCheckProof is a SumCheckProof
type ZeroCheckSubClaim = ZeroCheckSubClaim<F>;
type ZeroCheckProof = Self::SumCheckProof;
/// Initialize the system with a transcript
///
/// This function is optional -- in the case where a ZeroCheck is
/// an building block for a more complex protocol, the transcript
/// may be initialized by this complex protocol, and passed to the
/// ZeroCheck prover/verifier.
fn init_transcript() -> Self::Transcript {
IOPTranscript::<F>::new(b"Initializing ZeroCheck transcript")
}
/// Initialize the prover to argue for the sum of polynomial f(x) over
/// {0,1}^`num_vars` is zero.
///
/// f(x) is zero if \hat f(x) := f(x) * eq(x,r) is also a zero polynomial
/// for a random r sampled from transcript.
///
/// This function will build the \hat f(x) and then invoke the sumcheck
/// protocol to generate a proof for which the sum of \hat f(x) is zero
fn prove(
poly: &Self::VirtualPolynomial,
transcript: &mut Self::Transcript,
@ -91,15 +76,6 @@ impl ZeroCheck for PolyIOP {
res
}
/// Verify that the polynomial's sum is zero using the proof.
/// Return a Self::Subclaim that consists of the
///
/// - a Subclaim that the sum is zero
/// - the initial challenge `r` that is used to build `eq(x, r)`
///
/// This function will check that \hat f(x)'s sum is zero. It does not check
/// `\hat f(x)` is build correctly. The caller needs to makes sure that
/// `\hat f(x) = f(x) * eq(x, r)`
fn verify(
proof: &Self::ZeroCheckProof,
fx_aux_info: &Self::VPAuxInfo,
@ -122,20 +98,20 @@ impl ZeroCheck for PolyIOP {
// hat_fx's max degree is increased by eq(x, r).degree() which is 1
let mut hat_fx_aux_info = fx_aux_info.clone();
hat_fx_aux_info.max_degree += 1;
let subclaim =
let sum_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
// expected_eval = sumcheck.expect_eval/eq(v, r)
// where v = 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(|| {
let expected_evaluation = sum_subclaim.expected_evaluation
/ eq_x_r.evaluate(&sum_subclaim.point).ok_or_else(|| {
PolyIOPErrors::InvalidParameters("evaluation dimension does not match".to_string())
})?;
end_timer!(start);
Ok(ZeroCheckSubClaim {
sum_check_sub_claim: subclaim,
point: sum_subclaim.point,
expected_evaluation,
init_challenge: r,
})
@ -170,11 +146,10 @@ mod test {
let poly_info = poly.aux_info.clone();
let mut transcript = <PolyIOP<Fr> as ZeroCheck<Fr>>::init_transcript();
transcript.append_message(b"testing", b"initializing transcript for testing")?;
let subclaim =
<PolyIOP<Fr> as ZeroCheck<Fr>>::verify(&proof, &poly_info, &mut transcript)?
.sum_check_sub_claim;
let zero_subclaim =
<PolyIOP<Fr> as ZeroCheck<Fr>>::verify(&proof, &poly_info, &mut transcript)?;
assert!(
poly.evaluate(&subclaim.point)? == subclaim.expected_evaluation,
poly.evaluate(&zero_subclaim.point)? == zero_subclaim.expected_evaluation,
"wrong subclaim"
);
}

Loading…
Cancel
Save