@metalabel/dfos-protocol 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/PROTOCOL.md CHANGED
@@ -10,34 +10,26 @@ This spec is under active review. Discuss it in the [clear.txt](https://clear.df
10
10
 
11
11
  ## Philosophy
12
12
 
13
- DFOS is a dark forest operating system. Content lives in private spaces — visible only to members, governed by the communities that create it. The forest floor is dark by default.
13
+ DFOS is a dark forest operating system. Content lives in private spaces — visible only to members, governed by the communities that create it. The cryptographic proof layer is public: signed chains of commitments that anyone can independently verify with a public key and any standard EdDSA library.
14
14
 
15
- But the cryptographic proof layer is public and verifiable. Every piece of content, every identity, every edit has a signed chain of commitments that anyone can independently verify. You don't need to trust the platform. You don't need access to the database. You need a public key and a chain of JWS tokens.
15
+ Two chain types identity and content use the same mechanics: Ed25519 signatures, JWS compact tokens, content-addressed CIDs. The protocol knows about keys and document hashes. It doesn't know about posts, profiles, or any application concept. Document semantics are application layer free to evolve without protocol changes.
16
16
 
17
- If you have content from the official app, from an API export, from a pirate mirror, from anywhere — you can verify it's authentic. Hash the content, check the CID, walk the chain, verify the signature. The content is dark; the proof is light.
18
-
19
- The protocol makes this verification radically simple. Two chain types — identity and content — using the same mechanics: Ed25519 signatures, JWS compact tokens, content-addressed CIDs. The protocol is deliberately minimal. It knows about keys and document hashes. It doesn't know about posts, profiles, or any application concept. Document semantics are entirely application layer — free to evolve without protocol changes.
20
-
21
- This means the protocol is not coupled to DFOS. Any system could implement the same identity and content chain primitives — a fork, an alternative client, a completely independent platform — and produce interoperable, cross-verifiable proofs. An identity created on one system can sign content on another. A proof chain started here can be extended there. The protocol is a shared substrate, not a product feature. DFOS is one application built on it. There could be others.
22
-
23
- The result: a signed content ledger that any standard EdDSA library can verify, in any language, without DFOS-specific dependencies. The dark forest has public roots.
24
-
25
- ---
26
-
27
- All artifacts in this document are deterministic and reproducible from fixed seeds. An independent implementer can verify every value using standard Ed25519 + dag-cbor libraries.
17
+ The protocol is not coupled to the DFOS platform. Any system implementing the same chain primitives produces interoperable, cross-verifiable proofs. An identity created on one system can sign content on another.
28
18
 
29
19
  ---
30
20
 
31
21
  ## Protocol Overview
32
22
 
33
- The DFOS protocol has two layers:
23
+ The DFOS protocol has four components:
34
24
 
35
- | Layer | Concern |
25
+ | Component | Concern |
36
26
  | --------------------- | ---------------------------------------------------------------------------- |
37
27
  | **Crypto core** | Identity chains + content chains — Ed25519 signatures, JWS tokens, CID links |
38
- | **Document envelope** | Standard wrapper: `content` + `baseDocumentCID` + `createdByDID` + timestamp |
28
+ | **Beacons** | Signed merkle root announcements periodic commitment over content sets |
29
+ | **Countersignatures** | Witness attestation — third-party signatures over existing chain operations |
30
+ | **Merkle trees** | SHA-256 binary trees over content IDs — inclusion proofs for beacon roots |
39
31
 
40
- The crypto core is the trust boundary — everything below it is cryptographically verified. The document envelope provides structural metadata (attribution, edit lineage, timestamps). What goes inside the envelope's `content` field is application-defined — see the [DFOS Content Model](https://protocol.dfos.com/content-model) for the standard schema library.
32
+ The crypto core is the trust boundary — everything below it is cryptographically verified. Documents are flat content objects, content-addressed directly: `documentCID = CID(dagCborCanonicalEncode(contentObject))`. What goes inside the content object is application-defined — see the [DFOS Content Model](https://protocol.dfos.com/content-model) for the standard schema library.
41
33
 
42
34
  ### Crypto Core: Two Chain Types
43
35
 
@@ -49,47 +41,21 @@ The crypto core is the trust boundary — everything below it is cryptographical
49
41
  | JWS typ | `did:dfos:identity-op` | `did:dfos:content-op` |
50
42
  | Self-sovereign | Yes (signs own operations) | No (signed by external identity) |
51
43
 
52
- Both chains are signed linked lists of state commitments. Identity chains embed their state (key sets). Content chains reference their state via `documentCID` — a content-addressed pointer to a document envelope.
53
-
54
- ### Document Envelope
55
-
56
- Every document committed to by a content chain uses a standard envelope, defined by JSON Schema at [`schemas/document-envelope.v1.json`](schemas/document-envelope.v1.json) (`https://schemas.dfos.com/document-envelope/v1`):
57
-
58
- ```json
59
- {
60
- "content": { "$schema": "https://schemas.dfos.com/post/v1", ... },
61
- "baseDocumentCID": null,
62
- "createdByDID": "did:dfos:...",
63
- "createdAt": "2026-03-07T00:02:00.000Z"
64
- }
65
- ```
66
-
67
- | Field | Type | Description |
68
- | ----------------- | ------------ | --------------------------------------------------------------------------- |
69
- | `content` | object | Application-defined content — must include `$schema` URI, opaque to chains |
70
- | `baseDocumentCID` | string\|null | Optional CID of a prior document version. Semantics are application-defined |
71
- | `createdByDID` | string | DID of the identity that created this document version |
72
- | `createdAt` | ISO 8601 | When this document version was created |
73
-
74
- The `documentCID` in a content chain operation is `CID(dagCborEncode(envelope))`. The envelope provides attribution at the protocol level. The `content` object must include a `$schema` property identifying its content type — this makes every document self-describing and its schema cryptographically committed via the CID.
44
+ Both chains are signed linked lists of state commitments. Identity chains embed their state (key sets). Content chains reference their state via `documentCID` — a content-addressed pointer to a flat content object.
75
45
 
76
46
  ### Addressing
77
47
 
78
- Three canonical representations:
79
-
80
- | Thing | Form | Example |
81
- | ---------------------- | -------------------------- | --------------------------------- |
82
- | Operation or document | CID (dag-cbor + SHA-256) | See below |
83
- | Entity (content chain) | `<hash>` (bare, no prefix) | `67t27rzc83v7c22n9t6z7c` |
84
- | Identity (key chain) | `did:dfos:<hash>` | `did:dfos:e3vvtck42d4eacdnzvtrn6` |
48
+ Three addressing modes, self-describing by format:
85
49
 
86
- Example CID:
50
+ | Thing | Form | Example |
51
+ | --------------------- | ------------------------ | --------------------------------- |
52
+ | Operation or document | CID (dag-cbor + SHA-256) | `bafyrei...` (base32lower) |
53
+ | Content chain | contentId (22-char hash) | `a82z92a3hndk6c97thcrn8` |
54
+ | Identity chain | DID | `did:dfos:e3vvtck42d4eacdnzvtrn6` |
87
55
 
88
- ```
89
- bafyreibanjpgcqffcfhr4sptzjfthh5szohhbo5tjfulemkw7uhden5uqy
90
- ```
56
+ CIDs are specific immutable artifacts — a pointer to an exact operation or document. Content IDs are living content chain entities — the 22-char bare hash derived from the genesis CID. DIDs are living identity chain entities.
91
57
 
92
- Operations and documents are CIDs — standard IPLD content addresses. Entities and identities are derived identifiers — `customAlpha(SHA-256(genesis CID bytes))`. Same derivation for both. Identity chains prepend `did:dfos:` (W3C DID spec). Entity identifiers are bare — just the 22-char hash, no prefix.
58
+ Operations and documents are CIDs — standard IPLD content addresses. Content chains and identity chains use derived identifiers — `customAlpha(SHA-256(genesis CID bytes))`. Same derivation for both. Identity chains prepend `did:dfos:` (W3C DID spec). Content identifiers are bare — just the 22-char hash, no prefix.
93
59
 
94
60
  Application code may add prefixes for routing (e.g., `post_xxxx`) — these are strippable semantic sugar, not part of the protocol identifier.
95
61
 
@@ -99,17 +65,20 @@ Application code may add prefixes for routing (e.g., `post_xxxx`) — these are
99
65
 
100
66
  ### Commitment Scheme
101
67
 
102
- The protocol requires a **deterministic payload commitment**: given the same logical operation, the commitment (CID) MUST be identical regardless of implementation language or platform. The commitment scheme is **dag-cbor canonical encoding + SHA-256 + CIDv1**. This is not a recommendation — it is the protocol.
68
+ Both operations and documents are content-addressed via **CID** (`dagCborCanonicalEncode(payload)` SHA-256 CIDv1). Operations are additionally signed via **JWS**.
103
69
 
104
- Implementations MUST use dag-cbor canonical encoding as defined by the [IPLD dag-cbor codec specification](https://ipld.io/specs/codecs/dag-cbor/spec/). Raw JSON serialization, pretty-printed JSON, or any non-canonical encoding MUST NOT be used for CID derivation. The dag-cbor hex test vectors in this document allow byte-level verification of any implementation's canonical encoding.
70
+ | Representation | Encoding | Purpose |
71
+ | -------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
72
+ | CID | `dagCborCanonicalEncode(payload)` → SHA-256 → CIDv1 | Deterministic content addressing for operations and documents |
73
+ | JWS | `base64url(JSON.stringify(header))` + `.` + `base64url(JSON.stringify(payload))` → EdDSA signature covers both | Signature verification for operations |
105
74
 
106
- **JWS signing vs CID derivation are intentionally different representations of the same payload.** JWS signs `base64url(JSON.stringify(payload))` the UTF-8 bytes of the JSON serialization. CID commits to `dagCborCanonicalEncode(payload)` the dag-cbor canonical encoding of the parsed object. These produce different bytes from the same logical data. This is by design: JWS uses standard JSON for maximum interoperability with existing JWS libraries, while CID uses dag-cbor for deterministic content addressing.
75
+ CID uses [dag-cbor canonical encoding](https://ipld.io/specs/codecs/dag-cbor/spec/) for determinism given the same logical payload, the CID MUST be identical regardless of implementation language or platform. JWS uses standard JSON for library interoperability. The dag-cbor hex test vectors in this document allow byte-level verification.
107
76
 
108
77
  ### Chain Validity
109
78
 
110
79
  A valid chain is a **linear sequence** of operations. Each operation (after genesis) links to its predecessor via `previousOperationCID`. The chain provides structural ordering independent of timestamps.
111
80
 
112
- **Forks are invalid at the protocol level.** Two operations referencing the same `previousOperationCID` constitute a fork. The protocol does not define fork resolution — this is application-defined. In DFOS's custodial model, forks are prevented by database-level advisory locks. A non-custodial implementation would need its own fork resolution strategy (e.g., longest chain, first-seen, application-specified preference).
81
+ **Forks are invalid at the protocol level.** Two operations referencing the same `previousOperationCID` constitute a fork. The protocol does not define fork resolution — this is application-defined (e.g., longest chain, first-seen, advisory locks).
113
82
 
114
83
  **Timestamp ordering**: `createdAt` SHOULD be strictly increasing within a chain. Implementations SHOULD reject operations with non-increasing timestamps as a sanity check against replayed or mis-ordered operations. However, the chain link (CID reference) is the authoritative ordering mechanism, not the timestamp. Implementations MAY relax timestamp ordering in constrained environments where clock synchronization is impractical.
115
84
 
@@ -121,23 +90,24 @@ This is a self-sovereign invariant: the identity chain defines its own valid sig
121
90
 
122
91
  ### Content Chain Signer Model
123
92
 
124
- Content chain verification requires a **valid EdDSA signature** nothing more. The protocol does not define which identities may sign operations on a content chain, does not track or enforce key roles, and does not restrict a chain to a single signer.
93
+ Content chain verification requires a **valid EdDSA signature** and delegates key resolution to the caller. The `kid` in each operation's JWS header is a DID URL (`did:dfos:<id>#<keyId>`). The verifier calls `resolveKey(kid)` to obtain the raw Ed25519 public key bytes for that key on that identity. How the resolver obtains and validates the identity's key state is application-defined.
125
94
 
126
- The signing key is resolved via the `kid` (DID URL), which references a key on an external identity. The content chain verifier delegates key resolution to the caller via a `resolveKey` callback — the protocol does not prescribe how to look up an identity's current key state.
95
+ Identity chains are self-sovereign they define their own valid signers via `controllerKeys`. Content chains are externally signed a content chain with operations signed by multiple different identities is valid at the protocol level, as long as each signature verifies against the resolved key.
127
96
 
128
- This is a deliberate asymmetry with identity chains. Identity chains are self-sovereign they define their own valid signers internally. Content chains are externally signed the signing authority model is entirely an application concern, delegated through `resolveKey`. A content chain with operations signed by multiple different identities is valid at the protocol level, as long as each operation's signature verifies against the resolved key.
97
+ **Signer-payload consistency**: The `kid` DID in the JWS header MUST match the `did` field in the content operation payload. This enables discrimination between author operations and countersignatures if the kid DID differs from the payload `did`, it is a countersignature (witness attestation), not a chain operation.
129
98
 
130
99
  **What the protocol enforces:**
131
100
 
132
101
  - The EdDSA signature on each operation is valid against the key returned by `resolveKey(kid)`
133
102
  - Chain integrity (CID links, timestamp ordering, terminal state)
103
+ - The `kid` DID matches the payload `did` for chain operations
134
104
 
135
105
  **What the protocol does NOT enforce (application concerns):**
136
106
 
137
107
  - Which identities are authorized to sign operations on a given chain
138
108
  - Which key role (auth, assert, controller) the signing key must have
139
109
  - Whether a chain must have a single signer or may have multiple signers
140
- - Ownership or attribution semantics between signers and entities
110
+ - Ownership or attribution semantics between signers and content chains
141
111
 
142
112
  ### Terminal States and Special Operations
143
113
 
@@ -145,18 +115,28 @@ This is a deliberate asymmetry with identity chains. Identity chains are self-so
145
115
 
146
116
  **Controller key requirement:** `update` operations on identity chains MUST include at least one controller key. If decommissioning is intended, `delete` is the correct terminal operation.
147
117
 
148
- **Content-null:** An `update` on a content chain with `documentCID: null` means the entity exists but its content is cleared. The chain continues — a subsequent update can set content again.
118
+ **Content-null:** An `update` on a content chain with `documentCID: null` means the content exists but its document is cleared. The chain continues — a subsequent update can set content again.
149
119
 
150
120
  ### `typ` Header
151
121
 
152
- The JWS `typ` header (`did:dfos:identity-op`, `did:dfos:content-op`) aids routing but is not security-critical. Implementations SHOULD validate it but MUST NOT rely on it for security decisions.
122
+ The JWS `typ` header uses protocol-specific values (not IANA media types):
123
+
124
+ | `typ` value | Usage |
125
+ | ---------------------- | ------------------------- |
126
+ | `did:dfos:identity-op` | Identity chain operations |
127
+ | `did:dfos:content-op` | Content chain operations |
128
+ | `did:dfos:beacon` | Beacon announcements |
129
+ | `JWT` | Device auth tokens |
130
+
131
+ These are non-standard per JOSE convention, documented intentionally. The `typ` header aids routing but is not security-critical. Implementations SHOULD validate it but MUST NOT rely on it for security decisions.
153
132
 
154
133
  ### Operation Field Limits
155
134
 
156
- The protocol defines maximum sizes for all operation fields. These are abuse-prevention ceilings — deliberately loose, not tight validation. Implementations MUST reject operations that exceed these bounds. Implementations MAY impose stricter limits.
135
+ The protocol defines maximum sizes for all operation fields as abuse-prevention ceilings. Implementations MUST reject operations that exceed these bounds. Implementations MAY impose stricter limits.
157
136
 
158
137
  | Field | Max | Rationale |
159
138
  | -------------------------------------------- | --------- | -------------------------------------- |
139
+ | `did` | 256 chars | ~8× typical `did:dfos:` (~31 chars) |
160
140
  | `key.id` | 64 chars | ~3× typical key ID (`key_` + 22 chars) |
161
141
  | `key.publicKeyMultibase` | 128 chars | ~2× Ed25519 multikey (~50 chars) |
162
142
  | `authKeys` / `assertKeys` / `controllerKeys` | 16 items | Generous for key rotation |
@@ -310,19 +290,24 @@ DID: did:dfos:e3vvtck42d4eacdnzvtrn6
310
290
  ```typescript
311
291
  // Genesis — starts the content chain, commits initial document
312
292
  { version: 1, type: "create",
313
- documentCID: string, // CID of document content
293
+ did: string, // author DID, committed to by CID
294
+ documentCID: string, // CID of flat content object
295
+ baseDocumentCID: string | null, // edit lineage — CID of prior document version
314
296
  createdAt: string,
315
297
  note: string | null }
316
298
 
317
299
  // Content change (null documentCID = clear content)
318
300
  { version: 1, type: "update",
301
+ did: string, // author DID
319
302
  previousOperationCID: string,
320
303
  documentCID: string | null,
304
+ baseDocumentCID: string | null,
321
305
  createdAt: string,
322
306
  note: string | null }
323
307
 
324
- // Permanent entity destruction
308
+ // Permanent destruction
325
309
  { version: 1, type: "delete",
310
+ did: string, // author DID
326
311
  previousOperationCID: string,
327
312
  createdAt: string,
328
313
  note: string | null }
@@ -379,11 +364,7 @@ Every operation JWS (identity-op and content-op) includes a `cid` field in the p
379
364
  - `header.cid` is missing
380
365
  - `header.cid` does not match the derived CID
381
366
 
382
- This provides three benefits:
383
-
384
- - **Pre-verification routing**: The operation CID can be read from the header without parsing the payload or running dag-cbor encoding
385
- - **Cross-implementation consistency**: A CID mismatch between header and derived value immediately surfaces dag-cbor encoding disagreements across implementations
386
- - **Self-documenting tokens**: Each JWS token declares its content-addressed identity
367
+ A CID mismatch between header and derived value immediately surfaces dag-cbor encoding disagreements across implementations.
387
368
 
388
369
  Note: JWT tokens (device auth) do NOT include a `cid` header — this field is specific to operation JWS tokens.
389
370
 
@@ -405,6 +386,90 @@ Where `idEncode` is the 19-char alphabet encoding described above.
405
386
 
406
387
  ---
407
388
 
389
+ ## Beacons
390
+
391
+ A beacon is a signed announcement of a merkle root — a periodic commitment over a set of content IDs. Beacons are floating signed artifacts, not chained. They provide a compact, verifiable snapshot of an identity's content set at a point in time.
392
+
393
+ ### Beacon Payload
394
+
395
+ ```json
396
+ {
397
+ "version": 1,
398
+ "type": "beacon",
399
+ "did": "did:dfos:e3vvtck42d4eacdnzvtrn6",
400
+ "merkleRoot": "a3f8b2c1d4e5f6071829304a5b6c7d8e9f0a1b2c3d4e5f6071829304a5b6c7d8",
401
+ "createdAt": "2026-03-07T00:04:00.000Z"
402
+ }
403
+ ```
404
+
405
+ | Field | Type | Description |
406
+ | ------------ | ------ | ------------------------------------------------------- |
407
+ | `version` | 1 | Protocol version |
408
+ | `type` | string | Literal `"beacon"` |
409
+ | `did` | string | DID of the identity publishing the beacon |
410
+ | `merkleRoot` | string | Hex-encoded SHA-256 root (64 chars, `/^[0-9a-f]{64}$/`) |
411
+ | `createdAt` | string | ISO 8601 timestamp |
412
+
413
+ ### Beacon JWS Header
414
+
415
+ ```json
416
+ {
417
+ "alg": "EdDSA",
418
+ "typ": "did:dfos:beacon",
419
+ "kid": "did:dfos:e3vvtck42d4eacdnzvtrn6#key_ez9a874tckr3dv933d3ckd",
420
+ "cid": "bafyrei..."
421
+ }
422
+ ```
423
+
424
+ ### Beacon Semantics
425
+
426
+ Beacons are not chained — there is no `previousOperationCID`. For a given DID, the latest beacon with a strictly-greater `createdAt` timestamp wins. Beacons replace, not accumulate.
427
+
428
+ **Clock skew tolerance**: Implementations MUST reject beacons with a `createdAt` more than 5 minutes in the future relative to the verifier's clock. This prevents pre-dating attacks while accommodating reasonable clock drift.
429
+
430
+ **merkleRoot**: A hex-encoded SHA-256 hash (64 characters). This is a commitment, not a CID — it uses raw SHA-256, not dag-cbor encoding. See the Merkle Tree section below for construction. An empty content set produces a `null` merkle root (no beacon needed).
431
+
432
+ ---
433
+
434
+ ## Merkle Trees
435
+
436
+ Beacons commit to a set of content IDs via a pure SHA-256 binary Merkle tree. The tree has no dag-cbor dependency — it uses only SHA-256 over raw bytes.
437
+
438
+ ### Construction
439
+
440
+ 1. **Collect** all content IDs (22-char bare hashes) in the set
441
+ 2. **Sort** content IDs lexicographically (UTF-8 byte order)
442
+ 3. **Hash leaves**: for each content ID, `SHA-256(UTF-8(contentId))` → 32-byte leaf hash
443
+ 4. **Build tree**: recursively pair adjacent hashes. For each pair, `SHA-256(left || right)` → 32 bytes. If a level has an odd number of nodes, the last node is promoted to the next level unpaired.
444
+ 5. **Root**: the final 32-byte hash, hex-encoded to a 64-character string
445
+
446
+ An empty set of content IDs produces a `null` root. A single content ID produces a root equal to `hex(SHA-256(UTF-8(contentId)))`.
447
+
448
+ ### Inclusion Proofs
449
+
450
+ A Merkle inclusion proof demonstrates that a specific content ID is part of the committed set without revealing the full set. The proof consists of sibling hashes along the path from leaf to root, plus a direction (left/right) for each step.
451
+
452
+ ---
453
+
454
+ ## Countersignatures
455
+
456
+ A countersignature is a witness attestation — a third-party identity signing the same CID-committed bytes as an existing chain operation. Countersignatures use the same JWS format and `typ` (`did:dfos:content-op`) as the original operation.
457
+
458
+ ### Discrimination Rule
459
+
460
+ The protocol distinguishes author operations from countersignatures by comparing the `kid` DID in the JWS header to the `did` field in the operation payload:
461
+
462
+ - **`kid` DID === payload `did`** → author operation (chain operation)
463
+ - **`kid` DID !== payload `did`** → witness countersignature
464
+
465
+ ### Semantics
466
+
467
+ A countersignature proves that a witness identity has seen and attested to a specific operation. The witness signs the exact same payload (same CID), but with their own key. The countersignature's JWS header will contain the witness's `kid` (their DID URL), while the payload's `did` field remains the original author's DID.
468
+
469
+ Countersignatures are not part of the chain — they do not have `previousOperationCID` links and do not affect chain state. They are auxiliary attestations stored alongside chain operations.
470
+
471
+ ---
472
+
408
473
  ## Verification
409
474
 
410
475
  ### Identity Chain
@@ -427,15 +492,16 @@ Where `idEncode` is the 19-char alphabet encoding described above.
427
492
  2. First op must be `type: "create"`
428
493
  3. For each subsequent op: verify `previousOperationCID` matches, verify `createdAt` increasing
429
494
  4. Derive the operation CID via dag-cbor canonical encoding. Verify `header.cid` matches the derived CID.
430
- 5. Resolve `kid` via external key resolver (caller provides)
431
- 6. Verify EdDSA JWS signature
432
- 7. Apply state change (set document, clear, or delete)
495
+ 5. Verify the `kid` DID matches the payload `did` field (mismatches indicate a countersignature, not a chain operation)
496
+ 6. Resolve `kid` via external key resolver (caller provides)
497
+ 7. Verify EdDSA JWS signature
498
+ 8. Apply state change (set document, clear, or delete)
433
499
 
434
500
  ---
435
501
 
436
502
  ## Deterministic Reference Artifacts
437
503
 
438
- All values below are deterministic and reproducible. Private keys are derived from `SHA-256(UTF8("dfos-protocol-reference-key-N"))`.
504
+ All artifacts below are deterministic and reproducible from fixed seeds. An independent implementer can verify every value using standard Ed25519 + dag-cbor libraries. Private keys are derived from `SHA-256(UTF8("dfos-protocol-reference-key-N"))`.
439
505
 
440
506
  ### Key 1 (Genesis Controller)
441
507
 
@@ -510,7 +576,7 @@ JWS Signature (hex):
510
576
  JWS Token:
511
577
 
512
578
  ```
513
- eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmlkZW50aXR5LW9wIiwia2lkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgiLCJjaWQiOiJiYWZ5cmVpYmFuanBnY3FmZmNmaHI0c3B0empmdGhoNXN6b2hoYm81dGpmdWxlbWt3N3VoZGVuNXVxeSJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiY3JlYXRlIiwiYXV0aEtleXMiOlt7ImlkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgiLCJ0eXBlIjoiTXVsdGlrZXkiLCJwdWJsaWNLZXlNdWx0aWJhc2UiOiJ6Nk1rcnpMTU53b0pTVjRQM1ljY1djYnRrOHZkOUx0Z01LbkxlYURMVXFMdUFTamIifV0sImFzc2VydEtleXMiOlt7ImlkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgiLCJ0eXBlIjoiTXVsdGlrZXkiLCJwdWJsaWNLZXlNdWx0aWJhc2UiOiJ6Nk1rcnpMTU53b0pTVjRQM1ljY1djYnRrOHZkOUx0Z01LbkxlYURMVXFMdUFTamIifV0sImNvbnRyb2xsZXJLZXlzIjpbeyJpZCI6ImtleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4IiwidHlwZSI6Ik11bHRpa2V5IiwicHVibGljS2V5TXVsdGliYXNlIjoiejZNa3J6TE1Od29KU1Y0UDNZY2NXY2J0azh2ZDlMdGdNS25MZWFETFVxTHVBU2piIn1dLCJjcmVhdGVkQXQiOiIyMDI2LTAzLTA3VDAwOjAwOjAwLjAwMFoifQ.EDryDK1uvtix-17cHun9t6MacFIx2rMmMF1QLzfD5TFlSsOvMcue97pCgGn3CXeLVFtVxgpCoh0kGSXioKKzAw
579
+ eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmlkZW50aXR5LW9wIiwia2lkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgiLCJjaWQiOiJiYWZ5cmVpYmFuanBnY3FmZmNmaHI0c3B0empmdGhoNXN6b2hoYm81dGpmdWxlbWt3N3VoZGVuNXVxeSJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiY3JlYXRlIiwiYXV0aEtleXMiOlt7ImlkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgiLCJ0eXBlIjoiTXVsdGlrZXkiLCJwdWJsaWNLZXlNdWx0aWJhc2UiOiJ6Nk1rcnpMTU53b0pTVjRQM1ljY1djYnRrOHZkOUx0Z01LbkxlYURMVXFMdUFTamIifV0sImFzc2VydEtleXMiOlt7ImlkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgiLCJ0eXBlIjoiTXVsdGlrZXkiLCJwdWJsaWNLZXlNdWx0aWJhc2UiOiJ6Nk1rcnpMTU53b0pTVjRQM1ljY1djYnRrOHZkOUx0Z01LbkxlYURMVXFMdUFTamIifV0sImNvbnRyb2xsZXJLZXlzIjpbeyJpZCI6ImtleV9yOWV2MzRmdmMyM3o5OTF2ZWFhZnQ4IiwidHlwZSI6Ik11bHRpa2V5IiwicHVibGljS2V5TXVsdGliYXNlIjoiejZNa3J6TE1Od29KU1Y0UDNZY2NXY2J0azh2ZDlMdGdNS25MZWFETFVxTHVBU2piIn1dLCJjcmVhdGVkQXQiOiIyMDI2LTAzLTA3VDAwOjAwOjAwLjAwMFoifQ.EDryDK1uvtix-17cHun9t6MacFIx2rMmMF1QLzfD5TFlSsOvMcue97pCgGn3CXeLVFtVxgpCoh0kGSXioKKzAw
514
580
  ```
515
581
 
516
582
  Operation CID:
@@ -588,26 +654,22 @@ Post-rotation: DID unchanged (`did:dfos:e3vvtck42d4eacdnzvtrn6`), controller rot
588
654
 
589
655
  ### Content Chain: Document + Create
590
656
 
591
- Document (application layer):
657
+ Document (flat content object):
592
658
 
593
659
  ```json
594
660
  {
595
- "content": {
596
- "$schema": "https://schemas.dfos.com/post/v1",
597
- "format": "short-post",
598
- "title": "Hello World",
599
- "body": "First post on the protocol."
600
- },
601
- "baseDocumentCID": null,
602
- "createdByDID": "did:dfos:e3vvtck42d4eacdnzvtrn6",
603
- "createdAt": "2026-03-07T00:02:00.000Z"
661
+ "$schema": "https://schemas.dfos.com/post/v1",
662
+ "format": "short-post",
663
+ "title": "Hello World",
664
+ "body": "First post on the protocol.",
665
+ "createdByDID": "did:dfos:e3vvtck42d4eacdnzvtrn6"
604
666
  }
605
667
  ```
606
668
 
607
669
  Document CID:
608
670
 
609
671
  ```
610
- bafyreifpvwuarml62sfogdpi2vlltvg2ev6o4xtw74zfud7cpkg7426zne
672
+ bafyreihzwuoupfg3dxip6xmgzmxsywyii2jeoxxzbgx3zxm2in7knoi3g4
611
673
  ```
612
674
 
613
675
  Content Create JWS Header:
@@ -617,7 +679,7 @@ Content Create JWS Header:
617
679
  "alg": "EdDSA",
618
680
  "typ": "did:dfos:content-op",
619
681
  "kid": "did:dfos:e3vvtck42d4eacdnzvtrn6#key_ez9a874tckr3dv933d3ckd",
620
- "cid": "bafyreia5z7zxknae5ds72euihuf2rg3ixl6t4fbzjefhcogg3nqppyogqu"
682
+ "cid": "bafyreiaedhjq64aajpwociahl5w37j6uoxr5mojoq5dnah6fpvxr5d4lxu"
621
683
  }
622
684
  ```
623
685
 
@@ -627,7 +689,9 @@ Content Create Payload:
627
689
  {
628
690
  "version": 1,
629
691
  "type": "create",
630
- "documentCID": "bafyreifpvwuarml62sfogdpi2vlltvg2ev6o4xtw74zfud7cpkg7426zne",
692
+ "did": "did:dfos:e3vvtck42d4eacdnzvtrn6",
693
+ "documentCID": "bafyreihzwuoupfg3dxip6xmgzmxsywyii2jeoxxzbgx3zxm2in7knoi3g4",
694
+ "baseDocumentCID": null,
631
695
  "createdAt": "2026-03-07T00:02:00.000Z",
632
696
  "note": null
633
697
  }
@@ -636,19 +700,19 @@ Content Create Payload:
636
700
  Content Create JWS Signature (hex):
637
701
 
638
702
  ```
639
- b7f0c3909fd398d7a42065053b6d86f96efc4281385d383d2ca4388330101da2b707ae3dd538abf5bfb0b69fa173098436ed87aa789eaafe404a2a9f16b11b0f
703
+ 46feaf973e4c7ebc2a0d4ad25481ace197de05b91051205c5e1c7067a85fb9d4abe4cc61625d3c853a8b0ce0345b534c8cdd07b34216f635d3c0bc0fd5d30306
640
704
  ```
641
705
 
642
706
  Content Create JWS Token:
643
707
 
644
708
  ```
645
- eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNvbnRlbnQtb3AiLCJraWQiOiJkaWQ6ZGZvczplM3Z2dGNrNDJkNGVhY2RuenZ0cm42I2tleV9lejlhODc0dGNrcjNkdjkzM2QzY2tkIiwiY2lkIjoiYmFmeXJlaWE1ejd6eGtuYWU1ZHM3MmV1aWh1ZjJyZzNpeGw2dDRmYnpqZWZoY29nZzNucXBweW9ncXUifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiY3JlYXRlIiwiZG9jdW1lbnRDSUQiOiJiYWZ5cmVpZnB2d3Vhcm1sNjJzZm9nZHBpMnZsbHR2ZzJldjZvNHh0dzc0emZ1ZDdjcGtnNzQyNnpuZSIsImNyZWF0ZWRBdCI6IjIwMjYtMDMtMDdUMDA6MDI6MDAuMDAwWiIsIm5vdGUiOm51bGx9.t_DDkJ_TmNekIGUFO22G-W78QoE4XTg9LKQ4gzAQHaK3B6491Tir9b-wtp-hcwmENu2Hqnieqv5ASiqfFrEbDw
709
+ eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNvbnRlbnQtb3AiLCJraWQiOiJkaWQ6ZGZvczplM3Z2dGNrNDJkNGVhY2RuenZ0cm42I2tleV9lejlhODc0dGNrcjNkdjkzM2QzY2tkIiwiY2lkIjoiYmFmeXJlaWFlZGhqcTY0YWFqcHdvY2lhaGw1dzM3ajZ1b3hyNW1vam9xNWRuYWg2ZnB2eHI1ZDRseHUifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiY3JlYXRlIiwiZGlkIjoiZGlkOmRmb3M6ZTN2dnRjazQyZDRlYWNkbnp2dHJuNiIsImRvY3VtZW50Q0lEIjoiYmFmeXJlaWh6d3VvdXBmZzNkeGlwNnhtZ3pteHN5d3lpaTJqZW94eHpiZ3gzenhtMmluN2tub2kzZzQiLCJiYXNlRG9jdW1lbnRDSUQiOm51bGwsImNyZWF0ZWRBdCI6IjIwMjYtMDMtMDdUMDA6MDI6MDAuMDAwWiIsIm5vdGUiOm51bGx9.Rv6vlz5MfrwqDUrSVIGs4ZfeBbkQUSBcXhxwZ6hfudSr5MxhYl08hTqLDOA0W1NMjN0Hs0IW9jXTwLwP1dMDBg
646
710
  ```
647
711
 
648
712
  Content Operation CID:
649
713
 
650
714
  ```
651
- bafyreia5z7zxknae5ds72euihuf2rg3ixl6t4fbzjefhcogg3nqppyogqu
715
+ bafyreiaedhjq64aajpwociahl5w37j6uoxr5mojoq5dnah6fpvxr5d4lxu
652
716
  ```
653
717
 
654
718
  ### Content Chain: Update
@@ -659,39 +723,45 @@ Content Update Payload:
659
723
  {
660
724
  "version": 1,
661
725
  "type": "update",
662
- "previousOperationCID": "bafyreia5z7zxknae5ds72euihuf2rg3ixl6t4fbzjefhcogg3nqppyogqu",
663
- "documentCID": "bafyreieuo26zfmjxwpmw5jk6bqzqhvivxcbckgxtyeuc7ypf3p4sihgq4q",
726
+ "did": "did:dfos:e3vvtck42d4eacdnzvtrn6",
727
+ "previousOperationCID": "bafyreiaedhjq64aajpwociahl5w37j6uoxr5mojoq5dnah6fpvxr5d4lxu",
728
+ "documentCID": "bafyreidh7e36cvwy3uw5ypitcqk7uoktbkkkj7e6hxhky4o75rxn7kxilu",
729
+ "baseDocumentCID": "bafyreihzwuoupfg3dxip6xmgzmxsywyii2jeoxxzbgx3zxm2in7knoi3g4",
664
730
  "createdAt": "2026-03-07T00:03:00.000Z",
665
731
  "note": "edited title and body"
666
732
  }
667
733
  ```
668
734
 
669
- Updated document:
735
+ Updated document (flat content object):
670
736
 
671
737
  ```json
672
738
  {
673
- "content": {
674
- "$schema": "https://schemas.dfos.com/post/v1",
675
- "format": "short-post",
676
- "title": "Hello World (edited)",
677
- "body": "Updated content."
678
- },
679
- "baseDocumentCID": "bafyreifpvwuarml62sfogdpi2vlltvg2ev6o4xtw74zfud7cpkg7426zne",
680
- "createdByDID": "did:dfos:e3vvtck42d4eacdnzvtrn6",
681
- "createdAt": "2026-03-07T00:03:00.000Z"
739
+ "$schema": "https://schemas.dfos.com/post/v1",
740
+ "format": "short-post",
741
+ "title": "Hello World (edited)",
742
+ "body": "Updated content.",
743
+ "createdByDID": "did:dfos:e3vvtck42d4eacdnzvtrn6"
682
744
  }
683
745
  ```
684
746
 
685
747
  Document CID (edited):
686
748
 
687
749
  ```
688
- bafyreieuo26zfmjxwpmw5jk6bqzqhvivxcbckgxtyeuc7ypf3p4sihgq4q
750
+ bafyreidh7e36cvwy3uw5ypitcqk7uoktbkkkj7e6hxhky4o75rxn7kxilu
689
751
  ```
690
752
 
691
753
  Content Update CID:
692
754
 
693
755
  ```
694
- bafyreibb4lsvqmz4j76rsvhkqw3v2b4vp23t7dimm6vl5g5wlninvkemxq
756
+ bafyreih6e5cbjitpozhzhgmfktmiohmxyn3ucwhqd3mjixizvwmlhv7hm4
757
+ ```
758
+
759
+ ### Content Chain Verified State
760
+
761
+ ```
762
+ Content ID: a82z92a3hndk6c97thcrn8
763
+ Genesis CID: bafyreiaedhjq64aajpwociahl5w37j6uoxr5mojoq5dnah6fpvxr5d4lxu
764
+ Head CID: bafyreih6e5cbjitpozhzhgmfktmiohmxyn3ucwhqd3mjixizvwmlhv7hm4
695
765
  ```
696
766
 
697
767
  ---
@@ -707,7 +777,7 @@ Given the artifacts above, verify:
707
777
  → ba421e272fad4f941c221e47f87d9253bdc04f7d4ad2625ae667ab9f0688ce32
708
778
  ```
709
779
 
710
- 2. **Genesis JWS verify**: split token on `.`, take first two segments as signing input (UTF-8 bytes), base64url-decode third segment as 64-byte signature, `ed25519.verify(signature, signingInputBytes, publicKey)` → true. Note the header now contains `cid` alongside `alg`, `typ`, and `kid`.
780
+ 2. **Genesis JWS verify**: split token on `.`, take first two segments as signing input (UTF-8 bytes), base64url-decode third segment as 64-byte signature, `ed25519.verify(signature, signingInputBytes, publicKey)` → true. The header contains `cid` alongside `alg`, `typ`, and `kid`.
711
781
 
712
782
  3. **Genesis CID**: base64url-decode JWS payload → parse JSON → dag-cbor canonical encode → SHA-256 → CIDv1 → should be:
713
783
 
@@ -731,21 +801,23 @@ Given the artifacts above, verify:
731
801
  did:dfos:e3vvtck42d4eacdnzvtrn6#key_ez9a874tckr3dv933d3ckd
732
802
  ```
733
803
 
734
- 8. **Document CID**: dag-cbor canonical encode the document JSON → SHA-256 → CIDv1 → should be:
804
+ 8. **Document CID**: dag-cbor canonical encode the flat content object → SHA-256 → CIDv1 → should be:
735
805
 
736
806
  ```
737
- bafyreifpvwuarml62sfogdpi2vlltvg2ev6o4xtw74zfud7cpkg7426zne
807
+ bafyreihzwuoupfg3dxip6xmgzmxsywyii2jeoxxzbgx3zxm2in7knoi3g4
738
808
  ```
739
809
 
740
- 9. **Content chain integrity**: update's `previousOperationCID` matches create's operation CID
810
+ 9. **Content operation `did` field**: verify the `did` field in each content operation matches the `kid` DID in the JWS header
741
811
 
742
- 10. **Chain completeness**: all operation CIDs, DID derivation, key rotation, and content chain linkage verified end-to-end.
812
+ 10. **Content chain integrity**: update's `previousOperationCID` matches create's operation CID
813
+
814
+ 11. **Chain completeness**: all operation CIDs, DID derivation, key rotation, and content chain linkage verified end-to-end.
743
815
 
744
816
  ---
745
817
 
746
818
  ## Source and Verification
747
819
 
748
- All source lives in [`packages/dfos-protocol/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol) — self-contained, zero monorepo dependencies. 160 checks across 5 languages.
820
+ All source lives in [`packages/dfos-protocol/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol) — self-contained, zero monorepo dependencies. 235 checks across 5 languages.
749
821
 
750
822
  - [`crypto/ed25519`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/crypto/ed25519.ts) — `createNewEd25519Keypair`, `importEd25519Keypair`, `signPayloadEd25519`, `isValidEd25519Signature`
751
823
  - [`crypto/jws`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/crypto/jws.ts) — `createJws`, `verifyJws`, `decodeJwsUnsafe`
@@ -756,23 +828,26 @@ All source lives in [`packages/dfos-protocol/`](https://github.com/metalabel/dfo
756
828
  - [`chain/schemas`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/schemas.ts) — `IdentityOperation`, `ContentOperation`, `MultikeyPublicKey`, `VerifiedIdentity`
757
829
  - [`chain/identity-chain`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/identity-chain.ts) — `signIdentityOperation`, `verifyIdentityChain`
758
830
  - [`chain/content-chain`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/content-chain.ts) — `signContentOperation`, `verifyContentChain`
759
- - [`chain/derivation`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/derivation.ts) — `deriveChainIdentifier`
831
+ - [`chain/derivation`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/derivation.ts) — `deriveChainIdentifier`, `deriveContentId`
832
+ - [`chain/beacon`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/beacon.ts) — `signBeacon`, `verifyBeacon`
833
+ - [`chain/countersign`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/countersign.ts) — `signCountersignature`, `verifyCountersignature`
834
+ - [`merkle/tree`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/merkle/tree.ts) — `buildMerkleTree`, `hashLeaf`
835
+ - [`merkle/proof`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/merkle/proof.ts) — `generateMerkleProof`, `verifyMerkleProof`
760
836
 
761
837
  ### Related Specifications
762
838
 
763
839
  - [DID Method: `did:dfos`](https://protocol.dfos.com/did-method) — W3C DID method specification for identity chains
764
- - [Content Model](https://protocol.dfos.com/content-model) — Standard content schemas (post, profile) for the document envelope
765
- - [Registry API](https://protocol.dfos.com/registry-api) — HTTP API for chain storage and resolution
840
+ - [Content Model](https://protocol.dfos.com/content-model) — Standard content schemas (post, profile) for document content objects
766
841
 
767
842
  ### Cross-Language Verification
768
843
 
769
844
  | Language | Tests | Source |
770
845
  | ---------- | ----- | ---------------------------------------------------------------------------------------------------- |
771
- | TypeScript | 99 | [`tests/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/tests) |
772
- | Python | 35 | [`verify/python/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/python) |
773
- | Go | 9 | [`verify/go/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/go) |
774
- | Rust | 9 | [`verify/rust/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/rust) |
775
- | Swift | 8 | [`verify/swift/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/swift) |
846
+ | TypeScript | 149 | [`tests/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/tests) |
847
+ | Python | 48 | [`verify/python/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/python) |
848
+ | Go | 13 | [`verify/go/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/go) |
849
+ | Rust | 13 | [`verify/rust/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/rust) |
850
+ | Swift | 12 | [`verify/swift/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/swift) |
776
851
 
777
852
  ---
778
853
 
@@ -780,7 +855,3 @@ All source lives in [`packages/dfos-protocol/`](https://github.com/metalabel/dfo
780
855
 
781
856
  - **Vinny Bellavia** — [stcisgood.com](https://stcisgood.com)
782
857
  - **Allison Clift-Jennings** — [Jura Labs](https://juralabs.com)
783
-
784
- ---
785
-
786
- Yancey · Ilya · Brandon · Lena
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @metalabel/dfos-protocol
2
2
 
3
- Ed25519 signed chain primitives, verifiable content, and registry for the DFOS Protocol.
3
+ Cryptographic identity and content proof — Ed25519 signed chains, content-addressed CIDs, W3C DIDs. The protocol knows about keys and document hashes. It doesn't know about posts, profiles, or any application concept.
4
4
 
5
5
  ## Install
6
6
 
@@ -15,17 +15,17 @@ npm install @metalabel/dfos-protocol
15
15
  import { verifyContentChain, verifyIdentityChain } from '@metalabel/dfos-protocol/chain';
16
16
  // Crypto primitives
17
17
  import { createJws, dagCborCanonicalEncode, verifyJws } from '@metalabel/dfos-protocol/crypto';
18
- // Reference registry server
19
- import { createRegistryServer } from '@metalabel/dfos-protocol/registry';
18
+ // Merkle trees
19
+ import { buildMerkleTree, verifyMerkleProof } from '@metalabel/dfos-protocol/merkle';
20
20
  ```
21
21
 
22
22
  ## Subpath Exports
23
23
 
24
- | Export | Description |
25
- | ----------------------------------- | ------------------------------------------------------------------- |
26
- | `@metalabel/dfos-protocol/chain` | Identity and content chain signing, verification, multikey encoding |
27
- | `@metalabel/dfos-protocol/crypto` | Ed25519, JWS, JWT, dag-cbor, base64url, ID generation |
28
- | `@metalabel/dfos-protocol/registry` | Hono-based registry server, in-memory store, Zod schemas |
24
+ | Export | Description |
25
+ | --------------------------------- | ----------------------------------------------------------------------- |
26
+ | `@metalabel/dfos-protocol/chain` | Identity and content chain signing, verification, beacons, countersigns |
27
+ | `@metalabel/dfos-protocol/crypto` | Ed25519, JWS, JWT, dag-cbor, base64url, ID generation |
28
+ | `@metalabel/dfos-protocol/merkle` | SHA-256 binary merkle tree, inclusion proofs |
29
29
 
30
30
  ## Specifications
31
31
 
@@ -33,9 +33,7 @@ import { createRegistryServer } from '@metalabel/dfos-protocol/registry';
33
33
  | -------------------------------------- | -------------------------------------------------------------- |
34
34
  | [PROTOCOL.md](./PROTOCOL.md) | Core protocol — chains, signatures, verification, test vectors |
35
35
  | [DID-METHOD.md](./DID-METHOD.md) | W3C DID method specification for `did:dfos` |
36
- | [CONTENT-MODEL.md](./CONTENT-MODEL.md) | Standard content schemas (post, profile, media) |
37
- | [REGISTRY-API.md](./REGISTRY-API.md) | HTTP API for chain storage and resolution |
38
- | [openapi.yaml](./openapi.yaml) | OpenAPI 3.1 machine-readable registry spec |
36
+ | [CONTENT-MODEL.md](./CONTENT-MODEL.md) | Standard content schemas (post, profile, manifest) |
39
37
 
40
38
  ## Examples
41
39