Try it Live
Run ChaCha20-Poly1305 examples in the interactive playground
Overview
ChaCha20Poly1305 is an authenticated encryption algorithm combining ChaCha20 stream cipher with Poly1305 MAC, optimized for software implementations. Ethereum context: Not on Ethereum - High-performance alternative to AES-GCM for encrypted communications and storage. Key advantages over AES-GCM:- Fast in software (no hardware requirements)
- Constant-time operations (side-channel resistant)
- Simpler implementation (easier to audit)
- Better mobile/embedded performance
- No AES hardware acceleration available
- Constant-time execution is critical
- Running on mobile/embedded devices
- Simplicity and auditability matter
Status Note
ChaCha20-Poly1305 is not yet implemented in Voltaire. This documentation describes the specification and planned implementation based on RFC 8439. For production use, consider:- AES-GCM (currently implemented in Voltaire)
- @noble/ciphers - Pure TypeScript implementation
- libsodium.js - WebAssembly wrapper for libsodium
Specification
Standard: RFC 8439 (June 2018) Parameters:- Key size: 256 bits (32 bytes) only
- Nonce size: 96 bits (12 bytes)
- Tag size: 128 bits (16 bytes)
- Block size: 64 bytes (ChaCha20)
- Encrypt plaintext with ChaCha20 stream cipher
- Compute Poly1305 MAC over ciphertext and AAD
- Output ciphertext + 16-byte authentication tag
How It Works
ChaCha20 Stream Cipher
ChaCha20 generates a pseudorandom keystream from:- 256-bit key
- 96-bit nonce
- 32-bit counter (starts at 1)
- Fast in software (bitwise operations)
- Constant-time (no table lookups)
- Designed by Daniel J. Bernstein
Poly1305 MAC
Poly1305 is a one-time authenticator:- 256-bit one-time key (derived from ChaCha20)
- Processes message in 16-byte chunks
- Computes MAC using modular arithmetic (mod 2¹³⁰ - 5)
Combined AEAD Construction
Planned API
Security Properties
Confidentiality
IND-CPA Security:- Ciphertext reveals no plaintext information
- Requires unique nonces (never reuse!)
- 256-bit key provides strong security
- No known attacks better than brute-force (2²⁵⁶ operations)
- Post-quantum: Reduced to ~2¹²⁸ (Grover’s algorithm)
Authentication
Unforgeability:- 128-bit authentication tag
- Poly1305 is provably secure (one-time MAC)
- Forgery probability: ~2⁻¹²⁸ per attempt
Side-Channel Resistance
Constant-Time Operations:- No secret-dependent branches
- No table lookups (unlike AES without hardware)
- Resistant to cache-timing attacks
- AES (software): Vulnerable to cache-timing attacks
- ChaCha20: All operations constant-time by design
Comparison with AES-GCM
| ChaCha20-Poly1305 | AES-GCM | |
|---|---|---|
| Standard | RFC 8439 (IETF) | NIST SP 800-38D |
| Key Size | 256-bit only | 128, 192, 256-bit |
| Nonce Size | 96-bit (12 bytes) | 96-bit recommended |
| Tag Size | 128-bit (16 bytes) | 128-bit (can truncate) |
| Speed (HW) | Slower | Faster (AES-NI) |
| Speed (SW) | Faster | Slower |
| Mobile | Excellent | Good (if AES support) |
| Side-Channels | Resistant | Vulnerable (without AES-NI) |
| Simplicity | Simpler | More complex |
| Adoption | TLS 1.3, WireGuard | TLS, IPsec, widespread |
- Mobile/embedded systems
- Software-only environments
- Constant-time requirements
- Prefer simplicity/auditability
- Hardware acceleration available (AES-NI)
- NIST compliance required
- Legacy system compatibility
- Slightly faster with hardware
Nonce Management
CRITICAL: Never reuse nonces! Same nonce reuse attack as AES-GCM:- Exposes XOR of plaintexts
- Breaks authentication (Poly1305 key reuse)
- Complete security failure
Security Considerations
Critical Requirements
- Unique nonces: Never reuse with same key
- Cryptographically secure random: Use
crypto.getRandomValues() - Key protection: Store keys securely (encrypted, HSM, KMS)
- Key rotation: Rotate before 2⁴⁸ messages (random nonces)
Nonce Collision Risk
Random nonces:- 96-bit nonce space: 2⁹⁶ possible values
- Birthday paradox: ~50% collision after 2⁴⁸ messages
- Safe for: <2³² messages per key (~4 billion)
- No collisions (deterministic)
- Safe for: Up to 2⁹⁶ messages (practically unlimited)
Common Vulnerabilities
1. Nonce reuse:Use Cases
VPN/WireGuard
WireGuard uses ChaCha20-Poly1305 for:- Fast encryption on all platforms
- Constant-time operations (security)
- Simple implementation (fewer bugs)
TLS 1.3
ChaCha20-Poly1305 is mandatory cipher suite in TLS 1.3:TLS_CHACHA20_POLY1305_SHA256- Used when AES hardware unavailable
- Better mobile performance
Mobile Apps
Ideal for mobile encryption:- Fast on ARM processors
- Low battery consumption
- Constant-time (security)
Secure Messaging
Used by Signal, WhatsApp for:- End-to-end encryption
- Fast message encryption
- Strong authentication
Cryptocurrency Wallets
Encrypt private keys with user password:- Derive key from password (PBKDF2/Argon2)
- Encrypt private key
- Store encrypted wallet
Performance
Throughput (typical)
Desktop (Intel/AMD):- ChaCha20-Poly1305: ~1-2 GB/s (software)
- AES-GCM (AES-NI): ~3-5 GB/s (hardware)
- ChaCha20-Poly1305: ~500 MB/s - 1 GB/s
- AES-GCM (NEON): ~300 MB/s - 800 MB/s
- ChaCha20-Poly1305: ~10-50 MB/s
- AES-GCM: ~5-20 MB/s
Implementation Status
Current: Not yet implemented in Voltaire Planned:- Pure TypeScript implementation
- WASM implementation (performance)
- Zig implementation (native library)
RFC 8439 Test Vectors
Test Vector 1: Basic Encryption
Test Vector 2: With AAD
Best Practices
DO
✓ Use unique nonces for each encryption ✓ Usecrypto.getRandomValues() for nonces/keys
✓ Store nonce with ciphertext (not secret)
✓ Rotate keys periodically (<2⁴⁸ messages)
✓ Handle decryption errors gracefully
✓ Use strong passwords for key derivation
✓ Clear sensitive data from memory
DON’T
✗ Never reuse nonces with same key ✗ Never use predictable nonces (timestamp only) ✗ Never useMath.random() for crypto
✗ Never store keys in plaintext
✗ Never ignore decryption errors
✗ Never exceed 2⁴⁸ messages per key
✗ Never commit keys to version control
Error Handling
All ChaCha20Poly1305 functions throw typed errors that extendCryptoError:
| Error | Code | When |
|---|---|---|
InvalidKeyError | INVALID_KEY | Key not 32 bytes |
InvalidNonceError | INVALID_NONCE | Nonce not 12 bytes |
DecryptionError | DECRYPTION_FAILED | Auth tag verification fails, wrong key/nonce/AAD, or ciphertext too short |
ChaCha20Poly1305Error | CHACHA20_POLY1305_ERROR | Generic encryption failure |
name- Error class name (e.g.,"DecryptionError")code- Machine-readable error codemessage- Human-readable descriptiondocsPath- Link to relevant documentation

