Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture

crucible-prover is the proof engine of the Crucible polyrepo. It owns zero-knowledge proof generation, verification, proof artifacts, circuit interfaces, and prover backends. The other two polyrepos own their own domains and the boundaries between them are strict:

crucible-simulator owns the state and execution model. crucible-prover owns proving. crucible-scenarios owns scenario orchestration and adversarial testing.

This document describes the internal architecture of crucible-prover and the rules that keep it from becoming a dumping ground.

Repo layout at a glance

interfaces/        stable contracts shared by every crate and sibling repo
crates/
  proof-types/     versioned wire format (ProofEnvelope)
adapters/
  simulator/       simulator proof seam over the real prover (mock + real
                   UltraHonk proving)
  soroban/         on-chain verification payload path (up to the
                   deployed-contract boundary)
  (testnet)        future sibling-repo bridge
  witness/         private witness assembly, encoding, redaction
  artifacts/       pinned circuit artifacts + manifests (proving input)
  mock/            TEST-ONLY deterministic prover/verifier
  prover-core/     provider registry, dispatch, orchestration
  verifier/        verification dispatch + cross-verifier agreement
  noir/            nargo CLI adapter (compile/execute/info)
  ultrahonk/       UltraHonk provider/verifier + VK store + calldata encoding
schemas/           JSON Schema contracts for the wire formats
proofs/            committed proof-envelope fixtures (serialization pins)
benches/           in-process pipeline benchmarks (toolchain-free)
examples/          runnable end-to-end demos (mock backend)
scripts/           check.sh / test-all.sh, gates, and regeneration helpers
docs/              this and the other architecture docs
circuits/          Noir circuit workspace (shared lib, five ops, gadgets)
tests/             cross-crate security/invariant/live suites

adapters/ holds sibling-repo bridges. The simulator proof seam is implemented over the real UltraHonk backend (see docs/simulator-integration.md); the Soroban on-chain verification path is live — wire payload, verifier service registration, a real LiveSorobanClient targeting a deployed testnet verifier contract, and local + network-gated agreement tests (see docs/soroban-verification.md). The testnet bridge lands with its sibling workstream (see docs/testnet.md). The seams every adapter implements live in interfaces/, so no adapter imports another repository’s internals.

The canonical flow

Simulator State
      │
      ▼
Proof Request            interfaces::ProofRequest
      │
      ▼
Witness Construction     crucible-witness (private ↔ public split)
      │
      ▼
Circuit                  circuits/ (Noir workspace)
      │
      ▼
ACIR                     nargo compile (crucible-noir)
      │
      ▼
Prover Backend           ProofProvider impls (mock + UltraHonk/bb)
      │
      ▼
ZK Proof                 ProofResponse / ProofEnvelope
      │
      ▼
Public Inputs            bound to the response
      │
      ▼
Verification             crucible-verifier (local + on-chain agreement)

Layer rules

1. Clients depend on interfaces, never on backends

crucible-simulator and crucible-scenarios depend on crucible-interfaces only:

simulator / scenarios
      │  (ProofProvider / Prover traits)
      ▼
   interfaces
      ▲
      │
 mock · noir · ultrahonk

This is what lets the simulator tests stay fast (mock proofs), prover implementations evolve independently, and scenarios pick mock or real proofs per test depth.

2. The repository is not UltraHonk-specific

UltraHonk is the backend of the current Stellar Confidential Token implementation, but Crucible is the proof engine, not an UltraHonk shim. The ultrahonk crate contains only backend-specific knowledge — format tags, version compatibility, verification-key-id policy, calldata encoding — and plugs in through the same ProofProvider/Verifier traits the mock uses. RISC Zero/Groth16 or any future Stellar verifier architecture plugs in the same way.

3. The circuit/toolchain boundary is explicit

Noir is not “just another Rust crate”. nargo is its own toolchain: it compiles circuits/ into ACIR artifacts independently of Cargo, and crucible-noir is the only crate allowed to execute it. Proof generation and verification are not nargo’s job in current toolchains — they moved to the Barretenberg backend — so the ultrahonk crate consumes crucible-noir for witness solving and its own bb adapter for proving.

Compiled bytecode is pinned: every op’s artifact lives in artifacts/circuits/<op>/ next to a manifest declaring its SHA-256, and the provider proves only from that pinned root (layer rule 4).

4. Integrity before trust

Every compiled artifact is loaded through crucible-artifacts, which refuses to hand out bytes that do not match the artifact’s manifest byte-for-byte. Nothing is ever loaded partially, and no proof is ever accepted from an artifact that failed its checksum.

5. Verification round-trip is mandatory by default

ProverService::prove_and_verify refuses to return a proof that fails against its own response. crucible-verifier goes further: it can run the same proof through every verifier registered for a backend (local, on-chain) and report disagreement instead of assuming equivalence.

6. Privacy is structural

Private witness values cannot be formatted, logged, serialized, or embedded in errors by accident: SecretValue implements no Debug, Display, or Serialize. ProofRequest carries secrets and therefore has no Serialize; its only JSON form is the redacted view. Toolchain stderr is never echoed into errors because compiler diagnostics can contain source snippets with witness values.

What does NOT belong in this repo

  • a wallet, token contract, blockchain explorer, or transaction simulator
  • a compliance, audit, or policy engine
  • a general-purpose ZK framework or production key-management system
  • the entire OpenZeppelin Confidential Token implementation
  • large scenario catalogs, stress/adversarial/concurrency scenarios (those are crucible-scenarios’ job)

crucible-prover answers one question: can I construct and verify the proof for this state transition? crucible-scenarios answers: what happens when I execute hundreds of valid, invalid, adversarial, and pathological transitions?

Repository status

main carries the full proving pipeline: interfaces and wire types, witness and artifact management, the mock and UltraHonk backends with manifest-pinned artifacts, prover-core orchestration, the verification service (with cross-verifier agreement), the Noir circuits with cryptographic state binding, the cross-language vector catalog, committed proof fixtures, benchmarks, examples, and the crucible-prover CLI. Merkle membership for consumed commitments and the scenario layer’s live-network testnet adapter remain designed-but-unbuilt workstreams on top of these seams (see the roadmap docs). Soroban on-chain verification and the simulator adapter are built — the Soroban path is live against a deployed testnet contract (see the adapters section above and docs/deployment.md).