def _compute_tx_keys( state: State, dst_entr: MoneroTransactionDestinationEntry ) -> Tuple[Ge25519, Sc25519]: """Computes tx_out_key, amount_key""" if state.is_processing_offloaded: return None, None # no need to recompute # additional tx key if applicable additional_txkey_priv = _set_out_additional_keys(state, dst_entr) # derivation = a*R or r*A or s*C derivation = _set_out_derivation(state, dst_entr, additional_txkey_priv) # amount key = H_s(derivation || i) amount_key = crypto.derivation_to_scalar(derivation, state.current_output_index) # one-time destination address P = H_s(derivation || i)*G + B tx_out_key = crypto.derive_public_key( derivation, state.current_output_index, crypto.decodepoint(dst_entr.addr.spend_public_key), ) del (derivation, additional_txkey_priv) from apps.monero.xmr import monero mask = monero.commitment_mask(crypto.encodeint(amount_key)) state.output_masks.append(mask) return tx_out_key, amount_key
def test_public_spend(self): derivation = unhexlify( b"e720a09f2e3a0bbf4e4ba7ad93653bb296885510121f806acb2a5f9168fafa01" ) base = unhexlify( b"7d996b0f2db6dbb5f2a086211f2399a4a7479b2c911af307fdc3f7f61a88cb0e" ) pkey_ex = unhexlify( b"0846cae7405077b6b7800f0b932c10a186448370b6db318f8c9e13f781dab546" ) pkey_comp = crypto.derive_public_key(crypto.decodepoint(derivation), 0, crypto.decodepoint(base)) self.assertEqual(pkey_ex, crypto.encodepoint(pkey_comp))
def _compute_tx_keys(state: State, dst_entr): """Computes tx_out_key, amount_key""" if state.is_processing_offloaded: return None, None # no need to recompute # additional tx key if applicable additional_txkey_priv = _set_out_additional_keys(state, dst_entr) # derivation = a*R or r*A or s*C derivation = _set_out_derivation(state, dst_entr, additional_txkey_priv) # amount key = H_s(derivation || i) amount_key = crypto.derivation_to_scalar(derivation, state.current_output_index) # one-time destination address P = H_s(derivation || i)*G + B tx_out_key = crypto.derive_public_key( derivation, state.current_output_index, crypto.decodepoint(dst_entr.addr.spend_public_key), ) del (derivation, additional_txkey_priv) # Computes the newest mask if applicable if state.is_det_mask(): from apps.monero.xmr import monero mask = monero.commitment_mask(crypto.encodeint(amount_key)) elif state.current_output_index + 1 < state.output_count: mask = offloading_keys.det_comm_masks(state.key_enc, state.current_output_index) else: mask = state.output_last_mask state.output_last_mask = None state.output_masks.append(mask) return tx_out_key, amount_key
async def set_output(state: State, dst_entr, dst_entr_hmac, rsig_data): state.mem_trace(0, True) mods = utils.unimport_begin() await confirms.transaction_step(state.ctx, state.STEP_OUT, state.current_output_index + 1, state.output_count) state.mem_trace(1) state.current_output_index += 1 state.mem_trace(2, True) await _validate(state, dst_entr, dst_entr_hmac) # First output - we include the size of the container into the tx prefix hasher if state.current_output_index == 0: state.tx_prefix_hasher.uvarint(state.output_count) state.mem_trace(4, True) state.output_amounts.append(dst_entr.amount) state.summary_outs_money += dst_entr.amount utils.unimport_end(mods) state.mem_trace(5, True) # Range proof first, memory intensive rsig, mask = _range_proof(state, dst_entr.amount, rsig_data) utils.unimport_end(mods) state.mem_trace(6, True) # additional tx key if applicable additional_txkey_priv = _set_out_additional_keys(state, dst_entr) # derivation = a*R or r*A or s*C derivation = _set_out_derivation(state, dst_entr, additional_txkey_priv) # amount key = H_s(derivation || i) amount_key = crypto.derivation_to_scalar(derivation, state.current_output_index) # one-time destination address P = H_s(derivation || i)*G + B tx_out_key = crypto.derive_public_key( derivation, state.current_output_index, crypto.decodepoint(dst_entr.addr.spend_public_key), ) del (derivation, additional_txkey_priv) state.mem_trace(7, True) # Tx header prefix hashing, hmac dst_entr tx_out_bin, hmac_vouti = await _set_out_tx_out(state, dst_entr, tx_out_key) state.mem_trace(11, True) out_pk_dest, out_pk_commitment, ecdh_info_bin = _get_ecdh_info_and_out_pk( state=state, tx_out_key=tx_out_key, amount=dst_entr.amount, mask=mask, amount_key=amount_key, ) del (dst_entr, mask, amount_key, tx_out_key) state.mem_trace(12, True) # Incremental hashing of the ECDH info. # RctSigBase allows to hash only one of the (ecdh, out_pk) as they are serialized # as whole vectors. We choose to hash ECDH first, because it saves state space. state.full_message_hasher.set_ecdh(ecdh_info_bin) state.mem_trace(13, True) # output_pk_commitment is stored to the state as it is used during the signature and hashed to the # RctSigBase later. No need to store amount, it was already stored. state.output_pk_commitments.append(out_pk_commitment) state.mem_trace(14, True) from trezor.messages.MoneroTransactionSetOutputAck import ( MoneroTransactionSetOutputAck, ) out_pk_bin = bytearray(64) utils.memcpy(out_pk_bin, 0, out_pk_dest, 0, 32) utils.memcpy(out_pk_bin, 32, out_pk_commitment, 0, 32) return MoneroTransactionSetOutputAck( tx_out=tx_out_bin, vouti_hmac=hmac_vouti, rsig_data=_return_rsig_data(rsig), out_pk=out_pk_bin, ecdh_info=ecdh_info_bin, )