Security model
Exactly how WHSPR protects a conversation.
An exact account of the design, including what it does not do. Privacy claims are only useful when they are precise.
Authentication: Sign-In with Solana
The server issues a random single-use nonce bound to the requesting domain and wallet address, valid for five minutes. Your wallet signs a human-readable message containing the domain, address, nonce, issue and expiry times. No transaction is ever requested.
The server verifies the Ed25519 signature against the wallet public key, checks domain, expiry and nonce, and atomically marks the nonce used so it cannot be replayed. A random session token is issued in an HttpOnly, Secure cookie; only its SHA-256 hash is stored. Sessions expire after seven days and are revoked on sign-out.
Identity keys, separate from your wallet
Your wallet private key is never used for encryption. On first use, the browser generates an X25519 key pair for encryption and an Ed25519 key pair for message signing. Your wallet signs a statement binding both public keys to your address.
Every client verifies that wallet signature locally before using any key it receives, so the server cannot substitute a contact’s keys without their wallet. Clients remember each contact’s fingerprint and show a visible warning if it changes; sending is blocked until you review the change.
Message encryption
Each message is encrypted with a fresh random 256-bit content key using XChaCha20-Poly1305. The conversation, message ID, sender and sender key are bound as associated data. The content key is wrapped separately for the recipient and for your own key, each with a fresh ephemeral X25519 key pair and HKDF-SHA256.
The sender signs the full envelope with their Ed25519 identity key. Recipients reject messages whose signature, key binding or authenticated encryption fails. Message IDs are unique per sender, so a replayed envelope is rejected by the database.
All primitives come from the independently audited @noble libraries. WHSPR does not implement its own cryptographic primitives.
Rooms and communities
Private rooms and token-gated communities use the same envelope as direct messages. The content key is wrapped separately for every member’s verified X25519 key, so the server stores only ciphertext and per-member wrapped keys. Group size is capped to keep every envelope verifiable on each device.
Membership is enforced by the server on every read and send. A member who leaves stops receiving new envelopes, but anything already delivered to them stays readable on their device.
Encrypted files
Files are encrypted in the browser with a fresh random key using XChaCha20-Poly1305 before upload. Only the ciphertext reaches storage. The file key, name and size travel inside the signed, encrypted message envelope, so storage never sees them in plaintext.
Downloads are served only to conversation members and are decrypted locally. A file that fails authentication is rejected.
Scheduled messages
A scheduled message is fully encrypted and signed in your browser at the moment you schedule it. The server holds the ciphertext and releases it to the conversation at the chosen time. It cannot read or change it, and you can cancel it before delivery.
Because the envelope is sealed when scheduled, it uses the recipients’ keys as they were then. If a recipient rotates keys before delivery, they may be unable to open it.
WHSP Access verification
Premium features are unlocked by verified WHSP holdings in the wallet you signed in with. The server reads balances from the Solana chain and prices from an independent source. Client-supplied balances are never trusted, and every premium action is checked again on the server.
Holding checks reveal your wallet’s WHSP balance to WHSPR and to its blockchain data provider. Balances on Solana are already public.
Known limitations
Forward secrecy is limited. Ephemeral keys protect against compromise of the sender’s keys, but there is no ratchet: anyone who obtains a recipient’s long-term X25519 key can decrypt past messages sent to it. If a device is lost, rotate your keys. A Double Ratchet based protocol is planned.
Metadata is visible to the service: wallet addresses, who talks to whom, room membership and names, message timing, scheduled delivery times, file sizes and IP addresses.
Disappearing messages are deleted from the server and hidden on clients after the timer, but cannot prevent screenshots, copies, or retention by a modified client.
Private keys are stored in this browser’s IndexedDB. Malicious browser extensions or a compromised device can read them. Your wallet cannot recover these keys; only an encrypted backup file can.
Key backup
Backups are encrypted in the browser with a key derived from your passphrase via scrypt (N=2^17, r=8, p=1), then XChaCha20-Poly1305, and downloaded as a file. WHSPR never receives the file or the passphrase.
Delivery and server checks
Messages sync by polling the API every few seconds rather than through a persistent socket. Read and delivery receipts are derived from per-participant sequence numbers.
All endpoints require a valid session, check conversation membership on every request, validate input sizes, and rate-limit sign-in and sending.