* [bitcoindev] MHFE: memory-hard encryption of BIP39 backups into 24 words — request for review
@ 2026-10-01 16:46 Sergei Semenov
0 siblings, 0 replies; only message in thread
From: Sergei Semenov @ 2026-10-01 16:46 UTC (permalink / raw)
To: Bitcoin Development Mailing List
[-- Attachment #1.1: Type: text/plain, Size: 5622 bytes --]
Hi everyone,
I’m sharing *MHFE (Memory-Hard Feistel Encryption)*, an experimental
specification for encrypting an existing English BIP39 mnemonic with a
password into another checksum-valid, 24-word BIP39 mnemonic—the *container*
.
It is designed for *offline cold-storage backups*, particularly existing
metal plates and capsules. Recovery restores the exact original phrase: no
funds move, and the wallet remains unchanged. An existing BIP39 passphrase
stays separate and is applied after recovery as before.
- Specification, design analysis and test vectors
<https://github.com/hobby-eng/mhfe-spec>
- Reference implementation: Rust library, CLI and WebAssembly
<https://github.com/hobby-eng/mhfe>
A reference implementation is available as a Rust library, CLI and
WebAssembly package, alongside public test vectors and an independent
OpenSSL-based verification script. An offline HTML interface is also
available in the MHFE tab of Wallet Deriver, maintained in my separate
Multi-Chain Wallet Tools repository on Github.
One aspect I find particularly elegant is how the construction uses the
space left by shorter mnemonics. Their entropy occupies less than the
container’s 256-bit state. MHFE fills the remaining space with a recovery
verifier derived from SHA-256. Its leading bits are exactly the original
BIP39 checksum; the rest extend that same digest:
Original mnemonic -> source entropy + recovery verifier:
12 words -> 128 bits + 128 bits
15 words -> 160 bits + 96 bits
18 words -> 192 bits + 64 bits
21 words -> 224 bits + 32 bits
24 words -> 256 bits + no recovery verifier
The entire state is then encrypted and encoded as 24 BIP39 words with the
container’s own checksum. *The recovery check therefore requires no
additional backup words.* This verifier is distinct from a BIP32 wallet
fingerprint.
For someone creating a new wallet, this provides an explicit choice: *a
shorter original with an internal recovery check, or a 24-word original
with all 256 bits devoted to entropy and no internal password confirmation.*
For an existing wallet, its original length determines the layout. Verifier
matches can occur by chance and do not authenticate the container or
establish wallet identity; a trusted receiving address can check the
recovered wallet for either layout.
There is also *plausible deniability through prepared decoy wallets*. The
container itself opens as an ordinary BIP39 wallet. Additionally,
decrypting it with a different password and selecting 24 words produces
another valid mnemonic; the permutation under that password maps it back to
the same container. That alternative wallet can be funded and used
beforehand, allowing a working disclosure even when MHFE use is known.
The supplement
<https://github.com/hobby-eng/mhfe-spec/blob/main/docs/DESIGN-NOTES.md#deniability>
includes formal experiments and proofs for this deniability claim within
its stated model, including an adversary-advantage bound in the
random-oracle model. These depend on assumptions about password selection,
wallet history and external evidence. In particular, knowing that the real
original was shorter than 24 words defeats this alternative disclosure. The
proof has not received independent expert review and does not guarantee
that a coercer will believe the response or stop.
The construction uses a *12-round balanced Feistel permutation*. Each round
performs Argon2id with a state-derived salt. Defaults are *2 GiB, 12 passes
and four lanes per call*, with twelve sequential calls reusing memory.
Recovery takes roughly one to two minutes on the reference
laptop—deliberately expensive for an operation performed rarely. A strong,
independently generated password remains essential.
The salts aim to prevent reuse of expensive password computations across
independently generated source phrases. The analysis discusses SLIP-0039
and other related constructions, and documents an eleven-call password
filter when both source and container are known. Claims about the cheapest
attacks remain conjectures.
The fixed-size format has costs: it is deterministic, unauthenticated, and
carries no salt, version or settings fields. Long-term recovery therefore
needs compatible software and knowledge of any non-default settings.
Entering the container directly into a normal wallet opens an unrelated
wallet; MHFE recovery must come first.
I would especially welcome feedback on:
- *Cryptanalysis:* cheaper password filters, amortized attacks or
overlooked related constructions.
- *Deniability:* weaknesses or missing assumptions in the formal model.
- *Recovery and interoperability:* whether preserving exactly 24 backup
words justifies the tradeoffs, and what wallet developers would need
clarified.
The specification was developed with substantial ChatGPT and Claude
assistance, as disclosed in the document. It remains experimental and has
not received independent expert cryptographic review.
I would appreciate any technical feedback. Thank you for your time.
Best regards,
Sergei Semenov
--
You received this message because you are subscribed to the Google Groups "Bitcoin Development Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bitcoindev+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/bitcoindev/7917c5ea-82f2-4ce5-a5e4-b7415cca7441n%40googlegroups.com.
[-- Attachment #1.2: Type: text/html, Size: 6123 bytes --]
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-01 17:07 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-01 16:46 [bitcoindev] MHFE: memory-hard encryption of BIP39 backups into 24 words — request for review Sergei Semenov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox