def bip32_crack(parent_xpub: bytes, child_xprv: bytes) -> bytes: parent_xpub = b58decode_check(parent_xpub, 78) assert parent_xpub[45] in (2, 3), "extended parent key is not a public one" child_xprv = b58decode_check(child_xprv, 78) 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.n 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"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi", "failure" assert ext_pub == b"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8", "failure" # ==first (0) hardened child== depth = b'\x01' child_number = 0 + 0x80000000 #hardened child_number = child_number.to_bytes(4, byteorder='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, byteorder='big') P = ec.pointMultiply(p, ec.G) P_bytes = bytes_from_Point(ec, P, True) 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: octets, index: Union[octets, int]) -> bytes: """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, str): # hex string index = bytes.fromhex(index) if len(index) != 4: raise ValueError(f"a 4 bytes int is required, not {len(index)}") xparent = b58decode_check(xparentkey, 78) version = xparent[:4] # serialization data xkey = version # version xkey += (xparent[4] + 1).to_bytes(1, 'big') # (increased) depth if (version in PUBLIC): if xparent[45] not in (2, 3): # not a compressed public key raise ValueError("version/key mismatch in extended parent key") Parent_bytes = xparent[45:] Parent = octets2point(ec, Parent_bytes) xkey += h160(Parent_bytes)[:4] # parent pubkey fingerprint if index[0] >= 0x80: raise ValueError("no private/hardened derivation from pubkey") xkey += index # child index parent_chain_code = xparent[13:45] # normal derivation # actual extended key (key + chain code) derivation h = HMAC(parent_chain_code, Parent_bytes + index, sha512).digest() offset = int.from_bytes(h[:32], 'big') Offset = pointMult(ec, offset, ec.G) Child = ec.add(Parent, Offset) Child_bytes = point2octets(ec, Child, True) xkey += h[32:] # chain code xkey += Child_bytes # public key elif (version in PRIVATE): if xparent[45] != 0: # not a private key raise ValueError("version/key mismatch in extended parent key") parent = int.from_bytes(xparent[46:], 'big') Parent = pointMult(ec, parent, ec.G) Parent_bytes = point2octets(ec, Parent, True) xkey += h160(Parent_bytes)[:4] # parent pubkey fingerprint xkey += index # child index # actual extended key (key + chain code) derivation 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() offset = int.from_bytes(h[:32], 'big') child = (parent + offset) % ec.n child_bytes = b'\x00' + child.to_bytes(32, 'big') xkey += h[32:] # chain code xkey += child_bytes # private key else: raise ValueError("invalid extended key version") return b58encode_check(xkey)
def bip32_ckd(xparentkey: bytes, index: Union[bytes, int]) -> bytes: """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): assert len(index) == 4 else: raise TypeError("a 4 bytes int is required") xparent = b58decode_check(xparentkey, 78) version = xparent[:4] # serialization data 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 = tuple_from_Point(ec, 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 # actual extended key (key + chain code) derivation h = HMAC(parent_chain_code, Parent_bytes + index, sha512).digest() offset = int.from_bytes(h[:32], 'big') Offset = ec.pointMultiply(offset, ec.G) Child = ec.pointAdd(Parent, Offset) Child_bytes = bytes_from_Point(ec, Child, True) xkey += h[32:] # chain code 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, ec.G) Parent_bytes = bytes_from_Point(ec, Parent, True) xkey += h160(Parent_bytes)[:4] # parent pubkey fingerprint xkey += index # child index # actual extended key (key + chain code) derivation 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() offset = int.from_bytes(h[:32], 'big') child = (parent + offset) % ec.order child_bytes = b'\x00' + child.to_bytes(32, 'big') xkey += h[32:] # chain code xkey += child_bytes # private key else: raise ValueError("invalid extended key version") return b58encode_check(xkey)