Ed25519 private keys, encoding, and entropy: a complete note
A study note that follows the question from "why is brute-forcing infeasible?" all the way down to "what is entropy?"
Table of contents
- 256-bit random numbers and the infeasibility of brute force
- Why does a private key look like a pile of letters and digits?
- What if the private key happens to be 0?
- What does "enough entropy" actually mean?
- One-sentence summary
1. 256-bit random numbers and the infeasibility of brute force
A "256-bit random number" means the private key is essentially an integer drawn at random from 0 to 2²⁵⁶ − 1. For an attacker to hit the private key by brute-force guessing is equivalent to guessing that one number out of the entire range.
The point is how large that space is:
2²⁵⁶ ≈ 1.16 × 10⁷⁷- This magnitude is close to "the total number of atoms in the observable universe".
Getting a feel with concrete numbers
Suppose an attacker commands:
- 1 trillion machines worldwide (
10¹²) - Each able to try 1 trillion guesses per second (
10¹²) - A combined
10²⁴guesses per second (far beyond any real compute)
Divide that into the key space:
2²⁵⁶ / 10²⁴ ≈ 1.16 × 10⁵³ seconds
The age of the universe is only about 4.35 × 10¹⁷ seconds. In other words, even with this absurd amount of compute, it would take on average "10³⁵ times the age of the universe" to hit the key.
"Mathematically infeasible" doesn't mean "very hard" — it means there isn't physically enough time.
"Online" brute-force guessing is even more infeasible
An "online attack" means repeatedly trying to log in against a real running server, where every guess must:
- Make a network round trip and wait for the server's response
- Face rate limiting, lockout after failures, and other protections
In practice this may be only a few thousand guesses per second, or fewer. If even local full-speed cracking (an offline attack) is already infeasible, online guessing is even more of a fantasy.
The real risk has never been someone guessing the private key — it's the private key file leaking (no passphrase protection, read off by malware, accidentally pushed to a repo, etc.).
2. Why does a private key look like a pile of letters and digits?
That pile of letters and digits is just that 256-bit number "written a different way". Underneath, it's still the same thing.
The core idea: the same value can be written in different bases or encodings — the amount of information doesn't change at all.
A familiar analogy
We normally write the decimal 255; the computer internally stores the binary 11111111. They look completely different, yet are the same number.
The private key's conversion chain
A 256-bit random number
↓ rewrite
Binary: 256 zeros/ones
↓ group every 4 bits
Hexadecimal (hex): 64 characters (0-9 a-f)
↓ convert every 3 bytes
Base64: the string of letters and digits you actually see (A-Z a-z 0-9 + /)
- Hex: each character represents 0–15 (16 states), which maps exactly to 4 bits. 256 bits → 64 characters.
- Base64: the encoding used by SSH private key files (
-----BEGIN OPENSSH PRIVATE KEY-----), so the key can be stuffed into a plain-text file and copy-pasted without errors.
Each layer is just "a different appearance of the same number". What the attacker has to guess is always that bottom-layer value — which of the 2²⁵⁶ possibilities it is. Displaying it as letters and digits does not make guessing any easier.
Note: an OpenSSH private key file also wraps in extra structure (the corresponding public key, a comment, and — if a passphrase is set — encryption parameters), so the file is somewhat longer than "just 64 characters". But the core secret is still that one 256-bit random number.
3. What if the private key happens to be 0?
This intuition pokes at a very real point in cryptography. Two layers to the answer.
Layer one: an attacker "trying 0 first" is smart, but only helps if your key really is 0
The key misconception: an attacker trying 0 does not make "your key" become 0. Your key was fixed the moment it was generated.
If your key is some random value X buried deep in the 2²⁵⁶ space, then an attacker scanning up from 0, 1, 2, 3… still has to reach X to hit it — on average about 2²⁵⁵ values to scan. "Trying the small ones first" only pays off if the target happens to be a small number.
So the real question is: what's the probability that my key happens to be exactly 0 (or some other easy-to-guess value)? Under normal randomness, the answer is 1/2²⁵⁶ — exactly the same as the probability of it equaling any other specific value. 0 is no more likely to be your key than anything else.
Layer two: this is why "randomness" carries the entire security burden
The whole guarantee collapses the moment randomness breaks — and these are real disasters that have actually happened:
| Case | What happened |
|---|---|
| Debian OpenSSL bug (2008) | The RNG was broken, leaving only ~32,000 possible keys; an attacker could try them all and break in |
| Embedded / IoT devices | Not enough entropy at boot, producing predictable — even identical across devices — keys |
| Cryptocurrency brainwallets | People used memorable strings like password or 123456 as the seed, drained within seconds |
In these cases the attacker really did "try 0 and the likely values" and succeed — but the reason for success wasn't that 0 has magic; it's that the key generation process had no real randomness at all.
An Ed25519 design detail: even "seed = 0" doesn't degenerate
Ed25519 does not take the 256 bits directly as the scalar for its operations. It:
- First feeds the seed into SHA-512 and takes the first half
- Then performs clamping (always clears the lowest 3 bits, always sets bit 254 to 1)
Verifying in practice (seed set to all zeros):
import hashlib
seed = bytes(32) # seed = all zeros
h = hashlib.sha512(seed).digest()
a = bytearray(h[:32])
# Ed25519 clamping
a[0] &= 0xF8
a[31] &= 0x7F
a[31] |= 0x40
scalar = int.from_bytes(a, "little")
print("Is the scalar after clamping zero?", scalar == 0)
Output:
seed: 0000000000000000000000000000000000000000000000000000000000000000
Is the scalar after clamping zero? False
scalar (first 40 decimal digits): 3932564886698065279271500916921949606201 ...
corresponding public key (hex): 3b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29
Even with an all-zero seed, the scalar after clamping is a large non-zero number, and the corresponding public key is fully valid and looks completely patternless. In other words, Ed25519 doesn't degenerate into a mathematical flaw even in the extreme "seed = 0" case; at most it's "a key whose seed you already happen to know" — which loops back to layer one: probability 1/2²⁵⁶.
Some other schemes (where the private key is used directly as the scalar) do have degenerate weak keys like 0 and 1 that make the public key the identity element, but a proper implementation checks for and rejects those specific values at key-generation time.
4. What does "enough entropy" actually mean?
Entropy measures exactly one thing: how unpredictable the outcome of this generation process is. It can be measured precisely, in bits.
The cleanest definition:
Entropy = the base-2 logarithm of the total number of possibilities, assuming every outcome is equally likely.
| Scenario | Number of equally likely outcomes | Entropy |
|---|---|---|
| Flipping one fair coin | 2 | log₂(2) = 1 bit |
| Flipping two coins | 4 | 2 bits |
| A genuinely random 256-bit key | 2²⁵⁶ | 256 bits |
So "a 256-bit random number" stated precisely should be "a number carrying 256 bits of entropy".
Key point: key "length" ≠ key "entropy"
Imagine a buggy program: it claims to pick a "random" number from 1 to a trillion, but actually always picks 1 to 10, just padded out to width as 000000000007.
- Appearance: looks like one-in-a-trillion difficulty
- Real entropy: only log₂(10) ≈ 3.3 bits — broken in 10 tries
A private key is the same. The file has 64 hex characters and looks imposing, but if the random source only fed in 16 bits of real randomness, the effective strength is 16 bits (only 65,536 possibilities).
A key's real security equals its entropy, not its length. The Debian bug was essentially an "entropy collapse": real entropy plummeted from 256 bits to a dozen or so bits.
Where does a computer's entropy come from?
A computer is fundamentally a deterministic machine and cannot produce true randomness on its own. The operating system has to "harvest" unpredictability from the physical world and pool it into an entropy pool:
- The precise timing intervals of keystrokes and mouse movements (microsecond, nanosecond-level jitter)
- Tiny random fluctuations in the timing of disk reads/writes, interrupts, and network packet arrivals
- The CPU's built-in hardware random instructions (e.g. Intel
RDRAND), TPM chips - Thermal noise from the manufacturing process
Linux gathers these and supplies them, after cryptographic processing, through interfaces like /dev/urandom.
A classic disaster: a freshly booted embedded device
A device fresh from the factory, powered on for the first time:
- No one is typing, no mouse
- Disk behavior is identical
- The entropy pool is nearly empty, and every device's boot state is highly similar
If it rushes to generate an SSH key at this moment, the result is predictable — even identical across several devices. This is exactly why large numbers of IoT devices have been found sharing keys.
Practical advice
- Don't generate long-term keys right after boot, before the entropy has built up
- Make good use of modern CPUs' hardware random sources
- VM environments are physically noise-poor and especially prone to entropy starvation; when needed, add
havegedorrng-tools, or have the hypervisor pass the host's entropy in
5. One-sentence summary
Brute force is infeasible not because "there are no weak keys", but because "under genuine randomness, the probability of your key landing on any guessable value is so low it effectively doesn't exist".
Entropy is "the stock of unpredictability", measured in bits. A key can be as long as you like — without enough entropy it's a hollow shell. Whether a key can be trusted ultimately comes down to one question: at the moment it was generated, how much genuine randomness did the system have in hand?