I am implementing bip32 for my wallet as a project to learn Bitcoin.
I am following this documentation:
Since I am not implementing bip39 yet, I am getting the master private key and code chain from the BIP39 Root Key from this web:
using a random set of words which are:
praise vague cruise stem test gesture twin long donate violin special hamster horror rough loan
Comparing this output with another web implementation here: https://iancoleman.io/bip39/
These two outputs match. However, after this point they don’t. And my implementation doesn’t match with any of those implementations!
Here is my python code where I deserialize the BIP32 extended key. This matches perfectly with the master private key and chain code from the second web app:
def deserialize_xprvk(s): version = s.read(4) depth = s.read(1) fingerprint = s.read(4) index= s.read(4) chain_code = s.read(32) s.read(1) privkey = s.read(32) return [version,depth, fingerprint,index,chain_code,privkey] decoded =deserialize_xprvk( BytesIO(decode_base58_extended(xtprvk)))
printing “decoded” I get:
0x488ade4 0x0 0x0 0x0 0x10e85c06826fdcd006c244ff6c44200044c1418bdd82cc088c33e48ae7b4c2ca 0xf214c0afd9b311544fdb686cae5100f1ac0ac8aba2b6c55719ba41ac2d4f2d12
which matches perfectly with the 2nd implementation (the firs one doesn’t show the master private key or chain code).
Then I try to follow the instructions from here:
to derivate the child PRIVATE KEY with index 0 for this master key and chain code like this:
#The order of the ciclic group in the finite field of the ecliptic curve N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 #creates a string to emulate the index in a 4-byte hex format. def str_i(i): i_str = hex(i)[2:] while len(i_str)<8: i_str="0"+i_str return i_str pub_key = PrivateKey(int.from_bytes(master_priv_key,"big")).point.sec() #I put an extra "0" because every public key begins with a "02" or "03" but #the hex() function commits this character. #The str_i(0) means I am trying to get the index 0. msg=("0" + hex(int.from_bytes(pub_key,"big"))[2:] + str_i(0)).encode() I= hmac.new( key = hex(int.from_bytes(chain_code,"big"))[2:].encode() , msg=msg , digestmod=sha512).digest() I_L, I_R = I[:32], I[32:] child_privkey_int = (int.from_bytes(I_L,"big") + int.from_bytes(master_priv_key,"big"))%N child_privkey = PrivateKey(child_privkey_int).wif(compressed= True) child_chain_code = I_R
If I run this code and try to get the child private key for path m\0\0\ I get:
But in the first web app they get:
And in the second one they get:
Is it ok to disagree on different implementations?? or am I doing something really wrong? I am starting to pull off my hair trying to find out where I am messing up.