def b58decode(v: String, out_size: Optional[int] = None) -> bytes: """Decode a Base58Check encoded bytes-like object or ASCII string. Optionally, it also ensures required output size. """ if isinstance(v, str): # do not trim spaces v = v.encode("ascii") result = _b58decode(v) if len(result) < 4: err_msg = "not enough bytes for checksum, " err_msg += f"invalid base58 decoded size: {len(result)}" raise BTClibValueError(err_msg) result, checksum = result[:-4], result[-4:] h256 = hash256(result) if checksum != h256[:4]: err_msg = f"invalid checksum: 0x{checksum.hex()} instead of 0x{h256[:4].hex()}" raise BTClibValueError(err_msg) if out_size is None or len(result) == out_size: return result err_msg = "valid checksum, invalid decoded size: " err_msg += f"{len(result)} bytes instead of {out_size}" raise BTClibValueError(err_msg)
def legacy(script_: Octets, tx: Tx, vin_i: int, hash_type: int) -> bytes: script_ = bytes_from_octets(script_) new_tx = deepcopy(tx) for txin in new_tx.vin: txin.script_sig = b"" # TODO: delete sig from script_ (even if non standard) new_tx.vin[vin_i].script_sig = script_ if hash_type & 0x1F == NONE: new_tx.vout = [] for i, txin in enumerate(new_tx.vin): if i != vin_i: txin.sequence = 0 if hash_type & 0x1F == SINGLE: # sig_hash single bug if vin_i >= len(new_tx.vout): return (256**31).to_bytes(32, byteorder="big", signed=False) new_tx.vout = new_tx.vout[:vin_i + 1] for txout in new_tx.vout[:-1]: txout.script_pub_key = ScriptPubKey(b"") txout.value = 0xFFFFFFFFFFFFFFFF for i, txin in enumerate(new_tx.vin): if i != vin_i: txin.sequence = 0 if hash_type & 0x80: new_tx.vin = [new_tx.vin[vin_i]] preimage = new_tx.serialize(include_witness=False, check_validity=False) preimage += hash_type.to_bytes(4, byteorder="little", signed=False) return hash256(preimage)
def hash(self) -> bytes: """Return the transaction hash. It differs from tx_id for witness transactions. """ serialized_ = self.serialize(include_witness=True, check_validity=False) hash256_ = hash256(serialized_) return hash256_[::-1]
def segwit_v0(script_: Octets, tx: Tx, vin_i: int, hash_type: int, amount: int) -> bytes: script_ = bytes_from_octets(script_) hash_prev_outs = b"\x00" * 32 if not hash_type & ANYONECANPAY: hash_prev_outs = b"".join([vin.prev_out.serialize() for vin in tx.vin]) hash_prev_outs = hash256(hash_prev_outs) hash_seqs = b"\x00" * 32 if (not (hash_type & ANYONECANPAY) and (hash_type & 0x1F) != SINGLE and (hash_type & 0x1F) != NONE): hash_seqs = b"".join([ vin.sequence.to_bytes(4, byteorder="little", signed=False) for vin in tx.vin ]) hash_seqs = hash256(hash_seqs) hash_outputs = b"\x00" * 32 if hash_type & 0x1F not in (SINGLE, NONE): hash_outputs = b"".join([vout.serialize() for vout in tx.vout]) hash_outputs = hash256(hash_outputs) elif (hash_type & 0x1F) == SINGLE and vin_i < len(tx.vout): hash_outputs = hash256(tx.vout[vin_i].serialize()) preimage = b"".join([ tx.version.to_bytes(4, byteorder="little", signed=False), hash_prev_outs, hash_seqs, tx.vin[vin_i].prev_out.serialize(), var_bytes.serialize(script_), amount.to_bytes(8, byteorder="little", signed=False), # value tx.vin[vin_i].sequence.to_bytes(4, byteorder="little", signed=False), hash_outputs, tx.lock_time.to_bytes(4, byteorder="little", signed=False), hash_type.to_bytes(4, byteorder="little", signed=False), ]) return hash256(preimage)
def _assert_valid_hash256_preimages( hash256_preimages: Mapping[bytes, bytes]) -> None: for h, preimage in hash256_preimages.items(): if hash256(preimage) != h: raise BTClibValueError("Invalid HASH256 preimage")
def b58encode(v: Octets, in_size: Optional[int] = None) -> bytes: """Encode a bytes-like object using Base58Check.""" v = bytes_from_octets(v, in_size) h256 = hash256(v) return _b58encode(v + h256[:4])
def id(self) -> bytes: "Return the transaction id." serialized_ = self.serialize(include_witness=False, check_validity=False) hash256_ = hash256(serialized_) return hash256_[::-1]
def test_hash160_hash256() -> None: test_vectors = (plain_prv_keys + net_unaware_compressed_pub_keys + net_unaware_uncompressed_pub_keys) for hexstring in test_vectors: hash160(hexstring) hash256(hexstring)