DFOS Protocol Architecture

v0.1.0 · Verifiable identity · Dark forest content · Public proofs

Protocol Layers

Public proof substrate Controller's choice Dark forest content
L0 · Crypto
Ed25519 signatures, dag-cbor encoding, CIDv1 content addressing, JWS envelopes. The trust boundary. Everything above this is cryptographically verified. Self-certifying — no external authority needed. All verifiers check typ headers for defense in depth.
Ed25519 dag-cbor CIDv1 JWS
L1 · Identity
Self-sovereign identity chains. Append-only logs of key management operations. DID derived from genesis CID hash. Create, rotate keys, delete. The chain defines its own valid signers via controller keys. typ: did:dfos:identity-op
did:dfos:* identity-op create update delete
L2 · Content
Externally signed content chains. Append-only logs of document commitments. Each operation includes did (author DID, committed to by CID) and commits to a documentCID. The baseDocumentCID tracks document edit lineage. The protocol sees hashes, not content. typ: did:dfos:content-op
contentId content-op did documentCID baseDocumentCID
L3 · Beacon
Signed merkle root announcements. Floating artifacts declaring the DID's current content set. Pure SHA-256 binary Merkle tree over sorted contentIds — the root is a 64-char hex hash that reveals nothing about what's inside. Not chained — latest createdAt wins. 5-minute future clock skew tolerance. typ: did:dfos:beacon
beacon merkleRoot SHA-256
L3.5 · Witness
Countersignatures — third-party attestation. Same CID, different signer. Works for both content operations and beacons. The kid DID in the JWS header tells you who signed. When it matches payload did = author. When it differs = witness. No ambiguity from a single JWS alone.
countersign kid !== did witness
L4 · Structure
Merkle tree data — the content set. The sorted binary tree behind the beacon root. A set of contentIds — no values, just membership. Controller decides whether to share: root only, root + inclusion proofs, or full tree. Enables enumeration and verification.
sorted tree inclusion proofs set membership
L5 · Documents
Dark forest content. The actual payloads behind documentCIDs. Posts, profiles, manifests, attestations — all flat content objects with a $schema. Content-addressed directly: CID(dagCborCanonicalEncode(contentObject)). Authorized access only. The protocol proves they exist without revealing what they say.
post/v1 profile/v1 manifest/v1

Four Protocol Components

Component Concern JWS typ
Crypto core Identity chains + content chains — Ed25519 signatures, JWS tokens, CID links identity-op content-op
Beacons Signed merkle root announcements — periodic commitment over content sets beacon
Countersignatures Witness attestation — third-party signatures over operations and beacons content-op beacon
Merkle trees SHA-256 binary trees over content IDs — inclusion proofs for beacon roots n/a (pure SHA-256)

Disclosure Gradient

The DID controller decides how much to reveal. Each level exposes more without requiring the next.

Root hash
Always public
Merkle tree
Controller's choice
Manifest index
Authorized access
Document content
Dark forest

An observer at the leftmost level sees: a hash changed. At the second level: which contentIds exist. At the third: what they mean semantically. At the fourth: what they actually say. Each level requires increasing trust or authorization.

Signed Artifacts

Identity Operation
// JWS header
{ "alg": "EdDSA",
  "typ": "did:dfos:identity-op",
  "kid": "did:dfos:...#key_...",
  "cid": "bafyrei..." }

// payload (create)
{ "version": 1,
  "type": "create",
  "authKeys": [MultikeyPublicKey[]],
  "assertKeys": [MultikeyPublicKey[]],
  "controllerKeys": [MultikeyPublicKey[]],
  "createdAt": "2026-03-07T..." }
Content Operation
// JWS header
{ "alg": "EdDSA",
  "typ": "did:dfos:content-op",
  "kid": "did:dfos:...#key_...",
  "cid": "bafyrei..." }

// payload (create) — did committed to by CID
{ "version": 1,
  "type": "create",
  "did": "did:dfos:abc123",
  "documentCID": "bafyrei...",
  "baseDocumentCID": null,
  "createdAt": "2026-03-07T...",
  "note": null }
Beacon (Root Announcement)
// JWS header
{ "alg": "EdDSA",
  "typ": "did:dfos:beacon",
  "kid": "did:dfos:...#key_...",
  "cid": "bafyrei..." }

// payload — floating, no backlink
{ "version": 1,
  "type": "beacon",
  "did": "did:dfos:abc123",
  "merkleRoot": "7e80d478...28e",
  "createdAt": "2026-03-07T..." }

merkleRoot is hex SHA-256 (64 chars), not a CID. Signed by controller key. Latest createdAt supersedes. 5-min future clock skew tolerance.

Countersignature (Witness)
// content operation countersign
{ "typ": "did:dfos:content-op",
  "kid": "did:dfos:witness...#key_...",
  "cid": "bafyrei..." }
// same payload → same CID, different signer

// beacon countersign
{ "typ": "did:dfos:beacon",
  "kid": "did:dfos:witness...#key_...",
  "cid": "bafyrei..." }
// same beacon payload → same CID

Works for both content operations and beacons. Same typ as the original. Discrimination: kid DID vs payload did.

Author vs Witness — the did rule

Every content operation and beacon payload includes a did field committed to by the CID. Any JWS token for that CID is self-describing:

kid DID === payload.did  →  Author / Controller
kid DID !== payload.did  →  Countersignature (witness)

Decode, compare, done. No chain context needed. Works identically for content ops and beacons.

typ header discrimination

did:dfos:identity-op — identity chain operations
did:dfos:content-op — content chain ops + countersigns
did:dfos:beacon — beacon announcements + countersigns
JWT — device auth tokens (no CID)

All verifiers validate typ. Defense in depth — Zod schema discrimination is the primary safety net.

Document — Post (dark forest)
// flat content object, committed to by CID
{ "$schema": "https://schemas.dfos.com/post/v1",
  "format": "short-post",
  "createdByDID": "did:dfos:...",
  "title": "Hello World",
  "body": "First post on the protocol." }
Document — Manifest (dark forest)
// semantic index — the navigation layer
{ "$schema": "https://schemas.dfos.com/manifest/v1",
  "entries": {
    "profile": "67t27rzc83v7c22n9t6z7c",
    "posts": "a4b8c2d3e5f6g7h8i9j0k1",
    "dark-publisher": "did:dfos:proxy_xyz"
  } }

Points to contentIds, DIDs, other manifests. The semantic graph is dark forest content — invisible without authorization.

Merkle Tree Construction

Pure SHA-256 binary tree over content identifiers. No dag-cbor, no CIDs. The tree is a commitment scheme, not content-addressed data.

ROOT
SHA-256(H(ab) || H(cd,e))
↓↓
H(ab)
SHA-256(a || b)
H(cd,e)
SHA-256(H(cd) || e)
↓↓↓↓
alpha
bravo
H(cd)
echo ↑
↓↓
charlie
delta
1
Deduplicate + sort contentIds lexicographically (UTF-8 byte order)
2
Hash leaves: for each contentId, SHA-256(UTF-8(contentId)) → 32-byte leaf hash
3
Build tree: pair adjacent hashes, SHA-256(left || right) → 32 bytes. Odd nodes promoted unpaired.
4
Root: final 32-byte hash, hex-encoded → 64-char lowercase hex string. Empty set → null (no beacon needed).

Inclusion proofs: sibling hashes along the path from leaf to root, plus direction (left/right) for each step. Verifier recomputes root from leaf + proof, compares to claimed root. 231 cross-language checks verify this construction in Go, Python, Rust, Swift, and TypeScript.

Relay Resolution Paths

Four lookups. No global enumeration. No reverse indexes.

Lookup Returns Visibility
did Identity HEAD + full op chain (current key state) public
did Latest beacon (merkle root hash + witnesses) public
contentId Content HEAD + full op chain public
operationCID JWS token(s) — original + countersignatures public
did → contentIds Requires Merkle tree data (controller's choice to share) controller's choice
documentCID Document bytes dark forest
contentId → signer DID Via did field in operation payload (committed to by CID) and kid in JWS header always visible

Discovery is dark. Attribution is visible. Knowing a DID doesn't let you find its content. Knowing a contentId lets you find its signer. The asymmetry is the dark forest.

Full Resolution Flow

End-to-end dark forest content resolution. Every step independently verifiable. Proof from Alice, chain from Bob, document from a USB drive — verification is identical.

1
Merkle Proof — obtain beacon from relay, verify DID's signature and typ: did:dfos:beacon. Get inclusion proof for contentId against root.
Result: cryptographic proof this DID claims this content chain
2
Chain Resolution — look up contentId on any relay. Get operation chain (JWS tokens). Verify CID links, signatures, typ headers, signer DID matches payload did, timestamp ordering.
Result: verified chain with known head, known signer, known documentCID
3
Document Resolution — obtain document bytes from authorized source. Encode as dag-cbor, derive CID. Verify it matches documentCID in head operation.
Result: verified document — these bytes are exactly what the chain committed to
4
Manifest Navigation — if document is a manifest, parse the semantic index. Each entry points to another contentId. Repeat from step 1. Recursive, arbitrarily deep, same flow at every level.
Result: verified semantic navigation of a DID's dark forest content

Dark Identity Aliasing

The signer DID on the relay can be a proxy. The connection to the real identity is buried in dark forest manifest content. The protocol doesn't distinguish real from proxy — they're all just DIDs.

Real DID
did:dfos:real_abc
Manifest (dark)
{ "proxy": "did:dfos:dark_xyz" }
Proxy DID
did:dfos:dark_xyz
only visible with manifest access
linkage is dark forest content
visible on relay as signer

Arbitrarily deep nesting. Each layer uses the same protocol primitives. The graph is invisible without manifest access at each level.

Trust Architecture

First-party (the DID controller)

  • Identity chain — key management
  • Content chains — document commitments
  • Beacon — content set commitment
  • Manifests — semantic navigation (dark)
  • Documents — the actual content (dark)

Self-asserted, self-signed, self-certifying. The protocol verifies everything from cryptographic primitives. No third party needed. Runs on a laptop with no network.

Third-party (validators / witnesses)

  • Operation countersignatures — "I verified this op"
  • Beacon countersignatures — "I saw this root"
  • Attestation chains — rich witnessing records
  • Independent timestamps — validator's clock
  • Equivocation detection — conflicting roots

Corroboration that first-party assertions can't provide. The protocol is complete without validators. Validators add independent timestamps, availability proof, and equivocation detection.

Two Tiers of Witnessing

Tier 1

Countersignatures

Same CID, different JWS signer. Works for both content operations (typ: content-op) and beacons (typ: beacon). The payload contains did (the author/controller). When JWS kid DID matches payload did = author. When they differ = witness. Ed25519 is deterministic: same key + same payload = same signature, enabling dedup by JWS token string.

Boolean: "Is this vouched for?" Cheap. No metadata. Collected per-operation and per-beacon.

Tier 2

Attestation Content Chains

Validator maintains their own content chains with structured attestation documents. Rich metadata: timestamps, subject DID, checks performed. Auditable, queryable, historical.

Record: "Who witnessed what, when, with what checks?" The validator's own dark forest content. Same protocol primitives all the way down.

A validator might do both: countersign in real-time (tier 1) and maintain an attestation stream for audit (tier 2). The countersignature is the fast path. The attestation chain is the record.

Relay Architecture

HTTPS servers that store, serve, and sync protocol artifacts. Each relay defines its own policy — what it serves, to whom, for which DIDs. The protocol package (@metalabel/dfos-protocol) is a pure verification library — zero HTTP, storage, or runtime opinions. The relay is a separate artifact.

Relay serves
// Proof substrate (always)
Identity ops    — DID resolution, key state
Content ops     — chain verification
Root beacons    — merkle root announcements
JWS lookups     — operation CID → signatures
Witnesses       — countersignatures per CID

// Optional (operator policy)
Merkle tree      — full tree for enumeration
Documents       — dark forest content (authed)
SSE stream      — real-time operation feed
Relay sync
// Relay-to-relay reconciliation
1. Exchange root beacons for tracked DIDs
2. Compare roots — if equal, in sync
3. If different, exchange content ops
   to reconcile chain heads
4. MST (Merkle Search Tree) for
   efficient delta transfer

// Phase 1: HTTPS + hardcoded peers
// Phase 2: DNS discovery
// Phase 3: Relay directory
// Phase 4: libp2p (if needed)

The Dark Forest Gap

Proof Substrate (public)

Everything needed to verify without reading. Identity chains, content chain operations, root beacons, countersignatures. Who signed what, when, how many operations, which witnesses attested. The skeleton.

You can see that content exists.

Content Substrate (dark)

The actual documents behind CID commitments. Posts, profiles, manifests, identity linkages. Application semantics. What things actually say. Who is really behind what.

You cannot see what it says.

The gap between these two is where sovereignty lives. The proof layer is infrastructure. The content layer is meaning. The protocol proves without revealing.


DFOS Protocol v0.1.0 · Ed25519 · dag-cbor · CIDv1 · SHA-256 Merkle · W3C DIDs · Self-certifying · Transport-agnostic

231 cross-language checks · TypeScript 145 · Python 48 · Go 13 · Rust 13 · Swift 12

protocol.dfos.com · github.com/metalabel/dfos

v0.1.0 architecture · 2026-03-20