Your encrypted data might already be compromised. You just don't know it yet.
The attack is called "harvest now, decrypt later." Intelligence agencies and well-funded attackers are collecting encrypted traffic today, banking on quantum computers being able to break it tomorrow. If your data is encrypted with classical algorithms alone — RSA, ECDH, X25519 — that bet might pay off.
This isn't theoretical. NIST spent eight years evaluating post-quantum algorithms and finalized its first standards in 2024. The message was clear: start migrating now, not when quantum computers arrive.
We took that seriously. Metamorphic is a zero-knowledge encrypted habit tracker, and the data it protects — sobriety counters, mental health habits, fitness patterns — is the kind of data that stays sensitive for a lifetime. So we built metamorphic-crypto, an open-source Rust encryption library with hybrid post-quantum encryption, and it's running in production today.
Why hybrid?
A hybrid key encapsulation mechanism (KEM) combines a classical algorithm with a post-quantum one. In our case: X25519 + ML-KEM-768.
The reasoning is simple. ML-KEM (formerly CRYSTALS-Kyber) is NIST's primary post-quantum KEM standard. It's well-studied and conservative. But post-quantum cryptography is young. If a flaw is found in ML-KEM, the classical X25519 layer still protects your data. If quantum computers break X25519, the ML-KEM layer still holds. You need to break both to compromise the encryption.
The combined shared secret feeds into the symmetric layer — XSalsa20-Poly1305 for authenticated encryption, with keys derived through Argon2id where passwords are involved.
Version-tagged ciphertext
Algorithms change. Migration is inevitable. So every ciphertext blob produced by metamorphic-crypto carries a version tag — a prefix byte that identifies the encryption scheme used.
Version 1 is classical-only (X25519 + XSalsa20-Poly1305). Version 2 is hybrid post-quantum (X25519 + ML-KEM-768 + XSalsa20-Poly1305). When we decrypt, we read the tag first and select the right path automatically.
This means we can migrate users progressively. When a user logs in, the client checks whether they have hybrid keys. If not, it generates a new ML-KEM-768 keypair, encrypts it with their session key, and sends the public key and encrypted private key to the server. Then it re-seals their existing data with the hybrid scheme. The server never sees any plaintext during this process — it just stores updated ciphertext blobs.
If we ever need a version 3, the same mechanism works. No flag days, no forced migrations, no downtime.
Why Rust, compiled to WASM
Metamorphic is a web app. The zero-knowledge architecture means all encryption and decryption happens client-side, in the browser. That means the crypto library needs to run in JavaScript's environment.
We originally used libsodium-wrappers-sumo (the JS build of libsodium). It worked, but it didn't support ML-KEM, and extending it would have meant wrapping C code in JavaScript bindings ourselves.
Rust gave us several things at once:
- RustCrypto primitives — pure Rust implementations of X25519, XSalsa20-Poly1305, Argon2id, and ML-KEM-768. Well-audited, actively maintained, no C dependencies.
-
#![forbid(unsafe_code)]— the entire library is safe Rust, enforced at the compiler level. - wasm-pack compilation — one build step produces a WASM binary and JS bindings that run in any modern browser.
- UniFFI targets — the same Rust core can compile to native iOS and Android libraries when we build native apps. One cryptographic implementation, every platform.
The WASM module loads asynchronously on first use. Every function calls ensureReady() before executing, so the rest of the application doesn't need to care about initialization timing. The public API is identical to the old libsodium wrapper — same function names, same base64 string inputs and outputs. We swapped the implementation without changing a single call site.
The three-layer model
In production, user data is protected by three independent layers:
Client-side zero-knowledge encryption — data is encrypted in the browser with the user's keys before it ever leaves the device. The server receives and stores only ciphertext. This uses the hybrid post-quantum scheme for users who've migrated and classical for those who haven't yet.
Server-side application encryption — the Ecto fields are wrapped in AES-256-GCM via Elixir’s Cloak libraries, keyed to a server-side secret. This protects data at rest against database compromise, even though the server can't read the inner plaintext layer.
Database-level encryption — our infrastructure provider uses LUKS to implement full-disk encryption on the database volume, providing a third and final layer of encryption at rest.
An attacker who compromises the database gets AES-256-GCM ciphertext. An attacker who compromises the database and the server's Cloak key gets zero-knowledge ciphertext. They still can't read it. They'd need the user's password-derived key, which never leaves the browser.
What's in the open-source library
metamorphic-crypto contains the full cryptographic core:
- Hybrid KEM: X25519 + ML-KEM-768 key generation, seal, unseal
- Classical KEM: X25519 sealed boxes (NaCl-compatible)
- Symmetric encryption: XSalsa20-Poly1305 secret boxes
- Key derivation: Argon2id with configurable parameters
- Version-tagged ciphertext with automatic scheme detection
- Recovery key generation and encryption
- WASM build via wasm-pack, UniFFI scaffolding for future native targets
The library is MIT-licensed. If you're building something that needs post-quantum encryption in the browser, you can use it directly or use it as a reference for how to structure the hybrid KEM flow.
The trade-off
Zero-knowledge encryption with post-quantum protection means we can't offer server-side features that require reading your data. No AI that analyzes your journal entries. No recommendation engine based on your behavior. No aggregate analytics across users.
We think that's worth it. Your habits reveal who you were, who you are, and who you're trying to become. That data deserves encryption that will hold up not just today, but decades from now.
metamorphic.app · metamorphic-crypto on GitHub · Encryption deep-dive
Top comments (0)