def gen_transaction_prefix(self): """ Returns test transaction prefix :return: """ vin = [ TxinToKey(amount=123, key_offsets=[1, 2, 3, 2**76], k_image=bytearray(range(32))), TxinToKey(amount=456, key_offsets=[9, 8, 7, 6], k_image=bytearray(range(32, 64))), TxinGen(height=99), ] vout = [ TxOut(amount=11, target=TxoutToKey(key=bytearray(range(32)))), TxOut(amount=34, target=TxoutToKey(key=bytearray(range(64, 96)))), ] msg = TransactionPrefix(version=2, unlock_time=10, vin=vin, vout=vout, extra=list(range(31))) return msg
def test_txin_to_key(self): """ TxinToKey :return: """ msg = TxinToKey(amount=123, key_offsets=[1, 2, 3, 2**76], k_image=bytearray(range(32))) writer = MemoryReaderWriter() TxinToKey.dump(writer, msg) test_deser = TxinToKey.load(MemoryReaderWriter(writer.get_buffer())) self.assertEqual(msg.amount, test_deser.amount) self.assertEqual(msg, test_deser)
def test_txin_variant(self): """ TxInV :return: """ msg1 = TxinToKey(amount=123, key_offsets=[1, 2, 3, 2**76], k_image=bytearray(range(32))) writer = MemoryReaderWriter() TxInV.dump(writer, msg1) test_deser = TxInV.load(MemoryReaderWriter(writer.get_buffer())) self.assertEqual(test_deser.__class__, TxinToKey) self.assertEqual(msg1, test_deser)
async def set_input( state: State, src_entr: MoneroTransactionSourceEntry ) -> MoneroTransactionSetInputAck: from trezor.messages import MoneroTransactionSetInputAck from apps.monero.xmr.crypto import chacha_poly from apps.monero.xmr.serialize_messages.tx_prefix import TxinToKey from apps.monero.signing import offloading_keys state.current_input_index += 1 await layout.transaction_step(state, state.STEP_INP, state.current_input_index) if state.last_step > state.STEP_INP: raise ValueError("Invalid state transition") if state.current_input_index >= state.input_count: raise ValueError("Too many inputs") # real_output denotes which output in outputs is the real one (ours) if src_entr.real_output >= len(src_entr.outputs): raise ValueError( f"real_output index {src_entr.real_output} bigger than output_keys.size() {len(src_entr.outputs)}" ) state.summary_inputs_money += src_entr.amount # Secrets derivation # the UTXO's one-time address P out_key = crypto.decodepoint( src_entr.outputs[src_entr.real_output].key.dest) # the tx_pub of our UTXO stored inside its transaction tx_key = crypto.decodepoint(src_entr.real_out_tx_key) additional_tx_pub_key = _get_additional_public_key(src_entr) # Calculates `derivation = Ra`, private spend key `x = H(Ra||i) + b` to be able # to spend the UTXO; and key image `I = x*H(P||i)` xi, ki, _di = monero.generate_tx_spend_and_key_image_and_derivation( state.creds, state.subaddresses, out_key, tx_key, additional_tx_pub_key, src_entr.real_output_in_tx_index, state.account_idx, src_entr.subaddr_minor, ) state.mem_trace(1, True) # Construct tx.vin # If multisig is used then ki in vini should be src_entr.multisig_kLRki.ki vini = TxinToKey(amount=src_entr.amount, k_image=crypto.encodepoint(ki)) vini.key_offsets = _absolute_output_offsets_to_relative( [x.idx for x in src_entr.outputs]) if src_entr.rct: vini.amount = 0 # Serialize `vini` with variant code for TxinToKey (prefix = TxinToKey.VARIANT_CODE). # The binary `vini_bin` is later sent to step 4 and 9 with its hmac, # where it is checked and directly used. vini_bin = serialize.dump_msg(vini, preallocate=64, prefix=b"\x02") state.mem_trace(2, True) # HMAC(T_in,i || vin_i) hmac_vini = offloading_keys.gen_hmac_vini(state.key_hmac, src_entr, vini_bin, state.current_input_index) state.mem_trace(3, True) # PseudoOuts commitment, alphas stored to state alpha, pseudo_out = _gen_commitment(state, src_entr.amount) pseudo_out = crypto.encodepoint(pseudo_out) # The alpha is encrypted and passed back for storage pseudo_out_hmac = crypto.compute_hmac( offloading_keys.hmac_key_txin_comm(state.key_hmac, state.current_input_index), pseudo_out, ) alpha_enc = chacha_poly.encrypt_pack( offloading_keys.enc_key_txin_alpha(state.key_enc, state.current_input_index), crypto.encodeint(alpha), ) spend_enc = chacha_poly.encrypt_pack( offloading_keys.enc_key_spend(state.key_enc, state.current_input_index), crypto.encodeint(xi), ) state.last_step = state.STEP_INP if state.current_input_index + 1 == state.input_count: # When we finish the inputs processing, we no longer need # the precomputed subaddresses so we clear them to save memory. state.subaddresses = None state.input_last_amount = src_entr.amount return MoneroTransactionSetInputAck( vini=vini_bin, vini_hmac=hmac_vini, pseudo_out=pseudo_out, pseudo_out_hmac=pseudo_out_hmac, pseudo_out_alpha=alpha_enc, spend_key=spend_enc, )