def test_double_sha256(self): print("Double SHA256") self.assertEqual(tools.double_sha256(b"test double sha256"), unhexlify("1ab3067efb509c48bda198f48c473f034202537c28b7b4c3b2ab2c4bf4a95c8d")) self.assertEqual(tools.double_sha256(hexlify(b"test double sha256").decode()), unhexlify("1ab3067efb509c48bda198f48c473f034202537c28b7b4c3b2ab2c4bf4a95c8d")) self.assertEqual(tools.double_sha256(hexlify(b"test double sha256").decode(), 1), "1ab3067efb509c48bda198f48c473f034202537c28b7b4c3b2ab2c4bf4a95c8d")
def hash_to_address(address_hash, testnet=False, script_hash=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 address_hash: public key hash or script hash in HEX or bytes string format. :param testnet: (optional) flag for testnet network, by default is False. :param script_hash: (optional) flag for script hash (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(address_hash, str): address_hash = bytes_from_hex(address_hash) if not isinstance(address_hash, bytes): raise TypeError("address hash must be HEX encoded string or bytes") if not script_hash: if witness_version is None: if len(address_hash) != 20: raise ValueError("address hash length incorrect") if testnet: prefix = TESTNET_ADDRESS_BYTE_PREFIX else: prefix = MAINNET_ADDRESS_BYTE_PREFIX address_hash = b"%s%s" % (prefix, address_hash) address_hash += double_sha256(address_hash)[:4] return encode_base58(address_hash) else: if len(address_hash) not in (20, 32): raise ValueError("address hash length incorrect") if witness_version is None: if testnet: prefix = TESTNET_SCRIPT_ADDRESS_BYTE_PREFIX else: prefix = MAINNET_SCRIPT_ADDRESS_BYTE_PREFIX address_hash = b"%s%s" % (prefix, address_hash) address_hash += double_sha256(address_hash)[:4] return encode_base58(address_hash) if testnet: prefix = TESTNET_SEGWIT_ADDRESS_BYTE_PREFIX hrp = TESTNET_SEGWIT_ADDRESS_PREFIX else: prefix = MAINNET_SEGWIT_ADDRESS_BYTE_PREFIX hrp = MAINNET_SEGWIT_ADDRESS_PREFIX address_hash = b"%s%s" % (witness_version.to_bytes( 1, "big"), rebase_8_to_5(address_hash)) checksum = bech32_polymod(b"%s%s%s" % (prefix, address_hash, b"\x00" * 6)) checksum = rebase_8_to_5(checksum.to_bytes(5, "big"))[2:] return "%s1%s" % (hrp, rebase_5_to_32(address_hash + checksum).decode())
def merkle_root(tx_hash_list, hex=True): """ Calculate merkle root from transaction hash list :param tx_hash_list: list of transaction hashes in bytes or HEX encoded string. :param hex: (optional) If set to True return result in HEX format, by default is True. :return: merkle root in bytes or HEX encoded string corresponding hex flag. """ tx_hash_list = [h if isinstance(h, bytes) else s2rh(h) for h in tx_hash_list] if len(tx_hash_list) == 1: return tx_hash_list[0] while True: new_hash_list = list() append = new_hash_list.append while tx_hash_list: h1 = tx_hash_list.pop(0) try: h2 = tx_hash_list.pop(0) except: h2 = h1 append(double_sha256(h1 + h2)) if len(new_hash_list) > 1: tx_hash_list = new_hash_list else: return new_hash_list[0] if not hex else new_hash_list[0].hex()
def private_to_public_key(private_key, compressed=True, hex=True): """ Get public key from private key using ECDSA secp256k1 :param private_key: private key in WIF, HEX or bytes. :param compressed: (optional) flag of public key compressed format, by default set to True. In case private_key in WIF format, this flag is set in accordance with the key format specified in WIF string. :param hex: (optional) if set to True return key in HEX format, by default is True. :return: 33/65 bytes public key in HEX or bytes string. """ if not isinstance(private_key, bytes): if isinstance(private_key, bytearray): private_key = bytes(private_key) elif isinstance(private_key, str): try: if private_key[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX, TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX): compressed = False h = decode_base58(private_key) if double_sha256(h[:-4])[:4] != h[-4:]: raise Exception() private_key = h[1:33] except: try: private_key = bytes_from_hex(private_key) except: raise ValueError("private key HEX or WIF invalid") else: raise ValueError("private key must be a bytes or WIF or hex encoded string") if len(private_key) != 32: raise ValueError("private key length invalid") pub = __secp256k1_ec_pubkey_create__(private_key, bool(compressed)) return pub.hex() if hex else pub
def merkle_branches(tx_hash_list, hex=True): """ Calculate merkle branches for coinbase transacton :param tx_hash_list: list of transaction hashes in bytes or HEX encoded string. :param hex: (optional) If set to True return result in HEX format, by default is True. :return: list of merkle branches in bytes or HEX encoded string corresponding hex flag. """ tx_hash_list = [h if isinstance(h, bytes) else s2rh(h) for h in tx_hash_list] branches = [] if len(tx_hash_list) == 1: return [] tx_hash_list.pop(0) branches_append = branches.append while True: branches_append(tx_hash_list.pop(0)) new_hash_list = list() new_hash_list_append = new_hash_list.append while tx_hash_list: h1 = tx_hash_list.pop(0) try: h2 = tx_hash_list.pop(0) except: h2 = h1 new_hash_list_append(double_sha256(h1 + h2)) if len(new_hash_list) > 1: tx_hash_list = new_hash_list else: if new_hash_list: branches_append(new_hash_list.pop(0)) return branches if not hex else [h.hex() for h in branches]
def decode_block_tx(block): s = get_stream(block) b = dict() b["amount"] = 0 b["size"] = int(len(block) / 2) b["strippedSize"] = 80 b["version"] = unpack("<L", s.read(4))[0] b["versionHex"] = pack(">L", b["version"]).hex() b["previousBlockHash"] = rh2s(s.read(32)) b["merkleRoot"] = rh2s(s.read(32)) b["time"] = unpack("<L", s.read(4))[0] b["bits"] = s.read(4) b["target"] = bits_to_target(unpack("<L", b["bits"])[0]) b["targetDifficulty"] = target_to_difficulty(b["target"]) b["target"] = b["target"].to_bytes(32, byteorder="little") b["nonce"] = unpack("<L", s.read(4))[0] s.seek(-80, 1) b["header"] = s.read(80) b["bits"] = rh2s(b["bits"]) b["target"] = rh2s(b["target"]) b["hash"] = double_sha256(b["header"], hex=0) b["hash"] = rh2s(b["hash"]) b["rawTx"] = dict() b["tx"] = list() for i in range(var_int_to_int(read_var_int(s))): b["rawTx"][i] = Transaction(s, format="raw", keep_raw_tx=True) b["tx"].append(rh2s(b["rawTx"][i]["txId"])) b["amount"] += b["rawTx"][i]["amount"] b["strippedSize"] += b["rawTx"][i]["bSize"] b["strippedSize"] += var_int_len(len(b["tx"])) b["weight"] = b["strippedSize"] * 3 + b["size"] return b
def create_master_xprivate_key(seed, testnet=False, base58=None, hex=None): """ Create extended private key from seed :param str,bytes key: seed HEX or bytes string. :param boolean base58: (optional) return result as base58 encoded string, by default True. :param boolean hex: (optional) return result as HEX encoded string, by default False. In case True base58 flag value will be ignored. :return: extended private key in base58, HEX or bytes string format. """ seed = get_bytes(seed) i = hmac_sha512(b"Bitcoin seed", seed) m, c = i[:32], i[32:] m_int = int.from_bytes(m, byteorder="big") if m_int <= 0 or m_int > ECDSA_SEC256K1_ORDER: # pragma: no cover return None prefix = TESTNET_XPRIVATE_KEY_PREFIX if testnet else MAINNET_XPRIVATE_KEY_PREFIX key = b''.join( [prefix, b'\x00\x00\x00\x00\x00\x00\x00\x00\x00', c, b'\x00', m]) if base58 is None and hex is None: base58 = True if base58: key = b"".join([key, double_sha256(key)[:4]]) return encode_base58(key) else: if hex is None: hex = False return key if not hex else key.hex()
def create_master_xprivate_key(seed, testnet=False, base58=True, hex=False): """ Create extended private key from seed :param str,bytes key: seed HEX or bytes string. :param boolean base58: (optional) return result as base58 encoded string, by default True. :param boolean hex: (optional) return result as HEX encoded string, by default False. In case True base58 flag value will be ignored. :return: extended private key in base58, HEX or bytes string format. """ if isinstance(seed, str): seed = bytes.fromhex(seed) if not isinstance(seed, bytes): raise TypeError("seed should be bytes or hex encoded string") i = hmac_sha512(b"Bitcoin seed", seed) m, c = i[:32], i[32:] m_int = int.from_bytes(m, byteorder="big") if m_int <= 0 or m_int > ECDSA_SEC256K1_ORDER: return None prefix = TESTNET_XPRIVATE_KEY_PREFIX if testnet else MAINNET_XPRIVATE_KEY_PREFIX key = b''.join( [prefix, b'\x00\x00\x00\x00\x00\x00\x00\x00\x00', c, b'\x00', m]) if base58: key = b"".join([key, double_sha256(key)[:4]]) return encode_base58(key) else: return key
def merkle_root(tx_hash_list, return_hex=True, receive_hex=True): """ Calculate merkle root from transaction hash list :param tx_hash_list: list of transaction hashes in bytes or HEX encoded string. :param return_hex: (optional) If set to True return result in HEX format, by default is True. :param receive_hex: (optional) If set to False no internal check or decode from hex to bytes, by default is True. :return: merkle root in bytes or HEX encoded string corresponding hex flag. """ if receive_hex: tx_hash_list = deque([h if isinstance(h, bytes) else s2rh(h) for h in tx_hash_list]) else: tx_hash_list = deque(tx_hash_list) if len(tx_hash_list) == 1: return rh2s(tx_hash_list[0]) if return_hex else tx_hash_list[0] while True: new_hash_list = deque() append = new_hash_list.append while tx_hash_list: h1 = tx_hash_list.popleft() try: h2 = tx_hash_list.popleft() except: h2 = h1 append(double_sha256(b"".join((h1, h2)))) if len(new_hash_list) > 1: tx_hash_list = new_hash_list else: return new_hash_list[0] if not return_hex else rh2s(new_hash_list[0])
def merkle_tree(tx_hash_list, return_hex=False, receive_hex=False): if receive_hex: tx_hash_deque = deque() tx_hash_deque_append = tx_hash_deque.append for h in tx_hash_list: tx_hash_deque_append(h if isinstance(h, bytes) else s2rh(h)) else: tx_hash_deque = deque(tx_hash_list) c = merkle_tree_depth(len(tx_hash_deque)) m = {c: deque(tx_hash_deque)} while len(tx_hash_deque) > 1: new_deque = deque() new_deque_append = new_deque.append while tx_hash_deque: h1 = tx_hash_deque.popleft() try: h2 = tx_hash_deque.popleft() except: h2 = h1 hs = double_sha256(b"".join((h1, h2))) new_deque_append(hs) tx_hash_deque = new_deque c -= 1 m[c] = deque(tx_hash_deque) if return_hex: for i in m: for k in range(len(m[i])): m[i][k] = rh2s(m[i][k]) return m
def is_wif_valid(wif): """ Check is private key in WIF format string is valid. :param wif: private key in WIF format string. :return: boolean. """ if not isinstance(wif, str): raise TypeError("invalid wif key") if wif[0] not in PRIVATE_KEY_PREFIX_LIST: return False try: h = decode_base58(wif) except: return False checksum = h[-4:] if wif[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX, TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX): if len(h) != 37: return False elif len(h) != 38: return False if double_sha256(h[:-4])[:4] != checksum: return False return True
def __init__(self, raw_block=None, format="decoded", version=536870912, testnet=False): if format not in ("decoded", "raw"): raise ValueError("tx_format error, raw or decoded allowed") self["format"] = format self["testnet"] = testnet self["header"] = None self["hash"] = None self["version"] = version self["versionHex"] = pack(">L", version).hex() self["previousBlockHash"] = None self["merkleRoot"] = None self["tx"] = dict() self["time"] = None self["bits"] = None self["nonce"] = None self["weight"] = 0 self["size"] = 80 self["strippedSize"] = 80 self["amount"] = 0 self["height"] = None self["difficulty"] = None self["targetDifficulty"] = None self["target"] = None if raw_block is None: return self["size"] = len(raw_block) if isinstance(raw_block, bytes) else int( len(raw_block) / 2) s = self.get_stream(raw_block) self["format"] = "raw" self["version"] = unpack("<L", s.read(4))[0] self["versionHex"] = pack(">L", self["version"]).hex() self["previousBlockHash"] = s.read(32) self["merkleRoot"] = s.read(32) self["time"] = unpack("<L", s.read(4))[0] self["bits"] = s.read(4) self["target"] = bits_to_target(unpack("<L", self["bits"])[0]) self["targetDifficulty"] = target_to_difficulty(self["target"]) self["target"] = self["target"].to_bytes(32, byteorder="little") self["nonce"] = unpack("<L", s.read(4))[0] s.seek(-80, 1) self["header"] = s.read(80) self["hash"] = double_sha256(self["header"]) block_target = int.from_bytes(self["hash"], byteorder="little") self["difficulty"] = target_to_difficulty(block_target) tx_count = var_int_to_int(read_var_int(s)) self["tx"] = {i: Transaction(s, format="raw") for i in range(tx_count)} for t in self["tx"].values(): self["amount"] += t["amount"] self["strippedSize"] += t["bSize"] self["strippedSize"] += var_int_len(tx_count) self["weight"] = self["strippedSize"] * 3 + self["size"] if format == "decoded": self.decode(testnet=testnet)
def commit(self): if not self["vOut"] or not self["vIn"]: return if self["segwit"]: for i in self["vIn"]: if "txInWitness" not in self["vIn"][i]: if self["format"] == "raw": self["vIn"][i]["txInWitness"] = [] else: self["vIn"][i]["txInWitness"] = [] no_segwit_view = self.serialize(segwit=False, hex=False) self["txId"] = double_sha256(no_segwit_view) self["rawTx"] = self.serialize(segwit=True, hex=False) self["hash"] = double_sha256(self["rawTx"]) self["size"] = len(self["rawTx"]) self["bSize"] = len(no_segwit_view) self["weight"] = self["bSize"] * 3 + self["size"] self["vSize"] = ceil(self["weight"] / 4) if self["format"] != "raw": self["txId"] = rh2s(self["txId"]) self["hash"] = rh2s(self["hash"]) self["rawTx"] = self["rawTx"].hex() input_sum = 0 for i in self["vIn"]: if "value" in self["vIn"][i]: input_sum += self["vIn"][i]["value"] else: input_sum = None break output_sum = 0 for i in self["vOut"]: if "value" in self["vOut"][i]: output_sum += self["vOut"][i]["value"] else: output_sum = None break self["amount"] = output_sum if output_sum and input_sum: self["fee"] = input_sum - output_sum else: self["fee"] = None
def encode_base58(b, checksum=False): """Encode bytes to a base58-encoded string""" # Convert big-endian bytes to integer if not b: return '' b = get_bytes(b) if checksum: return __encode_base58__(b"%s%s" % (b, double_sha256(b)[:4])) return __encode_base58__(b)
def wif_to_private_key(h, hex=True): """ Decode WIF private key to bytes string or HEX encoded string :param hex: (optional) if set to True return key in HEX format, by default is True. :return: Private key HEX encoded string or raw bytes string. """ h = decode_base58(h) if double_sha256(h[:-4])[:4] != h[-4:]: raise TypeError("invalid wif key") return h[1:33].hex() if hex else h[1:33]
def merkleroot_from_branches(merkle_branches, coinbase_hash, hex=True): """ Calculate merkle root from merkle branches and coinbase transacton hash :param merkle_branches: list merkle branches in bytes or HEX encoded string. :param coinbase_hash: list coinbase transaction hash in bytes or HEX encoded string. :param hex: (optional) If set to True return result in HEX format, by default is True. :return: merkle root in bytes or HEX encoded string corresponding hex flag. """ merkle_root = coinbase_hash if not isinstance(coinbase_hash, str) else bytes_from_hex(coinbase_hash) for h in merkle_branches: if type(h) == str: h = bytes_from_hex(h) merkle_root = double_sha256(merkle_root + h) return merkle_root if not hex else merkle_root.hex()
def decode_base58(s, hex=False, checksum=False, verify_checksum=False): """Decode a base58-encoding string, returning bytes""" if verify_checksum: checksum = True if not s: return b'' if not isinstance(s, str): raise ValueError("base58 string required") b = __decode_base58__(s) if checksum: if verify_checksum: if double_sha256(b[:-4])[:4] != b[-4:]: raise Exception("invalid checksum") return b[:-4].hex() if hex else b[:-4] return b.hex() if hex else b
def xprivate_to_xpublic_key(xprivate_key, base58=True, hex=False): """ Get extended public key from extended private key using ECDSA secp256k1 :param str,bytes key: extended private key in base58, HEX or bytes string. :param boolean base58: (optional) return result as base58 encoded string, by default True. :param boolean hex: (optional) return result as HEX encoded string, by default False. In case True base58 flag value will be ignored. :return: extended public key in base58, HEX or bytes string format. """ if isinstance(xprivate_key, str): try: if len(xprivate_key) == 156: xprivate_key = bytes.fromhex(xprivate_key) else: xprivate_key = decode_base58(xprivate_key, checksum=True) except: raise ValueError("invalid extended private key") if not isinstance(xprivate_key, bytes): raise TypeError( "extended private key should be base58 string or bytes") if xprivate_key[:4] == TESTNET_XPRIVATE_KEY_PREFIX: prefix = TESTNET_XPUBLIC_KEY_PREFIX elif xprivate_key[:4] == MAINNET_XPRIVATE_KEY_PREFIX: prefix = MAINNET_XPUBLIC_KEY_PREFIX elif xprivate_key[:4] == MAINNET_M49_XPRIVATE_KEY_PREFIX: prefix = MAINNET_M49_XPUBLIC_KEY_PREFIX elif xprivate_key[:4] == TESTNET_M49_XPRIVATE_KEY_PREFIX: prefix = TESTNET_M49_XPUBLIC_KEY_PREFIX elif xprivate_key[:4] == MAINNET_M84_XPRIVATE_KEY_PREFIX: prefix = MAINNET_M84_XPUBLIC_KEY_PREFIX elif xprivate_key[:4] == TESTNET_M84_XPRIVATE_KEY_PREFIX: prefix = TESTNET_M84_XPUBLIC_KEY_PREFIX else: raise ValueError("invalid extended private key") key = b"".join([ prefix, xprivate_key[4:45], private_to_public_key(xprivate_key[46:], hex=False) ]) if hex: return key.hex() elif base58: key = b"".join([key, double_sha256(key)[:4]]) return encode_base58(key) else: return key
def merkle_root_from_proof(merkle_proof, tx_id, index, return_hex=True, receive_hex=True): if receive_hex: _merkle_proof = deque() _merkle_proof_append = _merkle_proof.append for h in merkle_proof: _merkle_proof_append(s2rh(h) if isinstance(h, str) else h) merkle_proof = _merkle_proof tx_id = bytes_from_hex(tx_id) if isinstance(tx_id, str) else tx_id root = tx_id for h in merkle_proof: root = double_sha256(b"".join((h, root) if index % 2 else (root, h))) index = index // 2 if return_hex: return rh2s(root) return root
def private_key_to_wif(h, compressed=True, testnet=False): """ Encode private key in HEX or RAW bytes format to WIF format. :param h: private key 32 byte string or HEX encoded string. :param compressed: (optional) flag of public key compressed format, by default set to True. :param testnet: (optional) flag for testnet network, by default is False. :return: Private key in WIF format. """ # uncompressed: 0x80 + [32-byte secret] + [4 bytes of Hash() of previous 33 bytes], base58 encoded. # compressed: 0x80 + [32-byte secret] + 0x01 + [4 bytes of Hash() previous 34 bytes], base58 encoded. if isinstance(h, str): h = bytes_from_hex(h) if len(h) != 32 and isinstance(h, bytes): raise TypeError("private key must be a 32 bytes or hex encoded string") if testnet: h = TESTNET_PRIVATE_KEY_BYTE_PREFIX + h else: h = MAINNET_PRIVATE_KEY_BYTE_PREFIX + h if compressed: h += b'\x01' h += double_sha256(h)[:4] return encode_base58(h)
def is_address_valid(address, testnet=False): """ Check is address valid. :param address: address in base58 or bech32 format. :param testnet: (optional) flag for testnet network, by default is False. :return: boolean. """ if not address or type(address) != str: return False if address[0] in (MAINNET_ADDRESS_PREFIX, MAINNET_SCRIPT_ADDRESS_PREFIX, TESTNET_ADDRESS_PREFIX, TESTNET_ADDRESS_PREFIX_2, TESTNET_SCRIPT_ADDRESS_PREFIX): if testnet: if address[0] not in (TESTNET_ADDRESS_PREFIX, TESTNET_ADDRESS_PREFIX_2, TESTNET_SCRIPT_ADDRESS_PREFIX): return False else: if address[0] not in (MAINNET_ADDRESS_PREFIX, MAINNET_SCRIPT_ADDRESS_PREFIX): return False h = decode_base58(address) if len(h) != 25: return False checksum = h[-4:] if double_sha256(h[:-4])[:4] != checksum: return False return True elif address[:2].lower() in (TESTNET_SEGWIT_ADDRESS_PREFIX, MAINNET_SEGWIT_ADDRESS_PREFIX): if len(address) not in (42, 62): return False try: prefix, payload = address.split('1') except: return False upp = True if prefix[0].isupper() else False for i in payload[1:]: if upp: if not i.isupper() or i not in base32charset_upcase: return False else: if i.isupper() or i not in base32charset: return False payload = payload.lower() prefix = prefix.lower() if testnet: if prefix != TESTNET_SEGWIT_ADDRESS_PREFIX: return False stripped_prefix = TESTNET_SEGWIT_ADDRESS_BYTE_PREFIX else: if prefix != MAINNET_SEGWIT_ADDRESS_PREFIX: return False stripped_prefix = MAINNET_SEGWIT_ADDRESS_BYTE_PREFIX d = rebase_32_to_5(payload) address_hash = d[:-6] checksum = d[-6:] checksum2 = bech32_polymod( b"%s%s%s" % (stripped_prefix, address_hash, b"\x00" * 6)) checksum2 = rebase_8_to_5(checksum2.to_bytes(5, "big"))[2:] if checksum != checksum2: return False return True
def encode_base58_with_checksum(b): return encode_base58(b"%s%s" % (b, double_sha256(b)[:4]))
def decode_base58_with_checksum(s): b = decode_base58(s) if double_sha256(b[:-4])[:4] != b[-4:]: raise Exception("invalid checksum") return b[:-4]
def bitcoin_message(msg): if isinstance(msg, str): msg = msg.encode() print(b"\x18Bitcoin Signed Message:\n" + int_to_var_int(len(msg)) + msg) return double_sha256(b"\x18Bitcoin Signed Message:\n" + int_to_var_int(len(msg)) + msg)
def sig_hash_segwit(self, n, amount, script_pub_key=None, sighash_type=SIGHASH_ALL, preimage=False): try: self["vIn"][n] except: raise Exception("sig_hash error, input not exist") # check script_pub_key for input if script_pub_key is not None: script_code = script_pub_key else: if "scriptPubKey" not in self["vIn"][n]: raise Exception("sig_hash error, scriptPubKey required") script_code = self["vIn"][n]["scriptPubKey"] if isinstance(script_code, str): script_code = bytes.fromhex(script_code) if not isinstance(script_code,bytes): raise Exception("sig_hash error, script_code type error") # remove opcode separators pm = bytearray() # 1. nVersion of the transaction (4-byte little endian) pm += pack('<L', self["version"]) # 2. hashPrevouts (32-byte hash) # 3. hashSequence (32-byte hash) # 4. outpoint (32-byte hash + 4-byte little endian) # 5. scriptCode of the input (serialized as scripts inside CTxOuts) # 6. value of the output spent by this input (8-byte little endian) # 7. nSequence of the input (4-byte little endian) hp = bytearray() # hash of out points hs = bytearray() # hash of sequences for i in self["vIn"]: tx_id = self["vIn"][i]["txId"] if type(tx_id) == str: tx_id = s2rh(tx_id) if not (sighash_type & SIGHASH_ANYONECANPAY): hp += b"%s%s" % (tx_id, pack('<L', self["vIn"][i]["vOut"])) if (sighash_type & 31) != SIGHASH_SINGLE and (sighash_type & 31) != SIGHASH_NONE: hs += pack('<L', self["vIn"][i]["sequence"]) if i == n: outpoint = b"%s%s" % (tx_id, pack('<L', self["vIn"][i]["vOut"])) n_sequence = pack('<L', self["vIn"][i]["sequence"]) hash_prevouts = double_sha256(hp) if hp else b'\x00' * 32 hash_sequence = double_sha256(hs) if hs else b'\x00' * 32 value = amount.to_bytes(8, 'little') # 8. hashOutputs (32-byte hash) ho = bytearray() for o in self["vOut"]: script_pub_key = self["vOut"][o]["scriptPubKey"] if type(self["vOut"][o]["scriptPubKey"]) == str: script_pub_key = bytes_from_hex(script_pub_key) if (sighash_type & 31) != SIGHASH_SINGLE and (sighash_type & 31) != SIGHASH_NONE: ho += b"%s%s%s" % (self["vOut"][o]["value"].to_bytes(8, 'little'), int_to_var_int(len(script_pub_key)), script_pub_key) elif (sighash_type & 31) == SIGHASH_SINGLE and n < len(self["vOut"]): if o == n: ho += b"%s%s%s" % (self["vOut"][o]["value"].to_bytes(8, 'little'), int_to_var_int(len(script_pub_key)), script_pub_key) hash_outputs = double_sha256(ho) if ho else b'\x00' * 32 pm += b"%s%s%s%s%s%s%s%s%s" % (hash_prevouts, hash_sequence, outpoint, script_code, value, n_sequence, hash_outputs, pack('<L', self["lockTime"]), pack('<L', sighash_type)) if not preimage: pm = double_sha256(pm) return pm if self["format"] == "raw" else pm.hex()
def sig_hash(self, n, script_pub_key=None, sighash_type=SIGHASH_ALL, preimage=False): try: self["vIn"][n] except: raise Exception("sig_hash error, input not exist") # check script_pub_key for input if script_pub_key is not None: script_code = script_pub_key else: if "scriptPubKey" not in self["vIn"][n]: raise Exception("sig_hash error, scriptPubKey required") script_code = self["vIn"][n]["scriptPubKey"] if isinstance(script_code, str): script_code = bytes.fromhex(script_code) if not isinstance(script_code,bytes): raise Exception("sig_hash error, script_code type error") # remove opcode separators if ((sighash_type & 31) == SIGHASH_SINGLE) and (n >= (len(self["vOut"]))): if self["format"] == "raw": return b'\x01%s' % (b'\x00' * 31) return rh2s(b'\x01%s' % (b'\x00' * 31)) script_code = delete_from_script(script_code, BYTE_OPCODE["OP_CODESEPARATOR"]) pm = bytearray() pm += b"%s%s" % (pack('<L', self["version"]), b'\x01' if sighash_type & SIGHASH_ANYONECANPAY else int_to_var_int(len(self["vIn"]))) for i in self["vIn"]: # skip all other inputs for SIGHASH_ANYONECANPAY case if (sighash_type & SIGHASH_ANYONECANPAY) and (n != i): continue sequence = self["vIn"][i]["sequence"] if ((sighash_type & 31) == SIGHASH_SINGLE or (sighash_type & 31) == SIGHASH_NONE) and (n != i): sequence = 0 tx_id = self["vIn"][i]["txId"] if isinstance(tx_id, str): tx_id = s2rh(tx_id) if n == i: pm += b"%s%s%s%s%s" % (tx_id, pack('<L', self["vIn"][i]["vOut"]), int_to_var_int(len(script_code)), script_code, pack('<L', sequence)) else: pm += b'%s%s\x00%s' % (tx_id, pack('<L', self["vIn"][i]["vOut"]), pack('<L', sequence)) if (sighash_type & 31) == SIGHASH_NONE: pm += b'\x00' else: if (sighash_type & 31) == SIGHASH_SINGLE: pm += int_to_var_int(n + 1) else: pm += int_to_var_int(len(self["vOut"])) if (sighash_type & 31) != SIGHASH_NONE: for i in self["vOut"]: script_pub_key = self["vOut"][i]["scriptPubKey"] if isinstance(self["vOut"][i]["scriptPubKey"], str): script_pub_key = bytes_from_hex(script_pub_key) if i > n and (sighash_type & 31) == SIGHASH_SINGLE: continue if (sighash_type & 31) == SIGHASH_SINGLE and (n != i): pm += b"%s%s" % (b'\xff' * 8, b'\x00') else: pm += b"%s%s%s" % (self["vOut"][i]["value"].to_bytes(8, 'little'), int_to_var_int(len(script_pub_key)), script_pub_key) pm += b"%s%s" % (self["lockTime"].to_bytes(4, 'little'), pack(b"<i", sighash_type)) if not preimage: pm = double_sha256(pm) return pm if self["format"] == "raw" else rh2s(pm)
def __init__(self, raw_tx=None, format="decoded", version=1, lock_time=0, testnet=False, auto_commit=True): if format not in ("decoded", "raw"): raise ValueError("format error, raw or decoded allowed") self.auto_commit = auto_commit self["format"] = format self["testnet"] = testnet self["segwit"] = False self["txId"] = None self["hash"] = None self["version"] = version self["size"] = 0 self["vSize"] = 0 self["bSize"] = 0 self["lockTime"] = lock_time self["vIn"] = dict() self["vOut"] = dict() self["rawTx"] = None self["blockHash"] = None self["confirmations"] = None self["time"] = None self["blockTime"] = None self["blockIndex"] = None self["coinbase"] = False self["fee"] = None self["data"] = None self["amount"] = None if raw_tx is None: return self["amount"] = 0 sw = sw_len = 0 stream = self.get_stream(raw_tx) start = stream.tell() read = stream.read tell = stream.tell seek = stream.seek # start deserialization self["version"] = unpack('<L', read(4))[0] n = read_var_int(stream) if n == b'\x00': # segwit format sw = 1 self["flag"] = read(1) n = read_var_int(stream) # inputs ic = var_int_to_int(n) for k in range(ic): self["vIn"][k] = dict() self["vIn"][k]["txId"] = read(32) self["vIn"][k]["vOut"] = unpack('<L', read(4))[0] self["vIn"][k]["scriptSig"] = read(var_int_to_int(read_var_int(stream))) self["vIn"][k]["sequence"] = unpack('<L', read(4))[0] # outputs for k in range(var_int_to_int(read_var_int(stream))): self["vOut"][k] = dict() self["vOut"][k]["value"] = unpack('<Q', read(8))[0] self["amount"] += self["vOut"][k]["value"] self["vOut"][k]["scriptPubKey"] = read(var_int_to_int(read_var_int(stream))) s = parse_script(self["vOut"][k]["scriptPubKey"]) self["vOut"][k]["nType"] = s["nType"] self["vOut"][k]["type"] = s["type"] if self["data"] is None: if s["nType"] == 3: self["data"] = s["data"] if s["nType"] not in (3, 4, 7, 8): self["vOut"][k]["addressHash"] = s["addressHash"] self["vOut"][k]["reqSigs"] = s["reqSigs"] # witness if sw: sw = tell() - start for k in range(ic): self["vIn"][k]["txInWitness"] = [read(var_int_to_int(read_var_int(stream))) \ for c in range(var_int_to_int(read_var_int(stream)))] sw_len = (stream.tell() - start) - sw + 2 self["lockTime"] = unpack('<L', read(4))[0] end = tell() seek(start) b = read(end - start) self["rawTx"] = b self["size"] = end - start self["bSize"] = end - start - sw_len self["weight"] = self["bSize"] * 3 + self["size"] self["vSize"] = ceil(self["weight"] / 4) if ic == 1 and \ self["vIn"][0]["txId"] == b'\x00' * 32 and \ self["vIn"][0]["vOut"] == 0xffffffff: self["coinbase"] = True else: self["coinbase"] = False if sw: self["segwit"] = True self["hash"] = double_sha256(b) self["txId"] = double_sha256(b"%s%s%s" % (b[:4], b[6:sw],b[-4:])) else: self["segwit"] = False self["txId"] = double_sha256(b) self["hash"] = self["txId"] if self["format"] == "decoded": self.decode()