async def final_msg(self, *args, **kwargs): """ Final step after transaction signing. :param args: :param kwargs: :return: """ from monero_glue.messages.MoneroTransactionFinalAck import ( MoneroTransactionFinalAck ) from monero_glue.xmr.enc import chacha_poly self.state.set_final() cout_key = self.enc_key_cout() if self.multi_sig else None # Encrypted tx keys under transaction specific key, derived from txhash and spend key. # Deterministic transaction key, so we can recover it just from transaction and the spend key. tx_key, salt, rand_mult = misc.compute_tx_key( self.creds.spend_key_private, self.tx_prefix_hash ) key_buff = crypto.encodeint(self.r) + b"".join( [crypto.encodeint(x) for x in self.additional_tx_private_keys] ) tx_enc_keys = chacha_poly.encrypt_pack(tx_key, key_buff) await self.trezor.iface.transaction_finished() gc.collect() return MoneroTransactionFinalAck( cout_key=cout_key, salt=salt, rand_mult=rand_mult, tx_enc_keys=tx_enc_keys )
async def state_save(self): try: s = self.tsx_obj.state_save() self.tsx_obj = None finally: gc.collect() return s
async def dispatch(self, ctx, ins, p1, p2, input): """ Main message dispatcher :param ctx: :param ins: :param p1: :param p2: :param input: :return: """ self.c_p1 = p1 self.c_p2 = p2 self.c_msg = input self.c_offset = 0 self.r_len = 0 from apps.monero.controller import iface self.ctx = ctx self.iface = iface.get_iface(ctx) sw = 0x6F01 try: log.debug(__name__, "Ins: %s, %s %s", ins, p1, p2) sw = await self._sub_dispatch(ins, p1) except Exception as e: log.error(__name__, "Exception dispatching: %s", e) raise gc.collect() return sw, self.r_msg[:self.r_len]
async def state_save(self): try: s = self.tsx_obj.state_save() self.tsx_obj = None finally: gc.collect() self._log_trace("State saved") return s
async def dump_msg_gc(msg, preallocate=None, msg_type=None, del_msg=False): b = await dump_msg(msg, preallocate=preallocate, msg_type=msg_type) if del_msg: del msg import gc gc.collect() return b
async def prove_range_bp_batch(amounts, masks): from monero_glue.xmr import bulletproof as bp bpi = bp.BulletProofBuilder() bp_proof = bpi.prove_batch([crypto.sc_init(a) for a in amounts], masks) del (bpi, bp) gc.collect() return bp_proof
async def sign(self, ctx, state, msg, iface=None): """ Main multiplex point :param ctx: :param state: :param msg: :param iface: :return: """ from apps.monero.controller import iface as mod_iface self.ctx = ctx self.iface = mod_iface.get_iface(ctx) if not iface else iface gc.collect() log.debug(__name__, "sign()") log.debug( __name__, "Mem Free: {} Allocated: {}".format(gc.mem_free(), gc.mem_alloc())) if msg.init: log.debug(__name__, "setup") await self.setup(msg.init) await self.restore(state if not msg.init else None) if msg.init: log.debug(__name__, "sign_init") return await self.tsx_init(msg.init.tsx_data) elif msg.set_input: log.debug(__name__, "sign_inp") return await self.tsx_set_input(msg.set_input) elif msg.input_permutation: log.debug(__name__, "sign_perm") return await self.tsx_inputs_permutation(msg.input_permutation) elif msg.input_vini: log.debug(__name__, "sign_vin") return await self.tsx_input_vini(msg.input_vini) elif msg.set_output: log.debug(__name__, "sign_out") return await self.tsx_set_output1(msg.set_output) elif msg.all_out_set: log.debug(__name__, "sign_out_set") return await self.tsx_all_out1_set(msg.all_out_set) elif msg.mlsag_done: log.debug(__name__, "sign_done") return await self.tsx_mlsag_done() elif msg.sign_input: log.debug(__name__, "sign_sinp") return await self.tsx_sign_input(msg.sign_input) elif msg.final_msg: log.debug(__name__, "sign_final") return await self.tsx_sign_final(msg.final_msg) else: raise ValueError("Unknown message")
def _log_trace(self, x=None, collect=False): log.debug( __name__, "Log trace %s, ... F: %s A: %s, S: %s", x, gc.mem_free(), gc.mem_alloc(), micropython.stack_use(), ) if collect: gc.collect()
async def prove_range_bp(amount, last_mask=None): mask = last_mask if last_mask is not None else crypto.random_scalar() bp_proof = await prove_range_bp_batch([amount], [mask]) C = crypto.decodepoint(bp_proof.V[0]) C = crypto.point_mul8(C) gc.collect() # Return as struct as the hash(BP_struct) != hash(BP_serialized) # as the original hashing does not take vector lengths into account which are dynamic # in the serialization scheme (and thus extraneous) return C, mask, bp_proof
async def verify_bp(bp_proof, amounts=None, masks=None): from monero_glue.xmr import bulletproof as bp if amounts: bp_proof.V = [] for i in range(len(amounts)): C = crypto.gen_c(masks[i], amounts[i]) crypto.scalarmult_into(C, C, crypto.sc_inv_eight()) bp_proof.V.append(crypto.encodepoint(C)) bpi = bp.BulletProofBuilder() res = bpi.verify(bp_proof) gc.collect() # Return as struct as the hash(BP_struct) != hash(BP_serialized) # as the original hashing does not take vector lengths into account which are dynamic # in the serialization scheme (and thus extraneous) return res
async def wake_up(self, ctx, state, msg, iface=None): """ Restore from the stored state :param state: :return: """ from apps.monero.controller import iface as mod_iface self.ctx = ctx self.iface = mod_iface.get_iface(ctx) if not iface else iface gc.collect() self._log_trace("wake_up()", True) if msg.MESSAGE_WIRE_TYPE == MessageType.MoneroTransactionInitRequest: self._log_trace("init") await self.setup(msg) await self.restore(state if msg.MESSAGE_WIRE_TYPE != MessageType. MoneroTransactionInitRequest else None) self._log_trace("wake_up() end", True)
async def sign_input( self, src_entr, vini, hmac_vini, pseudo_out, pseudo_out_hmac, alpha_enc, spend_enc, ): """ Generates a signature for one input. :param src_entr: Source entry :type src_entr: monero_glue.xmr.serialize_messages.tx_construct.TxSourceEntry :param vini: tx.vin[i] for the transaction. Contains key image, offsets, amount (usually zero) :param hmac_vini: HMAC for the tx.vin[i] as returned from Trezor :param pseudo_out: pedersen commitment for the current input, uses alpha as the mask. Only in memory offloaded scenario. Tuple containing HMAC, as returned from the Trezor. :param pseudo_out_hmac: :param alpha_enc: alpha mask for the current input. Only in memory offloaded scenario, tuple as returned from the Trezor :param spend_enc: :return: Generated signature MGs[i] """ self.state.set_signature() await self.trezor.iface.transaction_step( self.STEP_SIGN, self.inp_idx + 1, self.num_inputs() ) self.inp_idx += 1 if self.inp_idx >= self.num_inputs(): raise ValueError("Invalid ins") if self.use_simple_rct and (not self.in_memory() and alpha_enc is None): raise ValueError("Inconsistent1") if self.use_simple_rct and (not self.in_memory() and pseudo_out is None): raise ValueError("Inconsistent2") if self.inp_idx >= 1 and not self.use_simple_rct: raise ValueError("Inconsistent3") inv_idx = self.source_permutation[self.inp_idx] # Check HMAC of all inputs hmac_vini_comp = await self.gen_hmac_vini(src_entr, vini, inv_idx) if not common.ct_equal(hmac_vini_comp, hmac_vini): raise ValueError("HMAC is not correct") gc.collect() self._log_trace(1) if self.use_simple_rct and not self.in_memory(): pseudo_out_hmac_comp = crypto.compute_hmac( self.hmac_key_txin_comm(inv_idx), pseudo_out ) if not common.ct_equal(pseudo_out_hmac_comp, pseudo_out_hmac): raise ValueError("HMAC is not correct") gc.collect() self._log_trace(2) from monero_glue.xmr.enc import chacha_poly alpha_c = crypto.decodeint( chacha_poly.decrypt_pack( self.enc_key_txin_alpha(inv_idx), bytes(alpha_enc) ) ) pseudo_out_c = crypto.decodepoint(pseudo_out) elif self.use_simple_rct: alpha_c = self.input_alphas[self.inp_idx] pseudo_out_c = crypto.decodepoint(self.input_pseudo_outs[self.inp_idx]) else: alpha_c = None pseudo_out_c = None # Spending secret if self.many_inputs(): from monero_glue.xmr.enc import chacha_poly input_secret = crypto.decodeint( chacha_poly.decrypt_pack(self.enc_key_spend(inv_idx), bytes(spend_enc)) ) else: input_secret = self.input_secrets[self.inp_idx] gc.collect() self._log_trace(3) # Basic setup, sanity check index = src_entr.real_output in_sk = misc.StdObj(dest=input_secret, mask=crypto.decodeint(src_entr.mask)) kLRki = src_entr.multisig_kLRki if self.multi_sig else None # Private key correctness test self.assrt( crypto.point_eq( crypto.decodepoint(src_entr.outputs[src_entr.real_output][1].dest), crypto.scalarmult_base(in_sk.dest), ), "a1", ) self.assrt( crypto.point_eq( crypto.decodepoint(src_entr.outputs[src_entr.real_output][1].mask), crypto.gen_c(in_sk.mask, src_entr.amount), ), "a2", ) gc.collect() self._log_trace(4) # RCT signature gc.collect() from monero_glue.xmr import mlsag2 mg = None if self.use_simple_rct: # Simple RingCT mix_ring = [x[1] for x in src_entr.outputs] mg, msc = mlsag2.prove_rct_mg_simple( self.full_message, mix_ring, in_sk, alpha_c, pseudo_out_c, kLRki, None, index, ) if __debug__: self.assrt( mlsag2.ver_rct_mg_simple( self.full_message, mg, mix_ring, pseudo_out_c ) ) else: # Full RingCt, only one input txn_fee_key = crypto.scalarmult_h(self.get_fee()) mix_ring = [[x[1]] for x in src_entr.outputs] mg, msc = mlsag2.prove_rct_mg( self.full_message, mix_ring, [in_sk], self.output_sk, self.output_pk, kLRki, None, index, txn_fee_key, ) if __debug__: self.assrt( mlsag2.ver_rct_mg( mg, mix_ring, self.output_pk, txn_fee_key, self.full_message ) ) gc.collect() self._log_trace(5) # Encode from monero_glue.xmr.sub.recode import recode_msg mgs = recode_msg([mg]) cout = None gc.collect() self._log_trace(6) # Multisig values returned encrypted, keys returned after finished successfully. if self.multi_sig: from monero_glue.xmr.enc import chacha_poly cout = chacha_poly.encrypt_pack(self.enc_key_cout(), crypto.encodeint(msc)) # Final state transition if self.inp_idx + 1 == self.num_inputs(): self.state.set_signature_done() await self.trezor.iface.transaction_signed() gc.collect() self._log_trace() from monero_glue.messages.MoneroTransactionSignInputAck import ( MoneroTransactionSignInputAck ) return MoneroTransactionSignInputAck( signature=await misc.dump_msg_gc(mgs[0], preallocate=488, del_msg=True), cout=cout, )
def prove_range_chunked(amount, last_mask=None): a = crypto.sc_init(0) si = crypto.sc_init(0) c = crypto.sc_init(0) ee = crypto.sc_init(0) tmp_ai = crypto.sc_init(0) tmp_alpha = crypto.sc_init(0) C_acc = crypto.identity() C_h = crypto.xmr_H() C_tmp = crypto.identity() L = crypto.identity() Zero = crypto.identity() kck = crypto.get_keccak() ai = bytearray(32 * 64) alphai = bytearray(32 * 64) buff = bytearray(32) Cis = bytearray(32 * 64) s0s = bytearray(32 * 64) s1s = bytearray(32 * 64) ee_bin = bytearray(32) for ii in range(64): crypto.random_scalar_into(tmp_ai) if last_mask is not None and ii == 63: crypto.sc_sub_into(tmp_ai, last_mask, a) crypto.sc_add_into(a, a, tmp_ai) crypto.random_scalar_into(tmp_alpha) crypto.scalarmult_base_into(L, tmp_alpha) crypto.scalarmult_base_into(C_tmp, tmp_ai) # C_tmp += &Zero if BB(ii) == 0 else &C_h crypto.point_add_into(C_tmp, C_tmp, Zero if ((amount >> ii) & 1) == 0 else C_h) crypto.point_add_into(C_acc, C_acc, C_tmp) # Set Ci[ii] to sigs crypto.encodepoint_into(Cis, C_tmp, ii << 5) crypto.encodeint_into(ai, tmp_ai, ii << 5) crypto.encodeint_into(alphai, tmp_alpha, ii << 5) if ((amount >> ii) & 1) == 0: crypto.random_scalar_into(si) crypto.encodepoint_into(buff, L) crypto.hash_to_scalar_into(c, buff) crypto.point_sub_into(C_tmp, C_tmp, C_h) crypto.add_keys2_into(L, si, c, C_tmp) crypto.encodeint_into(s1s, si, ii << 5) crypto.encodepoint_into(buff, L) kck.update(buff) crypto.point_double_into(C_h, C_h) # Compute ee tmp_ee = kck.digest() crypto.decodeint_into(ee, tmp_ee) del (tmp_ee, kck) C_h = crypto.xmr_H() gc.collect() # Second pass, s0, s1 for ii in range(64): crypto.decodeint_into(tmp_alpha, alphai, ii << 5) crypto.decodeint_into(tmp_ai, ai, ii << 5) if ((amount >> ii) & 1) == 0: crypto.sc_mulsub_into(si, tmp_ai, ee, tmp_alpha) crypto.encodeint_into(s0s, si, ii << 5) else: crypto.random_scalar_into(si) crypto.encodeint_into(s0s, si, ii << 5) crypto.decodepoint_into(C_tmp, Cis, ii << 5) crypto.add_keys2_into(L, si, ee, C_tmp) crypto.encodepoint_into(buff, L) crypto.hash_to_scalar_into(c, buff) crypto.sc_mulsub_into(si, tmp_ai, c, tmp_alpha) crypto.encodeint_into(s1s, si, ii << 5) crypto.point_double_into(C_h, C_h) crypto.encodeint_into(ee_bin, ee) del (ai, alphai, buff, tmp_ai, tmp_alpha, si, c, ee, C_tmp, C_h, L, Zero) gc.collect() return C_acc, a, [s0s, s1s, ee_bin, Cis]
async def range_proof(self, idx, dest_pub_key, amount, amount_key): """ Computes rangeproof and related information - out_sk, out_pk, ecdh_info. In order to optimize incremental transaction build, the mask computation is changed compared to the official Monero code. In the official code, the input pedersen commitments are computed after range proof in such a way summed masks for commitments (alpha) and rangeproofs (ai) are equal. In order to save roundtrips we compute commitments randomly and then for the last rangeproof a[63] = (\\sum_{i=0}^{num_inp}alpha_i - \\sum_{i=0}^{num_outs-1} amasks_i) - \\sum_{i=0}^{62}a_i The range proof is incrementally hashed to the final_message. :param idx: :param dest_pub_key: :param amount: :param amount_key: :return: """ from monero_glue.xmr import ring_ct rsig = bytearray(32 * (64 + 64 + 64 + 1)) rsig_mv = memoryview(rsig) out_pk = misc.StdObj(dest=dest_pub_key, mask=None) is_last = idx + 1 == self.num_dests() last_mask = ( None if not is_last or not self.use_simple_rct else crypto.sc_sub(self.sumpouts_alphas, self.sumout) ) # Pedersen commitment on the value, mask from the commitment, range signature. C, mask, rsig = None, 0, None # Rangeproof gc.collect() if self.use_bulletproof: raise ValueError("Bulletproof not yet supported") else: C, mask, rsig = ring_ct.prove_range( amount, last_mask, backend_impl=True, byte_enc=True, rsig=rsig_mv ) rsig = memoryview(rsig) if __debug__: rsig_bytes = monero.inflate_rsig(rsig) self.assrt(ring_ct.ver_range(C, rsig_bytes)) self.assrt( crypto.point_eq( C, crypto.point_add( crypto.scalarmult_base(mask), crypto.scalarmult_h(amount) ), ), "rproof", ) # Incremental hashing await self.full_message_hasher.rsig_val( rsig, self.use_bulletproof, raw=True ) gc.collect() self._log_trace("rproof") # Mask sum out_pk.mask = crypto.encodepoint(C) self.sumout = crypto.sc_add(self.sumout, mask) self.output_sk.append(misc.StdObj(mask=mask)) # ECDH masking from monero_glue.xmr.sub.recode import recode_ecdh from monero_serialize.xmrtypes import EcdhTuple ecdh_info = EcdhTuple(mask=mask, amount=crypto.sc_init(amount)) ecdh_info = ring_ct.ecdh_encode( ecdh_info, derivation=crypto.encodeint(amount_key) ) recode_ecdh(ecdh_info, encode=True) gc.collect() return rsig, out_pk, ecdh_info
async def init_transaction(self, tsx_data, tsx_ctr): """ Initializes a new transaction. :param tsx_data: :type tsx_data: TsxData :param tsx_ctr: :return: """ from monero_glue.xmr.sub.addr import classify_subaddresses self.gen_r() self.state.init_tsx() self._log_trace(1) # Ask for confirmation confirmation = await self.trezor.iface.confirm_transaction(tsx_data, self.creds) if not confirmation: from monero_glue.messages import FailureType from monero_glue.messages.Failure import Failure return Failure(code=FailureType.ActionCancelled, message="rejected") gc.collect() self._log_trace(3) # Basic transaction parameters self.input_count = tsx_data.num_inputs self.output_count = len(tsx_data.outputs) self.output_change = misc.dst_entry_to_stdobj(tsx_data.change_dts) self.mixin = tsx_data.mixin self.fee = tsx_data.fee self.use_simple_rct = self.input_count > 1 self.use_bulletproof = tsx_data.is_bulletproof self.multi_sig = tsx_data.is_multisig self.state.inp_cnt(self.in_memory()) self.check_change(tsx_data.outputs) self.exp_tx_prefix_hash = common.defval_empty(tsx_data.exp_tx_prefix_hash, None) # Provided tx key, used mostly in multisig. if len(tsx_data.use_tx_keys) > 0: for ckey in tsx_data.use_tx_keys: crypto.check_sc(crypto.decodeint(ckey)) self.gen_r(use_r=crypto.decodeint(tsx_data.use_tx_keys[0])) self.additional_tx_private_keys = [ crypto.decodeint(x) for x in tsx_data.use_tx_keys[1:] ] # Additional keys w.r.t. subaddress destinations class_res = classify_subaddresses(tsx_data.outputs, self.change_address()) num_stdaddresses, num_subaddresses, single_dest_subaddress = class_res # if this is a single-destination transfer to a subaddress, we set the tx pubkey to R=s*D if num_stdaddresses == 0 and num_subaddresses == 1: self.r_pub = crypto.ge_scalarmult( self.r, crypto.decodepoint(single_dest_subaddress.m_spend_public_key) ) self.need_additional_txkeys = num_subaddresses > 0 and ( num_stdaddresses > 0 or num_subaddresses > 1 ) self._log_trace(4) # Extra processing, payment id self.tx.version = 2 self.tx.unlock_time = tsx_data.unlock_time await self.process_payment_id(tsx_data) await self.compute_sec_keys(tsx_data, tsx_ctr) gc.collect() # Iterative tx_prefix_hash hash computation await self._tprefix_update() gc.collect() # Final message hasher self.full_message_hasher.init(self.use_simple_rct) await self.full_message_hasher.set_type_fee(self.get_rct_type(), self.get_fee()) # Sub address precomputation if tsx_data.account is not None and tsx_data.minor_indices: self.precompute_subaddr(tsx_data.account, tsx_data.minor_indices) self._log_trace(5) # HMAC outputs - pinning hmacs = [] for idx in range(self.num_dests()): c_hmac = await self.gen_hmac_tsxdest(tsx_data.outputs[idx], idx) hmacs.append(c_hmac) gc.collect() self._log_trace(6) from monero_glue.messages.MoneroTransactionInitAck import ( MoneroTransactionInitAck ) return MoneroTransactionInitAck( in_memory=self.in_memory(), many_inputs=self.many_inputs(), many_outputs=self.many_outputs(), hmacs=hmacs, )
async def all_out1_set(self): """ All outputs were set in this phase. Computes additional public keys (if needed), tx.extra and transaction prefix hash. Adds additional public keys to the tx.extra :return: tx.extra, tx_prefix_hash """ self._log_trace(0) self.state.set_output_done() await self.trezor.iface.transaction_step(self.STEP_ALL_OUT) self._log_trace(1) if self.out_idx + 1 != self.num_dests(): raise ValueError("Invalid out num") # Test if \sum Alpha == \sum A if self.use_simple_rct: self.assrt(crypto.sc_eq(self.sumout, self.sumpouts_alphas)) # Fee test if self.fee != (self.summary_inputs_money - self.summary_outs_money): raise ValueError( "Fee invalid %s vs %s, out: %s" % ( self.fee, self.summary_inputs_money - self.summary_outs_money, self.summary_outs_money, ) ) self._log_trace(2) # Set public key to the extra # Not needed to remove - extra is clean await self.all_out1_set_tx_extra() self.additional_tx_public_keys = None gc.collect() self._log_trace(3) if self.summary_outs_money > self.summary_inputs_money: raise ValueError( "Transaction inputs money (%s) less than outputs money (%s)" % (self.summary_inputs_money, self.summary_outs_money) ) # Hashing transaction prefix await self.all_out1_set_tx_prefix() extra_b = self.tx.extra self.tx = None gc.collect() self._log_trace(4) # Txprefix match check for multisig if not common.is_empty(self.exp_tx_prefix_hash) and not common.ct_equal( self.exp_tx_prefix_hash, self.tx_prefix_hash ): self.state.set_fail() raise misc.TrezorTxPrefixHashNotMatchingError("Tx prefix invalid") gc.collect() self._log_trace(5) from monero_glue.messages.MoneroRingCtSig import MoneroRingCtSig from monero_glue.messages.MoneroTransactionAllOutSetAck import ( MoneroTransactionAllOutSetAck ) rv = self.init_rct_sig() rv_pb = MoneroRingCtSig(txn_fee=rv.txnFee, message=rv.message, rv_type=rv.type) return MoneroTransactionAllOutSetAck( extra=extra_b, tx_prefix_hash=self.tx_prefix_hash, rv=rv_pb )
async def set_out1(self, dst_entr, dst_entr_hmac): """ Set destination entry one by one. Computes destination stealth address, amount key, range proof + HMAC, out_pk, ecdh_info. :param dst_entr :type dst_entr: TxDestinationEntry :param dst_entr_hmac :return: """ from monero_serialize import xmrserialize await self.trezor.iface.transaction_step( self.STEP_OUT, self.out_idx + 1, self.num_dests() ) self._log_trace(1) if self.state.is_input_vins() and self.inp_idx + 1 != self.num_inputs(): raise ValueError("Invalid number of inputs") self.state.set_output() self.out_idx += 1 self._log_trace(2) if dst_entr.amount <= 0 and self.tx.version <= 1: raise ValueError("Destination with wrong amount: %s" % dst_entr.amount) # HMAC check of the destination dst_entr_hmac_computed = await self.gen_hmac_tsxdest(dst_entr, self.out_idx) if not common.ct_equal(dst_entr_hmac, dst_entr_hmac_computed): raise ValueError("HMAC invalid") gc.collect() self._log_trace(3) # First output - tx prefix hasher - size of the container self.tx_prefix_hasher.refresh(xser=xmrserialize) if self.out_idx == 0: await self._set_out1_prefix() gc.collect() self._log_trace(4) additional_txkey_priv = await self._set_out1_additional_keys(dst_entr) derivation = await self._set_out1_derivation(dst_entr, additional_txkey_priv) gc.collect() self._log_trace(5) amount_key = crypto.derivation_to_scalar(derivation, self.out_idx) tx_out_key = crypto.derive_public_key( derivation, self.out_idx, crypto.decodepoint(dst_entr.addr.m_spend_public_key), ) from monero_serialize.xmrtypes import TxoutToKey from monero_serialize.xmrtypes import TxOut tk = TxoutToKey(key=crypto.encodepoint(tx_out_key)) tx_out = TxOut(amount=0, target=tk) self.summary_outs_money += dst_entr.amount self._log_trace(6) # Tx header prefix hashing await self.tx_prefix_hasher.ar.field(tx_out, TxOut) gc.collect() # Hmac dest_entr. hmac_vouti = await self.gen_hmac_vouti(dst_entr, tx_out, self.out_idx) gc.collect() self._log_trace(7) # Range proof, out_pk, ecdh_info rsig, out_pk, ecdh_info = await self.range_proof( self.out_idx, dest_pub_key=tk.key, amount=dst_entr.amount, amount_key=amount_key, ) gc.collect() self._log_trace(8) # Incremental hashing of the ECDH info. # RctSigBase allows to hash only one of the (ecdh, out_pk) as they are serialized # as whole vectors. Hashing ECDH info saves state space. await self.full_message_hasher.set_ecdh(ecdh_info) self._log_trace(9) # Output_pk is stored to the state as it is used during the signature and hashed to the # RctSigBase later. self.output_pk.append(out_pk) gc.collect() self._log_trace(10) from monero_glue.messages.MoneroTransactionSetOutputAck import ( MoneroTransactionSetOutputAck ) from monero_serialize.xmrtypes import CtKey return MoneroTransactionSetOutputAck( tx_out=await misc.dump_msg(tx_out, preallocate=34), vouti_hmac=hmac_vouti, rsig=rsig, # rsig is already byte-encoded out_pk=await misc.dump_msg(out_pk, preallocate=64, msg_type=CtKey), ecdh_info=await misc.dump_msg(ecdh_info, preallocate=64), )
def _log_trace(self, x=None, collect=False): log.debug(__name__, "Log trace: %s, ... F: %s A: %s", x, gc.mem_free(), gc.mem_alloc()) if collect: gc.collect()