def _check_rsig_data(state: State, rsig_data: MoneroTransactionRsigData) -> None: """ There are two types of monero ring confidential transactions: 1. RCTTypeFull = 1 (used if num_inputs == 1 && Borromean) 2. RCTTypeSimple = 2 (for num_inputs > 1 || !Borromean) and four types of range proofs (set in `rsig_data.rsig_type`): 1. RangeProofBorromean = 0 2. RangeProofBulletproof = 1 3. RangeProofMultiOutputBulletproof = 2 4. RangeProofPaddedBulletproof = 3 The current code supports only HF9, HF10 thus TX type is always simple and RCT algorithm is always Bulletproof. """ state.rsig_grouping = rsig_data.grouping if rsig_data.rsig_type == 0: raise ValueError("Borromean range sig not supported") elif rsig_data.rsig_type not in (1, 2, 3): raise ValueError("Unknown rsig type") state.tx_type = signing.RctType.CLSAG if rsig_data.bp_version == 4: state.rsig_is_bp_plus = True state.tx_type = signing.RctType.RCTTypeBulletproofPlus if state.output_count > 2: state.rsig_offload = True _check_grouping(state)
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 state.tx_type = (signing.RctType.CLSAG if state.hard_fork >= 13 else signing.RctType.Bulletproof2) # 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) _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(state.tx_type, 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 = 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)