ebellocchia / bip_utils

Generation of mnemonics, seeds, private/public keys and addresses for different types of cryptocurrencies
MIT License
324 stars 86 forks source link

Get addresses from non-standard path derivation... #87

Closed AlishaPink closed 1 year ago

AlishaPink commented 1 year ago

Hello!! Absolutely fantastic implementation of everything BIP. It's been great exploring it so far. Thank you for all your effort.

Now, i'm trying to generate addresses from non-standard path derivations, similar to some wallets such as Ledger, Coinomi. I figured out how to get the Xprv & Xpub from this path: m/44'/0'/0' But for the life of me, i can't figure out how to get a list of addresses from this path.

Here's what i have...

Code:

from bip_utils import Bip39SeedGenerator, Bip32Slip10Secp256k1, Bip44Changes

mnemonic = "park mushroom rabbit strategy project among settle between unit tube pulp right"
seed_bytes = Bip39SeedGenerator(mnemonic).Generate()

bip32_ctx = Bip32Slip10Secp256k1.FromSeed(seed_bytes).DerivePath("m/44'/0'/0'")

print(bip32_ctx.PrivateKey().ToExtended())
print(bip32_ctx.PublicKey().ToExtended())

Result:

xprv9xnTRxZAe8ryTA1LRBscM8FjfSqqq8xLo4AYu86WKK6iafY6uaYQev4v1Dm2ZA8qrF7uVrE1bYu8VWrvr7iUJiyBk2jDxGTyHFh5pQ3UGVK
xpub6BmoqU64UWRGfe5oXDQciGCUDUgLEbgCAH69hWW7sedhTTsFT7rfCiPPrVcD3146VTziZ2V31faz4ZRtrpTks6NpekoN5xCozeBibCzctoL

Verifying these extended keys on iancoleman's tool, they are correct for BIP32 derivation path, for client Coinomi, Ledger So the corresponding addresses should be... 1GqZcmFNkT1HGgnZ2PZMjNuKJWuSi3RB1q at m/44'/0'/0'/0 181ex1Bref1L4XpiqsmKVy8XL6r7bNh6ir at m/44'/0'/0'/1 And so on...

ebellocchia commented 1 year ago

Hello and thank you. If you derive keys using BIP32, you should use the proper address encoding class depending on the coin you need the address of (which is automatically selected if you use BIP44/49/...). In case of Bitcoin legacy address, you need the P2PKHAddrEncoder.

from bip_utils import Bip39SeedGenerator, Bip32Slip10Secp256k1, CoinsConf, P2PKHAddrEncoder

mnemonic = "park mushroom rabbit strategy project among settle between unit tube pulp right"
seed_bytes = Bip39SeedGenerator(mnemonic).Generate()

bip32_ctx = Bip32Slip10Secp256k1.FromSeed(seed_bytes).DerivePath("m/44'/0'/0'")

print(bip32_ctx.PrivateKey().ToExtended())
print(bip32_ctx.PublicKey().ToExtended())

# m/44'/0'/0'/0 -> 1GqZcmFNkT1HGgnZ2PZMjNuKJWuSi3RB1q
addr = P2PKHAddrEncoder.EncodeKey(
    bip32_ctx.DerivePath("0").PublicKey().KeyObject(),
    net_ver=CoinsConf.BitcoinMainNet.ParamByKey("p2pkh_net_ver")
)
print(addr)
# m/44'/0'/0'/1 -> 181ex1Bref1L4XpiqsmKVy8XL6r7bNh6ir
addr = P2PKHAddrEncoder.EncodeKey(
    bip32_ctx.DerivePath("1").PublicKey().KeyObject(),
    net_ver=CoinsConf.BitcoinMainNet.ParamByKey("p2pkh_net_ver")
)
print(addr)

Regards, Emanuele

AlishaPink commented 1 year ago

Oh god. I'm amazed at such a swift reply!!

I would've never got this solution myself haha... i swear i scoured the docs to no avail. 😅

Saved me a ton of time and frustration. Thank you so much 💕

ebellocchia commented 1 year ago

You can find the same solution in the BIP32 examples, like here and here. Instead, the address encoding/decoding classes are described here. But yeah, I agree that from this doc is not clear that they should be used together with BIP32.

Anyway no problem, feel free to ask questions if you have any doubt.