Signal Protocol SDK
The Signal Protocol in pure TypeScript, for Expo, browser, and Node applications — with explicit storage, transport, and trust boundaries.
This SDK implements the Signal Protocol in Pure TypeScript for Expo, React Native, browsers, and Node. Native modules provide encrypted storage.
The SDK generates and stores keys on the device, establishes sessions, ratchets, and hands your infrastructure ciphertext. It does not require a hosted service, and there is no configuration in which private keys or plaintext leave the device.
For production delivery, choose one of two separate paths. The OpenE2EE Signal Protocol Relay is the hosted delivery service, built to work with the SDK. A self-hosted adapter keeps delivery in infrastructure that you operate. Both use the same device-side protocol boundary. Neither receives plaintext or device private keys.
Try the playground
Open the playground to send an encrypted message and decrypt a reply. The page and developer console show actual results. You need no account or installation.
Start on your runtime
Pick one here. Every page with runtime-specific instructions remembers the choice, so you will not have to pick again.
The runtime this SDK exists for, and the one with the most mature adapter. Protocol state lives in a SQLCipher-encrypted database. Its key lives in the iOS Keychain or Android Keystore.
npm install @open-e2ee/signal-protocol-sdk@13.0.0 react-native-get-random-values expo-secure-store expo-sqliteimport { expoStore } from '@open-e2ee/signal-protocol-sdk/local/store/expo';Load react-native-get-random-values before the first SDK call, with import 'react-native-get-random-values'; at the top of the app entry. It gives the SDK its global random source. Requires a development build: SQLCipher does not run in Expo Go. Expo setup has the full bootstrap and the seven integration questions answered.
The fastest way to see the protocol work, and the hardest place to make strong claims about it. Protocol state lives under your origin, in an encrypted SQLite database in the origin private file system, or in IndexedDB where that file system is not available.
npm install @open-e2ee/signal-protocol-sdk@13.0.0 idbimport { webSqliteStore } from '@open-e2ee/signal-protocol-sdk/local/store/web-sqlite';The SDK supports both stores. The web SQLite store needs a CSP that allows 'wasm-unsafe-eval'. No storage choice fixes the fact that your origin ships the code that encrypts. Browser setup states that boundary in full.
Services, integration tests, CLIs, Electron apps, and relay development. Protocol state lives in a SQLCipher database on disk, and its key lives in a vault that you pass.
npm install @open-e2ee/signal-protocol-sdk@13.0.0 better-sqlite3-multiple-ciphersimport { nodeStore } from '@open-e2ee/signal-protocol-sdk/local/store/node';A Node client is a full participant with a real identity key, which puts that machine inside the encryption boundary. Node setup covers when that is the right call and when it is not.
Quickstart
Run an encrypted exchange between two identities through a Sandbox environment.
Build an encrypted Expo chat
The complete build, end to end.
How E2EE is architected
The model underneath, before you write code against it.
What the SDK owns
Identity and prekey generation. Session establishment and ratcheting: PQXDH and the Double Ratchet. Every new session uses post-quantum key agreement. Multi-device state via Sesame, and group messaging via sender keys. Safety-number generation and comparison. Validation at every storage, relay, and serialized-state boundary.
What your application owns
User identity and account policy. The runtime storage adapter, which is the only required adapter and the one place private keys exist. Delivery and public-key distribution infrastructure. Encrypted attachment persistence. Trust verification and the user experience around it: including what you show a user when a contact's identity key changes.
That split is deliberate and it is not going to move. The SDK will not silently choose a backup strategy, an escrow mechanism, or a trust policy on your behalf.
Where to start
To try the SDK, open the playground or follow the quickstart. The quickstart uses a temporary in-memory store and a Sandbox environment of the Signal Protocol Relay.
If you evaluate the SDK, read what E2EE actually protects and what the relay can still see first. Both pages let you compare the implementation with its claims. The second page identifies limits that can invalidate product promises.
If you integrate the SDK, start with choosing adapters. This decision shapes everything else.
If you want hosted delivery, start with the Signal Protocol Relay quickstart. It starts with device-owned development identity and one acknowledged message. Production identity, push, retention, and billing come afterward.
If you migrate from libsignal-protocol-javascript or @privacyresearch/libsignal-protocol-typescript, read the migration guide before you plan the work. There is no wire compatibility. The change requires a new architecture, and the guide states this fact in its first section.
Status
Independent implementation profile
This project is not affiliated with Signal Messenger LLC or Signal Technology Foundation. Compatibility with the published specifications is a design direction and a correctness oracle, not a promise of interoperability with the Signal Messenger service. The ML-KEM Braid tag differs from Signal Messenger's, so there is no wire compatibility with Signal Messenger either.
Dual-licensed under MIT or Apache-2.0, at your option: see licensing.