async def load_unsigned_tx(priv_key, data): """ Loads unsigned transaction from the encrypted file :param priv_key: :param data: :return: """ magic_len = len(UNSIGNED_TX_PREFIX) magic = data[:magic_len - 1] version = int(data[magic_len - 1]) data = data[magic_len:] if magic != UNSIGNED_TX_PREFIX[:-1]: raise ValueError("Invalid file header") if version != 4: raise ValueError("Unsigned transaction v4 is supported only") tx_uns_ser = chacha.decrypt_xmr(priv_key, data, authenticated=True) reader = xmrserialize.MemoryReaderWriter(bytearray(tx_uns_ser)) ar = xmrboost.Archive(reader, False) msg = xmrtypes.UnsignedTxSet() await ar.root() await ar.message(msg) return msg
async def load_exported_outputs(priv_key, data): """ Loads exported outputs file :param data: :return: """ magic_len = len(OUTPUTS_PREFIX) magic = data[:magic_len - 1] version = int(data[magic_len - 1]) data = data[magic_len:] if magic != OUTPUTS_PREFIX[:-1]: raise ValueError("Invalid file header") if version != 3: raise ValueError("Exported outputs v3 is supported only") data_dec = chacha.decrypt_xmr(priv_key, data, authenticated=True) spend_pub = data_dec[:32] view_pub = data_dec[32:64] data_dec = data_dec[64:] reader = xmrserialize.MemoryReaderWriter(bytearray(data_dec)) ar = xmrboost.Archive(reader, False) await ar.root() exps = await ar.container(container_type=ExportedOutputs) return OutputsDump(m_spend_public_key=spend_pub, m_view_public_key=view_pub, tds=exps)
async def tx_sign_unsigned_boost(self, unsigned_tx, fl=None): """ Tx sign test with given unsigned transaction data, serialized by boost - unsigned tx produced by watch-only cli wallet. :param unsigned_tx: :param fl: :return: """ reader = xmrserialize.MemoryReaderWriter(bytearray(unsigned_tx)) ar = xmrboost.Archive(reader, False) unsig = xmrtypes.UnsignedTxSet() await ar.root() await ar.message(unsig) await self.tx_sign_unsigned_msg(unsig, fl)
async def save_exported_outputs(priv_spend, priv_view, transfers): writer = xmrserialize.MemoryReaderWriter() ar = xmrboost.Archive(writer, True) await ar.root() await ar.container(transfers, container_type=ExportedOutputs) trans_bin = writer.get_buffer() buff_dec = bytearray() buff_dec += crypto.encodepoint(crypto.scalarmult_base(priv_spend)) buff_dec += crypto.encodepoint(crypto.scalarmult_base(priv_view)) buff_dec += trans_bin data_enc = chacha.encrypt_xmr(priv_view, buff_dec, authenticated=True) return bytearray(bytes(OUTPUTS_PREFIX) + data_enc)
async def tx_sign_pending_boost(self, pending_tx, fl=None): """ Signs transaction produced by the wallet-rpc, metadata parser, boost :param metadata: :param fl: :return: """ self.skipTest('HP <= 8 not supported anymore') reader = xmrserialize.MemoryReaderWriter(bytearray(pending_tx)) ar = xmrboost.Archive(reader, False) pending = xmrtypes.PendingTransaction() await ar.root() await ar.message(pending) tagent = self.init_agent() await self.tx_sign_test(tagent, pending.construction_data, self.get_creds(), self.get_all_creds(), fl, sign_tx=True)
async def dump_unsigned_tx(priv_key, unsigned_tx): """ Dumps unsigned transaction :param priv_key: :param unsigned_tx: :return: """ writer = xmrserialize.MemoryReaderWriter() ar = xmrboost.Archive(writer, True) await ar.root() await ar.message(unsigned_tx) ciphertext = chacha.encrypt_xmr(priv_key, bytes(writer.get_buffer()), authenticated=True) return UNSIGNED_TX_PREFIX + ciphertext
async def dump_signed_tx(priv_key, signed_tx): """ Dumps signed_tx to a file as wallet produces :param priv_key: :param signed_tx: :return: """ writer = xmrserialize.MemoryReaderWriter() ar = xmrboost.Archive(writer, True) await ar.root() await ar.message(signed_tx) ciphertext = chacha.encrypt_xmr(priv_key, bytes(writer.get_buffer()), authenticated=True) return SIGNED_TX_PREFIX + ciphertext
async def dump_signed_tx(priv_key, signed_tx): """ Dumps signed_tx to a file as wallet produces :param priv_key: :param signed_tx: :return: """ writer = xmrserialize.MemoryReaderWriter() ar = xmrboost.Archive(writer, True) try: await ar.root() await ar.message(signed_tx) except Exception as e: logger.error('Exception in signed tx serialization: %s, field: %s' % (e, ar.tracker)) raise ciphertext = chacha.encrypt_xmr( priv_key, bytes(writer.get_buffer()), authenticated=True ) return SIGNED_TX_PREFIX + ciphertext
async def load_exported_outputs(priv_key, data): """ Loads exported outputs file :param data: :return: """ magic_len = len(OUTPUTS_PREFIX) magic = data[: magic_len - 1] version = int(data[magic_len - 1]) data = data[magic_len:] if magic != OUTPUTS_PREFIX[:-1]: raise ValueError("Invalid file header") if version not in [3, 4]: raise ValueError("Exported outputs v3, v4 are supported only") msg_to_parse = ExportedOutputsV4 if version == 4 else ExportedOutputs data_dec = chacha.decrypt_xmr(priv_key, data, authenticated=True) spend_pub = data_dec[:32] view_pub = data_dec[32:64] data_dec = data_dec[64:] reader = xmrserialize.MemoryReaderWriter(bytearray(data_dec)) ar = xmrboost.Archive(reader, False) await ar.root() if version == 3: exps = await ar.container(container_type=ExportedOutputs) elif version == 4: exps_root = await ar.tuple(elem_type=ExportedOutputsV4) exps = exps_root[1] if exps_root[0] != 0: raise ValueError('Offset has to be 0') return OutputsDump( m_spend_public_key=spend_pub, m_view_public_key=view_pub, tds=exps )
async def store_cdata(self, cdata, signed_tx, tx, transfers): """ Stores transaction data for later usage. - cdata.enc_salt1, cdata.enc_salt2, cdata.enc_keys - tx_keys are AEAD protected, key derived from spend key - only token can open. - construction data for further proofs. :param cdata: :param signed_tx: :param tx: :param transfers: :return: """ hash = cdata.tx_prefix_hash prefix = binascii.hexlify(hash[:12]) tx_key_salt = crypto.random_bytes(32) tx_key_inp = hash + crypto.encodeint(self.priv_view) tx_view_key = crypto.pbkdf2(tx_key_inp, tx_key_salt, 2048) unsigned_data = xmrtypes.UnsignedTxSet() unsigned_data.txes = [tx] unsigned_data.transfers = transfers if transfers is not None else [] writer = xmrserialize.MemoryReaderWriter() ar = xmrboost.Archive(writer, True) await ar.root() await ar.message(unsigned_data) unsigned_key = crypto.keccak_2hash(b'unsigned;' + tx_view_key) ciphertext = chacha_poly.encrypt_pack(unsigned_key, bytes(writer.get_buffer())) # Serialize signed transaction writer = xmrserialize.MemoryReaderWriter() ar = xmrserialize.Archive(writer, True) await ar.root() await ar.message(signed_tx) signed_tx_bytes = writer.get_buffer() signed_tx_hmac_key = crypto.keccak_2hash(b'hmac;' + tx_view_key) signed_tx_hmac = crypto.compute_hmac(signed_tx_hmac_key, signed_tx_bytes) try: js = { "time": int(time.time()), "hash": binascii.hexlify(hash).decode("ascii"), "enc_salt1": binascii.hexlify(cdata.enc_salt1).decode("ascii"), "enc_salt2": binascii.hexlify(cdata.enc_salt2).decode("ascii"), "tx_keys": binascii.hexlify(cdata.enc_keys).decode("ascii"), "unsigned_data": binascii.hexlify(ciphertext).decode("ascii"), "tx_salt": binascii.hexlify(tx_key_salt).decode("ascii"), "tx_signed": binascii.hexlify(signed_tx_bytes).decode("ascii"), "tx_signed_hmac": binascii.hexlify(signed_tx_hmac).decode("ascii"), } with open("transaction_%s.json" % prefix.decode("ascii"), "w") as fh: json.dump(js, fh, indent=2) fh.write("\n") except Exception as e: self.trace_logger.log(e) print("Unable to save transaction data for transaction %s" % binascii.hexlify(hash).decode("ascii"))