def __init__(self) -> None: self.h_prevouts = HashWriter( blake2b(outlen=32, personal=b"ZcashPrevoutHash")) self.h_sequence = HashWriter( blake2b(outlen=32, personal=b"ZcashSequencHash")) self.h_outputs = HashWriter( blake2b(outlen=32, personal=b"ZcashOutputsHash"))
def __init__(self, branch_id): self.branch_id = branch_id self.h_prevouts = HashWriter( blake2b(outlen=32, personal=b"ZcashPrevoutHash")) self.h_sequence = HashWriter( blake2b(outlen=32, personal=b"ZcashSequencHash")) self.h_outputs = HashWriter( blake2b(outlen=32, personal=b"ZcashOutputsHash"))
def __init__(self, hash_type='zcash'): self.h_prevouts = HashWriter( blake2b(outlen=32, personal=b"ZcashPrevoutHash")) self.h_sequence = HashWriter( blake2b(outlen=32, personal=b"ZcashSequencHash")) self.h_outputs = HashWriter( blake2b(outlen=32, personal=b"ZcashOutputsHash")) self.hash_type = hash_type self.hash_lock_offset = 777 if self.hash_type == 'komodo' else 0
def __init__(self): self.h_prevouts = HashWriter(blake2b, outlen=32, personal=b'ZcashPrevoutHash') self.h_sequence = HashWriter(blake2b, outlen=32, personal=b'ZcashSequencHash') self.h_outputs = HashWriter(blake2b, outlen=32, personal=b'ZcashOutputsHash')
def message_digest(coin, message): if coin.decred: h = HashWriter(blake256) else: h = HashWriter(sha256) write_varint(h, len(coin.signed_message_header)) h.extend(coin.signed_message_header) write_varint(h, len(message)) h.extend(message) ret = h.get_digest() if coin.sign_hash_double: ret = sha256(ret).digest() return ret
def address_multisig_p2wsh_in_p2sh(pubkeys: list[bytes], m: int, coin: CoinInfo) -> str: if coin.address_type_p2sh is None: raise wire.ProcessError("Multisig not enabled on this coin") witness_script_h = HashWriter(sha256()) write_output_script_multisig(witness_script_h, pubkeys, m) return address_p2wsh_in_p2sh(witness_script_h.get_digest(), coin)
def preimage_hash(self, tx: SignTx, txi: TxInputType, pubkeyhash: bytes, sighash: int) -> bytes: h_preimage = HashWriter(sha256) write_uint32(h_preimage, tx.version) # nVersion write_bytes(h_preimage, bytearray(self.get_prevouts_hash())) # hashPrevouts write_bytes(h_preimage, bytearray(self.get_sequence_hash())) # hashSequence write_bytes_rev(h_preimage, txi.prev_hash) # outpoint write_uint32(h_preimage, txi.prev_index) # outpoint script_code = self.derive_script_code(txi, pubkeyhash) write_varint(h_preimage, len(script_code)) # scriptCode length write_bytes(h_preimage, script_code) # scriptCode write_uint64(h_preimage, txi.amount) # amount write_uint32(h_preimage, txi.sequence) # nSequence write_bytes(h_preimage, bytearray(self.get_outputs_hash())) # hashOutputs write_uint32(h_preimage, tx.lock_time) # nLockTime write_uint32(h_preimage, sighash) # nHashType return get_tx_hash(h_preimage, True)
async def verify_original_txs(self) -> None: for orig in self.orig_txs: # should come out the same as h_inputs_check, checked before continuing h_check = HashWriter(sha256()) for i in range(orig.tx.inputs_count): txi = await helpers.request_tx_input( self.tx_req, i, self.coin, orig.orig_hash ) writers.write_tx_input_check(h_check, txi) script_pubkey = self.input_derive_script(txi) verifier = SignatureVerifier( script_pubkey, txi.script_sig, txi.witness, self.coin ) verifier.ensure_hash_type( (SigHashType.SIGHASH_ALL_TAPROOT, self.get_sighash_type(txi)) ) tx_digest = await self.get_tx_digest( i, txi, orig, verifier.public_keys, verifier.threshold, script_pubkey, ) verifier.verify(tx_digest) # check that the inputs were the same as those streamed for approval if h_check.get_digest() != orig.h_inputs_check: raise wire.ProcessError("Transaction has changed during signing")
async def sign_tx( ctx: wire.Context, msg: EosSignTx, keychain: seed.Keychain ) -> EosSignedTx: if msg.chain_id is None: raise wire.DataError("No chain id") if msg.header is None: raise wire.DataError("No header") if msg.num_actions is None or msg.num_actions == 0: raise wire.DataError("No actions") await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE) node = keychain.derive(msg.address_n) sha = HashWriter(sha256()) await _init(ctx, sha, msg) await _actions(ctx, sha, msg.num_actions) writers.write_variant32(sha, 0) writers.write_bytes(sha, bytearray(32)) digest = sha.get_digest() signature = secp256k1.sign( node.private_key(), digest, True, secp256k1.CANONICAL_SIG_EOS ) return EosSignedTx(signature=base58_encode("SIG_", "K1", signature))
def sig_digest( self, txi: TxInput | None, script_pubkey: bytes | None, ) -> bytes: """ Returns `S.2: transparent_sig_digest` field for signature digest computation. see: https://zips.z.cash/zip-0244#s-2-transparent-sig-digest """ if self.empty: assert txi is None assert script_pubkey is None return self.digest() h = HashWriter(blake2b(outlen=32, personal=b"ZTxIdTranspaHash")) # only SIGHASH_ALL is supported in Trezor write_uint8(h, SigHashType.SIGHASH_ALL) # S.2a write_hash(h, self.prevouts.get_digest()) # S.2b write_hash(h, self.amounts.get_digest()) # S.2c write_hash(h, self.scriptpubkeys.get_digest()) # S.2d write_hash(h, self.sequence.get_digest()) # S.2e write_hash(h, self.outputs.get_digest()) # S.2f write_hash(h, _txin_sig_digest(txi, script_pubkey)) # S.2g return h.get_digest()
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_rev(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)
async def process_unknown_action(ctx: wire.Context, w: Writer, action: EosTxActionAck) -> None: checksum = HashWriter(sha256()) writers.write_variant32(checksum, action.unknown.data_size) checksum.extend(action.unknown.data_chunk) writers.write_bytes_unchecked(w, action.unknown.data_chunk) bytes_left = action.unknown.data_size - len(action.unknown.data_chunk) while bytes_left != 0: action = await ctx.call(EosTxActionRequest(data_size=bytes_left), EosTxActionAck) if action.unknown is None: raise ValueError("Bad response. Unknown struct expected.") checksum.extend(action.unknown.data_chunk) writers.write_bytes_unchecked(w, action.unknown.data_chunk) bytes_left -= len(action.unknown.data_chunk) if bytes_left < 0: raise ValueError("Bad response. Buffer overflow.") await layout.confirm_action_unknown(ctx, action.common, checksum.get_digest())
async def ethereum_sign_tx(ctx, msg): from trezor.crypto.hashlib import sha3_256 msg = sanitize(msg) check(msg) data_total = msg.data_length # detect ERC - 20 token token = None recipient = msg.to value = int.from_bytes(msg.value, 'big') if len(msg.to) == 20 and \ len(msg.value) == 0 and \ data_total == 68 and \ len(msg.data_initial_chunk) == 68 and \ msg.data_initial_chunk[:16] == b'\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00': token = tokens.token_by_chain_address(msg.chain_id, msg.to) recipient = msg.data_initial_chunk[16:36] value = int.from_bytes(msg.data_initial_chunk[36:68], 'big') await require_confirm_tx(ctx, recipient, value, msg.chain_id, token) if token is None and msg.data_length > 0: await require_confirm_data(ctx, msg.data_initial_chunk, data_total) await require_confirm_fee(ctx, value, int.from_bytes(msg.gas_price, 'big'), int.from_bytes(msg.gas_limit, 'big'), msg.chain_id, token) data = bytearray() data += msg.data_initial_chunk data_left = data_total - len(msg.data_initial_chunk) total_length = get_total_length(msg, data_total) sha = HashWriter(sha3_256) sha.extend(rlp.encode_length(total_length, True)) # total length for field in [msg.nonce, msg.gas_price, msg.gas_limit, msg.to, msg.value]: sha.extend(rlp.encode(field)) if data_left == 0: sha.extend(rlp.encode(data)) else: sha.extend(rlp.encode_length(data_total, False)) sha.extend(rlp.encode(data, False)) while data_left > 0: resp = await send_request_chunk(ctx, data_left) data_left -= len(resp.data_chunk) sha.extend(resp.data_chunk) # eip 155 replay protection if msg.chain_id: sha.extend(rlp.encode(msg.chain_id)) sha.extend(rlp.encode(0)) sha.extend(rlp.encode(0)) digest = sha.get_digest(True) # True -> use keccak mode return await send_signature(ctx, msg, digest)
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)
def message_digest(message): h = HashWriter(sha3_256(keccak=True)) signed_message_header = "\x19Ethereum Signed Message:\n" h.extend(signed_message_header) h.extend(str(len(message))) h.extend(message) return h.get_digest()
def multisig_fingerprint(multisig: MultisigRedeemScriptType) -> bytes: pubkeys = multisig.pubkeys m = multisig.m n = len(pubkeys) if n < 1 or n > 15 or m < 1 or m > 15: raise MultisigError(FailureType.DataError, "Invalid multisig parameters") for hd in pubkeys: d = hd.node if len(d.public_key) != 33 or len(d.chain_code) != 32: raise MultisigError(FailureType.DataError, "Invalid multisig parameters") # casting to bytes(), sorting on bytearray() is not supported in MicroPython pubkeys = sorted(pubkeys, key=lambda hd: bytes(hd.node.public_key)) h = HashWriter(sha256) write_uint32(h, m) write_uint32(h, n) for hd in pubkeys: d = hd.node write_uint32(h, d.depth) write_uint32(h, d.fingerprint) write_uint32(h, d.child_num) write_bytes(h, d.chain_code) write_bytes(h, d.public_key) return h.get_digest()
def multisig_fingerprint(multisig: MultisigRedeemScriptType) -> bytes: if multisig.nodes: pubnodes = multisig.nodes else: pubnodes = [hd.node for hd in multisig.pubkeys] m = multisig.m n = len(pubnodes) if n < 1 or n > 15 or m < 1 or m > 15: raise wire.DataError("Invalid multisig parameters") for d in pubnodes: if len(d.public_key) != 33 or len(d.chain_code) != 32: raise wire.DataError("Invalid multisig parameters") # casting to bytes(), sorting on bytearray() is not supported in MicroPython pubnodes = sorted(pubnodes, key=lambda n: bytes(n.public_key)) h = HashWriter(sha256()) write_uint32(h, m) write_uint32(h, n) for d in pubnodes: write_uint32(h, d.depth) write_uint32(h, d.fingerprint) write_uint32(h, d.child_num) write_bytes_fixed(h, d.chain_code, 32) write_bytes_fixed(h, d.public_key, 33) return h.get_digest()
def message_digest(message): h = HashWriter(sha256()) signed_message_header = 'Beam Signed Message:\n' h.extend(signed_message_header) h.extend(str(len(message))) h.extend(message) return sha256(h.get_digest()).digest()
async def sign_tx(ctx: wire.Context, msg: EthereumSignTx, keychain: Keychain) -> EthereumTxRequest: check(msg) await paths.validate_path(ctx, keychain, msg.address_n) # Handle ERC20s token, address_bytes, recipient, value = await handle_erc20(ctx, msg) data_total = msg.data_length await require_confirm_tx(ctx, recipient, value, msg.chain_id, token) if token is None and msg.data_length > 0: await require_confirm_data(ctx, msg.data_initial_chunk, data_total) await require_confirm_fee( ctx, value, int.from_bytes(msg.gas_price, "big"), int.from_bytes(msg.gas_limit, "big"), msg.chain_id, token, ) data = bytearray() data += msg.data_initial_chunk data_left = data_total - len(msg.data_initial_chunk) total_length = get_total_length(msg, data_total) sha = HashWriter(sha3_256(keccak=True)) rlp.write_header(sha, total_length, rlp.LIST_HEADER_BYTE) if msg.tx_type is not None: rlp.write(sha, msg.tx_type) for field in (msg.nonce, msg.gas_price, msg.gas_limit, address_bytes, msg.value): rlp.write(sha, field) if data_left == 0: rlp.write(sha, data) else: rlp.write_header(sha, data_total, rlp.STRING_HEADER_BYTE, data) sha.extend(data) while data_left > 0: resp = await send_request_chunk(ctx, data_left) data_left -= len(resp.data_chunk) sha.extend(resp.data_chunk) # eip 155 replay protection rlp.write(sha, msg.chain_id) rlp.write(sha, 0) rlp.write(sha, 0) digest = sha.get_digest() result = sign_digest(msg, keychain, digest) return result
def message_digest(message): h = HashWriter(sha256) signed_message_header = "Lisk Signed Message:\n" write_varint(h, len(signed_message_header)) h.extend(signed_message_header) write_varint(h, len(message)) h.extend(message) return sha256(h.get_digest()).digest()
def preimage_hash( self, txi: TxInput, public_keys: list[bytes], threshold: int, tx: SignTx | PrevTx, coin: coininfo.CoinInfo, sighash_type: int, ) -> bytes: h_preimage = HashWriter( blake2b( outlen=32, personal=b"ZcashSigHash" + struct.pack("<I", tx.branch_id), )) assert tx.version_group_id is not None assert tx.expiry is not None zero_hash = b"\x00" * TX_HASH_SIZE # 1. nVersion | fOverwintered write_uint32(h_preimage, tx.version | OVERWINTERED) # 2. nVersionGroupId write_uint32(h_preimage, 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) # 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, tx.lock_time) # 10. expiryHeight write_uint32(h_preimage, tx.expiry) # 11. valueBalance write_uint64(h_preimage, 0) # 12. nHashType write_uint32(h_preimage, sighash_type) # 13a. outpoint write_bytes_reversed(h_preimage, txi.prev_hash, TX_HASH_SIZE) write_uint32(h_preimage, txi.prev_index) # 13b. scriptCode script_code = derive_script_code(txi, public_keys, threshold, coin) write_bytes_prefixed(h_preimage, script_code) # 13c. value write_uint64(h_preimage, txi.amount) # 13d. nSequence write_uint32(h_preimage, txi.sequence) return get_tx_hash(h_preimage)
def preimage_hash( self, txi: TxInput, public_keys: List[bytes], threshold: int, tx: Union[SignTx, PrevTx], coin: coininfo.CoinInfo, sighash_type: int, ) -> bytes: h_preimage = HashWriter(sha256()) # nVersion writers.write_uint32(h_preimage, tx.version) # hashPrevouts prevouts_hash = writers.get_tx_hash(self.h_prevouts, double=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=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, public_keys, threshold, coin) 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=coin.sign_hash_double) writers.write_bytes_fixed(h_preimage, outputs_hash, writers.TX_HASH_SIZE) # nLockTime writers.write_uint32(h_preimage, tx.lock_time) # nHashType writers.write_uint32(h_preimage, sighash_type) return writers.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(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 __init__(self) -> None: self.prevouts = HashWriter( blake2b(outlen=32, personal=b"ZTxIdPrevoutHash") ) # a hasher for fields T.2a & S.2b self.amounts = HashWriter( blake2b(outlen=32, personal=b"ZTxTrAmountsHash") ) # a hasher for field S.2c self.scriptpubkeys = HashWriter( blake2b(outlen=32, personal=b"ZTxTrScriptsHash") ) # a hasher for field S.2d self.sequence = HashWriter( blake2b(outlen=32, personal=b"ZTxIdSequencHash") ) # a hasher for fields T.2b & S.2e self.outputs = HashWriter( blake2b(outlen=32, personal=b"ZTxIdOutputsHash") ) # a hasher for fields T.2c & S.2f self.empty = True # inputs_amount + outputs_amount == 0
def test_p2wsh_address(self): coin = coins.by_name('Testnet') # pubkey OP_CHECKSIG script = unhexlify('210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac') h = HashWriter(sha256()) write_bytes_unchecked(h, script) address = address_p2wsh( h.get_digest(), coin.bech32_prefix ) self.assertEqual(address, 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7')
def message_digest(message): from apps.wallet.sign_tx.signing import write_varint from trezor.crypto.hashlib import sha3_256 from trezor.utils import HashWriter h = HashWriter(sha3_256) signed_message_header = 'Ethereum Signed Message:\n' write_varint(h, len(signed_message_header)) h.extend(signed_message_header) write_varint(h, len(message)) h.extend(message) return h.get_digest(True)
async def step3_verify_inputs(self) -> None: # should come out the same as h_inputs_check, checked before continuing h_check = HashWriter(sha256()) if self.taproot_only: # All internal inputs are Taproot. We only need to verify external inputs. We can trust # the amounts and scriptPubKeys, because if an invalid value is provided then all # issued signatures will be invalid. expected_digest = self.h_external_inputs for i in self.external: progress.advance() txi = await helpers.request_tx_input(self.tx_req, i, self.coin) writers.write_tx_input_check(h_check, txi) if not input_is_external_unverified(txi): assert txi.script_pubkey is not None # checked in sanitize_tx_input await self.verify_external_input(i, txi, txi.script_pubkey) progress.advance(self.tx_info.tx.inputs_count - len(self.external)) else: # There are internal non-Taproot inputs. We need to verify all inputs, because we can't # trust any amounts or scriptPubKeys. If we did, then an attacker who provides invalid # information about amounts, scriptPubKeys and/or script types may still obtain valid # signatures for legacy and SegWit v0 inputs. These valid signatures could be exploited # in subsequent signing operations to falsely claim externality of the already signed # inputs or to falsely claim that a transaction is a replacement of an already approved # transaction or to construct a valid transaction by combining signatures obtained in # multiple rounds of the attack. expected_digest = self.tx_info.h_inputs_check for i in range(self.tx_info.tx.inputs_count): progress.advance() txi = await helpers.request_tx_input(self.tx_req, i, self.coin) writers.write_tx_input_check(h_check, txi) prev_amount, script_pubkey = await self.get_prevtx_output( txi.prev_hash, txi.prev_index ) if prev_amount != txi.amount: raise wire.DataError("Invalid amount specified") if script_pubkey != self.input_derive_script(txi): raise wire.DataError("Input does not match scriptPubKey") if i in self.external and not input_is_external_unverified(txi): await self.verify_external_input(i, txi, script_pubkey) # check that the inputs were the same as those streamed for approval if h_check.get_digest() != expected_digest: raise wire.ProcessError("Transaction has changed during signing") # verify the signature of one SIGHASH_ALL input in each original transaction await self.verify_original_txs()
async def get_prevtx_output_value(coin: CoinInfo, tx_req: TxRequest, prev_hash: bytes, prev_index: int) -> int: total_out = 0 # sum of output amounts # STAGE_REQUEST_2_PREV_META tx = await request_tx_meta(tx_req, prev_hash) txh = HashWriter(sha256) if tx.overwintered: write_uint32(txh, tx.version | OVERWINTERED) # nVersion | fOverwintered write_uint32(txh, coin.version_group_id) # nVersionGroupId else: write_uint32(txh, tx.version) # nVersion write_varint(txh, tx.inputs_cnt) for i in range(tx.inputs_cnt): # STAGE_REQUEST_2_PREV_INPUT txi = await request_tx_input(tx_req, i, prev_hash) write_tx_input(txh, txi) write_varint(txh, tx.outputs_cnt) for o in range(tx.outputs_cnt): # STAGE_REQUEST_2_PREV_OUTPUT txo_bin = await request_tx_output(tx_req, o, prev_hash) write_tx_output(txh, txo_bin) if o == prev_index: total_out += txo_bin.amount write_uint32(txh, tx.lock_time) if tx.overwintered: write_uint32(txh, tx.expiry) ofs = 0 while ofs < tx.extra_data_len: size = min(1024, tx.extra_data_len - ofs) data = await request_tx_extra_data(tx_req, ofs, size, prev_hash) write_bytes(txh, data) ofs += len(data) if get_tx_hash(txh, double=coin.sign_hash_double, reverse=True) != prev_hash: raise SigningError(FailureType.ProcessError, "Encountered invalid prev_hash") return total_out
def digest(self) -> bytes: """ Returns `T.2: transparent_digest` field for txid computation. see: https://zips.z.cash/zip-0244#t-2-transparent-digest """ h = HashWriter(blake2b(outlen=32, personal=b"ZTxIdTranspaHash")) if not self.empty: write_hash(h, self.prevouts.get_digest()) # T.2a write_hash(h, self.sequence.get_digest()) # T.2b write_hash(h, self.outputs.get_digest()) # T.2c return h.get_digest()
def txid_digest(self) -> bytes: """ Returns the transaction identifier. see: https://zips.z.cash/zip-0244#id4 """ h = HashWriter(blake2b(outlen=32, personal=self.tx_hash_person)) write_hash(h, self.header.digest()) # T.1 write_hash(h, self.transparent.digest()) # T.2 write_hash(h, self.sapling.digest()) # T.3 write_hash(h, self.orchard.digest()) # T.4 return h.get_digest()