Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
Gilbert Vernam's 1917 patent described a cipher that XORed a teleprinter tape of the message with a tape of random key characters — the first mechanised one-time pad and the first time anyone built encryption around the XOR operation. XOR is the fundamental operation of all modern symmetric cryptography for two reasons: it is its own inverse (encrypt and decrypt are the same circuit), and it is information-theoretically the only operation under which a uniformly random key bit produces a uniformly random ciphertext bit. Every stream cipher (RC4, ChaCha20, AES-CTR) is a Vernam cipher whose 'random tape' is replaced by a deterministic pseudorandom keystream. Understanding why XOR sits at the heart of this design — and what goes catastrophically wrong when you reuse the keystream (the so-called 'two-time pad') — is essential for understanding the long history of stream-cipher disasters from Venona to WEP.
The Vernam cipher operates bit by bit: each plaintext bit is XORed with the corresponding key bit. With a fresh random key per message it is a one-time pad; with a deterministic keystream from a short key it is a stream cipher. Either way, the encrypt and decrypt operations are identical — XOR is an involution.
// main.go — run: go run main.go
package main
import (
"crypto/rand"
"fmt"
)
func vernam(data, key []byte) []byte {
out := make([]byte, len(data))
for i := range data {
out[i] = data[i] ^ key[i]
}
return out
}
func main() {
// Single-message Vernam (= OTP)
pt := []byte("the quick brown fox")
key := make([]byte, len(pt))
rand.Read(key)
ct := vernam(pt, key)
if string(vernam(ct, key)) != string(pt) {
panic("round-trip failed")
}
// The "two-time pad" disaster: reusing the same key for two messages
pt1 := []byte("attack at dawn 06")
pt2 := []byte("retreat at noon00")
ct1 := vernam(pt1, key[:len(pt1)])
ct2 := vernam(pt2, key[:len(pt2)])
// Attacker computes pt1 XOR pt2 with no knowledge of the key
leaked := vernam(ct1, ct2) // this is pt1 XOR pt2
fmt.Println("pt1 XOR pt2:", leaked)
// If the attacker guesses any portion of pt1, they get pt2 for free in that range
guess := []byte("attack at dawn 06")
recoveredPt2 := vernam(leaked, guess)
fmt.Println("recovered pt2:", string(recoveredPt2))
}go run main.go