mirror of https://github.com/zcash/halo2.git
250 lines
9.3 KiB
Rust
250 lines
9.3 KiB
Rust
use ff::Field;
|
|
use std::iter;
|
|
|
|
use super::super::{circuit::Any, ChallengeBeta, ChallengeGamma, ChallengeX};
|
|
use super::{Argument, VerifyingKey};
|
|
use crate::{
|
|
arithmetic::{CurveAffine, FieldExt},
|
|
plonk::{self, Error},
|
|
poly::{multiopen::VerifierQuery, Rotation},
|
|
transcript::{EncodedChallenge, TranscriptRead},
|
|
};
|
|
|
|
pub struct Committed<C: CurveAffine> {
|
|
permutation_product_commitments: Vec<C>,
|
|
}
|
|
|
|
pub struct EvaluatedSet<C: CurveAffine> {
|
|
permutation_product_commitment: C,
|
|
permutation_product_eval: C::Scalar,
|
|
permutation_product_next_eval: C::Scalar,
|
|
permutation_product_last_eval: Option<C::Scalar>,
|
|
}
|
|
|
|
pub struct Evaluated<C: CurveAffine> {
|
|
sets: Vec<EvaluatedSet<C>>,
|
|
permutation_evals: Vec<C::Scalar>,
|
|
}
|
|
|
|
impl Argument {
|
|
pub(crate) fn read_product_commitments<
|
|
C: CurveAffine,
|
|
E: EncodedChallenge<C>,
|
|
T: TranscriptRead<C, E>,
|
|
>(
|
|
&self,
|
|
vk: &plonk::VerifyingKey<C>,
|
|
transcript: &mut T,
|
|
) -> Result<Committed<C>, Error> {
|
|
let chunk_len = vk.cs.degree() - 2;
|
|
|
|
let permutation_product_commitments = self
|
|
.columns
|
|
.chunks(chunk_len)
|
|
.map(|_| transcript.read_point().map_err(|_| Error::TranscriptError))
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
|
|
Ok(Committed {
|
|
permutation_product_commitments,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<C: CurveAffine> Committed<C> {
|
|
pub(crate) fn evaluate<E: EncodedChallenge<C>, T: TranscriptRead<C, E>>(
|
|
self,
|
|
vkey: &VerifyingKey<C>,
|
|
transcript: &mut T,
|
|
) -> Result<Evaluated<C>, Error> {
|
|
let permutation_evals = vkey
|
|
.commitments
|
|
.iter()
|
|
.map(|_| transcript.read_scalar().map_err(|_| Error::TranscriptError))
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
|
|
let mut sets = vec![];
|
|
|
|
let mut iter = self.permutation_product_commitments.into_iter();
|
|
|
|
while let Some(permutation_product_commitment) = iter.next() {
|
|
let permutation_product_eval = transcript
|
|
.read_scalar()
|
|
.map_err(|_| Error::TranscriptError)?;
|
|
let permutation_product_next_eval = transcript
|
|
.read_scalar()
|
|
.map_err(|_| Error::TranscriptError)?;
|
|
let permutation_product_last_eval = if iter.len() > 0 {
|
|
Some(
|
|
transcript
|
|
.read_scalar()
|
|
.map_err(|_| Error::TranscriptError)?,
|
|
)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
sets.push(EvaluatedSet {
|
|
permutation_product_commitment,
|
|
permutation_product_eval,
|
|
permutation_product_next_eval,
|
|
permutation_product_last_eval,
|
|
});
|
|
}
|
|
|
|
Ok(Evaluated {
|
|
sets,
|
|
permutation_evals,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<C: CurveAffine> Evaluated<C> {
|
|
pub(in crate::plonk) fn expressions<'a>(
|
|
&'a self,
|
|
vk: &'a plonk::VerifyingKey<C>,
|
|
p: &'a Argument,
|
|
advice_evals: &'a [C::Scalar],
|
|
fixed_evals: &'a [C::Scalar],
|
|
instance_evals: &'a [C::Scalar],
|
|
l_0: C::Scalar,
|
|
l_last: C::Scalar,
|
|
l_blind: C::Scalar,
|
|
beta: ChallengeBeta<C>,
|
|
gamma: ChallengeGamma<C>,
|
|
x: ChallengeX<C>,
|
|
) -> impl Iterator<Item = C::Scalar> + 'a {
|
|
let chunk_len = vk.cs.degree() - 2;
|
|
iter::empty()
|
|
// Enforce only for the first set.
|
|
// l_0(X) * (1 - z_0(X)) = 0
|
|
.chain(
|
|
self.sets.first().map(|first_set| {
|
|
l_0 * &(C::Scalar::one() - &first_set.permutation_product_eval)
|
|
}),
|
|
)
|
|
// Enforce only for the last set.
|
|
// l_last(X) * (z_l(X)^2 - z_l(X)) = 0
|
|
.chain(self.sets.last().map(|last_set| {
|
|
(last_set.permutation_product_eval.square() - &last_set.permutation_product_eval)
|
|
* &l_last
|
|
}))
|
|
// Except for the first set, enforce.
|
|
// l_0(X) * (z_i(X) - z_{i-1}(\omega^(last) X)) = 0
|
|
.chain(
|
|
self.sets
|
|
.iter()
|
|
.skip(1)
|
|
.zip(self.sets.iter())
|
|
.map(|(set, last_set)| {
|
|
(
|
|
set.permutation_product_eval,
|
|
last_set.permutation_product_last_eval.unwrap(),
|
|
)
|
|
})
|
|
.collect::<Vec<_>>()
|
|
.into_iter()
|
|
.map(move |(set, prev_last)| (set - &prev_last) * &l_0),
|
|
)
|
|
// And for all the sets we enforce:
|
|
// (1 - (l_last + l_blind)) * (
|
|
// z_i(\omega X) \prod (p(X) + \beta s_i(X) + \gamma)
|
|
// - z_i(X) \prod (p(X) + \delta^i \beta X + \gamma)
|
|
// )
|
|
.chain(
|
|
self.sets
|
|
.iter()
|
|
.zip(p.columns.chunks(chunk_len))
|
|
.zip(self.permutation_evals.chunks(chunk_len))
|
|
.enumerate()
|
|
.map(move |(chunk_index, ((set, columns), permutation_evals))| {
|
|
let mut left = set.permutation_product_next_eval;
|
|
for (eval, permutation_eval) in columns
|
|
.iter()
|
|
.map(|&column| match column.column_type() {
|
|
Any::Advice => {
|
|
advice_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
|
|
}
|
|
Any::Fixed => {
|
|
fixed_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
|
|
}
|
|
Any::Instance => {
|
|
instance_evals
|
|
[vk.cs.get_any_query_index(column, Rotation::cur())]
|
|
}
|
|
})
|
|
.zip(permutation_evals.iter())
|
|
{
|
|
left *= &(eval + &(*beta * permutation_eval) + &*gamma);
|
|
}
|
|
|
|
let mut right = set.permutation_product_eval;
|
|
let mut current_delta = (*beta * &*x)
|
|
* &(C::Scalar::DELTA.pow_vartime(&[(chunk_index * chunk_len) as u64]));
|
|
for eval in columns.iter().map(|&column| match column.column_type() {
|
|
Any::Advice => {
|
|
advice_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
|
|
}
|
|
Any::Fixed => {
|
|
fixed_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
|
|
}
|
|
Any::Instance => {
|
|
instance_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
|
|
}
|
|
}) {
|
|
right *= &(eval + ¤t_delta + &*gamma);
|
|
current_delta *= &C::Scalar::DELTA;
|
|
}
|
|
|
|
(left - &right) * (C::Scalar::one() - &(l_last + &l_blind))
|
|
}),
|
|
)
|
|
}
|
|
|
|
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<'r, 'params, C>> + Clone {
|
|
let blinding_factors = vk.cs.blinding_factors();
|
|
let x_next = vk.domain.rotate_omega(*x, Rotation::next());
|
|
let x_last = vk
|
|
.domain
|
|
.rotate_omega(*x, Rotation(-((blinding_factors + 1) as i32)));
|
|
|
|
iter::empty()
|
|
.chain(self.sets.iter().flat_map(move |set| {
|
|
iter::empty()
|
|
// Open permutation product commitments at x and \omega^{-1} x
|
|
// Open permutation product commitments at x and \omega x
|
|
.chain(Some(VerifierQuery::new_commitment(
|
|
&set.permutation_product_commitment,
|
|
*x,
|
|
set.permutation_product_eval,
|
|
)))
|
|
.chain(Some(VerifierQuery::new_commitment(
|
|
&set.permutation_product_commitment,
|
|
x_next,
|
|
set.permutation_product_next_eval,
|
|
)))
|
|
}))
|
|
// Open it at \omega^{last} x for all but the last set
|
|
.chain(self.sets.iter().rev().skip(1).flat_map(move |set| {
|
|
Some(VerifierQuery::new_commitment(
|
|
&set.permutation_product_commitment,
|
|
x_last,
|
|
set.permutation_product_last_eval.unwrap(),
|
|
))
|
|
}))
|
|
// Open permutation commitments for each permutation argument at x
|
|
.chain(
|
|
vkey.commitments
|
|
.iter()
|
|
.zip(self.permutation_evals.iter())
|
|
.map(move |(commitment, &eval)| {
|
|
VerifierQuery::new_commitment(commitment, *x, eval)
|
|
}),
|
|
)
|
|
}
|
|
}
|