Use single-point opening expressions (#416)

I.e. instead of opening `Z` at `zeta` and `g zeta` by running FRI on a quotient involving an interpolant, we just run FRI on two separate opening expressions, one for `zeta` and one for `g zeta`.

A few motivations for this:
- I think this will make it slightly easier to generalize our FRI code to work with STARKs. I.e. if we have an object representing the structure of polynomial openings in an IOP, that object will be slightly simpler.
- It's less code. We could potentially remove some more code, e.g. the generality of `compute_quotient` is no longer needed, but I left it for now.
- It saves 3 gates!
This commit is contained in:
Daniel Lubarov 2022-01-03 08:34:44 -08:00 committed by GitHub
parent 6991257da5
commit 3de8d36c3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 73 deletions

View File

@ -172,21 +172,15 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
// Final low-degree polynomial that goes into FRI.
let mut final_poly = PolynomialCoeffs::empty();
let mut zs_polys = commitments[PlonkPolynomials::ZS_PARTIAL_PRODUCTS.index]
.polynomials
.iter()
.collect::<Vec<_>>();
let partial_products_polys = zs_polys.split_off(common_data.zs_range().end);
// Polynomials opened at a single point.
// All polynomials are opened at `zeta`.
let single_polys = [
PlonkPolynomials::CONSTANTS_SIGMAS,
PlonkPolynomials::WIRES,
PlonkPolynomials::ZS_PARTIAL_PRODUCTS,
PlonkPolynomials::QUOTIENT,
]
.iter()
.flat_map(|&p| &commitments[p.index].polynomials)
.chain(partial_products_polys);
.flat_map(|&p| &commitments[p.index].polynomials);
let single_composition_poly = timed!(
timing,
"reduce single polys",
@ -197,14 +191,13 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
final_poly += single_quotient;
alpha.reset();
// Zs polynomials are opened at `zeta` and `g*zeta`.
let zs_composition_poly = timed!(
timing,
"reduce Z polys",
alpha.reduce_polys_base(zs_polys.into_iter())
);
// Z polynomials have an additional opening at `g zeta`.
let zs_polys = &commitments[PlonkPolynomials::ZS_PARTIAL_PRODUCTS.index].polynomials
[common_data.zs_range()];
let zs_composition_poly =
timed!(timing, "reduce Z polys", alpha.reduce_polys_base(zs_polys));
let zs_quotient = Self::compute_quotient([zeta, g * zeta], zs_composition_poly);
let zs_quotient = Self::compute_quotient([g * zeta], zs_composition_poly);
alpha.shift_poly(&mut final_poly);
final_poly += zs_quotient;

View File

@ -274,22 +274,16 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let mut alpha = ReducingFactorTarget::new(alpha);
let mut sum = self.zero_extension();
// We will add three terms to `sum`:
// - one for polynomials opened at `x` only
// - one for polynomials opened at `x` and `g x`
// Polynomials opened at `x`, i.e., the constants-sigmas, wires, quotient and partial products polynomials.
// We will add two terms to `sum`: one for openings at `x`, and one for openings at `g x`.
// All polynomials are opened at `x`.
let single_evals = [
PlonkPolynomials::CONSTANTS_SIGMAS,
PlonkPolynomials::WIRES,
PlonkPolynomials::ZS_PARTIAL_PRODUCTS,
PlonkPolynomials::QUOTIENT,
]
.iter()
.flat_map(|&p| proof.unsalted_evals(p, config.zero_knowledge))
.chain(
&proof.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS, config.zero_knowledge)
[common_data.partial_products_range()],
)
.copied()
.collect::<Vec<_>>();
let single_composition_eval = alpha.reduce_base(&single_evals, self);
@ -307,16 +301,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
.collect::<Vec<_>>();
let zs_composition_eval = alpha.reduce_base(&zs_evals, self);
let interpol_val = self.mul_add_extension(
vanish_zeta,
precomputed_reduced_evals.slope,
precomputed_reduced_evals.zs,
);
let zs_numerator = self.sub_extension(zs_composition_eval, interpol_val);
let vanish_zeta_right =
self.sub_extension(subgroup_x, precomputed_reduced_evals.zeta_right);
sum = alpha.shift(sum, self);
let zs_denominator = self.mul_extension(vanish_zeta, vanish_zeta_right);
let zs_numerator =
self.sub_extension(zs_composition_eval, precomputed_reduced_evals.zs_right);
let zs_denominator = self.sub_extension(subgroup_x, precomputed_reduced_evals.zeta_right);
sum = alpha.shift(sum, self); // TODO: alpha^count could be precomputed.
sum = self.div_add_extension(zs_numerator, zs_denominator, sum);
sum
@ -470,9 +458,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
#[derive(Copy, Clone)]
struct PrecomputedReducedEvalsTarget<const D: usize> {
pub single: ExtensionTarget<D>,
pub zs: ExtensionTarget<D>,
/// Slope of the line from `(zeta, zs)` to `(zeta_right, zs_right)`.
pub slope: ExtensionTarget<D>,
pub zs_right: ExtensionTarget<D>,
pub zeta_right: ExtensionTarget<D>,
}
@ -490,24 +476,21 @@ impl<const D: usize> PrecomputedReducedEvalsTarget<D> {
.iter()
.chain(&os.plonk_sigmas)
.chain(&os.wires)
.chain(&os.quotient_polys)
.chain(&os.plonk_zs)
.chain(&os.partial_products)
.chain(&os.quotient_polys)
.copied()
.collect::<Vec<_>>(),
builder,
);
let zs = alpha.reduce(&os.plonk_zs, builder);
let zs_right = alpha.reduce(&os.plonk_zs_right, builder);
let g = builder.constant_extension(F::Extension::primitive_root_of_unity(degree_log));
let zeta_right = builder.mul_extension(g, zeta);
let numerator = builder.sub_extension(zs_right, zs);
let denominator = builder.sub_extension(zeta_right, zeta);
Self {
single,
zs,
slope: builder.div_extension(numerator, denominator),
zs_right,
zeta_right,
}
}

View File

@ -1,7 +1,7 @@
use anyhow::{ensure, Result};
use plonky2_field::extension_field::{flatten, Extendable, FieldExtension};
use plonky2_field::field_types::Field;
use plonky2_field::interpolation::{barycentric_weights, interpolate, interpolate2};
use plonky2_field::interpolation::{barycentric_weights, interpolate};
use plonky2_util::{log2_strict, reverse_index_bits_in_place};
use crate::fri::proof::{FriInitialTreeProof, FriProof, FriQueryRound};
@ -127,7 +127,6 @@ fn fri_verify_initial_proof<F: RichField, H: Hasher<F>>(
#[derive(Copy, Clone, Debug)]
pub(crate) struct PrecomputedReducedEvals<F: RichField + Extendable<D>, const D: usize> {
pub single: F::Extension,
pub zs: F::Extension,
pub zs_right: F::Extension,
}
@ -139,17 +138,13 @@ impl<F: RichField + Extendable<D>, const D: usize> PrecomputedReducedEvals<F, D>
.iter()
.chain(&os.plonk_sigmas)
.chain(&os.wires)
.chain(&os.quotient_polys)
.chain(&os.partial_products),
.chain(&os.plonk_zs)
.chain(&os.partial_products)
.chain(&os.quotient_polys),
);
let zs = alpha.reduce(os.plonk_zs.iter());
let zs_right = alpha.reduce(os.plonk_zs_right.iter());
Self {
single,
zs,
zs_right,
}
Self { single, zs_right }
}
}
@ -172,22 +167,16 @@ pub(crate) fn fri_combine_initial<
let mut alpha = ReducingFactor::new(alpha);
let mut sum = F::Extension::ZERO;
// We will add three terms to `sum`:
// - one for various polynomials which are opened at a single point `x`
// - one for Zs, which are opened at `x` and `g x`
// Polynomials opened at `x`, i.e., the constants-sigmas, wires, quotient and partial products polynomials.
// We will add two terms to `sum`: one for openings at `x`, and one for openings at `g x`.
// All polynomials are opened at `x`.
let single_evals = [
PlonkPolynomials::CONSTANTS_SIGMAS,
PlonkPolynomials::WIRES,
PlonkPolynomials::ZS_PARTIAL_PRODUCTS,
PlonkPolynomials::QUOTIENT,
]
.iter()
.flat_map(|&p| proof.unsalted_evals(p, config.zero_knowledge))
.chain(
&proof.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS, config.zero_knowledge)
[common_data.partial_products_range()],
)
.map(|&e| F::Extension::from_basefield(e));
let single_composition_eval = alpha.reduce(single_evals);
let single_numerator = single_composition_eval - precomputed_reduced_evals.single;
@ -195,7 +184,7 @@ pub(crate) fn fri_combine_initial<
sum += single_numerator / single_denominator;
alpha.reset();
// Polynomials opened at `x` and `g x`, i.e., the Zs polynomials.
// Z polynomials have an additional opening at `g x`.
let zs_evals = proof
.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS, config.zero_knowledge)
.iter()
@ -203,15 +192,8 @@ pub(crate) fn fri_combine_initial<
.take(common_data.zs_range().end);
let zs_composition_eval = alpha.reduce(zs_evals);
let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta;
let zs_interpol = interpolate2(
[
(zeta, precomputed_reduced_evals.zs),
(zeta_right, precomputed_reduced_evals.zs_right),
],
subgroup_x,
);
let zs_numerator = zs_composition_eval - zs_interpol;
let zs_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right);
let zs_numerator = zs_composition_eval - precomputed_reduced_evals.zs_right;
let zs_denominator = subgroup_x - zeta_right;
sum = alpha.shift(sum);
sum += zs_numerator / zs_denominator;