"Through 20 years of effort, we've successfully trained everyone to use passwords that are hard for humans to remember, but easy for computers to guess." — xkcd 936
A bulk xkcd-936-style passphrase generator in Go. Spits out
correct-horse-battery-staple-style passphrases as fast as the
hardware will let you, in parallel across every core.
Mirrored on both GitHub and Codeberg. Issues filed on either are welcome; commits are pushed to both.
Generates passphrases like correct-horse-battery-staple — four (or N)
random common words joined by a separator — in bulk, in parallel,
as fast as your CPU and disk will allow.
Entropy comes from crypto/rand (the OS CSPRNG — getrandom(2) on
Linux), drawn in large blocks once per worker rather than syscall-per-word.
The word source is a lightly-modified copy of the
EFF Long Wordlist — 7772 hand-curated,
unambiguous English words, ~12.92 bits of entropy each. (The bundled
copy strips the four hyphenated entries drop-down, felt-tip,
t-shirt, yo-yo from the upstream 7776-word list so that
default-separator output parses unambiguously when consumers split on
-. See "Wordlist attribution" below.)
| N words | Entropy (bits) | Roughly comparable to |
|---|---|---|
| 4 | 51.7 | 9-char fully-random alphanumeric |
| 5 | 64.6 | 11-char fully-random alphanumeric |
| 6 | 77.5 | 13-char fully-random alphanumeric |
| 7 | 90.4 | 16-char fully-random alphanumeric |
(6 words is the modern "this should survive a determined offline attack through 2030+" recommendation.)
correcthorsebatterystaple
(the Python one) is the humans-typing-at-a-prompt tool — chbs and
you have one passphrase. CorrectGopherBatteryStaple is the
millions-of-passphrases-into-a-file tool. Different problem, different
hot loop:
- Single static binary. No interpreter startup, no
pip install, drop on any Linux box. - Goroutine-per-core worker pool. Saturates every available core out of the box.
- Block-sized CSPRNG reads. One
crypto/rand.Readcall fills a buffer big enough for tens of thousands of passphrases — no syscall-per-word overhead. - Bias-free word selection via uint16 rejection sampling against 7776 (the wordlist size). No modulo bias, no skewed entropy.
- Buffered I/O. Output goes through a 1 MiB
bufio.Writerso the bottleneck stays compute, not write syscalls.
On a modern laptop, expect tens of millions of 4-word passphrases
per second to /dev/null, scaling roughly linearly with cores. On
a 24-thread i7-13700HX I measure ~11M/s single-threaded and ~93M/s
across all cores. Run go test -bench=. to see your machine's number.
From source:
git clone https://github.com/CryptoJones/CorrectGopherBatteryStaple.git
cd CorrectGopherBatteryStaple
go build -o cgbs .Or directly with go install:
go install github.com/CryptoJones/CorrectGopherBatteryStaple@latestThat produces a cgbs (or CorrectGopherBatteryStaple, depending how
you invoke it) binary on $GOPATH/bin.
$ cgbs
arrest-acrobat-gloom-zit
$ cgbs -n 6
phonics-saturated-twirl-undertow-aviation-pretzel
$ cgbs -n 6 -s ' '
shipping eggshell unmuted radial maker dabbing
$ cgbs -c
Cosmetics-Decimal-Pancake-Wildcat
$ cgbs -N 5
unpacking-stoning-cosponsor-deafness
hardly-dilation-deviator-extrude
attest-cling-unbutton-quiver
gathering-mistrust-mortified-overstuff
diction-dwelling-cutlery-tremble
$ cgbs --show-entropy
silvery-shameless-eyedrops-cyclic
# estimated entropy per passphrase: 51.70 bits
# Bulk mode — one million passphrases, every core:
$ cgbs -N 1000000 > out.txt
# Custom wordlist:
$ cgbs -w /usr/share/dict/words -n 4cgbs [-n N] [-s STR] [-c] [-N K] [-w PATH] [-j WORKERS] [--show-entropy] [--version]
| Flag | Default | Description |
|---|---|---|
-n N / --num-words N |
4 | Words per passphrase |
-s STR / --separator STR |
- |
String between words (use '' for none) |
-c / --capitalize |
off | Title-Case each word |
-N K / --count K |
1 | Generate K passphrases |
-w PATH / --wordlist PATH |
bundled EFF long list | Custom wordlist (one word per line, # comments ignored) |
-j N / --workers N |
GOMAXPROCS |
Parallel worker goroutines for bulk mode |
--show-entropy |
off | Print estimated entropy on stderr after output |
--version |
Print version + exit |
The hot loop is benchmarked in generator_test.go. To see your hardware's
throughput:
go test -bench=. -benchmemIndicative numbers (24-thread Intel i7-13700HX, 4-word passphrases, output discarded):
| Mode | Passphrases / sec |
|---|---|
| Single-worker | ~11M |
| All cores | ~93M |
| All cores, 6 words | ~62M |
The CSPRNG isn't the bottleneck — crypto/rand on Linux does
getrandom(2) and that's plenty fast when batched. The bottleneck at
the high end is bufio.Writer flush + string assembly. Generating
one million 4-word passphrases takes ~13 ms including startup,
wordlist parse, and writing the file to disk.
Those generate random strings. The xkcd-936 insight is that random words
are easier for humans to remember at equivalent entropy, and easier to type
correctly under stress (no l/1 / O/0 confusion).
Use this when the passphrase needs to be:
- Memorable (master password, GPG key, disk-encryption passphrase)
- Recoverable from a phone-photo of a sticky note
- Speakable over the phone to your future self
- Or when you need a lot of them at once — onboarding kits, honey-credentials, fuzzing corpora, load testing.
The bundled wordlist is a modified version of the EFF Long Wordlist by the Electronic Frontier Foundation, licensed CC BY 3.0.
Source file: eff_large_wordlist.txt.
Modifications from the upstream file:
- The original file has each line in
<dice-roll>\t<word>format; the bundled copy in this repo has the dice-roll prefix stripped. - The four hyphenated entries —
drop-down,felt-tip,t-shirt,yo-yo— have been removed, taking the list from 7776 entries down to 7772. This makes default-separator (-) output round-trip cleanly through asplit('-')parser. The entropy delta is negligible: 4 words × log₂(7772) ≈ 51.699 bits vs the upstream 51.700 bits.
The same modification notice is reproduced as a header comment block
at the top of eff_large_wordlist.txt in this repo.
To redistribute or fork: the EFF wordlist must be re-attributed under CC BY 3.0 with modifications marked; the rest of this project is Apache 2.0.
Apache 2.0 for the code. EFF Long Wordlist is CC BY 3.0 (see Wordlist attribution above). See LICENSE for the Apache 2.0 text.
Proudly Made in Nebraska. Go Big Red! 🌽 https://xkcd.com/2347/