def preimage_hash( self, coin: CoinInfo, tx: SignTx, txi: TxInputType, pubkeyhash: bytes, sighash: int, ) -> bytes: h_preimage = HashWriter(sha256) assert not tx.overwintered write_uint32(h_preimage, tx.version) # nVersion write_bytes(h_preimage, bytearray(self.get_prevouts_hash(coin))) # hashPrevouts write_bytes(h_preimage, bytearray(self.get_sequence_hash(coin))) # hashSequence write_bytes_reversed(h_preimage, txi.prev_hash) # outpoint write_uint32(h_preimage, txi.prev_index) # outpoint script_code = self.derive_script_code(txi, pubkeyhash) # scriptCode write_varint(h_preimage, len(script_code)) write_bytes(h_preimage, script_code) write_uint64(h_preimage, txi.amount) # amount write_uint32(h_preimage, txi.sequence) # nSequence write_bytes(h_preimage, bytearray(self.get_outputs_hash(coin))) # hashOutputs write_uint32(h_preimage, tx.lock_time) # nLockTime write_uint32(h_preimage, sighash) # nHashType return get_tx_hash(h_preimage, double=coin.sign_hash_double)
def preimage_hash(self, coin: CoinInfo, tx: SignTx, txi: TxInputType, pubkeyhash: bytes, sighash: int) -> bytes: h_preimage = HashWriter( blake2b, b'', 32, b'ZcashSigHash\x19\x1b\xa8\x5b') # BRANCH_ID = 0x5ba81b19 assert tx.overwintered write_uint32(h_preimage, tx.version | OVERWINTERED) # 1. nVersion | fOverwintered write_uint32(h_preimage, coin.version_group_id) # 2. nVersionGroupId write_bytes(h_preimage, bytearray(self.get_prevouts_hash())) # 3. hashPrevouts write_bytes(h_preimage, bytearray(self.get_sequence_hash())) # 4. hashSequence write_bytes(h_preimage, bytearray(self.get_outputs_hash())) # 5. hashOutputs write_bytes(h_preimage, b'\x00' * 32) # 6. hashJoinSplits write_uint32(h_preimage, tx.lock_time) # 7. nLockTime write_uint32(h_preimage, tx.expiry) # 8. expiryHeight write_uint32(h_preimage, sighash) # 9. nHashType write_bytes_rev(h_preimage, txi.prev_hash) # 10a. outpoint write_uint32(h_preimage, txi.prev_index) script_code = self.derive_script_code(txi, pubkeyhash) # 10b. scriptCode write_varint(h_preimage, len(script_code)) write_bytes(h_preimage, script_code) write_uint64(h_preimage, txi.amount) # 10c. value write_uint32(h_preimage, txi.sequence) # 10d. nSequence return get_tx_hash(h_preimage, False)
def preimage_hash( self, coin: CoinInfo, tx: SignTx, txi: TxInputType, pubkeyhash: bytes, sighash: int, ) -> bytes: h_preimage = HashWriter( blake2b(outlen=32, personal=b"ZcashSigHash" + struct.pack("<I", self.branch_id))) ensure(coin.overwintered) ensure(tx.version == 4) write_uint32(h_preimage, tx.version | OVERWINTERED) # 1. nVersion | fOverwintered write_uint32(h_preimage, tx.version_group_id) # 2. nVersionGroupId # 3. hashPrevouts write_bytes_fixed(h_preimage, bytearray(self.get_prevouts_hash()), TX_HASH_SIZE) # 4. hashSequence write_bytes_fixed(h_preimage, bytearray(self.get_sequence_hash()), TX_HASH_SIZE) # 5. hashOutputs write_bytes_fixed(h_preimage, bytearray(self.get_outputs_hash()), TX_HASH_SIZE) zero_hash = b"\x00" * TX_HASH_SIZE write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 6. hashJoinSplits write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 7. hashShieldedSpends write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 8. hashShieldedOutputs write_uint32(h_preimage, tx.lock_time) # 9. nLockTime write_uint32(h_preimage, tx.expiry) # 10. expiryHeight write_uint64(h_preimage, 0) # 11. valueBalance write_uint32(h_preimage, sighash) # 12. nHashType write_bytes_reversed(h_preimage, txi.prev_hash, TX_HASH_SIZE) # 13a. outpoint write_uint32(h_preimage, txi.prev_index) script_code = derive_script_code(txi, pubkeyhash) # 13b. scriptCode write_bytes_prefixed(h_preimage, script_code) write_uint64(h_preimage, txi.amount) # 13c. value write_uint32(h_preimage, txi.sequence) # 13d. nSequence return get_tx_hash(h_preimage)
def hash143_preimage_hash(self, txi: TxInputType, pubkeyhash: bytes) -> bytes: h_preimage = HashWriter(sha256()) # nVersion writers.write_uint32(h_preimage, self.tx.version) # hashPrevouts prevouts_hash = writers.get_tx_hash(self.h_prevouts, double=self.coin.sign_hash_double) writers.write_bytes_fixed(h_preimage, prevouts_hash, writers.TX_HASH_SIZE) # hashSequence sequence_hash = writers.get_tx_hash(self.h_sequence, double=self.coin.sign_hash_double) writers.write_bytes_fixed(h_preimage, sequence_hash, writers.TX_HASH_SIZE) # outpoint writers.write_bytes_reversed(h_preimage, txi.prev_hash, writers.TX_HASH_SIZE) writers.write_uint32(h_preimage, txi.prev_index) # scriptCode script_code = scripts.bip143_derive_script_code(txi, pubkeyhash) writers.write_bytes_prefixed(h_preimage, script_code) # amount writers.write_uint64(h_preimage, txi.amount) # nSequence writers.write_uint32(h_preimage, txi.sequence) # hashOutputs outputs_hash = writers.get_tx_hash(self.h_outputs, double=self.coin.sign_hash_double) writers.write_bytes_fixed(h_preimage, outputs_hash, writers.TX_HASH_SIZE) # nLockTime writers.write_uint32(h_preimage, self.tx.lock_time) # nHashType writers.write_uint32(h_preimage, self.get_hash_type()) return writers.get_tx_hash(h_preimage, double=self.coin.sign_hash_double)
def preimage_hash( self, coin: CoinInfo, tx: SignTx, txi: TxInputType, pubkeyhash: bytes, sighash: int, ) -> bytes: h_preimage = HashWriter( blake2b(outlen=32, personal=b"ZcashSigHash\xbb\x09\xb8\x76") ) # BRANCH_ID = 0x76b809bb / Sapling ensure(tx.overwintered) ensure(tx.version == 4) write_uint32(h_preimage, tx.version | OVERWINTERED) # 1. nVersion | fOverwintered write_uint32(h_preimage, tx.version_group_id) # 2. nVersionGroupId write_bytes(h_preimage, bytearray(self.get_prevouts_hash())) # 3. hashPrevouts write_bytes(h_preimage, bytearray(self.get_sequence_hash())) # 4. hashSequence write_bytes(h_preimage, bytearray(self.get_outputs_hash())) # 5. hashOutputs write_bytes(h_preimage, b"\x00" * 32) # 6. hashJoinSplits write_bytes(h_preimage, b"\x00" * 32) # 7. hashShieldedSpends write_bytes(h_preimage, b"\x00" * 32) # 8. hashShieldedOutputs write_uint32(h_preimage, tx.lock_time - self.hash_lock_offset) # 9. nLockTime write_uint32(h_preimage, tx.expiry) # 10. expiryHeight write_uint64(h_preimage, 0) # 11. valueBalance write_uint32(h_preimage, sighash) # 12. nHashType write_bytes_reversed(h_preimage, txi.prev_hash) # 13a. outpoint write_uint32(h_preimage, txi.prev_index) script_code = derive_script_code(txi, pubkeyhash) # 13b. scriptCode write_varint(h_preimage, len(script_code)) write_bytes(h_preimage, script_code) write_uint64(h_preimage, txi.amount) # 13c. value write_uint32(h_preimage, txi.sequence) # 13d. nSequence return get_tx_hash(h_preimage)
async def step7_finish(self) -> None: self.write_tx_footer(self.serialized_tx, self.tx) if self.tx.version == 3: write_uint32(self.serialized_tx, self.tx.expiry) # expiryHeight write_varint(self.serialized_tx, 0) # nJoinSplit elif self.tx.version == 4: write_uint32(self.serialized_tx, self.tx.expiry) # expiryHeight write_uint64(self.serialized_tx, 0) # valueBalance write_varint(self.serialized_tx, 0) # nShieldedSpend write_varint(self.serialized_tx, 0) # nShieldedOutput write_varint(self.serialized_tx, 0) # nJoinSplit else: raise SigningError( FailureType.DataError, "Unsupported version for overwintered transaction", ) await helpers.request_tx_finish(self.tx_req)
def preimage_hash( self, coin: CoinInfo, tx: SignTx, txi: TxInputType, pubkeyhash: bytes, sighash: int, ) -> bytes: h_preimage = HashWriter( blake2b( outlen=32, personal=b"ZcashSigHash" + struct.pack("<I", self.branch_id) ) ) ensure(tx.overwintered) ensure(tx.version == 3) write_uint32( h_preimage, tx.version | OVERWINTERED ) # 1. nVersion | fOverwintered write_uint32(h_preimage, tx.version_group_id) # 2. nVersionGroupId write_bytes(h_preimage, bytearray(self.get_prevouts_hash())) # 3. hashPrevouts write_bytes(h_preimage, bytearray(self.get_sequence_hash())) # 4. hashSequence write_bytes(h_preimage, bytearray(self.get_outputs_hash())) # 5. hashOutputs write_bytes(h_preimage, b"\x00" * 32) # 6. hashJoinSplits write_uint32(h_preimage, tx.lock_time) # 7. nLockTime write_uint32(h_preimage, tx.expiry) # 8. expiryHeight write_uint32(h_preimage, sighash) # 9. nHashType write_bytes_reversed(h_preimage, txi.prev_hash) # 10a. outpoint write_uint32(h_preimage, txi.prev_index) script_code = derive_script_code(txi, pubkeyhash) # 10b. scriptCode write_varint(h_preimage, len(script_code)) write_bytes(h_preimage, script_code) write_uint64(h_preimage, txi.amount) # 10c. value write_uint32(h_preimage, txi.sequence) # 10d. nSequence return get_tx_hash(h_preimage)
async def sign_tx(tx: SignTx, keychain: seed.Keychain): tx = helpers.sanitize_sign_tx(tx) progress.init(tx.inputs_count, tx.outputs_count) # Phase 1 h_first, hash143, segwit, authorized_in, wallet_path = await check_tx_fee( tx, keychain) # Phase 2 # - sign inputs # - check that nothing changed coin = coins.by_name(tx.coin_name) tx_ser = TxRequestSerializedType() txo_bin = TxOutputBinType() tx_req = TxRequest() tx_req.details = TxRequestDetailsType() tx_req.serialized = None if coin.decred: prefix_hash = hash143.prefix_hash() for i_sign in range(tx.inputs_count): progress.advance() txi_sign = None key_sign = None key_sign_pub = None if segwit[i_sign]: # STAGE_REQUEST_SEGWIT_INPUT txi_sign = await helpers.request_tx_input(tx_req, i_sign) if not input_is_segwit(txi_sign): raise SigningError(FailureType.ProcessError, "Transaction has changed during signing") input_check_wallet_path(txi_sign, wallet_path) key_sign = keychain.derive(txi_sign.address_n, coin.curve_name) key_sign_pub = key_sign.public_key() txi_sign.script_sig = input_derive_script(coin, txi_sign, key_sign_pub) w_txi = writers.empty_bytearray(7 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4) if i_sign == 0: # serializing first input => prepend headers writers.write_bytes(w_txi, get_tx_header(coin, tx, True)) writers.write_tx_input(w_txi, txi_sign) tx_ser.serialized_tx = w_txi tx_req.serialized = tx_ser elif coin.force_bip143 or tx.overwintered: # STAGE_REQUEST_SEGWIT_INPUT txi_sign = await helpers.request_tx_input(tx_req, i_sign) input_check_wallet_path(txi_sign, wallet_path) is_bip143 = (txi_sign.script_type == InputScriptType.SPENDADDRESS or txi_sign.script_type == InputScriptType.SPENDMULTISIG) if not is_bip143 or txi_sign.amount > authorized_in: raise SigningError(FailureType.ProcessError, "Transaction has changed during signing") authorized_in -= txi_sign.amount key_sign = keychain.derive(txi_sign.address_n, coin.curve_name) key_sign_pub = key_sign.public_key() hash143_hash = hash143.preimage_hash( coin, tx, txi_sign, addresses.ecdsa_hash_pubkey(key_sign_pub, coin), get_hash_type(coin), ) # if multisig, check if signing with a key that is included in multisig if txi_sign.multisig: multisig.multisig_pubkey_index(txi_sign.multisig, key_sign_pub) signature = ecdsa_sign(key_sign, hash143_hash) tx_ser.signature_index = i_sign tx_ser.signature = signature # serialize input with correct signature txi_sign.script_sig = input_derive_script(coin, txi_sign, key_sign_pub, signature) w_txi_sign = writers.empty_bytearray(5 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4) if i_sign == 0: # serializing first input => prepend headers writers.write_bytes(w_txi_sign, get_tx_header(coin, tx)) writers.write_tx_input(w_txi_sign, txi_sign) tx_ser.serialized_tx = w_txi_sign tx_req.serialized = tx_ser elif coin.decred: txi_sign = await helpers.request_tx_input(tx_req, i_sign) input_check_wallet_path(txi_sign, wallet_path) key_sign = keychain.derive(txi_sign.address_n, coin.curve_name) key_sign_pub = key_sign.public_key() if txi_sign.script_type == InputScriptType.SPENDMULTISIG: prev_pkscript = scripts.output_script_multisig( multisig.multisig_get_pubkeys(txi_sign.multisig), txi_sign.multisig.m, ) elif txi_sign.script_type == InputScriptType.SPENDADDRESS: prev_pkscript = scripts.output_script_p2pkh( addresses.ecdsa_hash_pubkey(key_sign_pub, coin)) else: raise ValueError("Unknown input script type") h_witness = utils.HashWriter(blake256()) writers.write_uint32( h_witness, tx.version | decred.DECRED_SERIALIZE_WITNESS_SIGNING) writers.write_varint(h_witness, tx.inputs_count) for ii in range(tx.inputs_count): if ii == i_sign: writers.write_varint(h_witness, len(prev_pkscript)) writers.write_bytes(h_witness, prev_pkscript) else: writers.write_varint(h_witness, 0) witness_hash = writers.get_tx_hash(h_witness, double=coin.sign_hash_double, reverse=False) h_sign = utils.HashWriter(blake256()) writers.write_uint32(h_sign, decred.DECRED_SIGHASHALL) writers.write_bytes(h_sign, prefix_hash) writers.write_bytes(h_sign, witness_hash) sig_hash = writers.get_tx_hash(h_sign, double=coin.sign_hash_double) signature = ecdsa_sign(key_sign, sig_hash) tx_ser.signature_index = i_sign tx_ser.signature = signature # serialize input with correct signature txi_sign.script_sig = input_derive_script(coin, txi_sign, key_sign_pub, signature) w_txi_sign = writers.empty_bytearray( 8 + 4 + len(hash143.get_last_output_bytes()) if i_sign == 0 else 0 + 16 + 4 + len(txi_sign.script_sig)) if i_sign == 0: writers.write_bytes(w_txi_sign, hash143.get_last_output_bytes()) writers.write_uint32(w_txi_sign, tx.lock_time) writers.write_uint32(w_txi_sign, tx.expiry) writers.write_varint(w_txi_sign, tx.inputs_count) writers.write_tx_input_decred_witness(w_txi_sign, txi_sign) tx_ser.serialized_tx = w_txi_sign tx_req.serialized = tx_ser else: # hash of what we are signing with this input h_sign = utils.HashWriter(sha256()) # same as h_first, checked before signing the digest h_second = utils.HashWriter(sha256()) if tx.overwintered: writers.write_uint32( h_sign, tx.version | zcash.OVERWINTERED) # nVersion | fOverwintered writers.write_uint32(h_sign, tx.version_group_id) # nVersionGroupId else: writers.write_uint32(h_sign, tx.version) # nVersion if tx.timestamp: writers.write_uint32(h_sign, tx.timestamp) writers.write_varint(h_sign, tx.inputs_count) for i in range(tx.inputs_count): # STAGE_REQUEST_4_INPUT txi = await helpers.request_tx_input(tx_req, i) input_check_wallet_path(txi, wallet_path) writers.write_tx_input_check(h_second, txi) if i == i_sign: txi_sign = txi key_sign = keychain.derive(txi.address_n, coin.curve_name) key_sign_pub = key_sign.public_key() # for the signing process the script_sig is equal # to the previous tx's scriptPubKey (P2PKH) or a redeem script (P2SH) if txi_sign.script_type == InputScriptType.SPENDMULTISIG: txi_sign.script_sig = scripts.output_script_multisig( multisig.multisig_get_pubkeys(txi_sign.multisig), txi_sign.multisig.m, ) elif txi_sign.script_type == InputScriptType.SPENDADDRESS: txi_sign.script_sig = scripts.output_script_p2pkh( addresses.ecdsa_hash_pubkey(key_sign_pub, coin)) if coin.bip115: txi_sign.script_sig += scripts.script_replay_protection_bip115( txi_sign.prev_block_hash_bip115, txi_sign.prev_block_height_bip115, ) else: raise SigningError(FailureType.ProcessError, "Unknown transaction type") else: txi.script_sig = bytes() writers.write_tx_input(h_sign, txi) writers.write_varint(h_sign, tx.outputs_count) for o in range(tx.outputs_count): # STAGE_REQUEST_4_OUTPUT txo = await helpers.request_tx_output(tx_req, o) txo_bin.amount = txo.amount txo_bin.script_pubkey = output_derive_script( txo, coin, keychain) writers.write_tx_output(h_second, txo_bin) writers.write_tx_output(h_sign, txo_bin) writers.write_uint32(h_sign, tx.lock_time) if tx.overwintered: writers.write_uint32(h_sign, tx.expiry) # expiryHeight writers.write_varint(h_sign, 0) # nJoinSplit writers.write_uint32(h_sign, get_hash_type(coin)) # check the control digests if writers.get_tx_hash(h_first, False) != writers.get_tx_hash(h_second): raise SigningError(FailureType.ProcessError, "Transaction has changed during signing") # if multisig, check if signing with a key that is included in multisig if txi_sign.multisig: multisig.multisig_pubkey_index(txi_sign.multisig, key_sign_pub) # compute the signature from the tx digest signature = ecdsa_sign( key_sign, writers.get_tx_hash(h_sign, double=coin.sign_hash_double)) tx_ser.signature_index = i_sign tx_ser.signature = signature # serialize input with correct signature txi_sign.script_sig = input_derive_script(coin, txi_sign, key_sign_pub, signature) w_txi_sign = writers.empty_bytearray(5 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4) if i_sign == 0: # serializing first input => prepend headers writers.write_bytes(w_txi_sign, get_tx_header(coin, tx)) writers.write_tx_input(w_txi_sign, txi_sign) tx_ser.serialized_tx = w_txi_sign tx_req.serialized = tx_ser if coin.decred: return await helpers.request_tx_finish(tx_req) for o in range(tx.outputs_count): progress.advance() # STAGE_REQUEST_5_OUTPUT txo = await helpers.request_tx_output(tx_req, o) txo_bin.amount = txo.amount txo_bin.script_pubkey = output_derive_script(txo, coin, keychain) # serialize output w_txo_bin = writers.empty_bytearray(5 + 8 + 5 + len(txo_bin.script_pubkey) + 4) if o == 0: # serializing first output => prepend outputs count writers.write_varint(w_txo_bin, tx.outputs_count) writers.write_tx_output(w_txo_bin, txo_bin) tx_ser.signature_index = None tx_ser.signature = None tx_ser.serialized_tx = w_txo_bin tx_req.serialized = tx_ser any_segwit = True in segwit.values() for i in range(tx.inputs_count): progress.advance() if segwit[i]: # STAGE_REQUEST_SEGWIT_WITNESS txi = await helpers.request_tx_input(tx_req, i) input_check_wallet_path(txi, wallet_path) if not input_is_segwit(txi) or txi.amount > authorized_in: raise SigningError(FailureType.ProcessError, "Transaction has changed during signing") authorized_in -= txi.amount key_sign = keychain.derive(txi.address_n, coin.curve_name) key_sign_pub = key_sign.public_key() hash143_hash = hash143.preimage_hash( coin, tx, txi, addresses.ecdsa_hash_pubkey(key_sign_pub, coin), get_hash_type(coin), ) signature = ecdsa_sign(key_sign, hash143_hash) if txi.multisig: # find out place of our signature based on the pubkey signature_index = multisig.multisig_pubkey_index( txi.multisig, key_sign_pub) witness = scripts.witness_p2wsh(txi.multisig, signature, signature_index, get_hash_type(coin)) else: witness = scripts.witness_p2wpkh(signature, key_sign_pub, get_hash_type(coin)) tx_ser.serialized_tx = witness tx_ser.signature_index = i tx_ser.signature = signature elif any_segwit: tx_ser.serialized_tx = bytearray( 1) # empty witness for non-segwit inputs tx_ser.signature_index = None tx_ser.signature = None tx_req.serialized = tx_ser writers.write_uint32(tx_ser.serialized_tx, tx.lock_time) if tx.overwintered: if tx.version == 3: writers.write_uint32(tx_ser.serialized_tx, tx.expiry) # expiryHeight writers.write_varint(tx_ser.serialized_tx, 0) # nJoinSplit elif tx.version == 4: writers.write_uint32(tx_ser.serialized_tx, tx.expiry) # expiryHeight writers.write_uint64(tx_ser.serialized_tx, 0) # valueBalance writers.write_varint(tx_ser.serialized_tx, 0) # nShieldedSpend writers.write_varint(tx_ser.serialized_tx, 0) # nShieldedOutput writers.write_varint(tx_ser.serialized_tx, 0) # nJoinSplit else: raise SigningError( FailureType.DataError, "Unsupported version for overwintered transaction", ) await helpers.request_tx_finish(tx_req)
def hash143_preimage_hash(self, txi: TxInputType, pubkeyhash: bytes) -> bytes: h_preimage = HashWriter( blake2b( outlen=32, personal=b"ZcashSigHash" + struct.pack("<I", self.tx.branch_id), ) ) # 1. nVersion | fOverwintered write_uint32(h_preimage, self.tx.version | OVERWINTERED) # 2. nVersionGroupId write_uint32(h_preimage, self.tx.version_group_id) # 3. hashPrevouts write_bytes_fixed(h_preimage, get_tx_hash(self.h_prevouts), TX_HASH_SIZE) # 4. hashSequence write_bytes_fixed(h_preimage, get_tx_hash(self.h_sequence), TX_HASH_SIZE) # 5. hashOutputs write_bytes_fixed(h_preimage, get_tx_hash(self.h_outputs), TX_HASH_SIZE) if self.tx.version == 3: # 6. hashJoinSplits write_bytes_fixed(h_preimage, b"\x00" * TX_HASH_SIZE, TX_HASH_SIZE) # 7. nLockTime write_uint32(h_preimage, self.tx.lock_time) # 8. expiryHeight write_uint32(h_preimage, self.tx.expiry) # 9. nHashType write_uint32(h_preimage, self.get_hash_type()) elif self.tx.version == 4: zero_hash = b"\x00" * TX_HASH_SIZE # 6. hashJoinSplits write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 7. hashShieldedSpends write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 8. hashShieldedOutputs write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 9. nLockTime write_uint32(h_preimage, self.tx.lock_time) # 10. expiryHeight write_uint32(h_preimage, self.tx.expiry) # 11. valueBalance write_uint64(h_preimage, 0) # 12. nHashType write_uint32(h_preimage, self.get_hash_type()) else: raise SigningError( FailureType.DataError, "Unsupported version for overwintered transaction", ) # 10a /13a. outpoint write_bytes_reversed(h_preimage, txi.prev_hash, TX_HASH_SIZE) write_uint32(h_preimage, txi.prev_index) # 10b / 13b. scriptCode script_code = derive_script_code(txi, pubkeyhash) write_bytes_prefixed(h_preimage, script_code) # 10c / 13c. value write_uint64(h_preimage, txi.amount) # 10d / 13d. nSequence write_uint32(h_preimage, txi.sequence) return get_tx_hash(h_preimage)