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)
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 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 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 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 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()
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 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()
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")
def get_tx_hash(w: HashWriter, double: bool = False, reverse: bool = False) -> bytes: d = w.get_digest() if double: d = sha256(d).digest() if reverse: d = bytes(reversed(d)) return d
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()
class TxInfoBase: def __init__(self, signer: Signer) -> None: # Checksum of multisig inputs, used to validate change-output. self.multisig_fingerprint = MultisigFingerprintChecker() # Common prefix of input paths, used to validate change-output. self.wallet_path = WalletPathChecker() # h_tx_check is used to make sure that the inputs and outputs streamed in # different steps are the same every time, e.g. the ones streamed for approval # in Steps 1 and 2 and the ones streamed for signing legacy inputs in Step 4. self.h_tx_check = HashWriter(sha256()) # not a real tx hash # BIP-0143 transaction hashing. self.hash143 = signer.create_hash143() # The minimum nSequence of all inputs. self.min_sequence = _SEQUENCE_FINAL def add_input(self, txi: TxInput) -> None: self.hash143.add_input( txi) # all inputs are included (non-segwit as well) writers.write_tx_input_check(self.h_tx_check, txi) self.min_sequence = min(self.min_sequence, txi.sequence) if not input_is_external(txi): self.wallet_path.add_input(txi) self.multisig_fingerprint.add_input(txi) def add_output(self, txo: TxOutput, script_pubkey: bytes) -> None: self.hash143.add_output(txo, script_pubkey) writers.write_tx_output(self.h_tx_check, txo, script_pubkey) def check_input(self, txi: TxInput) -> None: self.wallet_path.check_input(txi) self.multisig_fingerprint.check_input(txi) def output_is_change(self, txo: TxOutput) -> bool: if txo.script_type not in common.CHANGE_OUTPUT_SCRIPT_TYPES: return False if txo.multisig and not self.multisig_fingerprint.output_matches(txo): return False return (self.wallet_path.output_matches(txo) and len(txo.address_n) >= BIP32_WALLET_DEPTH and txo.address_n[-2] <= _BIP32_CHANGE_CHAIN and txo.address_n[-1] <= _BIP32_MAX_LAST_ELEMENT and txo.amount > 0) def lock_time_disabled(self) -> bool: return self.min_sequence == _SEQUENCE_FINAL def rbf_disabled(self) -> bool: return self.min_sequence > _MAX_BIP125_RBF_SEQUENCE def get_tx_check_digest(self) -> bytes: return self.h_tx_check.get_digest()
def message_digest(coin, message): 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 generate_proof( node: bip32.HDNode, script_type: InputScriptType, multisig: MultisigRedeemScriptType | None, coin: CoinInfo, user_confirmed: bool, ownership_ids: list[bytes], script_pubkey: bytes, commitment_data: bytes, ) -> tuple[bytes, bytes]: flags = 0 if user_confirmed: flags |= _FLAG_USER_CONFIRMED proof = utils.empty_bytearray(4 + 1 + 1 + len(ownership_ids) * _OWNERSHIP_ID_LEN) write_bytes_fixed(proof, _VERSION_MAGIC, 4) write_uint8(proof, flags) write_bitcoin_varint(proof, len(ownership_ids)) for ownership_id in ownership_ids: write_bytes_fixed(proof, ownership_id, _OWNERSHIP_ID_LEN) sighash = HashWriter(sha256(proof)) write_bytes_prefixed(sighash, script_pubkey) write_bytes_prefixed(sighash, commitment_data) if script_type in ( InputScriptType.SPENDADDRESS, InputScriptType.SPENDMULTISIG, InputScriptType.SPENDWITNESS, InputScriptType.SPENDP2SHWITNESS, ): signature = common.ecdsa_sign(node, sighash.get_digest()) elif script_type == InputScriptType.SPENDTAPROOT: signature = common.bip340_sign(node, sighash.get_digest()) else: raise wire.DataError("Unsupported script type.") public_key = node.public_key() write_bip322_signature_proof(proof, script_type, multisig, coin, public_key, signature) return proof, signature
def message_digest(coin: CoinType, message: bytes) -> bytes: 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 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)
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')
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()
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()
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 __init__(self, tx: SignTx | PrevTx): h = HashWriter(blake2b(outlen=32, personal=b"ZTxIdHeadersHash")) assert tx.version_group_id is not None assert tx.branch_id is not None # checked in sanitize_* assert tx.expiry is not None write_uint32(h, tx.version | (1 << 31)) # T.1a write_uint32(h, tx.version_group_id) # T.1b write_uint32(h, tx.branch_id) # T.1c write_uint32(h, tx.lock_time) # T.1d write_uint32(h, tx.expiry) # T.1e self._digest = h.get_digest()
async def sign_tx(ctx, msg, keychain): await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE) address_bytes = recipient = address.bytes_from_address(msg.to) value = int.from_bytes(msg.value, "big") 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, msg.tx_type) 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)) sha.extend(rlp.encode_length(total_length, True)) # total length if msg.tx_type is not None: sha.extend(rlp.encode(msg.tx_type)) for field in (msg.nonce, msg.gas_price, msg.gas_limit, address_bytes, 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() result = sign_digest(msg, keychain, digest) return result
def signature_digest( self, txi: TxInput | None, script_pubkey: bytes | None ) -> bytes: """ Returns the transaction signature digest. see: https://zips.z.cash/zip-0244#id13 """ h = HashWriter(blake2b(outlen=32, personal=self.tx_hash_person)) write_hash(h, self.header.digest()) # S.1 write_hash(h, self.transparent.sig_digest(txi, script_pubkey)) # S.2 write_hash(h, self.sapling.digest()) # S.3 write_hash(h, self.orchard.digest()) # S.4 return h.get_digest()
def verify_nonownership( proof: bytes, script_pubkey: bytes, commitment_data: bytes | None, keychain: Keychain, coin: CoinInfo, ) -> bool: try: r = utils.BufferReader(proof) if r.read_memoryview(4) != _VERSION_MAGIC: raise wire.DataError("Unknown format of proof of ownership") flags = r.get() if flags & 0b1111_1110: raise wire.DataError("Unknown flags in proof of ownership") # Determine whether our ownership ID appears in the proof. id_count = read_bitcoin_varint(r) ownership_id = get_identifier(script_pubkey, keychain) not_owned = True for _ in range(id_count): if utils.consteq(ownership_id, r.read_memoryview(_OWNERSHIP_ID_LEN)): not_owned = False # Verify the BIP-322 SignatureProof. proof_body = memoryview(proof)[:r.offset] if commitment_data is None: commitment_data = bytes() sighash = HashWriter(sha256(proof_body)) write_bytes_prefixed(sighash, script_pubkey) write_bytes_prefixed(sighash, commitment_data) script_sig, witness = read_bip322_signature_proof(r) # We don't call verifier.ensure_hash_type() to avoid possible compatibility # issues between implementations, because the hash type doesn't influence # the digest and the value to use is not defined in BIP-322. verifier = SignatureVerifier(script_pubkey, script_sig, witness, coin) verifier.verify(sighash.get_digest()) except (ValueError, EOFError): raise wire.DataError("Invalid proof of ownership") return not_owned
async def sign_tx(ctx: wire.Context, msg: EosSignTx, keychain: Keychain) -> EosSignedTx: if not msg.num_actions: raise wire.DataError("No actions") await paths.validate_path(ctx, keychain, msg.address_n) node = keychain.derive(msg.address_n) sha = HashWriter(sha256()) await _init(ctx, sha, msg) await _actions(ctx, sha, msg.num_actions) writers.write_uvarint(sha, 0) writers.write_bytes_fixed(sha, bytearray(32), 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))
class DecredPrefixHasher: """ While Decred does not have the exact same implementation as bip143/zip143, the semantics for using the prefix hash of transactions are close enough that a pseudo-bip143 class can be used to store the prefix hash during the check_fee stage of transaction signature to then reuse it at the sign_tx stage without having to request the inputs again. """ def __init__(self, tx: SignTx): self.h_prefix = HashWriter(blake256()) self.last_output_bytes = None write_uint32(self.h_prefix, tx.version | DECRED_SERIALIZE_NO_WITNESS) write_varint(self.h_prefix, tx.inputs_count) def add_prevouts(self, txi: TxInputType): write_tx_input_decred(self.h_prefix, txi) def add_sequence(self, txi: TxInputType): pass def add_output_count(self, tx: SignTx): write_varint(self.h_prefix, tx.outputs_count) def add_output(self, txo_bin: TxOutputBinType): write_tx_output(self.h_prefix, txo_bin) def set_last_output_bytes(self, w_txo_bin: bytearray): """ This is required because the last serialized output obtained in `check_fee` will only be sent to the client in `sign_tx` """ self.last_output_bytes = w_txo_bin def get_last_output_bytes(self): return self.last_output_bytes def add_locktime_expiry(self, tx: SignTx): write_uint32(self.h_prefix, tx.lock_time) write_uint32(self.h_prefix, tx.expiry) def prefix_hash(self) -> bytes: return self.h_prefix.get_digest()
async def sign_tx(ctx, msg): pubkey, seckey = await _get_keys(ctx, msg) transaction = _update_raw_tx(msg.transaction, pubkey) try: await _require_confirm_by_type(ctx, transaction) except AttributeError: raise wire.DataError("The transaction has invalid asset data field") await layout.require_confirm_fee(ctx, transaction.amount, transaction.fee) txbytes = _get_transaction_bytes(transaction) txhash = HashWriter(sha256()) for field in txbytes: txhash.extend(field) digest = txhash.get_digest() signature = ed25519.sign(seckey, digest) return LiskSignedTx(signature=signature)
def _txin_sig_digest( txi: TxInput | None, script_pubkey: bytes | None, ) -> bytes: """ Returns `S.2g: txin_sig_digest` field for signature digest computation. see: https://zips.z.cash/zip-0244#s-2g-txin-sig-digest """ h = HashWriter(blake2b(outlen=32, personal=b"Zcash___TxInHash")) if txi is not None: assert script_pubkey is not None write_prevout(h, txi) # 2.Sg.i write_uint64(h, txi.amount) # 2.Sg.ii write_bytes_prefixed(h, script_pubkey) # 2.Sg.iii write_uint32(h, txi.sequence) # 2.Sg.iv return h.get_digest()