The one-sentence version
A private key is just a random number. As long as this random number is not random enough (the selection range is too small, predictable, or reused), an attacker doesn't need to crack any cryptography; they can simply enumerate all possible private keys. From "Brain Wallets" to the Profanity vanity address tool, and the Milk Sad incident, the same reason lies behind repeated thefts: using 32-bit seeds, timestamps, or human-invented sentences instead of true cryptographically secure random numbers.
This article has three layers:
- Layer 1: The Intuition: A 256-bit lock, using only a 32-bit key
- Layer 2: Real-World Use: Brain Wallets, Android randomness vulnerability, Profanity, Milk Sad, Trust Wallet
- Layer 3: Entropy, CSPRNG, how to test randomness, and nonce in signatures
Layer 1: The Intuition
1.1 A 256-bit lock, a 32-bit key
An Ethereum private key is a 256-bit number, with approximately possible values—more than the number of atoms in the observable universe. Guessing it is impossible.
But what if the program generating the private key does this:
- Takes the current time (or a 32-bit number) as a "seed";
- Uses a standard pseudo-random number generator to calculate a 256-bit private key from that seed.
Then, while the private key looks like it has 256 bits, it actually only has hundred million possibilities. A single graphics card could try them all in a few hours.
The security of a private key depends on its entropy (the number of truly unpredictable bits), not its length.
1.2 Three common mistakes
| Mistake | Example |
|---|---|
| Seed is too short | Using a 32-bit integer or a timestamp as a seed for a random number generator |
| Wrong generator | Using pseudo-random numbers meant for games or simulations (like Mersenne Twister), whose output can be predicted |
| Humans "thinking" of randomness | Using the hash of a poem or a slogan as a private key (Brain Wallet) |
Layer 2: Real-World Use
| Event | Reason | Consequence |
|---|---|---|
| Brain Wallets (2010s) | Using the SHA-256 of a sentence as a private key | Researchers found that addresses corresponding to common sentences, quotes, and lyrics were monitored by bots, which instantly transferred funds as soon as they were deposited |
| Android SecureRandom (2013) | Flaw in the system's random number generator caused some signatures to reuse a nonce | Private keys for multiple Bitcoin wallet apps could be calculated, leading to stolen funds (see "Elliptic Curves" for why repetition is fatal) |
| Profanity (2022) | A popular Ethereum "vanity address" generation tool that used only a 32-bit seed for initialization | Months after security researchers disclosed the flaw, a vanity address belonging to the market maker Wintermute was stolen for approximately $160 million |
| Milk Sad (2023) | The bx seed command-line tool Libbitcoin Explorer used Mersenne Twister + a 32-bit time seed to generate recovery phrases |
A research team discovered that many wallets could be enumerated, and existing funds were stolen |
| Trust Wallet Browser Extension (2022–2023) | Insufficient entropy in the WebAssembly version of the random number generator | A batch of wallets generated during a specific period could be enumerated, resulting in losses |
The Profanity incident is particularly noteworthy: "Vanity addresses" are themselves a red flag. To obtain an address starting with 0x0000, the tool needs to generate a massive number of private keys very quickly, causing the developer to sacrifice randomness for speed.
Layer 3: Principles and Engineering
3.1 Entropy and CSPRNG
- Entropy: A measure of unpredictability. A fair coin flip provides 1 bit of entropy; a 32-bit seed provides at most 32 bits of entropy, and no amount of "shuffling" afterwards will increase it.
- CSPRNG (Cryptographically Secure Pseudo-Random Number Generator): After being provided with sufficient initial entropy, the output is indistinguishable from true randomness, and seeing previous outputs does not allow one to predict future outputs.
| Correct Sources | Incorrect Sources |
|---|---|
Operating Systems: /dev/urandom, getrandom(), BCryptGenRandom |
rand(), Math.random(), random.random() |
Browsers: crypto.getRandomValues() |
Mersenne Twister (MT19937) |
Python: secrets module |
Using timestamps or process IDs as seeds |
| Hardware wallet True Random Number Generators (TRNG) | Sentences you thought of, or a small number of dice you rolled yourself |
3.2 Why Mersenne Twister is insufficient
Mersenne Twister (MT19937) is an excellent statistical pseudo-random number generator, suitable for simulations and games. However, it is linear (based on linear recurrence over , the same class as LFSRs and stream ciphers): by observing 624 consecutive 32-bit outputs, one can reconstruct its entire internal state and predict all subsequent outputs. Even if the seed is long enough, it cannot be used for cryptography.
3.3 How to test
Randomness issues are almost impossible to detect just by looking at the output: a generator with only 32 bits of entropy will still produce output that looks random and passes statistical tests. Therefore, the focus of testing must be on code review:
- Identify all locations where private keys, recovery phrases, nonces, or session tokens are generated;
- Confirm that every instance directly calls the OS or the language standard library's CSPRNG;
- Confirm that no time, PID, or counters are used as seeds, and no seeds are fixed "for reproducibility";
- Be extra cautious in environments where "entropy might be insufficient," such as WebAssembly, embedded devices, or immediately after a virtual machine boots.
3.4 Randomness during signing
Not only does private key generation require randomness, but ECDSA also requires a random nonce for every signature; if it is repeated or predictable, the private key will be leaked. The modern approach is RFC 6979: generating deterministically using the private key and the message hash, completely removing reliance on the quality of a random number generator. Ed25519 and BLS signatures are inherently deterministic (see "Schnorr Signatures," Bilinear Pairings, and BLS Signatures).
3.5 Advice for users
- Only use well-known wallets and hardware wallets to generate recovery phrases;
- Do not use any "vanity address generators" unless they are open-source, audited, and use a CSPRNG;
- If an old wallet was generated using an unverified tool, transfer your assets to a newly generated wallet.
Summary
| Layer | Key points |
|---|---|
| Intuition | Private key security depends on entropy, not length; a 32-bit seed = 4.3 billion possibilities |
| Cases | Brain Wallets, Android, Profanity, Milk Sad, Trust Wallet |
| Principles | Only use CSPRNG; Mersenne Twister is linear and predictable |
| Testing | Rely on code review rather than statistical testing; use deterministic for signatures |