Why we chose XChaCha20-Poly1305 over AES-GCM for vault encryption

The cipher selection problem

When we designed TwinMail's vault encryption layer, we evaluated two primary candidates: AES-256-GCM and XChaCha20-Poly1305. Both are AEAD (Authenticated Encryption with Associated Data) ciphers with strong security properties. Both are widely deployed and audited.

The choice between them is not about raw security — both are considered secure under standard assumptions. The choice is about operational safety, nonce management, and the specific constraints of a local-first email client.

Nonce safety is the deciding factor

AES-GCM uses a 96-bit (12-byte) nonce. With random nonce generation, the birthday bound gives a collision probability of approximately 2^-32 after encrypting 2^32 messages under the same key. A nonce collision in AES-GCM is catastrophic: it leaks the authentication key and allows forgery of arbitrary ciphertexts.

XChaCha20-Poly1305 uses a 192-bit (24-byte) nonce. The birthday bound extends to approximately 2^96 messages before collision becomes probable. This is a qualitative difference, not merely a quantitative one.

Why nonce size matters for TwinMail

TwinMail's vault encrypts individual messages, overlay state operations, and sync blobs. A single vault may accumulate hundreds of thousands of encrypted records over its lifetime. With multiple devices generating encrypted records concurrently, the total record count grows faster than a single-device estimate would suggest.

Under AES-GCM with random nonces, a vault with 100,000 records has a nonce collision probability of roughly 1 in 10^19 — acceptable in isolation. But across millions of users, each with their own vault, the aggregate probability becomes concerning. This is the multi-key birthday problem: even if each individual vault is safe, the population-level risk grows linearly with user count.

XChaCha20-Poly1305 eliminates this concern entirely. The 192-bit nonce space is large enough that random generation is safe for any realistic workload.

Performance comparison

AES-GCM benefits from hardware acceleration via AES-NI instructions on x86 processors and ARMv8 cryptographic extensions. On hardware with these instructions, AES-GCM is typically 2-4x faster than ChaCha20-Poly1305 in raw throughput.

However, TwinMail's workload is not throughput-bound. Individual messages are typically 1-100 KB. Encrypting a 100 KB message takes approximately:

CipherTime (no HW accel)Time (with AES-NI/ARMv8)
AES-256-GCM12 us3 us
XChaCha20-Poly130515 us15 us

Both are sub-millisecond for any realistic message size. The throughput advantage of AES-GCM is irrelevant when the total encryption time per user action is measured in microseconds.

On devices without hardware AES acceleration — which includes some ARM-based devices and older hardware — ChaCha20 is actually faster than AES-GCM. This makes XChaCha20-Poly1305 a more portable choice.

Key derivation

TwinMail derives vault encryption keys from the user's passphrase using Argon2id with the following parameters:

  • Memory: 256 MB
  • Iterations: 4
  • Parallelism: 2
  • Output: 256-bit key

These parameters are tuned for a 1-2 second derivation time on a 2024 mid-range laptop. The derived key is used directly with XChaCha20-Poly1305 — no additional key schedule is required, unlike AES which requires an expanded key schedule computed from the raw key.

The libsodium advantage

XChaCha20-Poly1305 is the default AEAD cipher in libsodium, the most widely audited and deployed cryptographic library for application developers. Using the default, well-tested path reduces the surface area for implementation errors.

TwinMail uses libsodium's crypto_aead_xchacha20poly1305_ietf_encrypt and crypto_aead_xchacha20poly1305_ietf_decrypt functions directly, via Rust bindings in the Tauri backend. This means:

  • No custom cryptographic code
  • No cipher negotiation
  • No algorithm agility (which is itself an attack surface)

Decision summary

We chose XChaCha20-Poly1305 because:

  1. Nonce safety — 192-bit nonces eliminate multi-key birthday concerns at population scale
  2. Portability — consistent performance across hardware with and without AES acceleration
  3. Simplicity — libsodium default path, no key schedule, no cipher negotiation
  4. Auditability — single cipher, single library, no algorithm selection logic

The tradeoff is forgoing AES-NI acceleration on hardware that supports it. For TwinMail's workload, this is not a meaningful cost.

Request a technical preview

Get early access to evaluate TwinMail for your team.

12
Read trust documentation