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. It has no native modules, prebuild step, or platform binaries to ship. These properties let it run in Expo, where the alternatives do not.
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. OpenE2EE Relay supplies managed encrypted delivery infrastructure. 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.
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@1.0.0 expo-secure-store expo-sqlite drizzle-ormimport { expoStore } from '@open-e2ee/signal-protocol-sdk/local/store/expo';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 in IndexedDB under your origin.
npm install @open-e2ee/signal-protocol-sdk@1.0.0import { indexedDbStore } from '@open-e2ee/signal-protocol-sdk/local/store/web';The SDK supports this adapter. 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, and relay development. Protocol state lives in an encrypted directory on disk.
npm install @open-e2ee/signal-protocol-sdk@1.0.0import { 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
A real encrypted round trip in six lines. No backend, no accounts.
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: X3DH, PQXDH, and the Double Ratchet, with post-quantum key agreement required by default. 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
If you want to see it work, go to the quickstart: two identities and a real ciphertext, with no infrastructure.
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 managed delivery, start with the OpenE2EE 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.
Licensed AGPLv3, with a commercial option: see licensing.