Categories
Bitcoin Cryptocurrency Mastering Development

Why does my BIP32 implementation throw different results than other web implementations? They also disagree with each other tho

I am implementing bip32 for my wallet as a project to learn Bitcoin.

I am following this documentation:
https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki

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:
https://iancoleman.io/bip39/#english

using a random set of words which are:

praise vague cruise stem test gesture twin long donate violin special hamster horror rough loan

which throws:

xprv9s21ZrQH143K2E7weJFDreP9A8dFkx18swFoAJ6DBdsVuSPoFBLzekLca8vEG1i6ikCcvzZb79joaEZAjeM8Nz1DZ549aCnv3YFXy33mLoW

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:
https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
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:

“L29Rc5PyDkbUr2z1VcL2DuAhTQkNo3qwF7ENgRotS86ADUkiXPJF”

But in the first web app they get:
“KwuPS3DGMnCc3jMJWtqVVzkCoMyhybxGZrf68fPBEBtFfujBdPGs”

And in the second one they get:
“L1TcvgkPZFa6DyXhv9vYWceTXZhoAR7ZQMdt5rqV6LW3Zutpsqr8”

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.

Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *