Skip to content

Conversation

@pjkundert
Copy link
Contributor

Adds SLIP-39 (Shamir's Secret Sharing) mnemonic and seed support to python-hdwallet:

  • Implements SLIP39 mnemonic generation and validation with multi-share threshold schemes
  • Adds SLIP39 entropy handling and seed derivation functionality
  • Adds Nix development environment setup for reproducible builds
  • Comprehensive test coverage for all new SLIP39 functionality

Benefits

  • Enables secure multi-party wallet recovery through threshold secret sharing
  • Maintains backward compatibility with existing BIP39 workflows
  • Provides standardized SLIP39 implementation following official specifications
  • Improves development workflow with Nix environment automation

Test Plan

  • All existing tests pass
  • New SLIP39-specific test suites cover mnemonic generation, validation, and seed derivation
  • CLI integration tests verify SLIP39 functionality end-to-end

@meherett meherett requested review from axiom90 and meherett August 21, 2025 11:09
@pjkundert pjkundert force-pushed the feature/seeds branch 4 times, most recently from 4518382 to 1a2261d Compare August 21, 2025 15:21
Copy link
Collaborator

@axiom90 axiom90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved.

@pjkundert pjkundert force-pushed the feature/seeds branch 2 times, most recently from c352070 to a567114 Compare August 22, 2025 01:07
@pjkundert
Copy link
Contributor Author

Sorry, @axiom90! I pushed another enhancement to the SLIP39Mnemonic.decode and .decode, to support human-readable SLIP-39 Mnemonics via tabulate. It's difficult for humans to reliably parse these huge sets of Mnemonics, so this gives output in a readable Human form, that also parses reliably for recovery.

@axiom90 axiom90 self-requested a review August 23, 2025 16:04
Copy link
Collaborator

@axiom90 axiom90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, Re-approved.

@pjkundert
Copy link
Contributor Author

OK, thanks!

There are still issues with the way Mnemonics are handled; BIP-39 mnemonics with accents (such as 'déclarer') are not handled correctly. Also, determining language from a set of mnemonics is not deterministic.

I'm working through these issues right now, so don't merge this yet...

@meherett meherett added good first issue Good for newcomers enhancement New feature or request labels Sep 12, 2025
@pjkundert
Copy link
Contributor Author

OK, @meherett @axiom90 -- this is ready to take a look at.

The fundamental problem, is that Mnemonic languages are not deterministic, especially when accents and other letter UTF-8 "Marks" are ignored; generally required by all Mnemonic parsers. And, when abbreviations are allowed, it's even worse.

Thus, it is quite easy to come up with entropy that decodes to a Mnemonic phrase that is valid in english AND french; if you then decode that Mnemonic to try to recover the entropy (you originally asked for the french Mnemonic), you can end up with the wrong seed (decoded as English)!

So, I've improved the mnemonic APIs to support a preferred language for decoding the Mnemonic. This leaked into many parts of the code, unfortunately.

As part of this fix -- I've also implemented hdwallet.imnemonic.WordIndices; a Trie-based Mnemonic decoder that supports abbreviations and optional accents. It looks a lot like a simple {'word': } dictionary, but also supports the reverse mapping {: 'word'}, and supports indexing by unambiguous abbreviations.

This allowed me to implement IMnemonic.collect -- you give it a list of languages, and it produces a Generator that computes the remaining language(s) that are possible, and all of the "Next" characters that are valid for the mnemonic word in those languages. See tests/test_bip39_cross_language.py, test_bip39_collection.

Anyway, take a look. This pull might need some more documentation updates before acceptance.

@pjkundert
Copy link
Contributor Author

Well, I found another pretty much intractable issue with the current implementation of Mnemonic language deduction and decoding.

You just cannot separate langage deduction from decoding.

  1. The IMnemonic.find_language interface is purely "statistical", guessing whether a Mnemonic looks like english, french, etc. Unfortunately (and handling abbreviations and optional UTF-8 Marks made this worse), many mnemonics "look" valid in multiple languages, even if they are not.

  2. It is possible to end up generating Mnemonics that are completely valid in multiple languages, and also pass their internal "checksum" validation. These can only be detected when IMnemonic.decode is run, so that is where this exception has to be raised, not in .find_language.

So, this now implements full multi-language IMnemonic.decode across all of the implemented mnemonic types. If multiple languages might look valid, the .decode will attempt them all, and ensure that exactly one language correctly decodes the Mnemonic, failing if none do, or if multiple languages correctly decode it -- unless a preferred language is specified.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request good first issue Good for newcomers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants