def sc_mul(dst, a, b):
    dst = _ensure_dst_key(dst)
    crypto.decodeint_into_noreduce(tmp_sc_1, a)
    crypto.decodeint_into_noreduce(tmp_sc_2, b)
    crypto.sc_mul_into(tmp_sc_3, tmp_sc_1, tmp_sc_2)
    crypto.encodeint_into(dst, tmp_sc_3)
    return dst
示例#2
0
async def _sync_step(s, ctx, tds):
    if not tds.tdis:
        raise wire.DataError("Empty")

    kis = []
    buff = bytearray(32 * 3)
    buff_mv = memoryview(buff)

    await confirms.keyimage_sync_step(ctx, s.current_output, s.num_outputs)

    for td in tds.tdis:
        s.current_output += 1
        if s.current_output >= s.num_outputs:
            raise wire.DataError("Too many outputs")

        if __debug__:
            log.debug(__name__, "ki_sync, step i: %d", s.current_output)

        # Update the control hash
        s.hasher.update(key_image.compute_hash(td))

        # Compute keyimage + signature
        ki, sig = key_image.export_key_image(s.creds, s.subaddresses, td)

        # Serialize into buff
        crypto.encodepoint_into(buff_mv[0:32], ki)
        crypto.encodeint_into(buff_mv[32:64], sig[0][0])
        crypto.encodeint_into(buff_mv[64:], sig[0][1])

        # Encrypt with enc_key
        nonce, ciph, _ = chacha_poly.encrypt(s.enc_key, buff)

        kis.append(MoneroExportedKeyImage(iv=nonce, blob=ciph))

    return MoneroKeyImageSyncStepAck(kis=kis)
示例#3
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)
    def __getitem__(self, item):
        vector_z_two_i(self.logN, self.zpow, self.twoN, self.idxize(item), self.sc)
        if self.raw:
            return self.sc

        crypto.encodeint_into(self.cur, self.sc)
        return self.cur
def sc_mulsub(dst, a, b, c):
    dst = _ensure_dst_key(dst)
    crypto.decodeint_into_noreduce(tmp_sc_1, a)
    crypto.decodeint_into_noreduce(tmp_sc_2, b)
    crypto.decodeint_into_noreduce(tmp_sc_3, c)
    crypto.sc_mulsub_into(tmp_sc_4, tmp_sc_1, tmp_sc_2, tmp_sc_3)
    crypto.encodeint_into(dst, tmp_sc_4)
    return dst
 def sX_gen(self, ln=_BP_N):
     gc.collect()
     buff = bytearray(ln * 32)
     buff_mv = memoryview(buff)
     sc = crypto.new_scalar()
     for i in range(ln):
         crypto.random_scalar(sc)
         crypto.encodeint_into(buff_mv[i * 32 : (i + 1) * 32], sc)
         gc_iter(i)
     return KeyV(buffer=buff)
 def _det_mask(self, i, is_sL=True, dst=None):
     dst = _ensure_dst_key(dst)
     if self.fnc_det_mask:
         return self.fnc_det_mask(i, is_sL, dst)
     self.tmp_det_buff[64] = int(is_sL)
     memcpy(self.tmp_det_buff, 65, _ZERO, 0, 4)
     dump_uvarint_b_into(i, self.tmp_det_buff, 65)
     crypto.hash_to_scalar_into(self.tmp_sc_1, self.tmp_det_buff)
     crypto.encodeint_into(dst, self.tmp_sc_1)
     return dst
示例#8
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
def hash_vct_to_scalar(dst, data):
    dst = _ensure_dst_key(dst)
    ctx = crypto.get_keccak()
    for x in data:
        ctx.update(x)
    hsh = ctx.digest()

    crypto.decodeint_into(tmp_sc_1, hsh)
    crypto.encodeint_into(tmp_bf_1, tmp_sc_1)
    copy_key(dst, tmp_bf_1)
    return dst
    def test_square_multiply(self):
        for x in [2, 3, 16, 17, 31, 32]:
            ss = crypto.random_scalar()
            s1 = crypto.sc_copy(None, ss)
            s2 = crypto.sc_copy(None, ss)
            for i in range(1, x):
                crypto.sc_mul_into(s1, s1, ss)

            bp._sc_square_mult(s2, ss, x)
            self.assertEqual(crypto.encodeint_into(None, s1),
                             crypto.encodeint_into(None, s2))
示例#11
0
def inner_product(a, b, dst=None):
    if len(a) != len(b):
        raise ValueError("Incompatible sizes of a and b")
    dst = _ensure_dst_key(dst)
    crypto.sc_init_into(tmp_sc_1, 0)

    for i in range(len(a)):
        crypto.decodeint_into_noreduce(tmp_sc_2, a.to(i))
        crypto.decodeint_into_noreduce(tmp_sc_3, b.to(i))
        crypto.sc_muladd_into(tmp_sc_1, tmp_sc_2, tmp_sc_3, tmp_sc_1)
        gc_iter(i)

    crypto.encodeint_into(dst, tmp_sc_1)
    return dst
示例#12
0
def hash_cache_mash(dst, hash_cache, *args):
    dst = _ensure_dst_key(dst)
    ctx = crypto.get_keccak()
    ctx.update(hash_cache)

    for x in args:
        if x is None:
            break
        ctx.update(x)
    hsh = ctx.digest()

    crypto.decodeint_into(tmp_sc_1, hsh)
    crypto.encodeint_into(tmp_bf_1, tmp_sc_1)

    copy_key(dst, tmp_bf_1)
    copy_key(hash_cache, tmp_bf_1)
    return dst
示例#13
0
def vector_powers(x, n, dst=None, dynamic=False, **kwargs):
    if dynamic:
        return KeyVPowers(n, x, **kwargs)
    dst = _ensure_dst_keyvect(dst, n)
    if n == 0:
        return dst
    dst.read(0, _ONE)
    if n == 1:
        return dst
    dst.read(1, x)

    crypto.decodeint_into_noreduce(tmp_sc_1, x)
    crypto.decodeint_into_noreduce(tmp_sc_2, x)
    for i in range(2, n):
        crypto.sc_mul_into(tmp_sc_1, tmp_sc_1, tmp_sc_2)
        crypto.encodeint_into(tmp_bf_0, tmp_sc_1)
        dst.read(i, tmp_bf_0)
        gc_iter(i)
    return dst
示例#14
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
    def test_bpp_bprime(self):
        N, M = 64, 4
        MN = N * M
        y = unhexlify(
            b'60421950bee0aab949e63336db1eb9532dba6b4599c5cd9fb1dbde909114100e'
        )
        z = unhexlify(
            b'e0408b528e9d35ccb8386b87f39b85c724740644f4db412483a8852cdb3ceb00'
        )
        zc = crypto.decodeint_into(None, z)
        z_sq = bp._sc_mul(None, z, z)
        sv = [1234, 8789, 4455, 6697]
        sv = [crypto.encodeint_into(None, crypto.Scalar(x)) for x in sv]

        num_inp = len(sv)
        sc_zero = crypto.decodeint_into_noreduce(None, bp._ZERO)
        sc_mone = crypto.decodeint_into_noreduce(None, bp._MINUS_ONE)

        def e_xL(idx, d=None):
            j, i = idx // bp._BP_N, idx % bp._BP_N
            r = None
            if j >= num_inp:
                r = sc_mone
            elif sv[j][i // 8] & (1 << i % 8):
                r = sc_zero
            else:
                r = sc_mone
            if d:
                return crypto.sc_copy(d, r)
            return r

        aR = bp.KeyVEval(MN, lambda i, d: e_xL(i, d), raw=True)
        d_vct = bp.VctD(N, M, z_sq, raw=True)
        ypow_back = bp.KeyVPowersBackwards(MN + 1, y, raw=True)
        aR1_sc1 = crypto.Scalar()

        def aR1_fnc(i, d):
            crypto.sc_add_into(aR1_sc1, aR.to(i), zc)
            crypto.sc_muladd_into(aR1_sc1, d_vct[i], ypow_back[MN - i],
                                  aR1_sc1)
            return crypto.encodeint_into(d, aR1_sc1)

        bprime = bp.KeyVEval(MN, aR1_fnc, raw=False)  # aR1
        b64 = bp._copy_key(None, bprime.to(64))
        b65 = bp._copy_key(None, bprime.to(65))
        b128 = bp._copy_key(None, bprime.to(128))
        b65_2 = bp._copy_key(None, bprime.to(65))
        b64_2 = bp._copy_key(None, bprime.to(64))
        _ = bprime[89]
        b128_2 = bp._copy_key(None, bprime.to(128))

        self.assertEqual(b64, b64_2)
        self.assertEqual(b65, b65_2)
        self.assertEqual(b128, b128_2)
示例#16
0
async def _refresh_step(
        s: LiveRefreshState, ctx: Context,
        msg: MoneroLiveRefreshStepRequest) -> MoneroLiveRefreshStepAck:
    assert s.creds is not None

    buff = bytearray(32 * 3)
    buff_mv = memoryview(buff)

    await layout.live_refresh_step(ctx, s.current_output)
    s.current_output += 1

    if __debug__:
        log.debug(__name__, "refresh, step i: %d", s.current_output)

    # Compute spending secret key and the key image
    # spend_priv = Hs(recv_deriv || real_out_idx) + spend_key_private
    # If subaddr:
    #   spend_priv += Hs("SubAddr" || view_key_private || major || minor)
    # out_key = spend_priv * G, KI: spend_priv * Hp(out_key)
    out_key = crypto_helpers.decodepoint(msg.out_key)
    recv_deriv = crypto_helpers.decodepoint(msg.recv_deriv)
    received_index = msg.sub_addr_major, msg.sub_addr_minor
    spend_priv, ki = monero.generate_tx_spend_and_key_image(
        s.creds, out_key, recv_deriv, msg.real_out_idx, received_index)

    ki_enc = crypto_helpers.encodepoint(ki)
    sig = key_image.generate_ring_signature(ki_enc, ki, [out_key], spend_priv,
                                            0, False)
    del spend_priv  # spend_priv never leaves the device

    # Serialize into buff
    buff[0:32] = ki_enc
    crypto.encodeint_into(buff_mv[32:64], sig[0][0])
    crypto.encodeint_into(buff_mv[64:], sig[0][1])

    # Encrypt with view key private based key - so host can decrypt and verify HMAC
    enc_key, salt = misc.compute_enc_key_host(s.creds.view_key_private,
                                              msg.out_key)
    resp = chacha_poly.encrypt_pack(enc_key, buff)

    return MoneroLiveRefreshStepAck(salt=salt, key_image=resp)
示例#17
0
def scalar_fold(v, a, b, into=None, into_offset=0):
    """
    ln = len(v); h = ln // 2
    v[i] = v[i] * a + v[h+i] * b)
    """
    h = len(v) // 2
    crypto.decodeint_into_noreduce(tmp_sc_1, a)
    crypto.decodeint_into_noreduce(tmp_sc_2, b)
    into = into if into else v

    for i in range(h):
        crypto.decodeint_into_noreduce(tmp_sc_3, v.to(i))
        crypto.decodeint_into_noreduce(tmp_sc_4, v.to(h + i))
        crypto.sc_mul_into(tmp_sc_3, tmp_sc_3, tmp_sc_1)
        crypto.sc_mul_into(tmp_sc_4, tmp_sc_4, tmp_sc_2)
        crypto.sc_add_into(tmp_sc_3, tmp_sc_3, tmp_sc_4)
        crypto.encodeint_into(tmp_bf_0, tmp_sc_3)
        into.read(i + into_offset, tmp_bf_0)
        gc_iter(i)

    return into
示例#18
0
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
示例#19
0
def _generate_clsag(
    message: bytes,
    P: List[bytes],
    p: Sc25519,
    C_nonzero: List[bytes],
    z: Sc25519,
    Cout: Ge25519,
    index: int,
    mg_buff: List[bytes],
) -> List[bytes]:
    sI = crypto.new_point()  # sig.I
    sD = crypto.new_point()  # sig.D
    sc1 = crypto.new_scalar()  # sig.c1
    a = crypto.random_scalar()
    H = crypto.new_point()
    D = crypto.new_point()
    Cout_bf = crypto.encodepoint(Cout)

    tmp_sc = crypto.new_scalar()
    tmp = crypto.new_point()
    tmp_bf = bytearray(32)

    crypto.hash_to_point_into(H, P[index])
    crypto.scalarmult_into(sI, H, p)  # I = p*H
    crypto.scalarmult_into(D, H, z)  # D = z*H
    crypto.sc_mul_into(tmp_sc, z, crypto.sc_inv_eight())  # 1/8*z
    crypto.scalarmult_into(sD, H, tmp_sc)  # sig.D = 1/8*z*H
    sD = crypto.encodepoint(sD)

    hsh_P = crypto.get_keccak()  # domain, I, D, P, C, C_offset
    hsh_C = crypto.get_keccak()  # domain, I, D, P, C, C_offset
    hsh_P.update(_HASH_KEY_CLSAG_AGG_0)
    hsh_C.update(_HASH_KEY_CLSAG_AGG_1)

    def hsh_PC(x):
        nonlocal hsh_P, hsh_C
        hsh_P.update(x)
        hsh_C.update(x)

    for x in P:
        hsh_PC(x)

    for x in C_nonzero:
        hsh_PC(x)

    hsh_PC(crypto.encodepoint_into(tmp_bf, sI))
    hsh_PC(sD)
    hsh_PC(Cout_bf)
    mu_P = crypto.decodeint(hsh_P.digest())
    mu_C = crypto.decodeint(hsh_C.digest())

    del (hsh_PC, hsh_P, hsh_C)
    c_to_hash = crypto.get_keccak()  # domain, P, C, C_offset, message, aG, aH
    c_to_hash.update(_HASH_KEY_CLSAG_ROUND)
    for i in range(len(P)):
        c_to_hash.update(P[i])
    for i in range(len(P)):
        c_to_hash.update(C_nonzero[i])
    c_to_hash.update(Cout_bf)
    c_to_hash.update(message)

    chasher = c_to_hash.copy()
    crypto.scalarmult_base_into(tmp, a)
    chasher.update(crypto.encodepoint_into(tmp_bf, tmp))  # aG
    crypto.scalarmult_into(tmp, H, a)
    chasher.update(crypto.encodepoint_into(tmp_bf, tmp))  # aH
    c = crypto.decodeint(chasher.digest())
    del (chasher, H)

    L = crypto.new_point()
    R = crypto.new_point()
    c_p = crypto.new_scalar()
    c_c = crypto.new_scalar()
    i = (index + 1) % len(P)
    if i == 0:
        crypto.sc_copy(sc1, c)

    mg_buff.append(int_serialize.dump_uvarint_b(len(P)))
    for _ in range(len(P)):
        mg_buff.append(bytearray(32))

    while i != index:
        crypto.random_scalar(tmp_sc)
        crypto.encodeint_into(mg_buff[i + 1], tmp_sc)

        crypto.sc_mul_into(c_p, mu_P, c)
        crypto.sc_mul_into(c_c, mu_C, c)

        # L = tmp_sc * G + c_P * P[i] + c_c * C[i]
        crypto.add_keys2_into(L, tmp_sc, c_p,
                              crypto.decodepoint_into(tmp, P[i]))
        crypto.decodepoint_into(tmp, C_nonzero[i])  # C = C_nonzero - Cout
        crypto.point_sub_into(tmp, tmp, Cout)
        crypto.scalarmult_into(tmp, tmp, c_c)
        crypto.point_add_into(L, L, tmp)

        # R = tmp_sc * HP + c_p * I + c_c * D
        crypto.hash_to_point_into(tmp, P[i])
        crypto.add_keys3_into(R, tmp_sc, tmp, c_p, sI)
        crypto.point_add_into(R, R, crypto.scalarmult_into(tmp, D, c_c))

        chasher = c_to_hash.copy()
        chasher.update(crypto.encodepoint_into(tmp_bf, L))
        chasher.update(crypto.encodepoint_into(tmp_bf, R))
        crypto.decodeint_into(c, chasher.digest())

        P[i] = None
        C_nonzero[i] = None

        i = (i + 1) % len(P)
        if i == 0:
            crypto.sc_copy(sc1, c)

        if i & 3 == 0:
            gc.collect()

    # Final scalar = a - c * (mu_P * p + mu_c * Z)
    crypto.sc_mul_into(tmp_sc, mu_P, p)
    crypto.sc_muladd_into(tmp_sc, mu_C, z, tmp_sc)
    crypto.sc_mulsub_into(tmp_sc, c, tmp_sc, a)
    crypto.encodeint_into(mg_buff[index + 1], tmp_sc)

    mg_buff.append(crypto.encodeint(sc1))
    mg_buff.append(sD)
    return mg_buff
示例#20
0
def invert(dst, x):
    dst = _ensure_dst_key(dst)
    crypto.decodeint_into_noreduce(tmp_sc_1, x)
    crypto.sc_inv_into(tmp_sc_2, tmp_sc_1)
    crypto.encodeint_into(dst, tmp_sc_2)
    return dst
    def test_pow_back_skips(self):
        MN = 128
        y = unhexlify(
            '60421950bee0aab949e63336db1eb9532dba6b4599c5cd9fb1dbde909114100e')
        y_sc = crypto.decodeint_into(None, y)
        yinv = bp._invert(None, y)

        y_to_MN_1 = bp._sc_square_mult(None, y_sc, MN - 1)
        ymax = crypto.sc_mul_into(None, y_to_MN_1, y_sc)  ## y**MN
        ymax2 = bp._sc_square_mult(None, y_sc, MN)
        self.assertEqual(crypto.encodeint_into(None, ymax),
                         crypto.encodeint_into(None, ymax2))

        size = MN + 1
        ypow_back = bp.KeyVPowersBackwards(size,
                                           y,
                                           x_inv=yinv,
                                           x_max=ymax,
                                           raw=True)
        self.assertEqual(crypto.encodeint_into(None, ymax),
                         crypto.encodeint_into(None, ypow_back[MN]))

        for i in range(10):
            _ = ypow_back[MN - i]

        self.assertEqual(
            crypto.encodeint_into(None, ypow_back[MN - 9]),
            crypto.encodeint_into(None, bp._sc_square_mult(None, y_sc,
                                                           MN - 9)))
        self.assertEqual(
            crypto.encodeint_into(None, ypow_back[MN - 19]),
            crypto.encodeint_into(None,
                                  bp._sc_square_mult(None, y_sc, MN - 19)))
        self.assertEqual(
            crypto.encodeint_into(None, ypow_back[MN - 65]),
            crypto.encodeint_into(None,
                                  bp._sc_square_mult(None, y_sc, MN - 65)))
        self.assertEqual(
            crypto.encodeint_into(None, ypow_back[MN - 14]),
            crypto.encodeint_into(None,
                                  bp._sc_square_mult(None, y_sc, MN - 14)))

        tmp = crypto.sc_copy(None,
                             ypow_back[MN - 64])  # another jump back and forth
        _ = ypow_back[MN - 127]
        self.assertEqual(crypto.encodeint_into(None, ypow_back[MN - 64]),
                         crypto.encodeint_into(None, tmp))
        self.assertEqual(
            crypto.encodeint_into(None, ypow_back[MN - 64]),
            crypto.encodeint_into(None,
                                  bp._sc_square_mult(None, y_sc, MN - 64)))
示例#22
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]
示例#23
0
def prove_range_mem(amount, last_mask=None):
    """
    Memory optimized range proof.

    Gives C, and mask such that \sumCi = C
    c.f. http:#eprint.iacr.org/2015/1098 section 5.1

    Ci is a commitment to either 0 or 2^i, i=0,...,63
    thus this proves that "amount" is in [0, 2^ATOMS]
    mask is a such that C = aG + bH, and b = amount
    :param amount:
    :param last_mask: ai[ATOMS-1] will be computed as \sum_{i=0}^{ATOMS-2} a_i - last_mask
    :param use_asnl: use ASNL, used before Borromean
    :return: sumCi, mask, RangeSig.
        sumCi is Pedersen commitment on the amount value. sumCi = aG + amount*H
        mask is "a" from the Pedersent commitment above.
    """
    res = bytearray(32 * (64 + 64 + 64 + 1))
    mv = memoryview(res)
    gc.collect()

    def as0(mv, x, i):
        crypto.encodeint_into(x, mv[32 * i:])

    def as1(mv, x, i):
        crypto.encodeint_into(x, mv[32 * 64 + 32 * i:])

    def aci(mv, x, i):
        crypto.encodepoint_into(x, mv[32 * 64 * 2 + 32 + 32 * i:])

    n = 64
    bb = d2b(amount, n)  # gives binary form of bb in "digits" binary digits
    ai = key_zero_vector(n)
    a = crypto.sc_0()

    C = crypto.identity()
    alpha = key_zero_vector(n)
    c_H = crypto.gen_H()
    kck = crypto.get_keccak()  # ee computation

    # First pass, generates: ai, alpha, Ci, ee, s1
    for ii in range(n):
        ai[ii] = crypto.random_scalar()
        if last_mask is not None and ii == 64 - 1:
            ai[ii] = crypto.sc_sub(last_mask, a)

        a = crypto.sc_add(
            a, ai[ii]
        )  # creating the total mask since you have to pass this to receiver...

        alpha[ii] = crypto.random_scalar()
        L = crypto.scalarmult_base(alpha[ii])

        if bb[ii] == 0:
            Ctmp = crypto.scalarmult_base(ai[ii])
        else:
            Ctmp = crypto.point_add(crypto.scalarmult_base(ai[ii]), c_H)
        C = crypto.point_add(C, Ctmp)
        aci(mv, Ctmp, ii)

        if bb[ii] == 0:
            si = crypto.random_scalar()
            c = crypto.hash_to_scalar(crypto.encodepoint(L))
            L = crypto.add_keys2(si, c, crypto.point_sub(Ctmp, c_H))
            kck.update(crypto.encodepoint(L))
            as1(mv, si, ii)

        else:
            kck.update(crypto.encodepoint(L))

        c_H = crypto.point_double(c_H)

    # Compute ee, memory cleanup
    ee = crypto.sc_reduce32(crypto.decodeint(kck.digest()))
    crypto.encodeint_into(ee, mv[64 * 32 * 2:])
    del kck
    gc.collect()

    # Second phase computes: s0, s1
    c_H = crypto.gen_H()

    for jj in range(n):
        if not bb[jj]:
            s0 = crypto.sc_mulsub(ai[jj], ee, alpha[jj])

        else:
            s0 = crypto.random_scalar()
            Ctmp = crypto.decodepoint(
                mv[32 * 64 * 2 + 32 + 32 * jj:32 * 64 * 2 + 32 + 32 * jj + 32])
            LL = crypto.add_keys2(s0, ee, Ctmp)
            cc = crypto.hash_to_scalar(crypto.encodepoint(LL))
            si = crypto.sc_mulsub(ai[jj], cc, alpha[jj])
            as1(mv, si, jj)
        as0(mv, s0, jj)

        c_H = crypto.point_double(c_H)

    gc.collect()
    return C, a, res
示例#24
0
 def as0(mv, x, i):
     crypto.encodeint_into(x, mv[32 * i:])
示例#25
0
def hash_to_scalar(dst, data):
    dst = _ensure_dst_key(dst)
    crypto.hash_to_scalar_into(tmp_sc_1, data)
    crypto.encodeint_into(dst, tmp_sc_1)
    return dst
示例#26
0
 def as1(mv, x, i):
     crypto.encodeint_into(x, mv[32 * 64 + 32 * i:])
示例#27
0
def sc_gen(dst=None):
    dst = _ensure_dst_key(dst)
    crypto.random_scalar(tmp_sc_1)
    crypto.encodeint_into(dst, tmp_sc_1)
    return dst
示例#28
0
    def _prove_batch_main(
        self, V, gamma, aL, aR, hash_cache, logM, logN, M, N, proof_v8=False
    ):
        logMN = logM + logN
        MN = M * N
        hash_vct_to_scalar(hash_cache, V)

        # Extended precomputed GiHi
        Gprec = self._gprec_aux(MN)
        Hprec = self._hprec_aux(MN)

        # PAPER LINES 38-39
        alpha = sc_gen()
        ve = _ensure_dst_key()
        A = _ensure_dst_key()
        vector_exponent_custom(Gprec, Hprec, aL, aR, ve)
        add_keys(A, ve, scalarmult_base(tmp_bf_1, alpha))
        if not proof_v8:
            scalarmult_key(A, A, _INV_EIGHT)
        self.gc(11)

        # PAPER LINES 40-42
        sL = self.sL_vct(MN)
        sR = self.sR_vct(MN)
        rho = sc_gen()
        vector_exponent_custom(Gprec, Hprec, sL, sR, ve)
        S = _ensure_dst_key()
        add_keys(S, ve, scalarmult_base(tmp_bf_1, rho))
        if not proof_v8:
            scalarmult_key(S, S, _INV_EIGHT)
        del ve
        self.gc(12)

        # PAPER LINES 43-45
        y = _ensure_dst_key()
        hash_cache_mash(y, hash_cache, A, S)
        if y == _ZERO:
            return (0,)

        z = _ensure_dst_key()
        hash_to_scalar(hash_cache, y)
        copy_key(z, hash_cache)
        if z == _ZERO:
            return (0,)

        # Polynomial construction by coefficients
        zMN = const_vector(z, MN)
        l0 = _ensure_dst_keyvect(None, MN)
        vector_subtract(aL, zMN, l0)
        l1 = sL
        self.gc(13)

        # This computes the ugly sum/concatenation from PAPER LINE 65
        # r0 = aR + z
        r0 = vector_add(aR, zMN)
        del zMN
        self.gc(14)

        # r0 = r0 \odot yMN => r0[i]  = r0[i] * y^i
        # r1 = sR \odot yMN => r1[i]  = sR[i] * y^i
        yMN = vector_powers(y, MN, dynamic=False)
        hadamard(r0, yMN, dst=r0)
        self.gc(15)

        # r0 = r0 + zero_twos
        zpow = vector_powers(z, M + 2)
        twoN = self._two_aux(MN)
        zero_twos = vector_z_two(N, logN, M, zpow, twoN, dynamic=True, raw=True)
        vector_gen(
            r0,
            len(r0),
            lambda i, d: crypto.encodeint_into(
                d,
                crypto.sc_add_into(
                    tmp_sc_1,
                    zero_twos[i],  # noqa: F821
                    crypto.decodeint_into_noreduce(tmp_sc_2, r0.to(i)),  # noqa: F821
                ),
            ),
        )

        del (zero_twos, twoN)
        self.gc(15)

        # Polynomial construction before PAPER LINE 46
        # r1 = KeyVEval(MN, lambda i, d: sc_mul(d, yMN[i], sR[i]))
        # r1 optimization possible, but has clashing sc registers.
        # Moreover, max memory complexity is 4MN as below (while loop).
        r1 = hadamard(yMN, sR, yMN)  # re-use yMN vector for r1
        del (yMN, sR)
        self.gc(16)

        # Inner products
        # l0 = aL - z           r0   = ((aR + z) \cdot ypow) + zt
        # l1 = sL               r1   =   sR      \cdot ypow
        # t1_1 = l0 . r1,       t1_2 = l1 . r0
        # t1   = t1_1 + t1_2,   t2   = l1 . r1
        # l = l0 \odot x*l1     r    = r0 \odot x*r1
        t1, t2 = cross_inner_product(l0, r0, l1, r1)
        self.gc(17)

        # PAPER LINES 47-48
        tau1, tau2 = sc_gen(), sc_gen()
        T1, T2 = _ensure_dst_key(), _ensure_dst_key()

        add_keys(T1, scalarmultH(tmp_bf_1, t1), scalarmult_base(tmp_bf_2, tau1))
        if not proof_v8:
            scalarmult_key(T1, T1, _INV_EIGHT)

        add_keys(T2, scalarmultH(tmp_bf_1, t2), scalarmult_base(tmp_bf_2, tau2))
        if not proof_v8:
            scalarmult_key(T2, T2, _INV_EIGHT)
        del (t1, t2)
        self.gc(17)

        # PAPER LINES 49-51
        x = _ensure_dst_key()
        hash_cache_mash(x, hash_cache, z, T1, T2)
        if x == _ZERO:
            return (0,)

        # PAPER LINES 52-53
        taux = _ensure_dst_key()
        copy_key(taux, _ZERO)
        sc_mul(taux, tau1, x)
        xsq = _ensure_dst_key()
        sc_mul(xsq, x, x)
        sc_muladd(taux, tau2, xsq, taux)
        del (xsq, tau1, tau2)
        for j in range(1, len(V) + 1):
            sc_muladd(taux, zpow.to(j + 1), gamma[j - 1], taux)
        del zpow

        self.gc(18)
        mu = _ensure_dst_key()
        sc_muladd(mu, x, rho, alpha)
        del (rho, alpha)

        # PAPER LINES 54-57
        # l = l0 \odot x*l1, has to evaluated as it becomes aprime in the loop
        l = vector_gen(
            l0,
            len(l0),
            lambda i, d: sc_add(d, d, sc_mul(tmp_bf_1, l1.to(i), x)),  # noqa: F821
        )
        del (l0, l1, sL)
        self.gc(19)

        # r = r0 \odot x*r1, has to evaluated as it becomes bprime in the loop
        r = vector_gen(
            r0,
            len(r0),
            lambda i, d: sc_add(d, d, sc_mul(tmp_bf_1, r1.to(i), x)),  # noqa: F821
        )
        t = inner_product(l, r)
        del (r1, r0)
        self.gc(19)

        # PAPER LINES 32-33
        x_ip = hash_cache_mash(None, hash_cache, x, taux, mu, t)
        if x_ip == _ZERO:
            return 0, None

        # PHASE 2
        # These are used in the inner product rounds
        nprime = MN
        Gprime = _ensure_dst_keyvect(None, MN)
        Hprime = _ensure_dst_keyvect(None, MN)
        aprime = l
        bprime = r
        yinv = invert(None, y)
        yinvpow = init_key(_ONE)
        self.gc(20)

        for i in range(0, MN):
            Gprime.read(i, Gprec.to(i))
            scalarmult_key(tmp_bf_0, Hprec.to(i), yinvpow)
            Hprime.read(i, tmp_bf_0)
            sc_mul(yinvpow, yinvpow, yinv)
            gc_iter(i)
        self.gc(21)

        L = _ensure_dst_keyvect(None, logMN)
        R = _ensure_dst_keyvect(None, logMN)
        cL = _ensure_dst_key()
        cR = _ensure_dst_key()
        winv = _ensure_dst_key()
        w_round = _ensure_dst_key()
        tmp = _ensure_dst_key()

        round = 0
        _tmp_k_1 = _ensure_dst_key()

        # PAPER LINE 13
        while nprime > 1:
            # PAPER LINE 15
            npr2 = nprime
            nprime >>= 1
            self.gc(22)

            # PAPER LINES 16-17
            inner_product(
                aprime.slice_view(0, nprime), bprime.slice_view(nprime, npr2), cL
            )

            inner_product(
                aprime.slice_view(nprime, npr2), bprime.slice_view(0, nprime), cR
            )
            self.gc(23)

            # PAPER LINES 18-19
            vector_exponent_custom(
                Gprime.slice_view(nprime, npr2),
                Hprime.slice_view(0, nprime),
                aprime.slice_view(0, nprime),
                bprime.slice_view(nprime, npr2),
                tmp_bf_0,
            )

            sc_mul(tmp, cL, x_ip)
            add_keys(tmp_bf_0, tmp_bf_0, scalarmultH(_tmp_k_1, tmp))
            if not proof_v8:
                scalarmult_key(tmp_bf_0, tmp_bf_0, _INV_EIGHT)
            L.read(round, tmp_bf_0)
            self.gc(24)

            vector_exponent_custom(
                Gprime.slice_view(0, nprime),
                Hprime.slice_view(nprime, npr2),
                aprime.slice_view(nprime, npr2),
                bprime.slice_view(0, nprime),
                tmp_bf_0,
            )

            sc_mul(tmp, cR, x_ip)
            add_keys(tmp_bf_0, tmp_bf_0, scalarmultH(_tmp_k_1, tmp))
            if not proof_v8:
                scalarmult_key(tmp_bf_0, tmp_bf_0, _INV_EIGHT)
            R.read(round, tmp_bf_0)
            self.gc(25)

            # PAPER LINES 21-22
            hash_cache_mash(w_round, hash_cache, L.to(round), R.to(round))
            if w_round == _ZERO:
                return (0,)

            # PAPER LINES 24-25
            invert(winv, w_round)
            self.gc(26)

            hadamard_fold(Gprime, winv, w_round)
            self.gc(27)

            hadamard_fold(Hprime, w_round, winv, Gprime, nprime)
            Hprime.realloc_init_from(nprime, Gprime, nprime, round < 2)
            self.gc(28)

            # PAPER LINES 28-29
            scalar_fold(aprime, w_round, winv, Gprime, nprime)
            aprime.realloc_init_from(nprime, Gprime, nprime, round < 2)
            self.gc(29)

            scalar_fold(bprime, winv, w_round, Gprime, nprime)
            bprime.realloc_init_from(nprime, Gprime, nprime, round < 2)
            self.gc(30)

            # Finally resize Gprime which was buffer for all ops
            Gprime.resize(nprime, realloc=True)
            round += 1

        from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import Bulletproof

        return (
            1,
            Bulletproof(
                V=V,
                A=A,
                S=S,
                T1=T1,
                T2=T2,
                taux=taux,
                mu=mu,
                L=L,
                R=R,
                a=aprime.to(0),
                b=bprime.to(0),
                t=t,
            ),
        )
示例#29
0
def generate_mlsag(
    message: bytes,
    pk: KeyM,
    xx: List[Sc25519],
    index: int,
    dsRows: int,
    mg_buff: List[bytes],
) -> List[bytes]:
    """
    Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)

    :param message: the full message to be signed (actually its hash)
    :param pk: matrix of public keys and commitments
    :param xx: input secret array composed of a private key and commitment mask
    :param index: specifies corresponding public key to the `xx`'s private key in the `pk` array
    :param dsRows: separates pubkeys from commitment
    :param mg_buff: mg signature buffer
    """
    rows, cols = gen_mlsag_assert(pk, xx, index, dsRows)
    rows_b_size = int_serialize.uvarint_size(rows)

    # Preallocation of the chunked buffer, len + cols + cc
    for _ in range(1 + cols + 1):
        mg_buff.append(None)

    mg_buff[0] = int_serialize.dump_uvarint_b(cols)
    cc = crypto.new_scalar()  # rv.cc
    c = crypto.new_scalar()
    L = crypto.new_point()
    R = crypto.new_point()
    Hi = crypto.new_point()

    # calculates the "first" c, key images and random scalars alpha
    c_old, II, alpha = generate_first_c_and_key_images(message, pk, xx, index,
                                                       dsRows, rows, cols)

    i = (index + 1) % cols
    if i == 0:
        crypto.sc_copy(cc, c_old)

    ss = [crypto.new_scalar() for _ in range(rows)]
    tmp_buff = bytearray(32)

    while i != index:
        hasher = _hasher_message(message)

        # Serialize size of the row
        mg_buff[i + 1] = bytearray(rows_b_size + 32 * rows)
        int_serialize.dump_uvarint_b_into(rows, mg_buff[i + 1])

        for x in ss:
            crypto.random_scalar(x)

        for j in range(dsRows):
            # L = rv.ss[i][j] * G + c_old * pk[i][j]
            crypto.add_keys2_into(L, ss[j], c_old,
                                  crypto.decodepoint_into(Hi, pk[i][j]))
            crypto.hash_to_point_into(Hi, pk[i][j])

            # R = rv.ss[i][j] * H(pk[i][j]) + c_old * Ip[j]
            crypto.add_keys3_into(R, ss[j], Hi, c_old, II[j])

            hasher.update(pk[i][j])
            _hash_point(hasher, L, tmp_buff)
            _hash_point(hasher, R, tmp_buff)

        for j in range(dsRows, rows):
            # again, omitting R here as discussed above
            crypto.add_keys2_into(L, ss[j], c_old,
                                  crypto.decodepoint_into(Hi, pk[i][j]))
            hasher.update(pk[i][j])
            _hash_point(hasher, L, tmp_buff)

        for si in range(rows):
            crypto.encodeint_into(mg_buff[i + 1], ss[si],
                                  rows_b_size + 32 * si)

        crypto.decodeint_into(c, hasher.digest())
        crypto.sc_copy(c_old, c)
        pk[i] = None
        i = (i + 1) % cols

        if i == 0:
            crypto.sc_copy(cc, c_old)
        gc.collect()

    del II

    # Finalizing rv.ss by processing rv.ss[index]
    mg_buff[index + 1] = bytearray(rows_b_size + 32 * rows)
    int_serialize.dump_uvarint_b_into(rows, mg_buff[index + 1])
    for j in range(rows):
        crypto.sc_mulsub_into(ss[j], c, xx[j], alpha[j])
        crypto.encodeint_into(mg_buff[index + 1], ss[j], rows_b_size + 32 * j)

    # rv.cc
    mg_buff[-1] = crypto.encodeint(cc)
    return mg_buff
    def test_dvct_skips(self):
        z_sq = unhexlify(
            b'e0408b528e9d35ccb8386b87f39b85c724740644f4db412483a8852cdb3ceb00'
        )
        d_vct0 = bp.VctD(64, 8, z_sq, raw=True)
        d_vct1 = bp.VctD(64, 8, z_sq, raw=True)
        tmp = crypto.Scalar()

        # Linear scan vs jump
        for i in range(65):
            tmp = d_vct0[i]
        self.assertEqual(crypto.encodeint_into(None, tmp),
                         crypto.encodeint_into(None, d_vct1[64]))

        # Jumping around
        _ = d_vct0[128]
        self.assertEqual(crypto.encodeint_into(None, d_vct0[64]),
                         crypto.encodeint_into(None, d_vct1[64]))

        # Sync on the same jump
        self.assertEqual(crypto.encodeint_into(None, d_vct0[65]),
                         crypto.encodeint_into(None, d_vct1[65]))
        self.assertEqual(crypto.encodeint_into(None, d_vct0[65]),
                         crypto.encodeint_into(None, d_vct1[65]))

        # Jump vs linear again, move_one vs move_more
        for i in range(1, 10):
            tmp = d_vct0[65 + i]
        self.assertEqual(crypto.encodeint_into(None, tmp),
                         crypto.encodeint_into(None, d_vct1[74]))

        _ = d_vct0[85]
        _ = d_vct1[89]  # different jump sizes, internal state management test
        self.assertEqual(crypto.encodeint_into(None, d_vct0[95]),
                         crypto.encodeint_into(None, d_vct1[95]))

        _ = d_vct0[
            319]  # move_one mults by z_sq then; enforce z component updates
        self.assertEqual(crypto.encodeint_into(None, d_vct0[320]),
                         crypto.encodeint_into(None, d_vct1[320]))

        tmp = crypto.sc_copy(None, d_vct0[64])  # another jump back and forth
        _ = d_vct0[127]
        self.assertEqual(crypto.encodeint_into(None, d_vct0[64]),
                         crypto.encodeint_into(None, tmp))

        _ = d_vct0[0]
        _ = d_vct1[0]
        _ = d_vct0[64]
        self.assertEqual(crypto.encodeint_into(None, d_vct0[5]),
                         crypto.encodeint_into(None, d_vct1[5]))