mirror of https://github.com/zcash/halo2.git
Allow MSMs to be queried and not just raw commitments.
This allows us to avoid some interstitial arithmetic in the vanishing argument.
This commit is contained in:
parent
f7ef626858
commit
fd91b6b42c
|
@ -168,43 +168,43 @@ impl<C: CurveAffine> Evaluated<C> {
|
|||
))
|
||||
}
|
||||
|
||||
pub(in crate::plonk) fn queries<'a>(
|
||||
&'a self,
|
||||
vk: &'a VerifyingKey<C>,
|
||||
pub(in crate::plonk) fn queries<'r, 'params: 'r>(
|
||||
&'r self,
|
||||
vk: &'r VerifyingKey<C>,
|
||||
x: ChallengeX<C>,
|
||||
) -> impl Iterator<Item = VerifierQuery<'a, C>> + Clone {
|
||||
) -> impl Iterator<Item = VerifierQuery<'r, 'params, C>> + Clone {
|
||||
let x_inv = vk.domain.rotate_omega(*x, Rotation(-1));
|
||||
|
||||
iter::empty()
|
||||
// Open lookup product commitments at x
|
||||
.chain(Some(VerifierQuery {
|
||||
point: *x,
|
||||
commitment: &self.committed.product_commitment,
|
||||
eval: self.product_eval,
|
||||
}))
|
||||
.chain(Some(VerifierQuery::new_commitment(
|
||||
&self.committed.product_commitment,
|
||||
*x,
|
||||
self.product_eval,
|
||||
)))
|
||||
// Open lookup input commitments at x
|
||||
.chain(Some(VerifierQuery {
|
||||
point: *x,
|
||||
commitment: &self.committed.permuted.permuted_input_commitment,
|
||||
eval: self.permuted_input_eval,
|
||||
}))
|
||||
.chain(Some(VerifierQuery::new_commitment(
|
||||
&self.committed.permuted.permuted_input_commitment,
|
||||
*x,
|
||||
self.permuted_input_eval,
|
||||
)))
|
||||
// Open lookup table commitments at x
|
||||
.chain(Some(VerifierQuery {
|
||||
point: *x,
|
||||
commitment: &self.committed.permuted.permuted_table_commitment,
|
||||
eval: self.permuted_table_eval,
|
||||
}))
|
||||
.chain(Some(VerifierQuery::new_commitment(
|
||||
&self.committed.permuted.permuted_table_commitment,
|
||||
*x,
|
||||
self.permuted_table_eval,
|
||||
)))
|
||||
// Open lookup input commitments at \omega^{-1} x
|
||||
.chain(Some(VerifierQuery {
|
||||
point: x_inv,
|
||||
commitment: &self.committed.permuted.permuted_input_commitment,
|
||||
eval: self.permuted_input_inv_eval,
|
||||
}))
|
||||
.chain(Some(VerifierQuery::new_commitment(
|
||||
&self.committed.permuted.permuted_input_commitment,
|
||||
x_inv,
|
||||
self.permuted_input_inv_eval,
|
||||
)))
|
||||
// Open lookup product commitments at \omega^{-1} x
|
||||
.chain(Some(VerifierQuery {
|
||||
point: x_inv,
|
||||
commitment: &self.committed.product_commitment,
|
||||
eval: self.product_inv_eval,
|
||||
}))
|
||||
.chain(Some(VerifierQuery::new_commitment(
|
||||
&self.committed.product_commitment,
|
||||
x_inv,
|
||||
self.product_inv_eval,
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,35 +128,33 @@ impl<C: CurveAffine> Evaluated<C> {
|
|||
}))
|
||||
}
|
||||
|
||||
pub(in crate::plonk) fn queries<'a>(
|
||||
&'a self,
|
||||
vk: &'a plonk::VerifyingKey<C>,
|
||||
vkey: &'a VerifyingKey<C>,
|
||||
pub(in crate::plonk) fn queries<'r, 'params: 'r>(
|
||||
&'r self,
|
||||
vk: &'r plonk::VerifyingKey<C>,
|
||||
vkey: &'r VerifyingKey<C>,
|
||||
x: ChallengeX<C>,
|
||||
) -> impl Iterator<Item = VerifierQuery<'a, C>> + Clone {
|
||||
) -> impl Iterator<Item = VerifierQuery<'r, 'params, C>> + Clone {
|
||||
let x_inv = vk.domain.rotate_omega(*x, Rotation(-1));
|
||||
|
||||
iter::empty()
|
||||
// Open permutation product commitments at x and \omega^{-1} x
|
||||
.chain(Some(VerifierQuery {
|
||||
point: *x,
|
||||
commitment: &self.permutation_product_commitment,
|
||||
eval: self.permutation_product_eval,
|
||||
}))
|
||||
.chain(Some(VerifierQuery {
|
||||
point: x_inv,
|
||||
commitment: &self.permutation_product_commitment,
|
||||
eval: self.permutation_product_inv_eval,
|
||||
}))
|
||||
.chain(Some(VerifierQuery::new_commitment(
|
||||
&self.permutation_product_commitment,
|
||||
*x,
|
||||
self.permutation_product_eval,
|
||||
)))
|
||||
.chain(Some(VerifierQuery::new_commitment(
|
||||
&self.permutation_product_commitment,
|
||||
x_inv,
|
||||
self.permutation_product_inv_eval,
|
||||
)))
|
||||
// Open permutation commitments for each permutation argument at x
|
||||
.chain(
|
||||
vkey.commitments
|
||||
.iter()
|
||||
.zip(self.permutation_evals.iter())
|
||||
.map(move |(commitment, &eval)| VerifierQuery {
|
||||
point: *x,
|
||||
commitment,
|
||||
eval,
|
||||
.map(move |(commitment, &eval)| {
|
||||
VerifierQuery::new_commitment(commitment, *x, eval)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
use ff::Field;
|
||||
use group::{Curve, Group};
|
||||
|
||||
use crate::{
|
||||
arithmetic::CurveAffine,
|
||||
plonk::{Error, VerifyingKey},
|
||||
poly::multiopen::VerifierQuery,
|
||||
poly::{
|
||||
commitment::{Params, MSM},
|
||||
multiopen::VerifierQuery,
|
||||
},
|
||||
transcript::{read_n_points, EncodedChallenge, TranscriptRead},
|
||||
};
|
||||
|
||||
|
@ -15,8 +17,8 @@ pub struct Committed<C: CurveAffine> {
|
|||
h_commitments: Vec<C>,
|
||||
}
|
||||
|
||||
pub struct Evaluated<C: CurveAffine> {
|
||||
h_commitment: C,
|
||||
pub struct Evaluated<'params, C: CurveAffine> {
|
||||
h_commitment: MSM<'params, C>,
|
||||
expected_h_eval: C::Scalar,
|
||||
}
|
||||
|
||||
|
@ -34,23 +36,25 @@ impl<C: CurveAffine> Argument<C> {
|
|||
}
|
||||
|
||||
impl<C: CurveAffine> Committed<C> {
|
||||
pub(in crate::plonk) fn verify(
|
||||
pub(in crate::plonk) fn verify<'params>(
|
||||
self,
|
||||
params: &'params Params<C>,
|
||||
expressions: impl Iterator<Item = C::Scalar>,
|
||||
y: ChallengeY<C>,
|
||||
xn: C::Scalar,
|
||||
) -> Result<Evaluated<C>, Error> {
|
||||
) -> Result<Evaluated<'params, C>, Error> {
|
||||
let expected_h_eval = expressions.fold(C::Scalar::zero(), |h_eval, v| h_eval * &*y + &v);
|
||||
let expected_h_eval = expected_h_eval * ((xn - C::Scalar::one()).invert().unwrap());
|
||||
|
||||
let h_commitment = self
|
||||
.h_commitments
|
||||
let h_commitment =
|
||||
self.h_commitments
|
||||
.iter()
|
||||
.rev()
|
||||
.fold(C::CurveExt::identity(), |acc, eval| {
|
||||
acc * xn + eval.to_curve()
|
||||
})
|
||||
.to_affine();
|
||||
.fold(params.empty_msm(), |mut acc, commitment| {
|
||||
acc.scale(xn);
|
||||
acc.append_term(C::Scalar::one(), *commitment);
|
||||
acc
|
||||
});
|
||||
|
||||
Ok(Evaluated {
|
||||
expected_h_eval,
|
||||
|
@ -59,16 +63,19 @@ impl<C: CurveAffine> Committed<C> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<C: CurveAffine> Evaluated<C> {
|
||||
pub(in crate::plonk) fn queries(
|
||||
&self,
|
||||
impl<'params, C: CurveAffine> Evaluated<'params, C> {
|
||||
pub(in crate::plonk) fn queries<'r>(
|
||||
&'r self,
|
||||
x: ChallengeX<C>,
|
||||
) -> impl Iterator<Item = VerifierQuery<'_, C>> + Clone {
|
||||
Some(VerifierQuery {
|
||||
point: *x,
|
||||
commitment: &self.h_commitment,
|
||||
eval: self.expected_h_eval,
|
||||
})
|
||||
) -> impl Iterator<Item = VerifierQuery<'r, 'params, C>> + Clone
|
||||
where
|
||||
'params: 'r,
|
||||
{
|
||||
Some(VerifierQuery::new_msm(
|
||||
&self.h_commitment,
|
||||
*x,
|
||||
self.expected_h_eval,
|
||||
))
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,13 +13,13 @@ use crate::poly::{
|
|||
use crate::transcript::{read_n_points, read_n_scalars, EncodedChallenge, TranscriptRead};
|
||||
|
||||
/// Returns a boolean indicating whether or not the proof is valid
|
||||
pub fn verify_proof<'a, C: CurveAffine, E: EncodedChallenge<C>, T: TranscriptRead<C, E>>(
|
||||
params: &'a Params<C>,
|
||||
pub fn verify_proof<'params, C: CurveAffine, E: EncodedChallenge<C>, T: TranscriptRead<C, E>>(
|
||||
params: &'params Params<C>,
|
||||
vk: &VerifyingKey<C>,
|
||||
msm: MSM<'a, C>,
|
||||
msm: MSM<'params, C>,
|
||||
instance_commitments: &[&[C]],
|
||||
transcript: &mut T,
|
||||
) -> Result<Guard<'a, C, E>, Error> {
|
||||
) -> Result<Guard<'params, C, E>, Error> {
|
||||
// Check that instance_commitments matches the expected number of instance columns
|
||||
for instance_commitments in instance_commitments.iter() {
|
||||
if instance_commitments.len() != vk.cs.num_instance_columns {
|
||||
|
@ -217,7 +217,7 @@ pub fn verify_proof<'a, C: CurveAffine, E: EncodedChallenge<C>, T: TranscriptRea
|
|||
},
|
||||
);
|
||||
|
||||
vanishing.verify(expressions, y, xn)?
|
||||
vanishing.verify(params, expressions, y, xn)?
|
||||
};
|
||||
|
||||
let queries = instance_commitments
|
||||
|
@ -237,17 +237,21 @@ pub fn verify_proof<'a, C: CurveAffine, E: EncodedChallenge<C>, T: TranscriptRea
|
|||
)| {
|
||||
iter::empty()
|
||||
.chain(vk.cs.instance_queries.iter().enumerate().map(
|
||||
move |(query_index, &(column, at))| VerifierQuery {
|
||||
point: vk.domain.rotate_omega(*x, at),
|
||||
commitment: &instance_commitments[column.index()],
|
||||
eval: instance_evals[query_index],
|
||||
move |(query_index, &(column, at))| {
|
||||
VerifierQuery::new_commitment(
|
||||
&instance_commitments[column.index()],
|
||||
vk.domain.rotate_omega(*x, at),
|
||||
instance_evals[query_index],
|
||||
)
|
||||
},
|
||||
))
|
||||
.chain(vk.cs.advice_queries.iter().enumerate().map(
|
||||
move |(query_index, &(column, at))| VerifierQuery {
|
||||
point: vk.domain.rotate_omega(*x, at),
|
||||
commitment: &advice_commitments[column.index()],
|
||||
eval: advice_evals[query_index],
|
||||
move |(query_index, &(column, at))| {
|
||||
VerifierQuery::new_commitment(
|
||||
&advice_commitments[column.index()],
|
||||
vk.domain.rotate_omega(*x, at),
|
||||
advice_evals[query_index],
|
||||
)
|
||||
},
|
||||
))
|
||||
.chain(
|
||||
|
@ -270,10 +274,12 @@ pub fn verify_proof<'a, C: CurveAffine, E: EncodedChallenge<C>, T: TranscriptRea
|
|||
.fixed_queries
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(query_index, &(column, at))| VerifierQuery {
|
||||
point: vk.domain.rotate_omega(*x, at),
|
||||
commitment: &vk.fixed_commitments[column.index()],
|
||||
eval: fixed_evals[query_index],
|
||||
.map(|(query_index, &(column, at))| {
|
||||
VerifierQuery::new_commitment(
|
||||
&vk.fixed_commitments[column.index()],
|
||||
vk.domain.rotate_omega(*x, at),
|
||||
fixed_evals[query_index],
|
||||
)
|
||||
}),
|
||||
)
|
||||
.chain(vanishing.queries(x));
|
||||
|
|
|
@ -51,13 +51,55 @@ pub struct ProverQuery<'a, C: CurveAffine> {
|
|||
|
||||
/// A polynomial query at a point
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VerifierQuery<'a, C: CurveAffine> {
|
||||
pub struct VerifierQuery<'r, 'params: 'r, C: CurveAffine> {
|
||||
/// point at which polynomial is queried
|
||||
pub point: C::Scalar,
|
||||
point: C::Scalar,
|
||||
/// commitment to polynomial
|
||||
pub commitment: &'a C,
|
||||
commitment: CommitmentReference<'r, 'params, C>,
|
||||
/// evaluation of polynomial at query point
|
||||
pub eval: C::Scalar,
|
||||
eval: C::Scalar,
|
||||
}
|
||||
|
||||
impl<'r, 'params: 'r, C: CurveAffine> VerifierQuery<'r, 'params, C> {
|
||||
/// Create a new verifier query based on a commitment
|
||||
pub fn new_commitment(commitment: &'r C, point: C::Scalar, eval: C::Scalar) -> Self {
|
||||
VerifierQuery {
|
||||
point,
|
||||
eval,
|
||||
commitment: CommitmentReference::Commitment(commitment),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new verifier query based on a linear combination of commitments
|
||||
pub fn new_msm(
|
||||
msm: &'r commitment::MSM<'params, C>,
|
||||
point: C::Scalar,
|
||||
eval: C::Scalar,
|
||||
) -> Self {
|
||||
VerifierQuery {
|
||||
point,
|
||||
eval,
|
||||
commitment: CommitmentReference::MSM(msm),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum CommitmentReference<'r, 'params: 'r, C: CurveAffine> {
|
||||
Commitment(&'r C),
|
||||
MSM(&'r commitment::MSM<'params, C>),
|
||||
}
|
||||
|
||||
impl<'r, 'params: 'r, C: CurveAffine> PartialEq for CommitmentReference<'r, 'params, C> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(&CommitmentReference::Commitment(a), &CommitmentReference::Commitment(b)) => {
|
||||
std::ptr::eq(a, b)
|
||||
}
|
||||
(&CommitmentReference::MSM(a), &CommitmentReference::MSM(b)) => std::ptr::eq(a, b),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CommitmentData<F, T: PartialEq> {
|
||||
|
@ -279,21 +321,9 @@ fn test_roundtrip() {
|
|||
¶ms,
|
||||
&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,
|
||||
})),
|
||||
.chain(Some(VerifierQuery::new_commitment(&a, x, avx)))
|
||||
.chain(Some(VerifierQuery::new_commitment(&b, x, avx))) // NB: wrong!
|
||||
.chain(Some(VerifierQuery::new_commitment(&c, y, cvy))),
|
||||
msm,
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -313,21 +343,9 @@ fn test_roundtrip() {
|
|||
¶ms,
|
||||
&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,
|
||||
})),
|
||||
.chain(Some(VerifierQuery::new_commitment(&a, x, avx)))
|
||||
.chain(Some(VerifierQuery::new_commitment(&b, x, bvx)))
|
||||
.chain(Some(VerifierQuery::new_commitment(&c, y, cvy))),
|
||||
msm,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
|
@ -5,8 +5,8 @@ use super::super::{
|
|||
Error,
|
||||
};
|
||||
use super::{
|
||||
construct_intermediate_sets, ChallengeX1, ChallengeX2, ChallengeX3, ChallengeX4, Query,
|
||||
VerifierQuery,
|
||||
construct_intermediate_sets, ChallengeX1, ChallengeX2, ChallengeX3, ChallengeX4,
|
||||
CommitmentReference, Query, VerifierQuery,
|
||||
};
|
||||
use crate::arithmetic::{eval_polynomial, lagrange_interpolate, CurveAffine, FieldExt};
|
||||
use crate::transcript::{EncodedChallenge, TranscriptRead};
|
||||
|
@ -19,20 +19,20 @@ struct CommitmentData<C: CurveAffine> {
|
|||
|
||||
/// Verify a multi-opening proof
|
||||
pub fn verify_proof<
|
||||
'b,
|
||||
'a: 'b,
|
||||
'r,
|
||||
'params: 'r,
|
||||
I,
|
||||
C: CurveAffine,
|
||||
E: EncodedChallenge<C>,
|
||||
T: TranscriptRead<C, E>,
|
||||
>(
|
||||
params: &'a Params<C>,
|
||||
params: &'params Params<C>,
|
||||
transcript: &mut T,
|
||||
queries: I,
|
||||
mut msm: MSM<'a, C>,
|
||||
) -> Result<Guard<'a, C, E>, Error>
|
||||
mut msm: MSM<'params, C>,
|
||||
) -> Result<Guard<'params, C, E>, Error>
|
||||
where
|
||||
I: IntoIterator<Item = VerifierQuery<'b, C>> + Clone,
|
||||
I: IntoIterator<Item = VerifierQuery<'r, 'params, C>> + Clone,
|
||||
{
|
||||
// Scale the MSM by a random factor to ensure that if the existing MSM
|
||||
// has is_zero() == false then this argument won't be able to interfere
|
||||
|
@ -61,7 +61,14 @@ where
|
|||
{
|
||||
let mut accumulate = |set_idx: usize, new_commitment, evals: Vec<C::Scalar>| {
|
||||
q_commitments[set_idx].scale(*x_1);
|
||||
q_commitments[set_idx].append_term(C::Scalar::one(), new_commitment);
|
||||
match new_commitment {
|
||||
CommitmentReference::Commitment(c) => {
|
||||
q_commitments[set_idx].append_term(C::Scalar::one(), *c);
|
||||
}
|
||||
CommitmentReference::MSM(msm) => {
|
||||
q_commitments[set_idx].add_msm(msm);
|
||||
}
|
||||
}
|
||||
for (eval, set_eval) in evals.iter().zip(q_eval_sets[set_idx].iter_mut()) {
|
||||
*set_eval *= &(*x_1);
|
||||
*set_eval += eval;
|
||||
|
@ -73,7 +80,7 @@ where
|
|||
for commitment_data in commitment_map.into_iter() {
|
||||
accumulate(
|
||||
commitment_data.set_index, // set_idx,
|
||||
*commitment_data.commitment.0, // commitment,
|
||||
commitment_data.commitment, // commitment,
|
||||
commitment_data.evals, // evals
|
||||
);
|
||||
}
|
||||
|
@ -128,18 +135,8 @@ where
|
|||
super::commitment::verify_proof(params, msm, transcript, *x_3, msm_eval)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct CommitmentPointer<'a, C>(&'a C);
|
||||
|
||||
impl<'a, C> PartialEq for CommitmentPointer<'a, C> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
std::ptr::eq(self.0, other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, C: CurveAffine> Query<C::Scalar> for VerifierQuery<'a, C> {
|
||||
type Commitment = CommitmentPointer<'a, C>;
|
||||
impl<'a, 'b, C: CurveAffine> Query<C::Scalar> for VerifierQuery<'a, 'b, C> {
|
||||
type Commitment = CommitmentReference<'a, 'b, C>;
|
||||
type Eval = C::Scalar;
|
||||
|
||||
fn get_point(&self) -> C::Scalar {
|
||||
|
@ -149,6 +146,6 @@ impl<'a, C: CurveAffine> Query<C::Scalar> for VerifierQuery<'a, C> {
|
|||
self.eval
|
||||
}
|
||||
fn get_commitment(&self) -> Self::Commitment {
|
||||
CommitmentPointer(self.commitment)
|
||||
self.commitment
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue