def hash_prevouts(self): if self._hash_prevouts is None: all_prevouts = b"" all_sequence = b"" for tx_in in self.tx_ins: all_prevouts += tx_in.prev_tx[::-1] + int_to_little_endian( tx_in.prev_index, 4) all_sequence += tx_in.sequence.serialize() self._hash_prevouts = hash256(all_prevouts) self._hash_sequence = hash256(all_sequence) return self._hash_prevouts
def hash_outputs(self): if self._hash_outputs is None: all_outputs = b"" for tx_out in self.tx_outs: all_outputs += tx_out.serialize() self._hash_outputs = hash256(all_outputs) return self._hash_outputs
def check_pow(self): """Returns whether this block satisfies proof of work""" # get the hash256 of the serialization of this block h256 = hash256(self.serialize()) # interpret this hash as a little-endian number proof = little_endian_to_int(h256) # return whether this integer is less than the target return proof < self.target()
def hash(self): """Returns the hash256 interpreted little endian of the block""" # serialize s = self.serialize() # hash256 h256 = hash256(s) # reverse return h256[::-1]
def sig_hash_bip143( self, input_index, redeem_script=None, witness_script=None, hash_type=SIGHASH_ALL, ): """Returns the integer representation of the hash that needs to get signed for index input_index""" # grab the input being signed by looking up the input_index tx_in = self.tx_ins[input_index] # start with the version in 4 bytes, little endian s = int_to_little_endian(self.version, 4) # add the HashPrevouts and HashSequence if hash_type & SIGHASH_ANYONECANPAY != SIGHASH_ANYONECANPAY: s += self.hash_prevouts() if hash_type & SIGHASH_ANYONECANPAY != SIGHASH_ANYONECANPAY and ( hash_type & 3) not in (SIGHASH_SINGLE, SIGHASH_NONE): s += self.hash_sequence() # add the previous transaction hash in little endian s += tx_in.prev_tx[::-1] # add the previous transaction index in 4 bytes, little endian s += int_to_little_endian(tx_in.prev_index, 4) # for p2wpkh, we need to compute the ScriptCode # Exercise 1: account for p2wsh. Check first for the existence of a WitnessScript if witness_script: # for p2wsh and p2sh-p2wsh the ScriptCode is the WitnessScript script_code = witness_script elif redeem_script: # for p2sh-p2wpkh, get the hash160 which is the 2nd command of the RedeemScript h160 = redeem_script.commands[1] # the ScriptCode is the P2PKHScriptPubKey created using the hash160 script_code = P2PKHScriptPubKey(h160) else: # get the script pubkey associated with the previous output (remember network) script_pubkey = tx_in.script_pubkey(self.network) # next get the hash160 in the script_pubkey. for p2wpkh, it's the second command h160 = script_pubkey.commands[1] # finally the ScriptCode is the P2PKHScriptPubKey created using the hash160 script_code = P2PKHScriptPubKey(h160) # add the serialized ScriptCode s += script_code.serialize() # add the value of the input in 8 bytes, little endian s += int_to_little_endian(tx_in.value(network=self.network), 8) # add the sequence of the input in 4 bytes, little endian s += tx_in.sequence.serialize() # add the HashOutputs if (hash_type & 3) not in (SIGHASH_SINGLE, SIGHASH_NONE): s += self.hash_outputs() elif hash_type & SIGHASH_SINGLE == SIGHASH_SINGLE: s += self.tx_outs[input_index].serialize() # add the locktime in 4 bytes, little endian s += self.locktime.serialize() # add the sighash (SIGHASH_ALL) in 4 bytes, little endian s += int_to_little_endian(hash_type, 4) # hash256 the whole thing, interpret the as a big endian integer using int_to_big_endian return big_endian_to_int(hash256(s))
def verify_message(self, message, sig): """Verify a message in the form of bytes. Assumes that the z is calculated using hash256 interpreted as a big-endian integer""" # calculate the hash256 of the message h256 = hash256(message) # z is the big-endian interpretation. use big_endian_to_int z = big_endian_to_int(h256) # verify the message using the self.verify method return self.verify(z, sig)
def sign_message(self, message): """Sign a message in the form of bytes instead of the z. The z should be assumed to be the hash256 of the message interpreted as a big-endian integer.""" # compute the hash256 of the message h256 = hash256(message) # z is the big-endian interpretation. use big_endian_to_int z = big_endian_to_int(h256) # sign the message using the self.sign method return self.sign(z)
def __init__(self, filter_type, stop_hash, previous_filter_header, filter_hashes): self.filter_type = filter_type self.stop_hash = stop_hash self.previous_filter_header = previous_filter_header self.filter_hashes = filter_hashes current = self.previous_filter_header for filter_hash in self.filter_hashes: current = hash256(filter_hash + current) self.last_header = current
def serialize(self): """Returns the byte serialization of the entire network message""" # add the network magic using self.magic result = self.magic # command 12 bytes, fill leftover with b'\x00' * (12 - len(self.command)) result += self.command + b"\x00" * (12 - len(self.command)) # payload length 4 bytes, little endian result += int_to_little_endian(len(self.payload), 4) # checksum 4 bytes, first four of hash256 of payload result += hash256(self.payload)[:4] # payload result += self.payload return result
def fetch(cls, tx_id, network="mainnet", fresh=False): if fresh or (tx_id not in cls.cache): url = "{}/tx/{}/hex".format(cls.get_url(network), tx_id) req = Request(url, headers={"User-Agent": "Mozilla/5.0"}) response = urlopen(req).read().decode("utf-8").strip() try: raw = bytes.fromhex(response) except ValueError: raise ValueError(f"unexpected response: {response}") tx = Tx.parse(BytesIO(raw), network=network) # make sure the tx we got matches to the hash we requested if tx.segwit: computed = tx.id() else: computed = hash256(raw)[::-1].hex() if computed != tx_id: raise RuntimeError(f"server lied: {computed} vs {tx_id}") cls.cache[tx_id] = tx cls.cache[tx_id].network = network return cls.cache[tx_id]
def parse(cls, s, network="mainnet"): """Takes a stream and creates a NetworkEnvelope""" # check the network magic magic = s.read(4) if magic == b"": raise RuntimeError("Connection reset!") expected_magic = MAGIC[network] if magic != expected_magic: raise RuntimeError("magic is not right {} vs {}".format( magic.hex(), expected_magic.hex())) # command 12 bytes, strip the trailing 0's using .strip(b'\x00') command = s.read(12).strip(b"\x00") # payload length 4 bytes, little endian payload_length = little_endian_to_int(s.read(4)) # checksum 4 bytes, first four of hash256 of payload checksum = s.read(4) # payload is of length payload_length payload = s.read(payload_length) # verify checksum calculated_checksum = hash256(payload)[:4] if calculated_checksum != checksum: raise RuntimeError("checksum does not match") return cls(command, payload, network=network)
def hash(self): return hash256(self.filter_bytes)
def hash(self): return hash256(self.serialize())
def hash(self): """Binary hash of the legacy serialization""" return hash256(self.serialize_legacy())[::-1]
def op_hash256(stack): if len(stack) < 1: return False element = stack.pop() stack.append(hash256(element)) return True
def _calculate_msig_digest(quorum_m, root_xfp_hexes): fingerprints_to_hash = "-".join(sorted(root_xfp_hexes)) return hash256(f"{quorum_m}:{fingerprints_to_hash}".encode()).hex()
def sig_hash_legacy(self, input_index, redeem_script=None, hash_type=SIGHASH_ALL): """Returns the integer representation of the hash that needs to get signed for index input_index""" # consensus bugs related to invalid input indices DEFAULT = 1 << 248 if input_index >= len(self.tx_ins): return DEFAULT elif hash_type & 3 == SIGHASH_SINGLE and input_index >= len( self.tx_outs): return DEFAULT # create the serialization per spec # start with version: int_to_little_endian in 4 bytes s = int_to_little_endian(self.version, 4) # next, how many inputs there are: encode_varint s += encode_varint(len(self.tx_ins)) # loop through each input: for i, tx_in in enumerate(self.tx_ins) for i, tx_in in enumerate(self.tx_ins): sequence = tx_in.sequence # if the input index is the one we're signing if i == input_index: # if the RedeemScript was passed in, that's the ScriptSig if redeem_script: script_sig = redeem_script # otherwise the previous tx's ScriptPubkey is the ScriptSig else: script_sig = tx_in.script_pubkey(self.network) # Otherwise, the ScriptSig is empty else: script_sig = None if hash_type & 3 in (SIGHASH_NONE, SIGHASH_SINGLE): sequence = Sequence(0) # create a TxIn object with the prev_tx, prev_index and sequence # the same as the current tx_in and the script_sig from above new_tx_in = TxIn( prev_tx=tx_in.prev_tx, prev_index=tx_in.prev_index, script_sig=script_sig, sequence=sequence, ) # add the serialization of the TxIn object if hash_type & SIGHASH_ANYONECANPAY: if i == input_index: s += new_tx_in.serialize() else: s += new_tx_in.serialize() # add how many outputs there are using encode_varint s += encode_varint(len(self.tx_outs)) # add the serialization of each output for i, tx_out in enumerate(self.tx_outs): if hash_type & 3 == SIGHASH_NONE: continue elif hash_type & 3 == SIGHASH_SINGLE: if i == input_index: s += tx_out.serialize() break else: s += b"\xff\xff\xff\xff\xff\xff\xff\xff\x00" else: s += tx_out.serialize() # add the locktime using int_to_little_endian in 4 bytes s += self.locktime.serialize() # add SIGHASH_ALL using int_to_little_endian in 4 bytes s += int_to_little_endian(hash_type, 4) # hash256 the serialization h256 = hash256(s) # convert the result to an integer using big_endian_to_int(x) return big_endian_to_int(h256)