def serialize(self): '''Serialize this message to send over the network''' # protocol version is 4 bytes little-endian result = int_to_little_endian(self.version, 4) # number of hashes is a varint result += encode_varint(self.num_hashes) # start block is in little-endian result += self.start_block[::-1] # end block is also in little-endian result += self.end_block[::-1] return result
def serialize(self): '''Returns the byte serialization of the transaction output''' # serialize amount, 8 bytes, little endian result = int_to_little_endian(self.amount, 8) # get the scriptPubkey ready (use self.script_pubkey.serialize()) raw_script_pubkey = self.script_pubkey.serialize() # encode_varint on the length of the scriptPubkey result += encode_varint(len(raw_script_pubkey)) # add the scriptPubKey result += raw_script_pubkey return result
def sig_hash(self, input_index, redeem_script=None): '''Returns the integer representation of the hash that needs to get signed for index input_index''' # start the serialization with version # use int_to_little_endian in 4 bytes s = int_to_little_endian(self.version, 4) # add how many inputs there are using encode_varint s += encode_varint(len(self.tx_ins)) # loop through each input using enumerate, so we have the input index for i, tx_in in enumerate(self.tx_ins): # 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.testnet) # Otherwise, the ScriptSig is empty else: script_sig = None # add the serialization of the input with the ScriptSig we want s += TxIn( prev_tx=tx_in.prev_tx, prev_index=tx_in.prev_index, script_sig=script_sig, sequence=tx_in.sequence, ).serialize() # add how many outputs there are using encode_varint s += encode_varint(len(self.tx_outs)) # add the serialization of each output for tx_out in self.tx_outs: s += tx_out.serialize() # add the locktime using int_to_little_endian in 4 bytes s += int_to_little_endian(self.locktime, 4) # add SIGHASH_ALL using int_to_little_endian in 4 bytes s += int_to_little_endian(SIGHASH_ALL, 4) # hash256 the serialization h256 = hash256(s) # convert the result to an integer using int.from_bytes(x, 'big') return int.from_bytes(h256, 'big')
def sig_hash(self, input_index): s = int_to_little_endian(self.version, 4) s += encode_varint(len(self.tx_ins)) for i, tx_in in enumerate(self.tx_ins): if i == input_index: script_sig = tx_in.script_pubkey(self.testnet) else: script_sig = None s += TxIn( prev_tx=tx_in.prev_tx, prev_index=tx_in.prev_index, script_sig=script_sig, sequence=tx_in.sequence, ).serialize() s += encode_varint(len(self.tx_outs)) for tx_out in self.tx_outs: s += tx_out.serialize() s += int_to_little_endian(self.locktime, 4) s += int_to_little_endian(SIGHASH_ALL, 4) h256 = hash256(s) return int.from_bytes(h256, 'big')
def serialize(self, prev_block=False): '''Returns the byte serialization of the transaction''' # serialize version (4 bytes, little endian) result = int_to_little_endian(self.version, 4) if prev_block: result += self.prev_block_hash[::-1] # encode_varint on the number of inputs result += encode_varint(len(self.tx_ins)) # iterate inputs for tx_in in self.tx_ins: # serialize each input result += tx_in.serialize() # encode_varint on the number of inputs result += encode_varint(len(self.tx_outs)) # iterate outputs for tx_out in self.tx_outs: # serialize each output result += tx_out.serialize() # serialize locktime (4 bytes, little endian) result += int_to_little_endian(self.locktime, 4) return result
def serialize(self): # initialize what we'll send back result = b'' # go through each item for item in self.items: # if the item is an integer, it's an op code if type(item) == int: # turn the item into a single byte integer using int_to_little_endian result += int_to_little_endian(item, 1) else: # otherwise, this is an element # get the length in bytes length = len(item) # turn the length into a single byte integer using int_to_little_endian prefix = int_to_little_endian(length, 1) # append to the result both the length and the item result += prefix + item # get the length of the whole thing total = len(result) # encode_varint the total length of the result and prepend return encode_varint(total) + result
def sig_hash(self, input_index, hash_type): '''Returns the integer representation of the hash that needs to get signed for index input_index''' script_pubkey = self.tx_ins[input_index].script_pubkey() if script_pubkey.type() == 'p2wpkh': return self.sig_hash_w0(input_index, hash_type) # create a new set of tx_ins (alt_tx_ins) alt_tx_ins = [] # iterate over self.tx_ins for tx_in in self.tx_ins: # create a new TxIn that has a blank script_sig (b'') and add to alt_tx_ins alt_tx_ins.append(TxIn( prev_tx=tx_in.prev_tx, prev_index=tx_in.prev_index, script_sig=b'', sequence=tx_in.sequence, )) # grab the input at the input_index signing_input = alt_tx_ins[input_index] # grab the script_pubkey of the input script_pubkey = signing_input.script_pubkey(self.testnet) # Exercise 6.2: get the sig type from script_pubkey.type() sig_type = script_pubkey.type() # Exercise 6.2: the script_sig of the signing_input should be script_pubkey for p2pkh if sig_type == 'p2pkh': # Exercise 6.2: replace the input's scriptSig with the scriptPubKey signing_input.script_sig = script_pubkey # Exercise 6.2: the script_sig of the signing_input should be the redeemScript # of the current input of the real tx_in (self.tx_ins[input_index].redeem_script() elif sig_type == 'p2sh': # Exercise 6.2: replace the input's scriptSig with the RedeemScript current_input = self.tx_ins[input_index] # Exercise 6.2: replace the input's scriptSig with the Script.parse(redeem_script) signing_input.script_sig = Script.parse( current_input.redeem_script()) elif sig_type == 'p2pk': signing_input.script_sig = script_pubkey else: raise RuntimeError('no valid sig_type') # create an alternate transaction with the modified tx_ins alt_tx = self.__class__( version=self.version, tx_ins=alt_tx_ins, tx_outs=self.tx_outs, locktime=self.locktime) # add the hash_type int 4 bytes, little endian result = alt_tx.serialize() + int_to_little_endian(hash_type, 4) # get the double_sha256 of the tx serialization s256 = double_sha256(result) # convert this to a big-endian integer using int.from_bytes(x, 'big') return int.from_bytes(s256, 'big')
def zprv(self): if self.testnet: version = TESTNET_ZPRV else: version = MAINNET_ZPRV depth = int_to_little_endian(self.depth, 1) fingerprint = self.fingerprint child_number = self.child_number.to_bytes(4, 'big') chain_code = self.chain_code prv = b'\x00' + self.private_key.secret.to_bytes(32, 'big') return encode_base58_checksum( version + depth + fingerprint + child_number + chain_code + prv)
def serialize(self): '''Returns the byte serialization of the transaction''' if self.is_segwit(): return self.serialize_segwit() # serialize version (4 bytes, little endian) result = int_to_little_endian(self.version, 4) # encode_varint on the number of inputs result += encode_varint(len(self.tx_ins)) # iterate inputs for tx_in in self.tx_ins: # serialize each input result += tx_in.serialize() # encode_varint on the number of inputs result += encode_varint(len(self.tx_outs)) # iterate outputs for tx_out in self.tx_outs: # serialize each output result += tx_out.serialize() # serialize locktime (4 bytes, little endian) result += int_to_little_endian(self.locktime, 4) return result
def serialize_segwit(self): result = int_to_little_endian(self.version, 4) result += b'\x00\x01' # <2> result += encode_varint(len(self.tx_ins)) for tx_in in self.tx_ins: result += tx_in.serialize() result += encode_varint(len(self.tx_outs)) for tx_out in self.tx_outs: result += tx_out.serialize() for tx_in in self.tx_ins: # <3> if tx_in.witness is None: result += b'\x00' else: result += int_to_little_endian(len(tx_in.witness), 1) for item in tx_in.witness: if type(item) == int: result += int_to_little_endian(item, 1) else: result += encode_varint(len(item)) + item result += int_to_little_endian(self.locktime, 4) return result
def raw_serialize(self): result = b'' for cmd in self.cmds: # if it's an integer, we know it's an opcode because of the parse method. # Elements are pushed onto the stack as bytes. if type(cmd) == int: result += int_to_little_endian(cmd, 1) else: # number of bytes of the command. length = len(cmd) # if length <= 75, we encode the length of the element (cmd) as a single byte if length <= 75: result += int_to_little_endian(length, 1) # for any element with length between 76 and 255, we put a OP_PUSHDATA1 first, # then encode the length as a single byte, followed by the element. elif length > 75 and length < 256: result += int_to_little_endian(76, 1) result += int_to_little_endian(length, 1) # for any element with length between 256 and 520, we put a OP_PUSHDATA2 first, # then encode the length as 2 bytes, followed by the element. elif length >= 256 and length <= 520: result += int_to_little_endian(77, 1) result += int_to_little_endian(length, 2) else: raise ValueError('cmd is too long.') # we encode the cmd result += cmd return result
def raw_serialize(self): result = b'' # cmd should be consist of command (int) and element (byte) for cmd in self.cmds: # op_command if its type is int if type(cmd) == int: result += int_to_little_endian(cmd, 1) # if its type is byte, element else: len_element = len(cmd) # First, add length of element if len_element < 75: result += int_to_little_endian(len_element, 1) elif len_element > 75 and len_element < 0x100: result += int_to_little_endian(76, 1) result += int_to_little_endian(len_element, 1) elif len_element >= 0x100 and len_element <= 520: result += int_to_little_endian(77, 1) result += int_to_little_endian(len_element, 2) else: raise ValueError('too long cmd') # after length, add element result += cmd return result
def serialize(self): '''Serialize this message to send over the network''' # version is 4 bytes little endian result = int_to_little_endian(self.version, 4) # services is 8 bytes little endian result += int_to_little_endian(self.services, 8) # timestamp is 8 bytes little endian result += int_to_little_endian(self.timestamp, 8) # receiver services is 8 bytes little endian result += int_to_little_endian(self.receiver_services, 8) # IPV4 is 10 00 bytes and 2 ff bytes then receiver ip result += b'\x00' * 10 + b'\xff\xff' + self.receiver_ip # receiver port is 2 bytes, big endian result += self.receiver_port.to_bytes(2, 'big') # sender services is 8 bytes little endian result += int_to_little_endian(self.sender_services, 8) # IPV4 is 10 00 bytes and 2 ff bytes then sender ip result += b'\x00' * 10 + b'\xff\xff' + self.sender_ip # sender port is 2 bytes, big endian result += self.sender_port.to_bytes(2, 'big') # nonce result += self.nonce # useragent is a variable string, so varint first result += encode_varint(len(self.user_agent)) result += self.user_agent # latest block is 4 bytes little endian result += int_to_little_endian(self.latest_block, 4) # relay is 00 if false, 01 if true if self.relay: result += b'\x01' else: result += b'\x00' return result
def raw_serialize(self): # initialize what we'll send back result = b'' # go through each cmd for cmd in self.cmds: # if the cmd is an integer, it's an opcode if type(cmd) == int: # turn the cmd into a single byte integer using int_to_little_endian result += int_to_little_endian(cmd, 1) else: # otherwise, this is an element # get the length in bytes length = len(cmd) # for large lengths, we have to use a pushdata opcode if length < 75: # turn the length into a single byte integer result += int_to_little_endian(length, 1) elif length > 75 and length < 0x100: # 76 is pushdata1 result += int_to_little_endian(76, 1) result += int_to_little_endian(length, 1) elif length >= 0x100 and length <= 520: # 77 is pushdata2 result += int_to_little_endian(77, 1) result += int_to_little_endian(length, 2) else: raise ValueError('too long an cmd') result += cmd return result
def sig_hash_w0_preimage(self, input_index, hash_type): # support only ALL type for now assert hash_type == SIGHASH_ALL # p2wsh and other nested types not yet supported tx_in = self.tx_ins[input_index] # tx_in to sign assert tx_in.script_pubkey().type() == 'p2wpkh' hash_prevouts = self.hash_prevouts(hash_type) hash_sequence = self.hash_sequence(hash_type) hash_outputs = self.hash_outputs(hash_type) result = int_to_little_endian(self.version, 4) result += hash_prevouts; result += hash_sequence; result += tx_in.prev_tx[::-1] result += int_to_little_endian(tx_in.prev_index, 4) # 88 ac = OP_EQUALVERIFY OP_CHECKSIG scriptCode = unhexlify('1976a914') + tx_in.script_pubkey().elements[1] + unhexlify('88ac') result += scriptCode result += int_to_little_endian(tx_in.value(), 8) result += int_to_little_endian(tx_in.sequence, 4) result += hash_outputs result += int_to_little_endian(self.locktime, 4) result += int_to_little_endian(hash_type, 4) return result
def sig_hash_bip143(self, input_index, redeem_script=None, witness_script=None): '''Returns the integer representation of the hash that needs to get signed for index input_index''' tx_in = self.tx_ins[input_index] # per BIP143 spec s = int_to_little_endian(self.version, 4) s += self.hash_prevouts() + self.hash_sequence() s += tx_in.prev_tx[::-1] + int_to_little_endian(tx_in.prev_index, 4) if witness_script: script_code = witness_script.serialize() elif redeem_script: script_code = p2pkh_script(redeem_script.cmds[1]).serialize() else: script_code = p2pkh_script( tx_in.script_pubkey(self.testnet).cmds[1]).serialize() s += script_code s += int_to_little_endian(tx_in.value(), 8) s += int_to_little_endian(tx_in.sequence, 4) s += self.hash_outputs() s += int_to_little_endian(self.locktime, 4) s += int_to_little_endian(SIGHASH_ALL, 4) return int.from_bytes(hash256(s), 'big')
def sig_hash(self, input_index): '''Returns the integer representation of the hash that needs to get signed for index input_index''' # 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): # if the input index is the one we're signing if i == input_index: # the previous tx's ScriptPubkey is the ScriptSig script_sig = tx_in.script_pubkey(self.testnet) # Otherwise, the ScriptSig is empty else: script_sig = None # 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=tx_in.sequence, ) # add the serialization of the TxIn object 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 tx_out in self.tx_outs: s += tx_out.serialize() # add the locktime using int_to_little_endian in 4 bytes s += int_to_little_endian(self.locktime, 4) # add SIGHASH_ALL using int_to_little_endian in 4 bytes s += int_to_little_endian(SIGHASH_ALL, 4) # hash256 the serialization h256 = hash256(s) # convert the result to an integer using int.from_bytes(x, 'big') return int.from_bytes(h256, 'big')
def serialize(self): '''Returns the byte serialization of the entire network message''' # add the network magic b'\xf9\xbe\xb4\xd9' result = b'\xf9\xbe\xb4\xd9' # command 12 bytes result += self.command # payload length 4 bytes, little endian result += int_to_little_endian(len(self.payload), 4) # checksum 4 bytes, first four of double-sha256 of payload result += double_sha256(self.payload)[:4] # payload result += self.payload return result
def zpub(self): if self.testnet: version = TESTNET_ZPUB else: version = MAINNET_ZPUB depth = int_to_little_endian(self.depth, 1) fingerprint = self.fingerprint child_number = self.child_number.to_bytes(4, 'big') chain_code = self.chain_code sec = self.point.sec() return encode_base58_checksum( version + depth + fingerprint + child_number + chain_code + sec)
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_all_wifs_from_mnemonic(cls, mnemonic, password=b'', path=b'm', segwit=False): # grab all wifs that correspond to addresses that have had any activity # for any account, if we have 10 blank addresses, we assume the wallet # has no more to look at hd_private_key = cls.from_mnemonic(mnemonic, password, path) wifs = [] for account in range(10): account_private_key = hd_private_key.child(account, hardened=True) if segwit: account_index = 3 change_index = 10 else: xpub = account_private_key.xpub() url = 'http://blockchain.info/multiaddr?active={}'.format(xpub) data = requests.get(url).json()['addresses'][0] received = data['total_received'] if received == 0: continue account_index = data['account_index'] change_index = data['change_index'] for chain, max_index in ((0, account_index), (1, change_index)): chain_private_key = account_private_key.child(chain) index = 0 for index in range(max_index + 1): current_private_key = chain_private_key.child(index) h160 = current_private_key.h160() socket = cls.get_socket() nonce = int_to_little_endian(randint(0, 2**32), 4) msg = b'blockchain.fetch_history3' socket.send(msg, SNDMORE) socket.send(nonce, SNDMORE) socket.send(h160 + b'\x00\x00\x00\x00') response_msg = socket.recv() response_nonce = socket.recv() if response_msg != msg or response_nonce != nonce: raise RuntimeError('received wrong msg: {}'.format( response_msg.decode('ascii'))) response = socket.recv() response_code = little_endian_to_int(response[:4]) if response_code != 0: raise RuntimeError( 'got code from server: {}'.format(response_code)) response = response[4:] if len(response) > 0: print(current_private_key.address()) wifs.append(current_private_key.wif()) return wifs
def fetch_address_utxos(cls, address, at_block_height=None): # grab all unspent transaction outputs as of block block_height # if block_height is None, we include all utxos address_data = cls.get_address_data(address) serialized_script_pubkey = address_data['script_pubkey'].serialize() socket = cls.get_socket(address_data['testnet']) nonce = int_to_little_endian(random.randint(0, 2**32), 4) msg = b'blockchain.fetch_history3' socket.send(msg, zmq.SNDMORE) socket.send(nonce, zmq.SNDMORE) socket.send(address_data['h160'] + b'\x00\x00\x00\x00') response_msg = socket.recv() response_nonce = socket.recv() if response_msg != msg or response_nonce != nonce: raise RuntimeError('received wrong msg: {}'.format( response_msg.decode('ascii'))) response = socket.recv() response_code = little_endian_to_int(response[:4]) if response_code != 0: raise RuntimeError( 'got code from server: {}'.format(response_code)) response = response[4:] receives = [] spent = set() while len(response) > 0: kind = response[0] prev_tx = response[1:33] prev_index = response[33:37] block_height = little_endian_to_int(response[37:41]) if kind == 0: value = little_endian_to_int(response[41:49]) if at_block_height is None or block_height < at_block_height: receives.append([prev_tx, prev_index, value]) else: if at_block_height is None or block_height < at_block_height: spent.add(little_endian_to_int(response[41:49])) response = response[49:] utxos = [] tx_mask = 0xffffffffffff8000 index_mask = 0x7fff for prev_tx, prev_index, value in receives: tx_upper_49_bits = ( little_endian_to_int(prev_tx) >> 12 * 8) & tx_mask index_lower_15_bits = little_endian_to_int(prev_index) & index_mask key = tx_upper_49_bits | index_lower_15_bits if key not in spent: utxos.append([ serialized_script_pubkey, prev_tx[::-1], little_endian_to_int(prev_index), value ]) return utxos
def sig_hash(self, input_index): '''Returns the integer representation of the hash that needs to get signed for index input_index''' # start the serialization with version # use int_to_little_endian in 4 bytes result = int_to_little_endian(self.version, 4) # add how many inputs there are using encode_varint result += encode_varint(len(self.tx_ins)) # loop through each input using enumerate, so we have the input index for (i, tx_in) in enumerate(self.tx_ins): # if the input index is the one we're signing # the previous tx's ScriptPubkey is the ScriptSig # create new tx as copy as not to alter original tx new_tx = TxIn(tx_in.prev_tx, tx_in.prev_index, sequence=tx_in.sequence) if i == input_index: new_tx.script_sig = tx_in.script_pubkey() # Otherwise, the ScriptSig is empty else: new_tx.script_sig = Script() # add the serialization of the input with the ScriptSig we want result += new_tx.serialize() # add how many outputs there are using encode_varint result += encode_varint(len(self.tx_outs)) # add the serialization of each output for tx_out in self.tx_outs: result += tx_out.serialize() # add the locktime using int_to_little_endian in 4 bytes result += int_to_little_endian(self.locktime, 4) # add SIGHASH_ALL using int_to_little_endian in 4 bytes result += int_to_little_endian(SIGHASH_ALL, 4) # hash256 the serialization result = hash256(result) # convert the result to an integer using int.from_bytes(x, 'big') return int.from_bytes(result, 'big')
def is_coinbase(self): '''Returns whether this transaction is a coinbase transaction or not''' # check that there is exactly 1 input if len(self.tx_ins) != 1: return False if self.tx_ins[0].prev_tx != int_to_little_endian(0, 32): return False # grab the first input # check that first input prev_tx is b'\x00' * 32 bytes # check that first input prev_index is 0xffffffff if self.tx_ins[0].prev_index != 0xffffffff: return False return True
def __init__(self, raw_tx, host, port, magic=NETWORK_MAGIC, timeout=10): self.raw_tx = raw_tx self.tx_hash = double_sha256(raw_tx) self.inv_payload = b'\x01' + int_to_little_endian(1, 4) + self.tx_hash self._sent = False self._accepted = False self.host = host self.port = port self.magic = magic self.reader = None self.writer = None self.q = asyncio.Queue() self.keep_looping = True self.timeout = timeout
def serialize_segwit(self): '''Returns the byte serialization of the transaction''' # serialize version (4 bytes, little endian) result = int_to_little_endian(self.version, 4) # segwit marker '0001' result += b'\x00\x01' # encode_varint on the number of inputs result += encode_varint(len(self.tx_ins)) # iterate inputs for tx_in in self.tx_ins: # serialize each input result += tx_in.serialize() # encode_varint on the number of inputs result += encode_varint(len(self.tx_outs)) # iterate outputs for tx_out in self.tx_outs: # serialize each output result += tx_out.serialize() # add the witness data for tx_in in self.tx_ins: result += tx_in.witness_program # serialize locktime (4 bytes, little endian) result += int_to_little_endian(self.locktime, 4) return result
def test_exercise_3(self): hex_tx = '0100000001868278ed6ddfb6c1ed3ad5f8181eb0c7a385aa0836f01d5e4789e6bd304d87221a000000db00483045022100dc92655fe37036f47756db8102e0d7d5e28b3beb83a8fef4f5dc0559bddfb94e02205a36d4e4e6c7fcd16658c50783e00c341609977aed3ad00937bf4ee942a8993701483045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e75402201475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152aeffffffff04d3b11400000000001976a914904a49878c0adfc3aa05de7afad2cc15f483a56a88ac7f400900000000001976a914418327e3f3dda4cf5b9089325a4b95abdfa0334088ac722c0c00000000001976a914ba35042cfe9fc66fd35ac2224eebdafd1028ad2788acdc4ace020000000017a91474d691da1574e6b3c192ecfb52cc8984ee7b6c568700000000' hex_sec = '03b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb71' hex_der = '3045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e754022' hex_redeem_script = '475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152ae' sec = bytes.fromhex(hex_sec) der = bytes.fromhex(hex_der) redeem_script = Script.parse(BytesIO(bytes.fromhex(hex_redeem_script))) stream = BytesIO(bytes.fromhex(hex_tx)) tx_obj = Tx.parse(stream) s = int_to_little_endian(tx_obj.version, 4) s += encode_varint(len(tx_obj.tx_ins)) i = tx_obj.tx_ins[0] s += TxIn(i.prev_tx, i.prev_index, redeem_script, i.sequence).serialize() s += encode_varint(len(tx_obj.tx_outs)) for tx_out in tx_obj.tx_outs: s += tx_out.serialize() s += int_to_little_endian(tx_obj.locktime, 4) s += int_to_little_endian(SIGHASH_ALL, 4) z = int.from_bytes(hash256(s), 'big') point = S256Point.parse(sec) sig = Signature.parse(der) self.assertTrue(point.verify(z, sig))
def serialize(self): '''Returns the byte serialization of the entire network message''' # add the network magic result = self.magic result += self.command + b'\x00' * (12 - len(self.command)) result += int_to_little_endian(len(self.payload), 4) result += hash256(self.payload)[:4] result += self.payload return result # command 12 bytes # fill with 0's # payload length 4 bytes, little endian # checksum 4 bytes, first four of hash256 of payload # payload raise NotImplementedError
def serialize(self): '''Returns the byte serialization of the entire network message''' # add the network magic s = self.magic # command 12 bytes # fill with 0's s += self.command for _ in range(12 - len(self.command)): s += b'\x00' # payload length 4 bytes, little endian s += int_to_little_endian(len(self.payload), 4) # checksum 4 bytes, first four of hash256 of payload s += hash256(self.payload)[:4] # payload s += self.payload return s
def verify_input(self, input_index): '''Returns whether the input has a valid signature''' # get the relevant input tx_in = self.tx_ins[input_index] # grab the previous ScriptPubKey script_pubkey = tx_in.script_pubkey(testnet=self.testnet) # check to see if the ScriptPubkey is a p2sh if script_pubkey.is_p2sh_script_pubkey(): # the last instruction has to be the RedeemScript to trigger instruction = tx_in.script_sig.instructions[-1] # parse the RedeemScript raw_redeem = int_to_little_endian(len(instruction), 1) + instruction redeem_script = Script.parse(BytesIO(raw_redeem)) # the RedeemScript might be p2wpkh or p2wsh if redeem_script.is_p2wpkh_script_pubkey(): z = self.sig_hash_bip143(input_index, redeem_script) witness = tx_in.witness elif redeem_script.is_p2wsh_script_pubkey(): instruction = tx_in.witness[-1] raw_witness = encode_varint(len(instruction)) + instruction witness_script = Script.parse(BytesIO(raw_witness)) z = self.sig_hash_bip143(input_index, witness_script=witness_script) witness = tx_in.witness else: z = self.sig_hash(input_index, redeem_script) witness = None else: # ScriptPubkey might be a p2wpkh or p2wsh if script_pubkey.is_p2wpkh_script_pubkey(): z = self.sig_hash_bip143(input_index) witness = tx_in.witness elif script_pubkey.is_p2wsh_script_pubkey(): instruction = tx_in.witness[-1] raw_witness = encode_varint(len(instruction)) + instruction witness_script = Script.parse(BytesIO(raw_witness)) z = self.sig_hash_bip143(input_index, witness_script=witness_script) witness = tx_in.witness else: z = self.sig_hash(input_index) witness = None # combine the current ScriptSig and the previous ScriptPubKey combined = tx_in.script_sig + script_pubkey # evaluate the combined script return combined.evaluate(z, witness)