Upload files to "/"
This commit is contained in:
parent
18089806fc
commit
9586a9d948
2 changed files with 308 additions and 0 deletions
136
decentralized_cards_primer.md
Normal file
136
decentralized_cards_primer.md
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
# Primer: Decentralized Card & Capability Protocol
|
||||||
|
|
||||||
|
This primer introduces the main ideas of the Decentralized Card & Capability Protocol in a simplified, narrative form with examples and diagrams. It complements the full specification.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. What is a Card?
|
||||||
|
|
||||||
|
A **Card** is a small digital envelope that carries a piece of content (a message, credential, or document). Every Card is:
|
||||||
|
|
||||||
|
- **Signed** → you know who made it
|
||||||
|
- **Optional encrypted** → you can restrict who can read it
|
||||||
|
- **Policy-bound** → it carries rules for visibility, distribution, and revocation
|
||||||
|
|
||||||
|
Think of a Card as a "post" that can be **public** or **private**, and can move around the network.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Capabilities
|
||||||
|
|
||||||
|
Capabilities (caps) describe *features* in the system. Each cap has a unique ID (a hash of its definition).
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- `cap:card/v1` → basic card format
|
||||||
|
- `cap:hpke-x25519-xc20p` → encryption using HPKE
|
||||||
|
- `cap:vc-staple` → attach verifiable credentials
|
||||||
|
|
||||||
|
Cards declare:
|
||||||
|
- **Requirements (`reqs`)** → features a reader MUST support
|
||||||
|
- **Provenance (`prov`)** → features the sender’s software actually used (optional)
|
||||||
|
|
||||||
|
### Bundles (Rollups)
|
||||||
|
Sometimes a set of caps is used together often. These can be rolled into a **bundle cap**. Expanding the bundle reveals all the atomic caps inside.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Anatomy of a Card
|
||||||
|
|
||||||
|
```
|
||||||
|
+-------------------------------+
|
||||||
|
| Signed Envelope (COSE_Sign1) |
|
||||||
|
|-------------------------------|
|
||||||
|
| ver, type, net, rid, ts |
|
||||||
|
| reqs, prov |
|
||||||
|
| policy_ref (hash) |
|
||||||
|
| content_uri + content_hash |
|
||||||
|
+-------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Envelope**: signed by the creator
|
||||||
|
- **Policy capsule**: encrypted blob describing visibility & distribution
|
||||||
|
- **Content**: ciphertext payload (or plaintext for public cards)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Visibility Modes
|
||||||
|
|
||||||
|
- **Public**: anyone can read
|
||||||
|
- **Direct**: private to one user
|
||||||
|
- **Node**: private to members of a node
|
||||||
|
- **Trustset**: private to nodes your node trusts
|
||||||
|
- **Group**: private to a specific group of users
|
||||||
|
|
||||||
|
Recipient lists are hidden inside the encrypted policy capsule. Outsiders can’t even see who the recipients are.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Distribution Modes
|
||||||
|
|
||||||
|
Distribution is about **where the Card is allowed to go** (not who can read it):
|
||||||
|
|
||||||
|
- `to_recipients_only` → only to recipients
|
||||||
|
- `this_node_only` → never leaves a node
|
||||||
|
- `trusted_nodes` → shared with trusted peers
|
||||||
|
- `public` → gossip freely
|
||||||
|
|
||||||
|
Distribution rules can also be encrypted so outsiders can’t guess your intent.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Revocation
|
||||||
|
|
||||||
|
Cards that are not permanent can be **invalidated** later:
|
||||||
|
|
||||||
|
1. **Strong revoke (online gate)**
|
||||||
|
- Card points to a key gate.
|
||||||
|
- Gate can refuse further key requests → instant revoke.
|
||||||
|
|
||||||
|
2. **Crypto-shred (offline)**
|
||||||
|
- Keys are wrapped under a KEK.
|
||||||
|
- Delete the KEK → new readers can’t decrypt.
|
||||||
|
|
||||||
|
⚠️ If someone already decrypted before revocation, they still have the plaintext.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Example Flows
|
||||||
|
|
||||||
|
### Public Post
|
||||||
|
Alice publishes a permanent public Card:
|
||||||
|
- No encryption
|
||||||
|
- Flags `permanent_public=true`
|
||||||
|
- Anyone can read forever
|
||||||
|
|
||||||
|
### Private Message
|
||||||
|
Alice sends Bob a direct Card:
|
||||||
|
- Policy capsule contains an HPKE entry for Bob’s key
|
||||||
|
- Bob decrypts → gets the content
|
||||||
|
- Outsiders can’t see Bob is the recipient
|
||||||
|
|
||||||
|
### Group Message
|
||||||
|
Carol posts to her study group:
|
||||||
|
- Policy capsule carries MLS group state
|
||||||
|
- Only members can open it
|
||||||
|
- Outsiders can’t see who’s in the group
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Why This Matters
|
||||||
|
|
||||||
|
- **Privacy**: Audience lists are hidden
|
||||||
|
- **Control**: Users can revoke their Cards (unless marked permanent public)
|
||||||
|
- **Flexibility**: Supports nodes, trust sets, and groups without central control
|
||||||
|
- **Interoperability**: Capabilities make it possible to evolve without breaking old Cards
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Next Steps
|
||||||
|
|
||||||
|
- Developers should first implement **public cards** + **direct cards**
|
||||||
|
- Then add **node/trustset/group encryption**
|
||||||
|
- Finally add **revocation strategies** and **bundle caps**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**This primer is non-normative.** For authoritative details, see the [full specification](./decentralized_cards_spec.md).
|
||||||
172
decentralized_cards_spec.md
Normal file
172
decentralized_cards_spec.md
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
# Decentralized Card & Capability Protocol (Draft)
|
||||||
|
|
||||||
|
## 1. Introduction
|
||||||
|
|
||||||
|
This document specifies a decentralized protocol for the creation, distribution, and validation of signed and encrypted **Cards**. Cards are the fundamental unit of communication in the system. They may be public or private, and may carry access control, distribution rules, and revocation semantics. The protocol also defines a system of **Capabilities** that allow interoperable feature negotiation without central coordination.
|
||||||
|
|
||||||
|
This specification is written in the style of the [W3C ActivityPub Recommendation](https://www.w3.org/TR/activitypub/).
|
||||||
|
|
||||||
|
## 2. Terminology
|
||||||
|
|
||||||
|
- **Card**: A signed object representing a unit of content. Cards may be public or private, and may be encrypted.
|
||||||
|
- **Capability (cap)**: A content-addressed specification document that describes a feature, schema, or protocol behavior.
|
||||||
|
- **Capability ID (cap_id)**: The multibase-encoded hash of a capability spec. Immutable.
|
||||||
|
- **Requirements (`reqs`)**: Capabilities that a verifier MUST support in order to process the Card.
|
||||||
|
- **Provenance (`prov`)**: Capabilities the producer actually used when generating the Card. Defaults to `reqs` if omitted.
|
||||||
|
- **Bundle (rollup cap)**: A capability that implies a deterministic set of member capabilities.
|
||||||
|
- **Policy capsule**: An encrypted structure that defines the Card’s visibility, distribution, and keying material.
|
||||||
|
- **Visibility**: Who may decrypt the Card payload.
|
||||||
|
- **Distribution**: Where the Card may be transmitted.
|
||||||
|
- **Permanent public Card**: A Card with no encryption and no revocation path. Immutable.
|
||||||
|
|
||||||
|
## 3. Cards
|
||||||
|
|
||||||
|
### 3.1 Structure
|
||||||
|
|
||||||
|
A Card is a CBOR map wrapped in a COSE_Sign1 envelope. Fields:
|
||||||
|
|
||||||
|
- `ver`: Protocol version.
|
||||||
|
- `type`: MUST be `"card"`.
|
||||||
|
- `net`: Network identifier.
|
||||||
|
- `rid`: Unique Card identifier.
|
||||||
|
- `ts`: Creation timestamp.
|
||||||
|
- `reqs`: Array of capability IDs required to interpret the Card.
|
||||||
|
- `prov`: Optional. Array of capabilities actually used. If absent, treated as identical to `reqs`.
|
||||||
|
- `policy_ref`: Hash of the encrypted policy capsule.
|
||||||
|
- `content_uri`: URI of the ciphertext payload.
|
||||||
|
- `content_hash`: Integrity hash of the payload.
|
||||||
|
- `dist_tag`: Optional opaque routing hint.
|
||||||
|
- `sig`: Producer signature.
|
||||||
|
|
||||||
|
### 3.2 Policy Capsule
|
||||||
|
|
||||||
|
The policy capsule is an encrypted CBOR map. Fields:
|
||||||
|
|
||||||
|
- `visibility`: `"public" | "direct" | "node" | "trustset" | "group"`.
|
||||||
|
- `distribution`: `"to_recipients_only" | "this_node_only" | "trusted_nodes" | "public"`.
|
||||||
|
- `keying`: HPKE encapsulations, MLS group material, or gate instructions for CEK recovery.
|
||||||
|
- `flags`: e.g. `permanent_public`.
|
||||||
|
- `exp`, `ttl`: Optional expiry or validity constraints.
|
||||||
|
- `pad`: Optional padding to obscure audience size.
|
||||||
|
- `roster_encrypted`: Optional, group roster encrypted under the group secret.
|
||||||
|
|
||||||
|
### 3.3 Payload
|
||||||
|
|
||||||
|
- `payload_ciphertext` = AEAD(CEK, plaintext_card_body, AAD={net, rid, policy_ref})
|
||||||
|
- Public cards MAY inline plaintext content.
|
||||||
|
|
||||||
|
## 4. Capabilities
|
||||||
|
|
||||||
|
### 4.1 Capability ID
|
||||||
|
|
||||||
|
```
|
||||||
|
cap_id = multibase( sha256( canonical_cbor(spec_without_signatures) ) )
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 Capability Spec
|
||||||
|
|
||||||
|
A capability spec is a signed document:
|
||||||
|
|
||||||
|
- `schema`: MUST be `"cap-spec/v1"`.
|
||||||
|
- `name`: Human-friendly name.
|
||||||
|
- `semver`: Version.
|
||||||
|
- `purpose`: Summary of semantics.
|
||||||
|
- `behavior`: Protocol rules.
|
||||||
|
- `interop`: `{requires, supersedes, conflicts}`.
|
||||||
|
- `test_vectors`: Golden values for conformance.
|
||||||
|
- `docs_uri`: Documentation.
|
||||||
|
- `signatures`: Array of COSE signatures from authors/curators.
|
||||||
|
|
||||||
|
### 4.3 Bundles
|
||||||
|
|
||||||
|
A bundle spec lists `members` (cap IDs). Bundles MUST expand deterministically into their atomic members before enforcement.
|
||||||
|
|
||||||
|
### 4.4 Negotiation
|
||||||
|
|
||||||
|
- Nodes advertise supported caps at `/.well-known/node-caps`.
|
||||||
|
- Cards include `reqs` for enforcement, `prov` for provenance.
|
||||||
|
- Consumers MUST reject Cards if any `reqs` are unsupported.
|
||||||
|
|
||||||
|
## 5. Visibility Modes
|
||||||
|
|
||||||
|
- **Public**: No encryption. MAY be flagged permanent.
|
||||||
|
- **Direct**: Encrypted CEK to a single recipient (HPKE).
|
||||||
|
- **Node**: CEK encrypted to a node’s group key or gate.
|
||||||
|
- **Trustset**: CEK encrypted to each trusted node’s group key.
|
||||||
|
- **Group**: CEK encrypted to an MLS group. Roster MAY remain private.
|
||||||
|
|
||||||
|
## 6. Distribution Modes
|
||||||
|
|
||||||
|
- **to_recipients_only**: Honest nodes forward only to recipients.
|
||||||
|
- **this_node_only**: Not gossiped beyond node.
|
||||||
|
- **trusted_nodes**: Forwarded only to trustset.
|
||||||
|
- **public**: Freely gossiped. Encryption still protects confidentiality.
|
||||||
|
|
||||||
|
Distribution policies MAY be encrypted inside the policy capsule.
|
||||||
|
|
||||||
|
## 7. Revocation
|
||||||
|
|
||||||
|
- **Permanent public cards**: Irrevocable.
|
||||||
|
- **Strong revoke (online gate)**: CEK fetched from gate; revocation = disable at gate. Instant, requires availability.
|
||||||
|
- **Crypto-shred (offline)**: CEK wrapped under KEK. Revocation = delete KEK. Prevents new decryption, not past.
|
||||||
|
- **Card Revocation List (CRL)**: Optional signed log of revoked card IDs. Honest clients suppress display.
|
||||||
|
|
||||||
|
## 8. Security Considerations
|
||||||
|
|
||||||
|
- All hashes MUST be computed over canonical CBOR.
|
||||||
|
- Policy capsule MUST bind `{net, rid, content_hash}` in AEAD AAD.
|
||||||
|
- Bundles MUST be expanded before enforcement.
|
||||||
|
- Unknown required caps MUST cause rejection.
|
||||||
|
- Distribution enforcement relies on honest nodes; confidentiality relies on crypto.
|
||||||
|
- Padding SHOULD be used to obscure audience sizes.
|
||||||
|
|
||||||
|
## 9. Extensibility
|
||||||
|
|
||||||
|
- New caps define new features, schemas, and crypto suites.
|
||||||
|
- Specs are content-addressed, so evolution produces new cap IDs.
|
||||||
|
- Cards MAY carry adapters in `reqs` to allow downgrade/interop.
|
||||||
|
- Deprecated caps SHOULD publish signed deprecation notices.
|
||||||
|
|
||||||
|
## 10. Conformance
|
||||||
|
|
||||||
|
A conforming implementation MUST:
|
||||||
|
- Validate COSE signatures and hashes.
|
||||||
|
- Enforce all capabilities in `reqs`.
|
||||||
|
- Expand bundles before enforcement.
|
||||||
|
- Respect revocation policies.
|
||||||
|
- Reject unsupported or malformed Cards.
|
||||||
|
|
||||||
|
## Appendix A. Example Public Card
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ver": 1,
|
||||||
|
"type": "card",
|
||||||
|
"net": "net:prod:z9…",
|
||||||
|
"rid": "0x12b…",
|
||||||
|
"ts": 1738123456,
|
||||||
|
"reqs": ["cap:card/v1@…"],
|
||||||
|
"body": { "schema": "card/v1", "payload_hash": "…", "content": { "msg": "hello world" } }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Appendix B. Example Private Card (Direct)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ver": 1,
|
||||||
|
"type": "card",
|
||||||
|
"net": "net:prod:z9…",
|
||||||
|
"rid": "0x44a…",
|
||||||
|
"ts": 1738126789,
|
||||||
|
"reqs": ["cap:card/v2@…","cap:hpke-x25519-xc20p@…"],
|
||||||
|
"policy_ref": "sha256:7f…",
|
||||||
|
"content_uri": "ipfs://bafy…",
|
||||||
|
"content_hash": "sha256:aa…"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Status of this Document**
|
||||||
|
This is a working draft. It is subject to change as the protocol evolves. Implementers SHOULD anticipate breaking changes and support migration strategies.
|
||||||
Loading…
Add table
Reference in a new issue