Exemplo n.º 1
0
 def verify_tx_key(self, tx_priv, tx_pub, all_creds_subs):
     if crypto.point_eq(tx_pub, crypto.scalarmult_base(tx_priv)):
         return True
     for cred_idx, subs in enumerate(all_creds_subs):
         for ckey in subs:
             if crypto.point_eq(tx_pub, crypto.scalarmult(ckey, tx_priv)):
                 return True
     return False
Exemplo n.º 2
0
    def gen_clsag_sig(self, ring_size=11, index=None):
        msg = bytearray(random.getrandbits(8) for _ in range(32))
        amnt = crypto.sc_init(random.randint(0, 0xFFFFFF) + 12)
        priv = crypto.random_scalar()
        msk = crypto.random_scalar()
        alpha = crypto.random_scalar()
        P = crypto.scalarmult_base(priv)
        C = crypto.add_keys2(msk, amnt, crypto.xmr_H())
        Cp = crypto.add_keys2(alpha, amnt, crypto.xmr_H())

        ring = []
        for i in range(ring_size - 1):
            tk = TmpKey(
                crypto.encodepoint(
                    crypto.scalarmult_base(crypto.random_scalar())),
                crypto.encodepoint(
                    crypto.scalarmult_base(crypto.random_scalar())),
            )
            ring.append(tk)

        index = index if index is not None else random.randint(0, len(ring))
        ring.insert(index, TmpKey(crypto.encodepoint(P),
                                  crypto.encodepoint(C)))
        ring2 = list(ring)
        mg_buffer = []

        self.assertTrue(
            crypto.point_eq(crypto.scalarmult_base(priv),
                            crypto.decodepoint(ring[index].dest)))
        self.assertTrue(
            crypto.point_eq(
                crypto.scalarmult_base(crypto.sc_sub(msk, alpha)),
                crypto.point_sub(crypto.decodepoint(ring[index].commitment),
                                 Cp),
            ))

        mlsag2.generate_clsag_simple(
            msg,
            ring,
            CtKey(dest=priv, mask=msk),
            alpha,
            Cp,
            index,
            mg_buffer,
        )

        sD = crypto.decodepoint(mg_buffer[-1])
        sc1 = crypto.decodeint(mg_buffer[-2])
        scalars = [crypto.decodeint(x) for x in mg_buffer[1:-2]]
        H = crypto.new_point()
        sI = crypto.new_point()

        crypto.hash_to_point_into(H, crypto.encodepoint(P))
        crypto.scalarmult_into(sI, H, priv)  # I = p*H
        return msg, scalars, sc1, sI, sD, ring2, Cp
Exemplo n.º 3
0
    async def get_tx_key_test(self, agent, con_data, creds, all_creds):
        salt1 = con_data.enc_salt1
        salt2 = con_data.enc_salt2
        res = await agent.get_tx_key(salt1, salt2, con_data.enc_keys,
                                     con_data.tx_prefix_hash,
                                     creds.view_key_private)

        extras = await monero.parse_extra_fields(list(con_data.tx.extra))
        tx_pub = monero.find_tx_extra_field_by_type(extras,
                                                    xmrtypes.TxExtraPubKey, 0)
        additional_pub_keys = monero.find_tx_extra_field_by_type(
            extras, xmrtypes.TxExtraAdditionalPubKeys)

        # For verification need to build database creds -> pubkeys
        all_creds_subs = []
        for idx, ccred in enumerate(all_creds):
            subs = {}
            for accnt in range(10):
                subs = monero.compute_subaddresses(ccred, accnt, range(20),
                                                   subs)
            all_creds_subs.append(
                [crypto.decodepoint(xx) for xx in subs.keys()])

        if not self.verify_tx_key(res[0], crypto.decodepoint(tx_pub.pub_key),
                                  all_creds_subs):
            raise ValueError("Tx pub mismatch")

        if additional_pub_keys and len(
                additional_pub_keys.data) != len(res) - 1:
            raise ValueError("Invalid additional keys count")

        if additional_pub_keys:
            for i, ad in enumerate(additional_pub_keys.data):
                if not self.verify_tx_key(res[i + 1], crypto.decodepoint(ad),
                                          all_creds_subs):
                    raise ValueError("Tx additional %s pub mismatch" % i)

        my_pub = crypto.scalarmult_base(creds.view_key_private)
        res_der = await agent.get_tx_deriv(salt1, salt2, con_data.enc_keys,
                                           con_data.tx_prefix_hash,
                                           creds.view_key_private,
                                           crypto.encodepoint(my_pub))
        if len(res) != len(res_der):
            raise ValueError("Derivation array mismatch")
        tmp = crypto.scalarmult(my_pub, res[0])
        if not crypto.point_eq(tmp, res_der[0]):
            raise ValueError("Derivation 0 mismatch")

        if additional_pub_keys:
            for i in range(len(additional_pub_keys.data)):
                tmp = crypto.scalarmult(my_pub, res[i + 1])
                if not crypto.point_eq(tmp, res_der[i + 1]):
                    raise ValueError("Tx derivation additional %s mismatch" %
                                     i)
Exemplo n.º 4
0
    async def put_key(self):
        sec = crypto.decodeint(self._fetch(32))
        pub = crypto.decodepoint(self._fetch(32))
        if not crypto.point_eq(pub, crypto.scalarmult_base(sec)):
            return SW_WRONG_DATA
        self.a = sec

        sec = crypto.decodeint(self._fetch(32))
        pub = crypto.decodepoint(self._fetch(32))
        if not crypto.point_eq(pub, crypto.scalarmult_base(sec)):
            return SW_WRONG_DATA
        self.b = sec
        return SW_OK
Exemplo n.º 5
0
    async def mlsag_prehash_update(self):
        is_subaddress = 0
        Aout = None
        Bout = None
        C = None
        v = None
        k = None
        changed = 0

        is_subaddress = bool(self._fetch_u8())
        Aout = crypto.decodepoint(self._fetch())
        Bout = crypto.decodepoint(self._fetch())
        if self.sig_mode == TRANSACTION_CREATE_REAL:
            if crypto.point_eq(Aout, self.A) and crypto.point_eq(Bout, self.B):
                changed = 1

        AKout = self._fetch_decrypt()
        C = self._fetch()
        k = self._fetch()
        v = self._fetch()

        self.ctx_h.update(k)
        self.ctx_h.update(v)

        self.ctx_amount.update(AKout)

        v, k, AKout = self.unblind_int(v, k, AKout)
        self.ctx_amount.update(crypto.encodeint(k))
        self.ctx_amount.update(crypto.encodeint(v))

        vH = crypto.scalarmult_h(v)
        kG = crypto.scalarmult_base(k)
        k = crypto.point_add(kG, vH)

        if not crypto.point_eq(k, crypto.decodepoint(C)):
            raise ValueError(SW_SECURITY_COMMITMENT_CONTROL)

        self.ctx_commitment.update(C)
        if self.options & IN_OPTION_MORE_COMMAND == 0:
            k = self.ctx_amount.digest()
            if not common.ct_equal(k, self.KV):
                raise ValueError(SW_SECURITY_AMOUNT_CHAIN_CONTROL)

            self.C = self.ctx_commitment.digest()
            self.ctx_commitment = sha256()

        if self.sig_mode == TRANSACTION_CREATE_REAL:
            if not changed:
                await self._req_dst(Aout, Bout, v, is_subaddress)

        return SW_OK
Exemplo n.º 6
0
    def test_pointadd(self):
        a = crypto.random_scalar()
        A = crypto.scalarmult_base(a)
        A2 = crypto.point_add(A, A)
        A3 = crypto.point_add(A2, A)
        A4 = crypto.point_add(A3, A)
        A8 = crypto.scalarmult(A4, crypto.sc_init(2))

        A8p = crypto.point_mul8(A)
        self.assertTrue(crypto.point_eq(A8p, A8))
        self.assertTrue(
            crypto.point_eq(A4, crypto.scalarmult(A, crypto.sc_init(4))))
        self.assertTrue(
            crypto.point_eq(A3, crypto.scalarmult(A, crypto.sc_init(3))))
Exemplo n.º 7
0
def ver_range(C=None, rsig=None, use_asnl=False, decode=True):
    """
    Verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i
    :param C:
    :param rsig:
    :param use_asnl: use ASNL, used before Borromean, insecure!
    :param decode: decodes encoded range proof
    :return:
    """
    n = ATOMS
    CiH = [None] * n
    C_tmp = crypto.identity()
    c_H = crypto.gen_H()

    if decode:
        rsig = monero.recode_rangesig(rsig, encode=False, copy=True)

    for i in range(0, n):
        CiH[i] = crypto.point_sub(rsig.Ci[i], c_H)
        C_tmp = crypto.point_add(C_tmp, rsig.Ci[i])
        c_H = crypto.point_double(c_H)

    if C is not None and not crypto.point_eq(C_tmp, C):
        return 0

    if use_asnl:
        return asnl.ver_asnl(rsig.Ci, CiH, rsig.asig.s0, rsig.asig.s1,
                             rsig.asig.ee)
    else:
        return mlsag2.ver_borromean(rsig.Ci, CiH, rsig.asig.s0, rsig.asig.s1,
                                    rsig.asig.ee)
Exemplo n.º 8
0
def ver_asnl(P1, P2, L1, s2, s):
    """
    Aggregate Schnorr Non-Linkable
    :param P1:
    :param P2:
    :param L1:
    :param s2:
    :param s:
    :return:
    """
    logger.info("Verifying Aggregate Schnorr Non-linkable Ring Signature")

    n = len(P1)
    LHS = crypto.scalarmult_base(crypto.sc_0())
    RHS = crypto.scalarmult_base(s)
    for j in range(0, n):
        c2 = crypto.hash_to_scalar(crypto.encodepoint(L1[j]))
        L2 = crypto.point_add(crypto.scalarmult_base(s2[j]),
                              crypto.scalarmult(P2[j], c2))
        LHS = crypto.point_add(LHS, L1[j])
        c1 = crypto.hash_to_scalar(crypto.encodepoint(L2))
        RHS = crypto.point_add(RHS, crypto.scalarmult(P1[j], c1))

    if crypto.point_eq(LHS, RHS):
        return 1
    else:
        logger.warning("Didn't verify L1: %s, L1p: %s" %
                       (crypto.encodepoint(LHS), crypto.encodepoint(RHS)))
        return 0
Exemplo n.º 9
0
def ver_range(C=None, rsig=None, use_bulletproof=False, decode=True):
    """
    Verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i
    :param C:
    :param rsig:
    :param use_bulletproof: bulletproof
    :param decode: decodes encoded range proof
    :return:
    """
    n = ATOMS
    CiH = [None] * n
    C_tmp = crypto.identity()
    c_H = crypto.xmr_H()

    if decode and not use_bulletproof:
        rsig = monero.recode_rangesig(rsig, encode=False, copy=True)

    if not use_bulletproof:
        for i in range(0, n):
            CiH[i] = crypto.point_sub(rsig.Ci[i], c_H)
            C_tmp = crypto.point_add(C_tmp, rsig.Ci[i])
            c_H = crypto.point_double(c_H)

        if C is not None and not crypto.point_eq(C_tmp, C):
            return 0

    if use_bulletproof:
        bp = bulletproof.BulletProofBuilder()
        return bp.verify(rsig)

    return mlsag2.ver_borromean(rsig.Ci, CiH, rsig.asig.s0, rsig.asig.s1,
                                rsig.asig.ee)
Exemplo n.º 10
0
def generate_key_image_helper_precomp(
    ack, out_key, recv_derivation, real_output_index, received_index
):
    """
    Generates UTXO spending key and key image.

    :param ack: sender credentials
    :type ack: AccountCreds
    :param out_key: real output (from input RCT) destination key
    :param recv_derivation:
    :param real_output_index:
    :param received_index: subaddress index this payment was received to
    :return:
    """
    if ack.spend_key_private == 0:
        raise ValueError("Watch-only wallet not supported")

    # derive secret key with subaddress - step 1: original CN derivation
    scalar_step1 = crypto.derive_secret_key(
        recv_derivation, real_output_index, ack.spend_key_private
    )

    # step 2: add Hs(SubAddr || a || index_major || index_minor)
    subaddr_sk = None
    scalar_step2 = None
    if received_index == (0, 0):
        scalar_step2 = scalar_step1
    else:
        subaddr_sk = get_subaddress_secret_key(
            ack.view_key_private, major=received_index[0], minor=received_index[1]
        )
        scalar_step2 = crypto.sc_add(scalar_step1, subaddr_sk)

    # when not in multisig, we know the full spend secret key, so the output pubkey can be obtained by scalarmultBase
    if len(ack.multisig_keys) == 0:
        pub_ver = crypto.scalarmult_base(scalar_step2)

    else:
        # When in multisig, we only know the partial spend secret key. But we do know the full spend public key,
        # so the output pubkey can be obtained by using the standard CN key derivation.
        pub_ver = crypto.derive_public_key(
            recv_derivation, real_output_index, ack.spend_key_public
        )

        # Add the contribution from the subaddress part
        if received_index != (0, 0):
            subaddr_pk = crypto.scalarmult_base(subaddr_sk)
            pub_ver = crypto.point_add(pub_ver, subaddr_pk)

    if not crypto.point_eq(pub_ver, out_key):
        raise ValueError(
            "key image helper precomp: given output pubkey doesn't match the derived one"
        )

    ki = generate_key_image(crypto.encodepoint(pub_ver), scalar_step2)
    return scalar_step2, ki
Exemplo n.º 11
0
    def test_ge25519_double_scalarmult_vartime(self):
        for i in range(10):
            ap = crypto.random_scalar()
            A = crypto.scalarmult_base(ap)
            a = crypto.random_scalar()
            b = crypto.random_scalar()

            R = crypto.ge_double_scalarmult_base_vartime(a, A, b)
            R_exp = crypto.point_add(crypto.scalarmult(A, a), crypto.scalarmult_base(b))
            self.assertTrue(crypto.point_eq(R, R_exp))
Exemplo n.º 12
0
    def test_range_proof(self):
        proof = ring_ct.prove_range(0)
        res = ring_ct.ver_range(proof[0], proof[2])
        self.assertTrue(res)
        self.assertTrue(
            crypto.point_eq(
                proof[0],
                crypto.point_add(crypto.scalarmult_base(proof[1]),
                                 crypto.scalarmult_h(0)),
            ))

        proof = ring_ct.prove_range(0, mem_opt=False)
        res = ring_ct.ver_range(proof[0], proof[2])
        self.assertTrue(res)
        self.assertTrue(
            crypto.point_eq(
                proof[0],
                crypto.point_add(crypto.scalarmult_base(proof[1]),
                                 crypto.scalarmult_h(0)),
            ))
Exemplo n.º 13
0
 def test_encoding(self):
     point = unhexlify(
         b"2486224797d05cae3cba4be043be2db0df381f3f19cfa113f86ab38e3d8d2bd0"
     )
     self.assertEqual(point, crypto.encodepoint(crypto.decodepoint(point)))
     self.assertTrue(
         crypto.point_eq(
             crypto.decodepoint(point),
             crypto.decodepoint(
                 crypto.encodepoint(crypto.decodepoint(point))),
         ))
Exemplo n.º 14
0
    def test_scalarmult_base(self):
        scalar = crypto.decodeint(
            unhexlify(
                b"a0eea49140a3b036da30eacf64bd9d56ce3ef68ba82ef13571ec511edbcf8303"
            ))
        exp = unhexlify(
            b"16bb4a3c44e2ced511fc0d4cd86b13b3af21efc99fb0356199fac489f2544c09"
        )
        res = crypto.scalarmult_base(scalar)
        self.assertEqual(exp, crypto.encodepoint(res))
        self.assertTrue(crypto.point_eq(crypto.decodepoint(exp), res))

        scalar = crypto.decodeint(
            unhexlify(
                b"fd290dce39f781aebbdbd24584ed6d48bd300de19d9c3decfda0a6e2c6751d0f"
            ))
        exp = unhexlify(
            b"123daf90fc26f13c6529e6b49bfed498995ac383ef19c0db6771143f24ba8dd5"
        )
        res = crypto.scalarmult_base(scalar)
        self.assertEqual(exp, crypto.encodepoint(res))
        self.assertTrue(crypto.point_eq(crypto.decodepoint(exp), res))
Exemplo n.º 15
0
 def test_scalarmult(self):
     priv = unhexlify(
         b"3482fb9735ef879fcae5ec7721b5d3646e155c4fb58d6cc11c732c9c9b76620a"
     )
     pub = unhexlify(
         b"2486224797d05cae3cba4be043be2db0df381f3f19cfa113f86ab38e3d8d2bd0"
     )
     exp = unhexlify(
         b"adcd1f5881f46f254900a03c654e71950a88a0236fa0a3a946c9b8daed6ef43d"
     )
     res = crypto.scalarmult(crypto.decodepoint(pub),
                             crypto.decodeint(priv))
     self.assertEqual(exp, crypto.encodepoint(res))
     self.assertTrue(crypto.point_eq(crypto.decodepoint(exp), res))
Exemplo n.º 16
0
    async def open_with_keys(self, view_key, address):
        """
        Processess view key private + address
        :param view_key:
        :param address:
        :return:
        """
        self.pub_view = crypto.scalarmult_base(view_key)

        version, pub_spend, pub_view = monero.decode_addr(address)
        self.pub_spend = crypto.decodepoint(pub_spend)

        if not crypto.point_eq(self.pub_view, crypto.decodepoint(pub_view)):
            raise ValueError(
                "Computed view public key does not match the one from address")
Exemplo n.º 17
0
    async def amplify_inputs(self, tx, new_keys=None, new_subs=None):
        lst = tx.sources[-1]
        orig_amount = lst.amount
        partial = orig_amount // (self.args.inputs + 1)

        amnt_sum = partial
        lst.amount = partial
        commitment = crypto.encodepoint(crypto.gen_c(crypto.decodeint(lst.mask), partial))
        lst.outputs[lst.real_output][1].mask = commitment

        for i in range(1, self.args.inputs + 1):
            is_lst = i >= self.args.inputs
            new_amnt = orig_amount - amnt_sum if is_lst else partial
            amnt_sum += partial

            commitment = crypto.encodepoint(crypto.gen_c(crypto.decodeint(lst.mask), new_amnt))
            new_inp = TxSourceEntry(outputs=list(lst.outputs),
                                    real_output=lst.real_output,
                                    real_out_tx_key=lst.real_out_tx_key,
                                    real_out_additional_tx_keys=lst.real_out_additional_tx_keys,
                                    real_output_in_tx_index=lst.real_output_in_tx_index,
                                    amount=new_amnt,
                                    rct=lst.rct,
                                    mask=lst.mask,
                                    multisig_kLRki=lst.multisig_kLRki)

            # Amount changed -> update the commitment
            orig_key = new_inp.outputs[new_inp.real_output][1]
            new_inp.outputs[new_inp.real_output] = (0, CtKey(dest=orig_key.dest, mask=commitment))

            # Randomize mixin values
            for i in range(new_inp.real_output + 1, len(new_inp.outputs)):
                new_inp.outputs[i] = (0, CtKey(
                    mask=crypto.encodepoint(self.random_pub()),
                    dest=crypto.encodepoint(self.random_pub())))

                if new_inp.real_out_additional_tx_keys:
                    new_inp.real_out_additional_tx_keys[i] = crypto.encodepoint(self.random_pub())

            self.check_input(new_inp, new_keys, new_subs)

            if not crypto.point_eq(
                    crypto.decodepoint(new_inp.outputs[new_inp.real_output][1].mask),
                    crypto.gen_c(crypto.decodeint(new_inp.mask), new_inp.amount),
                ): raise ValueError("Real source entry's mask does not equal spend key's")

            tx.sources.append(new_inp)
Exemplo n.º 18
0
def ecdh_decode_simple(rv, sk, i):
    """
    Decodes ECDH from the transaction, checks mask (decoding validity).
    """
    if i >= len(rv.ecdhInfo):
        raise ValueError("Bad index")
    if len(rv.outPk) != len(rv.ecdhInfo):
        raise ValueError("outPk vs ecdhInfo mismatch")

    ecdh_info = rv.ecdhInfo[i]
    ecdh_info = recode_ecdh(ecdh_info, False)
    ecdh_info = ring_ct.ecdh_decode(ecdh_info, derivation=crypto.encodeint(sk))
    c_tmp = crypto.add_keys2(ecdh_info.mask, ecdh_info.amount, crypto.xmr_H())
    if not crypto.point_eq(c_tmp, crypto.decodepoint(rv.outPk[i].mask)):
        raise ValueError("Amount decoded incorrectly")

    return ecdh_info.amount, ecdh_info.mask
Exemplo n.º 19
0
 def test_encoding(self):
     point = bytes(
         [
             0x24,
             0x86,
             0x22,
             0x47,
             0x97,
             0xd0,
             0x5c,
             0xae,
             0x3c,
             0xba,
             0x4b,
             0xe0,
             0x43,
             0xbe,
             0x2d,
             0xb0,
             0xdf,
             0x38,
             0x1f,
             0x3f,
             0x19,
             0xcf,
             0xa1,
             0x13,
             0xf8,
             0x6a,
             0xb3,
             0x8e,
             0x3d,
             0x8d,
             0x2b,
             0xd0,
         ]
     )
     self.assertEqual(point, crypto.encodepoint(crypto.decodepoint(point)))
     self.assertTrue(
         crypto.point_eq(
             crypto.decodepoint(point),
             crypto.decodepoint(crypto.encodepoint(crypto.decodepoint(point))),
         )
     )
Exemplo n.º 20
0
def decode_rct(rv, sk, i):
    """
    c.f. http:#eprint.iacr.org/2015/1098 section 5.1.1
    Uses the attached ecdh info to find the amounts represented by each output commitment
    must know the destination private key to find the correct amount, else will return a random number

    :param rv:
    :param sk:
    :param i:
    :return:
    """
    decodedTuple = ecdh_decode(rv.ecdhInfo[i], sk)
    mask = decodedTuple.mask
    amount = decodedTuple.amount
    C = rv.outPk[i].mask
    H = crypto.xmr_H()
    Ctmp = crypto.point_add(crypto.scalarmult_base(mask), crypto.scalarmult(H, amount))
    if not crypto.point_eq(crypto.point_sub(C, Ctmp), crypto.identity()):
        logger.warning("warning, amount decoded incorrectly, will be unable to spend")
    return amount
Exemplo n.º 21
0
    async def verify_key(self):
        priv = self._fetch_decrypt_key()
        pub = crypto.decodepoint(self._fetch())
        computed_pub = crypto.identity()
        verified = 0

        if self.c_p1 == 0:
            computed_pub = crypto.scalarmult_base(priv)
        elif self.c_p1 == 1:
            pub = self.A
        elif self.c_p1 == 2:
            pub = self.B
        else:
            return SW_WRONG_P1P2

        if crypto.point_eq(computed_pub, pub):
            verified = 1

        self._insert_u32(verified)
        self._insert(self.creds.address)
        return SW_OK
Exemplo n.º 22
0
    def test_range_proof2(self):
        amount = 17 + (1 << 60)
        proof = ring_ct.prove_range(amount)
        res = ring_ct.ver_range(proof[0], proof[2])
        self.assertTrue(res)
        self.assertTrue(
            crypto.point_eq(
                proof[0],
                crypto.point_add(crypto.scalarmult_base(proof[1]),
                                 crypto.scalarmult_h(amount)),
            ))

        proof = ring_ct.prove_range(amount, mem_opt=False, decode=True)
        res = ring_ct.ver_range(proof[0], proof[2], decode=False)
        self.assertTrue(res)

        res = ring_ct.ver_range(
            crypto.point_add(proof[0],
                             crypto.scalarmult_base(crypto.sc_init(4))),
            proof[2],
            decode=False,
        )
        self.assertFalse(res)
Exemplo n.º 23
0
    async def test_live_refresh(self):
        if self.should_test_only_tx() or not int(
                os.getenv("TREZOR_TEST_LIVE_REFRESH", '1')):
            self.skipTest("Live refresh skipped")

        creds = self.get_trezor_creds(0)
        await self.agent.live_refresh_start()
        for att in range(22):
            r = crypto.random_scalar()
            R = crypto.scalarmult_base(r)
            D = crypto.scalarmult(R, creds.view_key_private)
            subaddr = 0, att

            scalar_step1 = crypto.derive_secret_key(D, att,
                                                    creds.spend_key_private)

            # step 2: add Hs(SubAddr || a || index_major || index_minor)
            if subaddr == (0, 0):
                scalar_step2 = scalar_step1
            else:
                subaddr_sk = monero.get_subaddress_secret_key(
                    creds.view_key_private, major=0, minor=att)
                scalar_step2 = crypto.sc_add(scalar_step1, subaddr_sk)

            pub_ver = crypto.scalarmult_base(scalar_step2)
            ki = monero.generate_key_image(crypto.encodepoint(pub_ver),
                                           scalar_step2)

            ki2 = await self.agent.live_refresh(creds.view_key_private,
                                                crypto.encodepoint(pub_ver),
                                                crypto.encodepoint(D), att, 0,
                                                att)

            if not crypto.point_eq(ki, ki2):
                raise ValueError("Key image inconsistent")
            time.sleep(0.1)
        await self.agent.live_refresh_final()
Exemplo n.º 24
0
def generate_ring_signature(prefix_hash,
                            image,
                            pubs,
                            sec,
                            sec_idx,
                            test=False):
    """
    Generates ring signature with key image.
    void crypto_ops::generate_ring_signature()
    """
    if test:
        t = crypto.scalarmult_base(sec)
        if not crypto.point_eq(t, pubs[sec_idx]):
            raise ValueError("Invalid sec key")

        k_i = monero.generate_key_image(crypto.encodepoint(pubs[sec_idx]), sec)
        if not crypto.point_eq(k_i, image):
            raise ValueError("Key image invalid")
        for k in pubs:
            crypto.ge_frombytes_vartime_check(k)

    image_unp = crypto.ge_frombytes_vartime(image)
    image_pre = crypto.ge_dsm_precomp(image_unp)

    buff_off = len(prefix_hash)
    buff = bytearray(buff_off + 2 * 32 * len(pubs))
    memcpy(buff, 0, prefix_hash, 0, buff_off)
    mvbuff = memoryview(buff)

    sum = crypto.sc_0()
    k = crypto.sc_0()
    sig = []
    for i in range(len(pubs)):
        sig.append([crypto.sc_0(), crypto.sc_0()])  # c, r

    for i in range(len(pubs)):
        if i == sec_idx:
            k = crypto.random_scalar()
            tmp3 = crypto.scalarmult_base(k)
            crypto.encodepoint_into(mvbuff[buff_off:buff_off + 32], tmp3)
            buff_off += 32

            tmp3 = crypto.hash_to_point(crypto.encodepoint(pubs[i]))
            tmp2 = crypto.scalarmult(tmp3, k)
            crypto.encodepoint_into(mvbuff[buff_off:buff_off + 32], tmp2)
            buff_off += 32

        else:
            sig[i] = [crypto.random_scalar(), crypto.random_scalar()]
            tmp3 = crypto.ge_frombytes_vartime(pubs[i])
            tmp2 = crypto.ge_double_scalarmult_base_vartime(
                sig[i][0], tmp3, sig[i][1])
            crypto.encodepoint_into(mvbuff[buff_off:buff_off + 32], tmp2)
            buff_off += 32

            tmp3 = crypto.hash_to_point(crypto.encodepoint(tmp3))
            tmp2 = crypto.ge_double_scalarmult_precomp_vartime(
                sig[i][1], tmp3, sig[i][0], image_pre)
            crypto.encodepoint_into(mvbuff[buff_off:buff_off + 32], tmp2)
            buff_off += 32

            sum = crypto.sc_add(sum, sig[i][0])

    h = crypto.hash_to_scalar(buff)
    sig[sec_idx][0] = crypto.sc_sub(h, sum)
    sig[sec_idx][1] = crypto.sc_mulsub(sig[sec_idx][0], sec, k)
    return sig
Exemplo n.º 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())
Exemplo n.º 26
0
    async def gen_rct_header(self, destinations, outamounts):
        """
        Initializes RV RctSig structure, processes outputs, computes range proofs, ecdh info masking.
        Common to gen_rct and gen_rct_simple.

        :param destinations:
        :param outamounts:
        :return:
        """
        rv = xmrtypes.RctSig()
        rv.p = xmrtypes.RctSigPrunable()

        rv.message = self.tx_prefix_hash
        rv.outPk = [None] * len(destinations)

        if self.use_bulletproof:
            rv.p.bulletproofs = [None] * len(destinations)
        else:
            rv.p.rangeSigs = [None] * len(destinations)
        rv.ecdhInfo = [None] * len(destinations)

        # Output processing
        sumout = crypto.sc_0()
        out_sk = [None] * len(destinations)
        for idx in range(len(destinations)):
            rv.outPk[idx] = xmrtypes.CtKey(dest=crypto.encodepoint(destinations[idx]))
            C, mask, rsig = None, 0, None

            # Rangeproof
            if self.use_bulletproof:
                raise ValueError("Bulletproof not yet supported")

            else:
                C, mask, rsig = ring_ct.prove_range(outamounts[idx])
                rv.p.rangeSigs[idx] = rsig
                if __debug__:
                    assert ring_ct.ver_range(C, rsig)
                    assert crypto.point_eq(
                        C,
                        crypto.point_add(
                            crypto.scalarmult_base(mask),
                            crypto.scalarmult_h(outamounts[idx]),
                        ),
                    )

            # Mask sum
            rv.outPk[idx].mask = crypto.encodepoint(C)
            sumout = crypto.sc_add(sumout, mask)
            out_sk[idx] = xmrtypes.CtKey(mask=mask)

            # ECDH masking
            amount_key = crypto.encodeint(self.output_secrets[idx][0])
            rv.ecdhInfo[idx] = xmrtypes.EcdhTuple(
                mask=mask, amount=crypto.sc_init(outamounts[idx])
            )
            rv.ecdhInfo[idx] = ring_ct.ecdh_encode(
                rv.ecdhInfo[idx], derivation=amount_key
            )
            monero.recode_ecdh(rv.ecdhInfo[idx], encode=True)

        return rv, sumout, out_sk
Exemplo n.º 27
0
    async def describe(self, inp, unsigned_txs, keys, key_subs):
        print("\nInp: %s, #txs: %s, #transfers: %s" % (inp, len(unsigned_txs.txes), len(unsigned_txs.transfers)))
        for txid, tx in enumerate(unsigned_txs.txes):
            srcs = tx.sources
            dsts = tx.splitted_dsts
            extra = tx.extra
            change = tx.change_dts
            account = tx.subaddr_account
            subs = tx.subaddr_indices
            mixin = len(srcs[0].outputs) - 1
            amnt_in = sum([x.amount for x in srcs])
            amnt_out = sum([x.amount for x in dsts])
            fee = amnt_in - amnt_out
            n_inp_additional = sum(
                [1 for x in srcs if len(x.real_out_additional_tx_keys) > 0]
            )

            change_addr = (
                addr.build_address(
                    change.addr.m_spend_public_key, change.addr.m_view_public_key
                )
                if change
                else None
            )
            out_txs2 = await self.reformat_outs(dsts)

            num_stdaddresses, num_subaddresses, single_dest_subaddress = addr.classify_subaddresses(
                out_txs2, change_addr
            )

            print(
                "  tx: %s, #inp: %2d, #inp_add: %2d, #out: %2d, mixin: %2d, acc: %s, subs: %s, "
                "xmr_in: %10.6f, xmr_out: %10.6f, fee: %10.6f, change: %10.6f, out_clean: %10.6f"
                % (
                    txid,
                    len(srcs),
                    n_inp_additional,
                    len(dsts),
                    mixin,
                    account,
                    subs,
                    wallet.conv_disp_amount(amnt_in),
                    wallet.conv_disp_amount(amnt_out),
                    wallet.conv_disp_amount(fee),
                    wallet.conv_disp_amount(change.amount) if change else 0,
                    wallet.conv_disp_amount(
                        (amnt_out - change.amount) if change else amnt_out
                    ),
                )
            )
            print(
                "  Out: num_std: %2d, num_sub: %2d, single_dest_sub: %s, total: %s"
                % (
                    num_stdaddresses,
                    num_subaddresses,
                    1 if single_dest_subaddress else 0,
                    len(dsts),
                )
            )

            accounts = set()
            subs = set()
            for inp in srcs:
                res = await self.analyze_input(keys, key_subs, inp)
                accounts.add(res[0])
                if res != (0, 0):
                    subs.add(res)

            print("  Ins: accounts: %s, subs: %s" % (accounts, len(subs)))

            extras = await monero.parse_extra_fields(extra)
            extras_val = []
            for c in extras:
                if isinstance(c, TxExtraPubKey):
                    extras_val.append("TxKey")
                elif isinstance(c, TxExtraNonce):
                    extras_val.append(
                        "Nonce: %s" % binascii.hexlify(c.nonce).decode("ascii")
                    )
                elif isinstance(c, TxExtraAdditionalPubKeys):
                    extras_val.append("AdditionalTxKeys: %s" % len(c.data))
                else:
                    extras_val.append(str(c))
            print("  Extras: %s" % ", ".join(extras_val))

            # Final verification
            for idx, inp in enumerate(tx.sources):
                self.check_input(inp, keys, key_subs)
                if not crypto.point_eq(
                        crypto.decodepoint(inp.outputs[inp.real_output][1].mask),
                        crypto.gen_c(crypto.decodeint(inp.mask), inp.amount),
                ): raise ValueError("Real source entry's mask does not equal spend key's. Inp: %d" % idx)
Exemplo n.º 28
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)
Exemplo n.º 29
0
    def rekey_input(self, inp, keys, subs=None, new_keys=None, new_subs=None, mixin_change=None):
        subs = subs if subs else {}
        real_out_key = inp.outputs[inp.real_output][1]
        out_key = crypto.decodepoint(real_out_key.dest)
        tx_key = crypto.decodepoint(inp.real_out_tx_key)
        additional_keys = [
            crypto.decodepoint(x) for x in inp.real_out_additional_tx_keys
        ]

        logger.debug("Current out key: %s" % binascii.hexlify(real_out_key.dest))
        secs = monero.generate_key_image_helper(
            keys, subs, out_key, tx_key, additional_keys, inp.real_output_in_tx_index
        )
        xi, ki, di = secs

        need_additional = additional_keys is not None and len(additional_keys) > 0
        is_dst_sub = self.dest_sub_major != 0 and (
            self.args.minors[0] != 0 or len(self.args.minors) > 1
        )
        logger.debug(
            "Is dst sub: %s, need additional: %s" % (is_dst_sub, need_additional)
        )

        if is_dst_sub and self.add_additionals:
            need_additional = True

        if is_dst_sub:
            rand_minor = random.choice(self.args.minors)
            m = monero.get_subaddress_secret_key(
                new_keys.view_key_private, major=self.dest_sub_major, minor=rand_minor
            )
            M = crypto.scalarmult_base(m)
            d = crypto.sc_add(m, new_keys.spend_key_private)
            D = crypto.point_add(new_keys.spend_key_public, M)
            C = crypto.scalarmult(D, new_keys.view_key_private)

        if not need_additional and not is_dst_sub:
            # real_out_key.dst = Hs(R*new_a || idx)G + newB
            r = crypto.random_scalar()
            tx_key = crypto.scalarmult_base(r)
            new_deriv = crypto.generate_key_derivation(new_keys.view_key_public, r)
            new_out_pr = crypto.derive_secret_key(
                new_deriv, inp.real_output_in_tx_index, new_keys.spend_key_private
            )
            new_out = crypto.scalarmult_base(new_out_pr)
            real_out_key.dest = crypto.encodepoint(new_out)

        elif not need_additional and is_dst_sub:
            # real_out_key.dst = Hs(r*C || idx)G + newB, R=rD
            r = crypto.random_scalar()
            tx_key = crypto.scalarmult(D, r)
            new_deriv = crypto.generate_key_derivation(C, r)
            new_out_pr = crypto.derive_secret_key(
                new_deriv, inp.real_output_in_tx_index, d
            )
            new_out = crypto.scalarmult_base(new_out_pr)
            real_out_key.dest = crypto.encodepoint(new_out)

        else:
            r = crypto.random_scalar()
            tx_key = crypto.scalarmult_base(r)

            gen_additionals = min(2, inp.real_output_in_tx_index + 1)
            if additional_keys is None or len(additional_keys) < gen_additionals:
                additional_keys = [
                    crypto.scalarmult_base(crypto.random_scalar())
                    for _ in range(gen_additionals)
                ]

            ri = crypto.random_scalar()
            if is_dst_sub:
                add_tx = crypto.scalarmult(D, ri)
                new_deriv = crypto.generate_key_derivation(C, ri)
                new_out_pr = crypto.derive_secret_key(
                    new_deriv, inp.real_output_in_tx_index, d
                )
                new_out = crypto.scalarmult_base(new_out_pr)
                if not crypto.point_eq(
                    new_out,
                    crypto.derive_public_key(new_deriv, inp.real_output_in_tx_index, D),
                ):
                    raise ValueError("Invalid txout computation")

            else:
                add_tx = crypto.scalarmult_base(ri)
                new_deriv = crypto.generate_key_derivation(new_keys.view_key_public, r)
                new_out_pr = crypto.derive_secret_key(
                    new_deriv, inp.real_output_in_tx_index, new_keys.spend_key_private
                )
                new_out = crypto.scalarmult_base(new_out_pr)

            additional_keys[inp.real_output_in_tx_index] = add_tx
            real_out_key.dest = crypto.encodepoint(new_out)

        # Increasing the size of the mixin
        if mixin_change and len(inp.outputs) < mixin_change:
            for i in range(mixin_change - len(inp.outputs)):
                inp.outputs.append((0, CtKey(
                    mask=crypto.encodepoint(self.random_pub()),
                    dest=crypto.encodepoint(self.random_pub()))))
                if additional_keys:
                    additional_keys.append(self.random_pub())

        inp.real_out_tx_key = crypto.encodepoint(tx_key)
        inp.real_out_additional_tx_keys = [
            crypto.encodepoint(x) for x in additional_keys
        ]

        logger.debug("New pub: %s" % binascii.hexlify(real_out_key.dest))

        # Self-check
        self.check_input(inp, new_keys, new_subs)
        return inp
Exemplo n.º 30
0
 def __eq__(self, other):
     if other == INFINITY:
         return crypto.point_eq(self._key, crypto.identity())
     return crypto.point_eq(self._key, other._key)