Scope
This issue scopes the network-topology gap between the current node and the Shielded CSV peer-to-peer model described in eprint 2025/068 and the original zkCoins gist.
It is orthogonal to SPEC.md §15 (D1–D11), which catalogues circuit/protocol divergences. The items below are about how the network is wired: who talks to whom, who holds what state, who can step in if one party disappears. Even with every D-item resolved, the architectural gaps below would remain.
This is a problem inventory only — no solutions are proposed here. Each item is a tracking placeholder for future design discussion.
What Bitcoin actually coordinates today
Exactly one subsystem is reconstructible from the chain alone, by anyone, without trust:
- The nullifier accumulator (SMT + MMR over the 64-byte commitments published as Taproot inscriptions with the
4242 marker prefix).
That is the entire on-chain coordination surface. It is sufficient for double-spend prevention and nothing else.
What Bitcoin does not coordinate (the gaps)
Every other piece of state lives in the node's Postgres and has no on-chain anchor or off-chain gossip path. Concretely:
| State |
Where it lives |
Reconstructible from chain? |
| Per-account balance |
accounts table (BYTEA bincode) |
No |
| Coin proofs |
Server filesystem, addressed by proof_id |
No |
| Username → address mapping |
usernames table |
No |
num_sends (BIP-32 key-rotation counter) |
Per-account column |
No |
| Mint authority |
Single PUBLISHER_KEY / MINTING_ADDRESS env vars |
No |
| Pending inscription state |
pending_inscriptions table |
No |
Problem inventory
P1 — Coin + proof transport is implicit and server-mediated
The paper specifies that (coin, coin_proof) is delivered directly from sender to receiver, off-chain. Today, this delivery is implicit: the sender POSTs to /api/send, the server stores the proof under a proof_id, and the same server later credits the recipient's account. There is no peer-to-peer transport — no gossip layer, no mailbox, no relay — and no out-of-band channel a sender could fall back to. If the node is unavailable, the payment cannot move, even if both parties have full Bitcoin chain access.
P2 — Receiver does not perform client-side validation
The defining property of CSV ("the receiver validates the coin proof; the chain does not") is not implemented end-to-end. The server validates the inputs to /api/send, generates the proof, updates its state, and the thin client trusts the resulting balance / num_sends response. No PCD verification runs on the receiver's device. The client has no independent way to detect a malicious or buggy server.
P3 — Proof generation is bound to a single operator's hardware
The Plonky2 prover runs server-side (3–15 min per /api/send on M3 Ultra). A user's ability to transact depends on:
- that the server is online,
- that the server accepts their request (no censorship),
- that the server has not lost or rolled back the prerequisite account state.
There is no path for a user to switch provers, run their own prover, or use a different operator for the same account.
P4 — Account state is non-portable across nodes
accounts, the SMT subtree for an address, the MMR snapshot used for the user's last send, and the cached coin proofs that back the user's balance all live in one server's Postgres. A second independent node, syncing from the same Bitcoin chain, would reconstruct an identical nullifier accumulator but a disjoint account universe. There is no protocol-level export, handoff, or reconciliation path. Two nodes would be two islands sharing only the double-spend register.
P5 — Username registry is server-local and non-portable
/api/username/claim and /api/username/resolve/:username operate against the usernames Postgres table. There is no on-chain commitment, no DNS/Nostr/LNURL anchor, and no cross-node namespace coordination. A username claimed on node A does not exist on node B, and there is no way to migrate or prove ownership of a name when changing operators.
P6 — Mint authority is a single off-chain key
MINTING_ADDRESS and the publisher's signing key are held by the operator. There is no bridge from native BTC (BitVM, one-way peg, federation, or otherwise), so all supply on the running networks is privileged-issued. This is acceptable for the closed testnet, but it means the system has no trust-minimised entry point for value today.
P7 — Publisher monoculture in practice
Code-wise the publisher role is permissionless: any operator running this binary can post nullifiers to Bitcoin. In practice, exactly one publisher exists (api.zkcoins.app). There is no nullifier-gossip layer between potential publishers, no fee market, no fallback if the single publisher stalls, and no protocol mechanism for a user to switch publishers mid-flight.
P8 — Reorg state ownership
The Conditional NAV mechanism described in the paper (and tracked separately as SPEC §15 D7) protects against orphaned-nullifier scenarios. Even with D7 closed inside the circuit, the state ownership question remains a network problem: today the server holds the canonical reorg-resolved view, and clients have no independent way to detect when the server's reorg handling has gone wrong.
P9 — Operator plaintext visibility (network-layer consequence)
Because P3 (server-side prover) and P2 (no client-side verify) hold, every /api/send request reaches the server as plaintext: sender address, recipient address, amount, signature. The request_log and event_log tables capture this in Postgres. Even with the cryptographic privacy goals (D2/D10) closed at the on-chain layer, the operator's visibility into off-chain traffic is a structural consequence of the current topology, not of the circuit.
P10 — Read endpoints expose state without authentication
/api/balance?address= and /api/username/resolve/:username are unauthenticated. The 256-bit address is simultaneously the receive address and the viewing capability for balance + num_sends. Combined with the public username-resolve path, username → address → balance + activity counter is a two-call public lookup. This is a network-layer privacy question (who can ask what) distinct from the on-chain privacy items in §15.
Out of scope for this issue
- Specific designs, implementations, or migration paths for any of P1–P10.
- The cryptographic divergences already tracked in SPEC.md §15 (D1–D11).
- Anything inside the circuit (
program-plonky2) or the prover host (script-plonky2).
References
Scope
This issue scopes the network-topology gap between the current node and the Shielded CSV peer-to-peer model described in eprint 2025/068 and the original zkCoins gist.
It is orthogonal to
SPEC.md§15 (D1–D11), which catalogues circuit/protocol divergences. The items below are about how the network is wired: who talks to whom, who holds what state, who can step in if one party disappears. Even with every D-item resolved, the architectural gaps below would remain.This is a problem inventory only — no solutions are proposed here. Each item is a tracking placeholder for future design discussion.
What Bitcoin actually coordinates today
Exactly one subsystem is reconstructible from the chain alone, by anyone, without trust:
4242marker prefix).That is the entire on-chain coordination surface. It is sufficient for double-spend prevention and nothing else.
What Bitcoin does not coordinate (the gaps)
Every other piece of state lives in the node's Postgres and has no on-chain anchor or off-chain gossip path. Concretely:
accountstable (BYTEA bincode)proof_idusernamestablenum_sends(BIP-32 key-rotation counter)PUBLISHER_KEY/MINTING_ADDRESSenv varspending_inscriptionstableProblem inventory
P1 — Coin + proof transport is implicit and server-mediated
The paper specifies that
(coin, coin_proof)is delivered directly from sender to receiver, off-chain. Today, this delivery is implicit: the sender POSTs to/api/send, the server stores the proof under aproof_id, and the same server later credits the recipient's account. There is no peer-to-peer transport — no gossip layer, no mailbox, no relay — and no out-of-band channel a sender could fall back to. If the node is unavailable, the payment cannot move, even if both parties have full Bitcoin chain access.P2 — Receiver does not perform client-side validation
The defining property of CSV ("the receiver validates the coin proof; the chain does not") is not implemented end-to-end. The server validates the inputs to
/api/send, generates the proof, updates its state, and the thin client trusts the resultingbalance/num_sendsresponse. No PCD verification runs on the receiver's device. The client has no independent way to detect a malicious or buggy server.P3 — Proof generation is bound to a single operator's hardware
The Plonky2 prover runs server-side (3–15 min per
/api/sendon M3 Ultra). A user's ability to transact depends on:There is no path for a user to switch provers, run their own prover, or use a different operator for the same account.
P4 — Account state is non-portable across nodes
accounts, the SMT subtree for an address, the MMR snapshot used for the user's last send, and the cached coin proofs that back the user's balance all live in one server's Postgres. A second independent node, syncing from the same Bitcoin chain, would reconstruct an identical nullifier accumulator but a disjoint account universe. There is no protocol-level export, handoff, or reconciliation path. Two nodes would be two islands sharing only the double-spend register.P5 — Username registry is server-local and non-portable
/api/username/claimand/api/username/resolve/:usernameoperate against theusernamesPostgres table. There is no on-chain commitment, no DNS/Nostr/LNURL anchor, and no cross-node namespace coordination. A username claimed on node A does not exist on node B, and there is no way to migrate or prove ownership of a name when changing operators.P6 — Mint authority is a single off-chain key
MINTING_ADDRESSand the publisher's signing key are held by the operator. There is no bridge from native BTC (BitVM, one-way peg, federation, or otherwise), so all supply on the running networks is privileged-issued. This is acceptable for the closed testnet, but it means the system has no trust-minimised entry point for value today.P7 — Publisher monoculture in practice
Code-wise the publisher role is permissionless: any operator running this binary can post nullifiers to Bitcoin. In practice, exactly one publisher exists (
api.zkcoins.app). There is no nullifier-gossip layer between potential publishers, no fee market, no fallback if the single publisher stalls, and no protocol mechanism for a user to switch publishers mid-flight.P8 — Reorg state ownership
The
Conditional NAVmechanism described in the paper (and tracked separately as SPEC §15 D7) protects against orphaned-nullifier scenarios. Even with D7 closed inside the circuit, the state ownership question remains a network problem: today the server holds the canonical reorg-resolved view, and clients have no independent way to detect when the server's reorg handling has gone wrong.P9 — Operator plaintext visibility (network-layer consequence)
Because P3 (server-side prover) and P2 (no client-side verify) hold, every
/api/sendrequest reaches the server as plaintext: sender address, recipient address, amount, signature. Therequest_logandevent_logtables capture this in Postgres. Even with the cryptographic privacy goals (D2/D10) closed at the on-chain layer, the operator's visibility into off-chain traffic is a structural consequence of the current topology, not of the circuit.P10 — Read endpoints expose state without authentication
/api/balance?address=and/api/username/resolve/:usernameare unauthenticated. The 256-bit address is simultaneously the receive address and the viewing capability forbalance+num_sends. Combined with the public username-resolve path,username → address → balance + activity counteris a two-call public lookup. This is a network-layer privacy question (who can ask what) distinct from the on-chain privacy items in §15.Out of scope for this issue
program-plonky2) or the prover host (script-plonky2).References
SPEC.md§15,MIGRATION_RESEARCH.md§3