Merge pull request #139 from zcash/remove-eval-from-multiopen-prover

Remove eval from ProverQuery in multiopen
This commit is contained in:
ebfull 2021-01-14 08:33:54 -07:00 committed by GitHub
commit 6c6b30dde4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 211 additions and 149 deletions

View File

@ -55,11 +55,6 @@ pub(in crate::plonk) struct Constructed<C: CurveAffine> {
pub(in crate::plonk) struct Evaluated<C: CurveAffine> {
constructed: Constructed<C>,
product_eval: C::Scalar,
product_inv_eval: C::Scalar,
permuted_input_eval: C::Scalar,
permuted_input_inv_eval: C::Scalar,
permuted_table_eval: C::Scalar,
}
impl Argument {
@ -465,14 +460,7 @@ impl<C: CurveAffine> Constructed<C> {
.map_err(|_| Error::TranscriptError)?;
}
Ok(Evaluated {
constructed: self,
product_eval,
product_inv_eval,
permuted_input_eval,
permuted_input_inv_eval,
permuted_table_eval,
})
Ok(Evaluated { constructed: self })
}
}
@ -490,35 +478,30 @@ impl<C: CurveAffine> Evaluated<C> {
point: *x,
poly: &self.constructed.product_poly,
blind: self.constructed.product_blind,
eval: self.product_eval,
}))
// Open lookup input commitments at x
.chain(Some(ProverQuery {
point: *x,
poly: &self.constructed.permuted_input_poly,
blind: self.constructed.permuted_input_blind,
eval: self.permuted_input_eval,
}))
// Open lookup table commitments at x
.chain(Some(ProverQuery {
point: *x,
poly: &self.constructed.permuted_table_poly,
blind: self.constructed.permuted_table_blind,
eval: self.permuted_table_eval,
}))
// Open lookup input commitments at x_inv
.chain(Some(ProverQuery {
point: x_inv,
poly: &self.constructed.permuted_input_poly,
blind: self.constructed.permuted_input_blind,
eval: self.permuted_input_inv_eval,
}))
// Open lookup product commitments at x_inv
.chain(Some(ProverQuery {
point: x_inv,
poly: &self.constructed.product_poly,
blind: self.constructed.product_blind,
eval: self.product_inv_eval,
}))
}
}

View File

@ -27,9 +27,6 @@ pub(crate) struct Constructed<C: CurveAffine> {
pub(crate) struct Evaluated<C: CurveAffine> {
constructed: Constructed<C>,
permutation_product_eval: C::Scalar,
permutation_product_inv_eval: C::Scalar,
permutation_evals: Vec<C::Scalar>,
}
impl Argument {
@ -218,20 +215,12 @@ impl<C: CurveAffine> super::ProvingKey<C> {
.collect()
}
fn open<'a>(
&'a self,
evals: &'a [C::Scalar],
x: ChallengeX<C>,
) -> impl Iterator<Item = ProverQuery<'a, C>> + Clone {
self.polys
.iter()
.zip(evals.iter())
.map(move |(poly, eval)| ProverQuery {
point: *x,
poly,
blind: Blind::default(),
eval: *eval,
})
fn open<'a>(&'a self, x: ChallengeX<C>) -> impl Iterator<Item = ProverQuery<'a, C>> + Clone {
self.polys.iter().map(move |poly| ProverQuery {
point: *x,
poly,
blind: Blind::default(),
})
}
}
@ -265,12 +254,7 @@ impl<C: CurveAffine> Constructed<C> {
.map_err(|_| Error::TranscriptError)?;
}
Ok(Evaluated {
constructed: self,
permutation_product_eval,
permutation_product_inv_eval,
permutation_evals,
})
Ok(Evaluated { constructed: self })
}
}
@ -289,15 +273,13 @@ impl<C: CurveAffine> Evaluated<C> {
point: *x,
poly: &self.constructed.permutation_product_poly,
blind: self.constructed.permutation_product_blind,
eval: self.permutation_product_eval,
}))
.chain(Some(ProverQuery {
point: x_inv,
poly: &self.constructed.permutation_product_poly,
blind: self.constructed.permutation_product_blind,
eval: self.permutation_product_inv_eval,
}))
// Open permutation polynomial commitments at x
.chain(pkey.open(&self.permutation_evals, x))
.chain(pkey.open(x))
}
}

View File

@ -304,53 +304,51 @@ pub fn create_proof<C: CurveAffine, T: TranscriptWrite<C>, ConcreteCircuit: Circ
.map(|p| p.evaluate(pk, x, transcript))
.collect::<Result<Vec<_>, _>>()?;
let instances =
iter::empty()
.chain(pk.vk.cs.advice_queries.iter().enumerate().map(
|(query_index, &(column, at))| ProverQuery {
let instances = iter::empty()
.chain(
pk.vk
.cs
.advice_queries
.iter()
.map(|&(column, at)| ProverQuery {
point: domain.rotate_omega(*x, at),
poly: &advice_polys[column.index()],
blind: advice_blinds[column.index()],
eval: advice_evals[query_index],
},
))
.chain(
pk.vk
.cs
.aux_queries
.iter()
.enumerate()
.map(|(query_index, &(column, at))| ProverQuery {
point: domain.rotate_omega(*x, at),
poly: &aux_polys[column.index()],
blind: Blind::default(),
eval: aux_evals[query_index],
}),
)
.chain(
pk.vk
.cs
.fixed_queries
.iter()
.enumerate()
.map(|(query_index, &(column, at))| ProverQuery {
point: domain.rotate_omega(*x, at),
poly: &pk.fixed_polys[column.index()],
blind: Blind::default(),
eval: fixed_evals[query_index],
}),
)
// We query the h(X) polynomial at x
.chain(vanishing.open(x))
.chain(
permutations
.iter()
.zip(pk.permutations.iter())
.map(|(p, pkey)| p.open(pk, pkey, x))
.into_iter()
.flatten(),
)
.chain(lookups.iter().map(|p| p.open(pk, x)).into_iter().flatten());
}),
)
.chain(
pk.vk
.cs
.aux_queries
.iter()
.map(|&(column, at)| ProverQuery {
point: domain.rotate_omega(*x, at),
poly: &aux_polys[column.index()],
blind: Blind::default(),
}),
)
.chain(
pk.vk
.cs
.fixed_queries
.iter()
.map(|&(column, at)| ProverQuery {
point: domain.rotate_omega(*x, at),
poly: &pk.fixed_polys[column.index()],
blind: Blind::default(),
}),
)
// We query the h(X) polynomial at x
.chain(vanishing.open(x))
.chain(
permutations
.iter()
.zip(pk.permutations.iter())
.map(|(p, pkey)| p.open(pk, pkey, x))
.into_iter()
.flatten(),
)
.chain(lookups.iter().map(|p| p.open(pk, x)).into_iter().flatten());
multiopen::create_proof(params, transcript, instances).map_err(|_| Error::OpeningError)
}

View File

@ -17,7 +17,6 @@ pub(in crate::plonk) struct Constructed<C: CurveAffine> {
pub(in crate::plonk) struct Evaluated<C: CurveAffine> {
constructed: Constructed<C>,
h_evals: Vec<C::Scalar>,
}
impl<C: CurveAffine> Argument<C> {
@ -85,10 +84,7 @@ impl<C: CurveAffine> Constructed<C> {
.map_err(|_| Error::TranscriptError)?;
}
Ok(Evaluated {
constructed: self,
h_evals,
})
Ok(Evaluated { constructed: self })
}
}
@ -101,12 +97,10 @@ impl<C: CurveAffine> Evaluated<C> {
.h_pieces
.iter()
.zip(self.constructed.h_blinds.iter())
.zip(self.h_evals.iter())
.map(move |((h_poly, h_blind), h_eval)| ProverQuery {
.map(move |(h_poly, h_blind)| ProverQuery {
point: *x,
poly: h_poly,
blind: *h_blind,
eval: *h_eval,
})
}
}

View File

@ -3,7 +3,6 @@
//!
//! [halo]: https://eprint.iacr.org/2019/1021
use ff::Field;
use std::collections::{BTreeMap, BTreeSet};
use super::*;
@ -48,8 +47,6 @@ pub struct ProverQuery<'a, C: CurveAffine> {
pub poly: &'a Polynomial<C::Scalar, Coeff>,
/// blinding factor of polynomial
pub blind: commitment::Blind<C::Scalar>,
/// evaluation of polynomial at query point
pub eval: C::Scalar,
}
/// A polynomial query at a point
@ -63,14 +60,14 @@ pub struct VerifierQuery<'a, C: CurveAffine> {
pub eval: C::Scalar,
}
struct CommitmentData<F: Field, T: PartialEq> {
struct CommitmentData<F, T: PartialEq> {
commitment: T,
set_index: usize,
point_indices: Vec<usize>,
evals: Vec<F>,
}
impl<F: Field, T: PartialEq> CommitmentData<F, T> {
impl<F, T: PartialEq> CommitmentData<F, T> {
fn new(commitment: T) -> Self {
CommitmentData {
commitment,
@ -83,21 +80,22 @@ impl<F: Field, T: PartialEq> CommitmentData<F, T> {
trait Query<F>: Sized {
type Commitment: PartialEq + Copy;
type Eval: Clone + Default;
fn get_point(&self) -> F;
fn get_eval(&self) -> F;
fn get_eval(&self) -> Self::Eval;
fn get_commitment(&self) -> Self::Commitment;
}
fn construct_intermediate_sets<F: FieldExt, I, Q: Query<F>>(
queries: I,
) -> (Vec<CommitmentData<F, Q::Commitment>>, Vec<Vec<F>>)
) -> (Vec<CommitmentData<Q::Eval, Q::Commitment>>, Vec<Vec<F>>)
where
I: IntoIterator<Item = Q> + Clone,
{
// Construct sets of unique commitments and corresponding information about
// their queries.
let mut commitment_map: Vec<CommitmentData<F, Q::Commitment>> = vec![];
let mut commitment_map: Vec<CommitmentData<Q::Eval, Q::Commitment>> = vec![];
// Also construct mapping from a unique point to a point_index. This defines
// an ordering on the points.
@ -151,7 +149,7 @@ where
// Initialise empty evals vec for each unique commitment
for commitment_data in commitment_map.iter_mut() {
let len = commitment_data.point_indices.len();
commitment_data.evals = vec![F::zero(); len];
commitment_data.evals = vec![Q::Eval::default(); len];
}
// Populate set_index, evals and points for each commitment using point_idx_sets
@ -203,6 +201,134 @@ where
(commitment_map, point_sets)
}
#[test]
fn test_roundtrip() {
use super::commitment::{Blind, Params};
use crate::arithmetic::{eval_polynomial, Curve, FieldExt};
use crate::pasta::{EqAffine, Fp};
const K: u32 = 4;
let params: Params<EqAffine> = Params::new(K);
let domain = EvaluationDomain::new(1, K);
let mut ax = domain.empty_coeff();
for (i, a) in ax.iter_mut().enumerate() {
*a = Fp::from(10 + i as u64);
}
let mut bx = domain.empty_coeff();
for (i, a) in bx.iter_mut().enumerate() {
*a = Fp::from(100 + i as u64);
}
let mut cx = domain.empty_coeff();
for (i, a) in cx.iter_mut().enumerate() {
*a = Fp::from(100 + i as u64);
}
let blind = Blind(Fp::rand());
let a = params.commit(&ax, blind).to_affine();
let b = params.commit(&bx, blind).to_affine();
let c = params.commit(&cx, blind).to_affine();
let x = Fp::rand();
let y = Fp::rand();
let avx = eval_polynomial(&ax, x);
let bvx = eval_polynomial(&bx, x);
let cvy = eval_polynomial(&cx, y);
let mut transcript = crate::transcript::DummyHashWrite::init(vec![], Field::one());
create_proof(
&params,
&mut transcript,
std::iter::empty()
.chain(Some(ProverQuery {
point: x,
poly: &ax,
blind,
}))
.chain(Some(ProverQuery {
point: x,
poly: &bx,
blind,
}))
.chain(Some(ProverQuery {
point: y,
poly: &cx,
blind,
})),
)
.unwrap();
let proof = transcript.finalize();
{
let mut proof = &proof[..];
let mut transcript = crate::transcript::DummyHashRead::init(&mut proof, Field::one());
let msm = params.empty_msm();
let guard = verify_proof(
&params,
&mut transcript,
std::iter::empty()
.chain(Some(VerifierQuery {
point: x,
commitment: &a,
eval: avx,
}))
.chain(Some(VerifierQuery {
point: x,
commitment: &b,
eval: avx, // NB: wrong!
}))
.chain(Some(VerifierQuery {
point: y,
commitment: &c,
eval: cvy,
})),
msm,
)
.unwrap();
// Should fail.
assert!(!guard.use_challenges().eval());
}
{
let mut proof = &proof[..];
let mut transcript = crate::transcript::DummyHashRead::init(&mut proof, Field::one());
let msm = params.empty_msm();
let guard = verify_proof(
&params,
&mut transcript,
std::iter::empty()
.chain(Some(VerifierQuery {
point: x,
commitment: &a,
eval: avx,
}))
.chain(Some(VerifierQuery {
point: x,
commitment: &b,
eval: bvx,
}))
.chain(Some(VerifierQuery {
point: y,
commitment: &c,
eval: cvy,
})),
msm,
)
.unwrap();
// Should succeed.
assert!(guard.use_challenges().eval());
}
}
#[cfg(test)]
mod tests {
use super::{construct_intermediate_sets, Query};
@ -216,14 +342,15 @@ mod tests {
eval: F,
}
impl<F: Copy> Query<F> for MyQuery<F> {
impl<F: Clone + Default> Query<F> for MyQuery<F> {
type Commitment = usize;
type Eval = F;
fn get_point(&self) -> F {
self.point
self.point.clone()
}
fn get_eval(&self) -> F {
self.eval
fn get_eval(&self) -> Self::Eval {
self.eval.clone()
}
fn get_commitment(&self) -> Self::Commitment {
self.commitment

View File

@ -7,9 +7,7 @@ use super::{
Query,
};
use crate::arithmetic::{
eval_polynomial, kate_division, lagrange_interpolate, Curve, CurveAffine, FieldExt,
};
use crate::arithmetic::{eval_polynomial, kate_division, Curve, CurveAffine, FieldExt};
use crate::transcript::TranscriptWrite;
use ff::Field;
@ -43,56 +41,36 @@ where
let mut q_polys: Vec<Option<Polynomial<C::Scalar, Coeff>>> = vec![None; point_sets.len()];
let mut q_blinds = vec![Blind(C::Scalar::zero()); point_sets.len()];
// A vec of vecs of evals. The outer vec corresponds to the point set,
// while the inner vec corresponds to the points in a particular set.
let mut q_eval_sets = Vec::with_capacity(point_sets.len());
for point_set in point_sets.iter() {
q_eval_sets.push(vec![C::Scalar::zero(); point_set.len()]);
}
{
let mut accumulate = |set_idx: usize,
new_poly: &Polynomial<C::Scalar, Coeff>,
blind: Blind<C::Scalar>,
evals: Vec<C::Scalar>| {
if let Some(poly) = &q_polys[set_idx] {
q_polys[set_idx] = Some(poly.clone() * *x_1 + new_poly);
} else {
q_polys[set_idx] = Some(new_poly.clone());
}
q_blinds[set_idx] *= *x_1;
q_blinds[set_idx] += blind;
// Each polynomial is evaluated at a set of points. For each set,
// we collapse each polynomial's evals pointwise.
for (eval, set_eval) in evals.iter().zip(q_eval_sets[set_idx].iter_mut()) {
*set_eval *= &(*x_1);
*set_eval += eval;
}
};
let mut accumulate =
|set_idx: usize, new_poly: &Polynomial<C::Scalar, Coeff>, blind: Blind<C::Scalar>| {
if let Some(poly) = &q_polys[set_idx] {
q_polys[set_idx] = Some(poly.clone() * *x_1 + new_poly);
} else {
q_polys[set_idx] = Some(new_poly.clone());
}
q_blinds[set_idx] *= *x_1;
q_blinds[set_idx] += blind;
};
for commitment_data in poly_map.into_iter() {
accumulate(
commitment_data.set_index, // set_idx,
commitment_data.commitment.poly, // poly,
commitment_data.commitment.blind, // blind,
commitment_data.evals, // evals
);
}
}
let f_poly = point_sets
.iter()
.zip(q_eval_sets.iter())
.zip(q_polys.iter())
.fold(None, |f_poly, ((points, evals), poly)| {
let mut poly = poly.clone().unwrap().values;
// TODO: makes implicit asssumption that poly degree is smaller than interpolation poly degree
for (p, r) in poly.iter_mut().zip(lagrange_interpolate(points, evals)) {
*p -= &r;
}
.fold(None, |f_poly, (points, poly)| {
let mut poly = points
.iter()
.fold(poly, |poly, point| kate_division(&poly, *point));
.fold(poly.clone().unwrap().values, |poly, point| {
kate_division(&poly, *point)
});
poly.resize(params.n as usize, C::Scalar::zero());
let poly = Polynomial {
values: poly,
@ -153,13 +131,12 @@ impl<'a, C: CurveAffine> PartialEq for PolynomialPointer<'a, C> {
impl<'a, C: CurveAffine> Query<C::Scalar> for ProverQuery<'a, C> {
type Commitment = PolynomialPointer<'a, C>;
type Eval = ();
fn get_point(&self) -> C::Scalar {
self.point
}
fn get_eval(&self) -> C::Scalar {
self.eval
}
fn get_eval(&self) -> () {}
fn get_commitment(&self) -> Self::Commitment {
PolynomialPointer {
poly: self.poly,

View File

@ -133,6 +133,7 @@ impl<'a, C> PartialEq for CommitmentPointer<'a, C> {
impl<'a, C: CurveAffine> Query<C::Scalar> for VerifierQuery<'a, C> {
type Commitment = CommitmentPointer<'a, C>;
type Eval = C::Scalar;
fn get_point(&self) -> C::Scalar {
self.point