Proof Pipeline
This is the engine room. Everything else in zkde.fi — the trading desk, the vaults, the privacy pools — eventually flows through this pipeline. Understanding it means understanding what the system actually guarantees.
The core idea: not every action needs the same proof weight. A low-stakes pool safety check doesn't need the same cryptographic treatment as a high-value vault rebalance. The pipeline supports three execution depths that trade verification strength for cost and speed, and the system picks the right one based on what's happening.
Live proof evidence for every lane: zkde.fi/test
How it's layered
The pipeline has three independent axes, and they compose:
flowchart LR A["<b>Execution depth</b><br/>How much proof?"] --> B["<b>Verifier lane</b><br/>Which proof system?"] B --> C["<b>Settlement path</b><br/>Where does it land?"] C --> D["Receipts + policy update"]
Execution depth decides how much proof infrastructure to spin up. Verifier lane determines which cryptographic system handles it. Settlement path decides where the proof gets registered. They're independent choices, and the system composes them per-action.
1. Execution depth: ProofMode
Source: backend/app/services/proof_mode.py
| Mode | What actually happens | Gas cost | When you'd see it |
|---|---|---|---|
EZKL_ONLY | EZKL runs the inference. The output is available programmatically, but no proof artifact is written on-chain. Verification stays off-chain. | 0 L2 gas | Fast advisory checks — "is this pool safe?" queries, development flows, low-stakes screening |
EZKL_BRIDGE | EZKL output gets bound into a bridge circuit (ModelBridge or ModelBridgeHeavy) and proven via Groth16. Garaga verifies the proof on-chain in Cairo. This is a real on-chain proof. | ~34M L2 gas | Standard execution gating — the model output is cryptographically verified before capital moves |
FULL_DUAL_PROVER | Everything from EZKL_BRIDGE, plus an independent STARK integrity lane via Stone. Two separate proof systems verify the same action independently. | ~77M L2 gas | High-value execution where you want dual independent verification. Belt and suspenders. |
The heavier modes aren't always available on every user-facing route. Capital submission paths are gated by EXECUTION_GATE_ALLOW_MAINNET_LIVE — if that's false, you can prove and verify but you can't execute against real pools. This is intentional for testnet environments.
2. Verifier lanes
Source: backend/app/services/proof_pipeline.py and l3_proving_path_client.py
Five lanes, all live, all with on-chain transaction evidence:
| Lane | How it works | Evidence |
|---|---|---|
| ModelBridge (Groth16/Garaga) | Standard EZKL → Circom bridge → Groth16 proof → Garaga BN254 pairing check on Starknet | Tx on Voyager |
| ModelBridgeHeavy (Groth16/Garaga) | Same flow but heavier artifact (~8MB zkey vs ~2MB) for complex model outputs | Tx on Voyager |
| Noir HONK | EZKL proof bridged through a Noir circuit, verified via HONK protocol | Tx on Voyager |
| Native KZG | Direct EZKL KZG proof, strict mode with bundle injection | Tx on Voyager |
| STARK Heavy Reputation | Reputation proof via Stone STARK prover | Tx on Voyager |
Why multiple lanes? Redundancy and flexibility. If one proving system has an issue, the others still work. Different lanes also have different performance characteristics — Groth16 proofs are small and cheap to verify but expensive to generate; STARKs are the opposite. Having both means the system can pick the right tradeoff per action.
Core verifier contracts
| Contract | Address | Network |
|---|---|---|
| ModelBridge Verifier | 0x037c4...626f | Starknet Sepolia |
| ZkmlVerifier | 0x068ab...8923 | Starknet Sepolia |
| GaragaVerifier (BN254) | 0x06d0c...6d37 | Starknet Sepolia |
| Halo2Verifier (EZKL KZG) | 0xF7b55...2Ab9 | Ethereum Sepolia |
3. Signal-to-receipt: the full lifecycle
Here's what actually happens when a user action flows through the pipeline, from intent to settled proof:
flowchart LR SIG["1. Signal arrives"] --> POL["2. Gate check"] POL --> ZKML["3. zkML screening"] ZKML --> ADP["4. Route selection"] ADP --> SIM["5. Simulation"] SIM --> TX["6. Wallet signs"] TX --> PROOF["7. Proof generation"] PROOF --> SETTLE["8. Settlement"] SETTLE --> RCPT["9. Receipt created"]
Walking through it:
Signal arrives — could be a market opportunity, a rebalance trigger, or just the user clicking "deploy." Something initiates the flow.
Policy gate evaluates — the system checks the user's reputation tier, collateral posture, and proof history. If they don't meet the threshold for this action, the flow stops here with a clear reason why.
zkML screening runs — the relevant circuits from the 13-circuit bundle evaluate the action's risk characteristics. Risk score, anomaly detection, impermanent loss prediction — whatever applies to this action type.
Route selected — the adapter layer determines the execution path. Ekubo swap? LP add? Lending supply? The adapter brings the right calldata builder and integration logic.
Simulation — calldata is built and dry-run before anything hits the chain. The user sees price impact, fees, and expected output. If the simulation looks bad, they can bail.
User signs — wallet signature. This is the "go" moment.
Proof generated — depending on ProofMode, this ranges from off-chain EZKL inference to full Groth16-via-Garaga on-chain verification. The proof covers the model output, the execution constraints, and the policy compliance.
Settlement — proof is registered on Madara L3 via
ObsqraFactRegistry, or on Starknet L2 as fallback. This is where the proof becomes a permanent, independently verifiable fact.Receipt created — an immutable receipt lands in
ReceiptRegistry. Trust/reputation state updates. The cycle closes.
4. Settlement paths
Three paths, from simplest to most recursive:
| Path | What it does | Status |
|---|---|---|
| Path 1 | Verify proofs on L3 contracts, register facts in ObsqraFactRegistry | Active production path — this is what runs today |
| Path 2 | Prove L3 block validity to L2 via SNOS-style recursive proof | Staged — the plumbing exists but isn't in the hot path |
| Path 3 | Move aggregation semantics into L3 contracts directly | Planned |
The endgame is full recursive closure: L3 proof → L2 validity proof → L1 settlement. That's not done yet, but the architecture supports it — the Madara L3 appchain was chosen specifically because it enables this recursive path.
Settlement endpoints
| Method | Endpoint | What it tells you |
|---|---|---|
GET | /api/v1/zkdefi/proofs/sequencer-status | Is the proof sequencer alive and processing? |
GET | /api/v1/aggregation/stats | Aggregation pipeline throughput stats |
GET | /api/v1/aggregation/madara/health | Madara L3 node health |
5. Runtime topology
The proof pipeline isn't a single service — it's distributed across several components that talk to each other:
flowchart TB UI["Frontend<br/>:3001"] BE["zkde backend<br/>:8003"] OB["obsqra backend<br/>:8002"] MAD["Madara L3<br/>:9944"] L2["Starknet L2"] UI --> BE BE -->|"policy, risk, routes"| BE BE -->|"proof sequencing"| OB OB -->|"fact registration"| MAD OB -->|"fallback settlement"| L2 MAD -->|"receipts"| BE L2 -->|"receipts"| BE BE -->|"UI state update"| UI
| Component | Port | What it handles |
|---|---|---|
| zkde backend | :8003 | Everything user-facing — trade, policy, profile, privacy, proof orchestration, WebSocket events |
| obsqra backend | :8002 | Proof aggregation, sequencing, settlement to L2/L3 |
| Madara L3 | :9944 | Dedicated appchain for proof fact registration |
| Frontend | :3001 | The app itself — /agent, /trade, /profile |
6. What this unlocks
The pipeline is infrastructure, but it has concrete product implications:
AI guidance becomes gateable execution. Instead of "the model recommends this" (a string), you get "the model proved this, and the proof was verified on-chain." That's an executable signal, not a recommendation.
Privacy rails work inside the proof framework. You can use shielded pools, nullifiers, relayers, and L3 settlement while still proving compliance. Privacy and verifiability aren't at odds — they compose.
Proof intensity scales with risk. A pool safety check runs
EZKL_ONLY(free, fast). A vault rebalance runsEZKL_BRIDGE(proven, moderate gas). A high-value autonomous action runsFULL_DUAL_PROVER(two independent proofs). Same pipeline, different trust levels.
Whether a specific user-facing flow exposes the full lane set depends on the route family and deployment config. Not everything is wired end-to-end yet.
7. What still needs to land
- Path B completion — universal
kzg_mpcheck_v1witness extraction + live strict-mode pass receipts. The sidecar/extractor hooks are wired; the remaining work is robust automatic extraction coverage. - Path A hardening — recurring HONK receipts plus a gas/latency benchmark cadence.
- Paths 2 and 3 — full recursive closure from L3 → L2 → L1.
Next: zkML + Circuit Stack · Privacy Rails · Live Proof Readout