From 0f22d86420b9563a0257e28d878593dcca007971 Mon Sep 17 00:00:00 2001 From: Ilya Lesokhin Date: Wed, 29 Apr 2026 14:42:53 +0300 Subject: [PATCH] Move component log sizes from proof claim to Statement The Statement trait now exposes get_component_log_sizes; verify reads log sizes from the statement instead of proof.claim. The Claim struct is removed (claimed_sums is now a top-level field on Proof), shrinking the serialized proof by one packed-u8 entry per component. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/cairo_verifier/src/privacy_test.rs | 11 +--- crates/cairo_verifier/src/statement.rs | 27 ++++++++- crates/cairo_verifier/src/test.rs | 25 ++++---- crates/cairo_verifier/src/verify.rs | 18 ++---- crates/circuit_prover/src/prover.rs | 14 ++--- crates/circuit_serialize/src/deserialize.rs | 20 +------ crates/circuit_serialize/src/serialize.rs | 23 +------- crates/circuit_serialize/src/test.rs | 7 +-- crates/circuit_verifier/src/circuit_claim.rs | 1 + crates/circuit_verifier/src/statement.rs | 43 ++++++++++++-- crates/circuit_verifier/src/verify.rs | 9 +-- crates/stark_verifier/src/constraint_eval.rs | 1 + crates/stark_verifier/src/proof.rs | 35 ++--------- .../src/proof_from_stark_proof.rs | 6 +- crates/stark_verifier/src/statement.rs | 2 + crates/stark_verifier/src/verify.rs | 12 ++-- .../stark_verifier_examples/src/simple_air.rs | 14 +---- .../src/simple_air_test.rs | 16 ++--- .../src/simple_statement.rs | 59 +++++++++++-------- .../src/verify_test.rs | 14 ++--- 20 files changed, 168 insertions(+), 189 deletions(-) diff --git a/crates/cairo_verifier/src/privacy_test.rs b/crates/cairo_verifier/src/privacy_test.rs index 1519cd60..710c5625 100644 --- a/crates/cairo_verifier/src/privacy_test.rs +++ b/crates/cairo_verifier/src/privacy_test.rs @@ -245,13 +245,8 @@ fn test_privacy_proof_info() { output_values: vec![QM31::zero(); preprocessed_circuit.params.output_addresses.len()], }; let mut context: Context = Context::new(N_RESERVED); - let statement = CircuitStatement::new( - &mut context, - &circuit_config.output_addresses, - &public_data.output_values, - circuit_config.preprocessed_column_log_sizes.clone(), - circuit_config.preprocessed_root, - ); + let statement = + CircuitStatement::new(&mut context, &circuit_config, &public_data.output_values); let enabled_bits = vec![true; all_circuit_components::().len()]; let proof_config = ProofConfig::new( @@ -264,5 +259,5 @@ fn test_privacy_proof_info() { let proof_info = ProofInfo::from_config(&proof_config); println!("{proof_info}"); // Assert the total size in bytes. - assert_eq!(proof_info.total_bytes(), 263808); + assert_eq!(proof_info.total_bytes(), 263796); } diff --git a/crates/cairo_verifier/src/statement.rs b/crates/cairo_verifier/src/statement.rs index 208cc4e1..200eb1a4 100644 --- a/crates/cairo_verifier/src/statement.rs +++ b/crates/cairo_verifier/src/statement.rs @@ -145,6 +145,7 @@ pub struct CairoStatement { pub packed_outputs: Simd, pub preprocessed_root: HashValue, pub preprocessed_trace_variant: PreProcessedTraceVariant, + pub component_log_sizes: Simd, } impl CairoStatement { @@ -261,21 +262,29 @@ impl CairoStatement { } impl CairoStatement { + /// `public_claim` is the flat public claim laid out as: + /// `[public_data (PUBLIC_DATA_LEN + outputs.len() + program.len() M31s) | component_log_sizes + /// (components.len() M31s)]`. pub fn new( context: &mut Context, - public_data: Vec, + public_claim: Vec, outputs: Vec<[M31; MEMORY_VALUES_LIMBS]>, program: Arc<[[M31; MEMORY_VALUES_LIMBS]]>, components: IndexMap<&'static str, Box>>, preprocessed_root: HashValue, preprocessed_trace_variant: PreProcessedTraceVariant, ) -> Self { - let packed_public_data = pack_into_qm31s(public_data.iter().cloned()) + let n_components = components.len(); + let public_data_len = PUBLIC_DATA_LEN + outputs.len() + program.len(); + assert_eq!(public_claim.len(), public_data_len + n_components); + let (public_data_m31s, log_sizes_m31s) = public_claim.split_at(public_data_len); + + let packed_public_data = pack_into_qm31s(public_data_m31s.iter().cloned()) .into_iter() .map(|qm31| Value::from_qm31(qm31).guess(context)) .collect_vec(); - let packed_public_data = Simd::from_packed(packed_public_data, public_data.len()); + let packed_public_data = Simd::from_packed(packed_public_data, public_data_m31s.len()); // Note that we don't enforce anything on the padding M31 in packed_public_data. let unpacked_simd = Simd::unpack(context, &packed_public_data); @@ -289,12 +298,19 @@ impl CairoStatement { .collect_vec(); let packed_outputs = Simd::from_packed(packed_outputs, n_outputs * MEMORY_VALUES_LIMBS); + let packed_log_sizes = pack_into_qm31s(log_sizes_m31s.iter().cloned()) + .into_iter() + .map(|qm31| Value::from_qm31(qm31).guess(context)) + .collect_vec(); + let component_log_sizes = Simd::from_packed(packed_log_sizes, n_components); + Self { packed_public_data, public_data, program, packed_outputs, components, + component_log_sizes, preprocessed_root, preprocessed_trace_variant, } @@ -306,6 +322,10 @@ impl Statement for CairoStatement { &self.components } + fn get_component_log_sizes(&self) -> &Simd { + &self.component_log_sizes + } + fn claims_to_mix(&self, context: &mut Context) -> Vec> { let Self { components: _components, @@ -313,6 +333,7 @@ impl Statement for CairoStatement { public_data: _public_data, program, packed_outputs, + component_log_sizes: _component_log_sizes, preprocessed_root: _preprocessed_root, preprocessed_trace_variant: _preprocessed_trace_variant, } = self; diff --git a/crates/cairo_verifier/src/test.rs b/crates/cairo_verifier/src/test.rs index f199235d..96e6e5f7 100644 --- a/crates/cairo_verifier/src/test.rs +++ b/crates/cairo_verifier/src/test.rs @@ -55,7 +55,7 @@ pub fn verify_cairo_with_component_set( cairo_proof: &CairoProof, component_set: HashSet<&str>, ) -> Result, String> { - let FlatClaim { component_enable_bits, component_log_sizes: _, public_data: _ } = + let FlatClaim { component_enable_bits, component_log_sizes, public_data: _ } = cairo_proof.claim.flatten_claim(); let components: indexmap::IndexMap<&'static str, Box>> = zip_eq(all_components::().into_iter(), &component_enable_bits) @@ -82,7 +82,8 @@ pub fn verify_cairo_with_component_set( ); let (proof, public_data) = prepare_cairo_proof_for_circuit_verifier(cairo_proof, &proof_config); - let (public_claim, outputs, program) = public_data.pack_into_u32s(); + let (mut public_claim, outputs, program) = public_data.pack_into_u32s(); + public_claim.extend(component_log_sizes); let outputs = outputs .chunks_exact(MEMORY_VALUES_LIMBS) .map(|chunk| array::from_fn(|i| M31::from_u32_unchecked(chunk[i]))) @@ -114,25 +115,27 @@ fn test_verify() { let mut novalue_context: Context = Context::new(N_RESERVED); let output_len = 1; let program_len = 128; - let flat_claim = vec![M31::zero(); PUBLIC_DATA_LEN + output_len + program_len]; let outputs = vec![[M31::zero(); MEMORY_VALUES_LIMBS]; output_len]; let program: Arc<[[M31; MEMORY_VALUES_LIMBS]]> = std::iter::repeat_n([M31::zero(); MEMORY_VALUES_LIMBS], program_len).collect(); - let components = all_components(); - let mut statement = CairoStatement::new( + // Remove the pedersen points table component since it requires long preprocessed columns, which + // are not supported. + let pedersen_points_index = + all_components::().get_full("pedersen_points_table_window_bits_18").unwrap().0; + let mut components = all_components(); + components.shift_remove("pedersen_points_table_window_bits_18"); + + let public_claim = + vec![M31::zero(); PUBLIC_DATA_LEN + output_len + program_len + components.len()]; + let statement = CairoStatement::new( &mut novalue_context, - flat_claim, + public_claim, outputs, program, components, get_preprocessed_root(20 + pcs_config.fri_config.log_blowup_factor), PreProcessedTraceVariant::CanonicalSmall, ); - // Remove the pedersen points table component since it requires long preprocessed columns, which - // are not supported. - let pedersen_points_index = - all_components::().get_full("pedersen_points_table_window_bits_18").unwrap().0; - statement.components.shift_remove("pedersen_points_table_window_bits_18"); let mut enabled_bits = vec![true; all_components::().len()]; enabled_bits[pedersen_points_index] = false; diff --git a/crates/cairo_verifier/src/verify.rs b/crates/cairo_verifier/src/verify.rs index c9720623..53b6c075 100644 --- a/crates/cairo_verifier/src/verify.rs +++ b/crates/cairo_verifier/src/verify.rs @@ -12,10 +12,8 @@ use circuits::finalize_constants::finalize_constants; use circuits::ivalue::{IValue, NoValue}; use circuits::ops::Guess; use circuits_stark_verifier::constraint_eval::CircuitEval; -use circuits_stark_verifier::proof::{Claim, Proof, ProofConfig, empty_proof}; -use circuits_stark_verifier::proof_from_stark_proof::{ - pack_component_log_sizes, proof_from_stark_proof, -}; +use circuits_stark_verifier::proof::{Proof, ProofConfig, empty_proof}; +use circuits_stark_verifier::proof_from_stark_proof::proof_from_stark_proof; use circuits_stark_verifier::verify::verify; use indexmap::IndexMap; use itertools::{Itertools, zip_eq}; @@ -142,13 +140,14 @@ pub fn build_cairo_verifier_circuit(verifier_config: &CairoVerifierConfig) -> Co let n_outputs = verifier_config.n_outputs; let program_len = verifier_config.program.len(); - let public_data = vec![M31::zero(); PUBLIC_DATA_LEN + n_outputs + program_len]; + let n_components = components.len(); + let public_claim = vec![M31::zero(); PUBLIC_DATA_LEN + n_outputs + program_len + n_components]; let outputs = vec![[M31::zero(); MEMORY_VALUES_LIMBS]; n_outputs]; let mut context: Context = Context::new(N_RESERVED); let statement = CairoStatement::new( &mut context, - public_data, + public_claim, outputs, verifier_config.program.clone(), components, @@ -185,15 +184,10 @@ pub fn prepare_cairo_proof_for_circuit_verifier( debug_assert_eq!(component_log_sizes.len(), proof_config.n_components()); debug_assert_eq!(claimed_sums.len(), proof_config.n_components()); - let claim = Claim { - packed_component_log_sizes: pack_component_log_sizes(&component_log_sizes), - claimed_sums, - }; - let proof = proof_from_stark_proof( extended_stark_proof, proof_config, - claim, + claimed_sums, *interaction_pow, *channel_salt, ); diff --git a/crates/circuit_prover/src/prover.rs b/crates/circuit_prover/src/prover.rs index 60d53770..b6281f23 100644 --- a/crates/circuit_prover/src/prover.rs +++ b/crates/circuit_prover/src/prover.rs @@ -10,10 +10,8 @@ pub use circuit_verifier::circuit_proof::CircuitProof; use circuit_verifier::statement::INTERACTION_POW_BITS; use circuit_verifier::verify::CircuitPublicData; use circuits_stark_verifier::proof::Proof; -use circuits_stark_verifier::proof::{Claim, ProofConfig}; -use circuits_stark_verifier::proof_from_stark_proof::{ - pack_component_log_sizes, proof_from_stark_proof, -}; +use circuits_stark_verifier::proof::ProofConfig; +use circuits_stark_verifier::proof_from_stark_proof::proof_from_stark_proof; use itertools::chain; use num_traits::Zero; use stwo::core::channel::{Channel, MerkleChannel}; @@ -172,6 +170,7 @@ where &trace_generator, twiddles, ); + claim.mix_into(channel); tree_builder.commit(channel); @@ -234,15 +233,12 @@ pub fn prepare_circuit_proof_for_circuit_verifier( let public_data = CircuitPublicData { output_values: claim.output_values.clone() }; - let claim = Claim { - packed_component_log_sizes: pack_component_log_sizes(&claim.log_sizes), - claimed_sums: interaction_claim.claimed_sums.to_vec(), - }; + let claimed_sums = interaction_claim.claimed_sums.to_vec(); let proof = proof_from_stark_proof( &stark_proof, proof_config, - claim, + claimed_sums, interaction_pow_nonce, channel_salt, ); diff --git a/crates/circuit_serialize/src/deserialize.rs b/crates/circuit_serialize/src/deserialize.rs index 10ccb9e3..67fbf28e 100644 --- a/crates/circuit_serialize/src/deserialize.rs +++ b/crates/circuit_serialize/src/deserialize.rs @@ -10,8 +10,7 @@ use circuits_stark_verifier::fri_proof::{ }; use circuits_stark_verifier::merkle::{AuthPath, AuthPaths}; use circuits_stark_verifier::oods::{EvalDomainSamples, N_COMPOSITION_COLUMNS}; -use circuits_stark_verifier::proof::{Claim, InteractionAtOods, N_TRACES, Proof, ProofConfig}; -use circuits_stark_verifier::proof_from_stark_proof::pack_component_log_sizes; +use circuits_stark_verifier::proof::{InteractionAtOods, N_TRACES, Proof, ProofConfig}; #[derive(Debug)] pub enum DeserializeError { @@ -105,7 +104,7 @@ pub fn deserialize_proof_with_config( let trace_root = HashValue::::deserialize(data)?; let interaction_root = HashValue::::deserialize(data)?; let composition_polynomial_root = HashValue::::deserialize(data)?; - let claim = deserialize_claim(data, config)?; + let claimed_sums = deserialize_vec(data, config.n_components())?; let preprocessed_columns_at_oods = deserialize_vec(data, config.n_preprocessed_columns)?; let trace_at_oods = deserialize_vec(data, config.n_trace_columns)?; let interaction_at_oods = deserialize_interaction_at_oods(data, config)?; @@ -124,7 +123,7 @@ pub fn deserialize_proof_with_config( preprocessed_columns_at_oods, trace_at_oods, composition_eval_at_oods, - claim, + claimed_sums, interaction_at_oods, eval_domain_samples, eval_domain_auth_paths, @@ -134,19 +133,6 @@ pub fn deserialize_proof_with_config( }) } -fn deserialize_claim(data: &mut &[u8], config: &ProofConfig) -> DeserializeResult> { - let n_components = config.n_components(); - - // Unpack log sizes from packed u8s (1 per u8, 8 bits each). - let log_sizes: Vec = - take_bytes(data, n_components.next_multiple_of(4))?.iter().map(|&b| b as u32).collect(); - let packed_component_log_sizes = pack_component_log_sizes(&log_sizes); - - let claimed_sums = deserialize_vec(data, n_components)?; - - Ok(Claim { packed_component_log_sizes, claimed_sums }) -} - fn deserialize_interaction_at_oods( data: &mut &[u8], config: &ProofConfig, diff --git a/crates/circuit_serialize/src/serialize.rs b/crates/circuit_serialize/src/serialize.rs index 8d3e9c1d..dae4dccf 100644 --- a/crates/circuit_serialize/src/serialize.rs +++ b/crates/circuit_serialize/src/serialize.rs @@ -6,8 +6,7 @@ use circuits::wrappers::M31Wrapper; use circuits_stark_verifier::fri_proof::{FriCommitProof, FriProof, FriWitness}; use circuits_stark_verifier::merkle::{AuthPath, AuthPaths}; use circuits_stark_verifier::oods::EvalDomainSamples; -use circuits_stark_verifier::proof::{Claim, InteractionAtOods, Proof}; -use circuits_stark_verifier::verify::LOG_SIZE_BITS; +use circuits_stark_verifier::proof::{InteractionAtOods, Proof}; pub trait CircuitSerialize { fn serialize(&self, output: &mut Vec); @@ -23,7 +22,7 @@ impl CircuitSerialize for Proof { preprocessed_columns_at_oods, trace_at_oods, composition_eval_at_oods, - claim, + claimed_sums, interaction_at_oods, eval_domain_samples, eval_domain_auth_paths, @@ -36,7 +35,7 @@ impl CircuitSerialize for Proof { trace_root.serialize(output); interaction_root.serialize(output); composition_polynomial_root.serialize(output); - claim.serialize(output); + claimed_sums.serialize(output); preprocessed_columns_at_oods.as_slice().serialize(output); trace_at_oods.as_slice().serialize(output); interaction_at_oods.as_slice().serialize(output); @@ -89,22 +88,6 @@ impl CircuitSerialize for HashValue { } } -impl CircuitSerialize for Claim { - fn serialize(&self, output: &mut Vec) { - let Self { packed_component_log_sizes, claimed_sums } = self; - - // Pack log sizes: 1 per u8 (requires `LOG_SIZE_BITS` <= 8). - assert!(LOG_SIZE_BITS as usize <= 8); - for qm31 in packed_component_log_sizes { - for m31 in qm31.to_m31_array().into_iter() { - output.push((m31.0 & 0xFF) as u8); - } - } - - claimed_sums.serialize(output); - } -} - impl CircuitSerialize for InteractionAtOods { fn serialize(&self, output: &mut Vec) { let Self { at_oods, at_prev } = self; diff --git a/crates/circuit_serialize/src/test.rs b/crates/circuit_serialize/src/test.rs index b4174304..40b52329 100644 --- a/crates/circuit_serialize/src/test.rs +++ b/crates/circuit_serialize/src/test.rs @@ -4,10 +4,9 @@ use crate::deserialize::deserialize_proof_with_config; use crate::serialize::CircuitSerialize; use circuits_stark_verifier::proof::{ProofConfig, ProofInfo}; use circuits_stark_verifier::proof_from_stark_proof::proof_from_stark_proof; -use circuits_stark_verifier::statement::Statement; use circuits_stark_verifier_examples::simple_air::create_proof; use circuits_stark_verifier_examples::simple_statement::{ - COMPONENT_ENABLE_BITS, PREPROCESSED_COLUMN_LOG_SIZES, SimpleStatement, + COMPONENT_ENABLE_BITS, PREPROCESSED_COLUMN_LOG_SIZES, simple_statement_components, }; #[test] @@ -15,9 +14,9 @@ fn test_serialize_deserialize() { let (_components, claim, pcs_config, proof, interaction_pow_nonce, channel_salt) = create_proof(); - let statement = &SimpleStatement::::default(); + let components = simple_statement_components::(); let config = ProofConfig::new( - statement.get_components(), + &components, COMPONENT_ENABLE_BITS.to_vec(), PREPROCESSED_COLUMN_LOG_SIZES.len(), &pcs_config, diff --git a/crates/circuit_verifier/src/circuit_claim.rs b/crates/circuit_verifier/src/circuit_claim.rs index c632eb48..60b4161b 100644 --- a/crates/circuit_verifier/src/circuit_claim.rs +++ b/crates/circuit_verifier/src/circuit_claim.rs @@ -18,6 +18,7 @@ pub type ClaimedSum = QM31; #[derive(Debug, PartialEq)] pub struct CircuitClaim { + // TODO(ilya): Remove `log_sizes` they are fixed given a CircuitConfig. pub log_sizes: [ComponentLogSize; N_COMPONENTS], pub output_values: Vec, } diff --git a/crates/circuit_verifier/src/statement.rs b/crates/circuit_verifier/src/statement.rs index 7e31baab..1ef9684c 100644 --- a/crates/circuit_verifier/src/statement.rs +++ b/crates/circuit_verifier/src/statement.rs @@ -4,6 +4,7 @@ use crate::components::{ verify_bitwise_xor_9, verify_bitwise_xor_12, }; use crate::relations::GATE_RELATION_ID; +use crate::verify::CircuitConfig; use circuits::blake::HashValue; use circuits::context::{Context, U_VALUE, U_VAR_IDX, Var}; use circuits::eval; @@ -14,6 +15,7 @@ use circuits::wrappers::M31Wrapper; use circuits_stark_verifier::constraint_eval::CircuitEval; use circuits_stark_verifier::logup::logup_use_term; use circuits_stark_verifier::order_hash_map::OrderedHashMap; +use circuits_stark_verifier::proof_from_stark_proof::pack_into_qm31s; use circuits_stark_verifier::statement::Statement; use indexmap::IndexMap; use itertools::{Itertools, zip_eq}; @@ -28,7 +30,9 @@ pub struct CircuitStatement { /// The variable indices (addresses) of the output gates. output_addresses: Vec>, /// The values of the output gates. - output_values: Vec, + pub output_values: Vec, + /// Per-component trace log sizes packed as a [`Simd`]. + pub component_log_sizes: Simd, /// Maps preprocessed column ids to their log sizes. /// The order of the keys is the same as the order of the columns in the prover's preprocessed /// trace. @@ -39,11 +43,16 @@ pub struct CircuitStatement { impl CircuitStatement { pub fn new( context: &mut Context, - output_addresses: &[usize], + circuit_config: &CircuitConfig, output_values: &[QM31], - preprocessed_column_log_sizes: OrderedHashMap, - preprocessed_root: HashValue, ) -> Self { + let CircuitConfig { + config: _, + output_addresses, + preprocessed_column_log_sizes, + preprocessed_root, + } = circuit_config; + // The circuit being verified should have `U_VAR_IDX` as the last output wire (see // `circuits::finalize_constants`: the call to `finalize_constants` should always be the // last to add outputs to the circuit). @@ -70,11 +79,28 @@ impl CircuitStatement { HashValue(Value::from_qm31(preprocessed_root.0), Value::from_qm31(preprocessed_root.1)) .guess(context); + let components = all_circuit_components::(); + let component_log_sizes = components + .values() + .map(|c| { + c.log_size(preprocessed_column_log_sizes) + .expect("The circuit components can't have a dynamic log_size.") + }) + .collect_vec(); + + let n_components = component_log_sizes.len(); + let packed_log_sizes = pack_into_qm31s(component_log_sizes.iter().cloned()) + .into_iter() + .map(|qm31| Value::from_qm31(qm31).guess(context)) + .collect_vec(); + let component_log_sizes = Simd::from_packed(packed_log_sizes, n_components); + Self { - components: all_circuit_components(), + components, output_addresses, output_values, - preprocessed_column_log_sizes, + component_log_sizes, + preprocessed_column_log_sizes: preprocessed_column_log_sizes.clone(), preprocessed_root, } } @@ -83,6 +109,7 @@ impl CircuitStatement { &self.output_values } } + impl Statement for CircuitStatement { fn claims_to_mix(&self, _context: &mut Context) -> Vec> { vec![self.output_values.clone()] @@ -92,6 +119,10 @@ impl Statement for CircuitStatement { &self.components } + fn get_component_log_sizes(&self) -> &Simd { + &self.component_log_sizes + } + fn public_logup_sum( &self, context: &mut Context, diff --git a/crates/circuit_verifier/src/verify.rs b/crates/circuit_verifier/src/verify.rs index 54fe4454..c99af84b 100644 --- a/crates/circuit_verifier/src/verify.rs +++ b/crates/circuit_verifier/src/verify.rs @@ -46,13 +46,8 @@ pub fn build_verification_circuit( public_data: CircuitPublicData, ) -> Result, String> { let mut context = Context::new(N_RESERVED); - let statement = CircuitStatement::new( - &mut context, - &circuit_config.output_addresses, - &public_data.output_values, - circuit_config.preprocessed_column_log_sizes.clone(), - circuit_config.preprocessed_root, - ); + let statement = + CircuitStatement::new(&mut context, &circuit_config, &public_data.output_values); let proof_config = ProofConfig::new( statement.get_components(), diff --git a/crates/stark_verifier/src/constraint_eval.rs b/crates/stark_verifier/src/constraint_eval.rs index e6818bd2..df4fcca9 100644 --- a/crates/stark_verifier/src/constraint_eval.rs +++ b/crates/stark_verifier/src/constraint_eval.rs @@ -228,6 +228,7 @@ pub trait CircuitEval { fn relation_uses_per_row(&self) -> &[RelationUse]; + /// Returns the log size of the component, or `None` if the component's log size is dynamic. fn log_size( &self, preprocessed_column_log_sizes: &OrderedHashMap, diff --git a/crates/stark_verifier/src/proof.rs b/crates/stark_verifier/src/proof.rs index d3d66cc3..328da344 100644 --- a/crates/stark_verifier/src/proof.rs +++ b/crates/stark_verifier/src/proof.rs @@ -58,9 +58,7 @@ impl ProofInfo { let fixed = (1 + 3 * 2 + 1 + 1) * SECURE_EXTENSION_DEGREE * N_U8S_PER_U32; - let packed_log_sizes = config.n_components().next_multiple_of(4); // 1 log per u8. - let claimed_sums = config.n_components() * SECURE_EXTENSION_DEGREE * N_U8S_PER_U32; - let claim = packed_log_sizes + claimed_sums; + let claim = config.n_components() * SECURE_EXTENSION_DEGREE * N_U8S_PER_U32; let n_columns_per_trace = config.n_columns_per_trace(); let total_columns: usize = n_columns_per_trace.iter().sum(); @@ -368,26 +366,6 @@ impl Guess for InteractionAtOods { } } -#[derive(Debug, PartialEq)] -pub struct Claim { - // The log sizes of the components in the AIR. - // Every QM31 hold up to 4 component log sizes. - pub packed_component_log_sizes: Vec, - - // Claimed sum for each component in the AIR. - pub claimed_sums: Vec, -} -impl Guess for Claim { - type Target = Claim; - - fn guess(&self, context: &mut Context) -> Self::Target { - Claim { - packed_component_log_sizes: self.packed_component_log_sizes.guess(context), - claimed_sums: self.claimed_sums.guess(context), - } - } -} - #[derive(Debug, PartialEq)] pub struct Proof { pub channel_salt: T, @@ -397,8 +375,8 @@ pub struct Proof { pub interaction_root: HashValue, pub composition_polynomial_root: HashValue, - // Claim. - pub claim: Claim, + // Claimed sum for each component in the AIR. + pub claimed_sums: Vec, // Evaluations at the OODS point and the previous point. pub preprocessed_columns_at_oods: Vec, @@ -471,10 +449,7 @@ pub fn empty_proof(config: &ProofConfig) -> Proof { } }) .collect(), - claim: Claim { - packed_component_log_sizes: vec![NoValue; n_components.div_ceil(4)], - claimed_sums: vec![NoValue; n_components], - }, + claimed_sums: vec![NoValue; n_components], composition_eval_at_oods: [NoValue; N_COMPOSITION_COLUMNS], eval_domain_samples: empty_eval_domain_samples( &config.n_columns_per_trace(), @@ -498,7 +473,7 @@ impl Guess for Proof { trace_root: self.trace_root.guess(context), interaction_root: self.interaction_root.guess(context), composition_polynomial_root: self.composition_polynomial_root.guess(context), - claim: self.claim.guess(context), + claimed_sums: self.claimed_sums.guess(context), preprocessed_columns_at_oods: self.preprocessed_columns_at_oods.guess(context), trace_at_oods: self.trace_at_oods.guess(context), interaction_at_oods: self.interaction_at_oods.guess(context), diff --git a/crates/stark_verifier/src/proof_from_stark_proof.rs b/crates/stark_verifier/src/proof_from_stark_proof.rs index 89561a6f..92f74022 100644 --- a/crates/stark_verifier/src/proof_from_stark_proof.rs +++ b/crates/stark_verifier/src/proof_from_stark_proof.rs @@ -16,14 +16,14 @@ use crate::fri_proof::compute_all_fold_steps; use crate::fri_proof::{FriCommitProof, FriProof}; use crate::merkle::{AuthPath, AuthPaths}; use crate::oods::EvalDomainSamples; -use crate::proof::{Claim, InteractionAtOods, N_TRACES, Proof, ProofConfig}; +use crate::proof::{InteractionAtOods, N_TRACES, Proof, ProofConfig}; use circuits::ivalue::qm31_from_u32s; /// Constructs [Proof] with the values from the given proof ([ExtendedStarkProof]). pub fn proof_from_stark_proof( proof: &ExtendedStarkProof, config: &ProofConfig, - claim: Claim, + claimed_sums: Vec, interaction_pow_nonce: u64, channel_salt: u32, ) -> Proof { @@ -57,7 +57,7 @@ pub fn proof_from_stark_proof( _ => panic!("Unexpected interaction at OODS values"), }) .collect_vec(), - claim, + claimed_sums, composition_eval_at_oods: as_single_row(&sampled_values[3]).try_into().unwrap(), eval_domain_samples: construct_eval_domain_samples(proof, config), eval_domain_auth_paths: construct_eval_domain_auth_paths(proof, config), diff --git a/crates/stark_verifier/src/statement.rs b/crates/stark_verifier/src/statement.rs index 38b18e1c..32cacea0 100644 --- a/crates/stark_verifier/src/statement.rs +++ b/crates/stark_verifier/src/statement.rs @@ -41,6 +41,8 @@ pub trait Statement { /// Returns the AIR components that define the constraint system. fn get_components(&self) -> &IndexMap<&'static str, Box>>; + fn get_component_log_sizes(&self) -> &Simd; + /// Returns the IDs of the preprocessed columns used by this statement's components. fn get_preprocessed_column_ids(&self) -> Vec; diff --git a/crates/stark_verifier/src/verify.rs b/crates/stark_verifier/src/verify.rs index 3bfe98c3..5d78dda6 100644 --- a/crates/stark_verifier/src/verify.rs +++ b/crates/stark_verifier/src/verify.rs @@ -74,9 +74,7 @@ pub fn verify( let preprocessed_root = statement.get_preprocessed_root(context); channel.mix_commitment(context, preprocessed_root); - let n_components = config.n_components(); - let component_log_sizes = - Simd::from_packed(proof.claim.packed_component_log_sizes.clone(), n_components); + let component_log_sizes = statement.get_component_log_sizes().clone(); let component_sizes = validate_and_compute_component_sizes(context, &component_log_sizes); // Check that the component sizes are at most 2^config.log_trace_size(). @@ -93,7 +91,7 @@ pub fn verify( pack_enable_bits(enable_bits).into_iter().map(|qm31| context.constant(qm31)).collect_vec(); channel.mix_qm31s(context, packed_enable_bits); - channel.mix_qm31s(context, proof.claim.packed_component_log_sizes.iter().cloned()); + channel.mix_qm31s(context, component_log_sizes.get_packed().iter().cloned()); for claim_to_mix in statement.claims_to_mix(context) { channel.mix_qm31s(context, claim_to_mix.iter().cloned()); } @@ -106,9 +104,9 @@ pub fn verify( let [interaction_z, interaction_alpha] = channel.draw_two_qm31s(context); let public_logup_sum = statement.public_logup_sum(context, [interaction_z, interaction_alpha]); - validate_logup_sum(context, public_logup_sum, &proof.claim.claimed_sums); + validate_logup_sum(context, public_logup_sum, &proof.claimed_sums); - channel.mix_qm31s(context, proof.claim.claimed_sums.iter().cloned()); + channel.mix_qm31s(context, proof.claimed_sums.iter().cloned()); channel.mix_commitment(context, proof.interaction_root); // Draw a random QM31 coefficient for the composition polynomial. @@ -139,7 +137,7 @@ pub fn verify( log_domain_size: config.log_trace_size(), composition_polynomial_coeff, interaction_elements: [interaction_z, interaction_alpha], - claimed_sums: &proof.claim.claimed_sums, + claimed_sums: &proof.claimed_sums, component_sizes: &unpacked_component_sizes, n_instances_bits: &component_sizes_bits, }, diff --git a/crates/stark_verifier_examples/src/simple_air.rs b/crates/stark_verifier_examples/src/simple_air.rs index c5de31ca..d508fbbe 100644 --- a/crates/stark_verifier_examples/src/simple_air.rs +++ b/crates/stark_verifier_examples/src/simple_air.rs @@ -1,5 +1,4 @@ use circuits::ivalue::qm31_from_u32s; -use circuits_stark_verifier::proof::Claim; use circuits_stark_verifier::proof_from_stark_proof::{ pack_component_log_sizes, pack_enable_bits, pack_public_claim, }; @@ -187,7 +186,7 @@ fn generate_seq_column( /// Creates a proof for the simple AIR. See documentation in [Eval]. pub fn create_proof() -> ( Vec>, - Claim, + Vec, PcsConfig, ExtendedStarkProof, u64, @@ -202,7 +201,7 @@ pub fn create_proof_with_fold_step( fold_step: u32, ) -> ( Vec>, - Claim, + Vec, PcsConfig, ExtendedStarkProof, u64, @@ -317,12 +316,5 @@ pub fn create_proof_with_fold_step( .unwrap(); let components: Vec> = vec![Box::new(component_1), Box::new(component_2)]; - ( - components, - Claim { packed_component_log_sizes, claimed_sums }, - config, - proof, - interaction_pow_nonce, - channel_salt, - ) + (components, claimed_sums, config, proof, interaction_pow_nonce, channel_salt) } diff --git a/crates/stark_verifier_examples/src/simple_air_test.rs b/crates/stark_verifier_examples/src/simple_air_test.rs index d3ff7aeb..153d5cdc 100644 --- a/crates/stark_verifier_examples/src/simple_air_test.rs +++ b/crates/stark_verifier_examples/src/simple_air_test.rs @@ -5,21 +5,15 @@ use stwo::core::vcs_lifted::blake2_merkle::Blake2sM31MerkleChannel; use stwo::core::verifier::verify; use crate::simple_air::{INTERACTION_POW_BITS, LOG_SIZE_LONG, LOG_SIZE_SHORT, create_proof}; -use crate::simple_statement::COMPONENT_ENABLE_BITS; +use crate::simple_statement::{COMPONENT_ENABLE_BITS, COMPONENT_LOG_SIZES}; use circuits::ivalue::qm31_from_u32s; -use circuits_stark_verifier::proof::Claim; -use circuits_stark_verifier::proof_from_stark_proof::pack_enable_bits; +use circuits_stark_verifier::proof_from_stark_proof::{pack_component_log_sizes, pack_enable_bits}; #[test] fn verify_simple_proof() { - let ( - components, - Claim { packed_component_log_sizes, claimed_sums }, - config, - proof, - interaction_pow_nonce, - channel_salt, - ) = create_proof(); + let (components, claimed_sums, config, proof, interaction_pow_nonce, channel_salt) = + create_proof(); + let packed_component_log_sizes = pack_component_log_sizes(&COMPONENT_LOG_SIZES); // Verify. let verifier_channel = &mut Blake2sM31Channel::default(); diff --git a/crates/stark_verifier_examples/src/simple_statement.rs b/crates/stark_verifier_examples/src/simple_statement.rs index a4b63da0..66357b51 100644 --- a/crates/stark_verifier_examples/src/simple_statement.rs +++ b/crates/stark_verifier_examples/src/simple_statement.rs @@ -4,13 +4,15 @@ use circuits::blake::HashValue; use circuits::context::{Context, Var}; use circuits::eval; use circuits::ivalue::{IValue, qm31_from_u32s}; -use circuits::ops::div; +use circuits::ops::{Guess, div}; +use circuits::simd::Simd; use circuits_stark_verifier::constraint_eval::RelationUse; use circuits_stark_verifier::constraint_eval::{ CircuitEval, ComponentDataTrait, CompositionConstraintAccumulator, }; use circuits_stark_verifier::logup::combine_term; use circuits_stark_verifier::order_hash_map::OrderedHashMap; +use circuits_stark_verifier::proof_from_stark_proof::pack_into_qm31s; use circuits_stark_verifier::statement::Statement; use indexmap::IndexMap; use num_traits::One; @@ -27,30 +29,37 @@ pub const PREPROCESSED_COLUMN_LOG_SIZES: [u32; 2] = [LOG_SIZE_SHORT, LOG_SIZE_LO pub struct SimpleStatement { components: IndexMap<&'static str, Box>>, + component_log_sizes: Simd, } -impl Default for SimpleStatement { - fn default() -> Self { - Self { - components: IndexMap::from([ - ( - "squared_fibonacci_long", - Box::new(SquaredFibonacciComponent { - preprocessed_column_id: PreProcessedColumnId { - id: "row_const_long".to_string(), - }, - }) as Box>, - ), - ( - "squared_fibonacci_short", - Box::new(SquaredFibonacciComponent { - preprocessed_column_id: PreProcessedColumnId { - id: "row_const_short".to_string(), - }, - }) as Box>, - ), - ]), - } +pub fn simple_statement_components() +-> IndexMap<&'static str, Box>> { + IndexMap::from([ + ( + "squared_fibonacci_long", + Box::new(SquaredFibonacciComponent { + preprocessed_column_id: PreProcessedColumnId { id: "row_const_long".to_string() }, + }) as Box>, + ), + ( + "squared_fibonacci_short", + Box::new(SquaredFibonacciComponent { + preprocessed_column_id: PreProcessedColumnId { id: "row_const_short".to_string() }, + }) as Box>, + ), + ]) +} + +impl SimpleStatement { + pub fn new(context: &mut Context) -> Self { + let n_components = COMPONENT_LOG_SIZES.len(); + let packed_log_sizes = pack_into_qm31s(COMPONENT_LOG_SIZES.iter().cloned()) + .into_iter() + .map(|qm31| Value::from_qm31(qm31).guess(context)) + .collect::>(); + let component_log_sizes = Simd::from_packed(packed_log_sizes, n_components); + + Self { components: simple_statement_components(), component_log_sizes } } } @@ -144,6 +153,10 @@ impl Statement for SimpleStatement { &self.components } + fn get_component_log_sizes(&self) -> &Simd { + &self.component_log_sizes + } + fn public_logup_sum( &self, context: &mut Context, diff --git a/crates/stark_verifier_examples/src/verify_test.rs b/crates/stark_verifier_examples/src/verify_test.rs index d6dc7b26..e422d088 100644 --- a/crates/stark_verifier_examples/src/verify_test.rs +++ b/crates/stark_verifier_examples/src/verify_test.rs @@ -6,6 +6,7 @@ use stwo::core::vcs::blake2_hash::Blake2sHash; use crate::simple_air::{create_proof, create_proof_with_fold_step}; use crate::simple_statement::{ COMPONENT_ENABLE_BITS, PREPROCESSED_COLUMN_LOG_SIZES, SimpleStatement, + simple_statement_components, }; use circuit_serialize::serialize::CircuitSerialize; use circuits::context::{Context, TraceContext}; @@ -15,7 +16,6 @@ use circuits::ops::Guess; use circuits_stark_verifier::fri_proof::compute_all_fold_steps; use circuits_stark_verifier::proof::{ProofConfig, ProofInfo, empty_proof}; use circuits_stark_verifier::proof_from_stark_proof::proof_from_stark_proof; -use circuits_stark_verifier::statement::Statement; use circuits_stark_verifier::verify::verify; enum ProofModifier { @@ -38,9 +38,9 @@ fn test_verify(#[case] proof_modifier: ProofModifier) { let (_components, claim, pcs_config, mut proof, interaction_pow_nonce, channel_salt) = create_proof(); - let statement = SimpleStatement::::default(); + let components = simple_statement_components::(); let config = ProofConfig::new( - statement.get_components(), + &components, COMPONENT_ENABLE_BITS.to_vec(), PREPROCESSED_COLUMN_LOG_SIZES.len(), &pcs_config, @@ -51,7 +51,7 @@ fn test_verify(#[case] proof_modifier: ProofModifier) { let empty_proof = empty_proof(&config); let mut novalue_context = Context::::default(); let proof_vars = empty_proof.guess(&mut novalue_context); - let statement = SimpleStatement::default(); + let statement = SimpleStatement::new(&mut novalue_context); verify(&mut novalue_context, &proof_vars, &config, &statement); finalize_constants(&mut novalue_context); novalue_context.finalize_guessed_vars(); @@ -89,7 +89,7 @@ fn test_verify(#[case] proof_modifier: ProofModifier) { let mut context = TraceContext::default(); let proof = proof_from_stark_proof(&proof, &config, claim, interaction_pow_nonce, channel_salt); let proof_vars = proof.guess(&mut context); - let statement = SimpleStatement::default(); + let statement = SimpleStatement::new(&mut context); verify(&mut context, &proof_vars, &config, &statement); finalize_constants(&mut context); @@ -149,9 +149,9 @@ fn test_proof_info(#[case] fold_step: u32) { let (_components, claim, pcs_config, proof, interaction_pow_nonce, channel_salt) = create_proof_with_fold_step(fold_step); - let statement = &SimpleStatement::::default(); + let components = simple_statement_components::(); let config = ProofConfig::new( - statement.get_components(), + &components, COMPONENT_ENABLE_BITS.to_vec(), PREPROCESSED_COLUMN_LOG_SIZES.len(), &pcs_config,