Zero-knowledge server
The backend stores only ciphertext, wrapped keys and routing metadata. Server operators, hosting providers and platform staff cannot read messages.
Panthera is an end-to-end encrypted messenger built on the Double Ratchet protocol. Keys are generated and unlocked on your device — the server never sees plaintext, never holds a decryption key, and cannot be compelled to hand one over.
The backend stores only ciphertext, wrapped keys and routing metadata. Server operators, hosting providers and platform staff cannot read messages.
Your identity private key is wrapped with a KEK derived from your passphrase via Argon2id and only ever unwrapped in memory.
Double Ratchet rotates message keys on every send. A compromised session key cannot decrypt past or future messages.
Peer identity keys are pinned locally. Any change is surfaced as a visible warning and requires explicit re-trust.
Every primitive comes from libsodium. Nothing is hand-rolled. The server only ever handles opaque ciphertext.
| Purpose | Primitive | Implementation |
|---|---|---|
| Symmetric cipher | XChaCha20-Poly1305 (AEAD) | libsodium |
| Key exchange | X25519 (Curve25519 ECDH) | libsodium |
| Signatures | Ed25519 | libsodium |
| Message ratchet | Double Ratchet (Signal spec) | in-house impl · frozen vectors |
| Session init | X3DH with one-time prekeys | in-house impl |
| Password KDF | Argon2id (interactive params) | libsodium |
| Session KDF | HKDF-SHA-256 | libsodium |
| Randomness | crypto.getRandomValues + libsodium | browser CSPRNG |
| Fingerprint | SHA-256 of identity public keys | verifiable in-app |
Panthera implements the same protocol family used by Signal: X3DH for the initial handshake, Double Ratchet for forward secrecy and post-compromise recovery on every single message.
On sign-up, a long-term Ed25519/X25519 identity keypair is generated locally. The private key is wrapped with Argon2id(passphrase) and stored encrypted.
A signed prekey and a batch of one-time prekeys are published. The server refills them on demand — it only sees public bytes.
The initiator combines three or four DHs (identity, signed prekey, ephemeral, one-time) to derive a shared root key. TOFU pinning locks the peer identity.
Every send advances a symmetric chain; every reply performs a fresh DH to rotate the root. Message keys are used once and destroyed.
Ciphertext + ratchet header are stored on the server. Rows without a valid header are unreadable by design — the legacy sealed-box path has been fully removed.
Being explicit about the boundary is part of the guarantee.
Maintained by the Panthera team. This page lists app-visible controls that are currently enabled; it is not an independent certification.
Enabled on every conversation. Non-optional.
Server holds ciphertext + wrapped keys only. Row-level security enforced on every table.
Argon2id derives the KEK from your passphrase; identity keys are wrapped at rest.
Configurable idle + background timers wipe the in-memory KEK and private key.
Sign-out clears IndexedDB, CacheStorage, service worker and web storage.
Compare identity fingerprints in person or via QR to detect MITM.
Import a peer's identity by scanning their code — no server-side directory lookup needed.
Usernames are SHA-256 hashed with a versioned domain tag before hitting auth.
Every public table has explicit GRANTs and policies scoped to the authenticated user.
All network calls use TLS. The service worker is disabled in dev/preview to avoid stale ciphertext caches.
Frozen test vectors + RFC vectors run on every build to catch regressions in the ratchet.
Registration is passphrase-gated; anonymous auth is disabled.
Found a vulnerability? We want to hear from you. Report privately before publishing so we can protect users first.
Report suspected vulnerabilities privately to the maintainers before any public disclosure. Include reproduction steps, affected versions, and your preferred contact. We aim to acknowledge within 72 hours.