The Proof Chain
Every registration produces one proof. These proofs form a chain of state transitions from genesis:
genesis_root (empty tree -- known constant)
|
+-- Proof 1: "alice" registered at block 100, txid abc...
| old_root = genesis_root --> new_root_1
|
+-- Proof 2: "bob" registered at block 105, txid def...
| old_root = new_root_1 --> new_root_2
|
+-- Proof 3: "carol" registered at block 110, txid 789...
old_root = new_root_2 --> new_root_3 (= current root)
Each proof's old_root must equal the previous proof's new_root. The first proof's old_root must equal the known genesis root (an empty Sparse Merkle Tree).
Verifying the Chain
A verifier checks the entire registration history in five steps:
- Get the SP1 verification key -- deterministically derived from the guest program binary
- Fetch all proofs from the API
- Verify each SP1 proof using the verification key
- Check the chain --
genesis == P1.old_root,P1.new_root == P2.old_root, ...,PN.new_root == current_root - Spot-check on-chain -- look up any committed
txidon a Zcash node and confirm the memo, value, and block match
If all checks pass, the entire registration history is correct -- no trust in the indexer needed.
Proof Pipeline
The scanner and prover run independently:
Zcash Blockchain
|
ZNS Scanner (validates, captures SMT state)
|
SQLite DB (status: "pending")
|
SP1 Prover (generates ZK proof, verifies it)
|
SQLite DB (status: "proved")
|
API Server (GET /v1/proof/{name})
The scanner never blocks on proof generation. The prover daemon polls for pending records and can run on separate hardware.