示例#1
0
async def get_pre_mlsag_hash(rv):
    """
    Generates final message for the Ring CT signature

    :param rv:
    :type rv: RctSig
    :return:
    """
    from monero_glue.xmr.sub.keccak_hasher import get_keccak_writer
    from monero_serialize.xmrtypes import RctType

    kc_master = HashWrapper(crypto.get_keccak())
    kc_master.update(rv.message)

    is_simple = rv.type in [
        RctType.Simple, RctType.Bulletproof, RctType.Bulletproof2
    ]
    outputs = len(rv.ecdhInfo)
    inputs = 0
    if rv.type == RctType.Simple:
        inputs = len(rv.pseudoOuts)
    elif rv.type in [RctType.Bulletproof, RctType.Bulletproof2]:
        inputs = len(rv.p.pseudoOuts)

    kwriter = get_keccak_writer()
    ar = xmrserialize.Archive(kwriter, True)
    await rv.serialize_rctsig_base(ar, inputs, outputs)
    c_hash = kwriter.get_digest()
    kc_master.update(c_hash)

    kc = crypto.get_keccak()
    if rv.type in [RctType.Bulletproof, RctType.Bulletproof2]:
        for p in rv.p.bulletproofs:
            kc.update(p.A)
            kc.update(p.S)
            kc.update(p.T1)
            kc.update(p.T2)
            kc.update(p.taux)
            kc.update(p.mu)
            for i in range(len(p.L)):
                kc.update(p.L[i])
            for i in range(len(p.R)):
                kc.update(p.R[i])
            kc.update(p.a)
            kc.update(p.b)
            kc.update(p.t)

    else:
        for r in rv.p.rangeSigs:
            for i in range(64):
                kc.update(r.asig.s0[i])
            for i in range(64):
                kc.update(r.asig.s1[i])
            kc.update(r.asig.ee)
            for i in range(64):
                kc.update(r.Ci[i])

    c_hash = kc.digest()
    kc_master.update(c_hash)
    return kc_master.digest()
示例#2
0
async def load_keys_data(data, password):
    """
    Loads wallet keys file passed as byte string
    :param file:
    :param password:
    :return:
    """
    reader = xmrserialize.MemoryReaderWriter(bytearray(data))
    ar = xmrserialize.Archive(reader, False)
    msg = xmrtypes.KeysFileData()
    await ar.message(msg)

    key = chacha.generate_key(password)
    buff = bytes(msg.iv + msg.account_data)
    dec = chacha.decrypt(key, buff)

    m = re.search(b'(.*)"key_data":"(.+?)",(.*)', dec)
    key_data = m.group(2)

    dat = xmrjson.unescape_json_str(key_data)
    reader = xmrserialize.MemoryReaderWriter(bytearray(dat))
    ar = xmrrpc.Archive(reader, False)

    key_data = {}
    await ar.root()
    await ar.section(key_data)

    rest_json = m.group(1) + m.group(3)
    wallet_key = json.loads(rest_json)
    wallet_key["key_data"] = key_data
    return wallet_key
示例#3
0
async def dump_msg(msg, preallocate=None, msg_type=None, prefix=None):
    writer = xmrserialize.MemoryReaderWriter(preallocate=preallocate)
    if prefix:
        writer.write(prefix)
    ar = xmrserialize.Archive(writer, True)
    await ar.message(msg, msg_type=msg_type)
    return writer.get_buffer()
示例#4
0
async def get_transaction_prefix_hash(tx):
    """
    Computes transaction prefix in one step
    """
    writer = get_keccak_writer()
    ar1 = xmrserialize.Archive(writer, True)
    await ar1.message(tx, msg_type=xmrtypes.TransactionPrefixExtraBlob)
    return writer.get_digest()
示例#5
0
 async def serialize_tx(self, tx):
     """
     Serializes transaction
     :param tx:
     :return:
     """
     writer = xmrserialize.MemoryReaderWriter()
     ar1 = xmrserialize.Archive(writer, True)
     await ar1.message(tx, msg_type=xmrtypes.Transaction)
     return bytes(writer.get_buffer())
示例#6
0
    def _ar(self, xser=None):
        if self.keeping and self.ar:
            return self.ar
        if xser:
            ar = xser.Archive(self.kwriter, True)
        else:
            from monero_serialize import xmrserialize

            ar = xmrserialize.Archive(self.kwriter, True)
        self.ar = ar if self.keeping else None
        return ar
示例#7
0
async def parse_extra_fields(extra_buff):
    """
    Parses extra buffer to the extra fields vector
    :param extra_buff:
    :return:
    """
    extras = []
    rw = MemoryReaderWriter(bytes(extra_buff))
    ar2 = xmrserialize.Archive(rw, False)
    while len(rw.get_buffer()) > 0:
        extras.append(await ar2.variant(elem_type=TxExtraField))
    return extras
示例#8
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:
     """
     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)
示例#9
0
async def remove_field_from_tx_extra(extra, mtype):
    """
    Removes extra field of fiven type from the buffer
    Reserializes with skipping the given mtype.
    :param extra:
    :param mtype:
    :return:
    """
    if len(extra) == 0:
        return []

    reader = MemoryReaderWriter(extra)
    writer = MemoryReaderWriter()
    ar_read = xmrserialize.Archive(reader, False)
    ar_write = xmrserialize.Archive(writer, True)
    while len(reader.get_buffer()) > 0:
        c_extras = await ar_read.variant(elem_type=TxExtraField)
        if not isinstance(c_extras, mtype):
            await ar_write.variant(c_extras, elem_type=TxExtraField)

    return writer.get_buffer()
示例#10
0
 async def compute_hmac_keys(self, tsx_ctr):
     """
     Generate master key H(TsxData || r || c_tsx)
     :return:
     """
     writer = monero.get_keccak_writer()
     ar1 = xmrserialize.Archive(writer, True)
     await ar1.message(self.tsx_data)
     await writer.awrite(crypto.encodeint(self.r))
     await xmrserialize.dump_uvarint(writer, tsx_ctr)
     self.key_master = writer.get_digest()
     self.key_hmac = crypto.keccak_hash(b"hmac" + self.key_master)
示例#11
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
示例#12
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)
示例#13
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)
示例#14
0
    async def compute_sec_keys(self, tsx_data, tsx_ctr):
        """
        Generate master key H(TsxData || r || c_tsx)
        :return:
        """
        from monero_glue.xmr.sub.keccak_hasher import get_keccak_writer
        from monero_serialize import xmrserialize

        writer = get_keccak_writer()
        ar1 = xmrserialize.Archive(writer, True)
        await ar1.message(tsx_data)
        await writer.awrite(crypto.encodeint(self.r))
        await xmrserialize.dump_uvarint(writer, tsx_ctr)
        self.key_master = crypto.keccak_2hash(
            writer.get_digest() + crypto.encodeint(crypto.random_scalar())
        )
        self.key_hmac = crypto.keccak_2hash(b"hmac" + self.key_master)
        self.key_enc = crypto.keccak_2hash(b"enc" + self.key_master)
示例#15
0
    async def gen_hmac_tsxdest(self, dst_entr, idx):
        """
        Generates HMAC for TxDestinationEntry[i]
        :param dst_entr:
        :param idx:
        :return:
        """
        from monero_glue.xmr.sub.keccak_hasher import get_keccak_writer
        from monero_serialize import xmrserialize
        from monero_serialize.xmrtypes import TxDestinationEntry

        kwriter = get_keccak_writer()
        ar = xmrserialize.Archive(kwriter, True)
        await ar.message(dst_entr, TxDestinationEntry)

        hmac_key = self.hmac_key_txdst(idx)
        hmac_tsxdest = crypto.compute_hmac(hmac_key, kwriter.get_digest())
        return hmac_tsxdest
示例#16
0
async def add_additional_tx_pub_keys_to_extra(tx_extra,
                                              additional_pub_keys=None,
                                              pub_enc=None):
    """
    Adds all pubkeys to the extra
    :param tx_extra:
    :param additional_pub_keys:
    :param pub_enc: None
    :return:
    """
    pubs_msg = TxExtraAdditionalPubKeys(
        data=pub_enc
        if pub_enc else [crypto.encodepoint(x) for x in additional_pub_keys])

    rw = MemoryReaderWriter()
    ar = xmrserialize.Archive(rw, True)

    # format: variant_tag (0x4) | array len varint | 32B | 32B | ...
    await ar.variant(pubs_msg, TxExtraField)
    tx_extra += bytes(rw.get_buffer())
    return tx_extra
示例#17
0
    async def gen_hmac_vini(self, src_entr, vini, idx):
        """
        Computes hmac (TxSourceEntry[i] || tx.vin[i])
        :param src_entr:
        :param vini:
        :param idx:
        :return:
        """
        from monero_glue.xmr.sub.keccak_hasher import get_keccak_writer
        from monero_serialize import xmrserialize
        from monero_serialize.xmrtypes import TxSourceEntry
        from monero_serialize.xmrtypes import TxinToKey

        kwriter = get_keccak_writer()
        ar = xmrserialize.Archive(kwriter, True)
        await ar.message(src_entr, TxSourceEntry)
        await ar.message(vini, TxinToKey)

        hmac_key_vini = self.hmac_key_txin(idx)
        hmac_vini = crypto.compute_hmac(hmac_key_vini, kwriter.get_digest())
        return hmac_vini
示例#18
0
    async def gen_hmac_vouti(self, dst_entr, tx_out, idx):
        """
        Generates HMAC for (TxDestinationEntry[i] || tx.vout[i])
        :param dst_entr:
        :param tx_out:
        :param idx:
        :return:
        """
        from monero_glue.xmr.sub.keccak_hasher import get_keccak_writer
        from monero_serialize import xmrserialize
        from monero_serialize.xmrtypes import TxDestinationEntry
        from monero_serialize.xmrtypes import TxOut

        kwriter = get_keccak_writer()
        ar = xmrserialize.Archive(kwriter, True)
        await ar.message(dst_entr, TxDestinationEntry)
        await ar.message(tx_out, TxOut)

        hmac_key_vouti = self.hmac_key_txout(idx)
        hmac_vouti = crypto.compute_hmac(hmac_key_vouti, kwriter.get_digest())
        return hmac_vouti
示例#19
0
async def gen_keys_file(password, wkeyfile):
    """
    Generates wallet keys file as bytestring
    :param password:
    :param wkeyfile:
    :return:
    """
    key_data = wkeyfile.key_data  # type: WalletKeyData
    js = wkeyfile.to_json()
    del js["key_data"]

    # encode wallet key file wth classical json encoder, key data added later with monero encoding.
    enc = json.dumps(js, cls=xmrjson.AutoJSONEncoder)

    # key_data KV serialization. Message -> Model.
    modeler = xmrrpc.Modeler(writing=True, modelize=True)
    mdl = await modeler.message(msg=key_data)

    # Model -> binary
    writer = xmrserialize.MemoryReaderWriter()
    ar = xmrrpc.Archive(writer, True)

    await ar.root()
    await ar.section(mdl)
    ser = bytes(writer.get_buffer())

    ser2 = xmrjson.escape_string_json(ser)
    enc2 = b'{"key_data":"' + ser2 + b'",' + enc[1:].encode("utf8")

    key = chacha.generate_key(password)
    enc_enc = chacha.encrypt(key, enc2)

    writer = xmrserialize.MemoryReaderWriter()
    ar = xmrserialize.Archive(writer, True)
    msg = xmrtypes.KeysFileData()
    msg.iv = enc_enc[0:8]
    msg.account_data = enc_enc[8:]
    await ar.message(msg)

    return bytes(writer.get_buffer())
示例#20
0
 async def parse_block(self, bindata):
     reader = xmrserialize.MemoryReaderWriter(bytearray(bindata))
     ar = xmrserialize.Archive(reader, False)
     return await ar.message(None, xmrtypes.Block)
示例#21
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)
示例#22
0
    def __init__(self, ctx=None):
        from monero_serialize import xmrserialize

        self.kwriter = get_keccak_writer(ctx=ctx)
        self.ar = xmrserialize.Archive(self.kwriter, True)
示例#23
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")
示例#24
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"))
示例#25
0
    async def signature(self, tx):
        """
        Computes the signature in one pass.
        Implements RingCT in Python.

        :param tx: const data
        :type tx: xmrtypes.TxConstructionData
        :return:
        """
        amount_in = 0
        inamounts = [None] * len(self.source_permutation)
        index = [None] * len(self.source_permutation)
        in_sk = [None] * len(self.source_permutation)  # type: list[xmrtypes.CtKey]

        for i in range(len(self.source_permutation)):
            idx = self.source_permutation[i]
            src = tx.sources[idx]
            amount_in += src.amount
            inamounts[i] = src.amount
            index[i] = src.real_output
            in_sk[i] = xmrtypes.CtKey(
                dest=self.input_secrets[i][0], mask=crypto.decodeint(src.mask)
            )
            # TODO: kLRki

            # private key correctness test
            if __debug__:
                assert crypto.point_eq(
                    crypto.decodepoint(src.outputs[src.real_output][1].dest),
                    crypto.scalarmult_base(in_sk[i].dest),
                )
                assert crypto.point_eq(
                    crypto.decodepoint(src.outputs[src.real_output][1].mask),
                    crypto.gen_c(in_sk[i].mask, inamounts[i]),
                )

        destinations = []
        outamounts = []
        amount_out = 0
        for idx, dst in enumerate(tx.splitted_dsts):
            destinations.append(crypto.decodepoint(self.tx.vout[idx].target.key))
            outamounts.append(self.tx.vout[idx].amount)
            amount_out += self.tx.vout[idx].amount

        if self.use_simple_rct:
            mix_ring = [None] * (self.inp_idx + 1)
            for i in range(len(self.source_permutation)):
                src = tx.sources[self.source_permutation[i]]
                mix_ring[i] = []
                for idx2, out in enumerate(src.outputs):
                    mix_ring[i].append(out[1])

        else:
            n_total_outs = len(tx.sources[0].outputs)
            mix_ring = [None] * n_total_outs
            for idx in range(n_total_outs):
                mix_ring[idx] = []
                for i in range(len(self.source_permutation)):
                    src = tx.sources[self.source_permutation[i]]
                    mix_ring[idx].append(src.outputs[idx][1])

        if not self.use_simple_rct and amount_in > amount_out:
            outamounts.append(amount_in - amount_out)

        # Hide amounts
        self.zero_out_amounts()

        # Tx prefix hash
        await self.compute_tx_prefix_hash()

        # Signature
        if self.use_simple_rct:
            rv = await self.gen_rct_simple(
                in_sk,
                destinations,
                inamounts,
                outamounts,
                amount_in - amount_out,
                mix_ring,
                None,
                None,
                index,
            )
        else:
            rv = await self.gen_rct(
                in_sk,
                destinations,
                outamounts,
                mix_ring,
                None,
                None,
                tx.sources[0].real_output,
            )

        # Recode for serialization
        rv = monero.recode_rct(rv, encode=True)
        self.tx.signatures = []
        self.tx.rct_signatures = rv
        del rv

        # Serialize response
        writer = xmrserialize.MemoryReaderWriter()
        ar1 = xmrserialize.Archive(writer, True)
        await ar1.message(self.tx, msg_type=xmrtypes.Transaction)

        return bytes(writer.get_buffer())
示例#26
0
 async def dump_extra_fields(self, extras):
     writer = xmrserialize.MemoryReaderWriter(preallocate=None)
     ar = xmrserialize.Archive(writer, True)
     await ar.container(extras, container_type=TxExtraFields)
     return writer.get_buffer()
示例#27
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
                ))
示例#28
0
 def __init__(self, ctx=None):
     self.kwriter = get_keccak_writer(ctx=ctx)
     self.ar = xmrserialize.Archive(self.kwriter, True)
示例#29
0
async def parse_msg(bts, msg):
    reader = xmrserialize.MemoryReaderWriter(bytearray(bts))
    ar = xmrserialize.Archive(reader, False)
    return await ar.message(msg)
示例#30
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)