async def _init_step(s: LiveRefreshState, ctx, msg: MoneroLiveRefreshStartRequest, keychain): await paths.validate_path(ctx, misc.validate_full_path, path=msg.address_n) await confirms.require_confirm_live_refresh(ctx) s.creds = misc.get_creds(keychain, msg.address_n, msg.network_type) return MoneroLiveRefreshStartAck()
async def get_watch_only(ctx, msg: MoneroGetWatchKey, keychain): await paths.validate_path(ctx, keychain, msg.address_n) await confirms.require_confirm_watchkey(ctx) creds = misc.get_creds(keychain, msg.address_n, msg.network_type) address = creds.address watch_key = crypto.encodeint(creds.view_key_private) return MoneroWatchKey(watch_key=watch_key, address=address)
async def _init_step(s: LiveRefreshState, ctx, msg: MoneroLiveRefreshStartRequest, keychain): await paths.validate_path(ctx, keychain, msg.address_n) if not storage.cache.get(storage.cache.APP_MONERO_LIVE_REFRESH): await confirms.require_confirm_live_refresh(ctx) storage.cache.set(storage.cache.APP_MONERO_LIVE_REFRESH, b"\x01") s.creds = misc.get_creds(keychain, msg.address_n, msg.network_type) return MoneroLiveRefreshStartAck()
async def get_watch_only( ctx: Context, msg: MoneroGetWatchKey, keychain: Keychain ) -> MoneroWatchKey: await paths.validate_path(ctx, keychain, msg.address_n) await layout.require_confirm_watchkey(ctx) creds = misc.get_creds(keychain, msg.address_n, msg.network_type) address = creds.address watch_key = crypto_helpers.encodeint(creds.view_key_private) return MoneroWatchKey(watch_key=watch_key, address=address.encode())
async def _init_step(s: LiveRefreshState, ctx, msg: MoneroLiveRefreshStartRequest, keychain): await paths.validate_path(ctx, misc.validate_full_path, keychain, msg.address_n, CURVE) passphrase_fprint = get_passphrase_fprint() if live_refresh_token() != passphrase_fprint: await confirms.require_confirm_live_refresh(ctx) live_refresh_token(passphrase_fprint) s.creds = misc.get_creds(keychain, msg.address_n, msg.network_type) return MoneroLiveRefreshStartAck()
async def get_address(ctx: wire.Context, msg: MoneroGetAddress, keychain: Keychain) -> MoneroAddress: await paths.validate_path(ctx, keychain, msg.address_n) creds = misc.get_creds(keychain, msg.address_n, msg.network_type) addr = creds.address have_subaddress = msg.account is not None and msg.minor is not None have_payment_id = msg.payment_id is not None if (msg.account is None) != (msg.minor is None): raise wire.ProcessError("Invalid subaddress indexes") if have_payment_id and have_subaddress: raise wire.DataError("Subaddress cannot be integrated") if have_payment_id: assert msg.payment_id is not None if len(msg.payment_id) != 8: raise ValueError("Invalid payment ID length") addr = addresses.encode_addr( net_version(msg.network_type, False, True), crypto_helpers.encodepoint(creds.spend_key_public), crypto_helpers.encodepoint(creds.view_key_public), msg.payment_id, ) if have_subaddress: assert msg.account is not None assert msg.minor is not None pub_spend, pub_view = monero.generate_sub_address_keys( creds.view_key_private, creds.spend_key_public, msg.account, msg.minor) addr = addresses.encode_addr( net_version(msg.network_type, True, False), crypto_helpers.encodepoint(pub_spend), crypto_helpers.encodepoint(pub_view), ) if msg.show_display: title = paths.address_n_to_str(msg.address_n) await show_address( ctx, address=addr, address_qr="monero:" + addr, title=title, ) return MoneroAddress(address=addr.encode())
async def get_address(ctx, msg, keychain): await paths.validate_path(ctx, misc.validate_full_path, keychain, msg.address_n) creds = misc.get_creds(keychain, msg.address_n, msg.network_type) if msg.show_display: desc = address_n_to_str(msg.address_n) while True: if await show_address(ctx, creds.address.decode(), desc=desc): break if await show_qr(ctx, creds.address.decode(), desc=desc): break return MoneroAddress(address=creds.address)
async def get_tx_keys(ctx: wire.Context, msg: MoneroGetTxKeyRequest, keychain: Keychain) -> MoneroGetTxKeyAck: await paths.validate_path(ctx, keychain, msg.address_n) do_deriv = msg.reason == _GET_TX_KEY_REASON_TX_DERIVATION await layout.require_confirm_tx_key(ctx, export_key=not do_deriv) creds = misc.get_creds(keychain, msg.address_n, msg.network_type) tx_enc_key = misc.compute_tx_key( creds.spend_key_private, msg.tx_prefix_hash, msg.salt1, crypto_helpers.decodeint(msg.salt2), ) # the plain_buff first stores the tx_priv_keys as decrypted here # and then is used to store the derivations if applicable plain_buff = chacha_poly.decrypt_pack(tx_enc_key, msg.tx_enc_keys) utils.ensure(len(plain_buff) % 32 == 0, "Tx key buffer has invalid size") msg.tx_enc_keys = b"" # If return only derivations do tx_priv * view_pub if do_deriv: if msg.view_public_key is None: raise wire.DataError("Missing view public key") plain_buff = bytearray(plain_buff) view_pub = crypto_helpers.decodepoint(msg.view_public_key) tx_priv = crypto.Scalar() derivation = crypto.Point() n_keys = len(plain_buff) // 32 for c in range(n_keys): crypto.decodeint_into(tx_priv, plain_buff, 32 * c) crypto.scalarmult_into(derivation, view_pub, tx_priv) crypto.encodepoint_into(plain_buff, derivation, 32 * c) # Encrypt by view-key based password. tx_enc_key_host, salt = misc.compute_enc_key_host(creds.view_key_private, msg.tx_prefix_hash) res = chacha_poly.encrypt_pack(tx_enc_key_host, plain_buff) res_msg = MoneroGetTxKeyAck(salt=salt) if do_deriv: res_msg.tx_derivations = res return res_msg res_msg.tx_keys = res return res_msg
async def _init_step(s, ctx, msg, keychain): await paths.validate_path(ctx, misc.validate_full_path, path=msg.address_n) s.creds = misc.get_creds(keychain, msg.address_n, msg.network_type) await confirms.require_confirm_keyimage_sync(ctx) s.num_outputs = msg.num s.expected_hash = msg.hash s.enc_key = crypto.random_bytes(32) for sub in msg.subs: monero.compute_subaddresses(s.creds, sub.account, sub.minor_indices, s.subaddresses) return MoneroKeyImageExportInitAck()
async def get_address(ctx, msg, keychain): await paths.validate_path(ctx, keychain, msg.address_n) creds = misc.get_creds(keychain, msg.address_n, msg.network_type) addr = creds.address if msg.payment_id: if len(msg.payment_id) != 8: raise ValueError("Invalid payment ID length") addr = addresses.encode_addr( net_version(msg.network_type, False, True), crypto.encodepoint(creds.spend_key_public), crypto.encodepoint(creds.view_key_public), msg.payment_id, ) if msg.account or msg.minor: if msg.payment_id: raise ValueError("Subaddress cannot be integrated") pub_spend, pub_view = monero.generate_sub_address_keys( creds.view_key_private, creds.spend_key_public, msg.account, msg.minor) addr = addresses.encode_addr( net_version(msg.network_type, True, False), crypto.encodepoint(pub_spend), crypto.encodepoint(pub_view), ) if msg.show_display: title = paths.address_n_to_str(msg.address_n) await show_address( ctx, address=addr.decode(), address_qr="monero:" + addr.decode(), title=title, ) return MoneroAddress(address=addr)
async def init_transaction( state: State, address_n: list, network_type: int, tsx_data: MoneroTransactionData, keychain, ) -> MoneroTransactionInitAck: from apps.monero.signing import offloading_keys from apps.common import paths await paths.validate_path(state.ctx, misc.validate_full_path, keychain, address_n, CURVE) state.creds = misc.get_creds(keychain, address_n, network_type) state.client_version = tsx_data.client_version or 0 if state.client_version == 0: raise ValueError("Client version not supported") state.fee = state.fee if state.fee > 0 else 0 state.tx_priv = crypto.random_scalar() state.tx_pub = crypto.scalarmult_base(state.tx_priv) state.mem_trace(1) state.input_count = tsx_data.num_inputs state.output_count = len(tsx_data.outputs) state.progress_total = 4 + 3 * state.input_count + state.output_count state.progress_cur = 0 # Ask for confirmation await confirms.require_confirm_transaction(state.ctx, state, tsx_data, state.creds.network_type) state.creds.address = None state.creds.network_type = None gc.collect() state.mem_trace(3) # Basic transaction parameters state.output_change = tsx_data.change_dts state.mixin = tsx_data.mixin state.fee = tsx_data.fee state.account_idx = tsx_data.account state.last_step = state.STEP_INIT if tsx_data.hard_fork: state.hard_fork = tsx_data.hard_fork # Ensure change is correct _check_change(state, tsx_data.outputs) # At least two outpus are required, this applies also for sweep txs # where one fake output is added. See _check_change for more info if state.output_count < 2: raise signing.NotEnoughOutputsError( "At least two outputs are required") _check_rsig_data(state, tsx_data.rsig_data) _check_subaddresses(state, tsx_data.outputs) # Extra processing, payment id _process_payment_id(state, tsx_data) await _compute_sec_keys(state, tsx_data) gc.collect() # Iterative tx_prefix_hash hash computation state.tx_prefix_hasher.uvarint( 2) # current Monero transaction format (RingCT = 2) state.tx_prefix_hasher.uvarint(tsx_data.unlock_time) state.tx_prefix_hasher.uvarint(state.input_count) # ContainerType, size state.mem_trace(10, True) # Final message hasher state.full_message_hasher.init() state.full_message_hasher.set_type_fee(signing.RctType.Bulletproof2, state.fee) # Sub address precomputation if tsx_data.account is not None and tsx_data.minor_indices: _precompute_subaddr(state, tsx_data.account, tsx_data.minor_indices) state.mem_trace(5, True) # HMACs all outputs to disallow tampering. # Each HMAC is then sent alongside the output # and trezor validates it. hmacs = [] for idx in range(state.output_count): c_hmac = await offloading_keys.gen_hmac_tsxdest( state.key_hmac, tsx_data.outputs[idx], idx) hmacs.append(c_hmac) gc.collect() state.mem_trace(6) from trezor.messages.MoneroTransactionInitAck import MoneroTransactionInitAck from trezor.messages.MoneroTransactionRsigData import MoneroTransactionRsigData rsig_data = MoneroTransactionRsigData(offload_type=state.rsig_offload) return MoneroTransactionInitAck(hmacs=hmacs, rsig_data=rsig_data)