Example #1
0
    def mask_consistency_check(self, bpi):
        sv = [crypto.sc_init(123)]
        gamma = [crypto.sc_init(432)]

        M, logM, aL, aR, V, gamma = bpi.prove_setup(sv, gamma)
        x = bp._ensure_dst_key()
        y = bp._ensure_dst_key()

        sL = bpi.sL_vct(64)
        sR = bpi.sR_vct(64)

        self.assertEqual(sL.to(0, x), sL.to(0, y))
        self.assertEqual(sL.to(1, x), sL.to(1, y))
        self.assertEqual(sL.to(63, x), sL.to(63, y))
        self.assertNotEqual(sL.to(1, x), sL.to(0, y))
        self.assertNotEqual(sL.to(10, x), sL.to(0, y))

        self.assertEqual(sR.to(0, x), sR.to(0, y))
        self.assertEqual(sR.to(1, x), sR.to(1, y))
        self.assertEqual(sR.to(63, x), sR.to(63, y))
        self.assertNotEqual(sR.to(1, x), sR.to(0, y))

        self.assertNotEqual(sL.to(0, x), sR.to(0, y))
        self.assertNotEqual(sL.to(1, x), sR.to(1, y))
        self.assertNotEqual(sL.to(63, x), sR.to(63, y))

        ve1 = bp._ensure_dst_key()
        ve2 = bp._ensure_dst_key()
        bpi.vector_exponent(aL, aR, ve1)
        bpi.vector_exponent(aL, aR, ve2)

        bpi.vector_exponent(sL, sR, ve1)
        bpi.vector_exponent(sL, sR, ve2)
        self.assertEqual(ve1, ve2)
Example #2
0
    def test_prove(self):
        bpi = bp.BulletProofBuilder()
        val = crypto.sc_init(123)
        mask = crypto.sc_init(432)

        bp_res = bpi.prove(val, mask)
        bpi.verify(bp_res)
Example #3
0
    def test_prove_testnet(self):
        bpi = bp.BulletProofBuilder()
        val = crypto.sc_init(123)
        mask = crypto.sc_init(432)

        bp_res = bpi.prove_testnet(val, mask)
        bpi.verify_testnet(bp_res)

        try:
            bp_res.S[0] += 1
            bpi.verify(bp_res)
            self.fail("Verification should have failed")
        except:
            pass
Example #4
0
    def test_prove_2(self):
        bpi = bp.BulletProofBuilder()
        val = crypto.sc_init((1 << 30) - 1 + 16)
        mask = crypto.random_scalar()

        bp_res = bpi.prove(val, mask)
        bpi.verify(bp_res)
Example #5
0
 def test_clsag_invalid_Cp(self):
     res = self.gen_clsag_sig(ring_size=11, index=5)
     msg, scalars, sc1, sI, sD, ring2, Cp = res
     with self.assertRaises(ValueError):
         Cp = crypto.point_add(Cp,
                               crypto.scalarmult_base(crypto.sc_init(1)))
         self.verify_clsag(msg, scalars, sc1, sI, sD, ring2, Cp)
Example #6
0
    def test_prove_random_masks(self):
        bpi = bp.BulletProofBuilder()
        bpi.use_det_masks = False  # trully randomly generated mask vectors
        val = crypto.sc_init((1 << 30) - 1 + 16)
        mask = crypto.random_scalar()

        bp_res = bpi.prove(val, mask)
        bpi.verify(bp_res)
Example #7
0
    def ctest_multiexp(self):
        scalars = [0, 1, 2, 3, 4, 99]
        point_base = [0, 2, 4, 7, 12, 18]
        scalar_sc = [crypto.sc_init(x) for x in scalars]
        points = [crypto.scalarmult_base(crypto.sc_init(x)) for x in point_base]

        muex = bp.MultiExp(scalars=[crypto.encodeint(x) for x in scalar_sc],
                           point_fnc=lambda i, d: crypto.encodepoint(points[i]))

        self.assertEqual(len(muex), len(scalars))
        res = bp.multiexp(None, muex)
        res2 = bp.vector_exponent_custom(
            A=bp.KeyVEval(3, lambda i, d: crypto.encodepoint_into(crypto.scalarmult_base(crypto.sc_init(point_base[i])), d)),
            B=bp.KeyVEval(3, lambda i, d: crypto.encodepoint_into(crypto.scalarmult_base(crypto.sc_init(point_base[3+i])), d)),
            a=bp.KeyVEval(3, lambda i, d: crypto.encodeint_into(crypto.sc_init(scalars[i]), d),),
            b=bp.KeyVEval(3, lambda i, d: crypto.encodeint_into(crypto.sc_init(scalars[i+3]), d)),
        )
        self.assertEqual(res, res2)
Example #8
0
def prove_range_bp_batch(amounts, masks):
    """Calculates Bulletproof in batches"""
    from apps.monero.xmr import bulletproof as bp

    bpi = bp.BulletProofBuilder()
    bp_proof = bpi.prove_batch([crypto.sc_init(a) for a in amounts], masks)
    del (bpi, bp)
    gc.collect()

    return bp_proof
Example #9
0
    def gen_clsag_sig(self, ring_size=11, index=None):
        msg = random.bytes(32)
        amnt = crypto.sc_init(random.uniform(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.uniform(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),
            ))

        mlsag.generate_clsag_simple(
            msg,
            ring,
            CtKey(priv, 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
Example #10
0
async def all_inputs_set(state: State):
    state.mem_trace(0)

    await confirms.transaction_step(state.ctx, state.STEP_ALL_IN)

    from trezor.messages.MoneroTransactionAllInputsSetAck import (
        MoneroTransactionAllInputsSetAck, )
    from trezor.messages.MoneroTransactionRsigData import MoneroTransactionRsigData

    # Generate random commitment masks to be used in range proofs.
    # If SimpleRCT is used the sum of the masks must match the input masks sum.
    state.sumout = crypto.sc_init(0)
    for i in range(state.output_count):
        cur_mask = crypto.new_scalar()  # new mask for each output
        is_last = i + 1 == state.output_count
        if is_last and state.rct_type == RctType.Simple:
            # in SimpleRCT the last mask needs to be calculated as an offset of the sum
            crypto.sc_sub_into(cur_mask, state.sumpouts_alphas, state.sumout)
        else:
            crypto.random_scalar(cur_mask)

        crypto.sc_add_into(state.sumout, state.sumout, cur_mask)
        state.output_masks.append(cur_mask)

    if state.rct_type == RctType.Simple:
        utils.ensure(crypto.sc_eq(state.sumout, state.sumpouts_alphas),
                     "Invalid masks sum")  # sum check
    state.sumout = crypto.sc_init(0)

    rsig_data = MoneroTransactionRsigData()
    resp = MoneroTransactionAllInputsSetAck(rsig_data=rsig_data)

    # If range proofs are being offloaded, we send the masks to the host, which uses them
    # to create the range proof. If not, we do not send any and we use them in the following step.
    if state.rsig_offload:
        tmp_buff = bytearray(32)
        rsig_data.mask = bytearray(32 * state.output_count)
        for i in range(state.output_count):
            crypto.encodeint_into(tmp_buff, state.output_masks[i])
            utils.memcpy(rsig_data.mask, 32 * i, tmp_buff, 0, 32)

    return resp
Example #11
0
def _ecdh_encode(amount: int, amount_key: bytes) -> EcdhTuple:
    """
    Output recipients decode amounts from EcdhTuple structure.
    """
    from apps.monero.xmr.serialize_messages.tx_ecdh import EcdhTuple

    ecdh_info = EcdhTuple(mask=crypto.NULL_KEY_ENC, amount=bytearray(32))
    amnt = crypto.sc_init(amount)
    crypto.encodeint_into(ecdh_info.amount, amnt)
    crypto.xor8(ecdh_info.amount, _ecdh_hash(amount_key))
    return ecdh_info
async def all_inputs_set(state: State) -> MoneroTransactionAllInputsSetAck:
    state.mem_trace(0)

    await layout.transaction_step(state, state.STEP_ALL_IN)

    from trezor.messages import MoneroTransactionAllInputsSetAck

    if state.last_step != state.STEP_VINI:
        raise ValueError("Invalid state transition")
    if state.current_input_index != state.input_count - 1:
        raise ValueError("Invalid input count")

    # The sum of the masks must match the input masks sum.
    state.sumout = crypto.sc_init(0)
    state.last_step = state.STEP_ALL_IN
    resp = MoneroTransactionAllInputsSetAck()
    return resp
Example #13
0
async def all_inputs_set(state: State):
    state.mem_trace(0)

    await confirms.transaction_step(state.ctx, state.STEP_ALL_IN)

    from trezor.messages.MoneroTransactionAllInputsSetAck import (
        MoneroTransactionAllInputsSetAck, )

    # Generate random commitment masks to be used in range proofs.
    # If SimpleRCT is used the sum of the masks must match the input masks sum.
    state.sumout = crypto.sc_init(0)
    rsig_data = None

    # Client 0, HF9. Non-deterministic masks
    if not state.is_det_mask():
        rsig_data = await _compute_masks(state)

    resp = MoneroTransactionAllInputsSetAck(rsig_data=rsig_data)
    return resp
Example #14
0
def _ecdh_encode(mask, amount, amount_key):
    """
    Output recipients need be able to reconstruct the amount commitments.
    This means the blinding factor `mask` and `amount` must be communicated
    to the receiver somehow.

    The mask and amount are stored as:
    - mask = mask + Hs(amount_key)
    - amount = amount + Hs(Hs(amount_key))
    Because the receiver can derive the `amount_key` they can
    easily derive both mask and amount as well.
    """
    from apps.monero.xmr.serialize_messages.tx_ecdh import EcdhTuple

    ecdh_info = EcdhTuple(mask=mask, amount=crypto.sc_init(amount))
    amount_key_hash_single = crypto.hash_to_scalar(amount_key)
    amount_key_hash_double = crypto.hash_to_scalar(
        crypto.encodeint(amount_key_hash_single))

    ecdh_info.mask = crypto.sc_add(ecdh_info.mask, amount_key_hash_single)
    ecdh_info.amount = crypto.sc_add(ecdh_info.amount, amount_key_hash_double)
    return _recode_ecdh(ecdh_info)
def _ecdh_encode(mask, amount, amount_key, v2=False):
    """
    Output recipients need be able to reconstruct the amount commitments.
    This means the blinding factor `mask` and `amount` must be communicated
    to the receiver somehow.

    The mask and amount are stored as:
    - mask = mask + Hs(amount_key)
    - amount = amount + Hs(Hs(amount_key))
    Because the receiver can derive the `amount_key` they can
    easily derive both mask and amount as well.
    """
    from apps.monero.xmr.serialize_messages.tx_ecdh import EcdhTuple

    ecdh_info = EcdhTuple(mask=mask, amount=crypto.sc_init(amount))

    if v2:
        amnt = ecdh_info.amount
        ecdh_info.mask = crypto.NULL_KEY_ENC
        ecdh_info.amount = bytearray(32)
        crypto.encodeint_into(ecdh_info.amount, amnt)
        crypto.xor8(ecdh_info.amount, _ecdh_hash(amount_key))
        return ecdh_info

    else:
        amount_key_hash_single = crypto.hash_to_scalar(amount_key)
        amount_key_hash_double = crypto.hash_to_scalar(
            crypto.encodeint(amount_key_hash_single))

        # Not modifying passed mask, is reused in BP.
        ecdh_info.mask = crypto.sc_add(ecdh_info.mask, amount_key_hash_single)
        crypto.sc_add_into(ecdh_info.amount, ecdh_info.amount,
                           amount_key_hash_double)
        ecdh_info.mask = crypto.encodeint(ecdh_info.mask)
        ecdh_info.amount = crypto.encodeint(ecdh_info.amount)
        return ecdh_info
Example #16
0
async def _compute_masks(state: State):
    """
    Output masks computed in advance. Used with client_version=0 && HF9.
    After HF10 (included) masks are deterministic, computed from the amount_key.

    After all client update to v1 this code will be removed.
    In order to preserve client_version=0 compatibility the masks have to be adjusted.
    """
    from trezor.messages.MoneroTransactionRsigData import MoneroTransactionRsigData
    from apps.monero.signing import offloading_keys

    rsig_data = MoneroTransactionRsigData()

    # If range proofs are being offloaded, we send the masks to the host, which uses them
    # to create the range proof. If not, we do not send any and we use them in the following step.
    if state.rsig_offload:
        rsig_data.mask = []

    # Deterministic masks, the last one is computed to balance the sums
    for i in range(state.output_count):
        if i + 1 == state.output_count:
            cur_mask = crypto.sc_sub(state.sumpouts_alphas, state.sumout)
            state.output_last_mask = cur_mask
        else:
            cur_mask = offloading_keys.det_comm_masks(state.key_enc, i)

        crypto.sc_add_into(state.sumout, state.sumout, cur_mask)

        if state.rsig_offload:
            rsig_data.mask.append(crypto.encodeint(cur_mask))

    if not crypto.sc_eq(state.sumpouts_alphas, state.sumout):
        raise ValueError("Sum eq error")

    state.sumout = crypto.sc_init(0)
    return rsig_data
Example #17
0
    async def diag(ctx, msg, **kwargs):
        log.debug(__name__, "----diagnostics")
        gc.collect()

        if msg.ins == 0:
            check_mem(0)
            return retit()

        elif msg.ins == 1:
            check_mem(1)
            micropython.mem_info(1)
            return retit()

        elif msg.ins == 2:
            log.debug(__name__, "_____________________________________________")
            log.debug(__name__, "_____________________________________________")
            log.debug(__name__, "_____________________________________________")
            return retit()

        elif msg.ins == 3:
            pass

        elif msg.ins == 4:
            total = 0
            monero = 0

            for k, v in sys.modules.items():
                log.info(__name__, "Mod[%s]: %s", k, v)
                total += 1
                if k.startswith("apps.monero"):
                    monero += 1
            log.info(__name__, "Total modules: %s, Monero modules: %s", total, monero)
            return retit()

        elif msg.ins in [5, 6, 7]:
            check_mem()
            from apps.monero.xmr import bulletproof as bp

            check_mem("BP Imported")
            from apps.monero.xmr import crypto

            check_mem("Crypto Imported")

            bpi = bp.BulletProofBuilder()
            bpi.gc_fnc = gc.collect
            bpi.gc_trace = log_trace

            vals = [crypto.sc_init((1 << 30) - 1 + 16), crypto.sc_init(22222)]
            masks = [crypto.random_scalar(), crypto.random_scalar()]
            check_mem("BP pre input")

            if msg.ins == 5:
                bp_res = bpi.prove_testnet(vals[0], masks[0])
                check_mem("BP post prove")
                bpi.verify_testnet(bp_res)
                check_mem("BP post verify")

            elif msg.ins == 6:
                bp_res = bpi.prove(vals[0], masks[0])
                check_mem("BP post prove")
                bpi.verify(bp_res)
                check_mem("BP post verify")

            elif msg.ins == 7:
                bp_res = bpi.prove_batch(vals, masks)
                check_mem("BP post prove")
                bpi.verify(bp_res)
                check_mem("BP post verify")

            return retit()

        return retit()
Example #18
0
 def test_prove_batch16(self):
     bpi = bp.BulletProofBuilder()
     sv = [crypto.sc_init(137*i) for i in range(16)]
     gamma = [crypto.sc_init(991*i) for i in range(16)]
     proof = bpi.prove_batch(sv, gamma)
     bpi.verify_batch([proof])
Example #19
0
 def test_prove_batch(self):
     bpi = bp.BulletProofBuilder()
     sv = [crypto.sc_init(123), crypto.sc_init(768)]
     gamma = [crypto.sc_init(456), crypto.sc_init(901)]
     proof = bpi.prove_batch(sv, gamma)
     bpi.verify_batch([proof])
Example #20
0
def prove_range_borromean(amount, last_mask):
    """Calculates Borromean range proof"""
    # The large chunks allocated first to avoid potential memory fragmentation issues.
    ai = bytearray(32 * 64)
    alphai = bytearray(32 * 64)
    Cis = bytearray(32 * 64)
    s0s = bytearray(32 * 64)
    s1s = bytearray(32 * 64)
    buff = bytearray(32)
    ee_bin = bytearray(32)

    a = crypto.sc_init(0)
    si = crypto.sc_init(0)
    c = crypto.sc_init(0)
    ee = crypto.sc_init(0)
    tmp_ai = crypto.sc_init(0)
    tmp_alpha = crypto.sc_init(0)

    C_acc = crypto.identity()
    C_h = crypto.xmr_H()
    C_tmp = crypto.identity()
    L = crypto.identity()
    kck = crypto.get_keccak()

    for ii in range(64):
        crypto.random_scalar(tmp_ai)
        if last_mask is not None and ii == 63:
            crypto.sc_sub_into(tmp_ai, last_mask, a)

        crypto.sc_add_into(a, a, tmp_ai)
        crypto.random_scalar(tmp_alpha)

        crypto.scalarmult_base_into(L, tmp_alpha)
        crypto.scalarmult_base_into(C_tmp, tmp_ai)

        # if 0: C_tmp += Zero (nothing is added)
        # if 1: C_tmp += 2^i*H
        # 2^i*H is already stored in C_h
        if (amount >> ii) & 1 == 1:
            crypto.point_add_into(C_tmp, C_tmp, C_h)

        crypto.point_add_into(C_acc, C_acc, C_tmp)

        # Set Ci[ii] to sigs
        crypto.encodepoint_into(Cis, C_tmp, ii << 5)
        crypto.encodeint_into(ai, tmp_ai, ii << 5)
        crypto.encodeint_into(alphai, tmp_alpha, ii << 5)

        if ((amount >> ii) & 1) == 0:
            crypto.random_scalar(si)
            crypto.encodepoint_into(buff, L)
            crypto.hash_to_scalar_into(c, buff)

            crypto.point_sub_into(C_tmp, C_tmp, C_h)
            crypto.add_keys2_into(L, si, c, C_tmp)

            crypto.encodeint_into(s1s, si, ii << 5)

        crypto.encodepoint_into(buff, L)
        kck.update(buff)

        crypto.point_double_into(C_h, C_h)

    # Compute ee
    tmp_ee = kck.digest()
    crypto.decodeint_into(ee, tmp_ee)
    del (tmp_ee, kck)

    C_h = crypto.xmr_H()
    gc.collect()

    # Second pass, s0, s1
    for ii in range(64):
        crypto.decodeint_into(tmp_alpha, alphai, ii << 5)
        crypto.decodeint_into(tmp_ai, ai, ii << 5)

        if ((amount >> ii) & 1) == 0:
            crypto.sc_mulsub_into(si, tmp_ai, ee, tmp_alpha)
            crypto.encodeint_into(s0s, si, ii << 5)

        else:
            crypto.random_scalar(si)
            crypto.encodeint_into(s0s, si, ii << 5)

            crypto.decodepoint_into(C_tmp, Cis, ii << 5)
            crypto.add_keys2_into(L, si, ee, C_tmp)
            crypto.encodepoint_into(buff, L)
            crypto.hash_to_scalar_into(c, buff)

            crypto.sc_mulsub_into(si, tmp_ai, c, tmp_alpha)
            crypto.encodeint_into(s1s, si, ii << 5)

        crypto.point_double_into(C_h, C_h)

    crypto.encodeint_into(ee_bin, ee)

    del (ai, alphai, buff, tmp_ai, tmp_alpha, si, c, ee, C_tmp, C_h, L)
    gc.collect()

    return C_acc, a, [s0s, s1s, ee_bin, Cis]