diff --git a/benches/plonk.rs b/benches/plonk.rs index 8c615705..2d59b2bb 100644 --- a/benches/plonk.rs +++ b/benches/plonk.rs @@ -5,7 +5,7 @@ extern crate halo2; use halo2::arithmetic::FieldExt; use halo2::pasta::{EqAffine, Fp, Fq}; use halo2::plonk::*; -use halo2::poly::commitment::Params; +use halo2::poly::{commitment::Params, Rotation}; use halo2::transcript::{DummyHashRead, DummyHashWrite}; use std::marker::PhantomData; @@ -166,14 +166,14 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { let sc = meta.fixed_column(); meta.create_gate(|meta| { - let a = meta.query_advice(a, 0); - let b = meta.query_advice(b, 0); - let c = meta.query_advice(c, 0); + let a = meta.query_advice(a, Rotation::cur()); + let b = meta.query_advice(b, Rotation::cur()); + let c = meta.query_advice(c, Rotation::cur()); - let sa = meta.query_fixed(sa, 0); - let sb = meta.query_fixed(sb, 0); - let sc = meta.query_fixed(sc, 0); - let sm = meta.query_fixed(sm, 0); + let sa = meta.query_fixed(sa, Rotation::cur()); + let sb = meta.query_fixed(sb, Rotation::cur()); + let sc = meta.query_fixed(sc, Rotation::cur()); + let sm = meta.query_fixed(sm, Rotation::cur()); a.clone() * sa + b.clone() * sb + a * b * sm + (c * sc * (-F::one())) }); diff --git a/examples/performance_model.rs b/examples/performance_model.rs index 0b871706..a23a4fb8 100644 --- a/examples/performance_model.rs +++ b/examples/performance_model.rs @@ -3,7 +3,10 @@ use halo2::{ model::ModelRecorder, pasta::{EqAffine, Fp, Fq}, plonk::*, - poly::commitment::{Blind, Params}, + poly::{ + commitment::{Blind, Params}, + Rotation, + }, transcript::{DummyHashRead, DummyHashWrite}, }; @@ -177,22 +180,22 @@ impl Circuit for MyCircuit { let sp = meta.fixed_column(); meta.create_gate(|meta| { - let a = meta.query_advice(a, 0); - let b = meta.query_advice(b, 0); - let c = meta.query_advice(c, 0); + let a = meta.query_advice(a, Rotation::cur()); + let b = meta.query_advice(b, Rotation::cur()); + let c = meta.query_advice(c, Rotation::cur()); - let sa = meta.query_fixed(sa, 0); - let sb = meta.query_fixed(sb, 0); - let sc = meta.query_fixed(sc, 0); - let sm = meta.query_fixed(sm, 0); + let sa = meta.query_fixed(sa, Rotation::cur()); + let sb = meta.query_fixed(sb, Rotation::cur()); + let sc = meta.query_fixed(sc, Rotation::cur()); + let sm = meta.query_fixed(sm, Rotation::cur()); a.clone() * sa + b.clone() * sb + a * b * sm + (c * sc * (-F::one())) }); meta.create_gate(|meta| { - let a = meta.query_advice(a, 0); - let p = meta.query_aux(p, 0); - let sp = meta.query_fixed(sp, 0); + let a = meta.query_advice(a, Rotation::cur()); + let p = meta.query_aux(p, Rotation::cur()); + let sp = meta.query_fixed(sp, Rotation::cur()); sp * (a + p * (-F::one())) }); diff --git a/src/dev.rs b/src/dev.rs index 2a691ba2..9e63e7a0 100644 --- a/src/dev.rs +++ b/src/dev.rs @@ -58,6 +58,7 @@ pub enum VerifyFailure { /// dev::{MockProver, VerifyFailure}, /// pasta::Fp, /// plonk::{Advice, Assignment, Circuit, Column, ConstraintSystem, Error}, +/// poly::Rotation, /// }; /// const K: u32 = 5; /// @@ -81,9 +82,9 @@ pub enum VerifyFailure { /// let c = meta.advice_column(); /// /// meta.create_gate(|meta| { -/// let a = meta.query_advice(a, 0); -/// let b = meta.query_advice(b, 0); -/// let c = meta.query_advice(c, 0); +/// let a = meta.query_advice(a, Rotation::cur()); +/// let b = meta.query_advice(b, Rotation::cur()); +/// let c = meta.query_advice(c, Rotation::cur()); /// /// // BUG: Should be a * b - c /// a * b + c diff --git a/src/plonk.rs b/src/plonk.rs index e4c7b5b5..bc819182 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -105,7 +105,10 @@ fn test_proving() { use crate::arithmetic::{Curve, FieldExt}; use crate::dev::MockProver; use crate::pasta::{EqAffine, Fp, Fq}; - use crate::poly::commitment::{Blind, Params}; + use crate::poly::{ + commitment::{Blind, Params}, + Rotation, + }; use crate::transcript::{DummyHashRead, DummyHashWrite}; use circuit::{Advice, Column, Fixed}; use std::marker::PhantomData; @@ -344,25 +347,25 @@ fn test_proving() { meta.lookup(&[a.into(), b.into()], &[sl.into(), sl2.into()]); meta.create_gate(|meta| { - let d = meta.query_advice(d, 1); - let a = meta.query_advice(a, 0); - let sf = meta.query_fixed(sf, 0); - let e = meta.query_advice(e, -1); - let b = meta.query_advice(b, 0); - let c = meta.query_advice(c, 0); + let d = meta.query_advice(d, Rotation::next()); + let a = meta.query_advice(a, Rotation::cur()); + let sf = meta.query_fixed(sf, Rotation::cur()); + let e = meta.query_advice(e, Rotation::prev()); + let b = meta.query_advice(b, Rotation::cur()); + let c = meta.query_advice(c, Rotation::cur()); - let sa = meta.query_fixed(sa, 0); - let sb = meta.query_fixed(sb, 0); - let sc = meta.query_fixed(sc, 0); - let sm = meta.query_fixed(sm, 0); + let sa = meta.query_fixed(sa, Rotation::cur()); + let sb = meta.query_fixed(sb, Rotation::cur()); + let sc = meta.query_fixed(sc, Rotation::cur()); + let sm = meta.query_fixed(sm, Rotation::cur()); a.clone() * sa + b.clone() * sb + a * b * sm + (c * sc * (-F::one())) + sf * (d * e) }); meta.create_gate(|meta| { - let a = meta.query_advice(a, 0); - let p = meta.query_aux(p, 0); - let sp = meta.query_fixed(sp, 0); + let a = meta.query_advice(a, Rotation::cur()); + let p = meta.query_aux(p, Rotation::cur()); + let sp = meta.query_fixed(sp, Rotation::cur()); sp * (a + p * (-F::one())) }); diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index 17673bf8..b2e7ab01 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -1,7 +1,6 @@ use core::cmp::max; use core::ops::{Add, Mul}; use ff::Field; -use std::collections::BTreeMap; use std::convert::TryFrom; use super::{lookup, permutation, Error}; @@ -307,9 +306,6 @@ pub struct ConstraintSystem { pub(crate) aux_queries: Vec<(Column, Rotation)>, pub(crate) fixed_queries: Vec<(Column, Rotation)>, - // Mapping from a witness vector rotation to the index in the point vector. - pub(crate) rotations: BTreeMap, - // Vector of permutation arguments, where each corresponds to a sequence of columns // that are involved in a permutation argument. pub(crate) permutations: Vec, @@ -321,9 +317,6 @@ pub struct ConstraintSystem { impl Default for ConstraintSystem { fn default() -> ConstraintSystem { - let mut rotations = BTreeMap::new(); - rotations.insert(Rotation::default(), PointIndex(0)); - ConstraintSystem { num_fixed_columns: 0, num_advice_columns: 0, @@ -332,7 +325,6 @@ impl Default for ConstraintSystem { fixed_queries: Vec::new(), advice_queries: Vec::new(), aux_queries: Vec::new(), - rotations, permutations: Vec::new(), lookups: Vec::new(), } @@ -343,12 +335,9 @@ impl ConstraintSystem { /// Add a permutation argument for some advice columns pub fn permutation(&mut self, columns: &[Column]) -> usize { let index = self.permutations.len(); - if self.permutations.is_empty() { - self.add_rotation(Rotation(-1)); - } for column in columns { - self.query_advice_index(*column, 0); + self.query_advice_index(*column, Rotation::cur()); } self.permutations .push(permutation::Argument::new(columns.to_vec())); @@ -367,15 +356,12 @@ impl ConstraintSystem { assert_eq!(input_columns.len(), table_columns.len()); let index = self.lookups.len(); - if self.lookups.is_empty() { - self.add_rotation(Rotation(-1)); - } for input in input_columns { - self.query_any_index(*input, 0); + self.query_any_index(*input, Rotation::cur()); } for table in table_columns { - self.query_any_index(*table, 0); + self.query_any_index(*table, Rotation::cur()); } self.lookups .push(lookup::Argument::new(input_columns, table_columns)); @@ -383,10 +369,7 @@ impl ConstraintSystem { index } - fn query_fixed_index(&mut self, column: Column, at: i32) -> usize { - let at = Rotation(at); - self.add_rotation(at); - + fn query_fixed_index(&mut self, column: Column, at: Rotation) -> usize { // Return existing query, if it exists for (index, fixed_query) in self.fixed_queries.iter().enumerate() { if fixed_query == &(column, at) { @@ -402,14 +385,11 @@ impl ConstraintSystem { } /// Query a fixed column at a relative position - pub fn query_fixed(&mut self, column: Column, at: i32) -> Expression { + pub fn query_fixed(&mut self, column: Column, at: Rotation) -> Expression { Expression::Fixed(self.query_fixed_index(column, at)) } - pub(crate) fn query_advice_index(&mut self, column: Column, at: i32) -> usize { - let at = Rotation(at); - self.add_rotation(at); - + pub(crate) fn query_advice_index(&mut self, column: Column, at: Rotation) -> usize { // Return existing query, if it exists for (index, advice_query) in self.advice_queries.iter().enumerate() { if advice_query == &(column, at) { @@ -425,14 +405,11 @@ impl ConstraintSystem { } /// Query an advice column at a relative position - pub fn query_advice(&mut self, column: Column, at: i32) -> Expression { + pub fn query_advice(&mut self, column: Column, at: Rotation) -> Expression { Expression::Advice(self.query_advice_index(column, at)) } - fn query_aux_index(&mut self, column: Column, at: i32) -> usize { - let at = Rotation(at); - self.add_rotation(at); - + fn query_aux_index(&mut self, column: Column, at: Rotation) -> usize { // Return existing query, if it exists for (index, aux_query) in self.aux_queries.iter().enumerate() { if aux_query == &(column, at) { @@ -448,11 +425,11 @@ impl ConstraintSystem { } /// Query an auxiliary column at a relative position - pub fn query_aux(&mut self, column: Column, at: i32) -> Expression { + pub fn query_aux(&mut self, column: Column, at: Rotation) -> Expression { Expression::Aux(self.query_aux_index(column, at)) } - fn query_any_index(&mut self, column: Column, at: i32) -> usize { + fn query_any_index(&mut self, column: Column, at: Rotation) -> usize { match column.column_type() { Any::Advice => self.query_advice_index(Column::::try_from(column).unwrap(), at), Any::Fixed => self.query_fixed_index(Column::::try_from(column).unwrap(), at), @@ -461,7 +438,7 @@ impl ConstraintSystem { } /// Query an Any column at a relative position - pub fn query_any(&mut self, column: Column, at: i32) -> Expression { + pub fn query_any(&mut self, column: Column, at: Rotation) -> Expression { match column.column_type() { Any::Advice => Expression::Advice( self.query_advice_index(Column::::try_from(column).unwrap(), at), @@ -475,8 +452,7 @@ impl ConstraintSystem { } } - pub(crate) fn get_advice_query_index(&self, column: Column, at: i32) -> usize { - let at = Rotation(at); + pub(crate) fn get_advice_query_index(&self, column: Column, at: Rotation) -> usize { for (index, advice_query) in self.advice_queries.iter().enumerate() { if advice_query == &(column, at) { return index; @@ -486,8 +462,7 @@ impl ConstraintSystem { panic!("get_advice_query_index called for non-existent query"); } - pub(crate) fn get_fixed_query_index(&self, column: Column, at: i32) -> usize { - let at = Rotation(at); + pub(crate) fn get_fixed_query_index(&self, column: Column, at: Rotation) -> usize { for (index, fixed_query) in self.fixed_queries.iter().enumerate() { if fixed_query == &(column, at) { return index; @@ -497,8 +472,7 @@ impl ConstraintSystem { panic!("get_fixed_query_index called for non-existent query"); } - pub(crate) fn get_aux_query_index(&self, column: Column, at: i32) -> usize { - let at = Rotation(at); + pub(crate) fn get_aux_query_index(&self, column: Column, at: Rotation) -> usize { for (index, aux_query) in self.aux_queries.iter().enumerate() { if aux_query == &(column, at) { return index; @@ -508,7 +482,7 @@ impl ConstraintSystem { panic!("get_aux_query_index called for non-existent query"); } - pub(crate) fn get_any_query_index(&self, column: Column, at: i32) -> usize { + pub(crate) fn get_any_query_index(&self, column: Column, at: Rotation) -> usize { match column.column_type() { Any::Advice => { self.get_advice_query_index(Column::::try_from(column).unwrap(), at) @@ -555,9 +529,4 @@ impl ConstraintSystem { self.num_aux_columns += 1; tmp } - - fn add_rotation(&mut self, at: Rotation) { - let len = self.rotations.len(); - self.rotations.entry(at).or_insert(PointIndex(len)); - } } diff --git a/src/plonk/keygen.rs b/src/plonk/keygen.rs index 5a2aad8c..94a020a5 100644 --- a/src/plonk/keygen.rs +++ b/src/plonk/keygen.rs @@ -147,7 +147,7 @@ where let mut l0 = domain.empty_lagrange(); l0[0] = C::Scalar::one(); let l0 = domain.lagrange_to_coeff(l0); - let l0 = domain.coeff_to_extended(l0, Rotation::default()); + let l0 = domain.coeff_to_extended(l0, Rotation::cur()); Ok(ProvingKey { vk: VerifyingKey { diff --git a/src/plonk/lookup/prover.rs b/src/plonk/lookup/prover.rs index 2ee207d2..4df79a70 100644 --- a/src/plonk/lookup/prover.rs +++ b/src/plonk/lookup/prover.rs @@ -94,7 +94,7 @@ impl Argument { }; ( &values[column.index()], - &cosets[pk.vk.cs.get_any_query_index(column, 0)], + &cosets[pk.vk.cs.get_any_query_index(column, Rotation::cur())], ) }) .unzip(); @@ -148,7 +148,7 @@ impl Argument { let permuted_input_coset = pk .vk .domain - .coeff_to_extended(permuted_input_poly.clone(), Rotation::default()); + .coeff_to_extended(permuted_input_poly.clone(), Rotation::cur()); let permuted_input_inv_coset = pk .vk .domain @@ -156,7 +156,7 @@ impl Argument { let permuted_table_coset = pk .vk .domain - .coeff_to_extended(permuted_table_poly.clone(), Rotation::default()); + .coeff_to_extended(permuted_table_poly.clone(), Rotation::cur()); Ok(Permuted { unpermuted_input_columns, @@ -310,11 +310,8 @@ impl<'a, C: CurveAffine> Permuted<'a, 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::default()); - let product_inv_coset = pk.vk.domain.coeff_to_extended(z.clone(), Rotation(-1)); + let product_coset = pk.vk.domain.coeff_to_extended(z.clone(), Rotation::cur()); + let product_inv_coset = pk.vk.domain.coeff_to_extended(z.clone(), Rotation::prev()); // Hash product commitment transcript diff --git a/src/plonk/lookup/verifier.rs b/src/plonk/lookup/verifier.rs index 317f6acd..272191e8 100644 --- a/src/plonk/lookup/verifier.rs +++ b/src/plonk/lookup/verifier.rs @@ -120,7 +120,7 @@ impl Evaluated { columns .iter() .map(|column| { - let index = vk.cs.get_any_query_index(*column, 0); + let index = vk.cs.get_any_query_index(*column, Rotation::cur()); match column.column_type() { Any::Advice => advice_evals[index], Any::Fixed => fixed_evals[index], diff --git a/src/plonk/permutation/keygen.rs b/src/plonk/permutation/keygen.rs index aa95fe58..017bf157 100644 --- a/src/plonk/permutation/keygen.rs +++ b/src/plonk/permutation/keygen.rs @@ -164,7 +164,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::default())); + cosets.push(domain.coeff_to_extended(poly, Rotation::cur())); } ( ProvingKey { diff --git a/src/plonk/permutation/prover.rs b/src/plonk/permutation/prover.rs index fe7dd2f2..843e4324 100644 --- a/src/plonk/permutation/prover.rs +++ b/src/plonk/permutation/prover.rs @@ -113,8 +113,8 @@ impl Argument { let permutation_product_blind = blind; let z = domain.lagrange_to_coeff(z); let permutation_product_poly = z.clone(); - let permutation_product_coset = domain.coeff_to_extended(z.clone(), Rotation::default()); - let permutation_product_coset_inv = domain.coeff_to_extended(z, Rotation(-1)); + let permutation_product_coset = domain.coeff_to_extended(z.clone(), Rotation::cur()); + let permutation_product_coset_inv = domain.coeff_to_extended(z, Rotation::prev()); let permutation_product_commitment = permutation_product_commitment_projective.to_affine(); @@ -158,7 +158,9 @@ impl Committed { for (advice, permutation) in p .columns .iter() - .map(|&column| &advice_cosets[pk.vk.cs.get_advice_query_index(column, 0)]) + .map(|&column| { + &advice_cosets[pk.vk.cs.get_advice_query_index(column, Rotation::cur())] + }) .zip(pkey.cosets.iter()) { parallelize(&mut left, |left, start| { @@ -175,11 +177,9 @@ impl Committed { let mut right = self.permutation_product_coset_inv.clone(); let mut current_delta = *beta * &C::Scalar::ZETA; let step = domain.get_extended_omega(); - for advice in p - .columns - .iter() - .map(|&column| &advice_cosets[pk.vk.cs.get_advice_query_index(column, 0)]) - { + for advice in p.columns.iter().map(|&column| { + &advice_cosets[pk.vk.cs.get_advice_query_index(column, Rotation::cur())] + }) { parallelize(&mut right, move |right, start| { let mut beta_term = current_delta * &step.pow_vartime(&[start as u64, 0, 0, 0]); diff --git a/src/plonk/permutation/verifier.rs b/src/plonk/permutation/verifier.rs index c4e6be13..9f865e7b 100644 --- a/src/plonk/permutation/verifier.rs +++ b/src/plonk/permutation/verifier.rs @@ -88,7 +88,9 @@ impl Evaluated { for (advice_eval, permutation_eval) in p .columns .iter() - .map(|&column| advice_evals[vk.cs.get_advice_query_index(column, 0)]) + .map(|&column| { + advice_evals[vk.cs.get_advice_query_index(column, Rotation::cur())] + }) .zip(self.permutation_evals.iter()) { left *= &(advice_eval + &(*beta * permutation_eval) + &*gamma); @@ -96,11 +98,9 @@ impl Evaluated { let mut right = self.permutation_product_inv_eval; let mut current_delta = *beta * &*x; - for advice_eval in p - .columns - .iter() - .map(|&column| advice_evals[vk.cs.get_advice_query_index(column, 0)]) - { + for advice_eval in p.columns.iter().map(|&column| { + advice_evals[vk.cs.get_advice_query_index(column, Rotation::cur())] + }) { right *= &(advice_eval + ¤t_delta + &*gamma); current_delta *= &C::Scalar::DELTA; } diff --git a/src/poly.rs b/src/poly.rs index 923d58ea..5ac1462c 100644 --- a/src/poly.rs +++ b/src/poly.rs @@ -200,3 +200,32 @@ impl<'a, F: Field, B: Basis> Mul for Polynomial { self } } + +/// Describes the relative rotation of a vector. Negative numbers represent +/// reverse (leftmost) rotations and positive numbers represent forward (rightmost) +/// rotations. Zero represents no rotation. +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct Rotation(pub i32); + +impl Default for Rotation { + fn default() -> Rotation { + Rotation(0) + } +} + +impl Rotation { + /// The current location in the evaluation domain + pub fn cur() -> Rotation { + Rotation(0) + } + + /// The previous location in the evaluation domain + pub fn prev() -> Rotation { + Rotation(-1) + } + + /// The next location in the evaluation domain + pub fn next() -> Rotation { + Rotation(1) + } +} diff --git a/src/poly/domain.rs b/src/poly/domain.rs index c6358acd..e8cc41ee 100644 --- a/src/poly/domain.rs +++ b/src/poly/domain.rs @@ -3,22 +3,11 @@ use crate::arithmetic::{best_fft, parallelize, BatchInvert, FieldExt, Group}; -use super::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial}; +use super::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, Rotation}; use ff::{Field, PrimeField}; use std::marker::PhantomData; -/// Describes a relative location in the evaluation domain; applying a rotation -/// by i will rotate the vector in the evaluation domain by i. -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] -pub struct Rotation(pub i32); - -impl Default for Rotation { - fn default() -> Rotation { - Rotation(0) - } -} - /// This structure contains precomputed constants and other details needed for /// performing operations on an evaluation domain of size $2^k$ and an extended /// domain of size $2^{k} * j$ with $j \neq 0$.