Split coset step up so that we can query wires at multiple spots.

This commit is contained in:
Sean Bowe 2020-08-24 13:50:52 -06:00
parent 24b7e6cc7c
commit 6051814c4b
No known key found for this signature in database
GPG key ID: 95684257D8F8B031
4 changed files with 79 additions and 39 deletions

View file

@ -111,9 +111,9 @@ pub trait Circuit<F: Field> {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Polynomial<F> { pub enum Polynomial<F> {
/// This is a fixed wire queried at a certain relative location /// This is a fixed wire queried at a certain relative location
Fixed(FixedWire, isize), Fixed(FixedWire, i32),
/// This is an advice (witness) wire queried at a certain relative location /// This is an advice (witness) wire queried at a certain relative location
Advice(AdviceWire, isize), Advice(AdviceWire, i32),
/// This is the sum of two polynomials /// This is the sum of two polynomials
Sum(Box<Polynomial<F>>, Box<Polynomial<F>>), Sum(Box<Polynomial<F>>, Box<Polynomial<F>>),
/// This is the product of two polynomials /// This is the product of two polynomials
@ -125,8 +125,8 @@ pub enum Polynomial<F> {
impl<F: Field> Polynomial<F> { impl<F: Field> Polynomial<F> {
fn evaluate<T>( fn evaluate<T>(
&self, &self,
fixed_wire: &impl Fn(FixedWire, isize) -> T, fixed_wire: &impl Fn(FixedWire, i32) -> T,
advice_wire: &impl Fn(AdviceWire, isize) -> T, advice_wire: &impl Fn(AdviceWire, i32) -> T,
sum: &impl Fn(T, T) -> T, sum: &impl Fn(T, T) -> T,
product: &impl Fn(T, T) -> T, product: &impl Fn(T, T) -> T,
scaled: &impl Fn(T, F) -> T, scaled: &impl Fn(T, F) -> T,
@ -193,8 +193,8 @@ pub struct MetaCircuit<F> {
pub(crate) num_advice_wires: usize, pub(crate) num_advice_wires: usize,
// permutations: Vec<Vec<Wire>>, // permutations: Vec<Vec<Wire>>,
gates: Vec<Polynomial<F>>, gates: Vec<Polynomial<F>>,
advice_queries: HashMap<(AdviceWire, isize), usize>, advice_queries: HashMap<(AdviceWire, i32), usize>,
fixed_queries: HashMap<(FixedWire, isize), usize>, fixed_queries: HashMap<(FixedWire, i32), usize>,
// num_queries: usize, // num_queries: usize,
} }
@ -212,7 +212,7 @@ impl<F: Field> Default for MetaCircuit<F> {
impl<F: Field> MetaCircuit<F> { impl<F: Field> MetaCircuit<F> {
/// Query a fixed wire at a relative position /// Query a fixed wire at a relative position
pub fn query_fixed(&mut self, wire: FixedWire, at: isize) -> Polynomial<F> { pub fn query_fixed(&mut self, wire: FixedWire, at: i32) -> Polynomial<F> {
let len = self.fixed_queries.len(); let len = self.fixed_queries.len();
self.fixed_queries.entry((wire, at)).or_insert_with(|| len); self.fixed_queries.entry((wire, at)).or_insert_with(|| len);
@ -220,7 +220,7 @@ impl<F: Field> MetaCircuit<F> {
} }
/// Query an advice wire at a relative position /// Query an advice wire at a relative position
pub fn query_advice(&mut self, wire: AdviceWire, at: isize) -> Polynomial<F> { pub fn query_advice(&mut self, wire: AdviceWire, at: i32) -> Polynomial<F> {
let len = self.advice_queries.len(); let len = self.advice_queries.len();
self.advice_queries.entry((wire, at)).or_insert_with(|| len); self.advice_queries.entry((wire, at)).or_insert_with(|| len);

View file

@ -8,6 +8,7 @@ pub struct EvaluationDomain<G: Group> {
n: u64, n: u64,
k: u32, k: u32,
extended_k: u32, extended_k: u32,
omega: G::Scalar,
omega_inv: G::Scalar, omega_inv: G::Scalar,
extended_omega: G::Scalar, extended_omega: G::Scalar,
extended_omega_inv: G::Scalar, extended_omega_inv: G::Scalar,
@ -91,6 +92,7 @@ impl<G: Group> EvaluationDomain<G> {
n, n,
k, k,
extended_k, extended_k,
omega,
omega_inv, omega_inv,
extended_omega, extended_omega,
extended_omega_inv, extended_omega_inv,
@ -103,32 +105,42 @@ impl<G: Group> EvaluationDomain<G> {
} }
} }
/// This takes us from an n-length vector into the coset evaluation domain. /// This takes us from an n-length vector into the coefficient form.
/// Also returns the polynomial.
/// ///
/// This function will panic if the provided vector is not the correct /// This function will panic if the provided vector is not the correct
/// length. /// length.
pub fn obtain_coset(&self, mut a: Vec<G>) -> (Vec<G>, Vec<G>) { pub fn obtain_poly(&self, mut a: Vec<G>) -> Vec<G> {
assert_eq!(a.len(), 1 << self.k); assert_eq!(a.len(), 1 << self.k);
// Perform inverse FFT to obtain the polynomial in coefficient form // Perform inverse FFT to obtain the polynomial in coefficient form
Self::ifft(&mut a, self.omega_inv, self.k, self.ifft_divisor); Self::ifft(&mut a, self.omega_inv, self.k, self.ifft_divisor);
// Keep this polynomial around; we'll need to evaluate it at arbitrary a
// points later. }
let old = a.clone();
// Distributes powers so that an FFT will move us into the coset /// This takes us from an n-length coefficient vector into the coset
// evaluation domain. /// evaluation domain.
Self::distribute_powers(&mut a, self.g_coset); ///
/// This function will panic if the provided vector is not the correct
/// length.
pub fn obtain_coset(&self, mut a: Vec<G>, index: i32) -> Vec<G> {
assert_eq!(a.len(), 1 << self.k);
// Resize to account for the quotient polynomial's size assert!(index != i32::MIN);
if index == 0 {
Self::distribute_powers_zeta(&mut a, self.g_coset);
} else {
let mut g = G::Scalar::ZETA;
if index > 0 {
g *= &self.omega.pow_vartime(&[index as u64, 0, 0, 0]);
} else {
g *= &self.omega_inv.pow_vartime(&[index.abs() as u64, 0, 0, 0]);
}
Self::distribute_powers(&mut a, g);
}
a.resize(1 << self.extended_k, G::group_zero()); a.resize(1 << self.extended_k, G::group_zero());
// Move into coset evaluation domain
best_fft(&mut a, self.extended_omega, self.extended_k); best_fft(&mut a, self.extended_omega, self.extended_k);
a
(a, old)
} }
/// This takes us from the coset evaluation domain and gets us the quotient /// This takes us from the coset evaluation domain and gets us the quotient
@ -176,7 +188,7 @@ impl<G: Group> EvaluationDomain<G> {
h_poly h_poly
} }
fn distribute_powers(mut a: &mut [G], g: G::Scalar) { fn distribute_powers_zeta(mut a: &mut [G], g: G::Scalar) {
let coset_powers = [g, g.square()]; let coset_powers = [g, g.square()];
parallelize(&mut a, |a, mut index| { parallelize(&mut a, |a, mut index| {
for a in a { for a in a {
@ -190,6 +202,16 @@ impl<G: Group> EvaluationDomain<G> {
}); });
} }
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) { fn ifft(a: &mut [G], omega_inv: G::Scalar, log_n: u32, divisor: G::Scalar) {
best_fft(a, omega_inv, log_n); best_fft(a, omega_inv, log_n);
parallelize(a, |a, _| { parallelize(a, |a, _| {

View file

@ -160,15 +160,24 @@ impl<C: CurveAffine> Proof<C> {
let domain = &srs.domain; let domain = &srs.domain;
let (a_coset, a_poly) = domain.obtain_coset(witness.a); let a_poly = domain.obtain_poly(witness.a);
let (b_coset, b_poly) = domain.obtain_coset(witness.b); let b_poly = domain.obtain_poly(witness.b);
let (c_coset, c_poly) = domain.obtain_coset(witness.c); let c_poly = domain.obtain_poly(witness.c);
let (d_coset, d_poly) = domain.obtain_coset(witness.d); let d_poly = domain.obtain_poly(witness.d);
let a_coset = domain.obtain_coset(a_poly.clone(), 0);
let b_coset = domain.obtain_coset(b_poly.clone(), 0);
let c_coset = domain.obtain_coset(c_poly.clone(), 0);
let d_coset = domain.obtain_coset(d_poly.clone(), 0);
let advice_polys: Vec<_> = witness let advice_polys: Vec<_> = witness
.advice .advice
.into_iter() .into_iter()
.map(|poly| domain.obtain_coset(poly)) .map(|poly| {
let poly = domain.obtain_poly(poly);
let coset = domain.obtain_coset(poly.clone(), 0);
(poly, coset)
})
.collect(); .collect();
// (a * sa) + (b * sb) + (a * sm * b) + (d * sd) - (c * sc) // (a * sa) + (b * sb) + (a * sm * b) + (d * sd) - (c * sc)

View file

@ -118,24 +118,33 @@ impl<C: CurveAffine> SRS<C> {
let domain = EvaluationDomain::new(GATE_DEGREE, params.k); let domain = EvaluationDomain::new(GATE_DEGREE, params.k);
let sa = domain.obtain_coset(assembly.sa); let sa_poly = domain.obtain_poly(assembly.sa);
let sb = domain.obtain_coset(assembly.sb); let sb_poly = domain.obtain_poly(assembly.sb);
let sc = domain.obtain_coset(assembly.sc); let sc_poly = domain.obtain_poly(assembly.sc);
let sd = domain.obtain_coset(assembly.sd); let sd_poly = domain.obtain_poly(assembly.sd);
let sm = domain.obtain_coset(assembly.sm); let sm_poly = domain.obtain_poly(assembly.sm);
let sa_coset = domain.obtain_coset(sa_poly.clone(), 0);
let sb_coset = domain.obtain_coset(sb_poly.clone(), 0);
let sc_coset = domain.obtain_coset(sc_poly.clone(), 0);
let sd_coset = domain.obtain_coset(sd_poly.clone(), 0);
let sm_coset = domain.obtain_coset(sm_poly.clone(), 0);
let fixed_polys = assembly let fixed_polys = assembly
.fixed .fixed
.into_iter() .into_iter()
.map(|poly| domain.obtain_coset(poly)) .map(|poly| {
let coeffs = domain.obtain_poly(poly);
let coset = domain.obtain_coset(coeffs.clone(), 0);
(coeffs, coset)
})
.collect(); .collect();
Ok(SRS { Ok(SRS {
sa, sa: (sa_coset, sa_poly),
sb, sb: (sb_coset, sb_poly),
sc, sc: (sc_coset, sc_poly),
sd, sd: (sd_coset, sd_poly),
sm, sm: (sm_coset, sm_poly),
sa_commitment, sa_commitment,
sb_commitment, sb_commitment,
sc_commitment, sc_commitment,