def _rsig_bp(state: State) -> bytes: """Bulletproof calculation in trezor""" from apps.monero.xmr import range_signatures rsig = range_signatures.prove_range_bp_batch(state.output_amounts, state.output_masks, state.rsig_is_bp_plus) 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, raw=False) state.mem_trace("post-bp-hash" if __debug__ else None, collect=True) rsig = _dump_rsig_bp_plus( rsig) if state.rsig_is_bp_plus else _dump_rsig_bp(rsig) state.mem_trace(f"post-bp-ser, size: {len(rsig)}" if __debug__ else None, collect=True) # state cleanup state.output_masks = [] state.output_amounts = [] return rsig
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