Signal Protocol encryption for Expo - wraps official libsignal library
npm install @toled/signal-expoSignal Protocol encryption for Expo/React Native - wraps the official libsignal library.
- End-to-end encryption using the Signal Protocol
- Key generation (identity keys, pre-keys, signed pre-keys)
- Session establishment via X3DH key agreement
- Message encryption/decryption with Double Ratchet
- Built on official Signal libraries (Swift + Kotlin bindings)
- Expo SDK 50+ or React Native 0.73+
- iOS 13.0+
- Android API 24+ (Android 7.0)
- Development build required (not compatible with Expo Go)
``bash`
npm install @toled/signal-expo expo-secure-store
Add the plugin to your app.json or app.config.js:
`json`
{
"expo": {
"plugins": ["@toled/signal-expo"]
}
}
Then generate native projects and run:
`bashGenerate native iOS/Android projects
npx expo prebuild --clean
$3
`bash
eas build --profile development --platform all
`Usage
`typescript
import {
generateIdentityKeyPair,
generateRegistrationId,
generatePreKeys,
generateSignedPreKey,
initialize,
createSession,
encrypt,
decrypt,
} from '@toled/signal-expo';// 1. Generate identity (do this once per device)
const identityKeyPair = generateIdentityKeyPair();
const registrationId = generateRegistrationId();
const preKeys = generatePreKeys(1, 100);
const signedPreKey = generateSignedPreKey(identityKeyPair, 1);
// 2. Initialize the protocol (required before encrypt/decrypt)
await initialize(identityKeyPair, registrationId, preKeys, signedPreKey);
// 3. Upload to your server (public keys only):
// - identityKeyPair.publicKey
// - registrationId
// - preKeys.map(k => ({ id: k.id, publicKey: k.publicKey }))
// - { id: signedPreKey.id, publicKey: signedPreKey.publicKey, signature: signedPreKey.signature }
// 4. Create session with recipient (using their pre-key bundle from server)
const recipientAddress = { name: 'user123', deviceId: 1 };
await createSession(recipientAddress, recipientPreKeyBundle);
// 5. Encrypt message
const plaintext = new TextEncoder().encode('Hello!');
const ciphertext = await encrypt(recipientAddress, plaintext);
// 6. Decrypt received message
const decrypted = await decrypt(senderAddress, receivedCiphertext);
const message = new TextDecoder().decode(decrypted.plaintext);
`API
$3
| Function | Description |
|----------|-------------|
|
generateIdentityKeyPair() | Creates a new identity key pair |
| generateRegistrationId() | Creates a 14-bit registration ID |
| generatePreKeys(start, count) | Generates pre-keys for X3DH |
| generateSignedPreKey(identityKeyPair, id) | Generates a signed pre-key |$3
| Function | Description |
|----------|-------------|
|
initialize(identityKeyPair, registrationId, preKeys, signedPreKey) | Initialize the protocol stores (required before encrypt/decrypt) |$3
| Function | Description |
|----------|-------------|
|
createSession(address, bundle) | Establishes session from pre-key bundle |
| hasSession(address) | Checks if session exists |
| deleteSession(address) | Removes a session |$3
| Function | Description |
|----------|-------------|
|
encrypt(address, plaintext) | Encrypts a message |
| decrypt(address, ciphertext) | Decrypts a message |Types
`typescript
interface IdentityKeyPair {
publicKey: Uint8Array; // 33 bytes
privateKey: Uint8Array; // 32 bytes
}interface ProtocolAddress {
name: string; // User identifier
deviceId: number; // Device ID
}
interface PreKeyBundle {
registrationId: number;
deviceId: number;
preKeyId: number | null;
preKeyPublic: Uint8Array | null;
signedPreKeyId: number;
signedPreKeyPublic: Uint8Array;
signedPreKeySignature: Uint8Array;
identityKey: Uint8Array;
}
``AGPL-3.0 (same as libsignal)
This library wraps the official Signal Protocol implementation from libsignal.