This is some working code for calculating a dad or mum prolonged non-public key from a grasp prolonged public key and baby prolonged non-public key.
#!/usr/bin/env python3
# pip set up hdwallet
# pip set up bitcoin-utils
import hmac
import hashlib
import struct
from binascii import unhexlify
from base58check import b58encode
from hdwallet import HDWallet as HDWallet
from hdwallet.symbols import BTC as SYMBOL
# --------------------
# Offered info
# --------------------
# Grasp Prolonged Public Key (m)
MASTER_EXTENDED_PUBLIC_KEY: str = "xpub661MyMwAqRbcF2s3gyqdcUgw6dU7DjLGHCwkM9jndzGT8WXJjMxZiYnvNmfuzsEXC13FUn9BTeefy3uYf4Cj5k86iHUFzLS1yatpXN9hq4u"
# Little one Prolonged Personal Key (m/44/0/0/1/404)
CHILD_EXTENDED_PRIVATE_KEY: str = "xprvA3WvYTa5Xv4kSXuL9mAFMimc5psTTB1Dq8x4q9HB7R4EmpufsXFuhi9SpVVYXsmyjM5dvoGowU3W9hDuYRrgkQiiE1d881TZrFLhLNxBs7g"
# ------
# Technique
# ------
# Initialize a pockets
hdwallet: HDWallet = HDWallet(image=SYMBOL)
# Create a HDWallet from the grasp prolonged public key
hdwallet.from_xpublic_key(xpublic_key=MASTER_EXTENDED_PUBLIC_KEY, strict=True)
# Get the dad or mum prolonged public key at m/44/0/0/1
# We want this in order that we will calculate the prolonged non-public key at m/44/0/0/1 (the extent above the kid non-public key that has been revealed)
PARENT_EXTENDED_PUBLIC_KEY = hdwallet.from_path("m/44/0/0/1")
PARENT_PUBLIC_KEY: str = PARENT_EXTENDED_PUBLIC_KEY.public_key()
PARENT_CHAIN_CODE: str = PARENT_EXTENDED_PUBLIC_KEY.chain_code()
print("Guardian Prolonged Public Key (m/44/0/0/1):", PARENT_EXTENDED_PUBLIC_KEY.xpublic_key())
print(" Public Key:", PARENT_PUBLIC_KEY)
print(" Chain Code:", PARENT_CHAIN_CODE)
print("")
# Extract the uncooked non-public key from the kid prolonged non-public key m/44/0/0/1/404
# We want this in order that we will calculate the dad or mum prolonged non-public key
baby: HDWallet = HDWallet(image=SYMBOL)
baby.from_xprivate_key(xprivate_key=CHILD_EXTENDED_PRIVATE_KEY, strict=False) # False permits you to initialize from a non-root prolonged key
CHILD_PRIVATE_KEY: str = baby.private_key()
print("Little one Personal Key:", CHILD_PRIVATE_KEY)
print("")
# Calculate the dad or mum prolonged non-public key for m/44/0/0/1 (that is the mathematical bit)
# Put the chain code and (dad or mum public key + index) via HMAC-SHA512
# This step is utilized in HD Wallets when deriving non-hardened kids for each non-public and public prolonged keys
index = struct.pack(">L", 404) # Use the identical index quantity because the baby prolonged non-public key that we all know
knowledge = unhexlify(PARENT_PUBLIC_KEY) + index
hmac_result = hmac.new(unhexlify(PARENT_CHAIN_CODE), knowledge, hashlib.sha512).hexdigest()
# Get the left aspect of the hmac digest (the left 32 bytes)
hmac_result_left = hmac_result[:64]
# Calculate the dad or mum non-public key (baby non-public key - hmac left)
# Notice: All non-public keys have to be modulo the variety of factors on the Secp256k1 curve
secp256k1_n = 115792089237316195423570985008687907852837564279074904382605163141518161494337
PARENT_PRIVATE_KEY: str = ((int(CHILD_PRIVATE_KEY, 16) - int(hmac_result_left, 16)) % secp256k1_n).to_bytes(32, "large").hex()
print("Guardian Personal Key:", PARENT_PRIVATE_KEY)
# Create an deal with for the dad or mum prolonged non-public key
# That is in order that we will intialize a brand new HD Pockets utilizing the prolonged non-public key and use it to derive kids simply utilizing the library
# Get the fingerprint, which might be discovered from the dad or mum of this dad or mum prolonged public key
parent_parent_extended_public_key: HDWallet = HDWallet(image=SYMBOL)
parent_parent_extended_public_key.from_xpublic_key(xpublic_key=MASTER_EXTENDED_PUBLIC_KEY, strict=True)
parent_fingerprint = parent_parent_extended_public_key.from_path("m/44/0/0").finger_print()
# Serialize all the info for the dad or mum prolonged non-public key
model = "0488ade4" # xprv (BIP)
depth = "04" # what number of ranges deep this prolonged secret is from grasp, so m/44/0/0/1 = 4
index = "00000001" # the index variety of this prolonged key from its dad or mum, which is the final variety of m/44/0/0/1
chain_code = PARENT_CHAIN_CODE
knowledge = "00" + PARENT_PRIVATE_KEY
uncooked = (model + depth + parent_fingerprint + index + chain_code + knowledge)
# Create a checksum for this serialized knowledge (first 4 bytes of the hash256 of the uncooked knowledge above)
checksum = hashlib.sha256(hashlib.sha256(unhexlify(uncooked)).digest()).hexdigest()[0:8]
# Create deal with by changing to base58
PARENT_EXTENDED_PRIVATE_KEY = b58encode(unhexlify(uncooked + checksum)).decode("utf-8")
print("Guardian Prolonged Personal Key (m/44/0/0/1):", PARENT_EXTENDED_PRIVATE_KEY)
print("")
# -----
# Utilization
# -----
# Now that we have calculated the prolonged non-public key for m/44/0/0/1, we will calculate all the baby keys beneath it.
# For instance, we will calculate the prolonged non-public key at m/44/0/0/1/402
# Initialize a brand new pockets from the deal with for this dad or mum prolonged non-public key at m/44/0/0/1
dad or mum: HDWallet = HDWallet(image=SYMBOL)
dad or mum.from_xprivate_key(xprivate_key=PARENT_EXTENDED_PRIVATE_KEY, strict=False) # False permits you to initialize from a non-root prolonged key
# Derive the prolonged non-public key at m/44/0/0/1/402
instance = dad or mum.from_path("m/402") # Notice: That is m/44/0/0/1/402, as a result of we're ranging from m/44/0/0/1
print("Instance (m/44/0/0/1/402):", instance.xprivate_key())
# ------
# Checks
# ------
# I already knew the grasp prolonged non-public key for this pockets, so we will use it to test that it derives the identical prolonged non-public key at m/44/0/0/1/402 because the dad or mum prolonged non-public key we calculated.
MASTER_EXTENDED_PRIVATE_KEY: str = "xprv9s21ZrQH143K2YnaaxJdFLkCYbdcpGcQuz29YmLB5ejUFiCABpeKAkUSXVuqysESjMJhk8yTfhxR3BT6Ag7Z5fYJ1jFgidmrGgfZYNCLnNB"
test: HDWallet = HDWallet(image=SYMBOL)
test.from_xprivate_key(xprivate_key=MASTER_EXTENDED_PRIVATE_KEY, strict=True) # False permits you to initialize from a non-root prolonged key
test.from_path("m/44/0/0/1/402")
print("Test (m/44/0/0/1/402):", test.xprivate_key())
Firstly, two caveats:
- I am not excellent at Python, and I’ve not used the
hdwallet
orbitcoin-utils
Python libraries earlier than. - There are no built-in strategies in these libraries for this, so I labored with what was out there. I needed to carry out some steps manually (e.g. changing a uncooked non-public key in to an deal with).
So mainly the code could be very tough, and I simply did the naked minimal to get it working.
Secondly, I’ve solely labored out the prolonged non-public key on the m/44/0/0/1
stage of the tree. This lets you work out all of the baby keys beneath that stage solely.
Due to this fact, if you happen to wished to calculate a baby prolonged non-public key at m/44/0/0/0/402
for instance, you would want to work backwards once more to calculate the prolonged non-public key at m/44/0/0
first. This may be achieved by calculating the prolonged public key at m/44/0/0
(from the grasp prolonged public key), then utilizing this together with the newly-calculated prolonged non-public key at m/44/0/0/1
to calculate the dad or mum prolonged non-public key above it at m/44/0/0
. From right here you’ll be able to then derive right down to m/44/0/0/0/402
.
The above might be achieved by repeating the related components of code.
I have never given the precise resolution to your problem, as I did not need take away from the training expertise, and this incorporates the code it is advisable to get began.
In equity, it is a pretty advanced problem that requires understanding of how HD Wallets work, and it isn’t one thing that you’d be capable of remedy utilizing the default capabilities discovered inside a library. It could in all probability helpful to write down your personal library for this sort of stuff.
Nonetheless, hopefully this code helps to get you heading in the right direction.
This web page explains among the particulars: https://learnmeabitcoin.com/technical/extended-keys
Previous reply
Utilizing a modified model of the instance code from right here: https://github.com/meherett/python-hdwallet/blob/grasp/examples/from_xprivate_key.py
#!/usr/bin/env python3
from hdwallet import HDWallet as HDWallet
from hdwallet.symbols import BTC as SYMBOL
# Bitcoin root xprivate key
XPRIVATE_KEY: str = "xprv9s21ZrQH143K2YnaaxJdFLkCYbdcpGcQuz29YmLB5ejUFiCABpeKAkUSXVuqysESjMJhk8yTfhxR3BT6Ag7Z5fYJ1jFgidmrGgfZYNCLnNB"
# Initialize Bitcoin mainnet HDWallet
hdwallet: HDWallet = HDWallet(image=SYMBOL)
# Get Bitcoin HDWallet from xprivate key
hdwallet.from_xprivate_key(xprivate_key=XPRIVATE_KEY, strict=True)
# Derivation from path
hdwallet.from_path("m/44/0/0/1/404")
# Print outcomes
print("Root XPrivate Key:", hdwallet.root_xprivate_key())
print("XPrivate Key:", hdwallet.xprivate_key())
You will want to switch the grasp prolonged non-public key with your personal. This code simply incorporates an instance for testing.
I have never used this library earlier than, so I can not clarify an excessive amount of about the right way to use it. However this instance ought to get you going.
EDIT:
Sorry I simply realized your asking to derive an prolonged non-public key from a grasp prolonged public key.
It is not potential to derive non-public keys from a grasp prolonged public key in a HD pockets. Are you certain that is what you are being requested to do with this problem?