Пример #1
0
 def __init__(self):
     self.tsx_data = None  # type: MoneroTransactionData
     self.tx_data = None  # construction data
     self.rsig_type = 0
     self.rsig_batches = []
     self.rsig_param = None
     self.cur_input_idx = 0
     self.cur_output_idx = 0
     self.cur_batch_idx = 0
     self.cur_output_in_batch_idx = 0
     self.tx = xmrtypes.Transaction(version=2, vin=[], vout=[], extra=[])
     self.tx_in_hmacs = []
     self.tx_out_entr_hmacs = []
     self.tx_out_hmacs = []
     self.tx_out_rsigs = []
     self.tx_out_pk = []
     self.tx_out_ecdh = []
     self.source_permutation = []
     self.alphas = []
     self.spend_encs = []
     self.pseudo_outs = []
     self.couts = []
     self.rsig_gamma = []
     self.tx_prefix_hash = None
     self.enc_salt1 = None
     self.enc_salt2 = None
     self.enc_keys = None  # encrypted tx keys
     self.rv = None
Пример #2
0
    def __init__(self, trezor=None):
        self.trezor = trezor  # type: Trezor
        self.creds = None  # type: monero.AccountCreds
        self.key_master = None
        self.key_hmac = None

        self.r = None  # txkey
        self.r_pub = None

        self.tsx_data = None  # type: monero.TsxData
        self.need_additional_txkeys = False
        self.use_bulletproof = False
        self.use_rct = True
        self.use_simple_rct = False
        self.additional_tx_keys = []
        self.additional_tx_public_keys = []
        self.inp_idx = -1
        self.out_idx = -1
        self.summary_inputs_money = 0
        self.summary_outs_money = 0
        self.input_rcts = []
        self.input_secrets = []
        self.output_secrets = []
        self.subaddresses = {}
        self.tx = xmrtypes.Transaction(vin=[], vout=[], extra=b"")
        self.source_permutation = []  # sorted by key images
        self.tx_prefix_hash = None
Пример #3
0
 def __init__(self):
     self.tsx_data = None  # type: TsxData
     self.tx_data = None  # construction data
     self.tx = xmrtypes.Transaction(version=2, vin=[], vout=[], extra=[])
     self.tx_in_hmacs = []
     self.tx_out_entr_hmacs = []
     self.tx_out_hmacs = []
     self.tx_out_rsigs = []
     self.tx_out_pk = []
     self.tx_out_ecdh = []
     self.source_permutation = []
     self.alphas = []
     self.spend_encs = []
     self.pseudo_outs = []
     self.couts = []
     self.tx_prefix_hash = None
     self.enc_salt1 = None
     self.enc_salt2 = None
     self.enc_keys = None  # encrypted tx keys
Пример #4
0
 def __init__(self):
     self.tsx_data = None  # type: monero.TsxData
     self.tx = xmrtypes.Transaction(vin=[], vout=[], extra=[])
     self.tx_in_hmacs = []
     self.source_permutation = []
Пример #5
0
    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")
Пример #6
0
    async def receive(self, tx, all_creds, con_data=None, exp_payment_id=None):
        """
        Test transaction receive with known view/spend keys of destinations.
        :param tx:
        :param all_creds:
        :param con_data:
        :param exp_payment_id:
        :return:
        """
        # Unserialize the transaction
        tx_obj = xmrtypes.Transaction()
        reader = xmrserialize.MemoryReaderWriter(bytearray(tx))
        ar1 = xmrserialize.Archive(reader, False)

        await ar1.message(tx_obj, msg_type=xmrtypes.Transaction)
        extras = await monero.parse_extra_fields(tx_obj.extra)
        tx_pub = monero.find_tx_extra_field_by_type(
            extras, xmrtypes.TxExtraPubKey
        ).pub_key
        additional_pub_keys = monero.find_tx_extra_field_by_type(
            extras, xmrtypes.TxExtraAdditionalPubKeys
        )
        num_outs = len(tx_obj.vout)
        num_received = 0

        # Try to receive tsx outputs with each account.
        tx_money_got_in_outs = collections.defaultdict(lambda: 0)
        outs = []

        change_idx = get_change_addr_idx(con_data.tsx_data.outputs, con_data.tsx_data.change_dts)

        for idx, creds in enumerate(all_creds):
            wallet_subs = {}
            for account in range(0, 5):
                monero.compute_subaddresses(creds, account, range(25), wallet_subs)

            derivation = crypto.generate_key_derivation(
                crypto.decodepoint(tx_pub), creds.view_key_private
            )
            additional_derivations = []
            if additional_pub_keys and additional_pub_keys.data:
                for x in additional_pub_keys.data:
                    additional_derivations.append(
                        crypto.generate_key_derivation(
                            crypto.decodepoint(x), creds.view_key_private
                        )
                    )

            for ti, to in enumerate(tx_obj.vout):
                tx_scan_info = monero.check_acc_out_precomp(
                    to, wallet_subs, derivation, additional_derivations, ti
                )
                if not tx_scan_info.received:
                    continue

                num_received += 1
                tx_scan_info = monero.scan_output(
                    creds, tx_obj, ti, tx_scan_info, tx_money_got_in_outs, outs, False
                )

                # Check spending private key correctness
                self.assertTrue(
                    crypto.point_eq(
                        crypto.decodepoint(tx_obj.rct_signatures.outPk[ti].mask),
                        crypto.gen_c(tx_scan_info.mask, tx_scan_info.amount),
                    )
                )

                self.assertTrue(
                    crypto.point_eq(
                        crypto.decodepoint(tx_obj.vout[ti].target.key),
                        crypto.scalarmult_base(tx_scan_info.in_ephemeral),
                    )
                )

                if exp_payment_id is not None:
                    payment_id = None
                    # Not checking payment id for change transaction
                    if exp_payment_id[0] == 1 and change_idx is not None and ti == change_idx:
                        continue

                    payment_id_type = None
                    extra_nonce = monero.find_tx_extra_field_by_type(extras, xmrtypes.TxExtraNonce)
                    if extra_nonce and monero.has_encrypted_payment_id(extra_nonce.nonce):
                        payment_id_type = 1
                        payment_id = monero.get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce)
                        payment_id = monero.encrypt_payment_id(payment_id, crypto.decodepoint(tx_pub), creds.view_key_private)

                    elif extra_nonce and monero.has_payment_id(extra_nonce.nonce):
                        payment_id_type = 0
                        payment_id = monero.get_payment_id_from_tx_extra_nonce(extra_nonce.nonce)

                    self.assertEqual(payment_id_type, exp_payment_id[0])
                    self.assertEqual(payment_id, exp_payment_id[1])

        # All outputs have to be successfully received
        self.assertEqual(num_outs, num_received)
Пример #7
0
    async def verify(self, tx, con_data=None, creds=None):
        """
        Transaction verification
        :param tx:
        :param con_data:
        :param creds:
        :return:
        """

        # Unserialize the transaction
        tx_obj = xmrtypes.Transaction()
        reader = xmrserialize.MemoryReaderWriter(bytearray(tx))
        ar1 = xmrserialize.Archive(reader, False)

        await ar1.message(tx_obj, msg_type=xmrtypes.Transaction)
        extras = await monero.parse_extra_fields(tx_obj.extra)
        monero.expand_transaction(tx_obj)

        tx_pub = crypto.decodepoint(monero.find_tx_extra_field_by_type(
            extras, xmrtypes.TxExtraPubKey
        ).pub_key)

        additional_pub_keys = monero.find_tx_extra_field_by_type(
            extras, xmrtypes.TxExtraAdditionalPubKeys
        )
        additional_pub_keys = [crypto.decodepoint(x) for x in additional_pub_keys.data] if additional_pub_keys is not None else None

        # Verify range proofs
        out_idx = 0
        is_bp = tx_obj.rct_signatures.type in [RctType.SimpleBulletproof, RctType.FullBulletproof]
        if not is_bp:
            for idx, rsig in enumerate(tx_obj.rct_signatures.p.rangeSigs):
                out_pk = tx_obj.rct_signatures.outPk[idx]
                C = crypto.decodepoint(out_pk.mask)
                rsig = tx_obj.rct_signatures.p.rangeSigs[idx]
                res = ring_ct.ver_range(C, rsig, use_bulletproof=is_bp)
                self.assertTrue(res)

        else:
            for idx, rsig in enumerate(tx_obj.rct_signatures.p.bulletproofs):
                rsig_num_outs = min(len(tx_obj.rct_signatures.outPk), 1 << (len(rsig.L) - 6))
                outs = tx_obj.rct_signatures.outPk[out_idx : out_idx + rsig_num_outs]
                rsig.V = [crypto.encodepoint(ring_ct.bp_comm_to_v(crypto.decodepoint(xx.mask))) for xx in outs]
                res = ring_ct.ver_range(None, rsig, use_bulletproof=is_bp)
                self.assertTrue(res)

        # Prefix hash
        prefix_hash = await monero.get_transaction_prefix_hash(tx_obj)
        is_simple = len(tx_obj.vin) > 1 or is_bp

        self.assertEqual(prefix_hash, con_data.tx_prefix_hash)
        tx_obj.rct_signatures.message = prefix_hash

        # MLSAG hash
        mlsag_hash = await monero.get_pre_mlsag_hash(tx_obj.rct_signatures)

        # Decrypt transaction key
        tx_key = misc.compute_tx_key(creds.spend_key_private, prefix_hash, salt=con_data.enc_salt1, rand_mult=con_data.enc_salt2)[0]
        key_buff = chacha_poly.decrypt_pack(tx_key, con_data.enc_keys)

        tx_priv_keys = [crypto.decodeint(x) for x in common.chunk(key_buff, 32) if x]
        tx_priv = tx_priv_keys[0]
        tx_additional_priv = tx_priv_keys[1:]

        # Verify mlsag signature
        monero.recode_msg(tx_obj.rct_signatures.p.MGs, encode=False)
        for idx in range(len(tx_obj.vin)):
            if is_simple:
                mix_ring = [MoneroRctKeyPublic(dest=x[1].dest, commitment=x[1].mask) for x in con_data.tx_data.sources[idx].outputs]
                if is_bp:
                    pseudo_out = crypto.decodepoint(bytes(tx_obj.rct_signatures.p.pseudoOuts[idx]))
                else:
                    pseudo_out = crypto.decodepoint(bytes(tx_obj.rct_signatures.pseudoOuts[idx]))
                self.assertTrue(mlsag2.ver_rct_mg_simple(
                    mlsag_hash, tx_obj.rct_signatures.p.MGs[idx], mix_ring, pseudo_out
                ))

            else:
                txn_fee_key = crypto.scalarmult_h(tx_obj.rct_signatures.txnFee)
                mix_ring = [[MoneroRctKeyPublic(dest=x[1].dest, commitment=x[1].mask)] for x in con_data.tx_data.sources[idx].outputs]
                self.assertTrue(mlsag2.ver_rct_mg(
                    tx_obj.rct_signatures.p.MGs[idx], mix_ring, tx_obj.rct_signatures.outPk, txn_fee_key, mlsag_hash
                ))
Пример #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)