Skip to content

Commit c89d052

Browse files
feat: root circuit uses re-introduced DagCommitSubAir (#2602)
Resolves INT-6981 and INT-6982. The PR to remove `DagCommitSubAir` is [here](https://github.com/openvm-org/openvm/pull/2533/changes). ## Overview This branch does two primary things: 1. Re-introduces `DagCommitSubAir` into the recursion circuit (reversing the recursion-side functional removal from `c6e042f3b8f833dde0222cb48d5c81f04e2274f8`). 2. Moves the root prover path to **no cached trace** mode (`has_cached = false`), using `CachedTraceCtx::Records` instead of cached PCS data. Branch commits: - `a97b89e37` — re-introduce `DagCommitSubAir` into recursion + API plumbing updates - `27e1c48d9` — root prover switched to no-cached mode - `6a25c5b35` — follow-up compile/test/type fixes ## Review Guide Suggested review order: 1. **Recursion DagCommit reintroduction** (`crates/recursion/**`) 2. **Root prover no-cached flow** (`crates/continuations/src/prover/root/**`) 3. **Cross-crate API updates** (`continuations` non-root traces, `guest-libs/verify-stark/circuit`, `sdk`, tests) --- ## 1) Recursion: DagCommitSubAir Reintroduced ### 1.1 New DagCommit sub-AIR implementation Files: - `crates/recursion/src/batch_constraint/expr_eval/dag_commit.rs` (new) - `crates/recursion/src/batch_constraint/expr_eval/mod.rs` What changed: - Restores `DagCommitSubAir`, `DagCommitCols`, `DagCommitPvs`, and helper logic for digest packing/collapse. - Adds `DagCommitInfo` generation (`commit` + Poseidon2 input stream) for no-cached mode. ### 1.2 SymbolicExpressionAir dual-mode behavior (cached vs no-cached) Files: - `crates/recursion/src/batch_constraint/expr_eval/symbolic_expression/air.rs` What changed: - `SymbolicExpressionAir` now carries `dag_commit_subair: Option<Arc<DagCommitSubAir<_>>>`. - In cached mode: - uses cached main width (`CachedSymbolicExpressionColumns`), zero public values. - In no-cached mode: - prefixes common main with `DagCommitCols`, - exposes `DagCommitPvs` public values, - evaluates DagCommit sub-AIR directly from common main prefix. ### 1.3 Trace generation restored for no-cached mode Files: - `crates/recursion/src/batch_constraint/expr_eval/symbolic_expression/trace.rs` What changed: - `SymbolicExpressionTraceGenerator` now takes `has_cached`. - `CachedTraceRecord` again carries optional `dag_commit_info`. - `build_cached_trace_record(child_vk, has_cached)` computes DagCommit inputs/commit when `has_cached == false`. - CPU tracegen writes DagCommit columns + symbolic-expression columns in no-cached mode. ### 1.4 Batch constraint/system plumbing and explicit cached context API Files: - `crates/recursion/src/batch_constraint/mod.rs` - `crates/recursion/src/system/mod.rs` What changed: - `BatchConstraintModule` now stores `has_cached` and configures `SymbolicExpressionAir` accordingly. - `VerifierConfig` includes `has_cached`. - Reintroduces explicit `CachedTraceCtx<PB>` API: - `PcsData(CommittedTraceData<PB>)` - `Records(CachedTraceRecord)` - `VerifierTraceGen::generate_proving_ctxs(_base)` now accepts `CachedTraceCtx` again. - CPU/GPU verifier tracegen paths now set either: - `cached_mains` from `PcsData`, or - symbolic-expression public values from `Records` (DagCommit commit). Note: - `DagCommitBus` is **not** reintroduced. DagCommit remains folded as sub-AIR, so bus-level wiring is still intentionally absent. ### 1.5 CUDA symbolic-expression DagCommit path restored Files: - `crates/recursion/cuda/src/batch_constraint/expr_eval/dag_commit.cuh` (new) - `crates/recursion/cuda/src/batch_constraint/expr_eval/symbolic_expression.cu` - `crates/recursion/src/batch_constraint/cuda_abi.rs` - `crates/recursion/src/batch_constraint/cuda_utils.rs` What changed: - Restores DagCommit column writing in CUDA symbolic-expression tracegen when no-cached mode is used. - Adds per-row cached metadata (`CachedGpuRecord`) carrying Poseidon2 start state + `is_constraint`. - `_sym_expr_common_tracegen`/Rust ABI now takes `d_cached_records` pointer. --- ## 2) Continuations Root Prover: No Cached Trace Files: - `crates/continuations/src/prover/root/mod.rs` - `crates/continuations/src/prover/root/trace.rs` - `crates/continuations/src/prover/mod.rs` What changed: - Root verifier subcircuit is built with `VerifierConfig { has_cached: false, ... }`. - Root prover now computes/stores `CachedTraceRecord` and feeds recursion via: - `CachedTraceCtx::Records(self.cached_trace_record.clone())` - Removed root prover dependency on cached PCS data for recursion tracegen (`child_vk_pcs_data` removed). - Removed root cached-commit getter (no longer needed by root path). - Simplified `RootProver` type shape by removing struct-level `PB`; backend type is now method-generic. - Updated root prover aliases accordingly. --- ## 3) Cross-Crate API Compatibility Updates ### 3.1 Continuations non-root prover calls updated to explicit `CachedTraceCtx` Files: - `crates/continuations/src/prover/inner/trace.rs` - `crates/continuations/src/prover/deferral/inner/trace.rs` - `crates/continuations/src/prover/deferral/hook/trace.rs` What changed: - Calls to recursion `generate_proving_ctxs` now pass `CachedTraceCtx::PcsData(...)`. ### 3.2 Verify-stark guest lib updated for recursion API changes Files: - `guest-libs/verify-stark/circuit/src/prover/mod.rs` - `guest-libs/verify-stark/circuit/src/prover/trace.rs` What changed: - Sets `VerifierConfig.has_cached = true` explicitly where required. - Uses `CachedTraceCtx::PcsData(...)` for recursion tracegen calls. ### 3.3 SDK/test call-site inference fixes after root prover generic changes Files: - `crates/sdk/src/prover/root.rs` - `crates/continuations/src/tests/mod.rs` - `crates/continuations/src/tests/e2e.rs` What changed: - Adds explicit PB typing where inference became ambiguous after moving root prover backend typing to method generics. --- ## 4) Test Updates Files: - `crates/recursion/src/tests.rs` What changed: - Adds coverage for no-cached DagCommit-subAIR path: - `test_recursion_circuit_dag_commit_subair` - uses `MixtureFixture::standard(...)` - builds verifier with `has_cached: false` - runs with `CachedTraceCtx::Records(...)`. - Existing recursion tests updated to pass `CachedTraceCtx::PcsData(...)` where appropriate. --- ## Primary Reviewer Focus If you only review a subset, prioritize: 1. `recursion` symbolic-expression + DagCommit integration (`air.rs`, `trace.rs`, `dag_commit.rs`, system wiring) 2. root prover no-cached migration (`continuations/prover/root/*`) 3. CUDA DagCommit tracegen plumbing (`symbolic_expression.cu`, `cuda_abi.rs`, `cuda_utils.rs`) --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com>
1 parent 84d6030 commit c89d052

File tree

23 files changed

+781
-169
lines changed

23 files changed

+781
-169
lines changed

Cargo.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/continuations/src/prover/deferral/hook/trace.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::iter::once;
22

33
use itertools::Itertools;
44
use openvm_recursion_circuit::system::{
5-
AggregationSubCircuit, VerifierExternalData, VerifierTraceGen,
5+
AggregationSubCircuit, CachedTraceCtx, VerifierExternalData, VerifierTraceGen,
66
};
77
use openvm_stark_backend::{
88
proof::Proof,
@@ -58,7 +58,7 @@ where
5858
.verifier_circuit
5959
.generate_proving_ctxs(
6060
&self.child_vk,
61-
self.child_vk_pcs_data.clone(),
61+
CachedTraceCtx::PcsData(self.child_vk_pcs_data.clone()),
6262
proof_slice,
6363
&mut external_data,
6464
default_duplex_sponge_recorder(),

crates/continuations/src/prover/deferral/inner/trace.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::iter::once;
22

33
use itertools::Itertools;
44
use openvm_recursion_circuit::system::{
5-
AggregationSubCircuit, VerifierExternalData, VerifierTraceGen,
5+
AggregationSubCircuit, CachedTraceCtx, VerifierExternalData, VerifierTraceGen,
66
};
77
use openvm_stark_backend::{
88
proof::Proof,
@@ -85,7 +85,7 @@ where
8585
.verifier_circuit
8686
.generate_proving_ctxs(
8787
child_vk,
88-
child_vk_pcs_data,
88+
CachedTraceCtx::PcsData(child_vk_pcs_data),
8989
proofs,
9090
&mut external_data,
9191
default_duplex_sponge_recorder(),

crates/continuations/src/prover/inner/trace.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use itertools::Itertools;
22
use openvm_recursion_circuit::system::{
3-
AggregationSubCircuit, VerifierExternalData, VerifierTraceGen,
3+
AggregationSubCircuit, CachedTraceCtx, VerifierExternalData, VerifierTraceGen,
44
};
55
use openvm_stark_backend::{
66
proof::Proof,
@@ -70,7 +70,7 @@ where
7070
.verifier_circuit
7171
.generate_proving_ctxs(
7272
child_vk,
73-
child_vk_pcs_data,
73+
CachedTraceCtx::PcsData(child_vk_pcs_data),
7474
proofs,
7575
&mut external_data,
7676
default_duplex_sponge_recorder(),

crates/continuations/src/prover/mod.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use openvm_cuda_backend::GpuBackend;
44
use openvm_recursion_circuit::system::VerifierSubCircuit;
55

66
#[cfg(feature = "root-prover")]
7-
use crate::{circuit::root::RootTraceGenImpl, RootSC};
7+
use crate::circuit::root::RootTraceGenImpl;
88
use crate::{
99
circuit::{
1010
deferral::{hook::DeferralHookTraceGenImpl, inner::DeferralInnerTraceGenImpl},
@@ -33,13 +33,9 @@ pub type InnerGpuProver<const MAX_NUM_PROOFS: usize> =
3333
InnerAggregationProver<GpuBackend, VerifierSubCircuit<MAX_NUM_PROOFS>, InnerTraceGenImpl>;
3434

3535
#[cfg(feature = "root-prover")]
36-
pub type RootCpuProver = RootProver<CpuBackend<RootSC>, VerifierSubCircuit<1>, RootTraceGenImpl>;
36+
pub type RootCpuProver = RootProver<VerifierSubCircuit<1>, RootTraceGenImpl>;
3737
#[cfg(all(feature = "cuda", feature = "root-prover"))]
38-
pub type RootGpuProver = RootProver<
39-
<openvm_cuda_backend::BabyBearBn254Poseidon2GpuEngine as openvm_stark_backend::StarkEngine>::PB,
40-
VerifierSubCircuit<1>,
41-
RootTraceGenImpl,
42-
>;
38+
pub type RootGpuProver = RootProver<VerifierSubCircuit<1>, RootTraceGenImpl>;
4339

4440
pub type DeferralInnerCpuProver =
4541
DeferralInnerProver<CpuBackend<SC>, VerifierSubCircuit<2>, DeferralInnerTraceGenImpl>;

crates/continuations/src/prover/root/mod.rs

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ use std::sync::Arc;
22

33
use eyre::Result;
44
use openvm_circuit::system::memory::dimensions::MemoryDimensions;
5-
use openvm_recursion_circuit::system::{AggregationSubCircuit, VerifierConfig, VerifierTraceGen};
5+
use openvm_recursion_circuit::{
6+
batch_constraint::expr_eval::CachedTraceRecord,
7+
system::{AggregationSubCircuit, VerifierConfig, VerifierTraceGen},
8+
};
69
use openvm_stark_backend::{
710
keygen::types::{MultiStarkProvingKey, MultiStarkVerifyingKey},
811
proof::Proof,
9-
prover::{CommittedTraceData, DeviceDataTransporter, ProverBackend, ProvingContext},
12+
prover::{DeviceDataTransporter, ProverBackend, ProvingContext},
1013
StarkEngine, SystemParams,
1114
};
1215
use openvm_stark_sdk::config::baby_bear_poseidon2::{EF, F};
@@ -25,35 +28,28 @@ use crate::{
2528

2629
mod trace;
2730

28-
pub struct RootProver<
29-
PB: ProverBackend<Val = F, Challenge = EF>,
30-
S: AggregationSubCircuit,
31-
T: RootTraceGen<PB>,
32-
> {
31+
pub struct RootProver<S: AggregationSubCircuit, T> {
3332
pk: Arc<MultiStarkProvingKey<RootSC>>,
3433
vk: Arc<MultiStarkVerifyingKey<RootSC>>,
3534

3635
agg_node_tracegen: T,
3736

3837
child_vk: Arc<MultiStarkVerifyingKey<SC>>,
39-
child_vk_pcs_data: CommittedTraceData<PB>,
38+
cached_trace_record: CachedTraceRecord,
4039
circuit: Arc<RootCircuit<S>>,
4140
trace_heights: Option<Vec<usize>>,
4241
}
4342

44-
impl<
45-
PB: ProverBackend<Val = F, Challenge = EF, Commitment = [Bn254; 1]>,
46-
S: AggregationSubCircuit + VerifierTraceGen<PB, RootSC>,
47-
T: RootTraceGen<PB>,
48-
> RootProver<PB, S, T>
49-
where
50-
PB::Matrix: Clone,
51-
{
43+
impl<S: AggregationSubCircuit, T> RootProver<S, T> {
5244
#[instrument(name = "total_proof", skip_all)]
53-
pub fn root_prove_from_ctx<E: StarkEngine<SC = RootSC, PB = PB>>(
54-
&self,
55-
ctx: ProvingContext<PB>,
56-
) -> Result<Proof<RootSC>> {
45+
pub fn root_prove_from_ctx<E>(&self, ctx: ProvingContext<E::PB>) -> Result<Proof<RootSC>>
46+
where
47+
E: StarkEngine<SC = RootSC>,
48+
E::PB: ProverBackend<Val = F, Challenge = EF, Commitment = [Bn254; 1]>,
49+
<E::PB as ProverBackend>::Matrix: Clone,
50+
S: VerifierTraceGen<E::PB, RootSC>,
51+
T: RootTraceGen<E::PB>,
52+
{
5753
if tracing::enabled!(tracing::Level::DEBUG) {
5854
trace_heights_tracing_info::<_, RootSC>(&ctx.per_trace, &self.circuit.airs());
5955
}
@@ -68,13 +64,8 @@ where
6864
}
6965
}
7066

71-
impl<
72-
PB: ProverBackend<Val = F, Challenge = EF, Commitment = [Bn254; 1]>,
73-
S: AggregationSubCircuit + VerifierTraceGen<PB, RootSC>,
74-
T: RootTraceGen<PB>,
75-
> RootProver<PB, S, T>
76-
{
77-
pub fn new<E: StarkEngine<SC = RootSC, PB = PB>>(
67+
impl<S: AggregationSubCircuit, T> RootProver<S, T> {
68+
pub fn new<E>(
7869
child_vk: Arc<MultiStarkVerifyingKey<SC>>,
7970
internal_recursive_cached_commit: CommitBytes,
8071
system_params: SystemParams,
@@ -84,20 +75,24 @@ impl<
8475
trace_heights: Option<Vec<usize>>,
8576
) -> Self
8677
where
87-
E::PD: DeviceDataTransporter<RootSC, PB> + Clone,
88-
PB::Val: Field + PrimeField32,
89-
PB::Matrix: Clone,
90-
PB::Commitment: Into<CommitBytes>,
78+
E: StarkEngine<SC = RootSC>,
79+
E::PB: ProverBackend<Val = F, Challenge = EF, Commitment = [Bn254; 1]>,
80+
S: VerifierTraceGen<E::PB, RootSC>,
81+
T: RootTraceGen<E::PB>,
82+
E::PD: DeviceDataTransporter<RootSC, E::PB> + Clone,
83+
<E::PB as ProverBackend>::Val: Field + PrimeField32,
84+
<E::PB as ProverBackend>::Matrix: Clone,
9185
{
9286
let verifier_circuit = S::new(
9387
child_vk.clone(),
9488
VerifierConfig {
9589
continuations_enabled: true,
90+
has_cached: false,
9691
..Default::default()
9792
},
9893
);
94+
let cached_trace_record = verifier_circuit.cached_trace_record(&child_vk);
9995
let engine = E::new(system_params);
100-
let child_vk_pcs_data = verifier_circuit.commit_child_vk(&engine, &child_vk);
10196
let internal_recursive_dag_commit = DagCommitBytes {
10297
cached_commit: internal_recursive_cached_commit,
10398
pre_hash: child_vk.pre_hash.into(),
@@ -115,13 +110,13 @@ impl<
115110
vk: Arc::new(vk),
116111
agg_node_tracegen: T::new(def_hook_vk_commit.is_some()),
117112
child_vk,
118-
child_vk_pcs_data,
113+
cached_trace_record,
119114
circuit,
120115
trace_heights,
121116
}
122117
}
123118

124-
pub fn from_pk<E: StarkEngine<SC = RootSC, PB = PB>>(
119+
pub fn from_pk<E>(
125120
child_vk: Arc<MultiStarkVerifyingKey<SC>>,
126121
internal_recursive_cached_commit: CommitBytes,
127122
pk: Arc<MultiStarkProvingKey<RootSC>>,
@@ -131,19 +126,22 @@ impl<
131126
trace_heights: Option<Vec<usize>>,
132127
) -> Self
133128
where
134-
PB::Val: Field + PrimeField32,
135-
PB::Matrix: Clone,
136-
PB::Commitment: Into<CommitBytes>,
129+
E: StarkEngine<SC = RootSC>,
130+
E::PB: ProverBackend<Val = F, Challenge = EF, Commitment = [Bn254; 1]>,
131+
S: VerifierTraceGen<E::PB, RootSC>,
132+
T: RootTraceGen<E::PB>,
133+
<E::PB as ProverBackend>::Val: Field + PrimeField32,
134+
<E::PB as ProverBackend>::Matrix: Clone,
137135
{
138136
let verifier_circuit = S::new(
139137
child_vk.clone(),
140138
VerifierConfig {
141139
continuations_enabled: true,
140+
has_cached: false,
142141
..Default::default()
143142
},
144143
);
145-
let engine = E::new(pk.params.clone());
146-
let child_vk_pcs_data = verifier_circuit.commit_child_vk(&engine, &child_vk);
144+
let cached_trace_record = verifier_circuit.cached_trace_record(&child_vk);
147145
let internal_recursive_dag_commit = DagCommitBytes {
148146
cached_commit: internal_recursive_cached_commit,
149147
pre_hash: child_vk.pre_hash.into(),
@@ -161,7 +159,7 @@ impl<
161159
vk,
162160
agg_node_tracegen: T::new(def_hook_vk_commit.is_some()),
163161
child_vk,
164-
child_vk_pcs_data,
162+
cached_trace_record,
165163
circuit,
166164
trace_heights,
167165
}
@@ -179,10 +177,6 @@ impl<
179177
self.vk.clone()
180178
}
181179

182-
pub fn get_cached_commit(&self) -> <PB as ProverBackend>::Commitment {
183-
self.child_vk_pcs_data.commitment
184-
}
185-
186180
pub fn get_trace_heights(&self) -> Option<Vec<usize>> {
187181
self.trace_heights.clone()
188182
}

crates/continuations/src/prover/root/trace.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use itertools::Itertools;
22
use openvm_circuit::system::memory::merkle::public_values::UserPublicValuesProof;
33
use openvm_recursion_circuit::system::{
4-
AggregationSubCircuit, VerifierExternalData, VerifierTraceGen,
4+
AggregationSubCircuit, CachedTraceCtx, VerifierExternalData, VerifierTraceGen,
55
};
66
use openvm_stark_backend::{
77
proof::Proof,
@@ -18,20 +18,19 @@ use crate::{
1818
RootSC, SC,
1919
};
2020

21-
impl<
22-
PB: ProverBackend<Val = F, Challenge = EF>,
23-
S: AggregationSubCircuit + VerifierTraceGen<PB, RootSC>,
24-
T: RootTraceGen<PB>,
25-
> RootProver<PB, S, T>
26-
where
27-
PB::Matrix: Clone,
28-
{
29-
pub fn generate_proving_ctx(
21+
impl<S: AggregationSubCircuit, T> RootProver<S, T> {
22+
pub fn generate_proving_ctx<PB>(
3023
&self,
3124
proof: Proof<SC>,
3225
user_pvs_proof: &UserPublicValuesProof<DIGEST_SIZE, PB::Val>,
3326
deferral_merkle_proofs: Option<&DeferralMerkleProofs<PB::Val>>,
34-
) -> Option<ProvingContext<PB>> {
27+
) -> Option<ProvingContext<PB>>
28+
where
29+
PB: ProverBackend<Val = F, Challenge = EF>,
30+
PB::Matrix: Clone,
31+
S: VerifierTraceGen<PB, RootSC>,
32+
T: RootTraceGen<PB>,
33+
{
3534
assert_eq!(
3635
user_pvs_proof.public_values.len(),
3736
self.circuit.num_user_pvs
@@ -71,7 +70,7 @@ where
7170

7271
let subcircuit_ctxs = self.circuit.verifier_circuit.generate_proving_ctxs(
7372
&self.child_vk,
74-
self.child_vk_pcs_data.clone(),
73+
CachedTraceCtx::Records(self.cached_trace_record.clone()),
7574
&[proof],
7675
&mut external_data,
7776
default_duplex_sponge_recorder(),
@@ -89,11 +88,17 @@ where
8988
}
9089

9190
#[instrument(name = "trace_gen", skip_all)]
92-
pub fn generate_proving_ctx_no_def(
91+
pub fn generate_proving_ctx_no_def<PB>(
9392
&self,
9493
proof: Proof<SC>,
9594
user_pvs_proof: &UserPublicValuesProof<DIGEST_SIZE, PB::Val>,
96-
) -> Option<ProvingContext<PB>> {
95+
) -> Option<ProvingContext<PB>>
96+
where
97+
PB: ProverBackend<Val = F, Challenge = EF>,
98+
PB::Matrix: Clone,
99+
S: VerifierTraceGen<PB, RootSC>,
100+
T: RootTraceGen<PB>,
101+
{
97102
assert!(
98103
self.circuit.def_hook_vk_commit.is_none(),
99104
"deferral-enabled root prover requires generate_proving_ctx_with_deferrals"

crates/continuations/src/tests/e2e.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -739,8 +739,11 @@ fn test_deferral_e2e() -> Result<()> {
739739
Some(def_hook_vk_commit.into()),
740740
None,
741741
);
742-
let ctx =
743-
root_prover.generate_proving_ctx(combined_proof, &user_pvs_proof, Some(&merkle_proofs));
742+
let ctx = root_prover.generate_proving_ctx::<<RootEngine as StarkEngine>::PB>(
743+
combined_proof,
744+
&user_pvs_proof,
745+
Some(&merkle_proofs),
746+
);
744747
warn!("proving root (CPU)");
745748
let root_proof = root_prover.root_prove_from_ctx::<RootEngine>(ctx.unwrap())?;
746749

0 commit comments

Comments
 (0)