Skip to main content

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

FeatureAES-GCMChaCha20-Poly1305
StandardNIST SP 800-38DRFC 8439 (IETF)
Key Size128, 192, 256-bit256-bit only
Nonce Size96-bit (recommended)96-bit (fixed)
Tag Size128-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 PerformanceGood (with NEON)Excellent
Side-Channel ResistanceVulnerable (without HW)Resistant
Implementation ComplexityHigh (GF multiplication)Low (simple ops)
NIST ApprovedYes (FIPS 140)No
AdoptionWidespread (TLS, IPsec)Growing (TLS 1.3, WireGuard)
Best ForServer w/ AES-NIMobile, Embedded, Software-only

Detailed Comparison

Performance

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

Performance Benchmarks

Desktop (Intel Core i7 with AES-NI)

AlgorithmThroughputKey GenTag Verify
AES-128-GCM4.2 GB/s0.01ms0.01ms
AES-256-GCM3.1 GB/s0.01ms0.01ms
ChaCha20-Poly13051.4 GB/s0.01ms0.01ms

Mobile (ARM Cortex-A76)

AlgorithmThroughputBattery (100 MB)
AES-128-GCM520 MB/s3.2 mAh
AES-256-GCM480 MB/s3.5 mAh
ChaCha20-Poly1305780 MB/s2.1 mAh

Embedded (ARM Cortex-M4, no crypto HW)

AlgorithmThroughputCode Size
AES-128-GCM8 MB/s~4 KB
AES-256-GCM6 MB/s~4 KB
ChaCha20-Poly130518 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