コード例 #1
0
def _range_proof(
    state: State, rsig_data: MoneroTransactionRsigData
) -> tuple[MoneroTransactionRsigData, crypto.Scalar]:
    """
    Computes rangeproof and handles range proof offloading logic.

    Since HF10 the commitments are deterministic.
    The range proof is incrementally hashed to the final_message.
    """
    provided_rsig = None
    if rsig_data and rsig_data.rsig and len(rsig_data.rsig) > 0:
        provided_rsig = rsig_data.rsig
    if not state.rsig_offload and provided_rsig:
        raise signing.Error("Provided unexpected rsig")

    # Batching & validation
    bidx = _get_rsig_batch(state, state.current_output_index)
    last_in_batch = _is_last_in_batch(state, state.current_output_index, bidx)
    if state.rsig_offload and provided_rsig and not last_in_batch:
        raise signing.Error("Provided rsig too early")

    if (state.rsig_offload and last_in_batch and not provided_rsig
            and state.is_processing_offloaded):
        raise signing.Error("Rsig expected, not provided")

    # Batch not finished, skip range sig generation now
    mask = state.output_masks[-1] if not state.is_processing_offloaded else None
    offload_mask = mask and state.rsig_offload

    # If not last, do not proceed to the BP processing.
    if not last_in_batch:
        rsig_data_new = (_return_rsig_data(
            mask=crypto_helpers.encodeint(mask)) if offload_mask else None)
        return rsig_data_new, mask

    # Rangeproof
    # Pedersen commitment on the value, mask from the commitment, range signature.
    rsig = None

    state.mem_trace("pre-rproof" if __debug__ else None, collect=True)
    if not state.rsig_offload:
        # Bulletproof calculation in Trezor
        rsig = _rsig_bp(state)

    elif not state.is_processing_offloaded:
        # Bulletproof offloaded to the host, deterministic masks. Nothing here, waiting for offloaded BP.
        pass

    else:
        # Bulletproof offloaded to the host, check BP, hash it.
        _rsig_process_bp(state, rsig_data)

    state.mem_trace("rproof" if __debug__ else None, collect=True)

    # Construct new rsig data to send back to the host.
    rsig_data_new = _return_rsig_data(
        rsig,
        crypto_helpers.encodeint(mask) if offload_mask else None)

    if state.current_output_index + 1 == state.output_count and (
            not state.rsig_offload or state.is_processing_offloaded):
        # output masks and amounts are not needed anymore
        state.output_amounts = None
        state.output_masks = None

    return rsig_data_new, mask
コード例 #2
0
def _range_proof(state, amount, rsig_data):
    """
    Computes rangeproof
    In order to optimize incremental transaction build, the mask computation is changed compared
    to the official Monero code. In the official code, the input pedersen commitments are computed
    after range proof in such a way summed masks for commitments (alpha) and rangeproofs (ai) are equal.

    In order to save roundtrips we compute commitments randomly and then for the last rangeproof
    a[63] = (\\sum_{i=0}^{num_inp}alpha_i - \\sum_{i=0}^{num_outs-1} amasks_i) - \\sum_{i=0}^{62}a_i

    The range proof is incrementally hashed to the final_message.
    """
    from apps.monero.xmr import range_signatures

    mask = state.output_masks[state.current_output_index]
    provided_rsig = None
    if rsig_data and rsig_data.rsig and len(rsig_data.rsig) > 0:
        provided_rsig = rsig_data.rsig
    if not state.rsig_offload and provided_rsig:
        raise signing.Error("Provided unexpected rsig")

    # Batching
    bidx = _get_rsig_batch(state, state.current_output_index)
    batch_size = state.rsig_grouping[bidx]
    last_in_batch = _is_last_in_batch(state, state.current_output_index, bidx)
    if state.rsig_offload and provided_rsig and not last_in_batch:
        raise signing.Error("Provided rsig too early")
    if state.rsig_offload and last_in_batch and not provided_rsig:
        raise signing.Error("Rsig expected, not provided")

    # Batch not finished, skip range sig generation now
    if not last_in_batch:
        return None, mask

    # Rangeproof
    # Pedersen commitment on the value, mask from the commitment, range signature.
    C, rsig = None, None

    state.mem_trace("pre-rproof" if __debug__ else None, collect=True)
    if state.rsig_type == RsigType.Bulletproof and not state.rsig_offload:
        """Bulletproof calculation in trezor"""
        rsig = range_signatures.prove_range_bp_batch(state.output_amounts,
                                                     state.output_masks)
        state.mem_trace("post-bp" if __debug__ else None, collect=True)

        # Incremental BP hashing
        # BP is hashed with raw=False as hash does not contain L, R
        # array sizes compared to the serialized bulletproof format
        # thus direct serialization cannot be used.
        state.full_message_hasher.rsig_val(rsig, True, raw=False)
        state.mem_trace("post-bp-hash" if __debug__ else None, collect=True)

        rsig = _dump_rsig_bp(rsig)
        state.mem_trace("post-bp-ser, size: %s" %
                        len(rsig) if __debug__ else None,
                        collect=True)

    elif state.rsig_type == RsigType.Borromean and not state.rsig_offload:
        """Borromean calculation in trezor"""
        C, mask, rsig = range_signatures.prove_range_borromean(amount, mask)
        del range_signatures

        # Incremental hashing
        state.full_message_hasher.rsig_val(rsig, False, raw=True)
        _check_out_commitment(state, amount, mask, C)

    elif state.rsig_type == RsigType.Bulletproof and state.rsig_offload:
        """Bulletproof calculated on host, verify in trezor"""
        from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import Bulletproof

        # TODO this should be tested
        # last_in_batch = True (see above) so this is fine
        masks = state.output_masks[1 + state.current_output_index -
                                   batch_size:1 + state.current_output_index]
        bp_obj = serialize.parse_msg(rsig_data.rsig, Bulletproof)
        rsig_data.rsig = None

        # BP is hashed with raw=False as hash does not contain L, R
        # array sizes compared to the serialized bulletproof format
        # thus direct serialization cannot be used.
        state.full_message_hasher.rsig_val(bp_obj, True, raw=False)
        res = range_signatures.verify_bp(bp_obj, state.output_amounts, masks)
        utils.ensure(res, "BP verification fail")
        state.mem_trace("BP verified" if __debug__ else None, collect=True)
        del (bp_obj, range_signatures)

    elif state.rsig_type == RsigType.Borromean and state.rsig_offload:
        """Borromean offloading not supported"""
        raise signing.Error(
            "Unsupported rsig state (Borromean offloaded is not supported)")

    else:
        raise signing.Error("Unexpected rsig state")

    state.mem_trace("rproof" if __debug__ else None, collect=True)
    if state.current_output_index + 1 == state.output_count:
        # output masks and amounts are not needed anymore
        state.output_amounts = []
        state.output_masks = []
    return rsig, mask