mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-04 23:03:08 +00:00
parent
f072d09ae4
commit
bf30fed701
@ -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)]
|
||||
|
||||
@ -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
|
||||
@ -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)]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
83
plonky2/src/fri/structure.rs
Normal file
83
plonky2/src/fri/structure.rs
Normal 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>>,
|
||||
}
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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`.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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("ient_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,
|
||||
"ient_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,
|
||||
"ient_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);
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user