Don't Trust, Verify: An Entropy Deep Dive
- I. How I got here
- II. The lesson is not “hardware wallets are bad”
- III. Generate your own entropy
- IV. Verify that your dice actually became your seed
- V. Generate the passphrase the same way
- VI. 12 words vs 24 words
- VII. Storage: where the actual risk lives
- VIII. Two designs that look smarter than they are
- IX. What “don’t trust, verify” actually costs
- The one-line version
I was holding one of the affected devices. Nothing of mine moved. Working out why turned out to be mostly a story about luck rather than judgement. Nobody who lost coins in this made a mistake. What follows is what I found when I went looking for a reason to feel safe and didn’t find one.
I. How I got here
Before anything else, because it needs saying first and plainly: the people who lost coins did nothing wrong. They bought reputable hardware, followed the instructions, and were robbed by a defect they had no means of detecting. That isn’t a consolation line, it’s the logical consequence of the argument this whole essay rests on. A weak seed is indistinguishable from a strong one. The flaw survived years of shipped firmware and its authors’ own code review. If the people who wrote it couldn’t see it, no user was going to. Nothing that follows is a list of things victims should have done. It’s a list of hedges that happen to route around a failure nobody could see, which is a different claim and the only honest one available.
With that said. I owned a device in the at-risk set, with a BIP-39 passphrase on it. When the sweeps happened, my coins stayed where they were.
The comfortable read is that I’d set things up properly. The accurate read is that I had two overlapping pieces of luck and can’t cleanly tell you which one did the work.
The first is the passphrase. The attack enumerates a shrunken seed space offline and checks each candidate against the chain. Derive a weak seed with no passphrase and you land on the wallet that seed alone produces. My coins weren’t in that wallet. They were in the one derived from seed plus passphrase, a different key entirely, and reaching it meant guessing both.
The second is that not every affected device was equally affected. The hardware revision I happened to own retained meaningfully more entropy than the earliest ones did. Still far below spec, still enumerable in principle, but enough more expensive that a sweep working through a population would reach it later, if at all.
So I was costly on two axes at once, and I have no way to know which mattered. That’s the part I keep coming back to. I wasn’t protected by a strong passphrase, and I wasn’t protected by a design decision. I was protected by being more expensive than the next wallet in the queue. Against mass enumeration, that’s enough. Against someone who had specifically decided to come after me, with the seed space already collapsed and a passphrase I’d invented myself, the arithmetic looks a lot worse. I got the right outcome from a setup that hadn’t earned it.
So I generated a new seed and moved everything, which is worth explaining because not everyone will think it was necessary. A weak seed doesn’t heal. The entropy sits permanently inside an enumerable set, which leaves the passphrase as the only thing between an attacker and the coins, carrying a load it was never designed to carry alone. A passphrase over a compromised seed is a mitigation you’re renting, not a fix you own. Queue position is not a security model, and it changes the day someone decides you specifically are worth the compute.
I also won’t buy from that manufacturer again. Not because they shipped a bug, since anyone can ship a bug, but because the bug sat in released firmware for years in the one subsystem where a defect is undetectable by the user, and it was found by attackers rather than by them. That’s a process failure rather than a coding failure, and process is what you’re actually buying from a hardware wallet vendor. Other people weigh that differently and I don’t think they’re being unreasonable. It’s my line, not a recommendation.
None of that makes the flaw my fault, and I want to be careful not to write as though ordinary diligence would have saved anyone. Within the trust model everyone was operating in, it wouldn’t have. Dice entropy did protect the people who used it, but that’s a hedge that happened to route around this particular failure, not a standard of care anyone was violating by skipping it. What I lacked wasn’t diligence, it was any account of why I was safe that I could have written down in advance. I had a hardware wallet, a backup, and a general sense I’d followed good practice, and no way to check whether the thing I trusted had done what it claimed. That gap is worth closing whether or not anything was ever going to go wrong.
So I spent a few days down the rabbit hole. Most of what follows is arithmetic I had to work through slowly, and several conclusions run against what gets repeated as settled advice. I’m showing the math rather than asserting results so you can catch me if I’ve got something wrong. I’m not an expert. I’m someone who got a scare and did the reading.
One ground rule. Everything I say about my own setup is past tense and describes a configuration that no longer holds anything. What follows is a recommended architecture, not what I run now. I won’t publish my current parameters, and the reason is in the essay: a partially exposed secret is only as strong as the attacker’s uncertainty about its shape. Publishing your construction gives that away for free, costing nothing while everything is intact and a great deal the day one plate gets photographed. Same applies to you. Take the reasoning, vary the parameters, tell nobody which ones you picked. An architecture is worth publishing. A configuration isn’t.
II. The lesson is not “hardware wallets are bad”
A hardware wallet promises two things: that your keys never leave the device, and that your keys are born from strong randomness.
The first is testable. The second is not.
A weak seed and a strong seed are indistinguishable from outside. Same 24 words, same valid addresses, same everything. A build error can route seed generation through a software PRNG instead of the hardware RNG, and nothing in the output announces it. That class of failure sat undiscovered in shipped firmware for years, through the manufacturer’s own code review, surfacing only when wallets started draining in a coordinated sweep. Because the weakness lives in the seed itself, the search runs entirely offline. No phishing, no malware. Nobody touches a device.
Bitcoin’s cryptography worked exactly as designed. One product’s randomness did not.
The generalizable rule: stop trusting any component you cannot verify.
Read that as a design principle, not a verdict on anyone. The rule is worth adopting precisely because the failure was undetectable, which is also why nobody who skipped it was being careless. Almost nobody supplies their own entropy, and the people who lost coins were doing exactly what everyone else does. The difference came down to which cohort the attacker’s script reached, and that’s a thin thing to rest on.
Entropy happens to be the one input you can supply yourself, verifiably, for ten minutes and a handful of dice. Almost nobody does. That’s an unusually good deal, and it’s available going forward regardless of what anyone did before.
Two standing warnings, since they follow every incident of this kind:
- Never enter seed words into any site or tool offering to check whether you’re vulnerable. That is the follow-on scam, every time.
- Move slowly, unless your seed is the one being exploited. A rushed migration usually beats the flaw for immediate risk. But that assumes you have time, and in an active sweep the vulnerable population doesn’t. Establish which group you’re in first, from the vendor’s advisory. In the at-risk set, you’re in a race and slowness loses it. Outside it, don’t churn a working setup because the timeline is loud.
III. Generate your own entropy
Dice math
Each six-sided roll carries log₂(6) = 2.585 bits. So 50 rolls gives you 129.25 bits, enough for a 12-word seed. 99 rolls gives 255.91, enough for 24.
There is a hard ceiling at 99. The common implementation hashes your roll string with SHA-256, producing a fixed 256-bit output. Feed it 500 rolls, you still get 256 bits. Rolling past 99 is theater.
Worth knowing that this hashing step is a convention rather than part of BIP-39. It’s what Coldcard-style dice entry does and what several open-source signers follow, but other wallets map rolls to entropy differently, treating them as raw base-6 digits or remapping face 6 to 0. This matters in section IV, where reproducing the derivation yourself depends on knowing which mapping your device uses.
There’s a second ceiling below that one, covered in section VI.
“Rolling dice is too complicated, people will get it wrong”
The most common objection I’ve seen, and worth answering rather than waving off, because its strong version isn’t about dice at all.
The weak version is that the math is hard. It isn’t. There is no math in the generation path. You roll a die, type a digit, repeat fifty times, and the device does the arithmetic. If you can enter a PIN you can do this. I’m being blunt because the perceived difficulty stops more people than the real difficulty does.
The strong version is better: every manual step is another way to ruin your own ceremony, and a botched one can leave you worse off than trusting the generator. True. Someone who miscounts, mis-transcribes, or performs the ritual while their phone watches has spent effort to end up weaker than the default.
I still land on dice, on an asymmetry rather than a probability, but the asymmetry needs stating precisely because the sloppy version of it is wrong.
Transcription and derivation errors are caught. Miscount your rolls, fat-finger a digit, restore to the wrong path, and it surfaces when you restore and compare, on a wallet holding nothing.
Physical-entropy errors are not caught, and I want to be honest about that rather than sell you a guarantee I can’t deliver. Under-tumbled dice, a misread multiset, someone’s camera in the room: all of those produce a perfectly valid, perfectly reproducible mnemonic. Section IV will faithfully confirm that your weak roll string became your seed exactly as intended. Verification proves provenance, not quality. Those failures are managed by procedure, which is what the ranked list above is for, not by any check you can run afterward.
So the real comparison is narrower than “dice are safe.” It’s this: the dice path has failure modes you can eliminate with a written procedure and a restore drill, and one class you have to get right the first time. The device path has a failure mode you cannot detect, cannot drill, and cannot procedure your way around. It looked identical to a good seed for five years, to everyone, including the people who wrote the firmware. Trading an undetectable risk for a mostly-detectable one is a good trade, and I’d rather defend that claim than the bigger one.
The objection does have real teeth in exactly one place: everything above depends on verification, and verification is the step people skip. So section IV names the existing, reviewed tools that do it, rather than telling you to go verify and leaving you there. If you only do one thing from this essay, do that one.
The irony
Where dice entropy replaces the device’s own generator, the seed is a pure function of your roll string, and a broken RNG never touches it. The people most paranoid about entropy quality were the ones protected from the manufacturer’s failure to deliver it.
Know which mode your device is in, because it matters more than it looks. Replace-mode means the seed is recomputable from your rolls, which is what makes section IV possible at all. Mix-mode, where your rolls are combined with device entropy, still protects you against a weak RNG, but the output is no longer something you can independently reproduce. One of these is verifiable. The other only inherits the good property.
Do you need casino dice?
No. Generic d6 is fine.
The bias source in cheap dice is pip drilling: the 6 face loses more material than the 1, so 6 comes up slightly more often. Casino dice fill pips flush with equal-density material. Entropy loss from bias is quadratic in the deviation, which is why it matters less than it feels like it should:
- 1 percentage point of deviation per face, already worse than most real dice, costs 0.0026 bits per roll. Over 50 rolls, 0.13 bits.
- 3 points, a visibly bad die, costs 0.0235 per roll. That’s 1.17 bits over 50 rolls.
Read those as percentage points, not relative. A face landing 1 point high means p = 0.1767 rather than 0.1667, which is already a 6% relative skew.
Now the part I nearly got away with. Those are Shannon figures, and two sections down I’ll tell you min-entropy is the accounting an attacker actually uses. Applying the strict standard where it helps my argument and the lenient one where it hurts would be exactly the kind of thing this essay is supposed to catch, so here it is both ways. Under min-entropy, 1 point of bias costs 0.084 bits per roll and 3 points costs 0.239, which over 50 rolls is 4.2 and 11.9 bits rather than 0.13 and 1.17.
That changes the picture at 50 rolls. 99 rolls gives 255.91 bits against a 128-bit target, a surplus of about 128 bits, and even the worst case above costs only around 24 of them, so bias cannot threaten the target there on any accounting. 50 rolls gives 129.25, a margin of 1.25 bits, and under min-entropy a visibly bad die doesn’t just eat the margin, it lands you at roughly 117.
Which makes the fix concrete rather than reassuring. Roll 55 instead of 50. That’s 142.17 bits nominal, and even at 3 points of bias on the conservative accounting you come out near 129, still above target. Six extra rolls and about forty seconds buys you a procedure that survives the pessimistic standard. Ordinary d6 bias is very unlikely to reach three points, so this is belt-and-braces, but it costs almost nothing and it means the recommendation doesn’t depend on which entropy measure you prefer.
What actually degrades your rolls
Ranked by real risk:
- Not tumbling. Dropping from a fixed height in a fixed orientation onto a soft surface is not rolling. Shake in a cup, throw against a backstop, let them bounce.
- Reading-order ambiguity with multiple dice. See below.
- Transcription errors. Write as you go, in groups of ten, with a running count. Verify the total before committing.
- Observation. Cameras, phones, windows, other people. Entropy someone watched is not entropy. This is the one that can zero you out.
- A physically damaged die: chipped, warped, or cracked. Visually obvious. Discard.
Manufacturing tolerance doesn’t make the list.
Multiple dice: order is everything
Never read dice as an unordered set. Five dice read as an ordered sequence carry 12.92 bits. The same five read as a multiset (“three 4s, two 6s”) carry 7.57 bits of Shannon entropy, and only 6.02 bits of min-entropy, since all-distinct multisets are 120 times likelier than five-of-a-kind. That’s a 41% loss on the generous accounting and 53% on the one an attacker uses. You’d never notice, because the digits still look random. This is the one that most argues for writing your procedure down before you start rather than improvising at the table.
Two workable schemes. Two colors, one of each per throw, fixed order, always black then white: zero ambiguity regardless of how they land or stack, 25 throws for a 12-word seed. Or a slotted tray (muffin tin, egg carton, channel cut in cardboard) with slots numbered permanently: shake in a cup, pour in, read by slot, five throws for 12 words with ten dice. If a die lands outside a slot or shares one, discard the whole throw rather than improvising a reading.
Avoid the middle ground. Five identical dice read “left to right” produces judgment calls on throws where two are effectively tied, and judgment calls in an entropy pipeline are silent errors.
IV. Verify that your dice actually became your seed
This is the step almost everyone skips. It’s also the one that closes the loop, and without it the rest of this essay is decoration.
Here’s the gap. A restore drill proves your mnemonic derives the xpub you recorded. It does not prove the device derived that mnemonic from your dice. A device that displays a dice-entry screen and quietly uses its own RNG passes every other check in this document without complaint. You’d have performed the entire ceremony for nothing and had no way to find out.
Verifying the mnemonic without verifying its origin just moves the trust one box to the left.
What the derivation actually is
Simpler than I expected, which was part of why I’d assumed I couldn’t check it. For the Coldcard-style convention:
entropy = SHA-256(roll string as ASCII digits) truncated to 128 or 256 bits
checksum = first ENT/32 bits of SHA-256(entropy)
mnemonic = (entropy || checksum) split into 11-bit groups, each indexing the 2048-word list
That’s the whole thing. No secret constants, no vendor magic. Deterministic, so the same rolls always produce the same words, which is exactly what makes it checkable.
You don’t need to be able to write that in order to check it, which is the point. Following the arithmetic and staking coins on your own implementation of it are very different bars, and only the first one is required here. The tools below already do the work. The reason to understand those three lines is so you can tell whether a tool is doing what it claims, not so you can rebuild it.
Use tools that already exist
Use tools that already have eyes on them. Never run a script someone pasted into a post against live seed material, and that includes anything I might have handed you. Trusting an anonymous author because the post sounded reasonable is the same trade this essay is arguing against, and a friendly tone doesn’t change the arithmetic.
Start with your vendor’s own verifier. Coldcard documents the procedure and publishes rolls.py for 24-word seeds and rolls12.py for 12, run as echo <your rolls> | python3 rolls12.py. Their documentation recommends doing it on a Tails machine with no network and no hard drives, which is the right posture. Other vendors with dice entry have equivalents; check their docs before assuming they don’t.
Then run something not written by your vendor. This is the part people skip. Verifying that a manufacturer’s device behaved, using only that manufacturer’s script, is partly circular. It isn’t fully circular, since the verification tool is separate code from the firmware and the failure in this incident lived in the RNG path rather than the dice math. But you already apply the cross-implementation principle to BIP-39 in section VII, and it belongs here for the same reason. verify-coldcard-dice-seed by Andreas Huber is one option, run as npx verify-coldcard-dice-seed@latest, and it goes further than the vendor script by checking the derived receive addresses as well as the mnemonic. That matters, because seed derivation being correct doesn’t prove address derivation is.
Two independent tools agreeing with your device is a real result. One tool agreeing is a weaker one.
The rest of the procedure is unglamorous. Offline machine, ideally one that has never been online and gets wiped after. Type in the exact digits you entered on the device, same order. Compare the words. If they match, your entropy is yours and you know it rather than assuming it. If they don’t, you’ve learned the most valuable thing available to you, on a wallet holding nothing, which is the best possible moment to learn it.
If they don’t match
Do not conclude your device is lying. There are four duller explanations and you should exhaust all of them first.
A different dice-to-entropy mapping is the likeliest by a wide margin, and it has a documented history. SeedSigner and Coldcard’s rolls.py produced different seeds from identical roll strings, and the divergence appeared only once a 6 was involved, which is the signature of one tool treating face 6 as 0 while the other hashes the literal ASCII digit. Same dice, same honest intent, different words. Read your vendor’s documented mapping before reading anything sinister into a mismatch.
Wrong mode is next. Some devices mix your rolls with their own entropy rather than replacing them. That still defends you against a weak RNG, but the output is not reproducible by design.
Then transcription. Compare character by character, since one dropped digit changes every word.
Then word count, because 12 and 24 truncate the same hash to different lengths.
Only after all four should you consider that a device given your dice didn’t use them. That accusation would be worth publishing, which is precisely why it deserves a high bar.
The honest caveat
This verifies the rolls became the mnemonic. It says nothing about whether the signing firmware behaves, whether nonces leak key material, or whether the supply chain was clean. Those are real and untouched here. What it closes is the one hole this class of incident actually exploited, using arithmetic you can check yourself. Narrow win. It’s also the difference between knowing and hoping.
V. Generate the passphrase the same way
A BIP-39 passphrase (the “25th word”) is an independent barrier, but only if it carries real entropy.
The KDF won’t save you. Derivation runs PBKDF2-HMAC-SHA512 at 2048 iterations, roughly 11 bits of stretching. That’s a rounding error on modern hardware, and it was weak even when it was written. The passphrase has to supply its own strength.
A phrase you invented is worth 20 to 30 bits, not 80. Wordlists already contain quotes, lyrics, names, dates, and l33tspeak substitutions. This is how people get drained.
I want to be careful here, because this is where I’m most tempted to claim more than I know. A passphrase is one of the two reasons my coins didn’t move, and it’s the one I’d point to first: it’s a genuinely independent barrier, and if the enumeration ever reached my seed’s class then the passphrase is what stopped it. But I can’t tell you it did, because the other explanation is that the sweep never got to my cohort at all. If that’s what happened, my passphrase wasn’t tested. It just wasn’t reached.
That distinction matters more than it looks. A passphrase that was never attacked has told you nothing about whether it would hold, and mine was a phrase I’d invented, worth maybe twenty or thirty bits. Against mass enumeration picking off whatever’s cheap, that’s plausibly enough. Against someone who has already narrowed your seed to a fraction of its intended space and decided you specifically are worth the compute, it isn’t close. I’d be claiming a passed exam I may never have sat.
Generate this one with dice, and don’t let a good outcome talk you out of it.
Recommended spec
9 words from EFF short wordlist #2
Physical dice, 4 rolls per word
Re-roll any word shorter than 4 letters
First 4 characters of each word
Concatenated, no spaces, all lowercase
Result: 36 characters, about 93 bits. Example shape: mangtrufsnorplaicredwistbarkfellrust
Every number there is a knob, not a commandment. 9 and 4 are defensible defaults. Pick your own and keep them to yourself, for the reason in section I: an attacker who knows your construction and later recovers part of a plate is solving a far smaller problem than one who knows only that the string is 36 characters.
The re-roll rule exists because truncating to 4 silently yields a shorter output for any word under 4 letters, breaking the fixed-width property and the count check that depends on it. Check your copy for short words first. Discarding a handful from 1296 costs a fraction of a bit. Finding out mid-restore that your passphrase is 34 characters costs rather more.
Why each choice:
- Physical dice. Not your laptop, not an online generator, and not the device’s own RNG, which is the component whose failure you cannot detect.
- 9 words is about 93 bits. Below 40 is already cracked. Past 100 or so you’re buying transcription risk, not security.
- EFF short list #2 (1296 words, 10.3 bits each) over the large list, because its words have unique 3-character prefixes, so truncating to 4 never collides. The large list does not guarantee that; it guarantees only that no word is a prefix of another, which is weaker. The stronger version gets repeated a lot. The file is
eff_short_wordlist_2_0.txt. Don’t take my copy or anyone’s on faith: hash what you download, compare against a hash sourced separately, and confirm 1296 lines before rolling. - Lowercase a–z only. Every BIP-39 implementation agrees on printable ASCII. Unicode normalization across vendors does not.
- No spaces. A space is invisible on steel and invisible in a masked entry field. A doubled or trailing one produces a different, silently valid, empty wallet.
- 36 characters fits under the tightest hardware wallet limit, and fixed-width 4 makes the character count a manual checksum against a dropped letter. Write “36” next to it.
Portability
BIP-39 passphrases are already universal. Every implementation handles a string identically. What actually breaks on recovery is derivation path and script type. You restore into a new wallet, it defaults to one path, your coins were on another, and you see zero.
Store alongside the backup:
- The passphrase and its exact reconstruction rule
- Master key fingerprint (XFP), the 8 hex characters that open a descriptor
- Derivation path for every account, as a literal string
- Script type per account
- Account xpub, which is your verification anchor
Record the fingerprint and the path together, in descriptor notation, rather than as loose fields:
[a1b2c3d4/84h/0h/0h]xpub6C...
That’s the form every coordinator and PSBT signer actually wants, and it’s what a multisig descriptor is assembled from. Loose fields in a notebook have to be reassembled correctly by someone under pressure, possibly not you.
The fingerprint is also passphrase-dependent. Change the passphrase and you get a different master key, so a different XFP. That makes it the cheapest check in a restore: if the fingerprint matches, your passphrase went in correctly, and you know it before deriving a single address.
Also: skip vendor-proprietary backup schemes. Plain BIP-39. If the vendor is gone, so is anything only they implemented.
VI. 12 words vs 24 words
I had 24 words. Working out what that actually bought me is the part of this that most changed how I think about the stack, and it’s the section I expect most disagreement on.
The common belief is that 24 words is twice as secure. It isn’t. It’s identically secure.
Why
An attacker takes the cheapest route to your private key. Two exist.
Route A is guessing the mnemonic: 2¹²⁸ for 12 words, 2²⁵⁶ for 24.
Route B is attacking the key directly. Your key is a scalar on secp256k1. The best known attack, Pollard’s rho, runs in √n, so a 256-bit curve gives 128-bit security. That’s fixed by the curve. It does not care how many words you wrote down.
So with 12 words, both routes cost 2¹²⁸. With 24, Route A rises to 2²⁵⁶ and Route B stays at 2¹²⁸. The attacker’s cheapest path is 2¹²⁸ either way.
One asterisk, since someone will raise it: Route B needs your public key, and for an address you’ve never spent from the pubkey is still hidden behind hash160. Pre-spend, the classical floor is higher. But you spend eventually, the pubkey goes on chain when you do, and 2¹²⁸ is already past the end of what’s reachable.
12 words sits exactly on the floor. 24 lifts one path above a floor that doesn’t move. You’ve hardened the wall next to the open door.
Why 2¹²⁸ ends the conversation
Bitcoin’s entire hashrate since genesis has performed somewhere around 2⁹⁵ to 2⁹⁶ hashes cumulatively, depending on when you count. Call it billions of times short of 2¹²⁸, against a network purpose-built to do nothing but hash, running flat out for seventeen years. Compute the current figure yourself from chainwork if you want it exact; the conclusion isn’t sensitive to a bit either way.
Skip the thermodynamic version of this argument. You’ll see it claimed that counting to 2¹²⁸ exceeds the sun’s remaining energy output. It doesn’t, by a wide margin. Landauer’s bound at room temperature is about 2.9 × 10⁻²¹ joules per irreversible bit operation, so a 2¹²⁸ counter needs roughly 9.8 × 10¹⁷ joules, and the sun emits that in about two and a half nanoseconds. The thermodynamic wall is real but it sits closer to 2²¹⁴, which is why that argument is normally deployed in favor of 256-bit keys. Borrowing it here means arguing one case with the other side’s evidence.
2¹²⁸ doesn’t need thermodynamics. It’s unreachable on engineering grounds, and the hashrate number shows it.
The usual quantum argument for 24 is backwards, and the good one is narrow
The usual defense imports intuition from Grover’s algorithm, which gives a square-root speedup on unstructured search and would halve a symmetric key’s strength. But elliptic curve keys aren’t broken by Grover. They’re broken by Shor’s algorithm, which solves discrete log in polynomial time and takes secp256k1 to effectively zero regardless of seed size. Once your public key is on chain, seed length is irrelevant. Both lengths are equally dead.
One version isn’t backwards and deserves a straight answer. For an address you’ve never spent from, the pubkey is hidden and Shor has nothing to work with, so the quantum route becomes Grover over the seed space: 2⁶⁴ iterations for 12 words against 2¹²⁸ for 24. Real asymmetry, and exactly the case address hygiene creates.
It still doesn’t move me, for reasons about Grover’s shape rather than its exponent. The iterations are inherently sequential, so a thousand quantum computers buy you a factor of thirty, not a thousand. And each iteration runs the entire derivation in superposition, reversibly, under error correction. An adversary who can do 2⁶⁴ of those can instead run Shor against every exposed pubkey on the chain, which is cheaper and pays better. The hedge is real but it’s priced against a machine that would be breaking the network at large rather than grinding your particular hidden seed.
So why does 24 exist?
BIP-39 is a general-purpose encoding standard, not a Bitcoin security tier. Its job is representing arbitrary binary entropy as transcribable words. The 128-bit ceiling lives two layers down, in secp256k1. A well-designed encoding layer doesn’t hardcode assumptions about a consumer it may not have.
Notice that BIP-39 also defines 15, 18, and 21 words. Almost nobody uses them. They exist because the spec parameterized entropy over a range in 32-bit steps and let the arithmetic fall out, not because anyone was ranking options.
24 became the default for non-technical reasons. Vendors shipped it out of the box, “more words = more secure” is the intuition everyone arrives at unaided, nobody gets fired for shipping 256 bits, and it reads as serious.
The one real advantage: checksum
12 words is 128 bits of entropy plus a 4-bit checksum. 24 words is 256 plus 8.
This checksum is a truncated SHA-256 hash, not an error-detecting code. Bech32 uses a BCH construction with provable distance guarantees: it detects any four character substitutions, always. BIP-39’s checksum guarantees nothing. It behaves like a random oracle, so any error of any magnitude passes with a flat 1 in 16 for 12 words, 1 in 256 for 24.
The consequences are no graceful degradation and no error correction. It can tell you something is wrong, never where.
People who noticed this went and built fixes. Codex32 (BIP-93) encodes a seed with a real BCH checksum that corrects errors rather than merely detecting them, and it’s designed to be verified by hand, on paper, without a computer. SLIP-39 also carries a stronger checksum, with Shamir splitting built into the format.
Neither is a drop-in replacement today, for opposite reasons. Codex32 is still a Draft BIP, informational and application-layer, requiring no consensus change from anyone. Being merged into the BIPs repository means the specification was published, not that anything ships it: the reference implementations are in Rust and PostScript, and mainstream wallet support is essentially absent. Using it means owning the tooling yourself. SLIP-39 has the inverse problem. It has real production support, concentrated almost entirely in one manufacturer’s hardware, which is precisely the vendor dependence this essay warns about a few paragraphs from here.
Worth knowing both exist, and worth watching codex32 in particular, because the weakness it was built to fix is the one this section just described.
Where the difference shows up concretely is one lost word in a known position. Either length gives you 2,048 candidates. With 12 words, about 128 survive the checksum. With 24, about 8.
Both are trivially searchable. 128 candidates resolves in seconds on a laptop, and open-source tools do this.
Convert the advantage into its own currency. The checksum filters 16× better, but one additional missing word costs 2048×. log₂(16)/log₂(2048) = 4/11, so 24 words buys roughly one third of a word of extra slack.
And it cuts both ways, because recovery difficulty and attack difficulty are the same number. An attacker holding 23 of your 24 words gets 8 candidates. Holding 11 of your 12, he gets 128. The stronger checksum is an oracle, and it serves whoever holds the fragment, which isn’t always you.
Be honest about how much that’s worth, though, because the triviality argument runs both directions. If 128 candidates resolve in seconds for you, they resolve in seconds for him. Neither length protects a seed that has partially leaked. Anyone claiming 12 words meaningfully limits partial-exposure damage is making the same mistake as the person claiming 24 meaningfully helps recovery, just facing the other way. What actually protects a partially exposed seed is the passphrase, which is the entire reason section V exists.
Finally: 24 words has twice as many words to lose. You’ve doubled the probability of the event you’re optimizing against to buy a 16× discount on its consequence.
The honest case for 12
Not memorability. Stamping burden. Half the punches, half the transcription opportunities, half the corrodible rows. Cheaper redundancy and faster verification follow from that.
One more misconception
Rolling 100 dice into a 12-word seed does not give you an 8-bit checksum. Checksum length is a pure function of the mnemonic format: CS = ENT/32. The implementation truncates your hashed entropy to 128 bits and computes a 4-bit checksum from that. Extra rolls are discarded. You cannot buy checksum strength with entropy. They aren’t fungible.
VII. Storage: where the actual risk lives
There is no wrong-passphrase error. Every candidate passphrase produces a valid wallet. A typo doesn’t fail. It silently shows an empty balance.
Recorded self-custody losses skew overwhelmingly toward forgotten, mistyped, and unrecoverable secrets, not brute force. Entropy is the cheap part. Durability is the engineering problem. It’s also the part I’d thought least about, which is the wrong way round.
Architecture
Seed (12 words) → steel, 2 separated locations
Passphrase (36 chars) → steel, 2 different separated locations
That’s the shape, not a prescription; counts and separation are yours to choose and worth keeping private. Four plates, four sites. No single plate and no single site reconstructs anything. Note what this is and isn’t: any seed plate paired with any passphrase plate does open the wallet, so four of the six possible pairs are sufficient. This is not a 2-of-4 scheme and shouldn’t be described as one. It’s redundancy against loss on two independent secrets, which is a different goal. If you want a genuine threshold, that’s Shamir, with its own costs.
Storing both plate types in the same drawer gives you a failure point and zero security.
Don’t rely on memory
A memorized seed is only load-bearing if it covers the whole secret. A 36-character dice-generated passphrase won’t be memorized, so the memorized seed alone recovers nothing.
Memory is also worse than you model it. You’re evaluating recall in a calm room having just generated it. The real test is five years later, under stress, after the event that destroyed your plate. Human memory rewrites rather than degrading gracefully, and it’s silently corrupted. You feel equally certain either way.
Memorization is also a liability rather than an asset. A memorized secret is extractable under coercion. A plate in another state is not, because you genuinely can’t produce it. In some jurisdictions there’s a meaningful legal distinction between compelling production of a physical object and compelling disclosure of memorized contents, and memorizing moves you to the worse side of that line.
Memorize where the plates are and what the reconstruction rule is. Not the secrets.
Verification ritual, before funding
- Wipe the device
- Restore from seed + passphrase
- Confirm the account xpub matches what you recorded
- Send a test amount
- Wipe again, restore again, spend it
Twice, on separate occasions. A passphrase you have never round-tripped is a coin flip.
Also verify seed + passphrase against two independent BIP-39 implementations, offline. An identical xpub proves your string survives normalization differences.
This drill is the only mechanism that catches a passphrase transcription error at all. Be clear on why: the BIP-39 checksum covers the mnemonic and nothing else. Against a mistyped passphrase it offers no protection whatsoever, which is the point this section opens with. Against a mistyped seed word it catches 15 out of 16, which isn’t a safety net either, just a coin flip you lose 6% of the time. Neither number is doing work for you. The round trip is.
Password managers
Supplementary copy, defensible. Primary copy, no.
The passphrase exists to be somewhere the seed isn’t. A network-connected device running a browser is a bad “somewhere.” You’d be moving half your key from a medium with no attack surface onto the most-attacked surface you own. And malware doesn’t need to exfiltrate to hurt you: altering one character in a vault entry produces a wrong passphrase you’d discover only when you needed it, with full confidence.
If you do it anyway: self-hosted and offline-capable (local encrypted file, no cloud sync, no browser extension), steel stays authoritative, the vault master password is itself on steel, the vault file is backed up offline, and the entry is never labeled. An unlabeled 36-character string is noise. A labeled one tells a burglar you hold coins.
The right split is secrets on metal, context in the vault. Context means plate locations, reconstruction rules, derivation paths: what gets lost when you’re not there to explain it, and not what an attacker needs.
One caveat on the xpub, since I told you to record it. It isn’t a spending key, but it exposes every address you’ve derived, your balance, and your full transaction history to anyone who reads it. Keep it with the context rather than the secrets, and never on the same plate as the passphrase.
Inheritance
Four unlabeled plates across four sites means heirs find two piles of metal with random words and no idea they combine.
Decide explicitly: Shamir, sealed instructions with an attorney, or nothing. Default-by-omission means the coins die with you. This is a decision, not an oversight to discover later.
VIII. Two designs that look smarter than they are
Multisig, probably not for this reason
Multi-vendor multisig does protect against an entropy bug. A quorum only breaks if enough of its devices are vulnerable, and the wallets swept in this class of incident are single-signature.
But that protection is incidental. Dice entropy fixes the same problem for fifty dice rolls instead of a permanent tripling of your operational surface. Dice-generate every seed in a 2-of-3 and multisig’s marginal value against this class of bug is zero. You already fixed it three times.
Dice entropy is a verifiable fix. Multisig is a diversification fix. Against a known, patched, entropy-class bug, verifiable wins.
Multisig genuinely protects against compromised signing firmware, supply-chain interception, physical extraction, single-location destruction, and coercion. None of those is what happened.
What it costs is descriptor loss as a new dominant failure mode. Seeds alone will not recover a multisig wallet, you need the full output descriptor. Add 3× the recovery testing, a coordinator software dependency, and materially harder inheritance.
Rule of thumb: if losing the stack wouldn’t change your life, single-sig with dice entropy. If it would, and you’ll actually run annual recovery drills, multisig. Amount and discipline decide this, not a news cycle. Reaching for multisig on the strength of a headline is solving the wrong problem at considerable cost.
The decoy wallet
The tempting design: same seed, small balance with no passphrase, majority behind a passphrase.
The two wallets link on-chain the moment you spend from both in a single transaction, which is the common-input-ownership heuristic, or the moment you fund one from the other, which is plain transaction-graph tracing and even more reliable. Surveillance firms run both by default. Once linked, the decoy advertises that its owner has a second, larger wallet, tied to whatever KYC exchange touched either side.
Worse, both derive from one seed. The decoy’s seed is the real wallet’s seed. And if you use the no-passphrase wallet for spending, you’re entering that seed on more devices, more often, increasing exposure of the secret that also guards cold storage.
Tiering only works if the tiers are independent. Use a second, separate seed for the hot wallet.
BIP-85 will derive a child seed from your master if a second ceremony is what’s stopping you, but know the trade: children are independent going forward, not backward. Whoever holds the master derives all of them. Fine for a hot wallet you accept losing, not a substitute for real separation.
On plausible deniability generally
Mostly theater. An attacker today knows BIP-39 passphrases exist and will keep asking. A decoy with a thin balance and no history reads as a decoy immediately. To be believable it needs years of activity and a balance large enough to hurt.
Use a passphrase because you want your seed backup to be useless alone. Not because you think it wins a wrench attack. That one is solved by nobody knowing you hold coins.
IX. What “don’t trust, verify” actually costs
The whole verifiable-entropy upgrade:
- Dice-generate seed, 50 rolls: about 10 minutes
- Dice-generate passphrase, 36 rolls: about 7 minutes
- Recompute the mnemonic from your roll string offline: about 15 minutes
- Cross-check against two BIP-39 implementations: about 20 minutes
- Full restore drill, twice: about an hour
- Steel plates, four sites: one afternoon plus hardware
That’s an afternoon. It closes an entire class of failure that took years to surface, drained hundreds of wallets, and was invisible to everyone, including the manufacturer and its own code review.
The failure that takes your coins is not cryptographic. It’s a steel plate in a house fire with the only other copy in the same drawer. It’s a passphrase you were certain you’d stamped correctly. It’s heirs holding metal they can’t interpret.
That part is entirely within your control. Do the drill.
The one-line version
Nobody who lost coins here did anything wrong; the flaw was undetectable and that’s the whole point. I held an affected device and wasn’t drained, not through any decision I’d reasoned my way to, but because two accidents of configuration made me more expensive than the next wallet in the queue. Queue position is not a security model. Roll your own dice for the seed and the passphrase, verify the rolls actually became the seed, because a ceremony you didn’t check is a ceremony you didn’t perform, and rotate a weak seed even if nothing was taken, because weak entropy doesn’t heal. Then spend your remaining effort on storage and inheritance, since that’s where the coins actually go missing.
I’m not a cryptographer. Everything here is arithmetic you can redo, and I’ve tried to show enough of it that you can catch my errors. Verify roll counts, hashes, and vendor guidance against primary sources before you act on any of it. Where I’ve been wrong before, it’s been where I was most confident.
Write a comment