Observe config parameters in challenger (#1678)

* Observe config in challenger

* Clippy
This commit is contained in:
Robin Salen
2025-05-06 09:19:45 -04:00
committed by GitHub
parent 6a2c1b47b7
commit cd907f68e1
8 changed files with 139 additions and 1 deletions

View File

@@ -152,4 +152,4 @@ jobs:
run: cargo fmt --all --check
- name: Run cargo clippy
run: cargo clippy --all-features --all-targets -- -D warnings -A incomplete-features
run: cargo clippy --all-features --all-targets -- -D warnings -A incomplete-features -A clippy::uninlined_format_args

View File

@@ -6,9 +6,14 @@
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use plonky2_field::extension::Extendable;
use serde::Serialize;
use crate::fri::reduction_strategies::FriReductionStrategy;
use crate::hash::hash_types::RichField;
use crate::iop::challenger::{Challenger, RecursiveChallenger};
use crate::plonk::circuit_builder::CircuitBuilder;
use crate::plonk::config::{AlgebraicHasher, Hasher};
mod challenges;
pub mod oracle;
@@ -63,6 +68,33 @@ impl FriConfig {
pub const fn num_cap_elements(&self) -> usize {
1 << self.cap_height
}
/// Observe the FRI configuration parameters.
pub fn observe<F: RichField, H: Hasher<F>>(&self, challenger: &mut Challenger<F, H>) {
challenger.observe_element(F::from_canonical_usize(self.rate_bits));
challenger.observe_element(F::from_canonical_usize(self.cap_height));
challenger.observe_element(F::from_canonical_u32(self.proof_of_work_bits));
challenger.observe_elements(&self.reduction_strategy.serialize());
challenger.observe_element(F::from_canonical_usize(self.num_query_rounds));
}
/// Observe the FRI configuration parameters for the recursive verifier.
pub fn observe_target<F, H, const D: usize>(
&self,
builder: &mut CircuitBuilder<F, D>,
challenger: &mut RecursiveChallenger<F, H, D>,
) where
F: RichField + Extendable<D>,
H: AlgebraicHasher<F>,
{
challenger.observe_element(builder.constant(F::from_canonical_usize(self.rate_bits)));
challenger.observe_element(builder.constant(F::from_canonical_usize(self.cap_height)));
challenger
.observe_element(builder.constant(F::from_canonical_u32(self.proof_of_work_bits)));
challenger.observe_elements(&builder.constants(&self.reduction_strategy.serialize()));
challenger
.observe_element(builder.constant(F::from_canonical_usize(self.num_query_rounds)));
}
}
/// FRI parameters, including generated parameters which are specific to an instance size, in
@@ -109,4 +141,41 @@ impl FriParams {
pub fn final_poly_len(&self) -> usize {
1 << self.final_poly_bits()
}
pub fn observe<F: RichField, H: Hasher<F>>(&self, challenger: &mut Challenger<F, H>) {
self.config.observe(challenger);
challenger.observe_element(F::from_bool(self.hiding));
challenger.observe_element(F::from_canonical_usize(self.degree_bits));
challenger.observe_elements(
&self
.reduction_arity_bits
.iter()
.map(|&e| F::from_canonical_usize(e))
.collect::<Vec<_>>(),
);
}
pub fn observe_target<F, H, const D: usize>(
&self,
builder: &mut CircuitBuilder<F, D>,
challenger: &mut RecursiveChallenger<F, H, D>,
) where
F: RichField + Extendable<D>,
H: AlgebraicHasher<F>,
{
self.config.observe_target(builder, challenger);
challenger.observe_element(builder.constant(F::from_bool(self.hiding)));
challenger.observe_element(builder.constant(F::from_canonical_usize(self.degree_bits)));
challenger.observe_elements(
&builder.constants(
&self
.reduction_arity_bits
.iter()
.map(|&e| F::from_canonical_usize(e))
.collect::<Vec<_>>(),
),
);
}
}

View File

@@ -6,6 +6,8 @@ use serde::Serialize;
#[cfg(feature = "timing")]
use web_time::Instant;
use crate::hash::hash_types::RichField;
/// A method for deciding what arity to use at each reduction layer.
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
pub enum FriReductionStrategy {
@@ -53,6 +55,29 @@ impl FriReductionStrategy {
}
}
}
pub fn serialize<F: RichField>(&self) -> Vec<F> {
match self {
FriReductionStrategy::Fixed(reduction_arity_bits) => core::iter::once(F::ZERO)
.chain(
reduction_arity_bits
.iter()
.map(|&x| F::from_canonical_usize(x)),
)
.collect(),
FriReductionStrategy::ConstantArityBits(arity_bits, final_poly_bits) => {
vec![
F::ONE,
F::from_canonical_usize(*arity_bits),
F::from_canonical_usize(*final_poly_bits),
]
}
FriReductionStrategy::MinSize(opt_max_arity_bits) => {
let max_arity = opt_max_arity_bits.unwrap_or(0);
vec![F::TWO, F::from_canonical_usize(max_arity)]
}
}
}
}
fn min_size_arity_bits(

View File

@@ -41,6 +41,9 @@ fn get_challenges<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, cons
let mut challenger = Challenger::<F, C::Hasher>::new();
let has_lookup = common_data.num_lookup_polys != 0;
// Observe the FRI config
common_data.fri_params.observe(&mut challenger);
// Observe the instance.
challenger.observe_hash::<C::Hasher>(*circuit_digest);
challenger.observe_hash::<C::InnerHasher>(public_inputs_hash);
@@ -278,6 +281,11 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let mut challenger = RecursiveChallenger::<F, C::Hasher, D>::new(self);
let has_lookup = inner_common_data.num_lookup_polys != 0;
// Observe the FRI config
inner_common_data
.fri_params
.observe_target(self, &mut challenger);
// Observe the instance.
challenger.observe_hash(&inner_circuit_digest);
challenger.observe_hash(&public_inputs_hash);

View File

@@ -185,6 +185,9 @@ where
let mut challenger = Challenger::<F, C::Hasher>::new();
// Observe the FRI config
common_data.fri_params.observe(&mut challenger);
// Observe the instance.
challenger.observe_hash::<C::Hasher>(prover_data.circuit_digest);
challenger.observe_hash::<C::InnerHasher>(public_inputs_hash);

View File

@@ -13,6 +13,9 @@ use plonky2::field::types::Field;
use plonky2::fri::reduction_strategies::FriReductionStrategy;
use plonky2::fri::{FriConfig, FriParams};
use plonky2::hash::hash_types::RichField;
use plonky2::iop::challenger::{Challenger, RecursiveChallenger};
use plonky2::plonk::circuit_builder::CircuitBuilder;
use plonky2::plonk::config::{AlgebraicHasher, Hasher};
/// A configuration containing the different parameters used by the STARK prover.
#[derive(Clone, Debug)]
@@ -94,6 +97,29 @@ impl StarkConfig {
Ok(())
}
}
/// Observes this [`StarkConfig`] for the given [`Challenger`].
pub(crate) fn observe<F: RichField, H: Hasher<F>>(&self, challenger: &mut Challenger<F, H>) {
challenger.observe_element(F::from_canonical_usize(self.security_bits));
challenger.observe_element(F::from_canonical_usize(self.num_challenges));
self.fri_config.observe(challenger);
}
/// Observes this [`StarkConfig`] for the given [`RecursiveChallenger`].
pub(crate) fn observe_target<F, H, const D: usize>(
&self,
builder: &mut CircuitBuilder<F, D>,
challenger: &mut RecursiveChallenger<F, H, D>,
) where
F: RichField + Extendable<D>,
H: AlgebraicHasher<F>,
{
challenger.observe_element(builder.constant(F::from_canonical_usize(self.security_bits)));
challenger.observe_element(builder.constant(F::from_canonical_usize(self.num_challenges)));
self.fri_config.observe_target(builder, challenger);
}
}
#[cfg(test)]

View File

@@ -45,6 +45,9 @@ where
{
let num_challenges = config.num_challenges;
// Observe the config
config.observe(challenger);
if let Some(cap) = &trace_cap {
challenger.observe_cap(cap);
}
@@ -211,6 +214,9 @@ where
{
let num_challenges = config.num_challenges;
// Observe the config
config.observe_target(builder, challenger);
if let Some(trace_cap) = trace_cap {
challenger.observe_cap(trace_cap);
}

View File

@@ -96,6 +96,7 @@ where
let trace_cap = trace_commitment.merkle_tree.cap.clone();
let mut challenger = Challenger::new();
challenger.observe_elements(public_inputs);
config.observe(&mut challenger);
challenger.observe_cap(&trace_cap);
prove_with_commitment(
&stark,