Skip to content

Commit

Permalink
xmr: state's use_simple_rct and use_bulletproof modified to enums
Browse files Browse the repository at this point in the history
  • Loading branch information
tsusanka committed Oct 11, 2018
1 parent 276712a commit 8303b42
Show file tree
Hide file tree
Showing 12 changed files with 113 additions and 48 deletions.
21 changes: 21 additions & 0 deletions src/apps/monero/controller/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,24 @@ def dump_rsig_bp(rsig):
offset += 32
memcpy(buff, offset, rsig.t, 0, 32)
return buff


def get_monero_rct_type(rct_type, rsig_type):
"""
This converts our internal representation of RctType and RsigType
into what is used in Monero:
- Null = 0
- Full = 1
- Simple = 2
- Simple/Full with bulletproof = 3
"""
from apps.monero.protocol.signing.rct_type import RctType
from apps.monero.protocol.signing.rsig_type import RsigType

if rsig_type == RsigType.Bulletproof:
return 3 # Bulletproofs

if rct_type == RctType.Simple:
return 2 # Simple
else:
return 1 # Full
13 changes: 13 additions & 0 deletions src/apps/monero/protocol/signing/rct_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""
There are two types of monero Ring Confidential Transactions:
1. RCTTypeFull = 1 (used if num_inputs == 1)
2. RCTTypeSimple = 2 (for num_inputs > 1)
There is actually also RCTTypeNull but we ignore that one.
"""
# TODO: to be moved somewhere else


class RctType:
Full = 1
Simple = 2
17 changes: 17 additions & 0 deletions src/apps/monero/protocol/signing/rsig_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# TODO: to be moved somewhere else
"""
Range signature types
There are four types of range proofs/signatures in official Monero:
1. RangeProofBorromean = 0
2. RangeProofBulletproof = 1
3. RangeProofMultiOutputBulletproof = 2
4. RangeProofPaddedBulletproof = 3
We simplify all the bulletproofs into one.
"""


class RsigType:
Borromean = 0
Bulletproof = 1
23 changes: 7 additions & 16 deletions src/apps/monero/protocol/signing/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,12 @@ def __init__(self, ctx):
"""
self.need_additional_txkeys = False

# TODO to be modified
self.use_bulletproof = False
self.use_simple_rct = False
# Ring Confidential Transaction type
# allowed values: RctType.{Full, Simple}
self.rct_type = None
# Range Signature type (also called range proof)
# allowed values: RsigType.{Borromean, Bulletproof}
self.rsig_type = None

self.input_count = 0
self.output_count = 0
Expand Down Expand Up @@ -96,7 +99,7 @@ def __init__(self, ctx):
# the range proofs are calculated in batches, this denotes the grouping
self.rsig_grouping = []
# is range proof computing offloaded or not
self.rsig_offload = 0
self.rsig_offload = False

# sum of all inputs' pseudo out masks
self.sumpouts_alphas = crypto.sc_0()
Expand Down Expand Up @@ -147,15 +150,3 @@ def assrt(self, condition, msg=None):

def change_address(self):
return self.output_change.addr if self.output_change else None

def get_rct_type(self):
"""
RCTsig type (simple/full x Borromean/Bulletproof)
:return:
"""
from apps.monero.xmr.serialize_messages.tx_rsig import RctType

if self.use_simple_rct:
return RctType.FullBulletproof if self.use_bulletproof else RctType.Simple
else:
return RctType.Full
38 changes: 28 additions & 10 deletions src/apps/monero/protocol/signing/step_01_init_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

from apps.monero.controller import misc
from apps.monero.layout import confirms
from apps.monero.protocol.signing.rct_type import RctType
from apps.monero.protocol.signing.rsig_type import RsigType
from apps.monero.protocol.signing.state import State
from apps.monero.xmr import common, crypto, monero

Expand Down Expand Up @@ -49,7 +51,7 @@ async def init_transaction(
if state.output_count < 2:
raise misc.TrezorNotEnoughOutputs("At least two outputs are required")

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

# Extra processing, payment id
Expand All @@ -66,8 +68,10 @@ async def init_transaction(
state.mem_trace(10, True)

# Final message hasher
state.full_message_hasher.init(state.use_simple_rct) # TODO investigate
state.full_message_hasher.set_type_fee(state.get_rct_type(), state.fee)
state.full_message_hasher.init(state.rct_type == RctType.Simple)
state.full_message_hasher.set_type_fee(
misc.get_monero_rct_type(state.rct_type, state.rsig_type), state.fee
)

# Sub address precomputation
if tsx_data.account is not None and tsx_data.minor_indices:
Expand Down Expand Up @@ -160,7 +164,7 @@ def _get_primary_change_address(state: State):
)


def _check_ringct_type(state: State, rsig_data: MoneroTransactionRsigData):
def _check_rsig_data(state: State, rsig_data: MoneroTransactionRsigData):
"""
There are two types of monero ring confidential transactions:
1. RCTTypeFull = 1 (used if num_inputs == 1)
Expand All @@ -172,11 +176,23 @@ def _check_ringct_type(state: State, rsig_data: MoneroTransactionRsigData):
3. RangeProofMultiOutputBulletproof = 2
4. RangeProofPaddedBulletproof = 3
"""
# TODO maybe make this more explicit - also in the state
state.rsig_grouping = rsig_data.grouping
state.rsig_offload = rsig_data.rsig_type > 0 and state.output_count > 2
state.use_bulletproof = rsig_data.rsig_type > 0
state.use_simple_rct = state.input_count > 1 or rsig_data.rsig_type != 0

if rsig_data.rsig_type == 0:
state.rsig_type = RsigType.Borromean
elif rsig_data.rsig_type in (1, 2, 3):
state.rsig_type = RsigType.Bulletproof
else:
raise ValueError("Unknown rsig type")

# unintuitively RctType.Simple is used for more inputs
if state.input_count > 1 or state.rsig_type == RsigType.Bulletproof:
state.rct_type = RctType.Simple
else:
state.rct_type = RctType.Full

if state.rsig_type == RsigType.Bulletproof and state.output_count > 2:
state.rsig_offload = True


def _check_change(state: State, outputs: list):
Expand Down Expand Up @@ -275,8 +291,6 @@ def _process_payment_id(state: State, tsx_data: MoneroTransactionData):
view_key_pub_enc = _get_key_for_payment_id_encryption(
tsx_data.outputs, state.change_address()
)
if view_key_pub_enc == crypto.NULL_KEY_ENC:
raise ValueError("Invalid key") # TODO can this be removed?

view_key_pub = crypto.decodepoint(view_key_pub_enc)
payment_id_encr = _encrypt_payment_id(
Expand Down Expand Up @@ -332,6 +346,10 @@ def _get_key_for_payment_id_encryption(destinations: list, change_addr=None):
)
addr = dest.addr
count += 1

if addr.view_public_key == crypto.NULL_KEY_ENC:
raise ValueError("Invalid key")

return addr.view_public_key


Expand Down
3 changes: 2 additions & 1 deletion src/apps/monero/protocol/signing/step_02_set_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

from apps.monero.controller import misc
from apps.monero.layout import confirms
from apps.monero.protocol.signing.rct_type import RctType
from apps.monero.xmr import crypto, monero

if False:
Expand Down Expand Up @@ -99,7 +100,7 @@ async def set_input(state: State, src_entr: MoneroTransactionSourceEntry):
pseudo_out_hmac = None
alpha_enc = None

if state.use_simple_rct:
if state.rct_type == RctType.Simple:
alpha, pseudo_out = _gen_commitment(state, src_entr.amount)
pseudo_out = crypto.encodepoint(pseudo_out)

Expand Down
6 changes: 4 additions & 2 deletions src/apps/monero/protocol/signing/step_04_input_vini.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

from apps.monero.layout import confirms
from apps.monero.protocol import hmac_encryption_keys
from apps.monero.protocol.signing.rct_type import RctType
from apps.monero.protocol.signing.rsig_type import RsigType
from apps.monero.xmr import common, crypto

if False:
Expand Down Expand Up @@ -52,8 +54,8 @@ async def input_vini(
state.tx_prefix_hasher.buffer(vini_bin)

# in monero version >= 8 pseudo outs were moved to a different place
# use_bulletproofs implies version >= 8
if state.use_simple_rct and not state.use_bulletproof:
# bulletproofs imply version >= 8
if state.rct_type == RctType.Simple and state.rsig_type != RsigType.Bulletproof:
_hash_vini_pseudo_out(state, pseudo_out, pseudo_out_hmac)

return MoneroTransactionInputViniAck()
Expand Down
5 changes: 3 additions & 2 deletions src/apps/monero/protocol/signing/step_05_all_inputs_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .state import State

from apps.monero.layout import confirms
from apps.monero.protocol.signing.rct_type import RctType
from apps.monero.xmr import crypto


Expand All @@ -27,7 +28,7 @@ async def all_inputs_set(state: State):
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.use_simple_rct:
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:
Expand All @@ -36,7 +37,7 @@ async def all_inputs_set(state: State):
crypto.sc_add_into(state.sumout, state.sumout, cur_mask)
state.output_masks.append(cur_mask)

if state.use_simple_rct:
if state.rct_type == RctType.Simple:
state.assrt(
crypto.sc_eq(state.sumout, state.sumpouts_alphas), "Invalid masks sum"
) # sum check
Expand Down
9 changes: 5 additions & 4 deletions src/apps/monero/protocol/signing/step_06_set_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from apps.monero.controller import misc
from apps.monero.layout import confirms
from apps.monero.protocol import hmac_encryption_keys
from apps.monero.protocol.signing.rsig_type import RsigType
from apps.monero.xmr import common, crypto


Expand Down Expand Up @@ -176,7 +177,7 @@ def _range_proof(state, amount, rsig_data):
C, rsig = None, None

state.mem_trace("pre-rproof" if __debug__ else None, collect=True)
if not state.rsig_offload and state.use_bulletproof:
if state.rsig_type == RsigType.Bulletproof and not state.rsig_offload:
"""Bulletproof calculation in trezor"""
rsig = ring_ct.prove_range_bp_batch(state.output_amounts, state.output_masks)
state.mem_trace("post-bp" if __debug__ else None, collect=True)
Expand All @@ -193,7 +194,7 @@ def _range_proof(state, amount, rsig_data):
"post-bp-ser, size: %s" % len(rsig) if __debug__ else None, collect=True
)

elif not state.rsig_offload and not state.use_bulletproof:
elif state.rsig_type == RsigType.Borromean and not state.rsig_offload:
"""Borromean calculation in trezor"""
C, mask, rsig = ring_ct.prove_range_chunked(amount, mask)
del (ring_ct)
Expand All @@ -202,7 +203,7 @@ def _range_proof(state, amount, rsig_data):
state.full_message_hasher.rsig_val(rsig, False, raw=True)
_check_out_commitment(state, amount, mask, C)

elif state.rsig_offload and state.use_bulletproof:
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

Expand All @@ -223,7 +224,7 @@ def _range_proof(state, amount, rsig_data):
state.mem_trace("BP verified" if __debug__ else None, collect=True)
del (bp_obj, ring_ct)

elif state.rsig_offload and not state.use_bulletproof:
elif state.rsig_type == RsigType.Borromean and state.rsig_offload:
"""Borromean offloading not supported"""
raise misc.TrezorError(
"Unsupported rsig state (Borromean offloaded is not supported)"
Expand Down
9 changes: 7 additions & 2 deletions src/apps/monero/protocol/signing/step_07_all_outputs_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from .state import State

from apps.monero.controller import misc
from apps.monero.layout import confirms
from apps.monero.xmr import crypto

Expand Down Expand Up @@ -46,7 +47,9 @@ async def all_outputs_set(state: State):

# Initializes RCTsig structure (fee, tx prefix hash, type)
rv_pb = MoneroRingCtSig(
txn_fee=state.fee, message=state.tx_prefix_hash, rv_type=state.get_rct_type()
txn_fee=state.fee,
message=state.tx_prefix_hash,
rv_type=misc.get_monero_rct_type(state.rct_type, state.rsig_type),
)

return MoneroTransactionAllOutSetAck(
Expand All @@ -55,11 +58,13 @@ async def all_outputs_set(state: State):


def _validate(state: State):
from apps.monero.protocol.signing.rct_type import RctType

if state.current_output_index + 1 != state.output_count:
raise ValueError("Invalid out num")

# Test if \sum Alpha == \sum A
if state.use_simple_rct:
if state.rct_type == RctType.Simple:
state.assrt(crypto.sc_eq(state.sumout, state.sumpouts_alphas))

# Fee test
Expand Down
11 changes: 6 additions & 5 deletions src/apps/monero/protocol/signing/step_09_sign_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from apps.monero.controller import misc
from apps.monero.layout import confirms
from apps.monero.protocol.signing.rct_type import RctType
from apps.monero.xmr import common, crypto

if False:
Expand Down Expand Up @@ -47,11 +48,11 @@ async def sign_input(
state.current_input_index += 1
if state.current_input_index >= state.input_count:
raise ValueError("Invalid inputs count")
if state.use_simple_rct and pseudo_out is None:
if state.rct_type == RctType.Simple and pseudo_out is None:
raise ValueError("SimpleRCT requires pseudo_out but none provided")
if state.use_simple_rct and pseudo_out_alpha_enc is None:
if state.rct_type == RctType.Simple and pseudo_out_alpha_enc is None:
raise ValueError("SimpleRCT requires pseudo_out's mask but none provided")
if state.current_input_index >= 1 and not state.use_simple_rct:
if state.current_input_index >= 1 and not state.rct_type == RctType.Simple:
raise ValueError("Two and more inputs must imply SimpleRCT")

input_position = state.source_permutation[state.current_input_index]
Expand All @@ -66,7 +67,7 @@ async def sign_input(
gc.collect()
state.mem_trace(1)

if state.use_simple_rct:
if state.rct_type == RctType.Simple:
# both pseudo_out and its mask were offloaded so we need to
# validate pseudo_out's HMAC and decrypt the alpha
pseudo_out_hmac_comp = crypto.compute_hmac(
Expand Down Expand Up @@ -130,7 +131,7 @@ async def sign_input(
# RCT signature
from apps.monero.xmr import mlsag2

if state.use_simple_rct:
if state.rct_type == RctType.Simple:
# Simple RingCT
mix_ring = [x.key for x in src_entr.outputs]
mg, msc = mlsag2.prove_rct_mg_simple(
Expand Down
6 changes: 0 additions & 6 deletions src/apps/monero/xmr/serialize_messages/tx_rsig.py

This file was deleted.

0 comments on commit 8303b42

Please sign in to comment.