def get_pubkey_at_path(self, path): if not check_keypath(path): raise BadArgumentError("Invalid keypath") path = path[2:] path = path.replace("h", "'") path = path.replace("H", "'") # This call returns raw uncompressed pubkey, chaincode pubkey = self.app.getWalletPublicKey(path) if path != "": parent_path = "" for ind in path.split("/")[:-1]: parent_path += ind + "/" parent_path = parent_path[:-1] # Get parent key fingerprint parent = self.app.getWalletPublicKey(parent_path) fpr = hash160(compress_public_key(parent["publicKey"]))[:4] # Compute child info childstr = path.split("/")[-1] hard = 0 if childstr[-1] == "'" or childstr[-1] == "h" or childstr[ -1] == "H": childstr = childstr[:-1] hard = 0x80000000 child = struct.pack(">I", int(childstr) + hard) # Special case for m else: child = bytearray.fromhex("00000000") fpr = child chainCode = pubkey["chainCode"] publicKey = compress_public_key(pubkey["publicKey"]) depth = len(path.split("/")) if len(path) > 0 else 0 depth = struct.pack("B", depth) if self.is_testnet: version = bytearray.fromhex("043587CF") else: version = bytearray.fromhex("0488B21E") extkey = version + depth + fpr + child + chainCode + publicKey checksum = hash256(extkey)[:4] xpub = base58.encode(extkey + checksum) result = {"xpub": xpub} if self.expert: xpub_obj = ExtendedKey() xpub_obj.deserialize(xpub) result.update(xpub_obj.get_printable_dict()) return result
def xpub_test_2_main(xpub: str) -> str: data = base58.decode(xpub) main_data = b"\x04\x88\xb2\x1e" + data[4:-4] checksum = base58.hash256(main_data)[0:4] return base58.encode(main_data + checksum)
def HDWQryXpub(conn, path, hstCred): # IN path like : [2147483692, 2147483648, 2147483648] Client_log.info('[HDWQryXpub]') Client_log.debug('[Path]: %s', path) Client_log.info('[1] parser path') #------------------------ parser path ------------------------ # m / purpose' / coin_type' / account' / change / address_index purpose = '2c000080' # purpose' set to 44 following the BIP43 cointype = '' account = '' change = '' address_i = '' if len(path) == 1: purpose = path[0].to_bytes(4, 'little').hex() childnumber = path[0].to_bytes(4, 'big').hex() elif len(path) == 2: purpose = path[0].to_bytes(4, 'little').hex() cointype = path[1].to_bytes(4, 'little').hex() childnumber = path[1].to_bytes(4, 'big').hex() elif len(path) == 3: purpose = path[0].to_bytes(4, 'little').hex() cointype = path[1].to_bytes(4, 'little').hex() account = path[2].to_bytes(4, 'little').hex() childnumber = path[2].to_bytes(4, 'big').hex() elif len(path) == 4: purpose = path[0].to_bytes(4, 'little').hex() cointype = path[1].to_bytes(4, 'little').hex() account = path[2].to_bytes(4, 'little').hex() change = path[3].to_bytes(4, 'little').hex() childnumber = path[3].to_bytes(4, 'big').hex() elif len(path) == 5: purpose = path[0].to_bytes(4, 'little').hex() cointype = path[1].to_bytes(4, 'little').hex() account = path[2].to_bytes(4, 'little').hex() change = path[3].to_bytes(4, 'little').hex() address_i = path[4].to_bytes(4, 'little').hex() childnumber = path[4].to_bytes(4, 'big').hex() else: raise ValueError('[HDWQryXpub]: error at path') Client_log.debug( '[Parser Path](m/purpose/coin_type/account/change/address): m/%s/%s/%s/%s/%s', purpose, cointype, account, change, address_i) Client_log.info('[2] get pubkey') #------------------------ get pubkey ------------------------ ret = conn.se_hdw_qry_xpub(purpose, cointype, account, change, address_i) rdata = bytes.fromhex(analysisReData(ret)) pubk = rdata[:64] # 64 bytes: public key chacode = rdata[64:64 + 32] # 32 bytes: chain code fingerprint = rdata[64 + 32:64 + 32 + 4] # 4 bytes: the fingerprint of the parent's key rmac = rdata[64 + 32 + 4:64 + 32 + 4 + 32] # 32 bytes: retuen MAC # get login info data = Readkey() Regotp = data[1:1 + 6] loginChlng = data[1 + 6:1 + 6 + 32] Client_log.info('[3] check mac') #------------------------ check mac ------------------------ mac = bind_session_mac(rdata[:64 + 32 + 4], hstCred, Regotp, loginChlng) if rmac != mac: raise ValueError('[HDWQryXpub]: MAC failed') Client_log.info('[4] make ex_pubkey') #------------------------ make ex_pubkey ------------------------ version = '0488B21E' # 4 bytes: version bytes (mainnet public) # CW not support testnet version ''' if testnet: version = '043587CF' # 4 bytes: version bytes (testnet public) ''' depth = "{:0>2d}".format(len(path)) # 1 byte: depth #childnumber = '80000000' # 4 bytes: child number (hardened addresses) pubkey_x = pubk[:32] # 32 bytes: public key x coordinate if int(pubk[32:].hex(), 16) % 2 == 0: prefix = '02' # 1 byte: public key y coordinate is even else: prefix = '03' # 1 byte: public key y coordinate is odd tmp = version \ + depth \ + fingerprint.hex() \ + childnumber \ + chacode.hex() \ + prefix \ + pubkey_x.hex() # double sha256 sha256 = hashlib.sha256() sha256.update(bytes.fromhex(tmp)) checksum_tmp = sha256.digest() sha256 = hashlib.sha256() sha256.update(checksum_tmp) checksum = sha256.digest() ex_pubkey = version \ + depth \ + fingerprint.hex() \ + childnumber \ + chacode.hex() \ + prefix \ + pubkey_x.hex() \ + checksum[:4].hex() return encode(bytes.fromhex(ex_pubkey))
def test_encoding(self): """Test base58 encoding""" for pair in TEST_VECTORS: encoded: str = base58.encode(unhexlify(pair[0])) self.assertEqual(encoded, pair[1])