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

Threat Model

An adversarial description of what crucible-prover must resist. Each entry names the adversary, the attack, and the defense that already exists or is planned. The security test suite (tests/security/) maps one-to-one onto the rows below.

Assets

AssetSensitivityWhere it lives
Private witness valuesHIGH — the privacy boundary itselfin-memory only, Prover.toml during proving
Verification keysHIGH — forge proofs if leakedartifact store, verified by checksum
Proving keys / secret backend materialCRITICAL — forge proofs if leakedbackend infrastructure, never in this repo
Compiled circuit artifactsMEDIUM — must be authentic, not secretartifacts/, integrity-checked
ProofsLOW per-proof, but must be authentic & context-boundenvelopes, stored/exchanged
Public inputs / state rootsPUBLICeverywhere, by design

Adversaries

A1. The curious bystander (privacy)

Goal: learn a private balance, amount, or opening from observable data.

Attack surface: logs, error messages, debug output, CI artifacts, transcripts, panics, serialized requests, git history.

Defenses: structural non-leakability (no Debug/Display/Serialize on secrets); redacted ProofRequest JSON; redacted transcripts; nargo stderr never echoed; .gitignore excludes generated witness/proof files; leakage tests scan everything for fixture secret values.

Status: enforced today. Test: tests/security/witness_leakage.rs.

A2. The forger (proof soundness)

Goal: produce a proof that verifies for a state transition that did not happen, or for a context it does not commit to.

Attack: forge bytes, reuse a proof against different state/outputs/key.

Defenses: real backends provide cryptographic soundness (mock does not, by design — it is TEST ONLY); context binding is checked field-by-field at verification; prove_and_verify round-trips every proof it returns.

Status: enforced today — cryptographic soundness via the Barretenberg adapter (UltraHonkProvider/UltraHonkVerifier), with the mock exercising the same rejection paths in CI. Tests: tests/tests/real_backend.rs, tests/tests/ultrahonk.rs, tests/security/proof_malleability.rs.

A3. The replayer / stale-state submitter

Goal: submit a previously valid proof after the state it applies to has moved on.

Attack: capture a valid proof for state root A; submit it when the account state is at root B.

Defense: state-bound operations (merge, transfer, withdraw) require a StateReference; verification compares the submitted reference against the proof’s binding and rejects with StateReferenceMismatch / MissingStateBinding.

Status: enforced today. Tests: tests/security/replay.rs, tests/security/stale_state.rs, tests/proofs/replay.rs.

A4. The artifact swapper (integrity)

Goal: make the system prove or verify with a modified circuit, or leak a verification key by convincing the loader to read outside the artifact root.

Attack: replace artifact bytes and/or its manifest; plant an extra file; craft a manifest whose paths escape the artifact directory.

Defense: crucible-artifacts verifies every file against its manifest before any content is returned, rejects undeclared files in strict mode, and validates paths against traversal; manifests carry their own checksum pinnable outside the artifact directory. The UltraHonk provider proves only from a pinned artifact root (artifacts/circuits/<op>/): it strict-loads the artifact through that loader before a single byte is touched, so swapped or tampered bytecode fails with ArtifactIntegrity/ArtifactUnavailable before any witness is solved or bb runs. A circuits-source change that forgets to re-pin its artifact fails CI (fresh compile must match the committed bytes byte-for-byte).

Status: enforced today — pinned artifacts committed for all five ops, verified by crucible-prover artifacts check. Tests: tests/security/artifact_tampering.rs and the live tests/tests/artifacts.rs (byte-flip, missing manifest/bytecode, and planted-file attacks against a copy of the pinned artifact).

A5. The misattribute (circuit/key confusion)

Goal: pass off a proof for circuit A (or version 1.0) as a proof for circuit B (or version 2.0), or under a different verification key.

Defense: proofs bind circuit, circuit version, backend, verification key id, and artifact checksum; verification checks each field and rejects with the specific reason.

Status: enforced today. Tests: tests/security/wrong_context.rs, tests/security/key_mismatch.rs, tests/verification/wrong_key.rs, tests/verification/wrong_public_inputs.rs.

A6. The toolchain saboteur

Goal: make compilation or proving fail in a way that leaks witness values through diagnostics, or make the system silently use an incompatible toolchain.

Defense: crucible-noir never echoes nargo stderr into errors; the toolchain adapter checks the nargo version against the supported major before running; crucible-ultrahonk gates the bb major version and CI installs the exact (nargo, bb) pair pinned in the compatibility matrix (noirup -v 1.0.0-beta.26 + bbup -v 6.0.0-nightly.20260903) — the same versions that generated the committed pinned artifacts.

Status: enforced — nargo and bb toolchains are both gated, and the live proving suite in tests/tests/ultrahonk.rs exercises the validated pairing on every CI run.

A7. The environment attacker (unsafe code)

Goal: exploit memory unsafety in witness/key handling.

Defense: unsafe_code = "forbid" workspace-wide. All handling is safe Rust.

Status: enforced today (workspace lint).

Out of scope (deliberately)

  • Side-channel resistance of real proving hardware/software (backend concern, addressed with the Barretenberg adapter).
  • Consensus/chain security (the ledger’s concern, not the prover’s).
  • Production key management (a different system; this repo never holds proving keys).