""" Final message, signatures were already returned in the previous step. Here we return private tx keys in encrypted form using transaction specific key, derived from tx hash and the private spend key. The key is deterministic, so we can recover it just from the transaction and the spend key. The private tx keys are used in other numerous Monero features. """ from trezor.messages.MoneroTransactionFinalAck import MoneroTransactionFinalAck from apps.monero import misc from apps.monero.xmr import crypto from apps.monero.xmr.crypto import chacha_poly from .state import State if False: from typing import Tuple from apps.monero.xmr.types import Sc25519 async def final_msg(state: State) -> MoneroTransactionFinalAck: if state.last_step != state.STEP_SIGN: raise ValueError("Invalid state transition") if state.current_input_index != state.input_count - 1: raise ValueError("Invalid input count") tx_key, salt, rand_mult = _compute_tx_key( state.creds.spend_key_private, state.tx_prefix_hash ) key_buff = crypto.encodeint(state.tx_priv) + b"".join( [crypto.encodeint(x) for x in state.additional_tx_private_keys] ) tx_enc_keys = chacha_poly.encrypt_pack(tx_key, key_buff) state.last_step = None return MoneroTransactionFinalAck( cout_key=None, salt=salt, rand_mult=rand_mult, tx_enc_keys=tx_enc_keys, opening_key=state.opening_key, ) def _compute_tx_key( spend_key_private: Sc25519, tx_prefix_hash: bytes ) -> Tuple[bytes, bytes, bytes]: salt = crypto.random_bytes(32) rand_mult_num = crypto.random_scalar() rand_mult = crypto.encodeint(rand_mult_num) tx_key = misc.compute_tx_key(spend_key_private, tx_prefix_hash, salt, rand_mult_num) return tx_key, salt, rand_mult