mirror of https://github.com/zcash/halo2.git
Merge pull request #322 from zcash/coset-optimization
Support rotations while in extended domain
This commit is contained in:
commit
ca44b40009
16
src/dev.rs
16
src/dev.rs
|
@ -610,8 +610,9 @@ impl<F: FieldExt> MockProver<F> {
|
|||
row: i32,
|
||||
queries: &'a [(Column<T>, Rotation)],
|
||||
cells: &'a [Vec<F>],
|
||||
) -> impl Fn(usize) -> Value<F> + 'a {
|
||||
move |index| {
|
||||
) -> impl Fn(usize, usize, Rotation) -> Value<F> + 'a
|
||||
{
|
||||
move |index, _, _| {
|
||||
let (column, at) = &queries[index];
|
||||
let resolved_row = (row + at.0) % n;
|
||||
Value::Real(cells[column.index()][resolved_row as usize])
|
||||
|
@ -623,8 +624,9 @@ impl<F: FieldExt> MockProver<F> {
|
|||
row: i32,
|
||||
queries: &'a [(Column<T>, Rotation)],
|
||||
cells: &'a [Vec<CellValue<F>>],
|
||||
) -> impl Fn(usize) -> Value<F> + 'a {
|
||||
move |index| {
|
||||
) -> impl Fn(usize, usize, Rotation) -> Value<F> + 'a
|
||||
{
|
||||
move |index, _, _| {
|
||||
let (column, at) = &queries[index];
|
||||
let resolved_row = (row + at.0) % n;
|
||||
cells[column.index()][resolved_row as usize].into()
|
||||
|
@ -674,7 +676,7 @@ impl<F: FieldExt> MockProver<F> {
|
|||
let load = |expression: &Expression<F>, row| {
|
||||
expression.evaluate(
|
||||
&|scalar| Value::Real(scalar),
|
||||
&|index| {
|
||||
&|index, _, _| {
|
||||
let query = self.cs.fixed_queries[index];
|
||||
let column_index = query.0.index();
|
||||
let rotation = query.1 .0;
|
||||
|
@ -682,7 +684,7 @@ impl<F: FieldExt> MockProver<F> {
|
|||
[(row as i32 + n + rotation) as usize % n as usize]
|
||||
.into()
|
||||
},
|
||||
&|index| {
|
||||
&|index, _, _| {
|
||||
let query = self.cs.advice_queries[index];
|
||||
let column_index = query.0.index();
|
||||
let rotation = query.1 .0;
|
||||
|
@ -690,7 +692,7 @@ impl<F: FieldExt> MockProver<F> {
|
|||
[(row as i32 + n + rotation) as usize % n as usize]
|
||||
.into()
|
||||
},
|
||||
&|index| {
|
||||
&|index, _, _| {
|
||||
let query = self.cs.instance_queries[index];
|
||||
let column_index = query.0.index();
|
||||
let rotation = query.1 .0;
|
||||
|
|
|
@ -537,11 +537,32 @@ pub enum Expression<F> {
|
|||
/// This is a constant polynomial
|
||||
Constant(F),
|
||||
/// This is a fixed column queried at a certain relative location
|
||||
Fixed(usize),
|
||||
Fixed {
|
||||
/// Query index
|
||||
query_index: usize,
|
||||
/// Column index
|
||||
column_index: usize,
|
||||
/// Rotation of this query
|
||||
rotation: Rotation,
|
||||
},
|
||||
/// This is an advice (witness) column queried at a certain relative location
|
||||
Advice(usize),
|
||||
Advice {
|
||||
/// Query index
|
||||
query_index: usize,
|
||||
/// Column index
|
||||
column_index: usize,
|
||||
/// Rotation of this query
|
||||
rotation: Rotation,
|
||||
},
|
||||
/// This is an instance (external) column queried at a certain relative location
|
||||
Instance(usize),
|
||||
Instance {
|
||||
/// Query index
|
||||
query_index: usize,
|
||||
/// Column index
|
||||
column_index: usize,
|
||||
/// Rotation of this query
|
||||
rotation: Rotation,
|
||||
},
|
||||
/// This is the sum of two polynomials
|
||||
Sum(Box<Expression<F>>, Box<Expression<F>>),
|
||||
/// This is the product of two polynomials
|
||||
|
@ -556,18 +577,30 @@ impl<F: Field> Expression<F> {
|
|||
pub fn evaluate<T>(
|
||||
&self,
|
||||
constant: &impl Fn(F) -> T,
|
||||
fixed_column: &impl Fn(usize) -> T,
|
||||
advice_column: &impl Fn(usize) -> T,
|
||||
instance_column: &impl Fn(usize) -> T,
|
||||
fixed_column: &impl Fn(usize, usize, Rotation) -> T,
|
||||
advice_column: &impl Fn(usize, usize, Rotation) -> T,
|
||||
instance_column: &impl Fn(usize, usize, Rotation) -> T,
|
||||
sum: &impl Fn(T, T) -> T,
|
||||
product: &impl Fn(T, T) -> T,
|
||||
scaled: &impl Fn(T, F) -> T,
|
||||
) -> T {
|
||||
match self {
|
||||
Expression::Constant(scalar) => constant(*scalar),
|
||||
Expression::Fixed(index) => fixed_column(*index),
|
||||
Expression::Advice(index) => advice_column(*index),
|
||||
Expression::Instance(index) => instance_column(*index),
|
||||
Expression::Fixed {
|
||||
query_index,
|
||||
column_index,
|
||||
rotation,
|
||||
} => fixed_column(*query_index, *column_index, *rotation),
|
||||
Expression::Advice {
|
||||
query_index,
|
||||
column_index,
|
||||
rotation,
|
||||
} => advice_column(*query_index, *column_index, *rotation),
|
||||
Expression::Instance {
|
||||
query_index,
|
||||
column_index,
|
||||
rotation,
|
||||
} => instance_column(*query_index, *column_index, *rotation),
|
||||
Expression::Sum(a, b) => {
|
||||
let a = a.evaluate(
|
||||
constant,
|
||||
|
@ -629,9 +662,9 @@ impl<F: Field> Expression<F> {
|
|||
pub fn degree(&self) -> usize {
|
||||
match self {
|
||||
Expression::Constant(_) => 0,
|
||||
Expression::Fixed(_) => 1,
|
||||
Expression::Advice(_) => 1,
|
||||
Expression::Instance(_) => 1,
|
||||
Expression::Fixed { .. } => 1,
|
||||
Expression::Advice { .. } => 1,
|
||||
Expression::Instance { .. } => 1,
|
||||
Expression::Sum(a, b) => max(a.degree(), b.degree()),
|
||||
Expression::Product(a, b) => a.degree() + b.degree(),
|
||||
Expression::Scaled(poly, _) => poly.degree(),
|
||||
|
@ -1150,43 +1183,49 @@ impl<'a, F: Field> VirtualCells<'a, F> {
|
|||
pub fn query_selector(&mut self, selector: Selector) -> Expression<F> {
|
||||
// Selectors are always queried at the current row.
|
||||
self.queried_selectors.push(selector);
|
||||
Expression::Fixed(self.meta.query_fixed_index(selector.0, Rotation::cur()))
|
||||
Expression::Fixed {
|
||||
query_index: self.meta.query_fixed_index(selector.0, Rotation::cur()),
|
||||
column_index: (selector.0).index,
|
||||
rotation: Rotation::cur(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Query a fixed column at a relative position
|
||||
pub fn query_fixed(&mut self, column: Column<Fixed>, at: Rotation) -> Expression<F> {
|
||||
self.queried_cells.push((column, at).into());
|
||||
Expression::Fixed(self.meta.query_fixed_index(column, at))
|
||||
Expression::Fixed {
|
||||
query_index: self.meta.query_fixed_index(column, at),
|
||||
column_index: column.index,
|
||||
rotation: at,
|
||||
}
|
||||
}
|
||||
|
||||
/// Query an advice column at a relative position
|
||||
pub fn query_advice(&mut self, column: Column<Advice>, at: Rotation) -> Expression<F> {
|
||||
self.queried_cells.push((column, at).into());
|
||||
Expression::Advice(self.meta.query_advice_index(column, at))
|
||||
Expression::Advice {
|
||||
query_index: self.meta.query_advice_index(column, at),
|
||||
column_index: column.index,
|
||||
rotation: at,
|
||||
}
|
||||
}
|
||||
|
||||
/// Query an instance column at a relative position
|
||||
pub fn query_instance(&mut self, column: Column<Instance>, at: Rotation) -> Expression<F> {
|
||||
self.queried_cells.push((column, at).into());
|
||||
Expression::Instance(self.meta.query_instance_index(column, at))
|
||||
Expression::Instance {
|
||||
query_index: self.meta.query_instance_index(column, at),
|
||||
column_index: column.index,
|
||||
rotation: at,
|
||||
}
|
||||
}
|
||||
|
||||
/// Query an Any column at a relative position
|
||||
pub fn query_any(&mut self, column: Column<Any>, at: Rotation) -> Expression<F> {
|
||||
self.queried_cells.push((column, at).into());
|
||||
match column.column_type() {
|
||||
Any::Advice => Expression::Advice(
|
||||
self.meta
|
||||
.query_advice_index(Column::<Advice>::try_from(column).unwrap(), at),
|
||||
),
|
||||
Any::Fixed => Expression::Fixed(
|
||||
self.meta
|
||||
.query_fixed_index(Column::<Fixed>::try_from(column).unwrap(), at),
|
||||
),
|
||||
Any::Instance => Expression::Instance(
|
||||
self.meta
|
||||
.query_instance_index(Column::<Instance>::try_from(column).unwrap(), at),
|
||||
),
|
||||
Any::Advice => self.query_advice(Column::<Advice>::try_from(column).unwrap(), at),
|
||||
Any::Fixed => self.query_fixed(Column::<Fixed>::try_from(column).unwrap(), at),
|
||||
Any::Instance => self.query_instance(Column::<Instance>::try_from(column).unwrap(), at),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use super::{
|
|||
};
|
||||
use crate::poly::{
|
||||
commitment::{Blind, Params},
|
||||
EvaluationDomain, Rotation,
|
||||
EvaluationDomain,
|
||||
};
|
||||
use crate::{arithmetic::CurveAffine, poly::batch_invert_assigned};
|
||||
|
||||
|
@ -243,14 +243,9 @@ where
|
|||
.map(|poly| vk.domain.lagrange_to_coeff(poly.clone()))
|
||||
.collect();
|
||||
|
||||
let fixed_cosets = vk
|
||||
.cs
|
||||
.fixed_queries
|
||||
let fixed_cosets = fixed_polys
|
||||
.iter()
|
||||
.map(|&(column, at)| {
|
||||
let poly = fixed_polys[column.index()].clone();
|
||||
vk.domain.coeff_to_extended(poly, at)
|
||||
})
|
||||
.map(|poly| vk.domain.coeff_to_extended(poly.clone()))
|
||||
.collect();
|
||||
|
||||
let permutation_pk = assembly
|
||||
|
@ -262,7 +257,7 @@ where
|
|||
let mut l0 = vk.domain.empty_lagrange();
|
||||
l0[0] = C::Scalar::one();
|
||||
let l0 = vk.domain.lagrange_to_coeff(l0);
|
||||
let l0 = vk.domain.coeff_to_extended(l0, Rotation::cur());
|
||||
let l0 = vk.domain.coeff_to_extended(l0);
|
||||
|
||||
// Compute l_blind(X) which evaluates to 1 for each blinding factor row
|
||||
// and 0 otherwise over the domain.
|
||||
|
@ -271,14 +266,14 @@ where
|
|||
*evaluation = C::Scalar::one();
|
||||
}
|
||||
let l_blind = vk.domain.lagrange_to_coeff(l_blind);
|
||||
let l_blind = vk.domain.coeff_to_extended(l_blind, Rotation::cur());
|
||||
let l_blind = vk.domain.coeff_to_extended(l_blind);
|
||||
|
||||
// Compute l_last(X) which evaluates to 1 on the first inactive row (just
|
||||
// before the blinding factors) and 0 otherwise over the domain
|
||||
let mut l_last = vk.domain.empty_lagrange();
|
||||
l_last[params.n as usize - cs.blinding_factors() - 1] = C::Scalar::one();
|
||||
let l_last = vk.domain.lagrange_to_coeff(l_last);
|
||||
let l_last = vk.domain.coeff_to_extended(l_last, Rotation::cur());
|
||||
let l_last = vk.domain.coeff_to_extended(l_last);
|
||||
|
||||
Ok(ProvingKey {
|
||||
vk,
|
||||
|
|
|
@ -27,7 +27,6 @@ pub(in crate::plonk) struct Permuted<C: CurveAffine> {
|
|||
permuted_input_expression: Polynomial<C::Scalar, LagrangeCoeff>,
|
||||
permuted_input_poly: Polynomial<C::Scalar, Coeff>,
|
||||
permuted_input_coset: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
|
||||
permuted_input_inv_coset: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
|
||||
permuted_input_blind: Blind<C::Scalar>,
|
||||
permuted_input_commitment: C,
|
||||
unpermuted_table_expressions: Vec<Polynomial<C::Scalar, LagrangeCoeff>>,
|
||||
|
@ -44,7 +43,6 @@ pub(in crate::plonk) struct Committed<C: CurveAffine> {
|
|||
permuted: Permuted<C>,
|
||||
product_poly: Polynomial<C::Scalar, Coeff>,
|
||||
product_coset: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
|
||||
product_next_coset: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
|
||||
product_blind: Blind<C::Scalar>,
|
||||
product_commitment: C,
|
||||
}
|
||||
|
@ -103,22 +101,13 @@ impl<F: FieldExt> Argument<F> {
|
|||
.map(|expression| {
|
||||
expression.evaluate(
|
||||
&|scalar| pk.vk.domain.constant_lagrange(scalar),
|
||||
&|index| {
|
||||
let query = pk.vk.cs.fixed_queries[index];
|
||||
let column_index = query.0.index();
|
||||
let rotation = query.1;
|
||||
&|_, column_index, rotation| {
|
||||
fixed_values[column_index].clone().rotate(rotation)
|
||||
},
|
||||
&|index| {
|
||||
let query = pk.vk.cs.advice_queries[index];
|
||||
let column_index = query.0.index();
|
||||
let rotation = query.1;
|
||||
&|_, column_index, rotation| {
|
||||
advice_values[column_index].clone().rotate(rotation)
|
||||
},
|
||||
&|index| {
|
||||
let query = pk.vk.cs.instance_queries[index];
|
||||
let column_index = query.0.index();
|
||||
let rotation = query.1;
|
||||
&|_, column_index, rotation| {
|
||||
instance_values[column_index].clone().rotate(rotation)
|
||||
},
|
||||
&|a, b| a + &b,
|
||||
|
@ -145,9 +134,21 @@ impl<F: FieldExt> Argument<F> {
|
|||
.map(|expression| {
|
||||
expression.evaluate(
|
||||
&|scalar| pk.vk.domain.constant_extended(scalar),
|
||||
&|index| fixed_cosets[index].clone(),
|
||||
&|index| advice_cosets[index].clone(),
|
||||
&|index| instance_cosets[index].clone(),
|
||||
&|_, column_index, rotation| {
|
||||
pk.vk
|
||||
.domain
|
||||
.rotate_extended(&fixed_cosets[column_index], rotation)
|
||||
},
|
||||
&|_, column_index, rotation| {
|
||||
pk.vk
|
||||
.domain
|
||||
.rotate_extended(&advice_cosets[column_index], rotation)
|
||||
},
|
||||
&|_, column_index, rotation| {
|
||||
pk.vk
|
||||
.domain
|
||||
.rotate_extended(&instance_cosets[column_index], rotation)
|
||||
},
|
||||
&|a, b| a + &b,
|
||||
&|a, b| a * &b,
|
||||
&|a, scalar| a * scalar,
|
||||
|
@ -212,18 +213,8 @@ impl<F: FieldExt> Argument<F> {
|
|||
.write_point(permuted_table_commitment)
|
||||
.map_err(|_| Error::TranscriptError)?;
|
||||
|
||||
let permuted_input_coset = pk
|
||||
.vk
|
||||
.domain
|
||||
.coeff_to_extended(permuted_input_poly.clone(), Rotation::cur());
|
||||
let permuted_input_inv_coset = pk
|
||||
.vk
|
||||
.domain
|
||||
.coeff_to_extended(permuted_input_poly.clone(), Rotation(-1));
|
||||
let permuted_table_coset = pk
|
||||
.vk
|
||||
.domain
|
||||
.coeff_to_extended(permuted_table_poly.clone(), Rotation::cur());
|
||||
let permuted_input_coset = pk.vk.domain.coeff_to_extended(permuted_input_poly.clone());
|
||||
let permuted_table_coset = pk.vk.domain.coeff_to_extended(permuted_table_poly.clone());
|
||||
|
||||
Ok(Permuted {
|
||||
unpermuted_input_expressions,
|
||||
|
@ -231,7 +222,6 @@ impl<F: FieldExt> Argument<F> {
|
|||
permuted_input_expression,
|
||||
permuted_input_poly,
|
||||
permuted_input_coset,
|
||||
permuted_input_inv_coset,
|
||||
permuted_input_blind,
|
||||
permuted_input_commitment,
|
||||
unpermuted_table_expressions,
|
||||
|
@ -392,8 +382,7 @@ impl<C: CurveAffine> Permuted<C> {
|
|||
let product_blind = Blind(C::Scalar::rand());
|
||||
let product_commitment = params.commit_lagrange(&z, product_blind).to_affine();
|
||||
let z = pk.vk.domain.lagrange_to_coeff(z);
|
||||
let product_coset = pk.vk.domain.coeff_to_extended(z.clone(), Rotation::cur());
|
||||
let product_next_coset = pk.vk.domain.coeff_to_extended(z.clone(), Rotation::next());
|
||||
let product_coset = pk.vk.domain.coeff_to_extended(z.clone());
|
||||
|
||||
// Hash product commitment
|
||||
transcript
|
||||
|
@ -404,7 +393,6 @@ impl<C: CurveAffine> Permuted<C> {
|
|||
permuted: self,
|
||||
product_poly: z,
|
||||
product_coset,
|
||||
product_next_coset,
|
||||
product_commitment,
|
||||
product_blind,
|
||||
})
|
||||
|
@ -427,6 +415,7 @@ impl<'a, C: CurveAffine> Committed<C> {
|
|||
Constructed<C>,
|
||||
impl Iterator<Item = Polynomial<C::Scalar, ExtendedLagrangeCoeff>> + 'a,
|
||||
) {
|
||||
let domain = &pk.vk.domain;
|
||||
let permuted = self.permuted;
|
||||
|
||||
let active_rows = Polynomial::one_minus(pk.l_last.clone() + &pk.l_blind);
|
||||
|
@ -447,7 +436,7 @@ impl<'a, C: CurveAffine> Committed<C> {
|
|||
// ) = 0
|
||||
.chain({
|
||||
// z(\omega X) (a'(X) + \beta) (s'(X) + \gamma)
|
||||
let mut left = self.product_next_coset.clone();
|
||||
let mut left = domain.rotate_extended(&self.product_coset, Rotation::next());
|
||||
parallelize(&mut left, |left, start| {
|
||||
for ((left, permuted_input), permuted_table) in left
|
||||
.iter_mut()
|
||||
|
@ -499,7 +488,11 @@ impl<'a, C: CurveAffine> Committed<C> {
|
|||
// (1 - (l_last + l_blind)) * (a′(X) − s′(X))⋅(a′(X) − a′(\omega^{-1} X)) = 0
|
||||
.chain(Some(
|
||||
(permuted.permuted_input_coset.clone() - &permuted.permuted_table_coset)
|
||||
* &(permuted.permuted_input_coset.clone() - &permuted.permuted_input_inv_coset)
|
||||
* &(domain.sub_extended(
|
||||
permuted.permuted_input_coset.clone(),
|
||||
&permuted.permuted_input_coset,
|
||||
Rotation::prev(),
|
||||
))
|
||||
* &active_rows,
|
||||
));
|
||||
|
||||
|
|
|
@ -134,9 +134,9 @@ impl<C: CurveAffine> Evaluated<C> {
|
|||
.map(|expression| {
|
||||
expression.evaluate(
|
||||
&|scalar| scalar,
|
||||
&|index| fixed_evals[index],
|
||||
&|index| advice_evals[index],
|
||||
&|index| instance_evals[index],
|
||||
&|index, _, _| fixed_evals[index],
|
||||
&|index, _, _| advice_evals[index],
|
||||
&|index, _, _| instance_evals[index],
|
||||
&|a, b| a + &b,
|
||||
&|a, b| a * &b,
|
||||
&|a, scalar| a * &scalar,
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
plonk::{Any, Column, Error},
|
||||
poly::{
|
||||
commitment::{Blind, Params},
|
||||
EvaluationDomain, Rotation,
|
||||
EvaluationDomain,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -199,7 +199,7 @@ impl Assembly {
|
|||
permutations.push(permutation_poly.clone());
|
||||
let poly = domain.lagrange_to_coeff(permutation_poly);
|
||||
polys.push(poly.clone());
|
||||
cosets.push(domain.coeff_to_extended(poly, Rotation::cur()));
|
||||
cosets.push(domain.coeff_to_extended(poly));
|
||||
}
|
||||
ProvingKey {
|
||||
permutations,
|
||||
|
|
|
@ -18,8 +18,6 @@ use crate::{
|
|||
pub struct CommittedSet<C: CurveAffine> {
|
||||
permutation_product_poly: Polynomial<C::Scalar, Coeff>,
|
||||
permutation_product_coset: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
|
||||
permutation_product_coset_next: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
|
||||
permutation_product_coset_last: Option<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>,
|
||||
permutation_product_blind: Blind<C::Scalar>,
|
||||
}
|
||||
|
||||
|
@ -75,12 +73,11 @@ impl Argument {
|
|||
|
||||
let mut sets = vec![];
|
||||
|
||||
let mut iter = self
|
||||
for (columns, permutations) in self
|
||||
.columns
|
||||
.chunks(chunk_len)
|
||||
.zip(pkey.permutations.chunks(chunk_len));
|
||||
|
||||
while let Some((columns, permutations)) = iter.next() {
|
||||
.zip(pkey.permutations.chunks(chunk_len))
|
||||
{
|
||||
// Goal is to compute the products of fractions
|
||||
//
|
||||
// (p_j(\omega^i) + \delta^j \omega^i \beta + \gamma) /
|
||||
|
@ -168,18 +165,7 @@ impl Argument {
|
|||
let z = domain.lagrange_to_coeff(z);
|
||||
let permutation_product_poly = z.clone();
|
||||
|
||||
// We only keep these around if there's another set afterward.
|
||||
let permutation_product_coset_last = if iter.len() > 0 {
|
||||
// Keep the polynomial around, rotated to l_last.
|
||||
Some(
|
||||
domain.coeff_to_extended(z.clone(), Rotation(-((blinding_factors + 1) as i32))),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let permutation_product_coset = domain.coeff_to_extended(z.clone(), Rotation::cur());
|
||||
let permutation_product_coset_next = domain.coeff_to_extended(z, Rotation::next());
|
||||
let permutation_product_coset = domain.coeff_to_extended(z.clone());
|
||||
|
||||
let permutation_product_commitment =
|
||||
permutation_product_commitment_projective.to_affine();
|
||||
|
@ -192,8 +178,6 @@ impl Argument {
|
|||
sets.push(CommittedSet {
|
||||
permutation_product_poly,
|
||||
permutation_product_coset,
|
||||
permutation_product_coset_next,
|
||||
permutation_product_coset_last,
|
||||
permutation_product_blind,
|
||||
});
|
||||
}
|
||||
|
@ -219,6 +203,8 @@ impl<C: CurveAffine> Committed<C> {
|
|||
) {
|
||||
let domain = &pk.vk.domain;
|
||||
let chunk_len = pk.vk.cs.degree() - 2;
|
||||
let blinding_factors = pk.vk.cs.blinding_factors();
|
||||
let last_rotation = Rotation(-((blinding_factors + 1) as i32));
|
||||
|
||||
let constructed = Constructed {
|
||||
sets: self
|
||||
|
@ -252,9 +238,11 @@ impl<C: CurveAffine> Committed<C> {
|
|||
.skip(1)
|
||||
.zip(self.sets.iter())
|
||||
.map(|(set, last_set)| {
|
||||
(set.permutation_product_coset.clone()
|
||||
- &last_set.permutation_product_coset_last.as_ref().unwrap())
|
||||
* &pk.l0
|
||||
domain.sub_extended(
|
||||
set.permutation_product_coset.clone(),
|
||||
&last_set.permutation_product_coset,
|
||||
last_rotation,
|
||||
) * &pk.l0
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
|
@ -270,22 +258,14 @@ impl<C: CurveAffine> Committed<C> {
|
|||
.zip(pkey.cosets.chunks(chunk_len))
|
||||
.enumerate()
|
||||
.map(move |(chunk_index, ((set, columns), cosets))| {
|
||||
let mut left = set.permutation_product_coset_next;
|
||||
let mut left = domain
|
||||
.rotate_extended(&set.permutation_product_coset, Rotation::next());
|
||||
for (values, permutation) in columns
|
||||
.iter()
|
||||
.map(|&column| match column.column_type() {
|
||||
Any::Advice => {
|
||||
&advice_cosets
|
||||
[pk.vk.cs.get_any_query_index(column, Rotation::cur())]
|
||||
}
|
||||
Any::Fixed => {
|
||||
&fixed_cosets
|
||||
[pk.vk.cs.get_any_query_index(column, Rotation::cur())]
|
||||
}
|
||||
Any::Instance => {
|
||||
&instance_cosets
|
||||
[pk.vk.cs.get_any_query_index(column, Rotation::cur())]
|
||||
}
|
||||
Any::Advice => &advice_cosets[column.index()],
|
||||
Any::Fixed => &fixed_cosets[column.index()],
|
||||
Any::Instance => &instance_cosets[column.index()],
|
||||
})
|
||||
.zip(cosets.iter())
|
||||
{
|
||||
|
@ -306,17 +286,9 @@ impl<C: CurveAffine> Committed<C> {
|
|||
* &(C::Scalar::DELTA.pow_vartime(&[(chunk_index * chunk_len) as u64]));
|
||||
let step = domain.get_extended_omega();
|
||||
for values in columns.iter().map(|&column| match column.column_type() {
|
||||
Any::Advice => {
|
||||
&advice_cosets
|
||||
[pk.vk.cs.get_any_query_index(column, Rotation::cur())]
|
||||
}
|
||||
Any::Fixed => {
|
||||
&fixed_cosets[pk.vk.cs.get_any_query_index(column, Rotation::cur())]
|
||||
}
|
||||
Any::Instance => {
|
||||
&instance_cosets
|
||||
[pk.vk.cs.get_any_query_index(column, Rotation::cur())]
|
||||
}
|
||||
Any::Advice => &advice_cosets[column.index()],
|
||||
Any::Fixed => &fixed_cosets[column.index()],
|
||||
Any::Instance => &instance_cosets[column.index()],
|
||||
}) {
|
||||
parallelize(&mut right, move |right, start| {
|
||||
let mut beta_term =
|
||||
|
|
|
@ -103,13 +103,9 @@ pub fn create_proof<
|
|||
})
|
||||
.collect();
|
||||
|
||||
let instance_cosets: Vec<_> = meta
|
||||
.instance_queries
|
||||
let instance_cosets: Vec<_> = instance_polys
|
||||
.iter()
|
||||
.map(|&(column, at)| {
|
||||
let poly = instance_polys[column.index()].clone();
|
||||
domain.coeff_to_extended(poly, at)
|
||||
})
|
||||
.map(|poly| domain.coeff_to_extended(poly.clone()))
|
||||
.collect();
|
||||
|
||||
Ok(InstanceSingle {
|
||||
|
@ -300,13 +296,9 @@ pub fn create_proof<
|
|||
.map(|poly| domain.lagrange_to_coeff(poly))
|
||||
.collect();
|
||||
|
||||
let advice_cosets: Vec<_> = meta
|
||||
.advice_queries
|
||||
let advice_cosets: Vec<_> = advice_polys
|
||||
.iter()
|
||||
.map(|&(column, at)| {
|
||||
let poly = advice_polys[column.index()].clone();
|
||||
domain.coeff_to_extended(poly, at)
|
||||
})
|
||||
.map(|poly| domain.coeff_to_extended(poly.clone()))
|
||||
.collect();
|
||||
|
||||
Ok(AdviceSingle {
|
||||
|
@ -434,9 +426,23 @@ pub fn create_proof<
|
|||
gate.polynomials().iter().map(move |poly| {
|
||||
poly.evaluate(
|
||||
&|scalar| pk.vk.domain.constant_extended(scalar),
|
||||
&|index| pk.fixed_cosets[index].clone(),
|
||||
&|index| advice.advice_cosets[index].clone(),
|
||||
&|index| instance.instance_cosets[index].clone(),
|
||||
&|_, column_index, rotation| {
|
||||
pk.vk
|
||||
.domain
|
||||
.rotate_extended(&pk.fixed_cosets[column_index], rotation)
|
||||
},
|
||||
&|_, column_index, rotation| {
|
||||
pk.vk.domain.rotate_extended(
|
||||
&advice.advice_cosets[column_index],
|
||||
rotation,
|
||||
)
|
||||
},
|
||||
&|_, column_index, rotation| {
|
||||
pk.vk.domain.rotate_extended(
|
||||
&instance.instance_cosets[column_index],
|
||||
rotation,
|
||||
)
|
||||
},
|
||||
&|a, b| a + &b,
|
||||
&|a, b| a * &b,
|
||||
&|a, scalar| a * scalar,
|
||||
|
|
|
@ -184,9 +184,9 @@ pub fn verify_proof<'params, C: CurveAffine, E: EncodedChallenge<C>, T: Transcri
|
|||
gate.polynomials().iter().map(move |poly| {
|
||||
poly.evaluate(
|
||||
&|scalar| scalar,
|
||||
&|index| fixed_evals[index],
|
||||
&|index| advice_evals[index],
|
||||
&|index| instance_evals[index],
|
||||
&|index, _, _| fixed_evals[index],
|
||||
&|index, _, _| advice_evals[index],
|
||||
&|index, _, _| instance_evals[index],
|
||||
&|a, b| a + &b,
|
||||
&|a, b| a * &b,
|
||||
&|a, scalar| a * &scalar,
|
||||
|
|
|
@ -239,26 +239,10 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
pub fn coeff_to_extended(
|
||||
&self,
|
||||
mut a: Polynomial<G, Coeff>,
|
||||
rotation: Rotation,
|
||||
) -> Polynomial<G, ExtendedLagrangeCoeff> {
|
||||
assert_eq!(a.values.len(), 1 << self.k);
|
||||
|
||||
assert!(rotation.0 != i32::MIN);
|
||||
if rotation.0 == 0 {
|
||||
// In this special case, the powers of zeta repeat so we do not need
|
||||
// to compute them.
|
||||
Self::distribute_powers_zeta(&mut a.values);
|
||||
} else {
|
||||
let mut g = self.g_coset;
|
||||
if rotation.0 > 0 {
|
||||
g *= &self.omega.pow_vartime(&[rotation.0 as u64, 0, 0, 0]);
|
||||
} else {
|
||||
g *= &self
|
||||
.omega_inv
|
||||
.pow_vartime(&[rotation.0.abs() as u64, 0, 0, 0]);
|
||||
}
|
||||
Self::distribute_powers(&mut a.values, g);
|
||||
}
|
||||
self.distribute_powers_zeta(&mut a.values, true);
|
||||
a.values.resize(self.extended_len(), G::group_zero());
|
||||
best_fft(&mut a.values, self.extended_omega, self.extended_k);
|
||||
|
||||
|
@ -268,6 +252,102 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
}
|
||||
}
|
||||
|
||||
fn op_extended(
|
||||
&self,
|
||||
mut left: Polynomial<G, ExtendedLagrangeCoeff>,
|
||||
right: &Polynomial<G, ExtendedLagrangeCoeff>,
|
||||
rotation: Rotation,
|
||||
op: impl Fn(&mut G, &G) + Send + Sync + 'static,
|
||||
) -> Polynomial<G, ExtendedLagrangeCoeff>
|
||||
where
|
||||
G: Field,
|
||||
{
|
||||
// Rotation while in the extended domain is simply exaggerated by how
|
||||
// much larger the extended domain is compared to the original domain.
|
||||
let rotation = (1 << (self.extended_k - self.k)) * rotation.0;
|
||||
|
||||
parallelize(&mut left.values, |lhs, start| {
|
||||
let start = ((((start + self.extended_len()) as i32) + rotation) as usize)
|
||||
% self.extended_len();
|
||||
|
||||
for (lhs, rhs) in lhs
|
||||
.iter_mut()
|
||||
.zip(right.values[start..].iter().chain(right.values.iter()))
|
||||
{
|
||||
op(lhs, rhs);
|
||||
}
|
||||
});
|
||||
|
||||
left
|
||||
}
|
||||
|
||||
/// Multiply two polynomials in the extended domain, rotating the latter
|
||||
/// polynomial over the original domain first.
|
||||
pub fn mul_extended(
|
||||
&self,
|
||||
left: Polynomial<G, ExtendedLagrangeCoeff>,
|
||||
right: &Polynomial<G, ExtendedLagrangeCoeff>,
|
||||
rotation: Rotation,
|
||||
) -> Polynomial<G, ExtendedLagrangeCoeff>
|
||||
where
|
||||
G: Field,
|
||||
{
|
||||
self.op_extended(left, right, rotation, |lhs, rhs| {
|
||||
*lhs *= *rhs;
|
||||
})
|
||||
}
|
||||
|
||||
/// Add two polynomials in the extended domain, rotating the latter
|
||||
/// polynomial over the original domain first.
|
||||
pub fn add_extended(
|
||||
&self,
|
||||
left: Polynomial<G, ExtendedLagrangeCoeff>,
|
||||
right: &Polynomial<G, ExtendedLagrangeCoeff>,
|
||||
rotation: Rotation,
|
||||
) -> Polynomial<G, ExtendedLagrangeCoeff>
|
||||
where
|
||||
G: Field,
|
||||
{
|
||||
self.op_extended(left, right, rotation, |lhs, rhs| {
|
||||
*lhs += *rhs;
|
||||
})
|
||||
}
|
||||
|
||||
/// Subtract a polynomial from another in the extended domain, rotating the
|
||||
/// former polynomial over the original domain first.
|
||||
pub fn sub_extended(
|
||||
&self,
|
||||
left: Polynomial<G, ExtendedLagrangeCoeff>,
|
||||
right: &Polynomial<G, ExtendedLagrangeCoeff>,
|
||||
rotation: Rotation,
|
||||
) -> Polynomial<G, ExtendedLagrangeCoeff>
|
||||
where
|
||||
G: Field,
|
||||
{
|
||||
self.op_extended(left, right, rotation, |lhs, rhs| {
|
||||
*lhs -= *rhs;
|
||||
})
|
||||
}
|
||||
|
||||
/// Rotate the extended domain polynomial over the original domain.
|
||||
pub fn rotate_extended(
|
||||
&self,
|
||||
poly: &Polynomial<G, ExtendedLagrangeCoeff>,
|
||||
rotation: Rotation,
|
||||
) -> Polynomial<G, ExtendedLagrangeCoeff> {
|
||||
let new_rotation = ((1 << (self.extended_k - self.k)) * rotation.0.abs()) as usize;
|
||||
|
||||
let mut poly = poly.clone();
|
||||
|
||||
if rotation.0 >= 0 {
|
||||
poly.values.rotate_left(new_rotation);
|
||||
} else {
|
||||
poly.values.rotate_right(new_rotation);
|
||||
}
|
||||
|
||||
poly
|
||||
}
|
||||
|
||||
/// This takes us from the extended evaluation domain and gets us the
|
||||
/// quotient polynomial coefficients.
|
||||
///
|
||||
|
@ -287,7 +367,7 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
|
||||
// Distribute powers to move from coset; opposite from the
|
||||
// transformation we performed earlier.
|
||||
Self::distribute_powers(&mut a.values, self.g_coset_inv);
|
||||
self.distribute_powers_zeta(&mut a.values, false);
|
||||
|
||||
// Truncate it to match the size of the quotient polynomial; the
|
||||
// evaluation domain might be slightly larger than necessary because
|
||||
|
@ -321,15 +401,22 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
}
|
||||
}
|
||||
|
||||
// Given a slice of group elements `[a_0, a_1, a_2, ...]`, this returns
|
||||
// `[a_0, [zeta]a_1, [zeta^2]a_2, a_3, [zeta]a_4, [zeta^2]a_5, a_6, ...]`,
|
||||
// where zeta is a cube root of unity in the multiplicative subgroup with
|
||||
// order (p - 1), i.e. zeta^3 = 1.
|
||||
fn distribute_powers_zeta(mut a: &mut [G]) {
|
||||
let coset_powers = [G::Scalar::ZETA, G::Scalar::ZETA.square()];
|
||||
/// Given a slice of group elements `[a_0, a_1, a_2, ...]`, this returns
|
||||
/// `[a_0, [zeta]a_1, [zeta^2]a_2, a_3, [zeta]a_4, [zeta^2]a_5, a_6, ...]`,
|
||||
/// where zeta is a cube root of unity in the multiplicative subgroup with
|
||||
/// order (p - 1), i.e. zeta^3 = 1.
|
||||
///
|
||||
/// `into_coset` should be set to `true` when moving into the coset,
|
||||
/// and `false` when moving out. This toggles the choice of `zeta`.
|
||||
fn distribute_powers_zeta(&self, mut a: &mut [G], into_coset: bool) {
|
||||
let coset_powers = if into_coset {
|
||||
[self.g_coset, self.g_coset_inv]
|
||||
} else {
|
||||
[self.g_coset_inv, self.g_coset]
|
||||
};
|
||||
parallelize(&mut a, |a, mut index| {
|
||||
for a in a {
|
||||
// Distribute powers to move into coset
|
||||
// Distribute powers to move into/from coset
|
||||
let i = index % (coset_powers.len() + 1);
|
||||
if i != 0 {
|
||||
a.group_scale(&coset_powers[i - 1]);
|
||||
|
@ -339,18 +426,6 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
});
|
||||
}
|
||||
|
||||
// Given a length-`n` slice of group elements `a` and a scalar `g`, this
|
||||
// returns `[a_0, [g]a_1, [g^2]a_2, [g^3]a_3, ..., [g^n-1] a_{n-1}]`.
|
||||
fn distribute_powers(mut a: &mut [G], g: G::Scalar) {
|
||||
parallelize(&mut a, |a, index| {
|
||||
let mut cur = g.pow_vartime(&[index as u64, 0, 0, 0]);
|
||||
for a in a {
|
||||
a.group_scale(&cur);
|
||||
cur *= &g;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn ifft(a: &mut [G], omega_inv: G::Scalar, log_n: u32, divisor: G::Scalar) {
|
||||
best_fft(a, omega_inv, log_n);
|
||||
parallelize(a, |a, _| {
|
||||
|
|
|
@ -521,74 +521,134 @@ fn plonk_api() {
|
|||
Sum(
|
||||
Sum(
|
||||
Product(
|
||||
Advice(
|
||||
Advice {
|
||||
query_index: 0,
|
||||
column_index: 1,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
Fixed(
|
||||
3,
|
||||
),
|
||||
),
|
||||
Product(
|
||||
Advice(
|
||||
1,
|
||||
),
|
||||
Fixed(
|
||||
4,
|
||||
),
|
||||
),
|
||||
),
|
||||
Product(
|
||||
Product(
|
||||
Advice(
|
||||
},
|
||||
Fixed {
|
||||
query_index: 3,
|
||||
column_index: 2,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
Advice(
|
||||
1,
|
||||
},
|
||||
),
|
||||
Product(
|
||||
Advice {
|
||||
query_index: 1,
|
||||
column_index: 2,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
Fixed {
|
||||
query_index: 4,
|
||||
column_index: 3,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
Fixed(
|
||||
6,
|
||||
Product(
|
||||
Product(
|
||||
Advice {
|
||||
query_index: 0,
|
||||
column_index: 1,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
Advice {
|
||||
query_index: 1,
|
||||
column_index: 2,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
),
|
||||
Fixed {
|
||||
query_index: 6,
|
||||
column_index: 1,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
Scaled(
|
||||
Product(
|
||||
Advice(
|
||||
2,
|
||||
Advice {
|
||||
query_index: 2,
|
||||
column_index: 3,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
Fixed(
|
||||
5,
|
||||
},
|
||||
Fixed {
|
||||
query_index: 5,
|
||||
column_index: 4,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
),
|
||||
0x40000000000000000000000000000000224698fc094cf91b992d30ed00000000,
|
||||
),
|
||||
),
|
||||
Product(
|
||||
Fixed(
|
||||
2,
|
||||
Fixed {
|
||||
query_index: 2,
|
||||
column_index: 0,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
Product(
|
||||
Advice(
|
||||
3,
|
||||
Advice {
|
||||
query_index: 3,
|
||||
column_index: 4,
|
||||
rotation: Rotation(
|
||||
1,
|
||||
),
|
||||
Advice(
|
||||
4,
|
||||
},
|
||||
Advice {
|
||||
query_index: 4,
|
||||
column_index: 0,
|
||||
rotation: Rotation(
|
||||
-1,
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
Product(
|
||||
Fixed(
|
||||
7,
|
||||
Fixed {
|
||||
query_index: 7,
|
||||
column_index: 5,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
Sum(
|
||||
Advice(
|
||||
Advice {
|
||||
query_index: 0,
|
||||
column_index: 1,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
Scaled(
|
||||
Instance(
|
||||
Instance {
|
||||
query_index: 0,
|
||||
column_index: 0,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
0x40000000000000000000000000000000224698fc094cf91b992d30ed00000000,
|
||||
),
|
||||
),
|
||||
|
@ -807,35 +867,59 @@ fn plonk_api() {
|
|||
lookups: [
|
||||
Argument {
|
||||
input_expressions: [
|
||||
Advice(
|
||||
Advice {
|
||||
query_index: 0,
|
||||
column_index: 1,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
],
|
||||
table_expressions: [
|
||||
Fixed(
|
||||
Fixed {
|
||||
query_index: 0,
|
||||
column_index: 6,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
Argument {
|
||||
input_expressions: [
|
||||
Product(
|
||||
Advice(
|
||||
Advice {
|
||||
query_index: 0,
|
||||
column_index: 1,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
Advice(
|
||||
1,
|
||||
},
|
||||
Advice {
|
||||
query_index: 1,
|
||||
column_index: 2,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
),
|
||||
],
|
||||
table_expressions: [
|
||||
Product(
|
||||
Fixed(
|
||||
Fixed {
|
||||
query_index: 0,
|
||||
column_index: 6,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
Fixed(
|
||||
1,
|
||||
},
|
||||
Fixed {
|
||||
query_index: 1,
|
||||
column_index: 7,
|
||||
rotation: Rotation(
|
||||
0,
|
||||
),
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue