Encryption
Trove encrypts everything that leaves your device. This page describes the primitives, where keys live, and what a relay can observe on the wire. The full implementation contract is in docs/CRYPTO_SPEC.md in the source.
What gets encrypted
Section titled “What gets encrypted”Anything that travels between devices or members of a writing group:
- Device-to-device sync of Manuscripts, Codexes, drafts, and Tome notes.
- Excerpts, comments, and chat shared inside a Circle (writing group).
- The MLS group state that maintains both of those.
On your disk, your writing sits as plain Markdown and TOML by default — so you can back it up, open it in other tools, or hand it to a co-writer. If you’d rather lock it all behind a passphrase, you can turn on at-rest encryption: it stays off until you switch it on, and when on it encrypts everything you write on that device. Full-disk encryption (FileVault, BitLocker, LUKS) is still worth using for everything else on the machine.
MLS — the transport
Section titled “MLS — the transport”Group encryption uses Messaging Layer Security (MLS), RFC 9420 — the IETF standard for end-to-end encrypted group messaging. The same standard underpins Apple iMessage and Cisco Webex.
Trove locks a single ciphersuite:
MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519Concretely:
| Primitive | Algorithm |
|---|---|
| KEM | DHKEM X25519 |
| AEAD | AES-128-GCM |
| Hash | SHA-256 |
| Signature | Ed25519 |
MLS gives us forward secrecy (compromising today’s keys does not reveal yesterday’s traffic) and post-compromise security (after a member’s device is compromised and the group commits, future traffic is private again).
The MLS implementation is openmls with the RustCrypto provider. No hand-rolled cryptography.
Identity and key derivation
Section titled “Identity and key derivation”Each account has a single 32-byte identity_seed, generated by the OS CSPRNG on first launch. Every long-lived keypair derives from it through HKDF-SHA-256 with a domain-separating label. That means a fresh device — once it knows the seed — recovers the same keys and rejoins your DeviceGroup.
Per-device leaf private keys live in the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service). They never leave the device.
What our relays see
Section titled “What our relays see”Trove runs Cloudflare Workers as federation relays. They perform no decryption. Their only crypto operation is verifying inbound ActivityPub HTTP Signatures so they know which Actor sent what.
A relay can see:
- That an Actor with handle
@you@trove.inkexists. - That some Actor sent a signed envelope to another Actor.
- The byte length of the ciphertext and the time it arrived.
A relay cannot see:
- Any plaintext you wrote — manuscripts, comments, chat, titles, anything.
- Your MLS group keys.
- Your
identity_seedor any key derived from it.
Recovery passphrase
Section titled “Recovery passphrase”When you choose to sync, Trove wraps your identity_seed under a passphrase you pick, so a fresh laptop can recover the account.
- KDF: Argon2id with parameters published in
docs/CRYPTO_SPEC.mdin the source. - AEAD for the wrapped seed: XChaCha20-Poly1305 (24-byte nonce, 16-byte tag).
- Verification is fail-closed — a wrong passphrase produces an AEAD tag mismatch and the client surfaces a generic error. The relay cannot distinguish “wrong passphrase” from “no such account”.
A 24-word Backup phrase (BIP39, English wordlist) encodes the identity_seed directly. If you lose both the passphrase and the phrase, the account is unrecoverable. Trove cannot reset it; we have no copy of the keys.
If Trove the company is gone
Section titled “If Trove the company is gone”Your library is plain Markdown and TOML in a folder you own. The app keeps writing, searching, and compiling offline forever — no relay required. Sync, Circles, and DMs need our hosted relay, but those are the only surfaces tied to it.
See also
Section titled “See also”- Threat model — what Trove protects against and where the limits are.
docs/CRYPTO_SPEC.mdin the source — implementation-level contract.docs/FEDERATION.mdin the source — the federation stack.