def add_keys2(dst, a, b, B):
    dst = _ensure_dst_key(dst)
    crypto.decodeint_into_noreduce(tmp_sc_1, a)
    crypto.decodeint_into_noreduce(tmp_sc_2, b)
    crypto.decodepoint_into(tmp_pt_1, B)
    crypto.add_keys2_into(tmp_pt_2, tmp_sc_1, tmp_sc_2, tmp_pt_1)
    crypto.encodepoint_into(dst, tmp_pt_2)
    return dst
Example #2
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
Example #3
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
Example #4
0
    def gen_clsag_sig(self, ring_size=11, index=None):
        msg = random.bytes(32)
        amnt = crypto.Scalar(random.uniform(0xFFFFFF) + 12)
        priv = crypto.random_scalar()
        msk = crypto.random_scalar()
        alpha = crypto.random_scalar()
        P = crypto.scalarmult_base_into(None, priv)
        C = crypto.add_keys2_into(None, msk, amnt, crypto.xmr_H())
        Cp = crypto.add_keys2_into(None, alpha, amnt, crypto.xmr_H())

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

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

        self.assertTrue(
            crypto.point_eq(
                crypto.scalarmult_base_into(None, priv),
                crypto_helpers.decodepoint(ring[index].dest),
            ))
        self.assertTrue(
            crypto.point_eq(
                crypto.scalarmult_base_into(
                    None, crypto.sc_sub_into(None, msk, alpha)),
                crypto.point_sub_into(
                    None, crypto_helpers.decodepoint(ring[index].commitment),
                    Cp),
            ))

        clsag.generate_clsag_simple(
            msg,
            ring,
            CtKey(priv, msk),
            alpha,
            Cp,
            index,
            mg_buffer,
        )

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

        crypto.hash_to_point_into(H, crypto_helpers.encodepoint(P))
        crypto.scalarmult_into(sI, H, priv)  # I = p*H
        return msg, scalars, sc1, sI, sD, ring2, Cp
Example #5
0
    def verify_clsag(self, msg, ss, sc1, sI, sD, pubs, C_offset):
        n = len(pubs)
        c = crypto.Scalar()
        D_8 = crypto.Point()
        tmp_bf = bytearray(32)
        C_offset_bf = crypto_helpers.encodepoint(C_offset)

        crypto.sc_copy(c, sc1)
        point_mul8_into(D_8, sD)

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

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

        for x in pubs:
            hsh_PC(x.dest)

        for x in pubs:
            hsh_PC(x.commitment)

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

        c_to_hash = crypto_helpers.get_keccak(
        )  # domain, P, C, C_offset, message, L, R
        c_to_hash.update(clsag._HASH_KEY_CLSAG_ROUND)
        for i in range(len(pubs)):
            c_to_hash.update(pubs[i].dest)
        for i in range(len(pubs)):
            c_to_hash.update(pubs[i].commitment)
        c_to_hash.update(C_offset_bf)
        c_to_hash.update(msg)

        c_p = crypto.Scalar()
        c_c = crypto.Scalar()
        L = crypto.Point()
        R = crypto.Point()
        tmp_pt = crypto.Point()
        i = 0
        while i < n:
            crypto.sc_mul_into(c_p, mu_P, c)
            crypto.sc_mul_into(c_c, mu_C, c)

            C_P = crypto.point_sub_into(
                None, crypto.decodepoint_into(tmp_pt, pubs[i].commitment),
                C_offset)
            crypto.add_keys2_into(
                L, ss[i], c_p, crypto.decodepoint_into(tmp_pt, pubs[i].dest))
            crypto.point_add_into(L, L,
                                  crypto.scalarmult_into(tmp_pt, C_P, c_c))

            HP = crypto.hash_to_point_into(None, pubs[i].dest)
            crypto.add_keys3_into(R, ss[i], HP, c_p, sI)
            crypto.point_add_into(R, R,
                                  crypto.scalarmult_into(tmp_pt, D_8, 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())
            i += 1
        res = crypto.sc_sub_into(None, c, sc1)
        if not crypto.sc_eq(res, crypto.Scalar(0)):
            raise ValueError("Signature error")
Example #6
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]