The Dominion Protocol

April 10, 2026 · View on GitHub

Epoch-Based Encrypted Content Access for Nostr

Version: 0.1.0 (Draft) Date: 2026-03-04 Status: Draft specification — seeking community feedback Licence: MIT


Abstract

Dominion is an open protocol for decentralised, tiered, revocable content access on Nostr. It enables content authors to encrypt data with epoch-based Content Keys (CKs) and distribute those keys to defined audiences via gift-wrapped Nostr events — without requiring any central authority, custom relay software, or new cryptographic primitives.

The protocol defines epoch-based key derivation, AES-GCM content encryption, gift-wrapped key distribution, audience tiers, and two Nostr event kinds. Any Nostr client can implement Dominion. Any content type can be vault-encrypted.

Tiered encrypted content for the open social web. Paywalls, private groups, and revocable access — all on standard Nostr relays.


Table of Contents

  1. Motivation
  2. Design Principles
  3. Core Concepts
  4. Epoch Content Keys
  5. Content Encryption
  6. Key Distribution
  7. Audience Tiers
  8. Revocation
  9. Event Kinds
  10. Metadata Privacy
  11. Performance
  12. Lightning-Gated Access
  13. Alignment with Existing NIPs
  14. Use Cases
  15. Limitations
  16. Reference Implementation

Designed Extensions (post-v1.0)

The following extensions are designed but not part of the v1.0 reference implementation. They live in spec/extensions/ so the v1.0 surface stays focused on what ships today.

  • Warden Relays — true instant revocation via NIP-42 AUTH-gated key stores
  • Quantum Vault — VMK + ML-KEM-768 decoupling of CK derivation from secp256k1

1. Motivation

The Access Control Gap on Nostr

Nostr content is either public or NIP-44 encrypted to specific recipients. There is no middle ground. Once a recipient has a decryption key, access cannot be revoked — the best you can do is stop issuing new keys. There is no mechanism for:

  • Audience-level access tiers — "friends", "close friends", "family", each seeing different content
  • Revocable access — remove someone's ability to decrypt future content
  • Paid content — subscription-based access with revocation on non-payment
  • Scalable encryption — encrypting to 500 followers without 500 separate NIP-44 operations

For Creators

Every creator on Nostr who wants to gate content today has no native primitive. Zaps are tips, not access control. There's no Patreon-equivalent that works without a platform taking a cut.

For Communities

Encrypted group communication on Nostr is unsolved at scale. Existing approaches (NIP-44 to each member) don't support tiers, revocation, or group membership changes without re-encrypting everything.

For Families

Parents sharing children's learning journals, photos, or milestones need granular control: full access for co-parents, limited access for grandparents, time-bounded access for teachers, and the ability to revoke any of these.

The Scalability Problem

Per-recipient encryption (NIP-44 to each person) works for DMs but doesn't scale:

RecipientsNIP-44 approachDominion approach
11 encryption1 encryption + 1 key share
1010 encryptions1 encryption + 10 key shares
100100 encryptions1 encryption + 100 key shares
1,0001,000 encryptions1 encryption + 1,000 key shares

Content is encrypted once. Only the lightweight key distribution scales with audience size.


2. Design Principles

  1. One key per epoch, not per item. A Content Key covers a time period (e.g. one week). Fifty posts in a week all use the same CK. This is what makes the system scale.

  2. Deterministically derived. CKs are derived from the author's private key material using HKDF. The author can always re-derive any CK — no key database to lose.

  3. Standard relays only (by default). The default path uses only standard Nostr relays and existing NIPs (NIP-44, NIP-59). No custom relay software required.

  4. Separation of content and access. Encrypted content propagates freely on any relay. Key distribution is a separate concern. Change who can decrypt without touching the content.

  5. Forward-only revocation is good enough. Stop distributing keys for new epochs. With weekly rotation, a revoked recipient loses access within 7 days. This matches how every E2E encrypted system works.

  6. Progressive sovereignty. Users start with managed infrastructure and can graduate to self-hosted or pure Nostr distribution. No lock-in at any level.

  7. Nostr-native. Built on secp256k1. Uses existing Nostr event infrastructure. Encrypted events are standard Nostr events — any relay stores them, any client can learn to decrypt them.

  8. Algorithm agility. Events are tagged with the asymmetric algorithm used for signing and key agreement (['algo', 'secp256k1']). When post-quantum algorithms become available, implementations can produce and consume events with different algorithm tags without breaking backward compatibility.


3. Core Concepts

How It Works

Author                                    Recipient
  │                                          │
  ├─ Derive epoch CK from private key        │
  ├─ Encrypt content with CK (AES-GCM)       │
  ├─ Publish encrypted event to relay         │
  ├─ Gift-wrap CK to each recipient ─────────┤
  │                                          ├─ Unwrap gift → get CK
  │                                          ├─ Fetch encrypted event
  │                                          └─ Decrypt with CK

  ├─ Next epoch: derive new CK
  ├─ Distribute to current recipients
  └─ Skip revoked recipients ─── revoked user can't decrypt new content

Key Insight

Content is encrypted once with an epoch-based Content Key. The CK is then distributed to recipients via gift-wrapped events. This separates the encryption operation (one-time) from the access control operation (per-recipient).

Terminology

TermDefinition
Content Key (CK)A 256-bit AES key used to encrypt content for a specific epoch
EpochA time period (default: one ISO week) during which a single CK is used
Epoch IDAn identifier for the epoch, format: YYYY-Www (e.g. 2026-W09)
Vault shareA gift-wrapped event containing a CK, sent to a specific recipient
TierAn audience level (e.g. family, connections, public) that determines CK distribution
Vault configA self-encrypted event storing the author's tier memberships and settings

4. Epoch Content Keys

Derivation

CKs are derived deterministically using HKDF-SHA256:

CK = HKDF-SHA256(
    ikm  = author's 32-byte private key (or key derived from mnemonic),
    salt = "dominion-ck-v1",
    info = "epoch:{epoch_id}:tier:{tier_name}",
    len  = 32
)

Epoch ID Format

Epoch IDs are ISO 8601 strings whose format depends on the configured length:

LengthFormatExampleMeaning
DailyYYYY-MM-DD2026-04-1313 April 2026
WeeklyYYYY-Www2026-W15Week 15 of 2026 (6–12 Apr)
MonthlyYYYY-MM2026-04April 2026

The three formats are visually distinct (the W prefix disambiguates weekly from monthly) and each maps to a single calendar period in UTC. Weekly is the default and matches NIP-78 epoch conventions used elsewhere in Nostr.

Why Deterministic?

  • No key database. The author's private key material is the only backup needed. Lose your device? Re-derive all CKs from your key.
  • Re-provisioning is cheap. If vault infrastructure changes, re-derive CKs and re-distribute. No migration of key material.
  • Offline derivation. CKs can be derived without network access. An offline author can encrypt content and distribute keys later.

Epoch Length

Epoch length is configurable per tier:

TierSuggested epochExposure windowRationale
High trust (family)Monthly30 daysLow churn, high trust
Moderate trust (connections)Weekly7 daysBalanced
Low trust (individual grants)Daily24 hoursTight exposure window

Implementations SHOULD default to weekly epochs. Implementations MAY support per-tier epoch configuration. The reference implementation ships helpers for all three lengths via getEpochIdForDate(date, length) and getCurrentEpochId(length), defaulting to weekly when no length is supplied.


5. Content Encryption

Algorithm

All content is encrypted with AES-256-GCM using the epoch CK.

Ciphertext Format

content = base64(iv || ciphertext || tag)
ComponentSizeNotes
IV12 bytesRandom, unique per encryption
CiphertextVariableAES-GCM encrypted content
Tag16 bytesAuthentication tag (appended by AES-GCM)

Event Tagging

Encrypted events MUST include a vault tag identifying the epoch and tier:

["vault", "<epoch_id>", "<tier>"]

This tells recipients which CK to use for decryption. Since CKs are derived per-epoch AND per-tier, both values are required for CK lookup. Events without a vault tag are either plaintext or use other encryption schemes (e.g. NIP-44).

Example encrypted event:

{
  "kind": 30078,
  "pubkey": "<author_pubkey>",
  "tags": [
    ["d", "journal-entry-2026-03-04"],
    ["vault", "2026-W10", "family"],
    // ... other tags
  ],
  "content": "dGhpcyBpcyBiYXNlNjQgZW5jb2RlZCBjaXBoZXJ0ZXh0..."  // base64(iv || ciphertext || tag)
}

Media Encryption

Binary content (images, video, documents) follows the same pattern:

  1. Compress media client-side (before encryption — server-side transcoding can't work on ciphertext)
  2. Encrypt with epoch CK (AES-256-GCM)
  3. Upload encrypted blob to a content-addressed server (e.g. Blossom)
  4. Embed the hash in the Nostr event

The content-addressed server stores only opaque ciphertext. It never sees plaintext.

Migration

Events encrypted with Dominion coexist with plaintext and NIP-44 encrypted events on the same relays. No batch migration is needed — new content uses Dominion, old content remains readable via its original method.


6. Key Distribution

Gift-Wrapped CK Shares (Default)

CKs are distributed to recipients using NIP-59 gift-wrapping:

Distribution Flow:

  Author                          Recipient
    │                                │
    ├─ Derive CK for epoch           │
    │                                │
    ├─ For each recipient:           │
    │   ├─ Create kind 30480 event   │
    │   │   (contains hex CK)        │
    │   ├─ NIP-44 encrypt to         │
    │   │   recipient's pubkey       │
    │   ├─ Seal in kind 13           │
    │   └─ Gift-wrap in kind 1059 ───┤
    │                                ├─ Unwrap kind 1059
    │                                ├─ Decrypt kind 13
    │                                ├─ Read kind 30480
    │                                └─ Extract CK

    ├─ Publish to standard relays
    └─ Done

Grant Scope

A grant distributes the current epoch's CK only. When granting access to a new recipient:

  • Only the current epoch CK is sent — never historical keys
  • An accidental grant exposes at most one epoch of content
  • Granting historical access is a separate, explicit action (send specific past epoch CKs)
  • New recipients see content from the grant date forward, not the entire history

Epoch Rotation

When a new epoch begins:

  1. Derive the new epoch CK
  2. Auto-distribute to all current tier members and individual grantees
  3. Skip revoked pubkeys
  4. Update local state to track the last distributed epoch

Implementations SHOULD trigger rotation on app load when the current epoch differs from the last distributed epoch.


7. Audience Tiers

Dominion supports Facebook-style audience tiers on a decentralised platform:

TierWho receives CKDistribution
PublicEveryoneNo encryption needed — standard plaintext event
ConnectionsMutual follows or curated listAuto-distribute on epoch rotation
Close friendsCurated listAuto-distribute on epoch rotation
FamilyExplicitly managed listAuto-distribute on epoch rotation
PrivateSelf onlyNo distribution — author-only journaling

Individual Grants

Independent of tiers. An author can grant CK access to any specific pubkey:

  • Stored as individual entries in vault config
  • Same gift-wrap distribution mechanism
  • Useful for: sharing with a specific person not in any tier, time-bounded access for a professional

Tier Membership

Tier memberships are stored in the author's vault configuration event (NIP-78, kind 30078), self-encrypted. Tier changes take effect at the next epoch rotation:

  • Add member: distribute current epoch CK immediately + include in future rotations
  • Remove member: stop distributing at next epoch rotation (forward-only revocation)

Per-Tier Epochs

Different tiers can use different epoch lengths. The CK derivation includes the tier:

CK = HKDF-SHA256(
    ikm  = author's private key,
    salt = "dominion-ck-v1",
    info = "epoch:{epoch_id}:tier:{tier_name}",
    len  = 32
)

This means the family tier CK and the connections tier CK are different keys, even for the same epoch. Content encrypted for the family tier cannot be decrypted by someone who only has the connections tier CK.


8. Revocation

Forward-Only (Default)

Revocation is forward-only: stop distributing CKs for new epochs to the revoked recipient.

Epoch lengthMax exposure after revocation
Daily24 hours
Weekly7 days
Monthly30 days

The revoked recipient retains any epoch CKs they already received. Content from those epochs remains accessible if they cached the key. This is the same model as every E2E encrypted system (Signal, WhatsApp, Matrix).

Revocation List

Revoked pubkeys are tracked in the vault configuration event (NIP-78, kind 30078). During epoch rotation, the distribution loop skips any pubkey in the revocation list.

True Revocation (Optional — Warden Relays)

For users who need instant revocation (custody disputes, institutional access, paid content with immediate cancellation), optional warden relay infrastructure is a designed extension to v1.0. See the Warden Relays extension for the full design.

Why Forward-Only Is Good Enough

  1. Weekly epochs cap exposure at 7 days. Most real-world scenarios don't need instant revocation.
  2. Grant = current epoch only. An accidental grant exposes at most one epoch.
  3. Daily epochs available. For low-trust individual grants, daily rotation gives a 24-hour window.
  4. No special infrastructure. Forward-only revocation works on standard Nostr relays with no custom software.

9. Event Kinds

Note: Kind numbers are proposals pending NIP allocation.

Kind 30480 — Vault Share

A parameterised replaceable event containing an epoch CK for a specific recipient. Distributed via NIP-59 gift-wrapping for metadata privacy.

{
  "kind": 30480,
  "pubkey": "<author_pubkey>",
  "created_at": 1709000000,
  "tags": [
    ["d", "2026-W10:family"],              // epoch ID + tier
    ["p", "<recipient_pubkey>"],          // who this share is for
    ["tier", "family"],                   // which audience tier
    ["algo", "secp256k1"],               // asymmetric algorithm (for future quantum migration)
    ["L", "dominion"],                     // protocol namespace label
    ["l", "share", "dominion"]             // protocol label
  ],
  "content": "<hex-encoded epoch CK>"     // 32 bytes = 64 hex chars
}

Tags:

TagRequiredDescription
dREQUIRED{epoch_id}:{tier} — parameterised replaceable identifier
pREQUIREDRecipient pubkey — who this share is for
tierREQUIREDAudience tier name (e.g. family, connections)
algoREQUIREDAsymmetric algorithm used for signing/key agreement (default: secp256k1)
LRECOMMENDEDProtocol namespace label (dominion)
lRECOMMENDEDProtocol label (share, namespaced under dominion)

Distribution: This event is NIP-44 encrypted to the recipient's pubkey, sealed in a kind 13 event, and gift-wrapped in a kind 1059 event (NIP-59). The recipient unwraps the gift to extract the CK.

Client behaviour:

  • On receiving a kind 30480 (via gift-wrap unwrapping), extract the CK and cache it locally
  • Use the d tag (epoch ID + tier) to match against vault tags on encrypted events
  • A newer event for the same d tag replaces the previous one (parameterised replaceable)

Example REQ filter:

// Subscribe to all vault shares from an author for a specific epoch and tier
["REQ", "vault-shares", {"kinds": [30480], "authors": ["<author_pubkey>"], "#d": ["2026-W10:family"]}]

// Subscribe to all vault shares from an author (any epoch/tier)
["REQ", "all-shares", {"kinds": [30480], "authors": ["<author_pubkey>"]}]

NIP-78 (Kind 30078) — Vault Configuration

A NIP-78 app-specific data event storing the author's vault settings. Self-encrypted (NIP-44 to own pubkey) — only the author can read it. Uses NIP-78 (kind 30078) with a namespaced d tag instead of a custom kind.

{
  "kind": 30078,
  "pubkey": "<author_pubkey>",
  "tags": [
    ["d", "dominion:vault-config"],
    ["encrypted", "nip44"],
    ["algo", "secp256k1"],
    ["L", "dominion"],
    ["l", "config", "dominion"]
  ],
  "content": "<NIP-44 self-encrypted JSON>"
}

Decrypted payload:

{
  "tiers": {
    "family": ["<pubkey1>", "<pubkey2>"],
    "connections": "auto",                    // auto = mutual follows
    "close_friends": ["<pubkey3>", "<pubkey4>"]
  },
  "individualGrants": [
    {
      "pubkey": "<pubkey5>",
      "label": "Maths tutor",                // human-readable label
      "grantedAt": 1709000000                 // unix timestamp
    }
  ],
  "revokedPubkeys": ["<pubkey6>"],
  "epochConfig": {
    "family": "monthly",
    "connections": "weekly",
    "close_friends": "weekly",
    "individual": "daily"
  },
  "blossomUrl": "https://blossom.example.com"  // optional media server
}

Fields:

FieldTypeDescription
tiersObjectMaps tier names to member lists. "auto" means derive from mutual follows. Note: programmatically adding a pubkey to an "auto" tier converts it to an explicit list, permanently replacing the auto-derivation behaviour. Implementing applications should guard against unintentional conversion.
individualGrantsArrayOne-off grants to specific pubkeys, independent of tiers.
revokedPubkeysArrayPubkeys to skip during CK distribution.
epochConfigObjectPer-tier epoch length. Values: "daily", "weekly", "monthly".
blossomUrlStringOptional content-addressed media server URL.

Tags on Encrypted Content Events

Any Nostr event encrypted with Dominion includes:

["vault", "<epoch_id>", "<tier>"]

Clients use this tag to determine which CK is needed. The epoch and tier together identify the exact CK required. If the client has the CK (received via kind 30480), it decrypts. If not, the content is inaccessible.


10. Metadata Privacy

The Problem with NIP-44

With standard NIP-44 encrypted events, the content relay sees:

  • Author pubkey
  • Recipient pubkey (in p tags or gift-wrap)
  • Timing of publication
  • Size and frequency patterns

A single relay has the full social graph of who communicates with whom.

How Dominion Improves This

Dominion splits knowledge across different entities:

EntitySeesDoes NOT see
Content relayAuthor pubkey, ciphertext, timingRecipients (no p tags on content)
Gift-wrap relayOuter gift-wrap metadataInner content, CK, tier info
RecipientCK, decrypted contentOther recipients' CKs

No single relay sees the full picture. The content relay doesn't know who can decrypt. The relay carrying gift-wrapped shares doesn't know what content they unlock.

Content Events Are Clean

Vault-encrypted events contain no recipient information:

{
  "kind": 30078,
  "pubkey": "<author>",
  "tags": [
    ["d", "some-identifier"],
    ["vault", "2026-W10", "family"]  // epoch + tier, no recipients
  ],
  "content": "<base64 ciphertext>"
}

Recipients are managed entirely through the separate gift-wrap channel. Adding or removing recipients doesn't touch the content event.

Tier Name Visibility

The vault tag on content events includes the tier name in cleartext: ["vault", "2026-W10", "family"]. This means relay operators can see which tier a piece of content was encrypted for, even though they cannot decrypt the content or identify recipients. For most use cases (creator paywalls, community groups) tier names carry no sensitive information. However, for privacy-sensitive deployments, implementations MAY use opaque tier identifiers (e.g. hashed or random strings) instead of human-readable names. The protocol treats tier names as opaque strings — any valid UTF-8 string works.


11. Performance

Overhead

OperationWithout DominionWith DominionDelta
PublishEncrypt + POSTEncrypt + POST + distribute CK shares+10–20ms per recipient
Read (first in session)Fetch + decryptFetch + unwrap gift + decrypt+20–50ms (one-time)
Read (cached)Fetch + decryptFetch + decrypt (CK cached)~0ms
RevokeN/AUpdate vault config<10ms

Optimisations

  • Session CK cache. Once a CK is unwrapped, cache it locally. All subsequent reads in the same epoch are instant.
  • High cache hit rate. One CK per epoch means a user reading 50 posts from the same week unwraps 1 gift, not 50.
  • Background prefetch. When loading a feed, prefetch CKs for visible epochs in the background. By the time the user scrolls, CKs are cached.
  • Batch distribution. When granting a new recipient, batch all epoch shares into a single session.

Realistic User Experience

First load of a vault-encrypted feed: ~50ms overhead (one-time CK unwrap). Every subsequent load in the same session: indistinguishable from unencrypted content. Most users will never notice the encryption layer exists.


12. Lightning-Gated Access

The epoch-based architecture maps naturally to paid content:

Subscription Model

Buyer pays Lightning invoice


Author's service confirms payment


Distribute current epoch CK to buyer (gift-wrapped)


Buyer decrypts vault-encrypted content


Next epoch: payment due again
  ├─ Paid → distribute new CK
  └─ Not paid → skip distribution → access stops

What This Enables

Use caseHow it works
Decentralised PatreonCreator tiers → vault tiers. Subscribers get CKs. No platform cut.
Paid newslettersVault-encrypted articles on Nostr relays. Subscribe = get epoch keys.
Course accessEducator encrypts curriculum. Students pay per term (per epoch).
Pay-per-articleSingle-epoch grant on payment. One Lightning payment → one CK.
Supporter content"Supporters" tier. Lightning payment → tier membership → CK distribution.

Why This Is Better Than Zaps

Zaps are tips after the fact. Vault gating is access control before the fact. The content is genuinely encrypted — there's no "view source" workaround.

Regulatory Note

Dominion is a key distribution protocol, not a payment processor. It must never custody, route, or intermediate funds. In a Lightning-gated access flow, payment occurs directly between the subscriber and the content creator's Lightning node. Dominion's only role is distributing the content key after the implementing application confirms payment externally. Any regulatory obligations arising from content monetisation (consumer rights, digital content directives, VAT on digital services) are the responsibility of the implementing application, not the Dominion protocol.


13. Alignment with Existing NIPs

Dominion builds on existing Nostr primitives and introduces minimal new surface area.

NIPRelevanceHow Dominion Uses It
NIP-01Basic protocolVault-encrypted events are standard Nostr events stored on any NIP-01 relay
NIP-44Versioned encryptionCK shares are NIP-44 encrypted to recipients; vault config is NIP-44 self-encrypted
NIP-59Gift wrappingCK distribution uses NIP-59 gift-wrapped events for metadata privacy
NIP-42AuthenticationWarden relays (optional) use NIP-42 AUTH to verify recipient identity
NIP-09Event deletionWarden relays honour deletion requests to support true revocation

New Surface Area

New elementTypePurpose
Kind 30480Parameterised replaceable eventCK share distribution
Kind 30078 (NIP-78)App-specific dataVault configuration (self-encrypted, d: dominion:vault-config)
["vault", "<epoch_id>", "<tier>"] tagContent event tagSignals Dominion encryption, epoch, and tier for CK lookup
["algo", "<algorithm>"] tagProtocol event tagIdentifies asymmetric algorithm (default: secp256k1). Enables post-quantum migration.
["L", "dominion"] / ["l", "...", "dominion"]Label tagsProtocol namespace

Why Not Existing NIPs?

Why not NIP-44 direct encryption? NIP-44 encrypts content to a single recipient. Encrypting to 100 recipients requires 100 separate NIP-44 operations per event. Dominion encrypts content once with an epoch CK and distributes the lightweight key separately — the scalability table in Section 1 quantifies this.

Why not NIP-EE / Marmot (MLS-based group encryption)? NIP-EE (now unrecommended, succeeded by the Marmot Protocol) uses MLS ratchet trees for secure group messaging with forward secrecy and post-compromise security. It is designed for chat — all group members are equal, there are no audience tiers, and clients must maintain ratchet tree state. Dominion is designed for content access control — audience tiers, stateless CK derivation (only needs private key + epoch + tier), and one-to-many content encryption. The two are complementary: Marmot handles real-time group messaging, Dominion handles tiered content publishing.

Why not NIP-29 relay-based groups? NIP-29 delegates access control to relay policy enforcement — the relay decides who can read. Dominion uses cryptographic enforcement — only CK holders can decrypt, regardless of which relay stores the event. NIP-29 also requires custom relay software, while Dominion works on any standard NIP-01 relay. The two are complementary: NIP-29 manages group membership at the relay level, Dominion manages content encryption at the cryptographic level.

Why not NIP-51 lists for tier membership? NIP-51 lists are published to relays and are visible to relay operators. Vault tier memberships (who is in your "family" or "close friends" list) are private — stored as NIP-44 self-encrypted data in the author's vault config (NIP-78). Publishing tier memberships via NIP-51 would leak the social graph that Dominion is designed to protect.

Interoperability

Any Nostr client can add Dominion decryption support with:

  1. Gift-wrap unwrapping (NIP-59) — ~50 lines
  2. AES-256-GCM decryption (WebCrypto) — ~30 lines
  3. Epoch CK caching — ~20 lines

Total: approximately 100 lines of code to read vault-encrypted content. The hard part (key derivation, distribution, tier management) is handled by the publishing client.


14. Use Cases

Creator Economy

Platform disruptedWhat Dominion replacesWhy it's better
PatreonSubscription tiersCreator holds keys, not platform. No 5–12% cut. No deplatforming.
SubstackPaid newsletter accessVault-encrypted posts on Nostr relays. Cancel = stop distributing CKs.
GumroadDigital product deliveryOne-time epoch CK grant = purchase receipt. Content on Blossom.
Ko-fiSupporter-only content"Supporters" vault tier. Lightning triggers CK distribution.

Communication

Platform disruptedWhat Dominion replacesWhy it's better
DiscordRole-based channel accessVault tiers = roles. No central server. Revoke = stop epoch keys.
Telegram groupsAdmin-managed groupsVault tiers replace admin kicks. Cryptographic, not policy-based.
Signal groupsEncrypted group messagingVault adds tiered access and revocation. Signal has neither.

Collaboration

Platform disruptedWhat Dominion replacesWhy it's better
Google WorkspaceShared docs with access controlVault-encrypted files. No provider reading your data.
NotionWorkspace sharingVault-encrypted knowledge base. Tiers = team/org/public.

Existing Nostr Apps (Immediate Adopters)

AppCurrent limitationDominion solution
Habla / YakihonneNo native paywallVault-gated articles. Tier = paid subscribers.
0xChatManual group adminVault tiers replace admin-managed groups.
Zap.streamStreams are all-or-nothingEpoch keys gate stream decryption per subscriber level.
Coracle / SnortAll content public or DM"Connections" tier = content visible only to mutual follows.

Industry Applications

IndustryUse caseHow Dominion helps
HealthcarePatient records shared with providersEpoch rotation = automatic access expiry for consultants
LegalClient-privileged documentsForward-only revocation today; M-of-N warden relays planned (see extension) for law firm dissolution scenarios
JournalismSource protection, embargo managementDead man's switch, time-locked epoch key release
AcademicPeer review, research collaborationVault-encrypted datasets, revocable on departure
HREmployee records, offboardingStop distributing epoch keys = clean access removal

Novel Primitives

PrimitiveDescription
Dead man's switchAuto-publish epoch keys if author fails to rotate on schedule
Time-locked contentDistribute CKs on a predetermined future schedule
Progressive disclosureUnlock content as users meet criteria (payment, reputation, completion)
DAO governanceProposals visible only to token holders; votes encrypted until tally
Escrow-based accessCK released on Lightning payment confirmation — no trusted intermediary
Reputation-gated accessTier membership based on web-of-trust score or proof-of-work

Bitcoin & Lightning Native

Use caseHow Dominion helps
OTC trading desksVault-encrypted order books. Tier = verification level.
Mining pool coordinationOperational data shared with members, revocable on exit.
Lightning channel backupsEncrypted on Blossom, vault-shared with backup contacts.
Collaborative custodyM-of-N vault shares map to multisig-style patterns.

15. Limitations

LimitationWhy it's acceptable
Forward-only revocation by defaultWeekly epochs cap exposure at 7 days. True instant revocation is a designed warden relays extension for users who need it. Same model as Signal/WhatsApp.
CK cached by recipientA recipient who caches a CK retains access to that epoch's content forever. This is inherent to all E2E systems — you can't un-show someone a message.
Epoch granularityAccess is per-epoch, not per-event. All content in an epoch shares one CK. For per-event access control, use NIP-44 directly.
Author must be online to distributeCKs are distributed by the author's client. If the author is offline for an entire epoch, new recipients won't get keys until the author comes online.
Key derivation requires private keyCKs are derived from the author's private key material. Implementations using NIP-46 (remote signing) must handle CK derivation at the signer, not the client.
No retroactive revocationRevoking a recipient doesn't un-encrypt content they've already decrypted. To truly revoke past access: re-encrypt with new CK, re-distribute, publish replacement events. Expensive but possible.

Quantum Readiness

Dominion's security posture against quantum computing is split across two layers:

LayerAlgorithmQuantum statusNotes
Content encryptionAES-256-GCMResistantGrover's algorithm reduces effective strength to AES-128 — still computationally infeasible
Key derivationHKDF-SHA-256ResistantHash-based; no known quantum speedup beyond Grover's quadratic
Shamir secret sharingFinite field arithmeticResistantInformation-theoretic security, not dependent on computational hardness
Event signingsecp256k1 (Schnorr/ECDSA)VulnerableShor's algorithm breaks elliptic curve discrete log in polynomial time
Key agreement (NIP-44)secp256k1 ECDHVulnerableSame vulnerability — shared secret derivation relies on ECDLP hardness

The symmetric layer is safe. Vault-encrypted content (AES-256-GCM) and deterministic key derivation (HKDF) are quantum-resistant. A quantum attacker cannot decrypt vault content from ciphertext alone.

The asymmetric layer is not. Event signing and NIP-44 key agreement both depend on secp256k1, which is vulnerable to Shor's algorithm on a sufficiently powerful quantum computer. This means:

  1. A quantum attacker could derive a Nostr private key from a public key
  2. With the private key, they could re-derive all epoch CKs (since derivation is deterministic from the private key)
  3. They could also forge new events — publishing fake vault shares or configurations

Mitigation: algorithm tagging. All Dominion events include an ['algo', 'secp256k1'] tag identifying the asymmetric algorithm used for signing and key agreement. This enables:

  • Parsers to distinguish pre- and post-quantum events
  • Migration tooling to identify events that need re-signing when post-quantum algorithms are adopted
  • Consumers to enforce minimum algorithm requirements (e.g. "only accept events signed with ML-DSA-65 or later")

When the Nostr ecosystem adopts post-quantum signing (likely tracking Bitcoin's eventual upgrade), Dominion implementations update the algo tag value. Events without an algo tag SHOULD be treated as secp256k1 for backward compatibility.

Timeline. The best current expert guidance places ECC-breaking quantum computers in the range of 2031–2045, with 2035 as the key planning date. The UK NCSC says organisations should complete migration to post-quantum cryptography by 2035; NIST has quantum-vulnerable public-key algorithms on a path to deprecation by the same date. The 2025 Global Risk Institute survey rates a cryptographically relevant quantum computer as "quite possible" within 10 years and likely within 15. More conservative estimates (e.g. MITRE, January 2025) push toward the 2050s, but the planning consensus centres on 2035. Note: this would not be a brute-force attack — Shor's algorithm solves the elliptic-curve discrete logarithm problem directly, which is qualitatively different from key-space exhaustion.

The algo tag is a zero-cost hedge: it adds one tag per event today and unlocks clean migration paths when the time comes.


16. Reference Implementation

The reference implementation is dominion-protocol, a standalone npm package providing the core cryptography (HKDF, AES-GCM, Shamir) and Nostr event layer as a two-layer library:

  • dominion-protocol — universal crypto primitives (HKDF, AES-GCM, Shamir, config)
  • dominion-protocol/nostr — Nostr event builders/parsers for kind 30480 and NIP-78

Dominion is designed as a standalone NIP. Any Nostr client can implement it independently. The protocol does not depend on any specific client.

Adoption Strategy

  1. Ship reference implementation as npm package
  2. Propose NIP as "Epoch-Based Encrypted Content Access"
  3. Pitch to Habla, 0xChat, Zap.stream as immediate adopters
  4. Let creator economy and enterprise use cases emerge organically
  5. The NIP succeeds if 2–3 other clients implement vault decryption

Contributing

Dominion is open source. Contributions, feedback, and NIP discussion are welcome.

  • Protocol specification: this document
  • Reference implementation: dominion-protocol
  • NIP proposal: pending (kind numbers are proposals)

This specification is a living document. It will evolve through community feedback and implementation experience.