Exemple #1
0
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 tx_sign_unsigned(self, unsigned_tx, fl=None):
     """
     Tx sign test with given unsigned transaction data
     :param unsigned_tx:
     :param fl:
     :return:
     """
     reader = xmrserialize.MemoryReaderWriter(bytearray(unsigned_tx))
     ar = xmrserialize.Archive(reader, False)
     unsig = xmrtypes.UnsignedTxSet()
     await ar.message(unsig)
     await self.tx_sign_unsigned_msg(unsig, fl)
Exemple #3
0
 async def tx_sign_unsigned(self, unsigned_tx, fl=None):
     """
     Tx sign test with given unsigned transaction data
     :param unsigned_tx:
     :param fl:
     :return:
     """
     self.skipTest('HP <= 8 not supported anymore')
     reader = xmrserialize.MemoryReaderWriter(bytearray(unsigned_tx))
     ar = xmrserialize.Archive(reader, False, self._get_bc_ver())
     unsig = xmrtypes.UnsignedTxSet()
     await ar.message(unsig)
     await self.tx_sign_unsigned_msg(unsig, fl)
Exemple #4
0
    async def tx_sign(self, unsigned_tx):
        """
        Tx sign test with given unsigned transaction data
        :param unsigned_tx:
        :return:
        """
        reader = xmrserialize.MemoryReaderWriter(bytearray(unsigned_tx))
        ar = xmrserialize.Archive(reader, False)
        unsig = xmrtypes.UnsignedTxSet()
        await ar.message(unsig)

        tagent = self.init_agent()
        await tagent.transfer_unsigned(unsig)
    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)
Exemple #6
0
    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"))
    async def test_tx_prefix(self):
        return
        url = "http://localhost:48084/json_rpc"
        req = {
            "jsonrpc": "2.0",
            "id": "0",
            "method": "transfer_unsigned",
            "params": {
                "destinations": [
                    {
                        "amount":
                        2110000000000,
                        "address":
                        "BZZeyHTQYZ9W9KX2M69WWxWat1Z6JQYsi4LjnZxuVTmCbsNxrUyLFbXiZHRwXgBcaESRz8HtHxTDGSCtgxDdEFpQFrKqXoX",
                    },
                    {
                        "amount":
                        2120000000000,
                        "address":
                        "BZg53n1EgLJhYDZNCi3VvxXFMdmmgk6HhhFCvvw9sMf1RQFp7LyjGvrNuF7TzukfaGh7Gsin2bEDpUNRv9oc8qSGMKCnktw",
                    },
                    {
                        "amount":
                        2130000000000,
                        "address":
                        "9wviCeWe2D8XS82k2ovp5EUYLzBt9pYNW2LXUFsZiv8S3Mt21FZ5qQaAroko1enzw3eGr9qC7X1D7Geoo2RrAotYPwq9Gm8",
                    },
                ],
                "account_index":
                0,
                "subaddr_indices": [],
                "priority":
                5,
                "mixin":
                4,
                "unlock_time":
                0,
                # "payment_id": "deadc0dedeadc0d1",
                "get_tx_keys":
                True,
                "do_not_relay":
                True,
                "get_tx_hex":
                True,
                "get_tx_metadata":
                True,
            },
        }

        resp = requests.post(url, json=req)
        js = resp.json()

        # Transaction parsing
        blobs = js["result"]["tx_blob_list"]
        tx_blob = blobs[0]
        tx_unsigned = js["result"]["tx_unsigned"]

        tsx_bin = base64.b16decode(tx_blob, True)
        reader = xmrserialize.MemoryReaderWriter(bytearray(tsx_bin))
        ar = xmrserialize.Archive(reader, False)
        msg = xmrtypes.Transaction()
        await ar.message(msg)

        # Unsigned transaction parsing
        tsx_unsigned_bin = base64.b16decode(tx_unsigned, True)
        reader = xmrserialize.MemoryReaderWriter(bytearray(tsx_unsigned_bin))
        ar = xmrserialize.Archive(reader, False)
        unsig = xmrtypes.UnsignedTxSet()
        await ar.message(unsig)

        tagent = self.init_agent()
        txes = await tagent.sign_unsigned_tx(unsig)

        resp = requests.post(
            "http://localhost:48081/sendrawtransaction",
            json={
                "tx_as_hex": binascii.hexlify(txes[0]).decode("utf8"),
                "do_not_relay": False,
            },
        )
        print(resp)

        print("Txblob: \n %s\n" % tx_blob)
        print("TxUns: \n %s\n" % tx_unsigned)
        print("TxMeta: \n %s\n" % js["result"]["tx_metadata_list"][0])
        print("Done")
Exemple #8
0
    async def test_node_transaction(self):
        tx_j = pkg_resources.resource_string(
            __name__, os.path.join("data", "tsx_01.json"))
        tx_c = pkg_resources.resource_string(
            __name__, os.path.join("data", "tsx_01_plain.txt"))
        tx_u_c = pkg_resources.resource_string(
            __name__, os.path.join("data", "tsx_01_uns.txt"))
        tx_js = json.loads(tx_j.decode("utf8"))

        reader = xmrserialize.MemoryReaderWriter(
            bytearray(binascii.unhexlify(tx_c)))
        ar = xmrserialize.Archive(reader, False, self._get_bc_ver())
        tx = xmrtypes.Transaction()
        await ar.message(tx)

        reader = xmrserialize.MemoryReaderWriter(
            bytearray(binascii.unhexlify(tx_u_c)))
        ar = xmrserialize.Archive(reader, False, self._get_bc_ver())
        uns = xmrtypes.UnsignedTxSet()
        await ar.message(uns)

        # Test message hash computation
        tx_prefix_hash = await monero.get_transaction_prefix_hash(tx)
        message = binascii.unhexlify(tx_js["tx_prefix_hash"])
        self.assertEqual(tx_prefix_hash, message)

        # RingCT, range sigs, hash
        rv = tx.rct_signatures
        rv.message = message
        rv.mixRing = self.mixring(tx_js)
        digest = await monero.get_pre_mlsag_hash(rv)
        full_message = binascii.unhexlify(tx_js["pre_mlsag_hash"])
        self.assertEqual(digest, full_message)

        # Recompute missing data
        monero.expand_transaction(tx)

        # Unmask ECDH data, check range proofs
        for i in range(len(tx_js["amount_keys"])):
            ecdh = monero.copy_ecdh(rv.ecdhInfo[i])
            monero.recode_ecdh(ecdh, encode=False)

            ecdh = ring_ct.ecdh_decode(ecdh,
                                       derivation=binascii.unhexlify(
                                           tx_js["amount_keys"][i]))
            self.assertEqual(crypto.sc_get64(ecdh.amount),
                             tx_js["outamounts"][i])
            self.assertTrue(
                crypto.sc_eq(
                    ecdh.mask,
                    crypto.decodeint(
                        binascii.unhexlify(tx_js["outSk"][i])[32:]),
                ))

            C = crypto.decodepoint(rv.outPk[i].mask)
            rsig = rv.p.rangeSigs[i]

            res = ring_ct.ver_range(C, rsig)
            self.assertTrue(res)

            res = ring_ct.ver_range(
                crypto.point_add(C, crypto.scalarmult_base(crypto.sc_init(3))),
                rsig)
            self.assertFalse(res)

        is_simple = len(tx.vin) > 1
        monero.recode_rct(rv, encode=False)

        if is_simple:
            for index in range(len(rv.p.MGs)):
                pseudo_out = crypto.decodepoint(
                    binascii.unhexlify(
                        tx_js["tx"]["rct_signatures"]["pseudoOuts"][index]))
                r = mlsag2.ver_rct_mg_simple(full_message, rv.p.MGs[index],
                                             rv.mixRing[index], pseudo_out)
                self.assertTrue(r)

                r = mlsag2.ver_rct_mg_simple(full_message, rv.p.MGs[index],
                                             rv.mixRing[index - 1], pseudo_out)
                self.assertFalse(r)

        else:
            txn_fee_key = crypto.scalarmult_h(rv.txnFee)
            r = mlsag2.ver_rct_mg(rv.p.MGs[0], rv.mixRing, rv.outPk,
                                  txn_fee_key, digest)
            self.assertTrue(r)

            r = mlsag2.ver_rct_mg(
                rv.p.MGs[0],
                rv.mixRing,
                rv.outPk,
                crypto.scalarmult_h(rv.txnFee - 100),
                digest,
            )
            self.assertFalse(r)