def bip32_crack(parent_xpub, child_xprv): parent_xpub = b58decode_check(parent_xpub) assert len(parent_xpub ) == 78, "wrong length for decoded extended parent public key" assert parent_xpub[45] in (2, 3), "extended parent key is not a public one" child_xprv = b58decode_check(child_xprv) assert len(child_xprv ) == 78, "wrong length for decoded extended child private key" assert child_xprv[45] == 0, "extended child key is not a private one" # check depth assert child_xprv[ 4] == parent_xpub[4] + 1, "wrong child/parent depth relation" # check fingerprint Parent_bytes = parent_xpub[45:] assert child_xprv[5:9] == h160( Parent_bytes)[:4], "not a child for the provided parent" # check normal derivation child_index = child_xprv[9:13] assert child_index[0] < 0x80, "hardened derivation" parent_xprv = child_xprv[:4] # version parent_xprv += parent_xpub[4:5] # depth parent_xprv += parent_xpub[5:9] # parent pubkey fingerprint parent_xprv += parent_xpub[9:13] # child index parent_chain_code = parent_xpub[13:45] parent_xprv += parent_chain_code # chain code h = HMAC(parent_chain_code, Parent_bytes + child_index, sha512).digest() offset = int.from_bytes(h[:32], 'big') child = int.from_bytes(child_xprv[46:], 'big') parent = (child - offset) % ec.order parent_bytes = b'\x00' + parent.to_bytes(32, 'big') parent_xprv += parent_bytes # private key return b58encode_check(parent_xprv)
#extended keys ext_prv = b58encode_check(xprv + idf + chain_code + p_bytes) print("\nm") print(ext_prv) ext_pub = b58encode_check(xpub + idf + chain_code + P_bytes) print("M") print(ext_pub) assert ext_prv == b"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6", "failure" assert ext_pub == b"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13", "failure" # ==first (0) hardened child== depth = b'\x01' child_number = 0 + 0x80000000 #hardened child_number = child_number.to_bytes(4, 'big') fingerprint = h160(P_bytes)[:4] idf = depth + fingerprint + child_number key = p_bytes if child_number[0] > 127 else P_bytes hashValue = HMAC(chain_code, key + child_number, sha512).digest() p = (p + int(hashValue[:32].hex(), 16)) % ec.order p_bytes = b'\x00' + p.to_bytes(32, 'big') P = ec.pointMultiply(p) P_bytes = (b'\x02' if (P[1] % 2 == 0) else b'\x03') + P[0].to_bytes(32, 'big') chain_code = hashValue[32:] ext_prv = b58encode_check(xprv + idf + chain_code + p_bytes) print("\nm/0'") print(ext_prv) ext_pub = b58encode_check(xpub + idf + chain_code + P_bytes) print("M/0'")
def bip32_ckd(xparentkey, index): """Child Key Derivation (CDK) Key derivation is normal if the extended parent key is public or child_index is less than 0x80000000. Key derivation is hardened if the extended parent key is private and child_index is not less than 0x80000000. """ if isinstance(index, int): index = index.to_bytes(4, 'big') elif isinstance(index, bytes) or isinstance(index, bytearray): assert len(index) == 4 else: raise TypeError("a 4 bytes int is required") xparent = b58decode_check(xparentkey) assert len(xparent) == 78, "wrong length for extended parent key" version = xparent[:4] xkey = version # version xkey += (xparent[4] + 1).to_bytes(1, 'big') # (increased) depth if (version in PUBLIC): assert xparent[45] in (2, 3), \ "version/key mismatch in extended parent key" Parent_bytes = xparent[45:] Parent = ec.tuple_from_point(Parent_bytes) xkey += h160(Parent_bytes)[:4] # parent pubkey fingerprint assert index[0] < 0x80, \ "no private/hardened derivation from pubkey" xkey += index # child index parent_chain_code = xparent[13:45] ## normal derivation h = HMAC(parent_chain_code, Parent_bytes + index, sha512).digest() xkey += h[32:] # chain code offset = int.from_bytes(h[:32], 'big') Offset = ec.pointMultiply(offset) Child = ec.pointAdd(Parent, Offset) Child_bytes = ec.bytes_from_point(Child, True) xkey += Child_bytes # public key elif (version in PRIVATE): assert xparent[45] == 0, "version/key mismatch in extended parent key" parent = int.from_bytes(xparent[46:], 'big') Parent = ec.pointMultiply(parent) Parent_bytes = ec.bytes_from_point(Parent, True) xkey += h160(Parent_bytes)[:4] # parent pubkey fingerprint xkey += index # child index parent_chain_code = xparent[13:45] if (index[0] < 0x80): ## normal derivation h = HMAC(parent_chain_code, Parent_bytes + index, sha512).digest() else: ## hardened derivation h = HMAC(parent_chain_code, xparent[45:] + index, sha512).digest() xkey += h[32:] # chain code offset = int.from_bytes(h[:32], 'big') child = (parent + offset) % ec.order child_bytes = b'\x00' + child.to_bytes(32, 'big') xkey += child_bytes # private key else: raise ValueError("invalid extended key version") return b58encode_check(xkey)