Skip to content

E2EE for pod content via did:nostr + NIP-44 / NIP-04 (no server-side changes required) #365

@melvincarvalho

Description

@melvincarvalho

Summary

JSS's did:nostr authentication makes end-to-end encryption available to pod clients today, with zero server-side changes. Clients sharing a pod can encrypt content using either NIP-44 (modern, authenticated, recommended) or NIP-04 (simple, legacy, widely deployed) — the same Nostr secp256k1 keypair that authenticates to JSS performs the ECDH key exchange. The pod stores ciphertext as ordinary RDF or blob content; JSS never sees plaintext.

This issue tracks the documentation work to make this pattern explicit for JSS users, and addresses the concern raised in solid/specification#788 (E2EE specification work item). The architectural insight: don't design new E2EE for Solid — leverage the existing Nostr primitives already deployed across the decentralized-web ecosystem.

Architecture: content-opaque storage, client-side encryption

Client A (did:nostr_A)              Client B (did:nostr_B)
    │                                    │
    │  shared_secret = ECDH(             │
    │    privkey_A, pubkey_B)            │
    │                                    │
    │  ciphertext = encrypt(             │
    │    content, shared_secret)         │
    │                                    │
    ├── PUT ciphertext ─────────┐        │
    │                           ▼        │
    │                  ┌────────────┐    │
    │                  │  JSS pod   │    │
    │                  │  (stores   │    │
    │                  │ ciphertext │    │
    │                  │ as RDF)    │    │
    │                  └────────────┘    │
    │                           │        │
    │                           └─ GET ──┤
    │                                    │
    │                  decrypt(ciphertext,│
    │                    ECDH(privkey_B,  │
    │                      pubkey_A))     │

The pod's role is content-opaque storage — exactly as today. The encryption boundary is between clients. JSS does not implement encryption, decryption, or key management. This is the architecturally correct shape for E2EE: the server is not in the trust boundary.

Protocols

NIP-44 (recommended for new applications)

The current Nostr E2EE standard. Production-grade, authenticated, side-channel-resistant.

  • Cipher: ChaCha20
  • Authentication: HMAC-SHA256
  • Key derivation: HKDF-SHA256 from ECDH shared secret
  • Padding: length-hiding, power-of-two padding scheme
  • Versioned wire format (current: v2)
  • Spec: https://github.com/nostr-protocol/nips/blob/master/44.md
  • External cryptographic review: design analyzed and reviewed pre-deployment

NIP-04 (simple, legacy, backwards-compatible)

The original Nostr DM encryption format. Simpler, widely deployed across older Nostr clients. Acceptable for backwards compatibility; new applications should use NIP-44.

JSS pods store ciphertext for both protocols identically — the wire format is just bytes from the server's perspective.

Ecosystem maturity

The Nostr E2EE ecosystem has substantial deployed infrastructure across multiple funded teams and cross-implementation interoperability:

  • White Noise (https://www.whitenoise.chat/) — Nostr-native E2EE messenger; NIP-44 in production
  • Damus, Amethyst, Nostur, Iris, Coracle — major Nostr clients with NIP-04 + NIP-44 implementations
  • Client libraries across languages: nostr-tools (JS), NDK (TS), nostr-rs / rust-nostr, nostr-php, python-nostr, nostr-sdk
  • Tens of thousands of users sending NIP-04/NIP-44 traffic daily across the Nostr relay network

Adopting these primitives for Solid pod content reuses that maturity rather than reinventing it. New cryptographic protocol design carries years of standardization, review, and ecosystem-bootstrap risk; pointing at NIP-44 carries none of that.

Implementation scope

Server-side: none. JSS already supports did:nostr authentication. Pod content storage is already content-opaque; ciphertext stores exactly like plaintext.

Documentation:

  1. JSS docs page "E2EE for pod content" — pattern explanation + example code for encrypting before PUT and decrypting after GET
  2. JSS docs page "Authentication via did:nostr" — link to E2EE as a downstream capability
  3. README: brief mention of E2EE as a first-class capability under did:nostr authentication

Optional (separate scope):

  • Reference client demo (NIP-44 + JSS pod) as examples/e2ee or in a separate repo
  • Helper utilities for the encrypt-then-PUT / GET-then-decrypt pattern
  • Compatibility tests against existing Nostr client libraries

Cross-reference: spec#788

solid/specification#788 proposes E2EE as a new spec work item. This pattern compresses that scope significantly: from "design new Solid-native E2EE protocol" to "document the bridge from did:nostr identity to existing NIP-44/NIP-04 primitives." The bridge already exists architecturally; only the documentation step is missing.

Acceptance

  • Docs page covering the did:nostr → NIP-44 pattern with example code
  • Docs page covering NIP-04 backwards-compatibility for clients that need it
  • README mention under did:nostr capabilities
  • (Optional) Reference client demo
  • Cross-link from JSS docs to NIP-44/NIP-04 specs and to spec#788

Metadata

Metadata

Assignees

No one assigned

    Labels

    nostrNostr relay, did:nostr auth, NIP-related

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions