Skip to main content
Stream Ciphers Intermediate

Salsa20 and ChaCha20

Designed by Daniel J. Bernstein as a fast, secure, RC4-free alternative for software encryption, ChaCha20 now secures TLS 1.3 and WireGuard alike. Learn how its add-rotate-XOR "quarter round" builds a full cipher from pure arithmetic.

PL
Pashalis Laoutaris
August 4, 2026
6 min read

Interactive ChaCha20 Visualizer

🔐 ChaCha20 Keystream

6
Defaults are the official RFC 8439 test vector.
Enter text and click a button to start!
Double-round: / 10
Click Generate Keystream to run all 20 rounds.

Salsa20 and ChaCha20

Introduction

Salsa20 was designed by Daniel J. Bernstein and submitted to the eSTREAM competition (a European effort to identify strong stream ciphers) in 2005. Its refined successor, ChaCha20, published in 2008, tightened the diffusion of Salsa20’s core round function for better security per operation. Today, ChaCha20 — almost always paired with the Poly1305 authenticator, covered in its own guide — secures a huge share of modern encrypted traffic: it’s a mandatory cipher suite in TLS 1.3, the sole cipher used by the WireGuard VPN protocol, and Google’s preferred choice for mobile devices whose processors lack dedicated AES hardware acceleration.

Table of Contents

Why Not Just Use AES?

AES is excellent, but it leans on dedicated hardware (AES-NI) for its best performance — hardware that’s ubiquitous on modern laptops and servers but historically inconsistent across mobile and embedded chips. Software-only AES implementations, particularly naive table-lookup ones, are also vulnerable to cache-timing side-channel attacks. ChaCha20 was built from the ground up to be fast and constant-time in pure software, using only addition, rotation, and XOR — operations every processor handles efficiently and safely, with no table lookups to leak timing information through.

The ChaCha State

ChaCha20 arranges its internal working data as a 4×4 matrix of 32-bit words (16 words total, 64 bytes):

[ const  const  const  const ]
[  key    key    key    key  ]
[  key    key    key    key  ]
[ counter nonce  nonce  nonce ]
  • Constants: four fixed 32-bit words (spelling out the ASCII string “expand 32-byte k”) — identical for every ChaCha20 operation, everywhere.
  • Key: the 256-bit secret key, split into eight 32-bit words.
  • Counter: a 32-bit block counter, incremented for every 64-byte block of keystream generated — this is what lets ChaCha20 encrypt arbitrarily long messages, and what lets you seek to and decrypt any part of a message independently.
  • Nonce: a 96-bit number that must never repeat under the same key, ensuring two messages never share the same keystream.

The Quarter Round

The entire cipher is built from repeating one small function, the quarter round, applied to four of the sixteen state words (a, b, c, d) at a time:

a += b; d ^= a; d = rotate_left(d, 16)
c += d; b ^= c; b = rotate_left(b, 12)
a += b; d ^= a; d = rotate_left(d, 8)
c += d; b ^= c; b = rotate_left(b, 7)

A full ChaCha20 block runs 20 rounds — 10 pairs, alternating between a “column round” (applying the quarter round to each column of the state matrix) and a “diagonal round” (applying it to each diagonal). This alternating pattern is exactly what gives the cipher its name: Cha-Cha, evoking the diagonal dance-step pattern the state mixing follows.

Interactive Visualizer

The visualizer above runs a genuine ChaCha20 block function — all 20 rounds of real quarter-round arithmetic — and was verified byte-for-byte against Node.js’s own built-in ChaCha20 implementation before being published here.

Generating the Keystream

After 20 rounds, the (heavily scrambled) working state is added, word by word, back to the original input state — this final addition step is what makes the transformation practically impossible to invert without knowing the key. The result, serialized as 64 bytes, is one block of keystream, which gets XORed with 64 bytes of plaintext. To encrypt a longer message, the counter increments and the process repeats for as many 64-byte blocks as needed.

A Verified Example

Using the official IETF test vector from RFC 8439:

  • Key: 00:01:02:...:1f (the bytes 0 through 31 in sequence)
  • Nonce: 00:00:00:09:00:00:00:4a:00:00:00:00
  • Block counter: 1

produces a specific, publicly documented 64-byte keystream block — exactly what the visualizer above reproduces with these same default values.

Salsa20 vs. ChaCha20

The two ciphers share the same overall structure (four-word state, quarter rounds, 20-round default), but differ in the details:

  • Diffusion speed: ChaCha20’s quarter round mixes bits faster per round than Salsa20’s original design, giving ChaCha stronger security guarantees for the same round count.
  • State layout: ChaCha places its counter and nonce words differently within the 4×4 matrix, and its column/diagonal round pattern differs from Salsa20’s row/column pattern.
  • Adoption: ChaCha20 (particularly paired with Poly1305) became the standardized, widely deployed variant in TLS 1.3 and WireGuard; Salsa20 remains influential and secure but sees far less direct real-world protocol adoption today.

Security and Real-World Use

Neither Salsa20 nor ChaCha20 has ever suffered a practical break — both remain fully secure at their standard 20-round configuration, with even aggressively reduced-round variants (7-8 rounds) resisting the best published cryptanalysis, a substantial security margin. On its own, ChaCha20 provides confidentiality only; real-world deployments almost always pair it with the Poly1305 message authenticator (see the dedicated ChaCha20-Poly1305 guide) to also guarantee the ciphertext hasn’t been tampered with.

FAQ

Is ChaCha20 as secure as AES?

Yes — both are considered fully secure with no practical attacks against their standard configurations. The choice between them today is mostly about performance characteristics (hardware acceleration availability) and protocol requirements, not a security gap.

Why does WireGuard use ChaCha20 instead of AES?

WireGuard’s designers prioritized consistent, predictable performance across all platforms, including mobile and embedded devices without AES-NI hardware, where ChaCha20’s pure-software design performs reliably fast and remains naturally resistant to timing side-channels.

Can ChaCha20 be used without Poly1305?

Technically yes — ChaCha20 alone provides only confidentiality, no integrity protection. In practice it’s almost always deployed as part of the ChaCha20-Poly1305 AEAD construction, which adds tamper detection.

What does the “20” in ChaCha20 refer to?

The number of rounds (10 double-rounds of column + diagonal mixing) applied to the internal state for every 64-byte keystream block. Reduced-round variants like ChaCha8 and ChaCha12 exist for performance-critical contexts with a smaller security margin.

Who is Daniel J. Bernstein?

A cryptographer and mathematician responsible for a remarkable share of modern applied cryptography, including Salsa20/ChaCha20, the Curve25519 elliptic curve (used throughout the Signal Protocol and modern TLS), and the Poly1305 authenticator.

References

  1. Bernstein, D. J. “ChaCha, a variant of Salsa20.” 2008. Available at: https://cr.yp.to/chacha.html

  2. Bernstein, D. J. “Salsa20 specification.” eSTREAM submission, 2005. Available at: https://cr.yp.to/snuffle/spec.pdf

  3. RFC 8439. “ChaCha20 and Poly1305 for IETF Protocols.” IETF, 2018. Available at: https://datatracker.ietf.org/doc/html/rfc8439

  4. Donenfeld, J. A. “WireGuard: Next Generation Kernel Network Tunnel.” NDSS 2017 — explains the protocol’s choice of ChaCha20-Poly1305.