Ejemplo n.º 1
0
def get_exponent(dst, base, idx):
    dst = _ensure_dst_key(dst)
    salt = b"bulletproof"
    idx_size = uvarint_size(idx)
    final_size = len(salt) + 32 + idx_size
    buff = tmp_bf_exp_mv
    memcpy(buff, 0, base, 0, 32)
    memcpy(buff, 32, salt, 0, len(salt))
    dump_uvarint_b_into(idx, buff, 32 + len(salt))
    crypto.keccak_hash_into(tmp_bf_1, buff[:final_size])
    crypto.hash_to_point_into(tmp_pt_1, tmp_bf_1)
    crypto.encodepoint_into(dst, tmp_pt_1)
    return dst
def _set_tx_extra(state: State) -> bytes:
    """
    Sets tx public keys into transaction's extra.
    Extra field is supposed to be sorted (by sort_tx_extra() in the Monero)
    Tag ordering: TX_EXTRA_TAG_PUBKEY, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS, TX_EXTRA_NONCE
    """
    from apps.monero.xmr.serialize import int_serialize

    # Extra buffer length computation
    # TX_EXTRA_TAG_PUBKEY (1B) | tx_pub_key (32B)
    extra_size = 33
    offset = 0
    num_keys = 0
    len_size = 0

    if state.need_additional_txkeys:
        num_keys = len(state.additional_tx_public_keys)
        len_size = int_serialize.uvarint_size(num_keys)

        # TX_EXTRA_TAG_ADDITIONAL_PUBKEYS (1B) | varint | keys
        extra_size += 1 + len_size + 32 * num_keys

    if state.extra_nonce:
        extra_size += len(state.extra_nonce)

    extra = bytearray(extra_size)
    extra[0] = 1  # TX_EXTRA_TAG_PUBKEY
    crypto.encodepoint_into(memoryview(extra)[1:], state.tx_pub)
    offset += 33

    if state.need_additional_txkeys:
        extra[offset] = 0x4  # TX_EXTRA_TAG_ADDITIONAL_PUBKEYS
        int_serialize.dump_uvarint_b_into(num_keys, extra, offset + 1)
        offset += 1 + len_size

        for idx in range(num_keys):
            extra[offset:offset + 32] = state.additional_tx_public_keys[idx]
            offset += 32

    if state.extra_nonce:
        utils.memcpy(extra, offset, state.extra_nonce, 0,
                     len(state.extra_nonce))
        state.extra_nonce = None

    return extra
def _add_additional_tx_pub_keys_to_extra(tx_extra, pub_keys):
    """
    Adds all additional tx public keys to the extra buffer
    """
    from apps.monero.xmr.serialize import int_serialize

    # format: variant_tag (0x4) | array len varint | 32B | 32B | ...
    num_keys = len(pub_keys)
    len_size = int_serialize.uvarint_size(num_keys)
    buffer = bytearray(1 + len_size + 32 * num_keys)

    buffer[0] = 0x4  # TX_EXTRA_TAG_ADDITIONAL_PUBKEYS
    int_serialize.dump_uvarint_b_into(num_keys, buffer, 1)  # uvarint(num_keys)
    offset = 1 + len_size

    for idx in range(num_keys):
        buffer[offset : offset + 32] = pub_keys[idx]
        offset += 32

    tx_extra += buffer
    return tx_extra
Ejemplo n.º 4
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