Skip to content

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

ModeWhat actually happensGas costWhen you'd see it
EZKL_ONLYEZKL runs the inference. The output is available programmatically, but no proof artifact is written on-chain. Verification stays off-chain.0 L2 gasFast advisory checks — "is this pool safe?" queries, development flows, low-stakes screening
EZKL_BRIDGEEZKL 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 gasStandard execution gating — the model output is cryptographically verified before capital moves
FULL_DUAL_PROVEREverything from EZKL_BRIDGE, plus an independent STARK integrity lane via Stone. Two separate proof systems verify the same action independently.~77M L2 gasHigh-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:

LaneHow it worksEvidence
ModelBridge (Groth16/Garaga)Standard EZKL → Circom bridge → Groth16 proof → Garaga BN254 pairing check on StarknetTx on Voyager
ModelBridgeHeavy (Groth16/Garaga)Same flow but heavier artifact (~8MB zkey vs ~2MB) for complex model outputsTx on Voyager
Noir HONKEZKL proof bridged through a Noir circuit, verified via HONK protocolTx on Voyager
Native KZGDirect EZKL KZG proof, strict mode with bundle injectionTx on Voyager
STARK Heavy ReputationReputation proof via Stone STARK proverTx 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

ContractAddressNetwork
ModelBridge Verifier0x037c4...626fStarknet Sepolia
ZkmlVerifier0x068ab...8923Starknet Sepolia
GaragaVerifier (BN254)0x06d0c...6d37Starknet Sepolia
Halo2Verifier (EZKL KZG)0xF7b55...2Ab9Ethereum 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:

  1. Signal arrives — could be a market opportunity, a rebalance trigger, or just the user clicking "deploy." Something initiates the flow.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. User signs — wallet signature. This is the "go" moment.

  7. 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.

  8. 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.

  9. 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:

PathWhat it doesStatus
Path 1Verify proofs on L3 contracts, register facts in ObsqraFactRegistryActive production path — this is what runs today
Path 2Prove L3 block validity to L2 via SNOS-style recursive proofStaged — the plumbing exists but isn't in the hot path
Path 3Move aggregation semantics into L3 contracts directlyPlanned

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

MethodEndpointWhat it tells you
GET/api/v1/zkdefi/proofs/sequencer-statusIs the proof sequencer alive and processing?
GET/api/v1/aggregation/statsAggregation pipeline throughput stats
GET/api/v1/aggregation/madara/healthMadara 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
ComponentPortWhat it handles
zkde backend:8003Everything user-facing — trade, policy, profile, privacy, proof orchestration, WebSocket events
obsqra backend:8002Proof aggregation, sequencing, settlement to L2/L3
Madara L3:9944Dedicated appchain for proof fact registration
Frontend:3001The 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 runs EZKL_BRIDGE (proven, moderate gas). A high-value autonomous action runs FULL_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

  1. Path B completion — universal kzg_mpcheck_v1 witness extraction + live strict-mode pass receipts. The sidecar/extractor hooks are wired; the remaining work is robust automatic extraction coverage.
  2. Path A hardening — recurring HONK receipts plus a gas/latency benchmark cadence.
  3. Paths 2 and 3 — full recursive closure from L3 → L2 → L1.

Next: zkML + Circuit Stack · Privacy Rails · Live Proof Readout

Built by Obsqra Labs