Skip to content

S2: BIP-39 mnemonics (Bitcoinex.BIP39)#109

Draft
SachinMeier wants to merge 2 commits into
sachin--slip39-1-utilsfrom
sachin--slip39-2-bip39
Draft

S2: BIP-39 mnemonics (Bitcoinex.BIP39)#109
SachinMeier wants to merge 2 commits into
sachin--slip39-1-utilsfrom
sachin--slip39-2-bip39

Conversation

@SachinMeier

Copy link
Copy Markdown
Collaborator

Stack: S0 → S1 → S2 → S3 → S4 → S5 → S6 (spec §3.2)

  • Bitcoinex.BIP39: entropy↔mnemonic with checksum validation, valid?/1, to_seed/2 (PBKDF2-HMAC-SHA512, NFKD on mnemonic+passphrase), to_master_private_key/3 feeding ExtendedKey.seed_to_master_private_key/2
  • All 24 official Trezor english vectors inlined (source URL + upstream sha256 recorded in the test file); vendored JSON removed
  • Properties: entropy round-trip across all 5 lengths; decoder-never-raises fuzz (arbitrary strings, valid-word sequences, 1–3 word substitutions asserting never-original-entropy)
  • CHANGELOG: Unreleased/Added entry

🤖 Generated with Claude Code

@SachinMeier

Copy link
Copy Markdown
Collaborator Author

Independent adversarial review (subagent) complete: no CRITICAL/MAJOR findings. All 24 inlined vectors re-verified against upstream (zero drift); independent Python BIP-39 implementation matched on mnemonic/seed/round-trip at all 5 entropy lengths with a Unicode passphrase.

Addressed in the follow-up commit:

  • strict whitespace validationmnemonic_to_entropy/1 now requires single-space separators (matching the reference implementation), closing the validate-lenient/derive-exact gap where a double-spaced mnemonic could validate yet derive a non-interoperable key
  • clear ArgumentError on non-UTF8 mnemonic/passphrase in to_seed/2
  • {:error, "invalid extended private key prefix"} for unknown prefix atoms (was a CaseClauseError crash)
  • removed redundant bare function head

SachinMeier and others added 2 commits July 1, 2026 21:26
Add Bitcoinex.BIP39 with entropy_to_mnemonic/1, mnemonic_to_entropy/1,
valid?/1, to_seed/2, and to_master_private_key/3. The english word list
is loaded at compile time via Bitcoinex.Wordlist.load!/2 from
priv/bip39_english.txt; seeds are derived with PBKDF2-HMAC-SHA512
(2048 iterations, 64 bytes) over the NFKD-normalized mnemonic and
passphrase, and master keys via ExtendedKey.seed_to_master_private_key/2.

Tests transcribe all 24 official Trezor english vectors inline as
@bip39_vectors (test/data/bip39_vectors.json removed) and cover every
error atom, NFKD normalization, seed/xprv derivation, plus stream_data
properties: entropy round-trips for all five lengths, decoder fuzzing
on arbitrary strings and random valid-word sequences, and 1-3 word
substitutions never decoding to the original entropy.

Also add a CHANGELOG Unreleased entry for BIP-39.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- reject non-canonical whitespace in mnemonic_to_entropy (single-space
  separators only, matching the reference implementation) so validation
  can never bless a mnemonic whose byte-exact seed differs from the
  canonical form
- raise a clear ArgumentError on non-UTF8 mnemonic/passphrase in to_seed
- return {:error, "invalid extended private key prefix"} for unknown
  prefix atoms instead of crashing in ExtendedKey
- drop redundant bare function head

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@SachinMeier SachinMeier force-pushed the sachin--slip39-1-utils branch from 421dd8f to f259342 Compare July 2, 2026 04:27
@SachinMeier SachinMeier force-pushed the sachin--slip39-2-bip39 branch from 9896406 to 6b4eeab Compare July 2, 2026 04:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant