Architecture
Overview
Relay is a two-component system: a mobile app that handles all cryptography and key management on-device, and a server that acts as a delivery relay and RPC proxy.
The critical design decision: all encryption, signing, and key derivation happens on the client. The server is intentionally limited to storing public data and forwarding encrypted payloads.
In plain English: Your phone does all the hard work — generating keys, encrypting messages, signing transactions. The server just passes things along. Think of it like a post office that delivers sealed envelopes. It knows where to send them, but it cannot open them.
Tech Stack
Mobile App
| Layer | Technology |
|---|---|
| Framework | React Native + Expo |
| Navigation | React Navigation (tabs + stack) |
| Cryptography | @noble/curves, @noble/hashes, @noble/ciphers, @scure/bip39 |
| Key storage | react-native-keychain (wallet), expo-secure-store (Signal) |
| Blockchain | @solana/web3.js |
| Real-time | WebSocket client |
| Local storage | AsyncStorage (encrypted via EncryptedStorage wrapper) |
Server
| Layer | Technology |
|---|---|
| Runtime | Node.js + TypeScript |
| Framework | Express |
| Database | PostgreSQL via Prisma ORM |
| Real-time | WebSocket (ws library) |
| Auth | JWT (access + refresh tokens) |
| RPC | Helius API proxy for Solana |
Data Flow
Sending a Message
Sending a Payment
In plain English: When you send a message, your phone encrypts it before it ever touches the network. The server holds the encrypted blob until the other person's phone picks it up and decrypts it. When you send money, the server builds the transaction but your phone signs it — the server never has the key to move your funds.
What the Server Holds
The server stores only what is strictly necessary to deliver encrypted messages and verify identity:
- Usernames and auth public keys — needed to route messages and verify login signatures.
- Signal pre-key bundles (public keys only) — needed so new contacts can establish an encrypted session.
- Encrypted ciphertext in transit — held temporarily until delivered, then automatically purged.
No private keys. No plaintext. No wallet addresses. No seed phrases. No PINs. No message history.
See Server Trust Model for a full breakdown of what the server never sees.