Encryption
mutande seals handoffs on your device before anything reaches the cloud. The hub only ever stores an envelope (ciphertext + per-device key wraps), never plaintext.
Building blocks
We use well-known primitives — not a custom cipher:
| Role | Technology | Reference |
|---|---|---|
| Content encryption | ChaCha20-Poly1305 (AEAD) | IETF RFC 8439 |
| Device key agreement / wrapping | X25519 + NaCl-style crypto_box (ChaChaBox) | RFC 7748 · NaCl |
| Private keys (Mac) | macOS Keychain | Apple platform crypto |
Libraries are standard Rust crates (chacha20poly1305, crypto_box) — the same families used widely in messaging and TLS ecosystems.
Seal (send) — shape only
- Resolve recipients to device public keys (handles expand outside crypto).
- Encrypt the bundle once → content ciphertext.
- Wrap the content key to each device pubkey →
wraps[]. - Ship an envelope: ciphertext + wraps (+ optional blob ref).
Open (receive)
Only a device that holds a matching private key can unwrap its wrap and decrypt the content.
Why wrap-to-N
- One seal scales to many devices without re-encrypting the payload per recipient.
- Adding a device means another wrap, not another content ciphertext.
We intentionally keep wire-format and implementation details out of this page — the trust claim is standard crypto + keys never leave the device, not a proprietary algorithm story.
How you can check
| Check | What it proves |
|---|---|
| Safety numbers | You’re sealing to the contact’s published key (not a lookalike) |
| Hub only delivers envelopes | Operators see ciphertext and routing metadata — see what the hub sees |
| Local seal before upload | Large files are encrypted before the presigned PUT to object storage |
A compromised AI host or unlocked Mac can still see plaintext on that machine — mutande protects the path between devices, not a rooted endpoint.
Related: large files, security overview.