Try to simplify open_plonk and fri_combine_initial a bit more (#59)

* Try to simplify open_plonk and fri_combine_initial a bit more

- Use `alpha.powers()` in `open_plonk` instead of the more "manual" approach
- No more "manually" reducing with `alpha_powers`; now using helper methods for that.
- Renaming & other small tweaks

* Remove type hint

* Feedback
This commit is contained in:
Daniel Lubarov 2021-06-09 16:17:56 -07:00 committed by GitHub
parent 72c2e19bc5
commit 60f3773a23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 90 additions and 86 deletions

View File

@ -1,5 +1,4 @@
use anyhow::{ensure, Result};
use itertools::izip;
use crate::field::extension_field::{flatten, Extendable, FieldExtension, OEF};
use crate::field::field::Field;
@ -156,31 +155,29 @@ fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
let mut sum = F::Extension::ZERO;
// We will add three terms to `sum`:
// - one for polynomials opened at `x` only
// - one for polynomials opened at `x` and `g x`
// - one for polynomials opened at `x` and its conjugate
// - one for various polynomials which are opened at a single point `x`
// - one for Zs, which are opened at `x` and `g x`
// - one for wire polynomials, which are opened at `x` and its conjugate
let evals = [0, 1, 4]
let single_evals = [0, 1, 4]
.iter()
.flat_map(|&i| proof.unsalted_evals(i, config))
.map(|&e| F::Extension::from_basefield(e));
let openings = os
let single_openings = os
.constants
.iter()
.chain(&os.plonk_s_sigmas)
.chain(&os.quotient_polys);
let numerator = izip!(evals, openings, &mut alpha_powers)
.map(|(e, &o, a)| a * (e - o))
.sum::<F::Extension>();
let denominator = subgroup_x - zeta;
sum += numerator / denominator;
let single_diffs = single_evals.zip(single_openings).map(|(e, &o)| e - o);
let single_numerator = reduce_with_iter(single_diffs, &mut alpha_powers);
let single_denominator = subgroup_x - zeta;
sum += single_numerator / single_denominator;
let ev: F::Extension = proof
let zs_evals = proof
.unsalted_evals(3, config)
.iter()
.zip(alpha_powers.clone())
.map(|(&e, a)| a * e.into())
.sum();
.map(|&e| F::Extension::from_basefield(e));
let zs_composition_eval = reduce_with_iter(zs_evals, alpha_powers.clone());
let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta;
let zs_interpol = interpolant(&[
(zeta, reduce_with_iter(&os.plonk_zs, alpha_powers.clone())),
@ -189,25 +186,24 @@ fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers),
),
]);
let numerator = ev - zs_interpol.eval(subgroup_x);
let denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right);
sum += numerator / denominator;
let zs_numerator = zs_composition_eval - zs_interpol.eval(subgroup_x);
let zs_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right);
sum += zs_numerator / zs_denominator;
let ev: F::Extension = proof
let wire_evals = proof
.unsalted_evals(2, config)
.iter()
.zip(alpha_powers.clone())
.map(|(&e, a)| a * e.into())
.sum();
.map(|&e| F::Extension::from_basefield(e));
let wire_composition_eval = reduce_with_iter(wire_evals, alpha_powers.clone());
let zeta_frob = zeta.frobenius();
let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::<Vec<_>>();
let wire_evals_frob = os.wires.iter().map(|e| e.frobenius());
let wires_interpol = interpolant(&[
(zeta, reduce_with_iter(&os.wires, alpha_powers.clone())),
(zeta_frob, reduce_with_iter(&wire_evals_frob, alpha_powers)),
(zeta_frob, reduce_with_iter(wire_evals_frob, alpha_powers)),
]);
let numerator = ev - wires_interpol.eval(subgroup_x);
let denominator = (subgroup_x - zeta) * (subgroup_x - zeta_frob);
sum += numerator / denominator;
let wires_numerator = wire_composition_eval - wires_interpol.eval(subgroup_x);
let wires_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_frob);
sum += wires_numerator / wires_denominator;
sum
}

View File

@ -1,9 +1,12 @@
use std::borrow::Borrow;
use crate::circuit_builder::CircuitBuilder;
use crate::circuit_data::CommonCircuitData;
use crate::field::extension_field::target::ExtensionTarget;
use crate::field::extension_field::Extendable;
use crate::field::field::Field;
use crate::gates::gate::GateRef;
use crate::polynomial::polynomial::PolynomialCoeffs;
use crate::target::Target;
use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase};
@ -209,13 +212,26 @@ pub(crate) fn reduce_with_powers_recursive<F: Extendable<D>, const D: usize>(
todo!()
}
pub(crate) fn reduce_with_iter<F: Field, I>(terms: &[F], coeffs: I) -> F
where
I: IntoIterator<Item = F>,
{
let mut sum = F::ZERO;
for (&term, coeff) in terms.iter().zip(coeffs) {
sum += coeff * term;
}
sum
/// Reduce a sequence of field elements by the given coefficients.
pub(crate) fn reduce_with_iter<F: Field>(
terms: impl IntoIterator<Item = impl Borrow<F>>,
coeffs: impl IntoIterator<Item = impl Borrow<F>>,
) -> F {
terms
.into_iter()
.zip(coeffs)
.map(|(t, c)| *t.borrow() * *c.borrow())
.sum()
}
/// Reduce a sequence of polynomials by the given coefficients.
pub(crate) fn reduce_polys_with_iter<F: Field>(
polys: impl IntoIterator<Item = impl Borrow<PolynomialCoeffs<F>>>,
coeffs: impl IntoIterator<Item = impl Borrow<F>>,
) -> PolynomialCoeffs<F> {
polys
.into_iter()
.zip(coeffs)
.map(|(p, c)| p.borrow() * *c.borrow())
.sum()
}

View File

@ -8,7 +8,7 @@ use crate::field::lagrange::interpolant;
use crate::fri::{prover::fri_proof, verifier::verify_fri_proof, FriConfig};
use crate::merkle_tree::MerkleTree;
use crate::plonk_challenger::Challenger;
use crate::plonk_common::reduce_with_powers;
use crate::plonk_common::{reduce_polys_with_iter, reduce_with_iter};
use crate::polynomial::polynomial::PolynomialCoeffs;
use crate::proof::{FriProof, Hash, OpeningSet};
use crate::timed;
@ -90,7 +90,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
assert!(D > 1, "Not implemented for D=1.");
let degree_log = log2_strict(commitments[0].degree);
let g = F::Extension::primitive_root_of_unity(degree_log);
for &p in &[zeta, g * zeta] {
for p in &[zeta, g * zeta] {
assert_ne!(
p.exp(1 << degree_log as u64),
F::Extension::ONE,
@ -110,45 +110,34 @@ impl<F: Field> ListPolynomialCommitment<F> {
challenger.observe_opening_set(&os);
let alpha = challenger.get_extension_challenge();
let mut cur_alpha = F::Extension::ONE;
let mut alpha_powers = alpha.powers();
// Final low-degree polynomial that goes into FRI.
let mut final_poly = PolynomialCoeffs::empty();
// Count the total number of polynomials accumulated into `final_poly`.
let mut poly_count = 0;
// Polynomials opened at a single point.
let composition_poly = [0, 1, 4]
let single_polys = [0, 1, 4]
.iter()
.flat_map(|&i| &commitments[i].polynomials)
.rev()
.fold(PolynomialCoeffs::empty(), |acc, p| {
poly_count += 1;
&(&acc * alpha) + &p.to_extension()
});
let composition_eval = [&os.constants, &os.plonk_s_sigmas, &os.quotient_polys]
.iter()
.flat_map(|v| v.iter())
.rev()
.fold(F::Extension::ZERO, |acc, &e| acc * alpha + e);
.map(|p| p.to_extension());
let single_os = [&os.constants, &os.plonk_s_sigmas, &os.quotient_polys];
let single_evals = single_os.iter().flat_map(|v| v.iter());
let single_composition_poly = reduce_polys_with_iter(single_polys, alpha_powers.clone());
let single_composition_eval = reduce_with_iter(single_evals, &mut alpha_powers);
let quotient = Self::compute_quotient(&[zeta], &[composition_eval], &composition_poly);
final_poly = &final_poly + &(&quotient * cur_alpha);
cur_alpha = alpha.exp(poly_count);
let single_quotient = Self::compute_quotient(
&[zeta],
&[single_composition_eval],
&single_composition_poly,
);
final_poly = &final_poly + &single_quotient;
// Zs polynomials are opened at `zeta` and `g*zeta`.
let zs_composition_poly =
commitments[3]
.polynomials
.iter()
.rev()
.fold(PolynomialCoeffs::empty(), |acc, p| {
poly_count += 1;
&(&acc * alpha) + &p.to_extension()
});
let zs_polys = commitments[3].polynomials.iter().map(|p| p.to_extension());
let zs_composition_poly = reduce_polys_with_iter(zs_polys, alpha_powers.clone());
let zs_composition_evals = [
reduce_with_powers(&os.plonk_zs, alpha),
reduce_with_powers(&os.plonk_zs_right, alpha),
reduce_with_iter(&os.plonk_zs, alpha_powers.clone()),
reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers),
];
let zs_quotient = Self::compute_quotient(
@ -156,33 +145,25 @@ impl<F: Field> ListPolynomialCommitment<F> {
&zs_composition_evals,
&zs_composition_poly,
);
final_poly = &final_poly + &(&zs_quotient * cur_alpha);
cur_alpha = alpha.exp(poly_count);
final_poly = &final_poly + &zs_quotient;
// When working in an extension field, need to check that wires are in the base field.
// Check this by opening the wires polynomials at `zeta` and `zeta.frobenius()` and using the fact that
// a polynomial `f` is over the base field iff `f(z).frobenius()=f(z.frobenius())` with high probability.
let wires_composition_poly =
commitments[2]
.polynomials
.iter()
.rev()
.fold(PolynomialCoeffs::empty(), |acc, p| {
poly_count += 1;
&(&acc * alpha) + &p.to_extension()
});
let wire_polys = commitments[2].polynomials.iter().map(|p| p.to_extension());
let wire_composition_poly = reduce_polys_with_iter(wire_polys, alpha_powers.clone());
let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::<Vec<_>>();
let wires_composition_evals = [
reduce_with_powers(&os.wires, alpha),
reduce_with_powers(&wire_evals_frob, alpha),
let wire_composition_evals = [
reduce_with_iter(&os.wires, alpha_powers.clone()),
reduce_with_iter(&wire_evals_frob, alpha_powers),
];
let wires_quotient = Self::compute_quotient(
&[zeta, zeta.frobenius()],
&wires_composition_evals,
&wires_composition_poly,
&wire_composition_evals,
&wire_composition_poly,
);
final_poly = &final_poly + &(&wires_quotient * cur_alpha);
final_poly = &final_poly + &wires_quotient;
let lde_final_poly = final_poly.lde(config.rate_bits);
let lde_final_values = lde_final_poly
@ -275,9 +256,9 @@ impl<F: Field + Extendable<D>, const D: usize> OpeningProof<F, D> {
#[cfg(test)]
mod tests {
use anyhow::Result;
use rand::Rng;
use super::*;
use rand::Rng;
fn gen_random_test_case<F: Field + Extendable<D>, const D: usize>(
k: usize,
@ -359,8 +340,10 @@ mod tests {
}
mod quadratic {
use super::*;
use crate::field::crandall_field::CrandallField;
use super::*;
#[test]
fn test_batch_polynomial_commitment() -> Result<()> {
check_batch_polynomial_commitment::<CrandallField, 2>()
@ -368,8 +351,10 @@ mod tests {
}
mod quartic {
use super::*;
use crate::field::crandall_field::CrandallField;
use super::*;
#[test]
fn test_batch_polynomial_commitment() -> Result<()> {
check_batch_polynomial_commitment::<CrandallField, 4>()

View File

@ -5,6 +5,7 @@ use crate::field::extension_field::Extendable;
use crate::field::fft::{fft, ifft};
use crate::field::field::Field;
use crate::util::log2_strict;
use std::iter::Sum;
/// A polynomial in point-value form.
///
@ -222,6 +223,12 @@ impl<F: Field> Add for &PolynomialCoeffs<F> {
}
}
impl<F: Field> Sum for PolynomialCoeffs<F> {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::empty(), |acc, p| &acc + &p)
}
}
impl<F: Field> Sub for &PolynomialCoeffs<F> {
type Output = PolynomialCoeffs<F>;