Skip to content

Commit 5428926

Browse files
alon-fclaude
andcommitted
Add BlakeGGate AIR component with full prove+verify
Integrates the auto-generated BlakeGGate into the circuit prover: - BlakeGGate added to ComponentList, CircuitComponents, trace writing, interaction trace, statement, and prover - Preprocessed column IDs renamed to match the AIR (blake_g_gate_input_addr_a/b/c/d/f0/f1, blake_g_gate_output_addr_a/b/c/d, blake_g_gate_multiplicity) - Padding for blake_g gates in finalize_context - Full prove+verify test (test_prove_and_stark_verify_blake_g_gate_context) - Updated FIBONACCI_CIRCUIT_PREPROCESSED_ROOT for N_COMPONENTS=18 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent fd97a69 commit 5428926

8 files changed

Lines changed: 170 additions & 19 deletions

File tree

crates/circuit_air/src/components/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ define_component_list! {
4242
BlakeG,
4343
BlakeOutput,
4444
TripleXor32,
45+
BlakeGGate,
4546
M31ToU32,
4647
TripleXor,
4748
VerifyBitwiseXor8,
@@ -62,6 +63,7 @@ pub struct CircuitComponents {
6263
pub blake_g: blake_g::Component,
6364
pub blake_output: blake_output::Component,
6465
pub triple_xor_32: triple_xor_32::Component,
66+
pub blake_g_gate: blake_g_gate::Component,
6567
pub m_31_to_u_32: m_31_to_u_32::Component,
6668
pub triple_xor: triple_xor::Component,
6769
pub verify_bitwise_xor_8: verify_bitwise_xor_8::Component,
@@ -157,6 +159,16 @@ impl CircuitComponents {
157159
},
158160
interaction_claim.claimed_sums[ComponentList::TripleXor32 as usize],
159161
);
162+
let blake_g_gate_component = blake_g_gate::Component::new(
163+
tree_span_provider,
164+
blake_g_gate::Eval {
165+
claim: blake_g_gate::Claim {
166+
log_size: circuit_claim.log_sizes[ComponentList::BlakeGGate as usize],
167+
},
168+
common_lookup_elements: interaction_elements.common_lookup_elements.clone(),
169+
},
170+
interaction_claim.claimed_sums[ComponentList::BlakeGGate as usize],
171+
);
160172
let m_31_to_u_32_component = m_31_to_u_32::Component::new(
161173
tree_span_provider,
162174
m_31_to_u_32::Eval {
@@ -242,6 +254,7 @@ impl CircuitComponents {
242254
blake_g: blake_g_component,
243255
blake_output: blake_output_component,
244256
triple_xor_32: triple_xor_32_component,
257+
blake_g_gate: blake_g_gate_component,
245258
m_31_to_u_32: m_31_to_u_32_component,
246259
triple_xor: triple_xor_component,
247260
verify_bitwise_xor_8: verify_bitwise_xor_8_component,
@@ -264,6 +277,7 @@ impl CircuitComponents {
264277
Box::new(self.blake_g) as Box<dyn Component>,
265278
Box::new(self.blake_output) as Box<dyn Component>,
266279
Box::new(self.triple_xor_32) as Box<dyn Component>,
280+
Box::new(self.blake_g_gate) as Box<dyn Component>,
267281
Box::new(self.m_31_to_u_32) as Box<dyn Component>,
268282
Box::new(self.triple_xor) as Box<dyn Component>,
269283
Box::new(self.verify_bitwise_xor_8) as Box<dyn Component>,

crates/circuit_air/src/statement.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::circuit_eval_components::{
2-
blake_g, blake_gate, blake_output, blake_round, blake_round_sigma, m_31_to_u_32,
2+
blake_g, blake_g_gate, blake_gate, blake_output, blake_round, blake_round_sigma, m_31_to_u_32,
33
range_check_15, range_check_16, triple_xor, triple_xor_32, verify_bitwise_xor_4,
44
verify_bitwise_xor_7, verify_bitwise_xor_8, verify_bitwise_xor_9, verify_bitwise_xor_12,
55
};
@@ -152,6 +152,7 @@ pub fn all_circuit_components<Value: IValue>() -> Vec<Box<dyn CircuitEval<Value>
152152
Box::new(blake_g::Component {}),
153153
Box::new(blake_output::Component {}),
154154
Box::new(triple_xor_32::Component {}),
155+
Box::new(blake_g_gate::Component {}),
155156
Box::new(m_31_to_u_32::Component {}),
156157
Box::new(triple_xor::Component {}),
157158
Box::new(verify_bitwise_xor_8::Component {}),

crates/circuit_common/src/finalize.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::N_LANES;
22
use circuits::blake::{HashValue, blake};
3-
use circuits::circuit::{M31ToU32Gate, TripleXorGate};
3+
use circuits::circuit::{BlakeGGate, M31ToU32Gate, TripleXorGate};
44
use circuits::context::{Context, Var};
55
use circuits::eval;
66
use circuits::ivalue::{IValue, qm31_from_u32s};
@@ -54,6 +54,30 @@ fn pad_blake(context: &mut Context<impl IValue>) {
5454
}
5555
}
5656

57+
fn pad_blake_g(context: &mut Context<impl IValue>) {
58+
let n_rows = context.circuit.blake_g.len();
59+
let padded = std::cmp::max(n_rows.next_power_of_two(), N_LANES);
60+
let zero = context.zero();
61+
for _ in n_rows..padded {
62+
let out_a = context.new_var(IValue::from_qm31(0.into()));
63+
let out_b = context.new_var(IValue::from_qm31(0.into()));
64+
let out_c = context.new_var(IValue::from_qm31(0.into()));
65+
let out_d = context.new_var(IValue::from_qm31(0.into()));
66+
context.circuit.blake_g.push(BlakeGGate {
67+
a: zero.idx,
68+
b: zero.idx,
69+
c: zero.idx,
70+
d: zero.idx,
71+
m0: zero.idx,
72+
m1: zero.idx,
73+
out_a: out_a.idx,
74+
out_b: out_b.idx,
75+
out_c: out_c.idx,
76+
out_d: out_d.idx,
77+
});
78+
}
79+
}
80+
5781
fn pad_m31_to_u32(context: &mut Context<impl IValue>) {
5882
let n_rows = context.circuit.m31_to_u32.len();
5983
let padded = std::cmp::max(n_rows.next_power_of_two(), N_LANES);
@@ -102,6 +126,7 @@ pub fn finalize_context(context: &mut Context<impl IValue>) {
102126
pad_eq(context);
103127
pad_qm31_ops(context);
104128
pad_blake(context);
129+
pad_blake_g(context);
105130
pad_m31_to_u32(context);
106131
pad_triple_xor(context);
107132
}

crates/circuit_common/src/preprocessed.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -459,17 +459,17 @@ fn add_blake_g_to_preprocessed_trace(
459459
fill_blake_g_columns(&circuit.blake_g, multiplicities, &mut columns);
460460

461461
let ids = [
462-
"blake_g_a_address",
463-
"blake_g_b_address",
464-
"blake_g_c_address",
465-
"blake_g_d_address",
466-
"blake_g_m0_address",
467-
"blake_g_m1_address",
468-
"blake_g_out_a_address",
469-
"blake_g_out_b_address",
470-
"blake_g_out_c_address",
471-
"blake_g_out_d_address",
472-
"blake_g_mult",
462+
"blake_g_gate_input_addr_a",
463+
"blake_g_gate_input_addr_b",
464+
"blake_g_gate_input_addr_c",
465+
"blake_g_gate_input_addr_d",
466+
"blake_g_gate_input_addr_f0",
467+
"blake_g_gate_input_addr_f1",
468+
"blake_g_gate_output_addr_a",
469+
"blake_g_gate_output_addr_b",
470+
"blake_g_gate_output_addr_c",
471+
"blake_g_gate_output_addr_d",
472+
"blake_g_gate_multiplicity",
473473
];
474474
for (id, column) in zip_eq(ids, columns) {
475475
pp_trace.push_column(PreProcessedColumnId { id: id.to_owned() }, column);

crates/circuit_common/src/preprocessed_test.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,12 @@ fn test_preprocess_decomposed_gates() {
196196
assert!(m31_mult.iter().all(|&m| m > 0));
197197

198198
// Verify BlakeG columns exist and have correct addresses.
199-
let bg_a = pp_trace.get_column(&PreProcessedColumnId { id: "blake_g_a_address".to_owned() });
200-
let bg_out_a =
201-
pp_trace.get_column(&PreProcessedColumnId { id: "blake_g_out_a_address".to_owned() });
202-
let bg_mult = pp_trace.get_column(&PreProcessedColumnId { id: "blake_g_mult".to_owned() });
199+
let bg_a = pp_trace
200+
.get_column(&PreProcessedColumnId { id: "blake_g_gate_input_addr_a".to_owned() });
201+
let bg_out_a = pp_trace
202+
.get_column(&PreProcessedColumnId { id: "blake_g_gate_output_addr_a".to_owned() });
203+
let bg_mult = pp_trace
204+
.get_column(&PreProcessedColumnId { id: "blake_g_gate_multiplicity".to_owned() });
203205
assert_eq!(bg_a.len(), 16);
204206
assert_eq!(bg_a[0], 16); // First gate's a = wire 16.
205207
assert_eq!(bg_out_a[0], 32); // First gate's out_a = wire 32.

crates/circuit_prover/src/prover.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ pub fn to_component_provers(
6464
&components.blake_g as &dyn ComponentProver<SimdBackend>,
6565
&components.blake_output as &dyn ComponentProver<SimdBackend>,
6666
&components.triple_xor_32 as &dyn ComponentProver<SimdBackend>,
67+
&components.blake_g_gate as &dyn ComponentProver<SimdBackend>,
6768
&components.m_31_to_u_32 as &dyn ComponentProver<SimdBackend>,
6869
&components.triple_xor as &dyn ComponentProver<SimdBackend>,
6970
&components.verify_bitwise_xor_8 as &dyn ComponentProver<SimdBackend>,

crates/circuit_prover/src/prover_test.rs

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use circuit_air::statement::{INTERACTION_POW_BITS, all_circuit_components};
66
use circuit_air::verify::{CircuitConfig, verify_circuit};
77
use circuit_common::finalize::finalize_context;
88
use circuit_common::preprocessed::PreprocessedCircuit;
9-
use circuits::blake::{blake, m31_to_u32_gate, pack_u32, triple_xor_gate};
9+
use circuits::blake::{blake, blake_g_gate as blake_g_gate_fn, m31_to_u32_gate, pack_u32, triple_xor_gate};
1010
use circuits::context::Var;
1111
use circuits::eval;
1212
use circuits::ivalue::{IValue, qm31_from_u32s};
@@ -278,7 +278,7 @@ fn test_prove_and_stark_verify_fibonacci_context() {
278278
}
279279

280280
const FIBONACCI_CIRCUIT_PREPROCESSED_ROOT: [u32; 8] =
281-
[819694180, 1334134931, 1528443241, 180931882, 500090799, 733233906, 1222299448, 1633395937];
281+
[623845414, 632928349, 1241137236, 579888351, 1255246133, 1278652435, 1440752206, 143572365];
282282

283283
#[test]
284284
fn test_prove_and_circuit_verify_fibonacci_context() {
@@ -477,6 +477,90 @@ fn test_prove_and_stark_verify_triple_xor_context() {
477477
);
478478
}
479479

480+
pub fn build_blake_g_gate_context() -> Context<QM31> {
481+
use circuits::wrappers::U32Wrapper;
482+
let mut context = Context::<QM31>::default();
483+
484+
// Create 32 blake_g gates (> N_LANES=16 so the trace is non-trivial).
485+
for i in 0..32u32 {
486+
let a = U32Wrapper::new_unsafe(guess(&mut context, pack_u32(i * 10 + 1)));
487+
let b = U32Wrapper::new_unsafe(guess(&mut context, pack_u32(i * 10 + 2)));
488+
let c = U32Wrapper::new_unsafe(guess(&mut context, pack_u32(i * 10 + 3)));
489+
let d = U32Wrapper::new_unsafe(guess(&mut context, pack_u32(i * 10 + 4)));
490+
let m0 = U32Wrapper::new_unsafe(guess(&mut context, pack_u32(i * 10 + 5)));
491+
let m1 = U32Wrapper::new_unsafe(guess(&mut context, pack_u32(i * 10 + 6)));
492+
let (_out_a, _out_b, _out_c, _out_d) =
493+
blake_g_gate_fn(&mut context, a, b, c, d, m0, m1);
494+
}
495+
let last = guess(&mut context, QM31::zero());
496+
output(&mut context, last);
497+
context
498+
}
499+
500+
#[test]
501+
fn test_prove_and_stark_verify_blake_g_gate_context() {
502+
let mut context = build_blake_g_gate_context();
503+
context.finalize_guessed_vars();
504+
context.validate_circuit();
505+
506+
let preprocessed_circuit = PreprocessedCircuit::preprocess_circuit(&mut context);
507+
let CircuitProof {
508+
pcs_config,
509+
claim,
510+
interaction_pow_nonce,
511+
interaction_claim,
512+
components,
513+
stark_proof,
514+
channel_salt,
515+
} = prove_circuit_assignment(
516+
context.values(),
517+
&preprocessed_circuit,
518+
&BaseColumnPool::<SimdBackend>::new(),
519+
);
520+
assert!(stark_proof.is_ok(), "Got error: {}", stark_proof.err().unwrap());
521+
let proof = stark_proof.unwrap();
522+
523+
let verifier_channel = &mut Blake2sM31Channel::default();
524+
verifier_channel.mix_felts(&[channel_salt.into()]);
525+
pcs_config.mix_into(verifier_channel);
526+
let commitment_scheme =
527+
&mut CommitmentSchemeVerifier::<Blake2sM31MerkleChannel>::new(pcs_config);
528+
529+
let sizes = TreeVec::concat_cols(components.iter().map(|c| c.trace_log_degree_bounds()));
530+
531+
commitment_scheme.commit(
532+
proof.proof.commitments[0],
533+
&preprocessed_circuit.preprocessed_trace.log_sizes(),
534+
verifier_channel,
535+
);
536+
claim.mix_into(verifier_channel);
537+
commitment_scheme.commit(proof.proof.commitments[1], &sizes[1], verifier_channel);
538+
verifier_channel.verify_pow_nonce(INTERACTION_POW_BITS, interaction_pow_nonce);
539+
verifier_channel.mix_u64(interaction_pow_nonce);
540+
let interaction_elements = CircuitInteractionElements::draw(verifier_channel);
541+
interaction_claim.mix_into(verifier_channel);
542+
commitment_scheme.commit(proof.proof.commitments[2], &sizes[2], verifier_channel);
543+
stwo::core::verifier::verify_ex(
544+
&components.iter().map(|c| c.as_ref()).collect::<Vec<&dyn Component>>(),
545+
verifier_channel,
546+
commitment_scheme,
547+
proof.proof,
548+
true,
549+
)
550+
.unwrap();
551+
552+
assert_eq!(
553+
lookup_sum(
554+
&claim,
555+
&interaction_claim,
556+
&interaction_elements,
557+
&preprocessed_circuit.params.output_addresses,
558+
preprocessed_circuit.params.n_blake_gates
559+
),
560+
QM31::zero()
561+
);
562+
}
563+
480564
#[test]
481565
fn test_finalize_context() {
482566
let mut context = build_fibonacci_context();

crates/circuit_prover/src/witness/trace.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::witness::components::qm31_ops;
1010
use crate::witness::components::range_check_15;
1111
use crate::witness::components::range_check_16;
1212
use crate::witness::components::triple_xor_32;
13+
use crate::witness::components::blake_g_gate;
1314
use crate::witness::components::triple_xor;
1415
use crate::witness::components::m_31_to_u_32;
1516
use crate::witness::components::verify_bitwise_xor_4;
@@ -197,6 +198,19 @@ pub fn write_trace(
197198
trace_evals.extend(blake_output_trace.to_evals());
198199
trace_evals.extend(triple_xor_32_trace.to_evals());
199200

201+
// Write blake_g_gate component.
202+
let (blake_g_gate_trace, blake_g_gate_claim, blake_g_gate_interaction_claim_gen) =
203+
blake_g_gate::write_trace(
204+
context_values,
205+
preprocessed_trace_ref,
206+
&verify_bitwise_xor_8_state,
207+
&verify_bitwise_xor_12_state,
208+
&verify_bitwise_xor_4_state,
209+
&verify_bitwise_xor_9_state,
210+
&verify_bitwise_xor_7_state,
211+
);
212+
trace_evals.extend(blake_g_gate_trace.to_evals());
213+
200214
// Write m31_to_u32 component.
201215
let (m_31_to_u_32_trace, m_31_to_u_32_claim, m_31_to_u_32_interaction_claim_gen) =
202216
m_31_to_u_32::write_trace(context_values, preprocessed_trace_ref, &range_check_16_state);
@@ -295,6 +309,7 @@ pub fn write_trace(
295309
blake_g_claim.log_size,
296310
blake_output_claim.log_size,
297311
triple_xor_32_claim.log_size,
312+
blake_g_gate_claim.log_size,
298313
m_31_to_u_32_claim.log_size,
299314
triple_xor_claim.log_size,
300315
circuit_air::components::verify_bitwise_xor_8::LOG_SIZE,
@@ -316,6 +331,7 @@ pub fn write_trace(
316331
blake_g: blake_g_interaction_claim_gen,
317332
blake_output: blake_output_interaction_claim_gen,
318333
triple_xor_32: triple_xor_32_interaction_claim_gen,
334+
blake_g_gate: blake_g_gate_interaction_claim_gen,
319335
m_31_to_u_32: m_31_to_u_32_interaction_claim_gen,
320336
triple_xor: triple_xor_interaction_claim_gen,
321337
verify_bitwise_xor_8: verify_bitwise_xor_8_interaction_claim_gen,
@@ -338,6 +354,7 @@ pub struct CircuitInteractionClaimGenerator {
338354
pub blake_g: blake_g::InteractionClaimGenerator,
339355
pub blake_output: blake_output::InteractionClaimGenerator,
340356
pub triple_xor_32: triple_xor_32::InteractionClaimGenerator,
357+
pub blake_g_gate: blake_g_gate::InteractionClaimGenerator,
341358
pub m_31_to_u_32: m_31_to_u_32::InteractionClaimGenerator,
342359
pub triple_xor: triple_xor::InteractionClaimGenerator,
343360
pub verify_bitwise_xor_8: verify_bitwise_xor_8::InteractionClaimGenerator,
@@ -409,6 +426,12 @@ pub fn write_interaction_trace(
409426
.write_interaction_trace(&interaction_elements.common_lookup_elements);
410427
tree_builder.extend_evals(triple_xor_32_trace);
411428

429+
// Write blake_g_gate interaction trace.
430+
let (blake_g_gate_trace, blake_g_gate_interaction_claim) = circuit_interaction_claim_generator
431+
.blake_g_gate
432+
.write_interaction_trace(&interaction_elements.common_lookup_elements);
433+
tree_builder.extend_evals(blake_g_gate_trace);
434+
412435
// Write m31_to_u32 interaction trace.
413436
let (m_31_to_u_32_trace, m_31_to_u_32_interaction_claim) = circuit_interaction_claim_generator
414437
.m_31_to_u_32
@@ -478,6 +501,7 @@ pub fn write_interaction_trace(
478501
blake_g_interaction_claim.claimed_sum,
479502
blake_output_interaction_claim.claimed_sum,
480503
triple_xor_32_interaction_claim.claimed_sum,
504+
blake_g_gate_interaction_claim.claimed_sum,
481505
m_31_to_u_32_interaction_claim.claimed_sum,
482506
triple_xor_interaction_claim.claimed_sum,
483507
verify_bitwise_xor_8_interaction_claim.claimed_sum,

0 commit comments

Comments
 (0)