def public_key_to_address(pubkey, testnet=False, p2sh_p2wpkh=False, witness_version=0): """ Get address from public key/script hash. In case PUBKEY, P2PKH, P2PKH public key/script hash is SHA256+RIPEMD160, P2WSH script hash is SHA256. :param pubkey: public key HEX or bytes string format. :param testnet: (optional) flag for testnet network, by default is False. :param p2sh_p2wpkh: (optional) flag for P2WPKH inside P2SH address, by default is False. :param witness_version: (optional) witness program version, by default is 0, for legacy address format use None. :return: address in base58 or bech32 format. """ if isinstance(pubkey, str): pubkey = bytes.fromhex(pubkey) if not isinstance(pubkey, bytes): raise TypeError("public key invalid, expected bytes or str") if p2sh_p2wpkh: if len(pubkey) != 33: raise ValueError("public key invalid") h = hash160(b'\x00\x14%s' % hash160(pubkey)) witness_version = None else: if witness_version is not None: if len(pubkey) != 33: raise ValueError("public key invalid") h = hash160(pubkey) return hash_to_address(h, testnet=testnet, script_hash=p2sh_p2wpkh, witness_version=witness_version)
def __init__(self, key=None, address_type="P2WPKH", testnet=False, compressed=True): if key is None: #: instance of ``PrivateKey`` class self.private_key = PrivateKey(testnet=testnet, compressed=compressed) #: instance of ``PublicKey`` class self.public_key = PublicKey(self.private_key) #: flag for testnet network address (boolean) self.testnet = testnet if isinstance(key, str) or isinstance(key, bytes): key = PrivateKey(key, testnet=testnet, compressed=compressed) if isinstance(key, PrivateKey): self.private_key = key self.testnet = key.testnet compressed = key.compressed self.public_key = PublicKey(self.private_key) elif isinstance(key, PublicKey): self.public_key = key self.testnet = testnet compressed = key.compressed if address_type not in ("P2PKH", "PUBKEY", "P2WPKH", "P2SH_P2WPKH"): raise TypeError("address type invalid") if not compressed: if address_type not in ("P2PKH", "PUBKEY", "P2SH"): raise TypeError("compressed public key invalid") #: flag for testnet network address (boolean) self.type = address_type if address_type == "PUBKEY": self.pubkey_script = b"%s%s" % (op_push_data(self.public_key.key), OP_CHECKSIG) self.pubkey_script_hex = self.pubkey_script.hex() #: version of witness program for SEGWIT address (string) self.witness_version = 0 if address_type == "P2WPKH" else None self.compressed = compressed if address_type == "P2SH_P2WPKH": #: flag for script hash address (boolean) self.script_hash = True #: redeeem script, only for P2SH_P2WPKH (bytes) self.redeem_script = public_key_to_p2sh_p2wpkh_script(self.public_key.key) #: redeeem script HEX, only for P2SH_P2WPKH (string) self.redeem_script_hex = self.redeem_script.hex() #: address hash self.hash = hash160(self.redeem_script) self.witness_version = None else: self.script_hash = False self.hash = hash160(self.public_key.key) #: address hash HEX (string) self.hash_hex = self.hash.hex() #: address in base58 or bech32 encoding (string) self.address = hash_to_address(self.hash, script_hash=self.script_hash, witness_version=self.witness_version, testnet=self.testnet)
def script_to_hash(script, witness=False, hex=True): """ Encode script to hash HASH160 or SHA256 in dependency of the witness. :param script: script in bytes or HEX encoded string. :param witness: (optional) If set to True return SHA256 hash for P2WSH, by default is False. :param hex: (optional) If set to True return key in HEX format, by default is True. :param sub_script: sub_script which is necessary to remove from target script in bytes or HEX encoded string. :return: script in bytes or HEX encoded string corresponding to the format of target script. """ if isinstance(script, str): s = bytes_from_hex(script) if witness: return sha256(script, hex) else: return hash160(script, hex)
def __init__(self, script, testnet=False, witness_version=0): self.witness_version = witness_version self.testnet = testnet if isinstance(script, str): script = bytes.fromhex(script) self.script = script self.script_hex = self.script.hex() if witness_version is None: self.hash = hash160(self.script) else: self.hash = sha256(self.script) self.script_opcodes = decode_script(self.script) self.script_opcodes_asm = decode_script(self.script, 1) self.address = hash_to_address(self.hash, script_hash=True, witness_version=self.witness_version, testnet=self.testnet)
def derive_child_xpublic_key(xpublic_key, i): c = xpublic_key[13:45] k = xpublic_key[45:] fingerprint = hash160(k)[:4] depth = xpublic_key[4] + 1 if depth > 255: raise ValueError("path depth should be <= 255") if i >= HARDENED_KEY: raise ValueError("derivation from extended public key impossible") s = hmac_sha512(c, k + pack(">L", i)) if int.from_bytes(s[:32], byteorder='big') >= ECDSA_SEC256K1_ORDER: return None pk = __secp256k1_ec_pubkey_tweak_add__(k, s[:32]) if isinstance(pk, int): raise RuntimeError("pubkey_tweak_add error %s" % pk) return b"".join([ xpublic_key[:4], bytes([depth]), fingerprint, pack(">L", i), s[32:], pk ])
def derive_child_xprivate_key(xprivate_key, i): c = xprivate_key[13:45] k = xprivate_key[45:] depth = xprivate_key[4] + 1 if depth > 255: raise ValueError("path depth should be <= 255") pub = private_to_public_key(k[1:], hex=False) fingerprint = hash160(pub)[:4] s = hmac_sha512(c, b"%s%s" % (k if i >= HARDENED_KEY else pub, pack(">L", i))) p_int = int.from_bytes(s[:32], byteorder='big') if p_int >= ECDSA_SEC256K1_ORDER: return None k_int = (int.from_bytes(k[1:], byteorder='big') + p_int) % ECDSA_SEC256K1_ORDER if not k_int: return None key = int.to_bytes(k_int, byteorder="big", length=32) return b"".join([ xprivate_key[:4], bytes([depth]), fingerprint, pack(">L", i), s[32:], b'\x00', key ])
def parse_script(script, segwit=True): """ Parse script and return script type, script address and required signatures count. :param script: script in bytes string or HEX encoded string format. :param segwit: (optional) If set to True recognize P2WPKH and P2WSH sripts, by default set to True. :return: dictionary: - nType - numeric script type - type - script type - addressHash - address hash in case address recognized - script - script if no address recognized - reqSigs - required signatures count """ if not script: return {"nType": 7, "type": "NON_STANDARD", "reqSigs": 0, "script": b""} if isinstance(script, str): try: script = bytes_from_hex(script) except: raise ValueError("hex encoded string required") l = len(script) if segwit: if l == 22 and script[0] == 0: return {"nType": 5, "type": "P2WPKH", "reqSigs": 1, "addressHash": script[2:]} if l == 34 and script[0] == 0: return {"nType": 6, "type": "P2WSH", "reqSigs": None, "addressHash": script[2:]} if l == 25 and \ script[:2] == b"\x76\xa9" and \ script[-2:] == b"\x88\xac": return {"nType": 0, "type": "P2PKH", "reqSigs": 1, "addressHash": script[3:-2]} if l == 23 and \ script[0] == 169 and \ script[-1] == 135: return {"nType": 1, "type": "P2SH", "reqSigs": None, "addressHash": script[2:-1]} if l == 67 and script[-1] == 172: return {"nType": 2, "type": "PUBKEY", "reqSigs": 1, "addressHash": hash160(script[1:-1])} if l == 35 and script[-1] == 172: return {"nType": 2, "type": "PUBKEY", "reqSigs": 1, "addressHash": hash160(script[1:-1])} if script[0] == OPCODE["OP_RETURN"]: if l == 1: return {"nType": 3, "type": "NULL_DATA", "reqSigs": 0, "data": b""} elif script[1] < OPCODE["OP_PUSHDATA1"]: if script[1] == l - 2: return {"nType": 3, "type": "NULL_DATA", "reqSigs": 0, "data": script[2:]} elif script[1] == OPCODE["OP_PUSHDATA1"]: if l > 2: if script[2] == l - 3 and script[2] <= 80: return {"nType": 3, "type": "NULL_DATA", "reqSigs": 0, "data": script[3:]} return {"nType": 8, "type": "NULL_DATA_NON_STANDARD", "reqSigs": 0, "script": script} if script[0] >= 81 and script[0] <= 96: if script[-1] == 174: if script[-2] >= 81 and script[-2] <= 96: if script[-2] >= script[0]: c, s = 0, 1 while l - 2 - s > 0: if script[s] < 0x4c: s += script[s] c += 1 else: c = 0 break s += 1 if c == script[-2] - 80: return {"nType": 4, "type": "MULTISIG", "reqSigs": script[0] - 80, "pubKeys": c, "script": script} s, m, n, last, req_sigs = 0, 0, 0, 0, 0 while l - s > 0: if script[s] >= 81 and script[s] <= 96: if not n: n = script[s] - 80 else: if m == 0: n, m = script[s] - 80, 0 elif n > m: n, m = script[s] - 80, 0 elif m == script[s] - 80: last = 0 if last else 2 elif script[s] < 0x4c: s += script[s] m += 1 if m > 16: n, m = 0, 0 elif script[s] == OPCODE["OP_PUSHDATA1"]: try: s += 1 + script[s + 1] except: break elif script[s] == OPCODE["OP_PUSHDATA2"]: try: s += 2 + unpack('<H', script[s: s + 2])[0] except: break elif script[s] == OPCODE["OP_PUSHDATA4"]: try: s += 4 + unpack('<L', script[s: s + 4])[0] except: break else: if script[s] == OPCODE["OP_CHECKSIG"]: req_sigs += 1 elif script[s] == OPCODE["OP_CHECKSIGVERIFY"]: req_sigs += 1 elif script[s] in (OPCODE["OP_CHECKMULTISIG"], OPCODE["OP_CHECKMULTISIGVERIFY"]): if last: req_sigs += n else: req_sigs += 20 n, m = 0, 0 if last: last -= 1 s += 1 return {"nType": 7, "type": "NON_STANDARD", "reqSigs": req_sigs, "script": script}
def public_key_to_p2sh_p2wpkh_script(pubkey): if len(pubkey) != 33: raise ValueError("public key len invalid") return b'\x00\x14%s' % hash160(pubkey)