Documentation Index
Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Both AES-GCM and ChaCha20-Poly1305 are modern AEAD (Authenticated Encryption with Associated Data) algorithms providing confidentiality, integrity, and authentication in a single operation.
Key Decision Factors:
- Hardware availability (AES-NI vs pure software)
- Performance requirements
- Platform (server, mobile, embedded)
- Security requirements (side-channel resistance)
- Compliance needs (NIST, FIPS)
Quick Comparison
| Feature | AES-GCM | ChaCha20-Poly1305 |
|---|
| Standard | NIST SP 800-38D | RFC 8439 (IETF) |
| Key Size | 128, 192, 256-bit | 256-bit only |
| Nonce Size | 96-bit (recommended) | 96-bit (fixed) |
| Tag Size | 128-bit (default) | 128-bit (fixed) |
| Speed (Hardware) | Very Fast (3-5 GB/s) | Fast (1-2 GB/s) |
| Speed (Software) | Slow (50-200 MB/s) | Very Fast (1-2 GB/s) |
| Mobile Performance | Good (with NEON) | Excellent |
| Side-Channel Resistance | Vulnerable (without HW) | Resistant |
| Implementation Complexity | High (GF multiplication) | Low (simple ops) |
| NIST Approved | Yes (FIPS 140) | No |
| Adoption | Widespread (TLS, IPsec) | Growing (TLS 1.3, WireGuard) |
| Best For | Server w/ AES-NI | Mobile, Embedded, Software-only |
Detailed Comparison
Server (Intel/AMD with AES-NI)
AES-GCM (Hardware):
- Encryption: 3-5 GB/s
- Decryption: 3-5 GB/s
- Key derivation: Fast (hardware-accelerated)
ChaCha20-Poly1305 (Software):
- Encryption: 1-2 GB/s
- Decryption: 1-2 GB/s
- Key derivation: Same as AES-GCM
Winner: AES-GCM (2-3x faster with hardware)
Mobile (ARM with NEON)
AES-GCM (NEON):
- Encryption: 300-800 MB/s
- Decryption: 300-800 MB/s
- Battery: Higher consumption
ChaCha20-Poly1305 (Software):
- Encryption: 500 MB/s - 1 GB/s
- Decryption: 500 MB/s - 1 GB/s
- Battery: Lower consumption
Winner: ChaCha20-Poly1305 (faster, less battery)
Embedded (No Crypto Hardware)
AES-GCM (Software):
- Encryption: 5-20 MB/s
- Decryption: 5-20 MB/s
- Side-channel: Vulnerable
ChaCha20-Poly1305 (Software):
- Encryption: 10-50 MB/s
- Decryption: 10-50 MB/s
- Side-channel: Resistant
Winner: ChaCha20-Poly1305 (2-3x faster, more secure)
Security Properties
Confidentiality
AES-GCM:
- AES-128: ~2¹²⁸ security (quantum: ~2⁶⁴)
- AES-256: ~2²⁵⁶ security (quantum: ~2¹²⁸)
- NIST approved for classified data
ChaCha20-Poly1305:
- 256-bit key: ~2²⁵⁶ security (quantum: ~2¹²⁸)
- Not NIST approved (but widely trusted)
Winner: Tie (both provide strong confidentiality)
Authentication
AES-GCM:
- 128-bit GMAC tag
- Based on finite field multiplication
- Forgery probability: ~2⁻¹²⁸
ChaCha20-Poly1305:
- 128-bit Poly1305 tag
- Based on polynomial evaluation
- Forgery probability: ~2⁻¹²⁸
Winner: Tie (equivalent authentication strength)
Side-Channel Resistance
AES-GCM (Software):
- Vulnerable to cache-timing attacks
- Table lookups leak information
- Requires constant-time implementation
- Mitigated by AES-NI (hardware)
ChaCha20-Poly1305:
- Resistant to cache-timing attacks
- No table lookups (bitwise operations only)
- Constant-time by design
- No hardware required
Winner: ChaCha20-Poly1305 (inherently constant-time)
Example Attack (AES-GCM without AES-NI):
Cache-timing attack on software AES:
1. Attacker measures encryption time
2. Time variations reveal table lookup patterns
3. Patterns leak key information
4. After ~2^32 measurements, key recovered
ChaCha20-Poly1305 immune to this attack.
Implementation Complexity
AES-GCM
Complexity: High
// AES-GCM requires:
// 1. AES block cipher (complex S-box, key schedule)
// 2. Counter mode (CTR)
// 3. Galois field multiplication (GF(2^128))
// 4. Authentication tag computation (GMAC)
// Total: ~500-1000 lines of complex code
// Difficult to implement correctly
// Easy to introduce vulnerabilities
Common pitfalls:
- Cache-timing vulnerabilities
- Side-channel leaks in multiplication
- Incorrect tag verification
- Nonce handling errors
ChaCha20-Poly1305
Complexity: Low
// ChaCha20-Poly1305 requires:
// 1. ChaCha20 stream cipher (simple quarter-round)
// 2. Poly1305 MAC (polynomial evaluation)
// 3. Nonce/counter management
// Total: ~200-400 lines of simple code
// Easier to implement correctly
// Harder to introduce vulnerabilities
Advantages:
- No table lookups (simpler)
- No complex finite field math
- Easier to audit
- More resistant to implementation bugs
Winner: ChaCha20-Poly1305 (simpler, easier to audit)
Standards and Compliance
AES-GCM
Standards:
- NIST SP 800-38D
- FIPS 197 (AES)
- FIPS 140-2/140-3 approved
Compliance:
- Required for US government (FIPS)
- PCI DSS approved
- HIPAA approved
- Widely accepted worldwide
Adoption:
- TLS 1.2/1.3 (most common cipher)
- IPsec
- Disk encryption (BitLocker, FileVault)
- Widespread industry use
ChaCha20-Poly1305
Standards:
- RFC 8439 (IETF)
- RFC 7539 (TLS)
Compliance:
- Not NIST/FIPS approved
- Not required by regulations
- Trusted by cryptographic community
Adoption:
- TLS 1.3 (mandatory cipher suite)
- WireGuard VPN
- Signal Protocol
- OpenSSH
- Growing adoption
Winner: AES-GCM (for compliance), ChaCha20-Poly1305 (for modern protocols)
Nonce Management
Both algorithms require unique nonces
Same vulnerability: Nonce reuse catastrophic for both
// DANGEROUS for both algorithms
const key = generateKey();
const nonce = generateNonce();
const ct1 = encrypt(msg1, key, nonce); // OK
const ct2 = encrypt(msg2, key, nonce); // SECURITY FAILURE!
// Consequences:
// AES-GCM: Exposes keystream XOR, breaks authentication
// ChaCha20: Exposes keystream XOR, breaks authentication
Nonce size:
- AES-GCM: 96 bits recommended (can use 1 to 2⁶⁴ bits)
- ChaCha20-Poly1305: 96 bits (fixed)
Safe usage limit:
- Both: ~2³² encryptions per key (random nonces)
- Both: Unlimited with counter-based nonces
Winner: Tie (same requirements)
Use Case Recommendations
Server-Side Encryption (with AES-NI)
Recommendation: AES-GCM
// Use AES-256-GCM on servers with AES-NI
import * as AesGcm from '@tevm/voltaire/AesGcm';
const key = await AesGcm.generateKey(256);
const nonce = AesGcm.generateNonce();
const ciphertext = await AesGcm.encrypt(plaintext, key, nonce);
Why:
- 2-3x faster with hardware acceleration
- NIST approved (compliance)
- Widespread industry adoption
- Well-tested in production
Mobile Apps
Recommendation: ChaCha20-Poly1305
// Use ChaCha20-Poly1305 on mobile devices
import { chacha20poly1305 } from '@noble/ciphers/chacha';
const key = crypto.getRandomValues(Bytes32());
const nonce = crypto.getRandomValues(new Uint8Array(12));
const ciphertext = chacha20poly1305(key, nonce).encrypt(plaintext);
Why:
- Faster on ARM processors
- Lower battery consumption
- No hardware dependencies
- Better consistency across devices
Embedded Systems
Recommendation: ChaCha20-Poly1305
Why:
- Fast without crypto hardware
- Constant-time (side-channel resistant)
- Smaller code size
- Simpler to implement correctly
VPN/Tunneling
Recommendation: ChaCha20-Poly1305
Examples: WireGuard, OpenSSH
Why:
- Fast on all platforms
- Simpler protocol design
- Better mobile performance
- Constant-time security
Database Encryption
Recommendation: AES-GCM
Why:
- Hardware acceleration on servers
- Compliance requirements (FIPS)
- Industry standard
- Well-integrated with databases
Wallet Encryption
Recommendation: Either (based on platform)
Server/Desktop: AES-GCM
// Wallet encryption with AES-256-GCM
const salt = crypto.getRandomValues(Bytes16());
const key = await AesGcm.deriveKey(password, salt, 600000, 256);
const nonce = AesGcm.generateNonce();
const encryptedPrivateKey = await AesGcm.encrypt(privateKey, key, nonce);
Mobile: ChaCha20-Poly1305
// Better mobile performance
const key = await deriveKey(password); // PBKDF2 or Argon2
const nonce = crypto.getRandomValues(new Uint8Array(12));
const encrypted = chacha20poly1305(key, nonce).encrypt(privateKey);
File Encryption
Recommendation: Either (based on size)
Small files (<100 MB): Either works well
Large files (>100 MB): AES-GCM (with AES-NI)
- Faster throughput with hardware
- Better for bulk encryption
Web Applications
Recommendation: AES-GCM
// WebCrypto API provides native AES-GCM
import * as AesGcm from '@tevm/voltaire/AesGcm';
// Hardware-accelerated in browsers
const key = await AesGcm.generateKey(256);
const encrypted = await AesGcm.encrypt(data, key, nonce);
Why:
- Native browser support (WebCrypto)
- Hardware acceleration available
- No dependencies required
Desktop (Intel Core i7 with AES-NI)
| Algorithm | Throughput | Key Gen | Tag Verify |
|---|
| AES-128-GCM | 4.2 GB/s | 0.01ms | 0.01ms |
| AES-256-GCM | 3.1 GB/s | 0.01ms | 0.01ms |
| ChaCha20-Poly1305 | 1.4 GB/s | 0.01ms | 0.01ms |
Mobile (ARM Cortex-A76)
| Algorithm | Throughput | Battery (100 MB) |
|---|
| AES-128-GCM | 520 MB/s | 3.2 mAh |
| AES-256-GCM | 480 MB/s | 3.5 mAh |
| ChaCha20-Poly1305 | 780 MB/s | 2.1 mAh |
Embedded (ARM Cortex-M4, no crypto HW)
| Algorithm | Throughput | Code Size |
|---|
| AES-128-GCM | 8 MB/s | ~4 KB |
| AES-256-GCM | 6 MB/s | ~4 KB |
| ChaCha20-Poly1305 | 18 MB/s | ~2 KB |
Migration Guide
From AES-GCM to ChaCha20-Poly1305
// Before (AES-GCM)
import * as AesGcm from '@tevm/voltaire/AesGcm';
const key = await AesGcm.generateKey(256); // 32 bytes
const nonce = AesGcm.generateNonce(); // 12 bytes
const ct = await AesGcm.encrypt(pt, key, nonce);
// After (ChaCha20-Poly1305)
import { chacha20poly1305 } from '@noble/ciphers/chacha';
const key = crypto.getRandomValues(Bytes32()); // 32 bytes
const nonce = crypto.getRandomValues(new Uint8Array(12)); // 12 bytes
const ct = chacha20poly1305(key, nonce).encrypt(pt);
Changes:
- Key size: Always 32 bytes (256-bit)
- Nonce size: Same (12 bytes)
- API: Similar pattern
- Output format: Same (ciphertext || tag)
From ChaCha20-Poly1305 to AES-GCM
// Before (ChaCha20-Poly1305)
import { chacha20poly1305 } from '@noble/ciphers/chacha';
const ct = chacha20poly1305(key, nonce).encrypt(pt);
// After (AES-GCM)
import * as AesGcm from '@tevm/voltaire/AesGcm';
const key = await AesGcm.importKey(keyBytes); // Convert key
const ct = await AesGcm.encrypt(pt, key, nonce);
Changes:
- Key handling: Use CryptoKey (async)
- API: Async operations
- Performance: Potentially faster (with AES-NI)
Decision Matrix
Choose AES-GCM if:
- ✓ Running on server with AES-NI
- ✓ NIST/FIPS compliance required
- ✓ Industry standard needed
- ✓ Hardware acceleration available
- ✓ Integrating with existing systems
Choose ChaCha20-Poly1305 if:
- ✓ Running on mobile/embedded
- ✓ No crypto hardware available
- ✓ Constant-time execution critical
- ✓ Simplicity/auditability important
- ✓ Better software performance needed
Choose either if:
- ≈ Standard security requirements
- ≈ Both algorithms available
- ≈ Performance acceptable for both
- ≈ No specific compliance requirements
Hybrid Approach
Use both algorithms based on platform:
// Platform-specific encryption
function encrypt(plaintext, key, nonce) {
if (hasAESNI()) {
return AesGcm.encrypt(plaintext, key, nonce);
} else {
return ChaCha20Poly1305.encrypt(plaintext, key, nonce);
}
}
// Detect AES-NI support
function hasAESNI() {
// Server: Check CPU flags
// Browser: Test performance
// Mobile: Assume ChaCha20 better
return platform === 'server' && cpuHasAESNI;
}
Summary
Best Overall:
- AES-GCM: Server, compliance, hardware available
- ChaCha20-Poly1305: Mobile, embedded, software-only
Security: Both provide equivalent security when used correctly
Performance: AES-GCM faster with hardware, ChaCha20 faster without
Simplicity: ChaCha20-Poly1305 simpler to implement correctly
Compliance: AES-GCM required for FIPS, ChaCha20 not approved
Recommendation: Use platform-appropriate algorithm, or default to AES-256-GCM for compatibility.
References