File 003 · The Blueprint
Don’t trust us. Check the math.
Most companies ask you to trust them. We'd rather show our work. This page is the actual design — the key hierarchy, the flows, the guarantees, and the parts we can't protect yet, stated just as plainly.
Last updated: August 2026 · Written by humans, checked against the code.
§ 01 · The System at a Glance
A courier who can’t open the safe.
Unlike Mail is a client for the mailbox you already own. On the web, your browser talks to our Rust server and our server talks to Google, Microsoft or Zoho on your behalf — a courier, and we designed the job so the courier carries the safe but never holds a key to it. The native apps go further and skip the courier: they talk to your provider directly (§ 07). Either way, everything we persist is ciphertext sealed under keys that only exist on your devices.
A mailbox reached over IMAP — Fastmail, iCloud, your company’s server, your own — takes the direct path and only the direct path. That connection is authenticated with a permanent full-mailbox password rather than a revocable token, so it belongs on your machine and nowhere else: the desktop app opens the socket itself, and our server never learns the host, the port, the password, or a single byte of the mail. It is the one provider arm the courier is not allowed to touch, which is also why it is desktop-only.
flowchart LR
D["your device<br/><small>the keys</small>"] -- "session cookie" --> S["our Rust server<br/><small>carries the safe</small>"]
S -- "OAuth2 + REST" --> P["Google · Microsoft · Zoho<br/><small>your mailbox</small>"]
S -- "opaque ciphertext only" --> DB@{ shape: cyl, label: "Postgres" }
D -. "native apps: direct calls" .-> P
D -. "desktop only: IMAP + SMTP<br/><small>server never in this path</small>" .-> I["any IMAP mailbox<br/><small>Fastmail · iCloud · your own server</small>"]§ 02 · Two Locks, Two Problems
Two different things need protecting.
Security claims get slippery when they blur what, exactly, is being protected. We protect two distinct things, with two distinct mechanisms:
- The credential that can read your mailbox. To act as your client we hold an OAuth token for your provider — long-lived, full-mailbox scope. It is the crown jewel, and Part I is how we store it so that even we can’t use it without you.
- The mail itself. Messages between Unlike Mail users are sealed end-to-end with post-quantum cryptography — Part II. Mail you exchange with people not on Unlike Mail is ordinary email, and we say so out loud (see what we can’t protect).
§ 03 · Part I — Token Custody
The zero-knowledge envelope.
Every key that matters is derived or unwrapped on your device, and wraps the next key down. The server participates in exactly one way: it stores blobs it cannot read.
flowchart LR PP["passphrase<br/><small>client only</small>"] -- "Argon2id + salt" --> KEK["KEK<br/><small>client only</small>"] PK["passkey PRF<br/><small>one per device, hardware-gated</small>"] -- "wraps" --> KEK KEK -- "wraps" --> DEK["DEK<br/><small>random 256-bit</small>"] DEK -- "AES-256-GCM" --> CT["stored ciphertext<br/><small>Postgres</small>"]
The KEK (key-encryption key) is derived from your passphrase with Argon2id — deterministic given the stored salt, so the same passphrase yields the same KEK on any device, and no key ever needs to be transferred between devices. The KEK wraps a random DEK (data-encryption key), which seals what we store. Each of your devices additionally wraps the KEK under its passkey’s PRF output, so day-to-day unlocking is one biometric gesture — no secret typed, nothing to keylog.
Who holds what
| Where | What it holds | For how long |
|---|---|---|
| Postgres | Wrapped DEK, per-device wrapped KEKs, KDF salts, sealed tokens & keys — all opaque ciphertext | At rest, permanently useless without you |
| Your device | The KEK and unwrapped private keys, inside an isolated crypto worker | While unlocked; nothing persisted by default |
| Server RAM | The working key + live token for your session | Session-scoped — evicted on logout or restart |
The guarantee ladder
“Encrypted” is doing a lot of work in most marketing. Here’s the actual ladder, and where we sit on it:
| Level | The server’s relationship to your data | DB leak | Live-server compromise |
|---|---|---|---|
| L1 | Encrypted at rest with a server key | Safe | Server can always decrypt — theatre |
| L2 | Password envelope, but the server unwraps it | Safe | Server briefly holds the master key |
| L3 — the web client | Client-side envelope; server holds no key, only ciphertext + transient session state | Useless to a thief | Only online web sessions exposed |
| L4 — the native apps | Device-keystore custody; the app calls your provider directly, the server never sees a token | Useless | Nothing to take |
No recovery. On purpose.
There is no master key, no “contact support to restore access,” no backdoor we could be forced to use. Lose every enrolled device and the passphrase, and your sealed history is gone — you re-connect your mailbox and start fresh. A recovery path for you would be a recovery path for anyone. We chose the version where mathematics doesn’t negotiate.
Inside the browser: one room holds the keys
Encrypting at rest isn’t enough if page scripts can read your keys while you’re unlocked. All key material lives in a dedicated crypto worker — a separate JavaScript realm the page can’t reach into — holding non-extractable WebCrypto keys. The app window can ask it to unlock or seal; it can never read the keys, and secrets travel only to our same-origin server.
flowchart LR A["app window · the UI<br/><small>sees no keys · sees no tokens · renders your inbox</small>"] -- "postMessage: setup / unlock / logout" --> W["crypto worker · the vault<br/><small>non-extractable keys · Argon2id · same-origin only</small>"] W -- "success / lock-state only" --> A
§ 04 · Part II — Sealing the Mail
OpenPGP’s idea. Post-quantum math.
The model is the one that made PGP legendary — every user has a keypair; you seal to the recipient’s public key; only their private key opens it. We kept the idea and replaced the math: ML-KEM-1024, the NIST-standardized post-quantum key-encapsulation mechanism (FIPS 203), hybridized with AES-256-GCM for the payload.
- At account creation, your device mints a unique ML-KEM keypair.
- Your public key goes into the server-side key registry — that’s what a public key is for.
- Your private key is wrapped under your KEK and only ever unwrapped on your devices. The registry holds locks, never keys.
flowchart LR
subgraph SEND["SEND · sealed on your device"]
direction TB
REG@{ shape: cyl, label: "public-key registry" }
REG -- "their public key" --> E["ML-KEM-1024<br/>encapsulate"]
E -- "shared secret" --> SS["AES-256-GCM<br/><small>seals body + subject</small>"]
SS --> CT["ciphertext"]
end
subgraph READ["READ · opened on theirs"]
direction TB
T["their device"] -- "ML-KEM decapsulate<br/><small>private key, on-device</small>" --> M["plaintext<br/><small>only they read it</small>"]
end
CT -- "rides your provider<br/><small>they carry it, can't open it</small>" --> TTo your provider, a sealed message is an ordinary email whose contents happen to be noise. They transport it, store it, and learn nothing. Decapsulation happens on the recipient’s device — the shared secret is never on the wire and never on our server.
Why post-quantum, today
Encrypted traffic is being recorded now to be broken later — the “harvest now, decrypt later” problem. Classical key exchange will not survive a cryptographically relevant quantum computer; lattice-based ML-KEM is built to. Sealing with it today means the mail you send this year isn’t next decade’s breach. We’d rather future-proof now than apologize later.
§ 05 · Passkey-First Trust
Hardware you own, not a password you remember.
Day-to-day, Unlike Mail unlocks with a passkey — your fingerprint, face, or security key, evaluated by hardware. The passkey’s PRF output unwraps your KEK; the KEK unwraps everything else. You type no secret, so there is no secret to phish, keylog, or reuse from a leaked password dump.
Enrolling a new device
- With your passphrase — enter it once; the new device derives the same KEK (same salt, same Argon2id), registers its own passkey, and never asks again.
- With a device you already trust — scan an authorization QR / code from any enrolled device and the credential is shared to the new one. No secret typed anywhere, trust flows hardware-to-hardware.
“Brute force isn’t on the menu.” The keys that matter are unwrapped by hardware-backed credentials — there is nothing to guess, so a weak password doesn’t become a weak vault. The one human-memorable secret in the system, the passphrase, is stretched through Argon2id: memory-hard by design, so offline guessing is priced in gigabytes of RAM per attempt, not luck. Your security leans on the hardware in your pocket, not on your creativity with special characters.
§ 06 · Threat Model
What must hold. In writing.
| # | Claim | Why it holds |
|---|---|---|
| T1 | A database leak is useless | A full dump yields wrapped keys and ciphertext. No key that opens them exists server-side. |
| T2 | The server holds no key for the at-rest data | The KEK never reaches us; working keys are RAM-only and session-scoped. A server compromise can’t unlock the store. |
| T3 | Page-level attacks can’t exfiltrate keys | Keys are non-extractable, held in an isolated worker, and secrets travel only same-origin. Script in the page can’t read or export them. |
§ 07 · The Honest Part
What we can’t protect — and won’t pretend to.
Residual risks · stated, not spun
Mail with people who aren’t on Unlike Mail is ordinary email. Sealing needs both ends. A message to a friend on ordinary webmail lives in plaintext at their provider, like all their other mail. We seal what can be sealed and never imply otherwise.
Services that host your mailbox can do one thing we can’t. Because they store the mail, they can encrypt all of it at rest against themselves — including a message from a stranger who has never heard of them. We hold none of your mail, which is exactly why your address stays yours, and exactly why our guarantee covers the messages both ends agree to seal rather than every byte in the box. That is a real trade, and the right one for most people, but it is a trade.
On the web, your live session lives on our server. A browser is not a secure home for API credentials — XSS is a permanent hazard — so the web client deliberately routes provider calls through our server, which must hold your working credential in RAM for exactly as long as you’re signed in. A live compromise of a running server could touch the sessions of web users online at that moment — never the store. The native apps don’t share this risk: they keep keys in the device keystore and call your provider directly, so your credentials never exist in server RAM at all — nothing to dump, even on a zero-day.
A compromised open tab can act as you, in that tab. Malicious script in a live web session can ask the worker to do authorized things while the tab is open. It still can’t read keys, persist access, or act from anywhere else. Web-only, again — a native app has no tab to hijack.
Losing everything means losing sealed history. No recovery is a feature with a cost, and the cost is yours to know about up front.
Every one of these has a plan or a reason. None of them has a euphemism.
§ 08 · The Stack
Built with things that don’t break.
| Layer | Technology | Why |
|---|---|---|
| Mail sealing | ML-KEM-1024 + AES-256-GCM | NIST-standardized post-quantum KEM, hybrid AEAD payload. |
| Key exchange | X25519 + ML-KEM hybrid | Classical + post-quantum — both must fall to break it. |
| Key derivation | Argon2id | Memory-hard. Guessing priced in RAM, not luck. |
| Device trust | WebAuthn passkeys (PRF) | Hardware-gated key unwrapping. Phishing-proof by construction. |
| Client core | Rust → WebAssembly | Memory-safe crypto. One buffer overflow and it’s all theatre. |
| Server | Rust (Axum) | The BFF that carries the safe. Fast, typed, boring on purpose. |
| Desktop | Rust + Tauri | Native performance. Your RAM isn’t free real estate. |
| Transport | TLS 1.3 + cert pinning | In-transit protection, no middleboxes in the middle. |
Every dependency pinned. Builds signed. The crypto core is Rust compiled to WebAssembly because we trust the browser’s sandbox, not a package registry’s supply chain. When you build a vault, you don’t use cardboard.
§ 09 · Trajectory
Where this goes next.
- Native everywhere (L4). Android and Windows already run the native model — keys in the OS keystore, direct provider calls, near-zero server dependency. iOS, macOS, and Linux join them next; on this path the web residuals above simply don’t exist, and the server shrinks toward a content-free relay: nothing to seize, nothing to subpoena.
- Origin hardening. Device-bound request signing, strict CSP and Trusted Types — shrinking the already-narrow live-tab residual.
- Provider reach (largely done). Google, Microsoft 365 and Zoho all sign in directly; the IMAP arm covers the long tail from the desktop app. What’s left is bringing IMAP setup to Android and running a compatibility pass across more hosted providers.
- Decentralized identity, eventually. Your keys, your address, no registry — not even ours.
Questions this page didn’t answer live in the FAQ, and the promises it makes are restated formally on Compliance & Trust.