Wire format

Every DMP record fits one 255-byte DNS TXT string by design. No multi-string splitting needed in the common path — records are sized so the binary body plus signature plus base64 plus protocol prefix lands under 255 bytes.

  1. Chunks
  2. Slot manifests
  3. Identity records
    1. Hashed form (shared mesh domain)
    2. Zone-anchored form
  4. Prekeys
  5. Magic prefixes
  6. Related reading

Chunks

chunk-<NNNN>-<msg_key12>.<mesh_domain>   IN TXT  "v=dmp1;t=chunk;d=<b64>"
  • <NNNN> — zero-padded 4-digit chunk index.
  • <msg_key12> — first 12 hex chars of sha256(msg_id + recipient_id + sender_spk). Senders and recipients derive the same path without the recipient needing to know the sender’s X25519 pubkey up front.

Each chunk carries one erasure share plus per-chunk Reed-Solomon parity:

Bytes Meaning
8 SHA-256 prefix checksum over the decoded data block
128 Data block (DATA_PER_CHUNK)
32 Reed-Solomon parity (RS_SYMBOLS) over the data block

Recipient: RS-decode first, then verify checksum. RS repairs up to 16 byte-errors per chunk inside the received data.

Slot manifests

slot-<N>.mb-<recipient_hash12>.<mesh_domain>
    IN TXT  "v=dmp1;t=manifest;d=<b64(body || sig)>"
  • <N> ∈ 0..9 — there are 10 slots per recipient.
  • <recipient_hash12>sha256(recipient_user_id)[:12]. Recipient’s user_id is itself sha256(recipient_x25519_pub).

Binary body = 108 bytes:

Offset Size Field Notes
0 16 msg_id UUIDv4 bytes
16 32 sender_spk Ed25519 signing pubkey
48 32 recipient_id sha256(recipient_x25519_pub)
80 4 total_chunks n; capped at MAX_TOTAL_CHUNKS = 1024
84 4 data_chunks k; erasure threshold
88 4 prekey_id 0 = long-term X25519 key (no FS)
92 8 ts Unix seconds — publication time
100 8 exp Unix seconds — drop after

Followed by a 64-byte Ed25519 signature over body. Total wire: 108 + 64 = 172 bytes → 232 base64 chars → 252 total prefix+b64.

Append semantics — mailbox slots hold multiple manifests at once; the receive path iterates all of them at each slot.

Identity records

Hashed form (shared mesh domain)

id-<sha256(username)[:16]>.<mesh_domain>
    IN TXT  "v=dmp1;t=identity;d=<b64(body || sig)>"

Zone-anchored form

dmp.<identity_domain>
    IN TXT  "v=dmp1;t=identity;d=<b64(body || sig)>"

Body (variable length, capped):

Field Size Required
username_len 1 byte yes
username up to 64 utf-8 bytes yes
x25519_pk 32 bytes yes
ed25519_spk 32 bytes yes
ts 8 bytes yes
versions_len 1 byte optional (see below)
versions versions_len × 1 byte optional

The optional versions suffix advertises the protocol versions the publishing client supports as a receiver. Each byte is a single protocol version number; the writer sorts and deduplicates them so the encoding is deterministic.

Compatibility rules:

  • Suffix absent ⇒ treat as versions = [1]. Records published before this field existed continue to parse and are correctly interpreted as v1-only. A new client that publishes versions = [1] MUST also omit the suffix entirely so the bytes are bit-identical to the pre-versions historical form (preserves cached body hashes).
  • Suffix presentversions_len ≥ 1 and the encoded list MUST be sorted and unique. Non-canonical encodings reject.

Senders consult the recipient’s versions field before emitting any wire feature beyond v1 (e.g. the DMPv2 plaintext envelope below). If a recipient hasn’t published v2 yet, the sender stays on v1 — automatic, safe rollout without a config flag.

Publishing v2 capability: the CLI defaults to publishing v1-only identity records so pre-this-release clients can still parse them (their strict length check rejects any trailing suffix). To opt in once your peers have updated, run:

dnsmesh identity publish --advertise-v2
dnsmesh identity rotate --advertise-v2 [...]

Once a peer’s record advertises v2, every upgraded sender starts emitting the DMPv2 envelope to them, populating a verified sender_label on first-contact messages.

Signed by the identity’s Ed25519 key. The fetcher verifies the signature against the embedded ed25519_spk (the record is self-authenticating).

In zone-anchored form the fetcher also requires record.username == address.user so a zone owner can’t publish a body naming someone else under their zone.

Prekeys

prekeys.id-<sha256(username)[:12]>.<mesh_domain>
    IN TXT  "v=dmp1;t=prekey;d=<b64(body || sig)>" (one RRset, many values)

Body = 44 bytes:

Offset Size Field
0 4 prekey_id
4 32 x25519_pub
36 8 exp

Followed by the 64-byte Ed25519 signature. Total wire: 108 + prefix = 162 chars.

Many prekey records share the same DNS name (RRset semantics); the sender gets all of them in one query and picks a random verified one.

Magic prefixes

Every DMP TXT value starts with v=dmp1;t=<type>; so a DMP-aware resolver can filter on prefix. Types seen on the wire:

t= Meaning
chunk Erasure share of an encrypted message
manifest Signed slot manifest
identity Signed identity record
prekey Signed one-time prekey

See Spec overview for the full registry including cluster and bootstrap, and Wire encoding conventions for the cross-record prefix / base64 / signature rules.

  • Spec overview — cross-cutting invariants every record on this page respects.
  • DNS name routing — owner-name helpers for chunks, manifests, identities, and prekeys.
  • End-to-end flows — how these records are produced and consumed during send / receive / identity publish.
  • Threat model — what the signatures on these records defend against, and what they don’t.
  • Cluster manifest and Bootstrap record — the two signed-record types introduced in M2 + M3 that live alongside the records on this page.