Shade

A reusable module for end-to-end encrypted communication in your own apps — using the same kind of protocol as Signal.

X3DH Double Ratchet TypeScript Platform-agnostic crypto

What does the project do?

Shade is a monorepo that implements secure messaging encryption between two parties (for example browser and server, or two clients). Messages are encrypted so the transport layer (HTTP, WebSocket, etc.) only sees opaque bytes — not the content.

Core idea: Embed ShadeSessionManager (from @shade/core) together with a CryptoProvider (e.g. Web Crypto in the browser/Bun) and storage. Then call encrypt / decrypt per peer, just like in the demo code demo.ts.

The first message to someone new performs key agreement (X3DH). After that each message uses the Double Ratchet: fresh message keys and periodic DH steps provide forward secrecy (past messages do not survive key compromise) and post-compromise security (the system “recovers” over time after a compromise).

Packages (how they fit)

The protocol. X3DH, Double Ratchet, session shapes, errors. No platform crypto here — only the CryptoProvider interface.

  • ShadeSessionManager — high-level API: initialize, createPreKeyBundle, initSessionFromBundle, encrypt, decrypt
  • Symmetric encryption: AES-256-GCM with AAD from the ratchet header

Keys at a glance

Ed25519 signs the “signed prekey”. X25519 is used in Diffie–Hellman in X3DH and in the ratchet. One identity per device/user is typical.

Interactive flow: zero to encrypted message

Click “Next step” to walk through the sequence as Shade builds it. This mirrors ShadeSessionManager and the demo in the repo.

Sessions and messages

X3DH and Double Ratchet (brief)

X3DH solves “I want to talk to Bob now, but Bob may not reply until later”. Bob publishes a prekey bundle on the server. Alice fetches it, runs 3 or 4 DH operations (depending on whether a one-time key is used), and derives a shared root key both parties can reconstruct — without the server learning the secret.

Double Ratchet uses that root as a starting point. For each message (or when new DH keys spin), keys are derived; on the wire payloads are AES-GCM with authentication (AAD binds ciphertext to the ratchet header). The protocol also tolerates messages arriving out of order within limits (MAX_SKIP).

Signal specifications (English): X3DH · Double Ratchet.

Using Shade across projects

Treat Shade as three layers you combine as needed:

  1. Core + crypto provider + storage — the E2EE engine itself (runs in a client or a server process that must decrypt).
  2. Proto — when you want compact binary serialization.
  3. Transport + prekey server — when you want standardized key discovery and channels.

Reference path: bun demo.ts from the repo root shows a frontend/backend flow with memory storage and real crypto primitives.