Skip to content

Commit

Permalink
xmr: protocol optimizations removed, flow unified
Browse files Browse the repository at this point in the history
- in_memory optimization stored tx.vin parts in the memory which enabled to skip roundtrips with permutations and hash_vini. Optimizations was removed so the protocol flow is unified among inputs, independent of the tx specs

- many_inputs: optimization stored spending keys for UTXO in memory, now it is offloaded in the encrypted form.
  • Loading branch information
ph4r05 committed Sep 17, 2018
1 parent ea69c7a commit 00dd8f6
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 108 deletions.
122 changes: 26 additions & 96 deletions src/apps/monero/protocol/tsx_sign_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,24 +164,6 @@ def check_change(self, outputs):

return True

def in_memory(self):
"""
Returns true if the input transaction can be processed whole in-memory
"""
return False and self.input_count <= 1

def many_inputs(self):
"""
Returns true if number of inputs > 10 (secret spending key offloaded)
"""
return self.input_count >= 10

def many_outputs(self):
"""
Returns true if number of outputs > 10 (increases number of roundtrips of the protocol)
"""
return self.output_count >= 10

def num_inputs(self):
return self.input_count

Expand Down Expand Up @@ -367,7 +349,7 @@ async def init_transaction(self, tsx_data):
self.fee = tsx_data.fee
self.account_idx = tsx_data.account
self.multi_sig = tsx_data.is_multisig
self.state.inp_cnt(self.in_memory())
self.state.inp_cnt()
self.check_change(tsx_data.outputs)
self.exp_tx_prefix_hash = common.defval_empty(tsx_data.exp_tx_prefix_hash, None)

Expand Down Expand Up @@ -437,9 +419,9 @@ async def init_transaction(self, tsx_data):

rsig_data = MoneroTransactionRsigData(offload_type=self.rsig_offload)
return MoneroTransactionInitAck(
in_memory=self.in_memory(),
many_inputs=self.many_inputs(),
many_outputs=self.many_outputs(),
in_memory=False,
many_inputs=True,
many_outputs=True,
hmacs=hmacs,
rsig_data=rsig_data,
)
Expand Down Expand Up @@ -578,9 +560,6 @@ async def set_input(self, src_entr):
vini_bin = misc.dump_msg(vini, preallocate=64, prefix=b"\x02")
self._mem_trace(2, True)

if self.in_memory():
self.tx.vin.append(vini)

# HMAC(T_in,i || vin_i)
hmac_vini = await self.gen_hmac_vini(src_entr, vini_bin, self.inp_idx)
self._mem_trace(3, True)
Expand All @@ -596,23 +575,16 @@ async def set_input(self, src_entr):
pseudo_out = crypto.encodepoint(pseudo_out)

# In full version the alpha is encrypted and passed back for storage
if self.in_memory():
self.input_alphas.append(alpha)
self.input_pseudo_outs.append(pseudo_out)
else:
pseudo_out_hmac = crypto.compute_hmac(
self.hmac_key_txin_comm(self.inp_idx), pseudo_out
)
alpha_enc = chacha_poly.encrypt_pack(
self.enc_key_txin_alpha(self.inp_idx), crypto.encodeint(alpha)
)

if self.many_inputs():
spend_enc = chacha_poly.encrypt_pack(
self.enc_key_spend(self.inp_idx), crypto.encodeint(xi)
pseudo_out_hmac = crypto.compute_hmac(
self.hmac_key_txin_comm(self.inp_idx), pseudo_out
)
else:
self.input_secrets.append(xi)
alpha_enc = chacha_poly.encrypt_pack(
self.enc_key_txin_alpha(self.inp_idx), crypto.encodeint(alpha)
)

spend_enc = chacha_poly.encrypt_pack(
self.enc_key_spend(self.inp_idx), crypto.encodeint(xi)
)

# All inputs done?
if self.inp_idx + 1 == self.num_inputs():
Expand All @@ -637,9 +609,6 @@ def tsx_inputs_done(self):
if self.inp_idx + 1 != self.num_inputs():
raise ValueError("Input count mismatch")

if self.in_memory():
return self.tsx_inputs_done_inm()

def tsx_inputs_done_inm(self):
"""
In-memory post processing - tx.vin[i] sorting by key image.
Expand All @@ -660,8 +629,6 @@ async def tsx_inputs_permutation(self, permutation):

await self.iface.transaction_step(self.STEP_PERM)

if self.in_memory():
return
self._tsx_inputs_permutation(permutation)
return MoneroTransactionInputsPermutationAck()

Expand All @@ -671,37 +638,8 @@ def _tsx_inputs_permutation(self, permutation):
"""
self.state.input_permutation()
self.source_permutation = permutation

def swapper(x, y):
if not self.many_inputs():
self.input_secrets[x], self.input_secrets[y] = (
self.input_secrets[y],
self.input_secrets[x],
)
if self.in_memory() and self.use_simple_rct:
self.input_alphas[x], self.input_alphas[y] = (
self.input_alphas[y],
self.input_alphas[x],
)
self.input_pseudo_outs[x], self.input_pseudo_outs[y] = (
self.input_pseudo_outs[y],
self.input_pseudo_outs[x],
)
if self.in_memory():
self.tx.vin[x], self.tx.vin[y] = self.tx.vin[y], self.tx.vin[x]

common.apply_permutation(self.source_permutation, swapper)
self.inp_idx = -1

# Incremental hashing
if self.in_memory():
for idx in range(self.num_inputs()):
vini_bin = misc.dump_msg(
self.tx.vin[idx], preallocate=65, prefix=b"\x02"
)
self.hash_vini_pseudo_out(vini_bin, idx)
self._mem_trace("i: %s" % idx if __debug__ else None, True)

async def input_vini(self, src_entr, vini_bin, hmac, pseudo_out, pseudo_out_hmac):
"""
Set tx.vin[i] for incremental tx prefix hash computation.
Expand All @@ -716,8 +654,6 @@ async def input_vini(self, src_entr, vini_bin, hmac, pseudo_out, pseudo_out_hmac
self.STEP_VINI, self.inp_idx + 1, self.num_inputs()
)

if self.in_memory():
return
if self.inp_idx >= self.num_inputs():
raise ValueError("Too many inputs")

Expand Down Expand Up @@ -746,15 +682,12 @@ def hash_vini_pseudo_out(
if not self.use_simple_rct or self.use_bulletproof:
return

if not self.in_memory():
idx = self.source_permutation[inp_idx]
pseudo_out_hmac_comp = crypto.compute_hmac(
self.hmac_key_txin_comm(idx), pseudo_out
)
if not common.ct_equal(pseudo_out_hmac, pseudo_out_hmac_comp):
raise ValueError("HMAC invalid for pseudo outs")
else:
pseudo_out = self.input_pseudo_outs[inp_idx]
idx = self.source_permutation[inp_idx]
pseudo_out_hmac_comp = crypto.compute_hmac(
self.hmac_key_txin_comm(idx), pseudo_out
)
if not common.ct_equal(pseudo_out_hmac, pseudo_out_hmac_comp):
raise ValueError("HMAC invalid for pseudo outs")

self.full_message_hasher.set_pseudo_out(pseudo_out)

Expand Down Expand Up @@ -1322,9 +1255,9 @@ async def sign_input(
self.inp_idx += 1
if self.inp_idx >= self.num_inputs():
raise ValueError("Invalid ins")
if self.use_simple_rct and (not self.in_memory() and alpha_enc is None):
if self.use_simple_rct and alpha_enc is None:
raise ValueError("Inconsistent1")
if self.use_simple_rct and (not self.in_memory() and pseudo_out is None):
if self.use_simple_rct and pseudo_out is None:
raise ValueError("Inconsistent2")
if self.inp_idx >= 1 and not self.use_simple_rct:
raise ValueError("Inconsistent3")
Expand All @@ -1339,7 +1272,7 @@ async def sign_input(
gc.collect()
self._mem_trace(1)

if self.use_simple_rct and not self.in_memory():
if self.use_simple_rct:
pseudo_out_hmac_comp = crypto.compute_hmac(
self.hmac_key_txin_comm(inv_idx), pseudo_out
)
Expand Down Expand Up @@ -1367,14 +1300,11 @@ async def sign_input(
pseudo_out_c = None

# Spending secret
if self.many_inputs():
from apps.monero.xmr.enc import chacha_poly
from apps.monero.xmr.enc import chacha_poly

input_secret = crypto.decodeint(
chacha_poly.decrypt_pack(self.enc_key_spend(inv_idx), bytes(spend_enc))
)
else:
input_secret = self.input_secrets[self.inp_idx]
input_secret = crypto.decodeint(
chacha_poly.decrypt_pack(self.enc_key_spend(inv_idx), bytes(spend_enc))
)

gc.collect()
self._mem_trace(3)
Expand Down
14 changes: 2 additions & 12 deletions src/apps/monero/protocol/tsx_sign_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,16 @@ class TState:

def __init__(self):
self.s = self.START
self.in_mem = False

def state_save(self):
return self.s, self.in_mem

def state_load(self, x):
self.s, self.in_mem = x

def init_tsx(self):
if self.s != self.START:
raise ValueError("Illegal state")
self.s = self.INIT

def inp_cnt(self, in_mem):
def inp_cnt(self):
if self.s != self.INIT:
raise ValueError("Illegal state")
self.s = self.INP_CNT
self.in_mem = in_mem

def input(self):
if self.s != self.INP_CNT and self.s != self.INPUT:
Expand All @@ -68,9 +60,7 @@ def is_input_vins(self):
return self.s == self.INPUT_VINS

def input_all_done(self):
if (not self.in_mem and self.s != self.INPUT_VINS) or (
self.in_mem and self.s != self.INPUT_PERM
):
if self.s != self.INPUT_VINS:
raise ValueError("Illegal state")
self.s = self.INPUT_ALL_DONE

Expand Down

0 comments on commit 00dd8f6

Please sign in to comment.