Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement] Bip39PrivateKey class #48

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

kdmukai
Copy link
Contributor

@kdmukai kdmukai commented Feb 2, 2023

This Bip39PrivateKey class extends PrivateKey.

It takes a BIP-39 mnemonic as its input (or randomly generates a new one for you) and then derives the Nostr PK using the NIP-06 derivation path.

Examples

# Generates a new random BIP-39 mnemonic
pk = Bip39PrivateKey()
print(pk.mnemonic)
> ['mechanic', 'dwarf', 'quit', ...]


# But it can still do all Nostr PrivateKey operations
pk.bech32()
> 'nsec14535ueh...'

pk.public_key.bech32()
> 'npub156jvsjq...'

event = Event(public_key=pk.public_key.hex(), content="Hello, world!")
pk.sign_event(event)


# Initialize from a user-supplied BIP-39 mnemonic
my_mnemonic = "power wolf resource spread ...".split() 
pk = Bip39PrivateKey(my_mnemonic)

# Initialize from a user-supplied BIP-39 mnemonic + BIP-39 passphrase
pk = Bip39PrivateKey(my_mnemonic, passphrase="SatoshiOnTheBrink")

# Opt for a randomly generated 12-word mnemonic instead
pk = Bip39PrivateKey.with_mnemonic_length(12)

Notes

embit

Adds Stepan Snigirev's embit library as a dependency. This is the library that powers the higher-level bitcoin operations for the Specter-DIY hardware wallet, Specter Desktop, SeedSigner, and Krux.

Note that embit includes its own copy of Pieter Wiulle's bec32.py script, but it is an older version that has since had breaking changes. embit's copy is isolated within its package name so there shouldn't be any conflicts.

Bip39PrivateKey.with_mnemonic_length

I wanted to provide an option to specify a 12-word mnemonic. At first glance it seems like it would have been simpler to just offer an optional mnemonic_length attr when creating a new instance. Except there's no clear way to communicate the intention of that field when I'm providing my own mnemonic.

If I had implemented it that way:

# Do I have to specify the length every time?
Bip39PrivateKey(my24word_mnemonic, mnemonic_length=24)

# What if they don't match?
Bip39PrivateKey(my24word_mnemonic, mnemonic_length=12)

# Doesn't even really look right when used properly
Bip39PrivateKey(mnemonic_length=12)

So instead, I just pulled it out into its own classmethod:

Bip39PrivateKey.with_mnemonic_length(12)

Debatable decision but seemed like the least confusing option.


Misc

Bumps required python version in the pyproject.toml to ">=3.9.0". The type hints that use the typing module work fine in earlier versions of python3, but elsewhere in the code there are newer type hints that were introduced in python3.9 and are not backwards-compatible. I'll probably look to make a future PR that would enable support down to python3.7 which is not yet at EOL. I'm not aware of any advantages of the new type hints from python3.9 (other than avoiding eventual future deprecation of the typing module).

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