async def subadress_outs(self, tx, change_idx=None): change_idx = await self.find_change_idx(tx, change_idx) for ix, ox in enumerate(tx.splitted_dsts): if change_idx is not None and ix == change_idx: continue # if ox.is_subaddress: # continue spkey = bytes(ox.addr.m_spend_public_key) orig_keys = self.dest_keys orig_idx = self.dest_sub_major, 0 if spkey in self.cur_subs: orig_keys = self.cur_keys orig_idx = self.cur_subs[spkey] logger.debug('Out %d, in cur subs, idx: %s' % (ix, orig_idx)) elif spkey in self.dest_subs: orig_idx = self.dest_subs[spkey] logger.debug('Out %d, in dst subs, idx: %s' % (ix, orig_idx)) naddr = monero.generate_sub_address_keys(orig_keys.view_key_private, orig_keys.spend_key_public, orig_idx[0], ix+1) ox.addr.m_spend_public_key = crypto.encodepoint(naddr[0]) ox.addr.m_view_public_key = crypto.encodepoint(naddr[1]) ox.is_subaddress = True return change_idx
async def get_subaddress(self): index = self._fetch(8) major, minor = self._idx_parse(index) D, C = monero.generate_sub_address_keys(self.a, self.B, major, minor) self._insert(crypto.encodepoint(C)) self._insert(crypto.encodepoint(D)) return SW_OK
async def primary_change_address(self, key, account): D, C = monero.generate_sub_address_keys( key.view_key_private, crypto.scalarmult_base(key.spend_key_private), account, 0, ) return misc.StdObj( view_public_key=crypto.encodepoint(C), spend_public_key=crypto.encodepoint(D), )
def gen_sub_address(sd, net_type, major_max, minor_max): for major in range(major_max): for minor in range(minor_max): if major == 0 and minor == 0: continue D, C = monero.generate_sub_address_keys(sd.view_sec, sd.spend_pub, major, minor) addr = encode_addr( net_version(net_type, is_subaddr=True), crypto.encodepoint(D), crypto.encodepoint(C), ) yield major, minor, addr
async def gen_output(self, value=1, dest=None, sub_major=0, sub_minor=0, payment_id=None): dest = dest if dest is not None else ( self.prng.choice(self.dest_keys) if isinstance( self.dest_keys, list) else self.dest_keys) is_sub = sub_major != 0 or sub_minor != 0 if is_sub and payment_id is not None: raise ValueError("Integrated cannot be subaddress") KS, KV = monero.generate_sub_address_keys(dest.view_key_private, dest.spend_key_public, sub_major, sub_minor) pubaddr = AccountPublicAddress( m_spend_public_key=crypto.encodepoint(KS), m_view_public_key=crypto.encodepoint(KV), ) pub2 = addr.PubAddress( pubaddr.m_spend_public_key, pubaddr.m_view_public_key, ) tde = TxDestinationEntry( amount=value, addr=pubaddr, is_subaddress=is_sub, original=addr.public_addr_encode(pub2, is_sub, self.nettype, payment_id), is_integrated=payment_id is not None, ) tdextra = DestInfo(dest, sub_major, sub_minor, payment_id) self.outputs.append(tde) self.outputs_extra.append(tdextra) return self
async def gen_input(self, value=1, sub_major=None, sub_minor=0, additionals=False): creds = self.src_keys r = self.random_scalar() R = crypto.scalarmult_base(r) additional_keys = [] Additional = None sub_major = sub_major if sub_major is not None else self.account_idx is_sub = sub_major != 0 or sub_minor != 0 if sub_major != self.account_idx: logger.warning( "Generating input with different major subindex, cannot be spent in the resulting " "transaction") kssec = monero.get_subaddress_secret_key(creds.view_key_private, major=sub_major, minor=sub_minor) kssub = crypto.sc_add( kssec, creds.spend_key_private) if is_sub else creds.spend_key_private kvsub = crypto.sc_mul(creds.view_key_private, kssub) if is_sub else creds.view_key_private KSSUB, KVSUB = monero.generate_sub_address_keys( creds.view_key_private, creds.spend_key_public, sub_major, sub_minor) if not crypto.point_eq(KSSUB, crypto.scalarmult_base(kssub)): raise ValueError("Invariant error") oidx = self.prng.randint(0, 12) additionals_cnt = self.prng.randint(oidx + 1, 2 * oidx + 1) deriv = crypto.generate_key_derivation(KVSUB, r) kout = crypto.derive_secret_key(deriv, oidx, kssub) KOUT = crypto.derive_public_key(deriv, oidx, KSSUB) if not crypto.point_eq(KOUT, crypto.scalarmult_base(kout)): raise ValueError("Invariant error") if additionals: if is_sub: Additional = crypto.scalarmult(KSSUB, r) else: Additional = crypto.scalarmult_base(r) else: if is_sub: R = crypto.scalarmult(KSSUB, r) amnt = crypto.sc_init(value) msk = self.random_scalar() # commitment mask C = crypto.add_keys2(msk, amnt, crypto.xmr_H()) ring = [] for i in range(self.ring_size - 1): tk = CtKey( dest=crypto.encodepoint(self.random_pub()), mask=crypto.encodepoint(self.random_pub()), ) ring.append(tk) index = self.prng.randint(0, len(ring)) ring.insert( index, CtKey(dest=crypto.encodepoint(KOUT), mask=crypto.encodepoint(C))) if additionals: additional_keys = [ self.random_pub() for _ in range(additionals_cnt) ] additional_keys[oidx] = Additional src = TxSourceEntry() src.outputs = [(self.random_glob_idx(), x) for x in ring] src.real_output = index src.real_out_tx_key = crypto.encodepoint(R) src.real_out_additional_tx_keys = [ crypto.encodepoint(x) for x in additional_keys ] src.real_output_in_tx_index = oidx src.amount = value src.rct = True src.mask = crypto.encodeint(msk) src.multisig_kLRki = MultisigKLRki(K=crypto.ZERO, L=crypto.ZERO, R=crypto.ZERO, ki=crypto.ZERO) td = TransferDetails() td.m_internal_output_index = oidx td.m_global_output_index = src.outputs[index][0] td.m_mask = src.mask td.m_amount = value td.m_subaddr_index = SubaddressIndex(major=sub_major, minor=sub_minor) td.m_rct = True td.m_txid = self.random_bytes(32) td.m_block_height = self.prng.randint(0, 0xFFFF) td.m_spent = False td.m_spent_height = 0 td.m_key_image_known = True td.m_key_image_requested = False td.m_key_image_partial = False td.m_multisig_k = [] td.m_multisig_info = [] td.m_uses = [] td.m_pk_index = 0 td.m_tx = self.gen_tx_prefix(self.prng.randint(1, 10), additionals_cnt) td.m_tx.vout[oidx].target.key = crypto.encodepoint(KOUT) extras = [] extras.append(TxExtraNonce(nonce=self.random_bytes(8))) extras.append(TxExtraPubKey(pub_key=src.real_out_tx_key)) if src.real_out_additional_tx_keys: extras.append( TxExtraAdditionalPubKeys(data=src.real_out_additional_tx_keys)) td.m_tx.extra = await self.dump_extra_fields(extras) tmpsubs = {} monero.compute_subaddresses(creds, sub_major, [sub_minor], tmpsubs) xi, ki, rderiv = self.check_input(src, creds, tmpsubs) if not crypto.sc_eq(xi, kout): raise ValueError("Invariant error") td.m_key_image = crypto.encodepoint(ki) self.sources.append(src) self.selected_transfers.append(len(self.transfers)) self.transfers.append(td) self.sources_creds.append(creds) if not crypto.point_eq( crypto.decodepoint(src.outputs[src.real_output][1].dest), crypto.scalarmult_base(kout)): raise ValueError("Invariant error") return self