Beta Pre-1.0 — the file-naming convention may still change. v1.0 will freeze it. ZDDC home · All specifications

ZDDC - Custody Extension ~1.0
ZDDC Custody Extension ~1.0
Status: Draft

Status: DRAFT of 1.0 (~1.0) — published for review 2026-09-22 (the design was approved 2026-08-12). The Custody Extension is an optional extension to ZDDC Core: the on-disk formats that let anyone verify, offline and decades later, who issued a record, what exactly they issued, and what the other side acknowledged receiving. It specifies a signed transmittal manifest, a DSSE envelope profile, key files and trust anchors, the link statements parties exchange, and the conformance contract an implementation is tested against.

~1.0 uses ZDDC's own draft prefix: this is a draft of version 1.0, and its text and vectors may still change. Finalising drops the ~; the same address then holds 1.0, which is immutable — corrections after that are errata, never edits in place.

The documents themselves call this layer "custody v1"; that is this extension, version 1.0.

What conformance means here

If an implementation passes the vectors, it interoperates. That is the entire claim. There is no certification and no registry of approved implementations. An implementation declares the levels it meets (conformance.md §1) — they compose, and nothing requires all four:

  • V — Verifier. Checks envelopes, anchors and statements; returns a tri-state verdict with its as-of date.
  • P — Producer. Emits canonical payloads, manifests and key files.
  • H — Hasher. The chunked Merkle construction and inclusion proofs alone.
  • L — Ledger. Monotonic acceptance, ledger placement, currency derivation.

Everything specified here is producible and verifiable entirely client-side, with the Web Crypto API, over self-contained artifacts, with no network. That is a design constraint, not a convenience, and several requirements exist only to protect it.

Documents

File Contents
manifest.md The signed transmittal manifest: fields, chunked Merkle file hashing (zddc-merkle-v1), path encoding, canonicalization, limits, extensibility
envelope.md The DSSE envelope profile: payloadType registry, PAE, Ed25519, key identification, the numbered verification procedure
keys.md Key formats: instance/link keys, per-DC operational keys + key-certification, the two-key anchor in the registry row, rotation/expiry posture; the server record-signing key, the personal signing key and the WebAuthn credential
statements.md The seven link statement types + the two local types, record-revision and content-attestation: payload schemas, signing/countersigning, on-disk placement, the receipt and review-response flows
conformance.md The runner contract, the conformance levels, and what v1 deliberately does not do — each deferral with its hook named
vectors/ The executable half: README.md (conformance contract, reason classes, requirement traceability), gen.js (deterministic, zero-dependency generator), and 233 fixtures under merkle/ canonical/ envelope/ statements/ currency/ (plus keys.json and contexts.json)
corpora/ Third-party Ed25519 known-answer corpora, vendored verbatim with provenance, licence and pinned SHA-256: Project Wycheproof (151 cases) and ed25519-speccheck (12). Required by [M-R12] for the [M-E10] axes no ZDDC vector can express
decisions.md Non-normative appendix. The rationale log: every wire-level choice the design memo did not pin, and how each was reviewed and closed. Read it to understand why, never to learn what

The whole set — these sources, the vectors and the corpora — is published as one archive, zddc-custody-1.0.tar.gz, with its SHA-256 beside it.

Reading order and requirement ids

manifest.md → envelope.md → keys.md → statements.md → conformance.md. Normative requirements carry stable ids: [M-C*] canonical form, [M-M*] manifest/Merkle, [M-E*] envelope, [M-K*] keys, [M-S*] statements, [M-R*] the runner contract. The key words MUST, SHOULD and MAY are used as in RFC 2119.

vectors/README.md §5 maps every id to the vector(s) exercising it or to an explicit not-vector-testable note — 122 of 157 are vector-covered; the other 35 are listed with why not and what pins them instead. Those numbers are derived from the files by the reference implementation's test suite, which fails if a sentence and the tree disagree.

What is normative

The normative text is manifest.md, envelope.md, keys.md, statements.md, conformance.md and vectors/README.md, together with the vectors themselves. Where prose and a vector disagree, that is a defect in the specification — report it; do not pick one locally.

These specs were transcribed from ZDDC's internal design memo, docs/design/federation-and-custody.md. Citations of the form (memo §6.11) point into it; the addenda cite further design notes under docs/design/ the same way (record-signing.md, personal-signing.md, webauthn.md, transmittal-producer.md). None of these is published. They record where a rule came from; they are not part of the rule, and nothing here requires reading them. These documents are the contract, not the memo ([M-R11]).

Also non-normative: decisions.md; notes marked Repo note, RESOLVED or CLOSED, which record how a question was settled; and references to paths in the reference implementation's source tree (zddc/internal/custody/, shared/custody*.js, peer/key.go and the like), which point at one implementation's evidence, not at requirements.

Reference implementations

Two implementations were built independently from this prose, in different worlds: zddc-server in Go (the inbound door, the ledger reader, and since the addenda a producer of record-revision), and the .html tools in the browser, using Web Crypto from file:// (the producer and the offline verifier). Both pass the vectors. A behaviour diff then drove both through 4 424 mutation probes over the scope approved on 2026-08-12, with zero disagreements at that pass; every divergence found on the way is closed in decisions.md and carries a vector that would have caught it.

That result is evidence, not proof. One further divergence (decisions.md D-S13, in [M-S8]) surfaced on 2026-08-24, when the first real mid-thread statement was produced — no vector distinguished the two readings. It is closed, with vectors on both sides. The later addenda are carried by their own vectors. In the reference implementation's repository the suite runs as tests/custody-vectors.spec.js.

Both are reference implementations of these documents, never the definition of them. A third implementation that passes the vectors interoperates with both.

Changes since approval

  • Published as a draft for review (2026-09-22). [M-R11] inverted: these specs, not the design memo, are authoritative — an unpublished internal document cannot bind a third-party implementation. No other requirement, no vector and no wire byte changed. This preamble replaced the working-tree status page.
  • Addenda (2026-08-16/17). Additive; nothing approved earlier changed. The local record-revision statement (statements.md §11, keys.md §8, the server record-signing key); the content-attestation statement and the in-band carriage rule [M-S66] (statements.md §12, §8); the personal signing key (keys.md §9); and the WebAuthn credential and assertion profile (keys.md §10, envelope.md §8). Each section carries its own dated note.
  • The cross-implementation passes (from 2026-08-13). decisions.md D-23–D-25 and "Where the two implementations can still differ": two substantive decisions, [M-C10] and [M-C11] written, [M-E23] extended, two unsatisfiable vectors repaired. None changed a byte on the wire.

Reporting defects

Specification defects, vector disputes and extension proposals go to the issue tracker: https://codeberg.org/VARASYS/ZDDC. If your implementation disagrees with a vector, the vector may be what is wrong — two were, and were repaired. Report it rather than working around it locally; a private workaround is how two implementations quietly stop interoperating.

Rendered from “ZDDC Custody Extension ~1.0” ZDDC