Skip to content

Commit 879b009

Browse files
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. CircuitStatement derives the per-component log sizes from n_blake_compress (added to CircuitParams/CircuitConfig) plus preprocessed column log sizes, and now takes &CircuitConfig instead of seven individual fields. Cairo's component log sizes ride along on public_claim, removing the dedicated field on CairoVerifierConfig. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 96ac738 commit 879b009

23 files changed

Lines changed: 274 additions & 218 deletions

File tree

crates/cairo_verifier/src/privacy_test.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ fn verify_circuit_proof(
4646
config: circuit_proof.pcs_config,
4747
output_addresses: preprocessed_circuit.params.output_addresses.clone(),
4848
n_blake_gates: preprocessed_circuit.params.n_blake_gates,
49+
n_blake_compress: preprocessed_circuit.params.n_blake_compress,
4950
preprocessed_column_ids: preprocessed_circuit.preprocessed_trace.ids(),
5051
preprocessed_column_log_sizes: preprocessed_circuit.preprocessed_trace.log_sizes(),
5152
preprocessed_root,
@@ -240,6 +241,7 @@ fn test_privacy_proof_info() {
240241
config: pcs_config,
241242
output_addresses: preprocessed_circuit.params.output_addresses.clone(),
242243
n_blake_gates: preprocessed_circuit.params.n_blake_gates,
244+
n_blake_compress: preprocessed_circuit.params.n_blake_compress,
243245
preprocessed_column_ids: preprocessed_circuit.preprocessed_trace.ids(),
244246
preprocessed_column_log_sizes: preprocessed_circuit.preprocessed_trace.log_sizes(),
245247
preprocessed_root,
@@ -248,15 +250,8 @@ fn test_privacy_proof_info() {
248250
output_values: vec![QM31::zero(); preprocessed_circuit.params.output_addresses.len()],
249251
};
250252
let mut context = Context::<NoValue>::default();
251-
let statement = CircuitStatement::new(
252-
&mut context,
253-
&circuit_config.output_addresses,
254-
&public_data.output_values,
255-
circuit_config.n_blake_gates,
256-
circuit_config.preprocessed_column_ids.clone(),
257-
circuit_config.preprocessed_column_log_sizes.clone(),
258-
circuit_config.preprocessed_root,
259-
);
253+
let statement =
254+
CircuitStatement::new(&mut context, &circuit_config, &public_data.output_values);
260255

261256
let enabled_bits = vec![true; all_circuit_components::<NoValue>().len()];
262257
let proof_config = ProofConfig::new(
@@ -269,5 +264,5 @@ fn test_privacy_proof_info() {
269264
let proof_info = ProofInfo::from_config(&proof_config);
270265
println!("{proof_info}");
271266
// Assert the total size in bytes.
272-
assert_eq!(proof_info.total_bytes(), 347360);
267+
assert_eq!(proof_info.total_bytes(), 347344);
273268
}

crates/cairo_verifier/src/statement.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ pub struct CairoStatement<Value: IValue> {
145145
pub packed_outputs: Simd,
146146
pub preprocessed_root: HashValue<QM31>,
147147
pub preprocessed_trace_variant: PreProcessedTraceVariant,
148+
pub component_log_sizes: Simd,
148149
}
149150

150151
impl<Value: IValue> CairoStatement<Value> {
@@ -261,21 +262,29 @@ impl<Value: IValue> CairoStatement<Value> {
261262
}
262263

263264
impl<Value: IValue> CairoStatement<Value> {
265+
/// `public_claim` is the flat public claim laid out as:
266+
/// `[public_data (PUBLIC_DATA_LEN + outputs.len() + program.len() M31s) | component_log_sizes
267+
/// (components.len() M31s)]`.
264268
pub fn new(
265269
context: &mut Context<Value>,
266-
public_data: Vec<M31>,
270+
public_claim: Vec<M31>,
267271
outputs: Vec<[M31; MEMORY_VALUES_LIMBS]>,
268272
program: Arc<[[M31; MEMORY_VALUES_LIMBS]]>,
269273
components: IndexMap<&'static str, Box<dyn CircuitEval<Value>>>,
270274
preprocessed_root: HashValue<QM31>,
271275
preprocessed_trace_variant: PreProcessedTraceVariant,
272276
) -> Self {
273-
let packed_public_data = pack_into_qm31s(public_data.iter().cloned())
277+
let n_components = components.len();
278+
let public_data_len = PUBLIC_DATA_LEN + outputs.len() + program.len();
279+
assert_eq!(public_claim.len(), public_data_len + n_components);
280+
let (public_data_m31s, log_sizes_m31s) = public_claim.split_at(public_data_len);
281+
282+
let packed_public_data = pack_into_qm31s(public_data_m31s.iter().cloned())
274283
.into_iter()
275284
.map(|qm31| Value::from_qm31(qm31).guess(context))
276285
.collect_vec();
277286

278-
let packed_public_data = Simd::from_packed(packed_public_data, public_data.len());
287+
let packed_public_data = Simd::from_packed(packed_public_data, public_data_m31s.len());
279288
// Note that we don't enforce anything on the padding M31 in packed_public_data.
280289
let unpacked_simd = Simd::unpack(context, &packed_public_data);
281290

@@ -289,12 +298,19 @@ impl<Value: IValue> CairoStatement<Value> {
289298
.collect_vec();
290299
let packed_outputs = Simd::from_packed(packed_outputs, n_outputs * MEMORY_VALUES_LIMBS);
291300

301+
let packed_log_sizes = pack_into_qm31s(log_sizes_m31s.iter().cloned())
302+
.into_iter()
303+
.map(|qm31| Value::from_qm31(qm31).guess(context))
304+
.collect_vec();
305+
let component_log_sizes = Simd::from_packed(packed_log_sizes, n_components);
306+
292307
Self {
293308
packed_public_data,
294309
public_data,
295310
program,
296311
packed_outputs,
297312
components,
313+
component_log_sizes,
298314
preprocessed_root,
299315
preprocessed_trace_variant,
300316
}
@@ -306,13 +322,18 @@ impl<Value: IValue> Statement<Value> for CairoStatement<Value> {
306322
&self.components
307323
}
308324

325+
fn get_component_log_sizes(&self) -> &Simd {
326+
&self.component_log_sizes
327+
}
328+
309329
fn claims_to_mix(&self, context: &mut Context<Value>) -> Vec<Vec<Var>> {
310330
let Self {
311331
components: _components,
312332
packed_public_data,
313333
public_data: _public_data,
314334
program,
315335
packed_outputs,
336+
component_log_sizes: _component_log_sizes,
316337
preprocessed_root: _preprocessed_root,
317338
preprocessed_trace_variant: _preprocessed_trace_variant,
318339
} = self;

crates/cairo_verifier/src/test.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub fn verify_cairo_with_component_set(
5353
cairo_proof: &CairoProof<Blake2sM31MerkleHasher>,
5454
component_set: HashSet<&str>,
5555
) -> Result<Context<QM31>, String> {
56-
let FlatClaim { component_enable_bits, component_log_sizes: _, public_data: _ } =
56+
let FlatClaim { component_enable_bits, component_log_sizes, public_data: _ } =
5757
cairo_proof.claim.flatten_claim();
5858
let components: indexmap::IndexMap<&'static str, Box<dyn CircuitEval<QM31>>> =
5959
zip_eq(all_components::<QM31>().into_iter(), &component_enable_bits)
@@ -80,7 +80,8 @@ pub fn verify_cairo_with_component_set(
8080
);
8181

8282
let (proof, public_data) = prepare_cairo_proof_for_circuit_verifier(cairo_proof, &proof_config);
83-
let (public_claim, outputs, program) = public_data.pack_into_u32s();
83+
let (mut public_claim, outputs, program) = public_data.pack_into_u32s();
84+
public_claim.extend(component_log_sizes);
8485
let outputs = outputs
8586
.chunks_exact(MEMORY_VALUES_LIMBS)
8687
.map(|chunk| array::from_fn(|i| M31::from_u32_unchecked(chunk[i])))
@@ -112,25 +113,27 @@ fn test_verify() {
112113
let mut novalue_context = Context::<NoValue>::default();
113114
let output_len = 1;
114115
let program_len = 128;
115-
let flat_claim = vec![M31::zero(); PUBLIC_DATA_LEN + output_len + program_len];
116116
let outputs = vec![[M31::zero(); MEMORY_VALUES_LIMBS]; output_len];
117117
let program: Arc<[[M31; MEMORY_VALUES_LIMBS]]> =
118118
std::iter::repeat_n([M31::zero(); MEMORY_VALUES_LIMBS], program_len).collect();
119-
let components = all_components();
120-
let mut statement = CairoStatement::new(
119+
// Remove the pedersen points table component since it requires long preprocessed columns, which
120+
// are not supported.
121+
let pedersen_points_index =
122+
all_components::<NoValue>().get_full("pedersen_points_table_window_bits_18").unwrap().0;
123+
let mut components = all_components();
124+
components.shift_remove("pedersen_points_table_window_bits_18");
125+
126+
let public_claim =
127+
vec![M31::zero(); PUBLIC_DATA_LEN + output_len + program_len + components.len()];
128+
let statement = CairoStatement::new(
121129
&mut novalue_context,
122-
flat_claim,
130+
public_claim,
123131
outputs,
124132
program,
125133
components,
126134
get_preprocessed_root(20 + pcs_config.fri_config.log_blowup_factor),
127135
PreProcessedTraceVariant::CanonicalSmall,
128136
);
129-
// Remove the pedersen points table component since it requires long preprocessed columns, which
130-
// are not supported.
131-
let pedersen_points_index =
132-
all_components::<NoValue>().get_full("pedersen_points_table_window_bits_18").unwrap().0;
133-
statement.components.shift_remove("pedersen_points_table_window_bits_18");
134137

135138
let mut enabled_bits = vec![true; all_components::<NoValue>().len()];
136139
enabled_bits[pedersen_points_index] = false;

crates/cairo_verifier/src/verify.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@ use circuits::context::{Context, TraceContext};
1010
use circuits::ivalue::{IValue, NoValue};
1111
use circuits::ops::Guess;
1212
use circuits_stark_verifier::constraint_eval::CircuitEval;
13-
use circuits_stark_verifier::proof::{Claim, Proof, ProofConfig, empty_proof};
14-
use circuits_stark_verifier::proof_from_stark_proof::{
15-
pack_component_log_sizes, proof_from_stark_proof,
16-
};
13+
use circuits_stark_verifier::proof::{Proof, ProofConfig, empty_proof};
14+
use circuits_stark_verifier::proof_from_stark_proof::proof_from_stark_proof;
1715
use circuits_stark_verifier::verify::verify;
1816
use indexmap::IndexMap;
1917
use itertools::{Itertools, zip_eq};
@@ -139,13 +137,14 @@ pub fn build_cairo_verifier_circuit(verifier_config: &CairoVerifierConfig) -> Co
139137

140138
let n_outputs = verifier_config.n_outputs;
141139
let program_len = verifier_config.program.len();
142-
let public_data = vec![M31::zero(); PUBLIC_DATA_LEN + n_outputs + program_len];
140+
let n_components = components.len();
141+
let public_claim = vec![M31::zero(); PUBLIC_DATA_LEN + n_outputs + program_len + n_components];
143142
let outputs = vec![[M31::zero(); MEMORY_VALUES_LIMBS]; n_outputs];
144143

145144
let mut context = Context::<NoValue>::default();
146145
let statement = CairoStatement::<NoValue>::new(
147146
&mut context,
148-
public_data,
147+
public_claim,
149148
outputs,
150149
verifier_config.program.clone(),
151150
components,
@@ -181,15 +180,10 @@ pub fn prepare_cairo_proof_for_circuit_verifier(
181180
debug_assert_eq!(component_log_sizes.len(), proof_config.n_components());
182181
debug_assert_eq!(claimed_sums.len(), proof_config.n_components());
183182

184-
let claim = Claim {
185-
packed_component_log_sizes: pack_component_log_sizes(&component_log_sizes),
186-
claimed_sums,
187-
};
188-
189183
let proof = proof_from_stark_proof(
190184
extended_stark_proof,
191185
proof_config,
192-
claim,
186+
claimed_sums,
193187
*interaction_pow,
194188
*channel_salt,
195189
);

crates/circuit_common/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ pub struct CircuitParams {
99
pub trace_log_size: u32,
1010
pub first_permutation_row: usize,
1111
pub n_blake_gates: usize,
12+
/// Total number of blake compression blocks across all blake gates, after padding to a
13+
/// multiple of `N_LANES` (but not yet to a power of two). Equals `sum(gate.input.len())`
14+
/// over the padded gates.
15+
pub n_blake_compress: usize,
1216
pub output_addresses: Vec<usize>,
1317
}
1418

crates/circuit_common/src/preprocessed.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,10 +556,12 @@ impl PreprocessedCircuit {
556556
let blake_g_log_size = log_n_blake_updates + 7;
557557
let trace_log_size = std::cmp::max(max_pp_trace_log_size, blake_g_log_size);
558558

559+
let n_blake_compress: usize = circuit.blake.iter().map(|gate| gate.input.len()).sum();
559560
let params = CircuitParams {
560561
trace_log_size,
561562
first_permutation_row: qm31_ops_trace_generator.first_permutation_row,
562563
n_blake_gates: circuit.blake.len(),
564+
n_blake_compress,
563565
output_addresses: circuit.output.iter().map(|out| out.in0).collect(),
564566
};
565567

crates/circuit_prover/src/prover.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@ use circuit_verifier::circuit_claim::{
1111
use circuit_verifier::statement::INTERACTION_POW_BITS;
1212
use circuit_verifier::verify::CircuitPublicData;
1313
use circuits_stark_verifier::proof::Proof;
14-
use circuits_stark_verifier::proof::{Claim, ProofConfig};
15-
use circuits_stark_verifier::proof_from_stark_proof::{
16-
pack_component_log_sizes, proof_from_stark_proof,
17-
};
14+
use circuits_stark_verifier::proof::ProofConfig;
15+
use circuits_stark_verifier::proof_from_stark_proof::proof_from_stark_proof;
1816
use itertools::chain;
1917
use num_traits::Zero;
2018
use stwo::core::air::Component;
@@ -156,7 +154,13 @@ where
156154
SimdBackend: stwo::prover::backend::BackendForChannel<MC>,
157155
{
158156
let PreprocessedCircuit { preprocessed_trace, params } = preprocessed_circuit;
159-
let CircuitParams { first_permutation_row, n_blake_gates, output_addresses, .. } = params;
157+
let CircuitParams {
158+
first_permutation_row,
159+
n_blake_gates,
160+
n_blake_compress,
161+
output_addresses,
162+
..
163+
} = params;
160164
let trace_generator = TraceGenerator {
161165
qm31_ops_trace_generator: Qm31OpsTraceGenerator {
162166
first_permutation_row: *first_permutation_row,
@@ -187,6 +191,7 @@ where
187191
values,
188192
preprocessed_trace.clone(),
189193
output_addresses,
194+
*n_blake_compress,
190195
&mut tree_builder,
191196
&trace_generator,
192197
twiddles,
@@ -263,15 +268,12 @@ pub fn prepare_circuit_proof_for_circuit_verifier(
263268

264269
let public_data = CircuitPublicData { output_values: claim.output_values.clone() };
265270

266-
let claim = Claim {
267-
packed_component_log_sizes: pack_component_log_sizes(&claim.log_sizes),
268-
claimed_sums: interaction_claim.claimed_sums.to_vec(),
269-
};
271+
let claimed_sums = interaction_claim.claimed_sums.to_vec();
270272

271273
let proof = proof_from_stark_proof(
272274
&stark_proof,
273275
proof_config,
274-
claim,
276+
claimed_sums,
275277
interaction_pow_nonce,
276278
channel_salt,
277279
);

crates/circuit_prover/src/prover_test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ fn circuit_verify(
251251
config: circuit_proof.pcs_config,
252252
output_addresses: preprocessed_circuit.params.output_addresses.clone(),
253253
n_blake_gates: preprocessed_circuit.params.n_blake_gates,
254+
n_blake_compress: preprocessed_circuit.params.n_blake_compress,
254255
preprocessed_column_ids: preprocessed_circuit.preprocessed_trace.ids(),
255256
preprocessed_column_log_sizes: preprocessed_circuit.preprocessed_trace.log_sizes(),
256257
preprocessed_root: preprocessed_root.into(),

crates/circuit_prover/src/witness/trace.rs

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use circuit_common::preprocessed::PreProcessedTrace;
2222
use circuit_verifier::circuit_claim::CircuitClaim;
2323
use circuit_verifier::circuit_claim::CircuitInteractionClaim;
2424
use circuit_verifier::circuit_claim::CircuitInteractionElements;
25+
use circuit_verifier::statement::component_log_sizes;
2526
use itertools::Itertools;
2627
use num_traits::Zero;
2728
use rayon::scope;
@@ -41,6 +42,7 @@ pub fn write_trace<MC: MerkleChannel>(
4142
context_values: &[QM31],
4243
preprocessed_trace: Arc<PreProcessedTrace>,
4344
output_addresses: &[usize],
45+
n_blake_compress: usize,
4446
tree_builder: &mut TreeBuilder<'_, '_, SimdBackend, MC>,
4547
trace_generator: &TraceGenerator,
4648
twiddles: &TwiddleTree<SimdBackend>,
@@ -387,28 +389,33 @@ where
387389

388390
let output_values = output_addresses.iter().map(|addr| context_values[*addr]).collect_vec();
389391

392+
let log_sizes = [
393+
eq_log_size,
394+
qm31_ops_log_size,
395+
blake_gate_interaction_claim_gen.log_size,
396+
blake_round_log_size.log_size,
397+
crate::circuit_air::components::blake_round_sigma::LOG_SIZE,
398+
blake_g_claim.log_size,
399+
blake_output_claim.log_size,
400+
triple_xor_32_claim.log_size,
401+
m_31_to_u_32_claim.log_size,
402+
crate::circuit_air::components::verify_bitwise_xor_8::LOG_SIZE,
403+
crate::circuit_air::components::verify_bitwise_xor_12::LOG_SIZE,
404+
crate::circuit_air::components::verify_bitwise_xor_4::LOG_SIZE,
405+
crate::circuit_air::components::verify_bitwise_xor_7::LOG_SIZE,
406+
crate::circuit_air::components::verify_bitwise_xor_9::LOG_SIZE,
407+
crate::circuit_air::components::range_check_15::LOG_SIZE,
408+
crate::circuit_air::components::range_check_16::LOG_SIZE,
409+
];
410+
let expected_log_sizes = component_log_sizes(
411+
n_blake_compress,
412+
&preprocessed_trace.ids(),
413+
&preprocessed_trace.log_sizes(),
414+
);
415+
assert_eq!(log_sizes, expected_log_sizes);
416+
390417
(
391-
CircuitClaim {
392-
log_sizes: [
393-
eq_log_size,
394-
qm31_ops_log_size,
395-
blake_gate_interaction_claim_gen.log_size,
396-
blake_round_log_size.log_size,
397-
crate::circuit_air::components::blake_round_sigma::LOG_SIZE,
398-
blake_g_claim.log_size,
399-
blake_output_claim.log_size,
400-
triple_xor_32_claim.log_size,
401-
m_31_to_u_32_claim.log_size,
402-
crate::circuit_air::components::verify_bitwise_xor_8::LOG_SIZE,
403-
crate::circuit_air::components::verify_bitwise_xor_12::LOG_SIZE,
404-
crate::circuit_air::components::verify_bitwise_xor_4::LOG_SIZE,
405-
crate::circuit_air::components::verify_bitwise_xor_7::LOG_SIZE,
406-
crate::circuit_air::components::verify_bitwise_xor_9::LOG_SIZE,
407-
crate::circuit_air::components::range_check_15::LOG_SIZE,
408-
crate::circuit_air::components::range_check_16::LOG_SIZE,
409-
],
410-
output_values,
411-
},
418+
CircuitClaim { log_sizes, output_values },
412419
CircuitInteractionClaimGenerator {
413420
eq_lookup_data,
414421
qm31_ops_lookup_data,

0 commit comments

Comments
 (0)