ChaCha20 is a stream cipher that achieves higher performance than AES on modern CPUs, especially on mobile devices and in software implementations.

Let’s see it in action. Imagine you need to encrypt a small piece of data, say, a secret message. Instead of breaking it into fixed-size blocks like AES does, ChaCha20 treats your message as a stream of bytes and encrypts it one byte at a time. It does this by generating a pseudo-random keystream that’s the same length as your message, and then XORing your message with this keystream. The magic is how it generates that keystream.

Here’s a simplified look at the core of ChaCha20, the ChaChaCore function, which is essentially a block cipher that runs on 512-bit (64-byte) blocks. It takes a 256-bit (32-byte) key, a 96-bit (12-byte) nonce, and a 32-bit block counter.

// This is a conceptual representation, not runnable Go code
func ChaChaCore(key []byte, nonce []byte, counter uint32, block []byte) {
    // State initialization (16 x 32-bit words)
    state := make([]uint32, 16)
    // ... fill state with constants, key, nonce, counter ...

    // Four rounds of operations
    for i := 0; i < 4; i++ { // ChaCha uses 20 rounds total, 4 rounds per block operation
        // Quarter round function applied to state
        // state[0] += state[4] ... etc.
        // ... intricate bitwise operations ...
    }

    // Add the initial state to the modified state
    // ...
    // The resulting 512-bit block is the keystream block
    // ...
}

The state is initialized with a fixed "quarter-round" constant, then the 256-bit key, the 96-bit nonce, and the 32-bit block counter. This 512-bit state is then mixed using a series of bitwise operations (additions, rotations, XORs) in what are called "quarter rounds." ChaCha20 performs 20 rounds of these quarter rounds (or 10 double-rounds). The final state is then added back to the initial state, and this 512-bit result is the keystream block. This block is then XORed with your plaintext data. To encrypt the next 64 bytes of your message, you simply increment the counter and repeat the process.

The real advantage of ChaCha20, especially the variant ChaCha20-Poly1305 (which adds message authentication), is its excellent performance on general-purpose CPUs. Unlike AES, which relies heavily on specific hardware instructions (like AES-NI) for speed, ChaCha20’s operations are simple additions, XORs, and rotations. These are operations that are fast on almost any processor, including the ARM processors common in mobile devices, and are highly parallelizable in software. This makes it a go-to for TLS 1.3, SSH, and many other protocols where speed and security are paramount, even without specialized hardware support.

The system solves the problem of needing a fast, secure, and widely implementable encryption algorithm. Traditional block ciphers like AES can be complex to implement efficiently in software and may perform poorly on platforms lacking dedicated hardware acceleration. ChaCha20 provides a strong cryptographic primitive using basic arithmetic and bitwise operations, making it portable and performant across a vast range of hardware.

The key to its design is the "quarter round" function, which is applied repeatedly. It’s a simple set of operations: a += b; a = rotl(a, 16); a ^= c; a ^= d;. This sequence is applied to pairs of 32-bit words within the 16-word state. The elegance is in how these simple operations, when repeated, create a diffusion and confusion effect strong enough for modern cryptography. The use of a 64-byte block size, combined with the counter, allows for very high throughput.

Most people understand that the nonce and key are critical inputs. What’s less obvious is how the 32-bit counter is used to derive unique 64-byte keystream blocks. This counter, starting at 0 for the first block and incrementing for each subsequent block, is a critical part of ensuring that even if you encrypt the same plaintext twice with the same key and nonce, you get different ciphertexts. Each increment of the counter effectively changes the input to the ChaChaCore function, producing a different keystream block.

The next concept you’ll likely encounter is authenticated encryption, specifically how ChaCha20-Poly1305 uses the ChaCha20 keystream to both encrypt data and provide integrity and authenticity.

Want structured learning?

Take the full Cryptography course →