Browse Source

pass only one multilinear polynomial to EE (#144)

* pass only one multilinear polynomial to EE

* update version
main
Srinath Setty 1 year ago
committed by GitHub
parent
commit
01ae6446a9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 223 additions and 289 deletions
  1. +1
    -1
      Cargo.toml
  2. +18
    -208
      src/provider/ipa_pc.rs
  3. +114
    -66
      src/spartan/mod.rs
  4. +79
    -3
      src/spartan/sumcheck.rs
  5. +11
    -11
      src/traits/evaluation.rs

+ 1
- 1
Cargo.toml

@ -1,6 +1,6 @@
[package] [package]
name = "nova-snark" name = "nova-snark"
version = "0.15.0"
version = "0.16.0"
authors = ["Srinath Setty <srinath@microsoft.com>"] authors = ["Srinath Setty <srinath@microsoft.com>"]
edition = "2021" edition = "2021"
description = "Recursive zkSNARKs without trusted setup" description = "Recursive zkSNARKs without trusted setup"

+ 18
- 208
src/provider/ipa_pc.rs

@ -11,7 +11,7 @@ use crate::{
}, },
Commitment, CommitmentGens, CompressedCommitment, CE, Commitment, CommitmentGens, CompressedCommitment, CE,
}; };
use core::{cmp::max, iter};
use core::iter;
use ff::Field; use ff::Field;
use rayon::prelude::*; use rayon::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -29,7 +29,6 @@ pub struct EvaluationGens {
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(bound = "")] #[serde(bound = "")]
pub struct EvaluationArgument<G: Group> { pub struct EvaluationArgument<G: Group> {
nifs: Vec<NIFSForInnerProduct<G>>,
ipa: InnerProductArgument<G>, ipa: InnerProductArgument<G>,
} }
@ -55,89 +54,38 @@ where
} }
} }
fn prove_batch(
fn prove(
gens: &Self::EvaluationGens, gens: &Self::EvaluationGens,
transcript: &mut G::TE, transcript: &mut G::TE,
comms: &[Commitment<G>],
polys: &[Vec<G::Scalar>],
points: &[Vec<G::Scalar>],
evals: &[G::Scalar],
comm: &Commitment<G>,
poly: &[G::Scalar],
point: &[G::Scalar],
eval: &G::Scalar,
) -> Result<Self::EvaluationArgument, NovaError> { ) -> Result<Self::EvaluationArgument, NovaError> {
// sanity checks (these should never fail)
assert!(polys.len() >= 2);
assert_eq!(comms.len(), polys.len());
assert_eq!(comms.len(), points.len());
assert_eq!(comms.len(), evals.len());
let mut r_U = InnerProductInstance::new(
&comms[0],
&EqPolynomial::new(points[0].clone()).evals(),
&evals[0],
);
let mut r_W = InnerProductWitness::new(&polys[0]);
let mut nifs = Vec::new();
for i in 1..polys.len() {
let (n, u, w) = NIFSForInnerProduct::prove(
&r_U,
&r_W,
&InnerProductInstance::new(
&comms[i],
&EqPolynomial::new(points[i].clone()).evals(),
&evals[i],
),
&InnerProductWitness::new(&polys[i]),
transcript,
)?;
nifs.push(n);
r_U = u;
r_W = w;
}
let ipa = InnerProductArgument::prove(&gens.gens_v, &gens.gens_s, &r_U, &r_W, transcript)?;
let u = InnerProductInstance::new(comm, &EqPolynomial::new(point.to_vec()).evals(), eval);
let w = InnerProductWitness::new(poly);
Ok(EvaluationArgument { nifs, ipa })
Ok(EvaluationArgument {
ipa: InnerProductArgument::prove(&gens.gens_v, &gens.gens_s, &u, &w, transcript)?,
})
} }
/// A method to verify purported evaluations of a batch of polynomials /// A method to verify purported evaluations of a batch of polynomials
fn verify_batch(
fn verify(
gens: &Self::EvaluationGens, gens: &Self::EvaluationGens,
transcript: &mut G::TE, transcript: &mut G::TE,
comms: &[Commitment<G>],
points: &[Vec<G::Scalar>],
evals: &[G::Scalar],
comm: &Commitment<G>,
point: &[G::Scalar],
eval: &G::Scalar,
arg: &Self::EvaluationArgument, arg: &Self::EvaluationArgument,
) -> Result<(), NovaError> { ) -> Result<(), NovaError> {
// sanity checks (these should never fail)
assert!(comms.len() >= 2);
assert_eq!(comms.len(), points.len());
assert_eq!(comms.len(), evals.len());
let mut r_U = InnerProductInstance::new(
&comms[0],
&EqPolynomial::new(points[0].clone()).evals(),
&evals[0],
);
let mut num_vars = points[0].len();
for i in 1..comms.len() {
let u = arg.nifs[i - 1].verify(
&r_U,
&InnerProductInstance::new(
&comms[i],
&EqPolynomial::new(points[i].clone()).evals(),
&evals[i],
),
transcript,
)?;
r_U = u;
num_vars = max(num_vars, points[i].len());
}
let u = InnerProductInstance::new(comm, &EqPolynomial::new(point.to_vec()).evals(), eval);
arg.ipa.verify( arg.ipa.verify(
&gens.gens_v, &gens.gens_v,
&gens.gens_s, &gens.gens_s,
(2_usize).pow(num_vars as u32),
&r_U,
(2_usize).pow(point.len() as u32),
&u,
transcript, transcript,
)?; )?;
@ -172,16 +120,6 @@ impl InnerProductInstance {
c: *c, c: *c,
} }
} }
fn pad(&self, n: usize) -> InnerProductInstance<G> {
let mut b_vec = self.b_vec.clone();
b_vec.resize(n, G::Scalar::zero());
InnerProductInstance {
comm_a_vec: self.comm_a_vec,
b_vec,
c: self.c,
}
}
} }
struct InnerProductWitness<G: Group> { struct InnerProductWitness<G: Group> {
@ -194,134 +132,6 @@ impl InnerProductWitness {
a_vec: a_vec.to_vec(), a_vec: a_vec.to_vec(),
} }
} }
fn pad(&self, n: usize) -> InnerProductWitness<G> {
let mut a_vec = self.a_vec.clone();
a_vec.resize(n, G::Scalar::zero());
InnerProductWitness { a_vec }
}
}
/// A non-interactive folding scheme (NIFS) for inner product relations
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NIFSForInnerProduct<G: Group> {
cross_term: G::Scalar,
}
impl<G: Group> NIFSForInnerProduct<G> {
fn protocol_name() -> &'static [u8] {
b"NIFSForInnerProduct"
}
fn prove(
U1: &InnerProductInstance<G>,
W1: &InnerProductWitness<G>,
U2: &InnerProductInstance<G>,
W2: &InnerProductWitness<G>,
transcript: &mut G::TE,
) -> Result<(Self, InnerProductInstance<G>, InnerProductWitness<G>), NovaError> {
transcript.absorb_bytes(b"protocol-name", Self::protocol_name());
// pad the instances and witness so they are of the same length
let U1 = U1.pad(max(U1.b_vec.len(), U2.b_vec.len()));
let U2 = U2.pad(max(U1.b_vec.len(), U2.b_vec.len()));
let W1 = W1.pad(max(U1.b_vec.len(), U2.b_vec.len()));
let W2 = W2.pad(max(U1.b_vec.len(), U2.b_vec.len()));
// add the two commitments and two public vectors to the transcript
// we do not need to add public vectors as their compressed versions were
// read from the transcript
U1.comm_a_vec
.append_to_transcript(b"U1_comm_a_vec", transcript);
U2.comm_a_vec
.append_to_transcript(b"U2_comm_a_vec", transcript);
// compute the cross-term
let cross_term = inner_product(&W1.a_vec, &U2.b_vec) + inner_product(&W2.a_vec, &U1.b_vec);
// add the cross-term to the transcript
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
&cross_term,
b"cross_term",
transcript,
);
// obtain a random challenge
let r = G::Scalar::challenge(b"r", transcript)?;
// fold the vectors and their inner product
let a_vec = W1
.a_vec
.par_iter()
.zip(W2.a_vec.par_iter())
.map(|(x1, x2)| *x1 + r * x2)
.collect::<Vec<G::Scalar>>();
let b_vec = U1
.b_vec
.par_iter()
.zip(U2.b_vec.par_iter())
.map(|(a1, a2)| *a1 + r * a2)
.collect::<Vec<G::Scalar>>();
let c = U1.c + r * r * U2.c + r * cross_term;
let comm_a_vec = U1.comm_a_vec + U2.comm_a_vec * r;
let W = InnerProductWitness { a_vec };
let U = InnerProductInstance {
comm_a_vec,
b_vec,
c,
};
Ok((NIFSForInnerProduct { cross_term }, U, W))
}
fn verify(
&self,
U1: &InnerProductInstance<G>,
U2: &InnerProductInstance<G>,
transcript: &mut G::TE,
) -> Result<InnerProductInstance<G>, NovaError> {
transcript.absorb_bytes(b"protocol-name", Self::protocol_name());
// pad the instances so they are of the same length
let U1 = U1.pad(max(U1.b_vec.len(), U2.b_vec.len()));
let U2 = U2.pad(max(U1.b_vec.len(), U2.b_vec.len()));
// add the two commitments and two public vectors to the transcript
// we do not need to add public vectors as their compressed representation
// were derived from the transcript
U1.comm_a_vec
.append_to_transcript(b"U1_comm_a_vec", transcript);
U2.comm_a_vec
.append_to_transcript(b"U2_comm_a_vec", transcript);
// add the cross-term to the transcript
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
&self.cross_term,
b"cross_term",
transcript,
);
// obtain a random challenge
let r = G::Scalar::challenge(b"r", transcript)?;
// fold the vectors and their inner product
let b_vec = U1
.b_vec
.par_iter()
.zip(U2.b_vec.par_iter())
.map(|(a1, a2)| *a1 + r * a2)
.collect::<Vec<G::Scalar>>();
let c = U1.c + r * r * U2.c + r * self.cross_term;
let comm_a_vec = U1.comm_a_vec + U2.comm_a_vec * r;
Ok(InnerProductInstance {
comm_a_vec,
b_vec,
c,
})
}
} }
/// An inner product argument /// An inner product argument

+ 114
- 66
src/spartan/mod.rs

@ -63,9 +63,12 @@ impl> VerifierKeyTrait
pub struct RelaxedR1CSSNARK<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> { pub struct RelaxedR1CSSNARK<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
sc_proof_outer: SumcheckProof<G>, sc_proof_outer: SumcheckProof<G>,
claims_outer: (G::Scalar, G::Scalar, G::Scalar), claims_outer: (G::Scalar, G::Scalar, G::Scalar),
sc_proof_inner: SumcheckProof<G>,
eval_E: G::Scalar, eval_E: G::Scalar,
sc_proof_inner: SumcheckProof<G>,
eval_W: G::Scalar, eval_W: G::Scalar,
sc_proof_batch: SumcheckProof<G>,
eval_E_prime: G::Scalar,
eval_W_prime: G::Scalar,
eval_arg: EE::EvaluationArgument, eval_arg: EE::EvaluationArgument,
} }
@ -103,7 +106,7 @@ impl> RelaxedR1CSSNARKTrait
// outer sum-check // outer sum-check
let tau = (0..num_rounds_x) let tau = (0..num_rounds_x)
.map(|_i| G::Scalar::challenge(b"challenge_tau", &mut transcript))
.map(|_i| G::Scalar::challenge(b"tau", &mut transcript))
.collect::<Result<Vec<G::Scalar>, NovaError>>()?; .collect::<Result<Vec<G::Scalar>, NovaError>>()?;
let mut poly_tau = MultilinearPolynomial::new(EqPolynomial::new(tau).evals()); let mut poly_tau = MultilinearPolynomial::new(EqPolynomial::new(tau).evals());
@ -140,35 +143,17 @@ impl> RelaxedR1CSSNARKTrait
// claims from the end of sum-check // claims from the end of sum-check
let (claim_Az, claim_Bz): (G::Scalar, G::Scalar) = (claims_outer[1], claims_outer[2]); let (claim_Az, claim_Bz): (G::Scalar, G::Scalar) = (claims_outer[1], claims_outer[2]);
let claim_Cz = poly_Cz.evaluate(&r_x); let claim_Cz = poly_Cz.evaluate(&r_x);
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
&claim_Az,
b"claim_Az",
&mut transcript,
);
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
&claim_Bz,
b"claim_Bz",
&mut transcript,
);
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
&claim_Cz,
b"claim_Cz",
&mut transcript,
);
let eval_E = MultilinearPolynomial::new(W.E.clone()).evaluate(&r_x); let eval_E = MultilinearPolynomial::new(W.E.clone()).evaluate(&r_x);
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
&eval_E,
b"eval_E",
<[G::Scalar] as AppendToTranscriptTrait<G>>::append_to_transcript(
&[claim_Az, claim_Bz, claim_Cz, eval_E],
b"claims_outer",
&mut transcript, &mut transcript,
); );
// inner sum-check // inner sum-check
let r_A = G::Scalar::challenge(b"challenge_rA", &mut transcript)?;
let r_B = G::Scalar::challenge(b"challenge_rB", &mut transcript)?;
let r_C = G::Scalar::challenge(b"challenge_rC", &mut transcript)?;
let claim_inner_joint = r_A * claim_Az + r_B * claim_Bz + r_C * claim_Cz;
let r = G::Scalar::challenge(b"r", &mut transcript)?;
let claim_inner_joint = claim_Az + r * claim_Bz + r * r * claim_Cz;
let poly_ABC = { let poly_ABC = {
// compute the initial evaluation table for R(\tau, x) // compute the initial evaluation table for R(\tau, x)
@ -216,7 +201,7 @@ impl> RelaxedR1CSSNARKTrait
assert_eq!(evals_A.len(), evals_C.len()); assert_eq!(evals_A.len(), evals_C.len());
(0..evals_A.len()) (0..evals_A.len())
.into_par_iter() .into_par_iter()
.map(|i| r_A * evals_A[i] + r_B * evals_B[i] + r_C * evals_C[i])
.map(|i| evals_A[i] + r * evals_B[i] + r * r * evals_C[i])
.collect::<Vec<G::Scalar>>() .collect::<Vec<G::Scalar>>()
}; };
@ -244,21 +229,63 @@ impl> RelaxedR1CSSNARKTrait
&mut transcript, &mut transcript,
); );
let eval_arg = EE::prove_batch(
&pk.gens,
// We will now reduce eval_W =? W(r_y[1..]) and eval_W =? E(r_x) into
// two claims: eval_W_prime =? W(rz) and eval_E_prime =? E(rz)
// We can them combine the two into one: eval_W_prime + gamma * eval_E_prime =? (W + gamma*E)(rz),
// where gamma is a public challenge
// Since commitments to W and E are homomorphic, the verifier can compute a commitment
// to the batched polynomial.
let rho = G::Scalar::challenge(b"rho", &mut transcript)?;
let claim_batch_joint = eval_E + rho * eval_W;
let num_rounds_z = num_rounds_x;
let comb_func =
|poly_A_comp: &G::Scalar,
poly_B_comp: &G::Scalar,
poly_C_comp: &G::Scalar,
poly_D_comp: &G::Scalar|
-> G::Scalar { *poly_A_comp * *poly_B_comp + rho * *poly_C_comp * *poly_D_comp };
let (sc_proof_batch, r_z, claims_batch) = SumcheckProof::prove_quad_sum(
&claim_batch_joint,
num_rounds_z,
&mut MultilinearPolynomial::new(EqPolynomial::new(r_x).evals()),
&mut MultilinearPolynomial::new(W.E.clone()),
&mut MultilinearPolynomial::new(EqPolynomial::new(r_y[1..].to_vec()).evals()),
&mut MultilinearPolynomial::new(W.W.clone()),
comb_func,
&mut transcript, &mut transcript,
&[U.comm_E, U.comm_W],
&[W.E.clone(), W.W.clone()],
&[r_x, r_y[1..].to_vec()],
&[eval_E, eval_W],
)?; )?;
let eval_E_prime = claims_batch[1];
let eval_W_prime = claims_batch[3];
<[G::Scalar] as AppendToTranscriptTrait<G>>::append_to_transcript(
&[eval_E_prime, eval_W_prime],
b"claims_batch",
&mut transcript,
);
// we now combine evaluation claims at the same point rz into one
let gamma = G::Scalar::challenge(b"gamma", &mut transcript)?;
let comm = U.comm_E + U.comm_W * gamma;
let poly = W
.E
.iter()
.zip(W.W.iter())
.map(|(e, w)| *e + gamma * w)
.collect::<Vec<G::Scalar>>();
let eval = eval_E_prime + gamma * eval_W_prime;
let eval_arg = EE::prove(&pk.gens, &mut transcript, &comm, &poly, &r_z, &eval)?;
Ok(RelaxedR1CSSNARK { Ok(RelaxedR1CSSNARK {
sc_proof_outer, sc_proof_outer,
claims_outer: (claim_Az, claim_Bz, claim_Cz), claims_outer: (claim_Az, claim_Bz, claim_Cz),
eval_E,
sc_proof_inner, sc_proof_inner,
eval_W, eval_W,
eval_E,
sc_proof_batch,
eval_E_prime,
eval_W_prime,
eval_arg, eval_arg,
}) })
} }
@ -278,7 +305,7 @@ impl> RelaxedR1CSSNARKTrait
// outer sum-check // outer sum-check
let tau = (0..num_rounds_x) let tau = (0..num_rounds_x)
.map(|_i| G::Scalar::challenge(b"challenge_tau", &mut transcript))
.map(|_i| G::Scalar::challenge(b"tau", &mut transcript))
.collect::<Result<Vec<G::Scalar>, NovaError>>()?; .collect::<Result<Vec<G::Scalar>, NovaError>>()?;
let (claim_outer_final, r_x) = let (claim_outer_final, r_x) =
@ -295,33 +322,21 @@ impl> RelaxedR1CSSNARKTrait
return Err(NovaError::InvalidSumcheckProof); return Err(NovaError::InvalidSumcheckProof);
} }
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
&self.claims_outer.0,
b"claim_Az",
&mut transcript,
);
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
&self.claims_outer.1,
b"claim_Bz",
&mut transcript,
);
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
&self.claims_outer.2,
b"claim_Cz",
&mut transcript,
);
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
&self.eval_E,
b"eval_E",
<[G::Scalar] as AppendToTranscriptTrait<G>>::append_to_transcript(
&[
self.claims_outer.0,
self.claims_outer.1,
self.claims_outer.2,
self.eval_E,
],
b"claims_outer",
&mut transcript, &mut transcript,
); );
// inner sum-check // inner sum-check
let r_A = G::Scalar::challenge(b"challenge_rA", &mut transcript)?;
let r_B = G::Scalar::challenge(b"challenge_rB", &mut transcript)?;
let r_C = G::Scalar::challenge(b"challenge_rC", &mut transcript)?;
let r = G::Scalar::challenge(b"r", &mut transcript)?;
let claim_inner_joint = let claim_inner_joint =
r_A * self.claims_outer.0 + r_B * self.claims_outer.1 + r_C * self.claims_outer.2;
self.claims_outer.0 + r * self.claims_outer.1 + r * r * self.claims_outer.2;
let (claim_inner_final, r_y) = let (claim_inner_final, r_y) =
self self
@ -351,11 +366,13 @@ impl> RelaxedR1CSSNARKTrait
let evaluate_with_table = let evaluate_with_table =
|M: &[(usize, usize, G::Scalar)], T_x: &[G::Scalar], T_y: &[G::Scalar]| -> G::Scalar { |M: &[(usize, usize, G::Scalar)], T_x: &[G::Scalar], T_y: &[G::Scalar]| -> G::Scalar {
(0..M.len()) (0..M.len())
.map(|i| {
.collect::<Vec<usize>>()
.par_iter()
.map(|&i| {
let (row, col, val) = M[i]; let (row, col, val) = M[i];
T_x[row] * T_y[col] * val T_x[row] * T_y[col] * val
}) })
.fold(G::Scalar::zero(), |acc, x| acc + x)
.reduce(G::Scalar::zero, |acc, x| acc + x)
}; };
let T_x = EqPolynomial::new(r_x.to_vec()).evals(); let T_x = EqPolynomial::new(r_x.to_vec()).evals();
@ -367,24 +384,55 @@ impl> RelaxedR1CSSNARKTrait
}; };
let (eval_A_r, eval_B_r, eval_C_r) = evaluate_as_sparse_polynomial(&vk.S, &r_x, &r_y); let (eval_A_r, eval_B_r, eval_C_r) = evaluate_as_sparse_polynomial(&vk.S, &r_x, &r_y);
let claim_inner_final_expected = (r_A * eval_A_r + r_B * eval_B_r + r_C * eval_C_r) * eval_Z;
let claim_inner_final_expected = (eval_A_r + r * eval_B_r + r * r * eval_C_r) * eval_Z;
if claim_inner_final != claim_inner_final_expected { if claim_inner_final != claim_inner_final_expected {
return Err(NovaError::InvalidSumcheckProof); return Err(NovaError::InvalidSumcheckProof);
} }
// verify eval_W and eval_E
// batch sum-check
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript( <G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
&self.eval_W, &self.eval_W,
b"eval_W", b"eval_W",
&mut transcript, &mut transcript,
); //eval_E is already in the transcript
);
let rho = G::Scalar::challenge(b"rho", &mut transcript)?;
let claim_batch_joint = self.eval_E + rho * self.eval_W;
let num_rounds_z = num_rounds_x;
let (claim_batch_final, r_z) =
self
.sc_proof_batch
.verify(claim_batch_joint, num_rounds_z, 2, &mut transcript)?;
let claim_batch_final_expected = {
let poly_rz = EqPolynomial::new(r_z.clone());
let rz_rx = poly_rz.evaluate(&r_x);
let rz_ry = poly_rz.evaluate(&r_y[1..]);
rz_rx * self.eval_E_prime + rho * rz_ry * self.eval_W_prime
};
if claim_batch_final != claim_batch_final_expected {
return Err(NovaError::InvalidSumcheckProof);
}
<[G::Scalar] as AppendToTranscriptTrait<G>>::append_to_transcript(
&[self.eval_E_prime, self.eval_W_prime],
b"claims_batch",
&mut transcript,
);
// we now combine evaluation claims at the same point rz into one
let gamma = G::Scalar::challenge(b"gamma", &mut transcript)?;
let comm = U.comm_E + U.comm_W * gamma;
let eval = self.eval_E_prime + gamma * self.eval_W_prime;
EE::verify_batch(
// verify eval_W and eval_E
EE::verify(
&vk.gens, &vk.gens,
&mut transcript, &mut transcript,
&[U.comm_E, U.comm_W],
&[r_x, r_y[1..].to_vec()],
&[self.eval_E, self.eval_W],
&comm,
&r_z,
&eval,
&self.eval_arg, &self.eval_arg,
)?; )?;

+ 79
- 3
src/spartan/sumcheck.rs

@ -46,7 +46,7 @@ impl SumcheckProof {
poly.append_to_transcript(b"poly", transcript); poly.append_to_transcript(b"poly", transcript);
//derive the verifier's challenge for the next round //derive the verifier's challenge for the next round
let r_i = G::Scalar::challenge(b"challenge_nextround", transcript)?;
let r_i = G::Scalar::challenge(b"challenge", transcript)?;
r.push(r_i); r.push(r_i);
@ -101,7 +101,7 @@ impl SumcheckProof {
poly.append_to_transcript(b"poly", transcript); poly.append_to_transcript(b"poly", transcript);
//derive the verifier's challenge for the next round //derive the verifier's challenge for the next round
let r_i = G::Scalar::challenge(b"challenge_nextround", transcript)?;
let r_i = G::Scalar::challenge(b"challenge", transcript)?;
r.push(r_i); r.push(r_i);
polys.push(poly.compress()); polys.push(poly.compress());
@ -122,6 +122,82 @@ impl SumcheckProof {
)) ))
} }
pub fn prove_quad_sum<F>(
claim: &G::Scalar,
num_rounds: usize,
poly_A: &mut MultilinearPolynomial<G::Scalar>,
poly_B: &mut MultilinearPolynomial<G::Scalar>,
poly_C: &mut MultilinearPolynomial<G::Scalar>,
poly_D: &mut MultilinearPolynomial<G::Scalar>,
comb_func: F,
transcript: &mut G::TE,
) -> Result<(Self, Vec<G::Scalar>, Vec<G::Scalar>), NovaError>
where
F: Fn(&G::Scalar, &G::Scalar, &G::Scalar, &G::Scalar) -> G::Scalar + Sync,
{
let mut r: Vec<G::Scalar> = Vec::new();
let mut polys: Vec<CompressedUniPoly<G>> = Vec::new();
let mut claim_per_round = *claim;
for _ in 0..num_rounds {
let poly = {
let len = poly_A.len() / 2;
// Make an iterator returning the contributions to the evaluations
let (eval_point_0, eval_point_2) = (0..len)
.into_par_iter()
.map(|i| {
// eval 0: bound_func is A(low)
let eval_point_0 = comb_func(&poly_A[i], &poly_B[i], &poly_C[i], &poly_D[i]);
// eval 2: bound_func is -A(low) + 2*A(high)
let poly_A_bound_point = poly_A[len + i] + poly_A[len + i] - poly_A[i];
let poly_B_bound_point = poly_B[len + i] + poly_B[len + i] - poly_B[i];
let poly_C_bound_point = poly_C[len + i] + poly_C[len + i] - poly_C[i];
let poly_D_bound_point = poly_D[len + i] + poly_D[len + i] - poly_D[i];
let eval_point_2 = comb_func(
&poly_A_bound_point,
&poly_B_bound_point,
&poly_C_bound_point,
&poly_D_bound_point,
);
(eval_point_0, eval_point_2)
})
.reduce(
|| (G::Scalar::zero(), G::Scalar::zero()),
|a, b| (a.0 + b.0, a.1 + b.1),
);
let evals = vec![eval_point_0, claim_per_round - eval_point_0, eval_point_2];
UniPoly::from_evals(&evals)
};
// append the prover's message to the transcript
poly.append_to_transcript(b"poly", transcript);
//derive the verifier's challenge for the next round
let r_i = G::Scalar::challenge(b"challenge", transcript)?;
r.push(r_i);
polys.push(poly.compress());
// Set up next round
claim_per_round = poly.evaluate(&r_i);
// bound all tables to the verifier's challenege
poly_A.bound_poly_var_top(&r_i);
poly_B.bound_poly_var_top(&r_i);
poly_C.bound_poly_var_top(&r_i);
poly_D.bound_poly_var_top(&r_i);
}
Ok((
SumcheckProof {
compressed_polys: polys,
},
r,
vec![poly_A[0], poly_B[0], poly_C[0], poly_D[0]],
))
}
pub fn prove_cubic_with_additive_term<F>( pub fn prove_cubic_with_additive_term<F>(
claim: &G::Scalar, claim: &G::Scalar,
num_rounds: usize, num_rounds: usize,
@ -193,7 +269,7 @@ impl SumcheckProof {
poly.append_to_transcript(b"poly", transcript); poly.append_to_transcript(b"poly", transcript);
//derive the verifier's challenge for the next round //derive the verifier's challenge for the next round
let r_i = G::Scalar::challenge(b"challenge_nextround", transcript)?;
let r_i = G::Scalar::challenge(b"challenge", transcript)?;
r.push(r_i); r.push(r_i);
polys.push(poly.compress()); polys.push(poly.compress());

+ 11
- 11
src/traits/evaluation.rs

@ -23,23 +23,23 @@ pub trait EvaluationEngineTrait:
/// A method to perform any additional setup needed to produce proofs of evaluations /// A method to perform any additional setup needed to produce proofs of evaluations
fn setup(gens: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentGens) -> Self::EvaluationGens; fn setup(gens: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentGens) -> Self::EvaluationGens;
/// A method to prove evaluations of a batch of polynomials
fn prove_batch(
/// A method to prove the evaluation of a multilinear polynomial
fn prove(
gens: &Self::EvaluationGens, gens: &Self::EvaluationGens,
transcript: &mut G::TE, transcript: &mut G::TE,
comm: &[<Self::CE as CommitmentEngineTrait<G>>::Commitment],
polys: &[Vec<G::Scalar>],
points: &[Vec<G::Scalar>],
evals: &[G::Scalar],
comm: &<Self::CE as CommitmentEngineTrait<G>>::Commitment,
poly: &[G::Scalar],
point: &[G::Scalar],
eval: &G::Scalar,
) -> Result<Self::EvaluationArgument, NovaError>; ) -> Result<Self::EvaluationArgument, NovaError>;
/// A method to verify purported evaluations of a batch of polynomials
fn verify_batch(
/// A method to verify the purported evaluation of a multilinear polynomials
fn verify(
gens: &Self::EvaluationGens, gens: &Self::EvaluationGens,
transcript: &mut G::TE, transcript: &mut G::TE,
comm: &[<Self::CE as CommitmentEngineTrait<G>>::Commitment],
points: &[Vec<G::Scalar>],
evals: &[G::Scalar],
comm: &<Self::CE as CommitmentEngineTrait<G>>::Commitment,
point: &[G::Scalar],
eval: &G::Scalar,
arg: &Self::EvaluationArgument, arg: &Self::EvaluationArgument,
) -> Result<(), NovaError>; ) -> Result<(), NovaError>;
} }

Loading…
Cancel
Save