mirror of
https://github.com/arnaucube/Nova.git
synced 2026-01-12 09:01:28 +01:00
Batch polynomial evaluations (#154)
* Ability to collect evaluation claims * defer polynomial evaluation claims * address cargo clippy
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nova-snark"
|
name = "nova-snark"
|
||||||
version = "0.19.0"
|
version = "0.19.1"
|
||||||
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"
|
||||||
|
|||||||
@@ -1095,8 +1095,8 @@ mod tests {
|
|||||||
assert_eq!(zn_secondary, vec![<G2 as Group>::Scalar::from(2460515u64)]);
|
assert_eq!(zn_secondary, vec![<G2 as Group>::Scalar::from(2460515u64)]);
|
||||||
|
|
||||||
// run the compressed snark with Spark compiler
|
// run the compressed snark with Spark compiler
|
||||||
type CC1Prime = spartan::spark::SparkEngine<G1, EE1>;
|
type CC1Prime = spartan::spark::SparkEngine<G1>;
|
||||||
type CC2Prime = spartan::spark::SparkEngine<G2, EE2>;
|
type CC2Prime = spartan::spark::SparkEngine<G2>;
|
||||||
type S1Prime = spartan::RelaxedR1CSSNARK<G1, EE1, CC1Prime>;
|
type S1Prime = spartan::RelaxedR1CSSNARK<G1, EE1, CC1Prime>;
|
||||||
type S2Prime = spartan::RelaxedR1CSSNARK<G2, EE2, CC2Prime>;
|
type S2Prime = spartan::RelaxedR1CSSNARK<G2, EE2, CC2Prime>;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::{
|
|||||||
evaluation::EvaluationEngineTrait, snark::RelaxedR1CSSNARKTrait, Group, TranscriptEngineTrait,
|
evaluation::EvaluationEngineTrait, snark::RelaxedR1CSSNARKTrait, Group, TranscriptEngineTrait,
|
||||||
TranscriptReprTrait,
|
TranscriptReprTrait,
|
||||||
},
|
},
|
||||||
CommitmentKey,
|
Commitment, CommitmentKey,
|
||||||
};
|
};
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
use itertools::concat;
|
use itertools::concat;
|
||||||
@@ -21,8 +21,67 @@ use rayon::prelude::*;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sumcheck::SumcheckProof;
|
use sumcheck::SumcheckProof;
|
||||||
|
|
||||||
|
/// A type that holds a witness to a polynomial evaluation instance
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct PolyEvalWitness<G: Group> {
|
||||||
|
p: Vec<G::Scalar>, // polynomial
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G: Group> PolyEvalWitness<G> {
|
||||||
|
fn pad(W: &[PolyEvalWitness<G>]) -> Vec<PolyEvalWitness<G>> {
|
||||||
|
// determine the maximum size
|
||||||
|
if let Some(n) = W.iter().map(|w| w.p.len()).max() {
|
||||||
|
W.iter()
|
||||||
|
.map(|w| {
|
||||||
|
let mut p = w.p.clone();
|
||||||
|
p.resize(n, G::Scalar::zero());
|
||||||
|
PolyEvalWitness { p }
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn weighted_sum(W: &[PolyEvalWitness<G>], s: &[G::Scalar]) -> PolyEvalWitness<G> {
|
||||||
|
assert_eq!(W.len(), s.len());
|
||||||
|
let mut p = vec![G::Scalar::zero(); W[0].p.len()];
|
||||||
|
for i in 0..W.len() {
|
||||||
|
for j in 0..W[i].p.len() {
|
||||||
|
p[j] += W[i].p[j] * s[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PolyEvalWitness { p }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A type that holds a polynomial evaluation instance
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct PolyEvalInstance<G: Group> {
|
||||||
|
c: Commitment<G>, // commitment to the polynomial
|
||||||
|
x: Vec<G::Scalar>, // evaluation point
|
||||||
|
e: G::Scalar, // claimed evaluation
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G: Group> PolyEvalInstance<G> {
|
||||||
|
fn pad(U: &[PolyEvalInstance<G>]) -> Vec<PolyEvalInstance<G>> {
|
||||||
|
// determine the maximum size
|
||||||
|
if let Some(ell) = U.iter().map(|u| u.x.len()).max() {
|
||||||
|
U.iter()
|
||||||
|
.map(|u| {
|
||||||
|
let mut x = vec![G::Scalar::zero(); ell - u.x.len()];
|
||||||
|
x.extend(u.x.clone());
|
||||||
|
PolyEvalInstance { c: u.c, x, e: u.e }
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A trait that defines the behavior of a computation commitment engine
|
/// A trait that defines the behavior of a computation commitment engine
|
||||||
pub trait CompCommitmentEngineTrait<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
|
pub trait CompCommitmentEngineTrait<G: Group> {
|
||||||
/// A type that holds opening hint
|
/// A type that holds opening hint
|
||||||
type Decommitment: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>;
|
type Decommitment: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>;
|
||||||
|
|
||||||
@@ -46,22 +105,26 @@ pub trait CompCommitmentEngineTrait<G: Group, EE: EvaluationEngineTrait<G, CE =
|
|||||||
/// proves an evaluation of R1CS matrices viewed as polynomials
|
/// proves an evaluation of R1CS matrices viewed as polynomials
|
||||||
fn prove(
|
fn prove(
|
||||||
ck: &CommitmentKey<G>,
|
ck: &CommitmentKey<G>,
|
||||||
ek: &EE::ProverKey,
|
|
||||||
S: &R1CSShape<G>,
|
S: &R1CSShape<G>,
|
||||||
decomm: &Self::Decommitment,
|
decomm: &Self::Decommitment,
|
||||||
comm: &Self::Commitment,
|
comm: &Self::Commitment,
|
||||||
r: &(&[G::Scalar], &[G::Scalar]),
|
r: &(&[G::Scalar], &[G::Scalar]),
|
||||||
transcript: &mut G::TE,
|
transcript: &mut G::TE,
|
||||||
) -> Result<Self::EvaluationArgument, NovaError>;
|
) -> Result<
|
||||||
|
(
|
||||||
|
Self::EvaluationArgument,
|
||||||
|
Vec<(PolyEvalWitness<G>, PolyEvalInstance<G>)>,
|
||||||
|
),
|
||||||
|
NovaError,
|
||||||
|
>;
|
||||||
|
|
||||||
/// verifies an evaluation of R1CS matrices viewed as polynomials and returns verified evaluations
|
/// verifies an evaluation of R1CS matrices viewed as polynomials and returns verified evaluations
|
||||||
fn verify(
|
fn verify(
|
||||||
vk: &EE::VerifierKey,
|
|
||||||
comm: &Self::Commitment,
|
comm: &Self::Commitment,
|
||||||
r: &(&[G::Scalar], &[G::Scalar]),
|
r: &(&[G::Scalar], &[G::Scalar]),
|
||||||
arg: &Self::EvaluationArgument,
|
arg: &Self::EvaluationArgument,
|
||||||
transcript: &mut G::TE,
|
transcript: &mut G::TE,
|
||||||
) -> Result<(G::Scalar, G::Scalar, G::Scalar), NovaError>;
|
) -> Result<(G::Scalar, G::Scalar, G::Scalar, Vec<PolyEvalInstance<G>>), NovaError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type that represents the prover's key
|
/// A type that represents the prover's key
|
||||||
@@ -70,7 +133,7 @@ pub trait CompCommitmentEngineTrait<G: Group, EE: EvaluationEngineTrait<G, CE =
|
|||||||
pub struct ProverKey<
|
pub struct ProverKey<
|
||||||
G: Group,
|
G: Group,
|
||||||
EE: EvaluationEngineTrait<G, CE = G::CE>,
|
EE: EvaluationEngineTrait<G, CE = G::CE>,
|
||||||
CC: CompCommitmentEngineTrait<G, EE>,
|
CC: CompCommitmentEngineTrait<G>,
|
||||||
> {
|
> {
|
||||||
pk_ee: EE::ProverKey,
|
pk_ee: EE::ProverKey,
|
||||||
S: R1CSShape<G>,
|
S: R1CSShape<G>,
|
||||||
@@ -84,7 +147,7 @@ pub struct ProverKey<
|
|||||||
pub struct VerifierKey<
|
pub struct VerifierKey<
|
||||||
G: Group,
|
G: Group,
|
||||||
EE: EvaluationEngineTrait<G, CE = G::CE>,
|
EE: EvaluationEngineTrait<G, CE = G::CE>,
|
||||||
CC: CompCommitmentEngineTrait<G, EE>,
|
CC: CompCommitmentEngineTrait<G>,
|
||||||
> {
|
> {
|
||||||
num_cons: usize,
|
num_cons: usize,
|
||||||
num_vars: usize,
|
num_vars: usize,
|
||||||
@@ -100,21 +163,20 @@ pub struct VerifierKey<
|
|||||||
pub struct RelaxedR1CSSNARK<
|
pub struct RelaxedR1CSSNARK<
|
||||||
G: Group,
|
G: Group,
|
||||||
EE: EvaluationEngineTrait<G, CE = G::CE>,
|
EE: EvaluationEngineTrait<G, CE = G::CE>,
|
||||||
CC: CompCommitmentEngineTrait<G, EE>,
|
CC: CompCommitmentEngineTrait<G>,
|
||||||
> {
|
> {
|
||||||
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),
|
||||||
eval_E: G::Scalar,
|
eval_E: G::Scalar,
|
||||||
sc_proof_inner: SumcheckProof<G>,
|
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_cc: CC::EvaluationArgument,
|
eval_arg_cc: CC::EvaluationArgument,
|
||||||
|
sc_proof_batch: SumcheckProof<G>,
|
||||||
|
evals_batch: Vec<G::Scalar>,
|
||||||
|
eval_arg: EE::EvaluationArgument,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>, CC: CompCommitmentEngineTrait<G, EE>>
|
impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>, CC: CompCommitmentEngineTrait<G>>
|
||||||
RelaxedR1CSSNARKTrait<G> for RelaxedR1CSSNARK<G, EE, CC>
|
RelaxedR1CSSNARKTrait<G> for RelaxedR1CSSNARK<G, EE, CC>
|
||||||
{
|
{
|
||||||
type ProverKey = ProverKey<G, EE, CC>;
|
type ProverKey = ProverKey<G, EE, CC>;
|
||||||
@@ -292,9 +354,8 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>, CC: CompCommitmentEngin
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
// we now prove evaluations of R1CS matrices at (r_x, r_y)
|
// we now prove evaluations of R1CS matrices at (r_x, r_y)
|
||||||
let eval_arg_cc = CC::prove(
|
let (eval_arg_cc, mut w_u_vec) = CC::prove(
|
||||||
ck,
|
ck,
|
||||||
&pk.pk_ee,
|
|
||||||
&pk.S,
|
&pk.S,
|
||||||
&pk.decomm,
|
&pk.decomm,
|
||||||
&pk.comm,
|
&pk.comm,
|
||||||
@@ -302,52 +363,111 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>, CC: CompCommitmentEngin
|
|||||||
&mut transcript,
|
&mut transcript,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let eval_W = MultilinearPolynomial::new(W.W.clone()).evaluate(&r_y[1..]);
|
// add additional claims about W and E polynomials to the list from CC
|
||||||
transcript.absorb(b"eval_W", &eval_W);
|
let eval_W = MultilinearPolynomial::evaluate_with(&W.W, &r_y[1..]);
|
||||||
|
w_u_vec.push((
|
||||||
|
PolyEvalWitness { p: W.W.clone() },
|
||||||
|
PolyEvalInstance {
|
||||||
|
c: U.comm_W,
|
||||||
|
x: r_y[1..].to_vec(),
|
||||||
|
e: eval_W,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
// We will now reduce eval_W =? W(r_y[1..]) and eval_W =? E(r_x) into
|
w_u_vec.push((
|
||||||
|
PolyEvalWitness { p: W.E },
|
||||||
|
PolyEvalInstance {
|
||||||
|
c: U.comm_E,
|
||||||
|
x: r_x,
|
||||||
|
e: eval_E,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
|
// We will now reduce a vector of claims of evaluations at different points into claims about them at the same point.
|
||||||
|
// For example, 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)
|
// 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),
|
// 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
|
// where gamma is a public challenge
|
||||||
// Since commitments to W and E are homomorphic, the verifier can compute a commitment
|
// Since commitments to W and E are homomorphic, the verifier can compute a commitment
|
||||||
// to the batched polynomial.
|
// to the batched polynomial.
|
||||||
let rho = transcript.squeeze(b"rho")?;
|
assert!(w_u_vec.len() >= 2);
|
||||||
|
|
||||||
let claim_batch_joint = eval_E + rho * eval_W;
|
let (w_vec, u_vec): (Vec<PolyEvalWitness<G>>, Vec<PolyEvalInstance<G>>) =
|
||||||
let num_rounds_z = num_rounds_x;
|
w_u_vec.into_iter().unzip();
|
||||||
let comb_func =
|
let w_vec_padded = PolyEvalWitness::pad(&w_vec); // pad the polynomials to be of the same size
|
||||||
|poly_A_comp: &G::Scalar,
|
let u_vec_padded = PolyEvalInstance::pad(&u_vec); // pad the evaluation points
|
||||||
poly_B_comp: &G::Scalar,
|
|
||||||
poly_C_comp: &G::Scalar,
|
let powers = |s: &G::Scalar, n: usize| -> Vec<G::Scalar> {
|
||||||
poly_D_comp: &G::Scalar|
|
assert!(n >= 1);
|
||||||
-> G::Scalar { *poly_A_comp * *poly_B_comp + rho * *poly_C_comp * *poly_D_comp };
|
let mut powers = Vec::new();
|
||||||
let (sc_proof_batch, r_z, claims_batch) = SumcheckProof::prove_quad_sum(
|
powers.push(G::Scalar::one());
|
||||||
|
for i in 1..n {
|
||||||
|
powers.push(powers[i - 1] * s);
|
||||||
|
}
|
||||||
|
powers
|
||||||
|
};
|
||||||
|
|
||||||
|
// generate a challenge
|
||||||
|
let rho = transcript.squeeze(b"r")?;
|
||||||
|
let num_claims = w_vec_padded.len();
|
||||||
|
let powers_of_rho = powers(&rho, num_claims);
|
||||||
|
let claim_batch_joint = u_vec_padded
|
||||||
|
.iter()
|
||||||
|
.zip(powers_of_rho.iter())
|
||||||
|
.map(|(u, p)| u.e * p)
|
||||||
|
.fold(G::Scalar::zero(), |acc, item| acc + item);
|
||||||
|
|
||||||
|
let mut polys_left: Vec<MultilinearPolynomial<G::Scalar>> = w_vec_padded
|
||||||
|
.iter()
|
||||||
|
.map(|w| MultilinearPolynomial::new(w.p.clone()))
|
||||||
|
.collect();
|
||||||
|
let mut polys_right: Vec<MultilinearPolynomial<G::Scalar>> = u_vec_padded
|
||||||
|
.iter()
|
||||||
|
.map(|u| MultilinearPolynomial::new(EqPolynomial::new(u.x.clone()).evals()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let num_rounds_z = u_vec_padded[0].x.len();
|
||||||
|
let comb_func = |poly_A_comp: &G::Scalar, poly_B_comp: &G::Scalar| -> G::Scalar {
|
||||||
|
*poly_A_comp * *poly_B_comp
|
||||||
|
};
|
||||||
|
let (sc_proof_batch, r_z, claims_batch) = SumcheckProof::prove_quad_batch(
|
||||||
&claim_batch_joint,
|
&claim_batch_joint,
|
||||||
num_rounds_z,
|
num_rounds_z,
|
||||||
&mut MultilinearPolynomial::new(EqPolynomial::new(r_x.clone()).evals()),
|
&mut polys_left,
|
||||||
&mut MultilinearPolynomial::new(W.E.clone()),
|
&mut polys_right,
|
||||||
&mut MultilinearPolynomial::new(EqPolynomial::new(r_y[1..].to_vec()).evals()),
|
&powers_of_rho,
|
||||||
&mut MultilinearPolynomial::new(W.W.clone()),
|
|
||||||
comb_func,
|
comb_func,
|
||||||
&mut transcript,
|
&mut transcript,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let eval_E_prime = claims_batch[1];
|
let (claims_batch_left, _): (Vec<G::Scalar>, Vec<G::Scalar>) = claims_batch;
|
||||||
let eval_W_prime = claims_batch[3];
|
|
||||||
transcript.absorb(b"claims_batch", &[eval_E_prime, eval_W_prime].as_slice());
|
transcript.absorb(b"l", &claims_batch_left.as_slice());
|
||||||
|
|
||||||
// we now combine evaluation claims at the same point rz into one
|
// we now combine evaluation claims at the same point rz into one
|
||||||
let gamma = transcript.squeeze(b"gamma")?;
|
let gamma = transcript.squeeze(b"g")?;
|
||||||
let comm = U.comm_E + U.comm_W * gamma;
|
let powers_of_gamma: Vec<G::Scalar> = powers(&gamma, num_claims);
|
||||||
let poly = W
|
let comm_joint = u_vec_padded
|
||||||
.E
|
|
||||||
.iter()
|
.iter()
|
||||||
.zip(W.W.iter())
|
.zip(powers_of_gamma.iter())
|
||||||
.map(|(e, w)| *e + gamma * w)
|
.map(|(u, g_i)| u.c * *g_i)
|
||||||
.collect::<Vec<G::Scalar>>();
|
.fold(Commitment::<G>::default(), |acc, item| acc + item);
|
||||||
let eval = eval_E_prime + gamma * eval_W_prime;
|
let poly_joint = PolyEvalWitness::weighted_sum(&w_vec_padded, &powers_of_gamma);
|
||||||
|
let eval_joint = claims_batch_left
|
||||||
|
.iter()
|
||||||
|
.zip(powers_of_gamma.iter())
|
||||||
|
.map(|(e, g_i)| *e * *g_i)
|
||||||
|
.fold(G::Scalar::zero(), |acc, item| acc + item);
|
||||||
|
|
||||||
let eval_arg = EE::prove(ck, &pk.pk_ee, &mut transcript, &comm, &poly, &r_z, &eval)?;
|
let eval_arg = EE::prove(
|
||||||
|
ck,
|
||||||
|
&pk.pk_ee,
|
||||||
|
&mut transcript,
|
||||||
|
&comm_joint,
|
||||||
|
&poly_joint.p,
|
||||||
|
&r_z,
|
||||||
|
&eval_joint,
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(RelaxedR1CSSNARK {
|
Ok(RelaxedR1CSSNARK {
|
||||||
sc_proof_outer,
|
sc_proof_outer,
|
||||||
@@ -355,11 +475,10 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>, CC: CompCommitmentEngin
|
|||||||
eval_E,
|
eval_E,
|
||||||
sc_proof_inner,
|
sc_proof_inner,
|
||||||
eval_W,
|
eval_W,
|
||||||
sc_proof_batch,
|
|
||||||
eval_E_prime,
|
|
||||||
eval_W_prime,
|
|
||||||
eval_arg,
|
|
||||||
eval_arg_cc,
|
eval_arg_cc,
|
||||||
|
sc_proof_batch,
|
||||||
|
evals_batch: claims_batch_left,
|
||||||
|
eval_arg,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,25 +552,50 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>, CC: CompCommitmentEngin
|
|||||||
};
|
};
|
||||||
|
|
||||||
// verify evaluation argument to retrieve evaluations of R1CS matrices
|
// verify evaluation argument to retrieve evaluations of R1CS matrices
|
||||||
let (eval_A, eval_B, eval_C) = CC::verify(
|
let (eval_A, eval_B, eval_C, mut u_vec) =
|
||||||
&vk.vk_ee,
|
CC::verify(&vk.comm, &(&r_x, &r_y), &self.eval_arg_cc, &mut transcript)?;
|
||||||
&vk.comm,
|
|
||||||
&(&r_x, &r_y),
|
|
||||||
&self.eval_arg_cc,
|
|
||||||
&mut transcript,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let claim_inner_final_expected = (eval_A + r * eval_B + r * r * eval_C) * eval_Z;
|
let claim_inner_final_expected = (eval_A + r * eval_B + r * r * eval_C) * 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// batch sum-check
|
// add additional claims about W and E polynomials to the list from CC
|
||||||
transcript.absorb(b"eval_W", &self.eval_W);
|
u_vec.push(PolyEvalInstance {
|
||||||
|
c: U.comm_W,
|
||||||
|
x: r_y[1..].to_vec(),
|
||||||
|
e: self.eval_W,
|
||||||
|
});
|
||||||
|
|
||||||
let rho = transcript.squeeze(b"rho")?;
|
u_vec.push(PolyEvalInstance {
|
||||||
let claim_batch_joint = self.eval_E + rho * self.eval_W;
|
c: U.comm_E,
|
||||||
let num_rounds_z = num_rounds_x;
|
x: r_x,
|
||||||
|
e: self.eval_E,
|
||||||
|
});
|
||||||
|
|
||||||
|
let u_vec_padded = PolyEvalInstance::pad(&u_vec); // pad the evaluation points
|
||||||
|
|
||||||
|
let powers = |s: &G::Scalar, n: usize| -> Vec<G::Scalar> {
|
||||||
|
assert!(n >= 1);
|
||||||
|
let mut powers = Vec::new();
|
||||||
|
powers.push(G::Scalar::one());
|
||||||
|
for i in 1..n {
|
||||||
|
powers.push(powers[i - 1] * s);
|
||||||
|
}
|
||||||
|
powers
|
||||||
|
};
|
||||||
|
|
||||||
|
// generate a challenge
|
||||||
|
let rho = transcript.squeeze(b"r")?;
|
||||||
|
let num_claims = u_vec.len();
|
||||||
|
let powers_of_rho = powers(&rho, num_claims);
|
||||||
|
let claim_batch_joint = u_vec
|
||||||
|
.iter()
|
||||||
|
.zip(powers_of_rho.iter())
|
||||||
|
.map(|(u, p)| u.e * p)
|
||||||
|
.fold(G::Scalar::zero(), |acc, item| acc + item);
|
||||||
|
|
||||||
|
let num_rounds_z = u_vec_padded[0].x.len();
|
||||||
let (claim_batch_final, r_z) =
|
let (claim_batch_final, r_z) =
|
||||||
self
|
self
|
||||||
.sc_proof_batch
|
.sc_proof_batch
|
||||||
@@ -459,32 +603,47 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>, CC: CompCommitmentEngin
|
|||||||
|
|
||||||
let claim_batch_final_expected = {
|
let claim_batch_final_expected = {
|
||||||
let poly_rz = EqPolynomial::new(r_z.clone());
|
let poly_rz = EqPolynomial::new(r_z.clone());
|
||||||
let rz_rx = poly_rz.evaluate(&r_x);
|
let evals = u_vec_padded
|
||||||
let rz_ry = poly_rz.evaluate(&r_y[1..]);
|
.iter()
|
||||||
rz_rx * self.eval_E_prime + rho * rz_ry * self.eval_W_prime
|
.map(|u| poly_rz.evaluate(&u.x))
|
||||||
|
.collect::<Vec<G::Scalar>>();
|
||||||
|
|
||||||
|
evals
|
||||||
|
.iter()
|
||||||
|
.zip(self.evals_batch.iter())
|
||||||
|
.zip(powers_of_rho.iter())
|
||||||
|
.map(|((e_i, p_i), rho_i)| *e_i * *p_i * rho_i)
|
||||||
|
.fold(G::Scalar::zero(), |acc, item| acc + item)
|
||||||
};
|
};
|
||||||
|
|
||||||
if claim_batch_final != claim_batch_final_expected {
|
if claim_batch_final != claim_batch_final_expected {
|
||||||
return Err(NovaError::InvalidSumcheckProof);
|
return Err(NovaError::InvalidSumcheckProof);
|
||||||
}
|
}
|
||||||
|
|
||||||
transcript.absorb(
|
transcript.absorb(b"l", &self.evals_batch.as_slice());
|
||||||
b"claims_batch",
|
|
||||||
&[self.eval_E_prime, self.eval_W_prime].as_slice(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// we now combine evaluation claims at the same point rz into one
|
// we now combine evaluation claims at the same point rz into one
|
||||||
let gamma = transcript.squeeze(b"gamma")?;
|
let gamma = transcript.squeeze(b"g")?;
|
||||||
let comm = U.comm_E + U.comm_W * gamma;
|
let powers_of_gamma: Vec<G::Scalar> = powers(&gamma, num_claims);
|
||||||
let eval = self.eval_E_prime + gamma * self.eval_W_prime;
|
let comm_joint = u_vec_padded
|
||||||
|
.iter()
|
||||||
|
.zip(powers_of_gamma.iter())
|
||||||
|
.map(|(u, g_i)| u.c * *g_i)
|
||||||
|
.fold(Commitment::<G>::default(), |acc, item| acc + item);
|
||||||
|
let eval_joint = self
|
||||||
|
.evals_batch
|
||||||
|
.iter()
|
||||||
|
.zip(powers_of_gamma.iter())
|
||||||
|
.map(|(e, g_i)| *e * *g_i)
|
||||||
|
.fold(G::Scalar::zero(), |acc, item| acc + item);
|
||||||
|
|
||||||
// verify eval_W and eval_E
|
// verify
|
||||||
EE::verify(
|
EE::verify(
|
||||||
&vk.vk_ee,
|
&vk.vk_ee,
|
||||||
&mut transcript,
|
&mut transcript,
|
||||||
&comm,
|
&comm_joint,
|
||||||
&r_z,
|
&r_z,
|
||||||
&eval,
|
&eval_joint,
|
||||||
&self.eval_arg,
|
&self.eval_arg,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
errors::NovaError,
|
errors::NovaError,
|
||||||
r1cs::R1CSShape,
|
r1cs::R1CSShape,
|
||||||
spartan::{math::Math, CompCommitmentEngineTrait},
|
spartan::{math::Math, CompCommitmentEngineTrait, PolyEvalInstance, PolyEvalWitness},
|
||||||
traits::{evaluation::EvaluationEngineTrait, Group, TranscriptReprTrait},
|
traits::{evaluation::EvaluationEngineTrait, Group, TranscriptReprTrait},
|
||||||
CommitmentKey,
|
CommitmentKey,
|
||||||
};
|
};
|
||||||
@@ -43,7 +43,7 @@ impl<G: Group> TranscriptReprTrait<G> for TrivialCommitment<G> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> CompCommitmentEngineTrait<G, EE>
|
impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> CompCommitmentEngineTrait<G>
|
||||||
for TrivialCompComputationEngine<G, EE>
|
for TrivialCompComputationEngine<G, EE>
|
||||||
{
|
{
|
||||||
type Decommitment = TrivialDecommitment<G>;
|
type Decommitment = TrivialDecommitment<G>;
|
||||||
@@ -66,29 +66,36 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> CompCommitmentEngineTra
|
|||||||
/// proves an evaluation of R1CS matrices viewed as polynomials
|
/// proves an evaluation of R1CS matrices viewed as polynomials
|
||||||
fn prove(
|
fn prove(
|
||||||
_ck: &CommitmentKey<G>,
|
_ck: &CommitmentKey<G>,
|
||||||
_ek: &EE::ProverKey,
|
|
||||||
_S: &R1CSShape<G>,
|
_S: &R1CSShape<G>,
|
||||||
_decomm: &Self::Decommitment,
|
_decomm: &Self::Decommitment,
|
||||||
_comm: &Self::Commitment,
|
_comm: &Self::Commitment,
|
||||||
_r: &(&[G::Scalar], &[G::Scalar]),
|
_r: &(&[G::Scalar], &[G::Scalar]),
|
||||||
_transcript: &mut G::TE,
|
_transcript: &mut G::TE,
|
||||||
) -> Result<Self::EvaluationArgument, NovaError> {
|
) -> Result<
|
||||||
Ok(TrivialEvaluationArgument {
|
(
|
||||||
|
Self::EvaluationArgument,
|
||||||
|
Vec<(PolyEvalWitness<G>, PolyEvalInstance<G>)>,
|
||||||
|
),
|
||||||
|
NovaError,
|
||||||
|
> {
|
||||||
|
Ok((
|
||||||
|
TrivialEvaluationArgument {
|
||||||
_p: Default::default(),
|
_p: Default::default(),
|
||||||
})
|
},
|
||||||
|
Vec::new(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// verifies an evaluation of R1CS matrices viewed as polynomials
|
/// verifies an evaluation of R1CS matrices viewed as polynomials
|
||||||
fn verify(
|
fn verify(
|
||||||
_vk: &EE::VerifierKey,
|
|
||||||
comm: &Self::Commitment,
|
comm: &Self::Commitment,
|
||||||
r: &(&[G::Scalar], &[G::Scalar]),
|
r: &(&[G::Scalar], &[G::Scalar]),
|
||||||
_arg: &Self::EvaluationArgument,
|
_arg: &Self::EvaluationArgument,
|
||||||
_transcript: &mut G::TE,
|
_transcript: &mut G::TE,
|
||||||
) -> Result<(G::Scalar, G::Scalar, G::Scalar), NovaError> {
|
) -> Result<(G::Scalar, G::Scalar, G::Scalar, Vec<PolyEvalInstance<G>>), NovaError> {
|
||||||
let (r_x, r_y) = r;
|
let (r_x, r_y) = r;
|
||||||
let evals = SparsePolynomial::<G>::multi_evaluate(&[&comm.S.A, &comm.S.B, &comm.S.C], r_x, r_y);
|
let evals = SparsePolynomial::<G>::multi_evaluate(&[&comm.S.A, &comm.S.B, &comm.S.C], r_x, r_y);
|
||||||
Ok((evals[0], evals[1], evals[2]))
|
Ok((evals[0], evals[1], evals[2], Vec::new()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,9 +105,8 @@ mod sparse;
|
|||||||
use sparse::{SparseEvaluationArgument, SparsePolynomial, SparsePolynomialCommitment};
|
use sparse::{SparseEvaluationArgument, SparsePolynomial, SparsePolynomialCommitment};
|
||||||
|
|
||||||
/// A non-trivial implementation of `CompCommitmentEngineTrait` using Spartan's SPARK compiler
|
/// A non-trivial implementation of `CompCommitmentEngineTrait` using Spartan's SPARK compiler
|
||||||
pub struct SparkEngine<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
|
pub struct SparkEngine<G: Group> {
|
||||||
_p: PhantomData<G>,
|
_p: PhantomData<G>,
|
||||||
_p2: PhantomData<EE>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An implementation of Spark decommitment
|
/// An implementation of Spark decommitment
|
||||||
@@ -156,18 +162,16 @@ impl<G: Group> TranscriptReprTrait<G> for SparkCommitment<G> {
|
|||||||
/// Provides an implementation of a trivial evaluation argument
|
/// Provides an implementation of a trivial evaluation argument
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
#[serde(bound = "")]
|
#[serde(bound = "")]
|
||||||
pub struct SparkEvaluationArgument<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
|
pub struct SparkEvaluationArgument<G: Group> {
|
||||||
arg_A: SparseEvaluationArgument<G, EE>,
|
arg_A: SparseEvaluationArgument<G>,
|
||||||
arg_B: SparseEvaluationArgument<G, EE>,
|
arg_B: SparseEvaluationArgument<G>,
|
||||||
arg_C: SparseEvaluationArgument<G, EE>,
|
arg_C: SparseEvaluationArgument<G>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> CompCommitmentEngineTrait<G, EE>
|
impl<G: Group> CompCommitmentEngineTrait<G> for SparkEngine<G> {
|
||||||
for SparkEngine<G, EE>
|
|
||||||
{
|
|
||||||
type Decommitment = SparkDecommitment<G>;
|
type Decommitment = SparkDecommitment<G>;
|
||||||
type Commitment = SparkCommitment<G>;
|
type Commitment = SparkCommitment<G>;
|
||||||
type EvaluationArgument = SparkEvaluationArgument<G, EE>;
|
type EvaluationArgument = SparkEvaluationArgument<G>;
|
||||||
|
|
||||||
/// commits to R1CS matrices
|
/// commits to R1CS matrices
|
||||||
fn commit(
|
fn commit(
|
||||||
@@ -182,39 +186,60 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> CompCommitmentEngineTra
|
|||||||
/// proves an evaluation of R1CS matrices viewed as polynomials
|
/// proves an evaluation of R1CS matrices viewed as polynomials
|
||||||
fn prove(
|
fn prove(
|
||||||
ck: &CommitmentKey<G>,
|
ck: &CommitmentKey<G>,
|
||||||
pk_ee: &EE::ProverKey,
|
|
||||||
S: &R1CSShape<G>,
|
S: &R1CSShape<G>,
|
||||||
decomm: &Self::Decommitment,
|
decomm: &Self::Decommitment,
|
||||||
comm: &Self::Commitment,
|
comm: &Self::Commitment,
|
||||||
r: &(&[G::Scalar], &[G::Scalar]),
|
r: &(&[G::Scalar], &[G::Scalar]),
|
||||||
transcript: &mut G::TE,
|
transcript: &mut G::TE,
|
||||||
) -> Result<Self::EvaluationArgument, NovaError> {
|
) -> Result<
|
||||||
let arg_A =
|
(
|
||||||
SparseEvaluationArgument::prove(ck, pk_ee, &decomm.A, &S.A, &comm.comm_A, r, transcript)?;
|
Self::EvaluationArgument,
|
||||||
let arg_B =
|
Vec<(PolyEvalWitness<G>, PolyEvalInstance<G>)>,
|
||||||
SparseEvaluationArgument::prove(ck, pk_ee, &decomm.B, &S.B, &comm.comm_B, r, transcript)?;
|
),
|
||||||
let arg_C =
|
NovaError,
|
||||||
SparseEvaluationArgument::prove(ck, pk_ee, &decomm.C, &S.C, &comm.comm_C, r, transcript)?;
|
> {
|
||||||
|
let (arg_A, u_w_vec_A) =
|
||||||
|
SparseEvaluationArgument::prove(ck, &decomm.A, &S.A, &comm.comm_A, r, transcript)?;
|
||||||
|
let (arg_B, u_w_vec_B) =
|
||||||
|
SparseEvaluationArgument::prove(ck, &decomm.B, &S.B, &comm.comm_B, r, transcript)?;
|
||||||
|
let (arg_C, u_w_vec_C) =
|
||||||
|
SparseEvaluationArgument::prove(ck, &decomm.C, &S.C, &comm.comm_C, r, transcript)?;
|
||||||
|
|
||||||
Ok(SparkEvaluationArgument {
|
let u_w_vec = {
|
||||||
|
let mut u_w_vec = u_w_vec_A;
|
||||||
|
u_w_vec.extend(u_w_vec_B);
|
||||||
|
u_w_vec.extend(u_w_vec_C);
|
||||||
|
u_w_vec
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
SparkEvaluationArgument {
|
||||||
arg_A,
|
arg_A,
|
||||||
arg_B,
|
arg_B,
|
||||||
arg_C,
|
arg_C,
|
||||||
})
|
},
|
||||||
|
u_w_vec,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// verifies an evaluation of R1CS matrices viewed as polynomials
|
/// verifies an evaluation of R1CS matrices viewed as polynomials
|
||||||
fn verify(
|
fn verify(
|
||||||
vk_ee: &EE::VerifierKey,
|
|
||||||
comm: &Self::Commitment,
|
comm: &Self::Commitment,
|
||||||
r: &(&[G::Scalar], &[G::Scalar]),
|
r: &(&[G::Scalar], &[G::Scalar]),
|
||||||
arg: &Self::EvaluationArgument,
|
arg: &Self::EvaluationArgument,
|
||||||
transcript: &mut G::TE,
|
transcript: &mut G::TE,
|
||||||
) -> Result<(G::Scalar, G::Scalar, G::Scalar), NovaError> {
|
) -> Result<(G::Scalar, G::Scalar, G::Scalar, Vec<PolyEvalInstance<G>>), NovaError> {
|
||||||
let eval_A = arg.arg_A.verify(vk_ee, &comm.comm_A, r, transcript)?;
|
let (eval_A, u_vec_A) = arg.arg_A.verify(&comm.comm_A, r, transcript)?;
|
||||||
let eval_B = arg.arg_B.verify(vk_ee, &comm.comm_B, r, transcript)?;
|
let (eval_B, u_vec_B) = arg.arg_B.verify(&comm.comm_B, r, transcript)?;
|
||||||
let eval_C = arg.arg_C.verify(vk_ee, &comm.comm_C, r, transcript)?;
|
let (eval_C, u_vec_C) = arg.arg_C.verify(&comm.comm_C, r, transcript)?;
|
||||||
|
|
||||||
Ok((eval_A, eval_B, eval_C))
|
let u_vec = {
|
||||||
|
let mut u_vec = u_vec_A;
|
||||||
|
u_vec.extend(u_vec_B);
|
||||||
|
u_vec.extend(u_vec_C);
|
||||||
|
u_vec
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((eval_A, eval_B, eval_C, u_vec))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,9 @@ use crate::{
|
|||||||
math::Math,
|
math::Math,
|
||||||
polynomial::{EqPolynomial, MultilinearPolynomial},
|
polynomial::{EqPolynomial, MultilinearPolynomial},
|
||||||
spark::product::{IdentityPolynomial, ProductArgumentBatched},
|
spark::product::{IdentityPolynomial, ProductArgumentBatched},
|
||||||
SumcheckProof,
|
PolyEvalInstance, PolyEvalWitness, SumcheckProof,
|
||||||
},
|
|
||||||
traits::{
|
|
||||||
commitment::CommitmentEngineTrait, evaluation::EvaluationEngineTrait, Group,
|
|
||||||
TranscriptEngineTrait, TranscriptReprTrait,
|
|
||||||
},
|
},
|
||||||
|
traits::{commitment::CommitmentEngineTrait, Group, TranscriptEngineTrait, TranscriptReprTrait},
|
||||||
Commitment, CommitmentKey,
|
Commitment, CommitmentKey,
|
||||||
};
|
};
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
@@ -227,7 +224,7 @@ impl<G: Group> SparsePolynomial<G> {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
#[serde(bound = "")]
|
#[serde(bound = "")]
|
||||||
pub struct SparseEvaluationArgument<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
|
pub struct SparseEvaluationArgument<G: Group> {
|
||||||
// claimed evaluation
|
// claimed evaluation
|
||||||
eval: G::Scalar,
|
eval: G::Scalar,
|
||||||
|
|
||||||
@@ -240,7 +237,6 @@ pub struct SparseEvaluationArgument<G: Group, EE: EvaluationEngineTrait<G, CE =
|
|||||||
eval_E_row: G::Scalar,
|
eval_E_row: G::Scalar,
|
||||||
eval_E_col: G::Scalar,
|
eval_E_col: G::Scalar,
|
||||||
eval_val: G::Scalar,
|
eval_val: G::Scalar,
|
||||||
arg_eval: EE::EvaluationArgument,
|
|
||||||
|
|
||||||
// proof that E_row is well-formed
|
// proof that E_row is well-formed
|
||||||
eval_init_row: G::Scalar,
|
eval_init_row: G::Scalar,
|
||||||
@@ -262,24 +258,23 @@ pub struct SparseEvaluationArgument<G: Group, EE: EvaluationEngineTrait<G, CE =
|
|||||||
eval_col_read_ts: G::Scalar,
|
eval_col_read_ts: G::Scalar,
|
||||||
eval_E_col2: G::Scalar,
|
eval_E_col2: G::Scalar,
|
||||||
eval_col_audit_ts: G::Scalar,
|
eval_col_audit_ts: G::Scalar,
|
||||||
arg_row_col_joint: EE::EvaluationArgument,
|
|
||||||
arg_row_audit_ts: EE::EvaluationArgument,
|
|
||||||
arg_col_audit_ts: EE::EvaluationArgument,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> SparseEvaluationArgument<G, EE> {
|
impl<G: Group> SparseEvaluationArgument<G> {
|
||||||
pub fn prove(
|
pub fn prove(
|
||||||
ck: &CommitmentKey<G>,
|
ck: &CommitmentKey<G>,
|
||||||
pk_ee: &EE::ProverKey,
|
|
||||||
poly: &SparsePolynomial<G>,
|
poly: &SparsePolynomial<G>,
|
||||||
sparse: &[(usize, usize, G::Scalar)],
|
sparse: &[(usize, usize, G::Scalar)],
|
||||||
comm: &SparsePolynomialCommitment<G>,
|
comm: &SparsePolynomialCommitment<G>,
|
||||||
r: &(&[G::Scalar], &[G::Scalar]),
|
r: &(&[G::Scalar], &[G::Scalar]),
|
||||||
transcript: &mut G::TE,
|
transcript: &mut G::TE,
|
||||||
) -> Result<Self, NovaError> {
|
) -> Result<(Self, Vec<(PolyEvalWitness<G>, PolyEvalInstance<G>)>), NovaError> {
|
||||||
let (r_x, r_y) = r;
|
let (r_x, r_y) = r;
|
||||||
let eval = SparsePolynomial::<G>::multi_evaluate(&[sparse], r_x, r_y)[0];
|
let eval = SparsePolynomial::<G>::multi_evaluate(&[sparse], r_x, r_y)[0];
|
||||||
|
|
||||||
|
// keep track of evaluation claims
|
||||||
|
let mut w_u_vec: Vec<(PolyEvalWitness<G>, PolyEvalInstance<G>)> = Vec::new();
|
||||||
|
|
||||||
// compute oracles to prove the correctness of `eval`
|
// compute oracles to prove the correctness of `eval`
|
||||||
let (E_row, E_col, T_x, T_y) = SparsePolynomial::<G>::evaluation_oracles(sparse, r_x, r_y);
|
let (E_row, E_col, T_x, T_y) = SparsePolynomial::<G>::evaluation_oracles(sparse, r_x, r_y);
|
||||||
let val = poly.val.clone();
|
let val = poly.val.clone();
|
||||||
@@ -316,15 +311,16 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> SparseEvaluationArgumen
|
|||||||
.zip(val.iter())
|
.zip(val.iter())
|
||||||
.map(|((a, b), c)| *a + rho * *b + rho * rho * *c)
|
.map(|((a, b), c)| *a + rho * *b + rho * rho * *c)
|
||||||
.collect::<Vec<G::Scalar>>();
|
.collect::<Vec<G::Scalar>>();
|
||||||
let arg_eval = EE::prove(
|
|
||||||
ck,
|
// add the claim to prove for later
|
||||||
pk_ee,
|
w_u_vec.push((
|
||||||
transcript,
|
PolyEvalWitness { p: poly_eval },
|
||||||
&comm_joint,
|
PolyEvalInstance {
|
||||||
&poly_eval,
|
c: comm_joint,
|
||||||
&r_eval,
|
x: r_eval,
|
||||||
&eval_joint,
|
e: eval_joint,
|
||||||
)?;
|
},
|
||||||
|
));
|
||||||
|
|
||||||
// we now need to prove that E_row and E_col are well-formed
|
// we now need to prove that E_row and E_col are well-formed
|
||||||
// we use memory checking: H(INIT) * H(WS) =? H(RS) * H(FINAL)
|
// we use memory checking: H(INIT) * H(WS) =? H(RS) * H(FINAL)
|
||||||
@@ -462,37 +458,41 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> SparseEvaluationArgumen
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let arg_row_col_joint = EE::prove(
|
// add the claim to prove for later
|
||||||
ck,
|
w_u_vec.push((
|
||||||
pk_ee,
|
PolyEvalWitness { p: poly_joint },
|
||||||
transcript,
|
PolyEvalInstance {
|
||||||
&comm_joint,
|
c: comm_joint,
|
||||||
&poly_joint,
|
x: r_read_write_row_col,
|
||||||
&r_read_write_row_col,
|
e: eval_joint,
|
||||||
&eval_joint,
|
},
|
||||||
)?;
|
));
|
||||||
|
|
||||||
let arg_row_audit_ts = EE::prove(
|
transcript.absorb(b"a", &eval_row_audit_ts); // add evaluation to transcript, commitment is already in
|
||||||
ck,
|
w_u_vec.push((
|
||||||
pk_ee,
|
PolyEvalWitness {
|
||||||
transcript,
|
p: poly.row_audit_ts.clone(),
|
||||||
&comm.comm_row_audit_ts,
|
},
|
||||||
&poly.row_audit_ts,
|
PolyEvalInstance {
|
||||||
&r_init_audit_row,
|
c: comm.comm_row_audit_ts,
|
||||||
&eval_row_audit_ts,
|
x: r_init_audit_row,
|
||||||
)?;
|
e: eval_row_audit_ts,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
let arg_col_audit_ts = EE::prove(
|
transcript.absorb(b"a", &eval_col_audit_ts); // add evaluation to transcript, commitment is already in
|
||||||
ck,
|
w_u_vec.push((
|
||||||
pk_ee,
|
PolyEvalWitness {
|
||||||
transcript,
|
p: poly.col_audit_ts.clone(),
|
||||||
&comm.comm_col_audit_ts,
|
},
|
||||||
&poly.col_audit_ts,
|
PolyEvalInstance {
|
||||||
&r_init_audit_col,
|
c: comm.comm_col_audit_ts,
|
||||||
&eval_col_audit_ts,
|
x: r_init_audit_col,
|
||||||
)?;
|
e: eval_col_audit_ts,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
Ok(Self {
|
let eval_arg = Self {
|
||||||
// claimed evaluation
|
// claimed evaluation
|
||||||
eval,
|
eval,
|
||||||
|
|
||||||
@@ -505,7 +505,6 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> SparseEvaluationArgumen
|
|||||||
eval_E_row: claims_eval[0],
|
eval_E_row: claims_eval[0],
|
||||||
eval_E_col: claims_eval[1],
|
eval_E_col: claims_eval[1],
|
||||||
eval_val: claims_eval[2],
|
eval_val: claims_eval[2],
|
||||||
arg_eval,
|
|
||||||
|
|
||||||
// proof that E_row and E_row are well-formed
|
// proof that E_row and E_row are well-formed
|
||||||
eval_init_row: eval_init_audit_row[0],
|
eval_init_row: eval_init_audit_row[0],
|
||||||
@@ -527,21 +526,22 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> SparseEvaluationArgumen
|
|||||||
eval_col_read_ts,
|
eval_col_read_ts,
|
||||||
eval_E_col2,
|
eval_E_col2,
|
||||||
eval_col_audit_ts,
|
eval_col_audit_ts,
|
||||||
arg_row_col_joint,
|
};
|
||||||
arg_row_audit_ts,
|
|
||||||
arg_col_audit_ts,
|
Ok((eval_arg, w_u_vec))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify(
|
pub fn verify(
|
||||||
&self,
|
&self,
|
||||||
vk_ee: &EE::VerifierKey,
|
|
||||||
comm: &SparsePolynomialCommitment<G>,
|
comm: &SparsePolynomialCommitment<G>,
|
||||||
r: &(&[G::Scalar], &[G::Scalar]),
|
r: &(&[G::Scalar], &[G::Scalar]),
|
||||||
transcript: &mut G::TE,
|
transcript: &mut G::TE,
|
||||||
) -> Result<G::Scalar, NovaError> {
|
) -> Result<(G::Scalar, Vec<PolyEvalInstance<G>>), NovaError> {
|
||||||
let (r_x, r_y) = r;
|
let (r_x, r_y) = r;
|
||||||
|
|
||||||
|
// keep track of evaluation claims
|
||||||
|
let mut u_vec: Vec<PolyEvalInstance<G>> = Vec::new();
|
||||||
|
|
||||||
// append the transcript and scalar
|
// append the transcript and scalar
|
||||||
transcript.absorb(b"E", &vec![self.comm_E_row, self.comm_E_col].as_slice());
|
transcript.absorb(b"E", &vec![self.comm_E_row, self.comm_E_col].as_slice());
|
||||||
transcript.absorb(b"e", &self.eval);
|
transcript.absorb(b"e", &self.eval);
|
||||||
@@ -562,14 +562,13 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> SparseEvaluationArgumen
|
|||||||
let rho = transcript.squeeze(b"r")?;
|
let rho = transcript.squeeze(b"r")?;
|
||||||
let comm_joint = self.comm_E_row + self.comm_E_col * rho + comm.comm_val * rho * rho;
|
let comm_joint = self.comm_E_row + self.comm_E_col * rho + comm.comm_val * rho * rho;
|
||||||
let eval_joint = self.eval_E_row + rho * self.eval_E_col + rho * rho * self.eval_val;
|
let eval_joint = self.eval_E_row + rho * self.eval_E_col + rho * rho * self.eval_val;
|
||||||
EE::verify(
|
|
||||||
vk_ee,
|
// add the claim to prove for later
|
||||||
transcript,
|
u_vec.push(PolyEvalInstance {
|
||||||
&comm_joint,
|
c: comm_joint,
|
||||||
&r_eval,
|
x: r_eval,
|
||||||
&eval_joint,
|
e: eval_joint,
|
||||||
&self.arg_eval,
|
});
|
||||||
)?;
|
|
||||||
|
|
||||||
// (2) verify if E_row and E_col are well formed
|
// (2) verify if E_row and E_col are well formed
|
||||||
let gamma_1 = transcript.squeeze(b"g1")?;
|
let gamma_1 = transcript.squeeze(b"g1")?;
|
||||||
@@ -700,33 +699,26 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> SparseEvaluationArgumen
|
|||||||
+ comm.comm_col_read_ts * c * c * c * c
|
+ comm.comm_col_read_ts * c * c * c * c
|
||||||
+ self.comm_E_col * c * c * c * c * c;
|
+ self.comm_E_col * c * c * c * c * c;
|
||||||
|
|
||||||
EE::verify(
|
u_vec.push(PolyEvalInstance {
|
||||||
vk_ee,
|
c: comm_joint,
|
||||||
transcript,
|
x: r_read_write_row_col,
|
||||||
&comm_joint,
|
e: eval_joint,
|
||||||
&r_read_write_row_col,
|
});
|
||||||
&eval_joint,
|
|
||||||
&self.arg_row_col_joint,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
EE::verify(
|
transcript.absorb(b"a", &self.eval_row_audit_ts); // add evaluation to transcript, commitment is already in
|
||||||
vk_ee,
|
u_vec.push(PolyEvalInstance {
|
||||||
transcript,
|
c: comm.comm_row_audit_ts,
|
||||||
&comm.comm_row_audit_ts,
|
x: r_init_audit_row,
|
||||||
&r_init_audit_row,
|
e: self.eval_row_audit_ts,
|
||||||
&self.eval_row_audit_ts,
|
});
|
||||||
&self.arg_row_audit_ts,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
EE::verify(
|
transcript.absorb(b"a", &self.eval_col_audit_ts); // add evaluation to transcript, commitment is already in
|
||||||
vk_ee,
|
u_vec.push(PolyEvalInstance {
|
||||||
transcript,
|
c: comm.comm_col_audit_ts,
|
||||||
&comm.comm_col_audit_ts,
|
x: r_init_audit_col,
|
||||||
&r_init_audit_col,
|
e: self.eval_col_audit_ts,
|
||||||
&self.eval_col_audit_ts,
|
});
|
||||||
&self.arg_col_audit_ts,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(self.eval)
|
Ok((self.eval, u_vec))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,54 +126,52 @@ impl<G: Group> SumcheckProof<G> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prove_quad_sum<F>(
|
pub fn prove_quad_batch<F>(
|
||||||
claim: &G::Scalar,
|
claim: &G::Scalar,
|
||||||
num_rounds: usize,
|
num_rounds: usize,
|
||||||
poly_A: &mut MultilinearPolynomial<G::Scalar>,
|
poly_A_vec: &mut Vec<MultilinearPolynomial<G::Scalar>>,
|
||||||
poly_B: &mut MultilinearPolynomial<G::Scalar>,
|
poly_B_vec: &mut Vec<MultilinearPolynomial<G::Scalar>>,
|
||||||
poly_C: &mut MultilinearPolynomial<G::Scalar>,
|
coeffs: &[G::Scalar],
|
||||||
poly_D: &mut MultilinearPolynomial<G::Scalar>,
|
|
||||||
comb_func: F,
|
comb_func: F,
|
||||||
transcript: &mut G::TE,
|
transcript: &mut G::TE,
|
||||||
) -> Result<(Self, Vec<G::Scalar>, Vec<G::Scalar>), NovaError>
|
) -> Result<(Self, Vec<G::Scalar>, (Vec<G::Scalar>, Vec<G::Scalar>)), NovaError>
|
||||||
where
|
where
|
||||||
F: Fn(&G::Scalar, &G::Scalar, &G::Scalar, &G::Scalar) -> G::Scalar + Sync,
|
F: Fn(&G::Scalar, &G::Scalar) -> G::Scalar,
|
||||||
{
|
{
|
||||||
|
let mut e = *claim;
|
||||||
let mut r: Vec<G::Scalar> = Vec::new();
|
let mut r: Vec<G::Scalar> = Vec::new();
|
||||||
let mut polys: Vec<CompressedUniPoly<G>> = Vec::new();
|
let mut quad_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
|
for _j in 0..num_rounds {
|
||||||
let (eval_point_0, eval_point_2) = (0..len)
|
let mut evals: Vec<(G::Scalar, G::Scalar)> = Vec::new();
|
||||||
.into_par_iter()
|
|
||||||
.map(|i| {
|
for (poly_A, poly_B) in poly_A_vec.iter().zip(poly_B_vec.iter()) {
|
||||||
|
let mut eval_point_0 = G::Scalar::zero();
|
||||||
|
let mut eval_point_2 = G::Scalar::zero();
|
||||||
|
|
||||||
|
let len = poly_A.len() / 2;
|
||||||
|
for i in 0..len {
|
||||||
// eval 0: bound_func is A(low)
|
// 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_point_0 += comb_func(&poly_A[i], &poly_B[i]);
|
||||||
|
|
||||||
// eval 2: bound_func is -A(low) + 2*A(high)
|
// 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_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_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];
|
eval_point_2 += comb_func(&poly_A_bound_point, &poly_B_bound_point);
|
||||||
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];
|
evals.push((eval_point_0, eval_point_2));
|
||||||
UniPoly::from_evals(&evals)
|
}
|
||||||
};
|
|
||||||
|
let evals_combined_0 = (0..evals.len())
|
||||||
|
.map(|i| evals[i].0 * coeffs[i])
|
||||||
|
.fold(G::Scalar::zero(), |acc, item| acc + item);
|
||||||
|
let evals_combined_2 = (0..evals.len())
|
||||||
|
.map(|i| evals[i].1 * coeffs[i])
|
||||||
|
.fold(G::Scalar::zero(), |acc, item| acc + item);
|
||||||
|
|
||||||
|
let evals = vec![evals_combined_0, e - evals_combined_0, evals_combined_2];
|
||||||
|
let poly = UniPoly::from_evals(&evals);
|
||||||
|
|
||||||
// append the prover's message to the transcript
|
// append the prover's message to the transcript
|
||||||
transcript.absorb(b"p", &poly);
|
transcript.absorb(b"p", &poly);
|
||||||
@@ -181,25 +179,22 @@ impl<G: Group> SumcheckProof<G> {
|
|||||||
// derive the verifier's challenge for the next round
|
// derive the verifier's challenge for the next round
|
||||||
let r_i = transcript.squeeze(b"c")?;
|
let r_i = transcript.squeeze(b"c")?;
|
||||||
r.push(r_i);
|
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
|
// bound all tables to the verifier's challenege
|
||||||
|
for (poly_A, poly_B) in poly_A_vec.iter_mut().zip(poly_B_vec.iter_mut()) {
|
||||||
poly_A.bound_poly_var_top(&r_i);
|
poly_A.bound_poly_var_top(&r_i);
|
||||||
poly_B.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((
|
e = poly.evaluate(&r_i);
|
||||||
SumcheckProof {
|
quad_polys.push(poly.compress());
|
||||||
compressed_polys: polys,
|
}
|
||||||
},
|
|
||||||
r,
|
let poly_A_final = (0..poly_A_vec.len()).map(|i| poly_A_vec[i][0]).collect();
|
||||||
vec![poly_A[0], poly_B[0], poly_C[0], poly_D[0]],
|
let poly_B_final = (0..poly_B_vec.len()).map(|i| poly_B_vec[i][0]).collect();
|
||||||
))
|
let claims_prod = (poly_A_final, poly_B_final);
|
||||||
|
|
||||||
|
Ok((SumcheckProof::new(quad_polys), r, claims_prod))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prove_cubic_with_additive_term<F>(
|
pub fn prove_cubic_with_additive_term<F>(
|
||||||
|
|||||||
Reference in New Issue
Block a user