예제 #1
0
def ver_borromean(P1, P2, s0, s1, ee):
    """
    Verify range proof signature, Borromean
    (c.f. gmax/andytoshi's paper)
    :param P1:
    :param P2:
    :param s0:
    :param s1:
    :param ee:
    :return:
    """
    n = len(P1)
    Lv1 = key_vector(n)
    for ii in range(n):
        LL = crypto.add_keys2(s0[ii], ee, P1[ii])
        chash = crypto.hash_to_scalar(crypto.encodepoint(LL))
        Lv1[ii] = crypto.add_keys2(s1[ii], chash, P2[ii])

    kck = crypto.get_keccak()
    for ii in range(n):
        kck.update(crypto.encodepoint(Lv1[ii]))

    # ee_computed = crypto.hash_to_scalar(crypto.encodepoint(Lv1))
    ee_computed = crypto.decodeint(kck.digest())

    return crypto.sc_eq(ee_computed, ee)
예제 #2
0
def gen_mlsag_ext(message, pk, xx, kLRki, mscout, index, dsRows):
    """
    Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)

    :param message:
    :param pk: matrix of points, point form (not encoded)
    :param xx:
    :param kLRki:
    :param mscout:
    :param index:
    :param dsRows:
    :return:
    """
    rows, cols = gen_mlsag_assert(pk, xx, kLRki, mscout, index, dsRows)

    rv = xmrtypes.MgSig()
    c, L, R, Hi = 0, None, None, None

    c_old, Ip, alpha = gen_mlsag_rows(message, rv, pk, xx, kLRki, index,
                                      dsRows, rows, cols)

    i = (index + 1) % cols
    if i == 0:
        rv.cc = c_old

    while i != index:
        rv.ss[i] = scalar_gen_vector(rows)
        hasher = hasher_message(message)

        for j in range(dsRows):
            L = crypto.add_keys2(rv.ss[i][j], c_old, pk[i][j])
            Hi = crypto.hash_to_point(crypto.encodepoint(
                pk[i][j]))  # originally hashToPoint()
            R = crypto.add_keys3(rv.ss[i][j], Hi, c_old, Ip[j])
            hasher.update(crypto.encodepoint(pk[i][j]))
            hasher.update(crypto.encodepoint(L))
            hasher.update(crypto.encodepoint(R))

        for j in range(dsRows, rows):
            L = crypto.add_keys2(rv.ss[i][j], c_old, pk[i][j])
            hasher.update(crypto.encodepoint(pk[i][j]))
            hasher.update(crypto.encodepoint(L))

        c = crypto.decodeint(hasher.digest())
        c_old = c
        i = (i + 1) % cols

        if i == 0:
            rv.cc = c_old

    for j in range(rows):
        rv.ss[index][j] = crypto.sc_mulsub(
            c, xx[j],
            alpha[j])  # alpha[j] - c * xx[j]; sc_mulsub in original does c-ab

    if mscout:
        mscout(c)

    return rv, c
예제 #3
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
예제 #4
0
def ver_mlsag(pk, I, c0, s):
    """
    Verify MLSAG
    :param pk:
    :param I:
    :param c0:
    :param s:
    :return:
    """
    rows = len(pk[0])
    cols = len(pk)
    logger.debug("verifying MG sig of dimensions %s x %s" % (rows, cols))
    c = [None] * (cols + 1)
    c[0] = c0
    L = key_matrix(rows, cols)
    R = key_matrix(rows, cols)

    m = "".join(pk[0])
    for i in range(1, cols):
        m = m + "".join(pk[i])

    i = 0
    while i < cols:
        L[i] = [crypto.add_keys2(s[i][j], c[i], pk[i][j]) for j in range(0, rows)]

        Hi = hash_key_vector(pk[i])
        R[i] = [crypto.add_keys3(s[i][j], Hi[j], c[i], I[j]) for j in range(0, rows)]

        oldi = i
        i = i + 1
        c[i] = crypto.cn_fast_hash(m + "".join(L[oldi]) + "".join(R[oldi]))

    return c0 == c[cols]
예제 #5
0
def gen_mlsag(pk, xx, index):
    """
    Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)

    These are aka MG signatutes in earlier drafts of the ring ct paper
    c.f. http://eprint.iacr.org/2015/1098 section 2.
    keyImageV just does I[i] = xx[i] * Hash(xx[i] * G) for each i

    Gen creates a signature which proves that for some column in the keymatrix "pk"
       the signer knows a secret key for each row in that column
    Ver verifies that the MG sig was created correctly

    :param pk:
    :param xx:
    :param index:
    :return:
    """
    rows = len(xx)
    cols = len(pk)
    logger.debug("Generating MG sig of size %s x %s" % (rows, cols))
    logger.debug("index is: %s, %s" % (index, pk[index]))
    c = [None] * cols
    alpha = scalar_gen_vector(rows)
    I = key_image_vector(xx)
    L = key_matrix(rows, cols)
    R = key_matrix(rows, cols)
    s = key_matrix(rows, cols)

    m = "".join(pk[0])
    for i in range(1, cols):
        m = m + "".join(pk[i])

    L[index] = [crypto.scalarmult_base(aa) for aa in alpha]  # L = aG
    Hi = hash_key_vector(pk[index])
    R[index] = [crypto.scalarmult(Hi[ii], alpha[ii])
                for ii in range(0, rows)]  # R = aI

    oldi = index
    i = (index + 1) % cols
    c[i] = crypto.cn_fast_hash(m + "".join(L[oldi]) + "".join(R[oldi]))

    while i != index:
        s[i] = scalar_gen_vector(rows)
        L[i] = [
            crypto.add_keys2(s[i][j], c[i], pk[i][j]) for j in range(0, rows)
        ]

        Hi = hash_key_vector(pk[i])
        R[i] = [
            crypto.add_keys3(s[i][j], Hi[j], c[i], I[j])
            for j in range(0, rows)
        ]
        oldi = i
        i = (i + 1) % cols
        c[i] = crypto.cn_fast_hash(m + "".join(L[oldi]) + "".join(R[oldi]))

    s[index] = [
        crypto.sc_mulsub(c[index], xx[j], alpha[j]) for j in range(0, rows)
    ]  # alpha - c * x
    return I, c[0], s
예제 #6
0
def ver_mlsag_ext(message, pk, rv, dsRows):
    """
    Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
    c.f. http://eprint.iacr.org/2015/1098 section 2.
    keyImageV just does I[i] = xx[i] * Hash(xx[i] * G) for each i

    :param message:
    :param pk: matrix of EC points, point form.
    :param rv:
    :param dsRows:
    :return:
    """
    rows, cols = ver_mlsag_assert(pk, rv, dsRows)
    c_old = rv.cc

    Ip = key_vector(dsRows)
    for i in range(dsRows):
        Ip[i] = crypto.precomp(rv.II[i])

    i = 0
    while i < cols:
        c = 0
        hasher = hasher_message(message)
        for j in range(dsRows):
            L = crypto.add_keys2(rv.ss[i][j], c_old, pk[i][j])
            Hi = crypto.hash_to_point(crypto.encodepoint(
                pk[i][j]))  # originally hashToPoint()
            R = crypto.add_keys3(rv.ss[i][j], Hi, c_old, Ip[j])
            hasher.update(crypto.encodepoint(pk[i][j]))
            hasher.update(crypto.encodepoint(L))
            hasher.update(crypto.encodepoint(R))

        for j in range(dsRows, rows):
            L = crypto.add_keys2(rv.ss[i][j], c_old, pk[i][j])
            hasher.update(crypto.encodepoint(pk[i][j]))
            hasher.update(crypto.encodepoint(L))

        c = crypto.decodeint(hasher.digest())
        c_old = c
        i += 1

    c = crypto.sc_sub(c_old, rv.cc)
    return not crypto.sc_isnonzero(c)
예제 #7
0
def gen_borromean(x, P1, P2, indices):
    """
    Generates Borromean signature for range proofs.
    :return:
    """
    n = len(P1)
    alpha = key_zero_vector(n)
    s1 = key_zero_vector(n)
    kck = crypto.get_keccak()  # ee computation

    for ii in range(n):
        alpha[ii] = crypto.random_scalar()
        L = crypto.scalarmult_base(alpha[ii])

        if indices[ii] == 0:
            s1[ii] = crypto.random_scalar()
            c = crypto.hash_to_scalar(crypto.encodepoint(L))
            L = crypto.add_keys2(s1[ii], c, P2[ii])
            kck.update(crypto.encodepoint(L))

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

    ee = crypto.decodeint(kck.digest())
    del kck

    s0 = key_zero_vector(n)

    for jj in range(n):
        if not indices[jj]:
            s0[jj] = crypto.sc_mulsub(x[jj], ee, alpha[jj])
        else:
            s0[jj] = crypto.random_scalar()
            LL = crypto.add_keys2(s0[jj], ee, P1[jj])
            cc = crypto.hash_to_scalar(crypto.encodepoint(LL))
            s1[jj] = crypto.sc_mulsub(x[jj], cc, alpha[jj])

    return s0, s1, ee
예제 #8
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
예제 #9
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
    :return: sumCi, mask, RangeSig.
        sumCi is Pedersen commitment on the amount value. sumCi = aG + amount*H
        mask is "a" from the Pedersent commitment above.
    """
    n = ATOMS
    bb = d2b(amount, n)  # gives binary form of bb in "digits" binary digits
    ai = [None] * len(bb)
    Ci = [None] * len(bb)
    a = crypto.sc_0()

    C = crypto.identity()
    alpha = mlsag2.key_zero_vector(n)
    s1 = mlsag2.key_zero_vector(n)
    c_H = crypto.xmr_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 == ATOMS - 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:
            Ci[ii] = crypto.scalarmult_base(ai[ii])
        else:
            Ci[ii] = crypto.point_add(crypto.scalarmult_base(ai[ii]), c_H)
        C = crypto.point_add(C, Ci[ii])

        if bb[ii] == 0:
            s1[ii] = crypto.random_scalar()
            c = crypto.hash_to_scalar(crypto.encodepoint(L))
            L = crypto.add_keys2(s1[ii], c, crypto.point_sub(Ci[ii], c_H))
            kck.update(crypto.encodepoint(L))

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

        c_H = crypto.point_double(c_H)

    # Compute ee, memory cleanup
    ee = crypto.decodeint(kck.digest())
    del kck

    # Second phase computes: s0, s1
    c_H = crypto.xmr_H()
    s0 = mlsag2.key_zero_vector(n)

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

        else:
            s0[jj] = crypto.random_scalar()
            LL = crypto.add_keys2(s0[jj], ee, Ci[jj])
            cc = crypto.hash_to_scalar(crypto.encodepoint(LL))
            s1[jj] = crypto.sc_mulsub(ai[jj], cc, alpha[jj])
        c_H = crypto.point_double(c_H)

    A = xmrtypes.BoroSig()
    A.s0, A.s1, A.ee = s0, s1, ee

    R = xmrtypes.RangeSig()
    R.asig = A
    R.Ci = Ci

    return C, a, R
예제 #10
0
    async def gen_input(self,
                        value=1,
                        sub_major=None,
                        sub_minor=0,
                        additionals=False):
        creds = self.src_keys
        r = self.random_scalar()
        R = crypto.scalarmult_base(r)
        additional_keys = []
        Additional = None
        sub_major = sub_major if sub_major is not None else self.account_idx
        is_sub = sub_major != 0 or sub_minor != 0

        if sub_major != self.account_idx:
            logger.warning(
                "Generating input with different major subindex, cannot be spent in the resulting "
                "transaction")

        kssec = monero.get_subaddress_secret_key(creds.view_key_private,
                                                 major=sub_major,
                                                 minor=sub_minor)
        kssub = crypto.sc_add(
            kssec,
            creds.spend_key_private) if is_sub else creds.spend_key_private
        kvsub = crypto.sc_mul(creds.view_key_private,
                              kssub) if is_sub else creds.view_key_private
        KSSUB, KVSUB = monero.generate_sub_address_keys(
            creds.view_key_private, creds.spend_key_public, sub_major,
            sub_minor)

        if not crypto.point_eq(KSSUB, crypto.scalarmult_base(kssub)):
            raise ValueError("Invariant error")

        oidx = self.prng.randint(0, 12)
        additionals_cnt = self.prng.randint(oidx + 1, 2 * oidx + 1)
        deriv = crypto.generate_key_derivation(KVSUB, r)
        kout = crypto.derive_secret_key(deriv, oidx, kssub)
        KOUT = crypto.derive_public_key(deriv, oidx, KSSUB)
        if not crypto.point_eq(KOUT, crypto.scalarmult_base(kout)):
            raise ValueError("Invariant error")

        if additionals:
            if is_sub:
                Additional = crypto.scalarmult(KSSUB, r)
            else:
                Additional = crypto.scalarmult_base(r)
        else:
            if is_sub:
                R = crypto.scalarmult(KSSUB, r)

        amnt = crypto.sc_init(value)
        msk = self.random_scalar()  # commitment mask
        C = crypto.add_keys2(msk, amnt, crypto.xmr_H())

        ring = []
        for i in range(self.ring_size - 1):
            tk = CtKey(
                dest=crypto.encodepoint(self.random_pub()),
                mask=crypto.encodepoint(self.random_pub()),
            )
            ring.append(tk)

        index = self.prng.randint(0, len(ring))
        ring.insert(
            index,
            CtKey(dest=crypto.encodepoint(KOUT), mask=crypto.encodepoint(C)))
        if additionals:
            additional_keys = [
                self.random_pub() for _ in range(additionals_cnt)
            ]
            additional_keys[oidx] = Additional

        src = TxSourceEntry()
        src.outputs = [(self.random_glob_idx(), x) for x in ring]
        src.real_output = index
        src.real_out_tx_key = crypto.encodepoint(R)
        src.real_out_additional_tx_keys = [
            crypto.encodepoint(x) for x in additional_keys
        ]
        src.real_output_in_tx_index = oidx
        src.amount = value
        src.rct = True
        src.mask = crypto.encodeint(msk)
        src.multisig_kLRki = MultisigKLRki(K=crypto.ZERO,
                                           L=crypto.ZERO,
                                           R=crypto.ZERO,
                                           ki=crypto.ZERO)

        td = TransferDetails()
        td.m_internal_output_index = oidx
        td.m_global_output_index = src.outputs[index][0]
        td.m_mask = src.mask
        td.m_amount = value
        td.m_subaddr_index = SubaddressIndex(major=sub_major, minor=sub_minor)
        td.m_rct = True
        td.m_txid = self.random_bytes(32)
        td.m_block_height = self.prng.randint(0, 0xFFFF)
        td.m_spent = False
        td.m_spent_height = 0
        td.m_key_image_known = True
        td.m_key_image_requested = False
        td.m_key_image_partial = False
        td.m_multisig_k = []
        td.m_multisig_info = []
        td.m_uses = []
        td.m_pk_index = 0
        td.m_tx = self.gen_tx_prefix(self.prng.randint(1, 10), additionals_cnt)
        td.m_tx.vout[oidx].target.key = crypto.encodepoint(KOUT)

        extras = []
        extras.append(TxExtraNonce(nonce=self.random_bytes(8)))
        extras.append(TxExtraPubKey(pub_key=src.real_out_tx_key))
        if src.real_out_additional_tx_keys:
            extras.append(
                TxExtraAdditionalPubKeys(data=src.real_out_additional_tx_keys))
        td.m_tx.extra = await self.dump_extra_fields(extras)

        tmpsubs = {}
        monero.compute_subaddresses(creds, sub_major, [sub_minor], tmpsubs)
        xi, ki, rderiv = self.check_input(src, creds, tmpsubs)
        if not crypto.sc_eq(xi, kout):
            raise ValueError("Invariant error")

        td.m_key_image = crypto.encodepoint(ki)

        self.sources.append(src)
        self.selected_transfers.append(len(self.transfers))
        self.transfers.append(td)
        self.sources_creds.append(creds)

        if not crypto.point_eq(
                crypto.decodepoint(src.outputs[src.real_output][1].dest),
                crypto.scalarmult_base(kout)):
            raise ValueError("Invariant error")

        return self