ZK proofs
Proving a BAMFS root resolves to a given IPFS CID, with no trusted relayer. Designed and tested, not shipped.
Not shipped. The circuit, prover and verifier exist and are covered by tests, but no verifier is deployed in production and no proof has been submitted outside development. Treat this page as a design record.
The claim being proved:
The BAMFS root
0xDEAD…BEEFon chain A — directory or single file — resolves to IPFS CIDbafy…rkdi, and here is a proof of that fact.
Anyone who runs the prover can submit one to IpfsCidVerifier on a destination
chain. On success it records (rootCid, ipfsCid, sourceChainId, prover, verifiedAt), so contracts elsewhere can rely on the binding without trusting a
bridge operator.
Flow
source chain A off-chain destination chain B
┌───────────────┐ ┌──────────────────┐ ┌────────────────────┐
│ ContentStore │ │ RISC Zero guest │ │ IpfsCidVerifier │
│ FileStore │ ─────▶ │ verify BAMFS CID│ ─────▶ │ .verifyAndStore() │
│ DirectoryStore│ input │ decompress │ seal │ └─ IZkVerifier │
└───────────────┘ │ re-derive IPFS │ journal└────────────────────┘
└──────────────────┘The guest reads the stored chunks, verifies they hash to the claimed BAMFS root,
decompresses them, and re-derives the IPFS CID from the logical bytes. It commits
(rootCid, sourceChainId, ipfsCid) to the journal.
The journal is the only trusted boundary. The verifier returns it, and
IpfsCidVerifier ABI-decodes it and asserts every field matches the call
arguments before storing anything. A prover that lies about any of the three
produces a journal that fails that check.
Prover backends
@bamfs/zk-prover ships four, selected with --backend:
| Backend | Use |
|---|---|
docker | The real proof, in a pinned image. The reproducible default. |
local | The real proof against a local Rust toolchain. Fast to iterate on. |
http | Delegate to a remote proving service. |
mock | No ZK at all — pairs with MockVerifier on a dev chain. |
bamfs prove-and-submit <rootCid> --backend mockThe image ID pins the guest
The on-chain verifier stores the image ID of the guest it accepts — a hash of the compiled circuit. Change the guest and the image ID changes, and old proofs stop verifying.
This is why packages/zk-circuit pins its Rust toolchain: the toolchain version
is an input to the compiled circuit, so bumping it silently invalidates every
proof already on chain. The host toolchain can move freely; the guest's cannot.
