Make FRI more generic (#419)

* Make FRI more generic

* PR feedback
This commit is contained in:
Daniel Lubarov 2022-01-06 11:40:08 -08:00 committed by GitHub
parent f072d09ae4
commit bf30fed701
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 476 additions and 300 deletions

View File

@ -1,10 +1,11 @@
use crate::fri::reduction_strategies::FriReductionStrategy;
pub mod commitment;
pub mod oracle;
pub mod proof;
pub mod prover;
pub mod recursive_verifier;
pub mod reduction_strategies;
pub mod structure;
pub mod verifier;
#[derive(Debug, Clone, Eq, PartialEq)]

View File

@ -7,13 +7,12 @@ use rayon::prelude::*;
use crate::fri::proof::FriProof;
use crate::fri::prover::fri_proof;
use crate::fri::structure::{FriBatchInfo, FriInstanceInfo};
use crate::hash::hash_types::RichField;
use crate::hash::merkle_tree::MerkleTree;
use crate::iop::challenger::Challenger;
use crate::plonk::circuit_data::CommonCircuitData;
use crate::plonk::config::GenericConfig;
use crate::plonk::plonk_common::PlonkPolynomials;
use crate::plonk::proof::OpeningSet;
use crate::timed;
use crate::util::reducing::ReducingFactor;
use crate::util::reverse_bits;
@ -23,12 +22,9 @@ use crate::util::transpose;
/// Four (~64 bit) field elements gives ~128 bit security.
pub const SALT_SIZE: usize = 4;
/// Represents a batch FRI based commitment to a list of polynomials.
pub struct PolynomialBatchCommitment<
F: RichField + Extendable<D>,
C: GenericConfig<D, F = F>,
const D: usize,
> {
/// Represents a FRI oracle, i.e. a batch of polynomials which have been Merklized.
pub struct PolynomialBatch<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
{
pub polynomials: Vec<PolynomialCoeffs<F>>,
pub merkle_tree: MerkleTree<F, C::Hasher>,
pub degree_log: usize,
@ -37,7 +33,7 @@ pub struct PolynomialBatchCommitment<
}
impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
PolynomialBatchCommitment<F, C, D>
PolynomialBatch<F, C, D>
{
/// Creates a list polynomial commitment for the polynomials interpolating the values in `values`.
pub(crate) fn from_values(
@ -130,78 +126,36 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
&slice[..slice.len() - if self.blinding { SALT_SIZE } else { 0 }]
}
/// Takes the commitments to the constants - sigmas - wires - zs - quotient — polynomials,
/// and an opening point `zeta` and produces a batched opening proof + opening set.
pub(crate) fn open_plonk(
commitments: &[&Self; 4],
zeta: F::Extension,
/// Produces a batch opening proof.
pub(crate) fn prove_openings(
instance: &FriInstanceInfo<F, D>,
oracles: &[&Self],
challenger: &mut Challenger<F, C::Hasher>,
common_data: &CommonCircuitData<F, C, D>,
timing: &mut TimingTree,
) -> (FriProof<F, C::Hasher, D>, OpeningSet<F, D>) {
let config = &common_data.config;
) -> FriProof<F, C::Hasher, D> {
assert!(D > 1, "Not implemented for D=1.");
let degree_log = commitments[0].degree_log;
let g = F::Extension::primitive_root_of_unity(degree_log);
for p in &[zeta, g * zeta] {
assert_ne!(
p.exp_u64(1 << degree_log as u64),
F::Extension::ONE,
"Opening point is in the subgroup."
);
}
let os = timed!(
timing,
"construct the opening set",
OpeningSet::new(
zeta,
g,
commitments[0],
commitments[1],
commitments[2],
commitments[3],
common_data,
)
);
challenger.observe_opening_set(&os);
let alpha = challenger.get_extension_challenge::<D>();
let mut alpha = ReducingFactor::new(alpha);
// Final low-degree polynomial that goes into FRI.
let mut final_poly = PolynomialCoeffs::empty();
// 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);
let single_composition_poly = timed!(
timing,
"reduce single polys",
alpha.reduce_polys_base(single_polys)
);
for FriBatchInfo { point, polynomials } in &instance.batches {
let polys_coeff = polynomials.iter().map(|fri_poly| {
&oracles[fri_poly.oracle_index].polynomials[fri_poly.polynomial_index]
});
let composition_poly = timed!(
timing,
&format!("reduce batch of {} polynomials", polynomials.len()),
alpha.reduce_polys_base(polys_coeff)
);
let quotient = Self::compute_quotient([*point], composition_poly);
alpha.shift_poly(&mut final_poly);
final_poly += quotient;
}
let single_quotient = Self::compute_quotient([zeta], single_composition_poly);
final_poly += single_quotient;
alpha.reset();
// 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([g * zeta], zs_composition_poly);
alpha.shift_poly(&mut final_poly);
final_poly += zs_quotient;
let lde_final_poly = final_poly.lde(config.fri_config.rate_bits);
let lde_final_poly = final_poly.lde(common_data.config.fri_config.rate_bits);
let lde_final_values = timed!(
timing,
&format!("perform final FFT {}", lde_final_poly.len()),
@ -209,7 +163,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
);
let fri_proof = fri_proof::<F, C, D>(
&commitments
&oracles
.par_iter()
.map(|c| &c.merkle_tree)
.collect::<Vec<_>>(),
@ -220,7 +174,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
timing,
);
(fri_proof, os)
fri_proof
}
/// Given `points=(x_i)`, `evals=(y_i)` and `poly=P` with `P(x_i)=y_i`, computes the polynomial

View File

@ -15,7 +15,7 @@ use crate::iop::ext_target::ExtensionTarget;
use crate::iop::target::Target;
use crate::plonk::circuit_data::CommonCircuitData;
use crate::plonk::config::{GenericConfig, Hasher};
use crate::plonk::plonk_common::PolynomialsIndexBlinding;
use crate::plonk::plonk_common::salt_size;
use crate::plonk::proof::{FriInferredElements, ProofChallenges};
/// Evaluations and Merkle proof produced by the prover in a FRI query step.
@ -41,13 +41,13 @@ pub struct FriInitialTreeProof<F: RichField, H: Hasher<F>> {
}
impl<F: RichField, H: Hasher<F>> FriInitialTreeProof<F, H> {
pub(crate) fn unsalted_evals(
&self,
polynomials: PolynomialsIndexBlinding,
zero_knowledge: bool,
) -> &[F] {
let evals = &self.evals_proofs[polynomials.index].0;
&evals[..evals.len() - polynomials.salt_size(zero_knowledge)]
pub(crate) fn unsalted_eval(&self, oracle_index: usize, poly_index: usize, salted: bool) -> F {
self.unsalted_evals(oracle_index, salted)[poly_index]
}
fn unsalted_evals(&self, oracle_index: usize, salted: bool) -> &[F] {
let evals = &self.evals_proofs[oracle_index].0;
&evals[..evals.len() - salt_size(salted)]
}
}
@ -57,13 +57,18 @@ pub struct FriInitialTreeProofTarget {
}
impl FriInitialTreeProofTarget {
pub(crate) fn unsalted_evals(
pub(crate) fn unsalted_eval(
&self,
polynomials: PolynomialsIndexBlinding,
zero_knowledge: bool,
) -> &[Target] {
let evals = &self.evals_proofs[polynomials.index].0;
&evals[..evals.len() - polynomials.salt_size(zero_knowledge)]
oracle_index: usize,
poly_index: usize,
salted: bool,
) -> Target {
self.unsalted_evals(oracle_index, salted)[poly_index]
}
fn unsalted_evals(&self, oracle_index: usize, salted: bool) -> &[Target] {
let evals = &self.evals_proofs[oracle_index].0;
&evals[..evals.len() - salt_size(salted)]
}
}

View File

@ -1,8 +1,9 @@
use itertools::Itertools;
use plonky2_field::extension_field::Extendable;
use plonky2_field::field_types::Field;
use plonky2_util::{log2_strict, reverse_index_bits_in_place};
use crate::fri::proof::{FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget};
use crate::fri::structure::{FriBatchInfoTarget, FriInstanceInfoTarget, FriOpeningsTarget};
use crate::fri::FriConfig;
use crate::gadgets::interpolation::InterpolationGate;
use crate::gates::gate::Gate;
@ -17,7 +18,6 @@ use crate::iop::target::{BoolTarget, Target};
use crate::plonk::circuit_builder::CircuitBuilder;
use crate::plonk::circuit_data::{CircuitConfig, CommonCircuitData};
use crate::plonk::config::{AlgebraicConfig, AlgebraicHasher, GenericConfig};
use crate::plonk::plonk_common::PlonkPolynomials;
use crate::plonk::proof::OpeningSetTarget;
use crate::util::reducing::ReducingFactorTarget;
use crate::with_context;
@ -127,10 +127,9 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
pub fn verify_fri_proof<C: AlgebraicConfig<D, F = F>>(
&mut self,
instance: &FriInstanceInfoTarget<D>,
// Openings of the PLONK polynomials.
os: &OpeningSetTarget<D>,
// Point at which the PLONK polynomials are opened.
zeta: ExtensionTarget<D>,
initial_merkle_caps: &[MerkleCapTarget],
proof: &FriProofTarget<D>,
challenger: &mut RecursiveChallenger<F, C::Hasher, D>,
@ -186,13 +185,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let precomputed_reduced_evals = with_context!(
self,
"precompute reduced evaluations",
PrecomputedReducedEvalsTarget::from_os_and_alpha(
os,
alpha,
common_data.degree_bits,
zeta,
self
)
PrecomputedReducedOpeningsTarget::from_os_and_alpha(&os.to_fri_openings(), alpha, self)
);
for (i, round_proof) in proof.query_round_proofs.iter().enumerate() {
@ -211,9 +204,9 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
level,
&format!("verify one (of {}) query rounds", num_queries),
self.fri_verifier_query_round(
zeta,
instance,
alpha,
precomputed_reduced_evals,
&precomputed_reduced_evals,
initial_merkle_caps,
proof,
challenger,
@ -255,11 +248,11 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
fn fri_combine_initial<C: GenericConfig<D, F = F>>(
&mut self,
instance: &FriInstanceInfoTarget<D>,
proof: &FriInitialTreeProofTarget,
alpha: ExtensionTarget<D>,
subgroup_x: Target,
vanish_zeta: ExtensionTarget<D>,
precomputed_reduced_evals: PrecomputedReducedEvalsTarget<D>,
precomputed_reduced_evals: &PrecomputedReducedOpeningsTarget<D>,
common_data: &CommonCircuitData<F, C, D>,
) -> ExtensionTarget<D> {
assert!(D > 1, "Not implemented for D=1.");
@ -274,47 +267,35 @@ 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 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))
.copied()
.collect::<Vec<_>>();
let single_composition_eval = alpha.reduce_base(&single_evals, self);
let single_numerator =
self.sub_extension(single_composition_eval, precomputed_reduced_evals.single);
sum = self.div_add_extension(single_numerator, vanish_zeta, sum);
alpha.reset();
// Polynomials opened at `x` and `g x`, i.e., the Zs polynomials.
let zs_evals = proof
.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS, config.zero_knowledge)
for (batch, reduced_openings) in instance
.batches
.iter()
.take(common_data.zs_range().end)
.copied()
.collect::<Vec<_>>();
let zs_composition_eval = alpha.reduce_base(&zs_evals, self);
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);
.zip(&precomputed_reduced_evals.reduced_openings_at_point)
{
let FriBatchInfoTarget { point, polynomials } = batch;
let evals = polynomials
.iter()
.map(|p| {
let poly_blinding = instance.oracles[p.oracle_index].blinding;
let salted = config.zero_knowledge && poly_blinding;
proof.unsalted_eval(p.oracle_index, p.polynomial_index, salted)
})
.collect_vec();
let reduced_evals = alpha.reduce_base(&evals, self);
let numerator = self.sub_extension(reduced_evals, *reduced_openings);
let denominator = self.sub_extension(subgroup_x, *point);
sum = alpha.shift(sum, self);
sum = self.div_add_extension(numerator, denominator, sum);
}
sum
}
fn fri_verifier_query_round<C: AlgebraicConfig<D, F = F>>(
&mut self,
zeta: ExtensionTarget<D>,
instance: &FriInstanceInfoTarget<D>,
alpha: ExtensionTarget<D>,
precomputed_reduced_evals: PrecomputedReducedEvalsTarget<D>,
precomputed_reduced_evals: &PrecomputedReducedOpeningsTarget<D>,
initial_merkle_caps: &[MerkleCapTarget],
proof: &FriProofTarget<D>,
challenger: &mut RecursiveChallenger<F, C::Hasher, D>,
@ -346,16 +327,12 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
);
// `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain.
let (mut subgroup_x, vanish_zeta) = with_context!(self, "compute x from its index", {
let mut subgroup_x = with_context!(self, "compute x from its index", {
let g = self.constant(F::coset_shift());
let phi = F::primitive_root_of_unity(n_log);
let phi = self.exp_from_bits_const_base(phi, x_index_bits.iter().rev());
let g_ext = self.convert_to_ext(g);
let phi_ext = self.convert_to_ext(phi);
// `subgroup_x = g*phi, vanish_zeta = g*phi - zeta`
let subgroup_x = self.mul(g, phi);
let vanish_zeta = self.mul_sub_extension(g_ext, phi_ext, zeta);
(subgroup_x, vanish_zeta)
// subgroup_x = g * phi
self.mul(g, phi)
});
// old_eval is the last derived evaluation; it will be checked for consistency with its
@ -364,10 +341,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
self,
"combine initial oracles",
self.fri_combine_initial(
instance,
&round_proof.initial_trees_proof,
alpha,
subgroup_x,
vanish_zeta,
precomputed_reduced_evals,
common_data,
)
@ -455,43 +432,26 @@ 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_right: ExtensionTarget<D>,
pub zeta_right: ExtensionTarget<D>,
/// For each opening point, holds the reduced (by `alpha`) evaluations of each polynomial that's
/// opened at that point.
#[derive(Clone)]
struct PrecomputedReducedOpeningsTarget<const D: usize> {
reduced_openings_at_point: Vec<ExtensionTarget<D>>,
}
impl<const D: usize> PrecomputedReducedEvalsTarget<D> {
impl<const D: usize> PrecomputedReducedOpeningsTarget<D> {
fn from_os_and_alpha<F: RichField + Extendable<D>>(
os: &OpeningSetTarget<D>,
openings: &FriOpeningsTarget<D>,
alpha: ExtensionTarget<D>,
degree_log: usize,
zeta: ExtensionTarget<D>,
builder: &mut CircuitBuilder<F, D>,
) -> Self {
let mut alpha = ReducingFactorTarget::new(alpha);
let single = alpha.reduce(
&os.constants
.iter()
.chain(&os.plonk_sigmas)
.chain(&os.wires)
.chain(&os.plonk_zs)
.chain(&os.partial_products)
.chain(&os.quotient_polys)
.copied()
.collect::<Vec<_>>(),
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 reduced_openings_at_point = openings
.batches
.iter()
.map(|batch| ReducingFactorTarget::new(alpha).reduce(&batch.values, builder))
.collect();
Self {
single,
zs_right,
zeta_right,
reduced_openings_at_point,
}
}
}

View File

@ -0,0 +1,83 @@
//! Information about the structure of a FRI instance, in terms of the oracles and polynomials
//! involved, and the points they are opened at.
use std::ops::Range;
use crate::field::extension_field::Extendable;
use crate::hash::hash_types::RichField;
use crate::iop::ext_target::ExtensionTarget;
/// Describes an instance of a FRI-based batch opening.
pub struct FriInstanceInfo<F: RichField + Extendable<D>, const D: usize> {
/// The oracles involved, not counting oracles created during the commit phase.
pub oracles: Vec<FriOracleInfo>,
/// Batches of openings, where each batch is associated with a particular point.
pub batches: Vec<FriBatchInfo<F, D>>,
}
/// Describes an instance of a FRI-based batch opening.
pub struct FriInstanceInfoTarget<const D: usize> {
/// The oracles involved, not counting oracles created during the commit phase.
pub oracles: Vec<FriOracleInfo>,
/// Batches of openings, where each batch is associated with a particular point.
pub batches: Vec<FriBatchInfoTarget<D>>,
}
#[derive(Copy, Clone)]
pub struct FriOracleInfo {
pub blinding: bool,
}
/// A batch of openings at a particular point.
pub struct FriBatchInfo<F: RichField + Extendable<D>, const D: usize> {
pub point: F::Extension,
pub polynomials: Vec<FriPolynomialInfo>,
}
/// A batch of openings at a particular point.
pub struct FriBatchInfoTarget<const D: usize> {
pub point: ExtensionTarget<D>,
pub polynomials: Vec<FriPolynomialInfo>,
}
#[derive(Copy, Clone, Debug)]
pub struct FriPolynomialInfo {
/// Index into `FriInstanceInfoTarget`'s `oracles` list.
pub oracle_index: usize,
/// Index of the polynomial within the oracle.
pub polynomial_index: usize,
}
impl FriPolynomialInfo {
pub fn from_range(
oracle_index: usize,
polynomial_indices: Range<usize>,
) -> Vec<FriPolynomialInfo> {
polynomial_indices
.map(|polynomial_index| FriPolynomialInfo {
oracle_index,
polynomial_index,
})
.collect()
}
}
/// Opened values of each polynomial.
pub struct FriOpenings<F: RichField + Extendable<D>, const D: usize> {
pub batches: Vec<FriOpeningBatch<F, D>>,
}
/// Opened values of each polynomial that's opened at a particular point.
pub struct FriOpeningBatch<F: RichField + Extendable<D>, const D: usize> {
pub values: Vec<F::Extension>,
}
/// Opened values of each polynomial.
pub struct FriOpeningsTarget<const D: usize> {
pub batches: Vec<FriOpeningBatchTarget<D>>,
}
/// Opened values of each polynomial that's opened at a particular point.
pub struct FriOpeningBatchTarget<const D: usize> {
pub values: Vec<ExtensionTarget<D>>,
}

View File

@ -5,13 +5,13 @@ use plonky2_field::interpolation::{barycentric_weights, interpolate};
use plonky2_util::{log2_strict, reverse_index_bits_in_place};
use crate::fri::proof::{FriInitialTreeProof, FriProof, FriQueryRound};
use crate::fri::structure::{FriBatchInfo, FriInstanceInfo, FriOpenings};
use crate::fri::FriConfig;
use crate::hash::hash_types::RichField;
use crate::hash::merkle_proofs::verify_merkle_proof;
use crate::hash::merkle_tree::MerkleCap;
use crate::plonk::circuit_data::CommonCircuitData;
use crate::plonk::config::{GenericConfig, Hasher};
use crate::plonk::plonk_common::PlonkPolynomials;
use crate::plonk::proof::{OpeningSet, ProofChallenges};
use crate::util::reducing::ReducingFactor;
use crate::util::reverse_bits;
@ -63,6 +63,7 @@ pub(crate) fn verify_fri_proof<
C: GenericConfig<D, F = F>,
const D: usize,
>(
instance: &FriInstanceInfo<F, D>,
// Openings of the PLONK polynomials.
os: &OpeningSet<F, D>,
challenges: &ProofChallenges<F, D>,
@ -89,15 +90,16 @@ pub(crate) fn verify_fri_proof<
);
let precomputed_reduced_evals =
PrecomputedReducedEvals::from_os_and_alpha(os, challenges.fri_alpha);
PrecomputedReducedOpenings::from_os_and_alpha(&os.to_fri_openings(), challenges.fri_alpha);
for (&x_index, round_proof) in challenges
.fri_query_indices
.iter()
.zip(&proof.query_round_proofs)
{
fri_verifier_query_round::<F, C, D>(
instance,
challenges,
precomputed_reduced_evals,
&precomputed_reduced_evals,
initial_merkle_caps,
proof,
x_index,
@ -127,49 +129,39 @@ pub(crate) fn fri_combine_initial<
C: GenericConfig<D, F = F>,
const D: usize,
>(
instance: &FriInstanceInfo<F, D>,
proof: &FriInitialTreeProof<F, C::Hasher>,
alpha: F::Extension,
zeta: F::Extension,
subgroup_x: F,
precomputed_reduced_evals: PrecomputedReducedEvals<F, D>,
precomputed_reduced_evals: &PrecomputedReducedOpenings<F, D>,
common_data: &CommonCircuitData<F, C, D>,
) -> F::Extension {
let config = &common_data.config;
assert!(D > 1, "Not implemented for D=1.");
let degree_log = common_data.degree_bits;
let subgroup_x = F::Extension::from_basefield(subgroup_x);
let mut alpha = ReducingFactor::new(alpha);
let mut sum = F::Extension::ZERO;
// 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))
.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;
let single_denominator = subgroup_x - zeta;
sum += single_numerator / single_denominator;
alpha.reset();
// Z polynomials have an additional opening at `g x`.
let zs_evals = proof
.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS, config.zero_knowledge)
for (batch, reduced_openings) in instance
.batches
.iter()
.map(|&e| F::Extension::from_basefield(e))
.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_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;
.zip(&precomputed_reduced_evals.reduced_openings_at_point)
{
let FriBatchInfo { point, polynomials } = batch;
let evals = polynomials
.iter()
.map(|p| {
let poly_blinding = instance.oracles[p.oracle_index].blinding;
let salted = config.zero_knowledge && poly_blinding;
proof.unsalted_eval(p.oracle_index, p.polynomial_index, salted)
})
.map(F::Extension::from_basefield);
let reduced_evals = alpha.reduce(evals);
let numerator = reduced_evals - *reduced_openings;
let denominator = subgroup_x - *point;
sum = alpha.shift(sum);
sum += numerator / denominator;
}
sum
}
@ -179,8 +171,9 @@ fn fri_verifier_query_round<
C: GenericConfig<D, F = F>,
const D: usize,
>(
instance: &FriInstanceInfo<F, D>,
challenges: &ProofChallenges<F, D>,
precomputed_reduced_evals: PrecomputedReducedEvals<F, D>,
precomputed_reduced_evals: &PrecomputedReducedOpenings<F, D>,
initial_merkle_caps: &[MerkleCap<F, C::Hasher>],
proof: &FriProof<F, C::Hasher, D>,
mut x_index: usize,
@ -201,9 +194,9 @@ fn fri_verifier_query_round<
// old_eval is the last derived evaluation; it will be checked for consistency with its
// committed "parent" value in the next iteration.
let mut old_eval = fri_combine_initial(
instance,
&round_proof.initial_trees_proof,
challenges.fri_alpha,
challenges.plonk_zeta,
subgroup_x,
precomputed_reduced_evals,
common_data,
@ -257,28 +250,22 @@ fn fri_verifier_query_round<
Ok(())
}
/// Holds the reduced (by `alpha`) evaluations at `zeta` for the polynomial opened just at
/// zeta, for `Z` at zeta and for `Z` at `g*zeta`.
#[derive(Copy, Clone, Debug)]
pub(crate) struct PrecomputedReducedEvals<F: RichField + Extendable<D>, const D: usize> {
pub single: F::Extension,
pub zs_right: F::Extension,
/// For each opening point, holds the reduced (by `alpha`) evaluations of each polynomial that's
/// opened at that point.
#[derive(Clone, Debug)]
pub(crate) struct PrecomputedReducedOpenings<F: RichField + Extendable<D>, const D: usize> {
pub reduced_openings_at_point: Vec<F::Extension>,
}
impl<F: RichField + Extendable<D>, const D: usize> PrecomputedReducedEvals<F, D> {
pub(crate) fn from_os_and_alpha(os: &OpeningSet<F, D>, alpha: F::Extension) -> Self {
let mut alpha = ReducingFactor::new(alpha);
let single = alpha.reduce(
os.constants
.iter()
.chain(&os.plonk_sigmas)
.chain(&os.wires)
.chain(&os.plonk_zs)
.chain(&os.partial_products)
.chain(&os.quotient_polys),
);
let zs_right = alpha.reduce(os.plonk_zs_right.iter());
Self { single, zs_right }
impl<F: RichField + Extendable<D>, const D: usize> PrecomputedReducedOpenings<F, D> {
pub(crate) fn from_os_and_alpha(openings: &FriOpenings<F, D>, alpha: F::Extension) -> Self {
let reduced_openings_at_point = openings
.batches
.iter()
.map(|batch| ReducingFactor::new(alpha).reduce(batch.values.iter()))
.collect();
Self {
reduced_openings_at_point,
}
}
}

View File

@ -10,7 +10,7 @@ use plonky2_field::field_types::Field;
use plonky2_field::polynomial::PolynomialValues;
use plonky2_util::{log2_ceil, log2_strict};
use crate::fri::commitment::PolynomialBatchCommitment;
use crate::fri::oracle::PolynomialBatch;
use crate::fri::{FriConfig, FriParams};
use crate::gadgets::arithmetic::BaseArithmeticOperation;
use crate::gadgets::arithmetic_extension::ExtensionArithmeticOperation;
@ -41,7 +41,7 @@ use crate::plonk::circuit_data::{
use crate::plonk::config::{GenericConfig, Hasher};
use crate::plonk::copy_constraint::CopyConstraint;
use crate::plonk::permutation_argument::Forest;
use crate::plonk::plonk_common::PlonkPolynomials;
use crate::plonk::plonk_common::PlonkOracle;
use crate::util::context_tree::ContextTree;
use crate::util::marking::{Markable, MarkedTargets};
use crate::util::partial_products::num_partial_products;
@ -641,10 +641,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let fft_root_table = fft_root_table(max_fft_points);
let constants_sigmas_vecs = [constant_vecs, sigma_vecs.clone()].concat();
let constants_sigmas_commitment = PolynomialBatchCommitment::from_values(
let constants_sigmas_commitment = PolynomialBatch::from_values(
constants_sigmas_vecs,
rate_bits,
self.config.zero_knowledge & PlonkPolynomials::CONSTANTS_SIGMAS.blinding,
PlonkOracle::CONSTANTS_SIGMAS.blinding,
self.config.fri_config.cap_height,
&mut timing,
Some(&fft_root_table),

View File

@ -5,16 +5,23 @@ use anyhow::Result;
use plonky2_field::extension_field::Extendable;
use plonky2_field::fft::FftRootTable;
use crate::fri::commitment::PolynomialBatchCommitment;
use crate::field::field_types::Field;
use crate::fri::oracle::PolynomialBatch;
use crate::fri::reduction_strategies::FriReductionStrategy;
use crate::fri::structure::{
FriBatchInfo, FriBatchInfoTarget, FriInstanceInfo, FriInstanceInfoTarget, FriPolynomialInfo,
};
use crate::fri::{FriConfig, FriParams};
use crate::gates::gate::PrefixedGate;
use crate::hash::hash_types::{MerkleCapTarget, RichField};
use crate::hash::merkle_tree::MerkleCap;
use crate::iop::ext_target::ExtensionTarget;
use crate::iop::generator::WitnessGenerator;
use crate::iop::target::Target;
use crate::iop::witness::PartialWitness;
use crate::plonk::circuit_builder::CircuitBuilder;
use crate::plonk::config::{GenericConfig, Hasher};
use crate::plonk::plonk_common::{PlonkOracle, FRI_ORACLES};
use crate::plonk::proof::{CompressedProofWithPublicInputs, ProofWithPublicInputs};
use crate::plonk::prover::prove;
use crate::plonk::verifier::verify;
@ -178,7 +185,7 @@ pub(crate) struct ProverOnlyCircuitData<
/// they watch.
pub generator_indices_by_watches: BTreeMap<usize, Vec<usize>>,
/// Commitments to the constants polynomials and sigma polynomials.
pub constants_sigmas_commitment: PolynomialBatchCommitment<F, C, D>,
pub constants_sigmas_commitment: PolynomialBatch<F, C, D>,
/// The transpose of the list of sigma polynomials.
pub sigmas: Vec<Vec<F>>,
/// Subgroup of order `degree`.
@ -286,6 +293,95 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
pub fn partial_products_range(&self) -> RangeFrom<usize> {
self.config.num_challenges..
}
pub(crate) fn get_fri_instance(&self, zeta: F::Extension) -> FriInstanceInfo<F, D> {
// All polynomials are opened at zeta.
let zeta_batch = FriBatchInfo {
point: zeta,
polynomials: self.fri_all_polys(),
};
// The Z polynomials are also opened at g * zeta.
let g = F::Extension::primitive_root_of_unity(self.degree_bits);
let zeta_right = g * zeta;
let zeta_right_batch = FriBatchInfo {
point: zeta_right,
polynomials: self.fri_zs_polys(),
};
let openings = vec![zeta_batch, zeta_right_batch];
FriInstanceInfo {
oracles: FRI_ORACLES.to_vec(),
batches: openings,
}
}
pub(crate) fn get_fri_instance_target(
&self,
builder: &mut CircuitBuilder<F, D>,
zeta: ExtensionTarget<D>,
) -> FriInstanceInfoTarget<D> {
// All polynomials are opened at zeta.
let zeta_batch = FriBatchInfoTarget {
point: zeta,
polynomials: self.fri_all_polys(),
};
// The Z polynomials are also opened at g * zeta.
let g = F::primitive_root_of_unity(self.degree_bits);
let zeta_right = builder.mul_const_extension(g, zeta);
let zeta_right_batch = FriBatchInfoTarget {
point: zeta_right,
polynomials: self.fri_zs_polys(),
};
let openings = vec![zeta_batch, zeta_right_batch];
FriInstanceInfoTarget {
oracles: FRI_ORACLES.to_vec(),
batches: openings,
}
}
fn fri_preprocessed_polys(&self) -> Vec<FriPolynomialInfo> {
let num_preprocessed_polys = self.sigmas_range().end;
FriPolynomialInfo::from_range(
PlonkOracle::CONSTANTS_SIGMAS.index,
0..num_preprocessed_polys,
)
}
fn fri_wire_polys(&self) -> Vec<FriPolynomialInfo> {
let num_wire_polys = self.config.num_wires;
FriPolynomialInfo::from_range(PlonkOracle::WIRES.index, 0..num_wire_polys)
}
fn fri_zs_partial_products_polys(&self) -> Vec<FriPolynomialInfo> {
let num_zs_partial_products_polys =
self.config.num_challenges * (1 + self.num_partial_products.0);
FriPolynomialInfo::from_range(
PlonkOracle::ZS_PARTIAL_PRODUCTS.index,
0..num_zs_partial_products_polys,
)
}
fn fri_zs_polys(&self) -> Vec<FriPolynomialInfo> {
FriPolynomialInfo::from_range(PlonkOracle::ZS_PARTIAL_PRODUCTS.index, self.zs_range())
}
fn fri_quotient_polys(&self) -> Vec<FriPolynomialInfo> {
let num_quotient_polys = self.config.num_challenges * self.quotient_degree_factor;
FriPolynomialInfo::from_range(PlonkOracle::QUOTIENT.index, 0..num_quotient_polys)
}
fn fri_all_polys(&self) -> Vec<FriPolynomialInfo> {
[
self.fri_preprocessed_polys(),
self.fri_wire_polys(),
self.fri_zs_partial_products_polys(),
self.fri_quotient_polys(),
]
.concat()
}
}
/// The `Target` version of `VerifierCircuitData`, for use inside recursive circuits. Note that this

View File

@ -4,7 +4,7 @@ use plonky2_field::extension_field::Extendable;
use plonky2_field::polynomial::PolynomialCoeffs;
use crate::fri::proof::{CompressedFriProof, FriProof};
use crate::fri::verifier::{compute_evaluation, fri_combine_initial, PrecomputedReducedEvals};
use crate::fri::verifier::{compute_evaluation, fri_combine_initial, PrecomputedReducedOpenings};
use crate::hash::hash_types::RichField;
use crate::hash::merkle_tree::MerkleCap;
use crate::iop::challenger::Challenger;
@ -187,8 +187,10 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
// Holds the indices that have already been seen at each reduction depth.
let mut seen_indices_by_depth =
vec![HashSet::new(); common_data.fri_params.reduction_arity_bits.len()];
let precomputed_reduced_evals =
PrecomputedReducedEvals::from_os_and_alpha(&self.proof.openings, *fri_alpha);
let precomputed_reduced_evals = PrecomputedReducedOpenings::from_os_and_alpha(
&self.proof.openings.to_fri_openings(),
*fri_alpha,
);
let log_n = common_data.degree_bits + common_data.config.fri_config.rate_bits;
// Simulate the proof verification and collect the inferred elements.
// The content of the loop is basically the same as the `fri_verifier_query_round` function.
@ -196,15 +198,15 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR
* F::primitive_root_of_unity(log_n).exp_u64(reverse_bits(x_index, log_n) as u64);
let mut old_eval = fri_combine_initial(
&common_data.get_fri_instance(*plonk_zeta),
&self
.proof
.opening_proof
.query_round_proofs
.initial_trees_proofs[&x_index],
*fri_alpha,
*plonk_zeta,
subgroup_x,
precomputed_reduced_evals,
&precomputed_reduced_evals,
common_data,
);
for (i, &arity_bits) in common_data

View File

@ -2,49 +2,59 @@ use plonky2_field::extension_field::Extendable;
use plonky2_field::field_types::Field;
use plonky2_field::packed_field::PackedField;
use crate::fri::commitment::SALT_SIZE;
use crate::fri::oracle::SALT_SIZE;
use crate::fri::structure::FriOracleInfo;
use crate::hash::hash_types::RichField;
use crate::iop::ext_target::ExtensionTarget;
use crate::iop::target::Target;
use crate::plonk::circuit_builder::CircuitBuilder;
use crate::util::reducing::ReducingFactorTarget;
pub(crate) const FRI_ORACLES: [FriOracleInfo; 4] = [
PlonkOracle::CONSTANTS_SIGMAS.as_fri_oracle(),
PlonkOracle::WIRES.as_fri_oracle(),
PlonkOracle::ZS_PARTIAL_PRODUCTS.as_fri_oracle(),
PlonkOracle::QUOTIENT.as_fri_oracle(),
];
/// Holds the Merkle tree index and blinding flag of a set of polynomials used in FRI.
#[derive(Debug, Copy, Clone)]
pub struct PolynomialsIndexBlinding {
pub struct PlonkOracle {
pub(crate) index: usize,
pub(crate) blinding: bool,
}
impl PolynomialsIndexBlinding {
pub fn salt_size(&self, zero_knowledge: bool) -> usize {
if zero_knowledge & self.blinding {
SALT_SIZE
} else {
0
impl PlonkOracle {
pub const CONSTANTS_SIGMAS: PlonkOracle = PlonkOracle {
index: 0,
blinding: false,
};
pub const WIRES: PlonkOracle = PlonkOracle {
index: 1,
blinding: true,
};
pub const ZS_PARTIAL_PRODUCTS: PlonkOracle = PlonkOracle {
index: 2,
blinding: true,
};
pub const QUOTIENT: PlonkOracle = PlonkOracle {
index: 3,
blinding: true,
};
pub(crate) const fn as_fri_oracle(&self) -> FriOracleInfo {
FriOracleInfo {
blinding: self.blinding,
}
}
}
/// Holds the indices and blinding flags of the Plonk polynomials.
pub struct PlonkPolynomials;
impl PlonkPolynomials {
pub const CONSTANTS_SIGMAS: PolynomialsIndexBlinding = PolynomialsIndexBlinding {
index: 0,
blinding: false,
};
pub const WIRES: PolynomialsIndexBlinding = PolynomialsIndexBlinding {
index: 1,
blinding: true,
};
pub const ZS_PARTIAL_PRODUCTS: PolynomialsIndexBlinding = PolynomialsIndexBlinding {
index: 2,
blinding: true,
};
pub const QUOTIENT: PolynomialsIndexBlinding = PolynomialsIndexBlinding {
index: 3,
blinding: true,
};
pub fn salt_size(salted: bool) -> usize {
if salted {
SALT_SIZE
} else {
0
}
}
/// Evaluate the polynomial which vanishes on any multiplicative subgroup of a given order `n`.

View File

@ -2,8 +2,11 @@ use plonky2_field::extension_field::Extendable;
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use crate::fri::commitment::PolynomialBatchCommitment;
use crate::fri::oracle::PolynomialBatch;
use crate::fri::proof::{CompressedFriProof, FriProof, FriProofTarget};
use crate::fri::structure::{
FriOpeningBatch, FriOpeningBatchTarget, FriOpenings, FriOpeningsTarget,
};
use crate::hash::hash_types::{MerkleCapTarget, RichField};
use crate::hash::merkle_tree::MerkleCap;
use crate::iop::ext_target::ExtensionTarget;
@ -274,33 +277,53 @@ pub struct OpeningSet<F: RichField + Extendable<D>, const D: usize> {
impl<F: RichField + Extendable<D>, const D: usize> OpeningSet<F, D> {
pub fn new<C: GenericConfig<D, F = F>>(
z: F::Extension,
zeta: F::Extension,
g: F::Extension,
constants_sigmas_commitment: &PolynomialBatchCommitment<F, C, D>,
wires_commitment: &PolynomialBatchCommitment<F, C, D>,
zs_partial_products_commitment: &PolynomialBatchCommitment<F, C, D>,
quotient_polys_commitment: &PolynomialBatchCommitment<F, C, D>,
constants_sigmas_commitment: &PolynomialBatch<F, C, D>,
wires_commitment: &PolynomialBatch<F, C, D>,
zs_partial_products_commitment: &PolynomialBatch<F, C, D>,
quotient_polys_commitment: &PolynomialBatch<F, C, D>,
common_data: &CommonCircuitData<F, C, D>,
) -> Self {
let eval_commitment = |z: F::Extension, c: &PolynomialBatchCommitment<F, C, D>| {
let eval_commitment = |z: F::Extension, c: &PolynomialBatch<F, C, D>| {
c.polynomials
.par_iter()
.map(|p| p.to_extension().eval(z))
.collect::<Vec<_>>()
};
let constants_sigmas_eval = eval_commitment(z, constants_sigmas_commitment);
let zs_partial_products_eval = eval_commitment(z, zs_partial_products_commitment);
let constants_sigmas_eval = eval_commitment(zeta, constants_sigmas_commitment);
let zs_partial_products_eval = eval_commitment(zeta, zs_partial_products_commitment);
Self {
constants: constants_sigmas_eval[common_data.constants_range()].to_vec(),
plonk_sigmas: constants_sigmas_eval[common_data.sigmas_range()].to_vec(),
wires: eval_commitment(z, wires_commitment),
wires: eval_commitment(zeta, wires_commitment),
plonk_zs: zs_partial_products_eval[common_data.zs_range()].to_vec(),
plonk_zs_right: eval_commitment(g * z, zs_partial_products_commitment)
plonk_zs_right: eval_commitment(g * zeta, zs_partial_products_commitment)
[common_data.zs_range()]
.to_vec(),
partial_products: zs_partial_products_eval[common_data.partial_products_range()]
.to_vec(),
quotient_polys: eval_commitment(z, quotient_polys_commitment),
quotient_polys: eval_commitment(zeta, quotient_polys_commitment),
}
}
pub(crate) fn to_fri_openings(&self) -> FriOpenings<F, D> {
let zeta_batch = FriOpeningBatch {
values: [
self.constants.as_slice(),
self.plonk_sigmas.as_slice(),
self.wires.as_slice(),
self.plonk_zs.as_slice(),
self.partial_products.as_slice(),
self.quotient_polys.as_slice(),
]
.concat(),
};
let zeta_right_batch = FriOpeningBatch {
values: self.plonk_zs_right.clone(),
};
FriOpenings {
batches: vec![zeta_batch, zeta_right_batch],
}
}
}
@ -317,6 +340,28 @@ pub struct OpeningSetTarget<const D: usize> {
pub quotient_polys: Vec<ExtensionTarget<D>>,
}
impl<const D: usize> OpeningSetTarget<D> {
pub(crate) fn to_fri_openings(&self) -> FriOpeningsTarget<D> {
let zeta_batch = FriOpeningBatchTarget {
values: [
self.constants.as_slice(),
self.plonk_sigmas.as_slice(),
self.wires.as_slice(),
self.plonk_zs.as_slice(),
self.partial_products.as_slice(),
self.quotient_polys.as_slice(),
]
.concat(),
};
let zeta_right_batch = FriOpeningBatchTarget {
values: self.plonk_zs_right.clone(),
};
FriOpeningsTarget {
batches: vec![zeta_batch, zeta_right_batch],
}
}
}
#[cfg(test)]
mod tests {
use anyhow::Result;

View File

@ -1,20 +1,22 @@
use std::mem::swap;
use anyhow::ensure;
use anyhow::Result;
use plonky2_field::extension_field::Extendable;
use plonky2_field::polynomial::{PolynomialCoeffs, PolynomialValues};
use plonky2_util::log2_ceil;
use rayon::prelude::*;
use crate::fri::commitment::PolynomialBatchCommitment;
use crate::field::field_types::Field;
use crate::fri::oracle::PolynomialBatch;
use crate::hash::hash_types::RichField;
use crate::iop::challenger::Challenger;
use crate::iop::generator::generate_partial_witness;
use crate::iop::witness::{MatrixWitness, PartialWitness, Witness};
use crate::plonk::circuit_data::{CommonCircuitData, ProverOnlyCircuitData};
use crate::plonk::config::{GenericConfig, Hasher};
use crate::plonk::plonk_common::PlonkPolynomials;
use crate::plonk::plonk_common::ZeroPolyOnCoset;
use crate::plonk::plonk_common::{PlonkOracle, ZeroPolyOnCoset};
use crate::plonk::proof::OpeningSet;
use crate::plonk::proof::{Proof, ProofWithPublicInputs};
use crate::plonk::vanishing_poly::eval_vanishing_poly_base_batch;
use crate::plonk::vars::EvaluationVarsBaseBatch;
@ -69,10 +71,10 @@ pub(crate) fn prove<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, co
let wires_commitment = timed!(
timing,
"compute wires commitment",
PolynomialBatchCommitment::from_values(
PolynomialBatch::from_values(
wires_values,
config.fri_config.rate_bits,
config.zero_knowledge & PlonkPolynomials::WIRES.blinding,
config.zero_knowledge && PlonkOracle::WIRES.blinding,
config.fri_config.cap_height,
timing,
prover_data.fft_root_table.as_ref(),
@ -109,10 +111,10 @@ pub(crate) fn prove<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, co
let partial_products_and_zs_commitment = timed!(
timing,
"commit to partial products and Z's",
PolynomialBatchCommitment::from_values(
PolynomialBatch::from_values(
zs_partial_products,
config.fri_config.rate_bits,
config.zero_knowledge & PlonkPolynomials::ZS_PARTIAL_PRODUCTS.blinding,
config.zero_knowledge && PlonkOracle::ZS_PARTIAL_PRODUCTS.blinding,
config.fri_config.cap_height,
timing,
prover_data.fft_root_table.as_ref(),
@ -158,10 +160,10 @@ pub(crate) fn prove<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, co
let quotient_polys_commitment = timed!(
timing,
"commit to quotient polys",
PolynomialBatchCommitment::from_coeffs(
PolynomialBatch::from_coeffs(
all_quotient_poly_chunks,
config.fri_config.rate_bits,
config.zero_knowledge & PlonkPolynomials::QUOTIENT.blinding,
config.zero_knowledge && PlonkOracle::QUOTIENT.blinding,
config.fri_config.cap_height,
timing,
prover_data.fft_root_table.as_ref(),
@ -171,18 +173,41 @@ pub(crate) fn prove<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, co
challenger.observe_cap(&quotient_polys_commitment.merkle_tree.cap);
let zeta = challenger.get_extension_challenge::<D>();
// To avoid leaking witness data, we want to ensure that our opening locations, `zeta` and
// `g * zeta`, are not in our subgroup `H`. It suffices to check `zeta` only, since
// `(g * zeta)^n = zeta^n`, where `n` is the order of `g`.
let g = F::Extension::primitive_root_of_unity(common_data.degree_bits);
ensure!(
zeta.exp_power_of_2(common_data.degree_bits) != F::Extension::ONE,
"Opening point is in the subgroup."
);
let (opening_proof, openings) = timed!(
let openings = timed!(
timing,
"construct the opening set",
OpeningSet::new(
zeta,
g,
&prover_data.constants_sigmas_commitment,
&wires_commitment,
&partial_products_and_zs_commitment,
&quotient_polys_commitment,
common_data,
)
);
challenger.observe_opening_set(&openings);
let opening_proof = timed!(
timing,
"compute opening proofs",
PolynomialBatchCommitment::open_plonk(
PolynomialBatch::prove_openings(
&common_data.get_fri_instance(zeta),
&[
&prover_data.constants_sigmas_commitment,
&wires_commitment,
&partial_products_and_zs_commitment,
&quotient_polys_commitment,
],
zeta,
&mut challenger,
common_data,
timing,
@ -300,8 +325,8 @@ fn compute_quotient_polys<
common_data: &CommonCircuitData<F, C, D>,
prover_data: &'a ProverOnlyCircuitData<F, C, D>,
public_inputs_hash: &<<C as GenericConfig<D>>::InnerHasher as Hasher<F>>::Hash,
wires_commitment: &'a PolynomialBatchCommitment<F, C, D>,
zs_partial_products_commitment: &'a PolynomialBatchCommitment<F, C, D>,
wires_commitment: &'a PolynomialBatch<F, C, D>,
zs_partial_products_commitment: &'a PolynomialBatch<F, C, D>,
betas: &[F],
gammas: &[F],
alphas: &[F],
@ -325,9 +350,8 @@ fn compute_quotient_polys<
let lde_size = points.len();
// Retrieve the LDE values at index `i`.
let get_at_index = |comm: &'a PolynomialBatchCommitment<F, C, D>, i: usize| -> &'a [F] {
comm.get_lde_values(i * step)
};
let get_at_index =
|comm: &'a PolynomialBatch<F, C, D>, i: usize| -> &'a [F] { comm.get_lde_values(i * step) };
let z_h_on_coset = ZeroPolyOnCoset::new(common_data.degree_bits, max_degree_bits);

View File

@ -107,12 +107,13 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
proof.quotient_polys_cap,
];
let fri_instance = inner_common_data.get_fri_instance_target(self, zeta);
with_context!(
self,
"verify FRI proof",
self.verify_fri_proof(
&fri_instance,
&proof.openings,
zeta,
merkle_caps,
&proof.opening_proof,
&mut challenger,

View File

@ -86,6 +86,7 @@ pub(crate) fn verify_with_challenges<
];
verify_fri_proof(
&common_data.get_fri_instance(challenges.plonk_zeta),
&proof.openings,
&challenges,
merkle_caps,

View File

@ -238,7 +238,14 @@ impl<const D: usize> ReducingFactorTarget<D> {
where
F: RichField + Extendable<D>,
{
let exp = builder.exp_u64_extension(self.base, self.count);
let zero_ext = builder.zero_extension();
let exp = if x == zero_ext {
// The result will get zeroed out, so don't actually compute the exponentiation.
zero_ext
} else {
builder.exp_u64_extension(self.base, self.count)
};
self.count = 0;
builder.mul_extension(exp, x)
}