Example #1
0
def _return_rsig_data(rsig):
    if rsig is None:
        return None
    from trezor.messages.MoneroTransactionRsigData import MoneroTransactionRsigData

    if isinstance(rsig, list):
        return MoneroTransactionRsigData(rsig_parts=rsig)
    else:
        return MoneroTransactionRsigData(rsig=rsig)
def _return_rsig_data(rsig=None, mask=None):
    if rsig is None and mask is None:
        return None

    from trezor.messages.MoneroTransactionRsigData import MoneroTransactionRsigData

    rsig_data = MoneroTransactionRsigData()

    if mask:
        rsig_data.mask = mask

    if rsig:
        rsig_data.rsig = rsig

    return rsig_data
Example #3
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
Example #4
0
async def _compute_masks(state: State):
    """
    Output masks computed in advance. Used with client_version=0 && HF9.
    After HF10 (included) masks are deterministic, computed from the amount_key.

    After all client update to v1 this code will be removed.
    In order to preserve client_version=0 compatibility the masks have to be adjusted.
    """
    from trezor.messages.MoneroTransactionRsigData import MoneroTransactionRsigData
    from apps.monero.signing import offloading_keys

    rsig_data = MoneroTransactionRsigData()

    # 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:
        rsig_data.mask = []

    # Deterministic masks, the last one is computed to balance the sums
    for i in range(state.output_count):
        if i + 1 == state.output_count:
            cur_mask = crypto.sc_sub(state.sumpouts_alphas, state.sumout)
            state.output_last_mask = cur_mask
        else:
            cur_mask = offloading_keys.det_comm_masks(state.key_enc, i)

        crypto.sc_add_into(state.sumout, state.sumout, cur_mask)

        if state.rsig_offload:
            rsig_data.mask.append(crypto.encodeint(cur_mask))

    if not crypto.sc_eq(state.sumpouts_alphas, state.sumout):
        raise ValueError("Sum eq error")

    state.sumout = crypto.sc_init(0)
    return rsig_data
Example #5
0
def _rsig_process_bp(state: State, rsig_data: MoneroTransactionRsigData):
    from apps.monero.xmr import range_signatures
    from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import Bulletproof

    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, raw=False)
    res = range_signatures.verify_bp(bp_obj, state.output_amounts, state.output_masks)
    utils.ensure(res, "BP verification fail")
    state.mem_trace("BP verified" if __debug__ else None, collect=True)
    del (bp_obj, range_signatures)

    # State cleanup after verification is finished
    state.output_amounts = []
    state.output_masks = []
async def init_transaction(
    state: State,
    address_n: list,
    network_type: int,
    tsx_data: MoneroTransactionData,
    keychain,
) -> MoneroTransactionInitAck:
    from apps.monero.signing import offloading_keys
    from apps.common import paths

    await paths.validate_path(state.ctx, misc.validate_full_path, keychain,
                              address_n, CURVE)

    state.creds = misc.get_creds(keychain, address_n, network_type)
    state.client_version = tsx_data.client_version or 0
    if state.client_version == 0:
        raise ValueError("Client version not supported")

    state.fee = state.fee if state.fee > 0 else 0
    state.tx_priv = crypto.random_scalar()
    state.tx_pub = crypto.scalarmult_base(state.tx_priv)
    state.mem_trace(1)

    state.input_count = tsx_data.num_inputs
    state.output_count = len(tsx_data.outputs)
    state.progress_total = 4 + 3 * state.input_count + state.output_count
    state.progress_cur = 0

    # Ask for confirmation
    await confirms.require_confirm_transaction(state.ctx, state, tsx_data,
                                               state.creds.network_type)
    state.creds.address = None
    state.creds.network_type = None
    gc.collect()
    state.mem_trace(3)

    # Basic transaction parameters
    state.output_change = tsx_data.change_dts
    state.mixin = tsx_data.mixin
    state.fee = tsx_data.fee
    state.account_idx = tsx_data.account
    state.last_step = state.STEP_INIT
    if tsx_data.hard_fork:
        state.hard_fork = tsx_data.hard_fork

    # Ensure change is correct
    _check_change(state, tsx_data.outputs)

    # At least two outpus are required, this applies also for sweep txs
    # where one fake output is added. See _check_change for more info
    if state.output_count < 2:
        raise signing.NotEnoughOutputsError(
            "At least two outputs are required")

    _check_rsig_data(state, tsx_data.rsig_data)
    _check_subaddresses(state, tsx_data.outputs)

    # Extra processing, payment id
    _process_payment_id(state, tsx_data)
    await _compute_sec_keys(state, tsx_data)
    gc.collect()

    # Iterative tx_prefix_hash hash computation
    state.tx_prefix_hasher.uvarint(
        2)  # current Monero transaction format (RingCT = 2)
    state.tx_prefix_hasher.uvarint(tsx_data.unlock_time)
    state.tx_prefix_hasher.uvarint(state.input_count)  # ContainerType, size
    state.mem_trace(10, True)

    # Final message hasher
    state.full_message_hasher.init()
    state.full_message_hasher.set_type_fee(signing.RctType.Bulletproof2,
                                           state.fee)

    # Sub address precomputation
    if tsx_data.account is not None and tsx_data.minor_indices:
        _precompute_subaddr(state, tsx_data.account, tsx_data.minor_indices)
    state.mem_trace(5, True)

    # HMACs all outputs to disallow tampering.
    # Each HMAC is then sent alongside the output
    # and trezor validates it.
    hmacs = []
    for idx in range(state.output_count):
        c_hmac = await offloading_keys.gen_hmac_tsxdest(
            state.key_hmac, tsx_data.outputs[idx], idx)
        hmacs.append(c_hmac)
        gc.collect()

    state.mem_trace(6)

    from trezor.messages.MoneroTransactionInitAck import MoneroTransactionInitAck
    from trezor.messages.MoneroTransactionRsigData import MoneroTransactionRsigData

    rsig_data = MoneroTransactionRsigData(offload_type=state.rsig_offload)

    return MoneroTransactionInitAck(hmacs=hmacs, rsig_data=rsig_data)