Accounting and audit
audience: operators
Anonymous broadcast looks, from the outside, uncomfortably like a
thing you cannot account for. Auditors will ask. This page tells
you what you can attest to, what you cannot, and how to produce
evidence for each. Everything here is scoped to a single zipnet
instance — multiple instances on the same universe are separately
audited against their own committee roster and Broadcasts
collection.
What the protocol is designed to guarantee
- Given at least one honest committee server, no party — not the operator, not the aggregator, not the remaining committee members, not an outside observer of the network — can determine which client authored which published broadcast.
- Given all parties operating the protocol honestly, every
broadcast in the
Broadcastslog is the XOR-sum of the messages of the clients listed in that round’sparticipantsfield, subject to slot collisions. - Committed broadcasts are signed-in-transit by every bonded pair and logically signed by the Raft leader at commit time. Replays are detectable.
What the protocol is not designed to guarantee
- Who an individual
ClientIdrefers to. A client’sClientIdis a hash of its X25519 public key, not a legal identity. You will need an out-of-band registration process if you want to tie aClientIdto a legal entity. - That a broadcast is well-formed. A malicious client can put garbage in its slot. The falsification tag protects honest clients from other clients corrupting their slot, but not from a client corrupting its own slot.
- Censorship-resistance. A malicious aggregator or a majority of malicious committee servers can delay or drop rounds. Anonymity still holds; availability does not.
What you can attest to
“Did this instance publish this broadcast on this date?”
Every entry in the instance’s Broadcasts collection carries:
round: RoundIdparticipants: Vec<ClientId>— snapshot of the active clients at round-open timeservers: Vec<ServerId>— committee members that contributed partialsbroadcast: Vec<u8>— the final XORed vector
Together with the Raft commit index, this is a point-in-time claim
signed (through the bond layer) by every committee server. Archive
the Broadcasts entries you care about, keyed by instance name —
there is no authoritative external registry.
“Who was running which node on this date?”
This is an organizational fact, not a cryptographic one. Maintain an external table per instance:
| Instance | PeerId | Legal entity | Role | Valid from | Valid to |
|---|---|---|---|---|---|
acme.mainnet | f5e28a… | Acme Corp | committee-server-1 | 2026-03-01 | present |
acme.mainnet | 4c210e… | Acme Corp | aggregator | 2026-03-01 | present |
acme.preview | a91742… | Acme Corp | committee-server-1 | 2026-04-02 | present |
Sign this table with your corporate root, version it, and include
it in your audit package. PeerId is stable when ZIPNET_SECRET
is stable; rotate only via a documented procedure (see
Rotations and upgrades).
“Was a specific server in the committee on this round?”
BroadcastRecord::servers lists every committee member whose
partial unblind was folded into the published broadcast. Combine
with your PeerId → legal entity table to produce a legal-readable
statement.
“Did this committee server operate honestly?”
You cannot prove this from the record alone — a malicious committee member can behave indistinguishably from an honest one, provided at least one other committee member is honest. (That’s the whole point of the any-trust model.) What you can attest to:
- The server was up and participating (its partial is folded in).
- The server’s key material was controlled by the claimed legal
entity (via the
PeerEntrysignature). - For TDX-gated instances, the server’s boot measurement matched the committee’s pinned MR_TD. Archive the quote alongside the instance deployment record (see below).
In regulatory settings where “operated honestly” must be proven positively, a TDX attestation is as close as the protocol gets — the quote cryptographically proves the code running inside the committee server matches a published image hash.
Archival recommendations
-
Archive
Broadcastscontinuously, per instance. A committee server’s in-memory copy is the source of truth in v1; if the majority of the committee goes offline at once, the log is gone. Mirror the log into durable storage at your cadence of choice. A minimal script: open aZipnet::<D>::read(&network, &CONFIG)handle from a non-committee host, iterate values newer than your checkpoint, append to a signed ledger, commit. -
Archive the
PeerIdtable, keyed by instance. Version it; keep change history. A SHA-256 of this table goes into your audit manifest. -
Archive the instance configuration. For each instance:
- Instance name.
ZIPNET_COMMITTEE_SECRET’s blake3 fingerprint (not the raw secret).RoundParams.ConsensusConfig.- Committee roster.
- Committee MR_TD (if TDX-gated).
-
Archive TDX attestation quotes. For TDX-gated instances, each committee server’s quote includes its MR_TD and RTMRs. Store them per instance, per deploy.
Evidence package for external audit
A minimal per-quarter package, per instance:
- Instance name and its universe
NetworkId. Broadcastslog excerpt for the quarter (signed by your corporate root).PeerId → legal entitytable for that instance (signed, version-pinned).- Instance configuration fingerprint: SHA-256 of
blake3(COMMITTEE_SECRET) || blake3(ROUND_PARAMS) || blake3(CONSENSUS_CONFIG) || instance_name. - Committee MR_TD (TDX-gated instances).
- List of committee membership changes, cross-referenced to git/CD deployment records.
- Incident log covering any stuck rounds, split-brain events, or membership changes in the period.
An auditor can re-derive ClientIds referenced in participants
from the corresponding signed PeerEntry tickets archived from
gossip — useful if they want to ask “was client X part of round Y”.
Multiple instances, shared universe
Because zipnet instances share a universe, an auditor who reads your raw gossip logs will see traffic that belongs to other instances — and possibly to other mosaik services entirely. Two consequences to call out in your audit narrative:
- Gossip-level traffic volume from your fleet is not a proxy for
your instance’s traffic. A committee server on
acme.mainnetroutinely forwards discovery messages on behalf of other instances and services on the same universe. - Peer-catalog size is likewise a universe-level quantity. Do not attempt to derive per-instance population from catalog counts.
For per-instance accounting, stick to the Broadcasts collection
and the ServerRegistry / ClientRegistry contents read through
the Zipnet::<D>::read / receipts handles for each Config.
Privacy and data retention
Published broadcasts are, by design, readable by anyone who can read
the Broadcasts collection. Treat them as public data. Archival
retention policy is a business decision; the protocol neither
enforces nor contradicts any specific retention period.
Signed PeerEntrys (carrying peers’ ClientBundles / ServerBundles)
are also public by design — they are gossiped to every universe
member. There is no way to revoke a signed entry retroactively.
Security warning
Do not publish
ZIPNET_COMMITTEE_SECRETor any committee server’s X25519 secret, historic or current. Disclosure of any committee server’s DH secret, combined with disclosure of any other committee server’s DH secret, breaks anonymity of every round in which both nodes participated.
See also
- Security posture checklist — what must be protected, per role.
- Rotations and upgrades — change procedures that your audit log must cross-reference.