diff --git a/src/apps/monero/protocol/tsx_sign_builder.py b/src/apps/monero/protocol/tsx_sign_builder.py index c592ee683..bdff6a7a5 100644 --- a/src/apps/monero/protocol/tsx_sign_builder.py +++ b/src/apps/monero/protocol/tsx_sign_builder.py @@ -867,7 +867,10 @@ def _return_rsig_data(self, rsig): return None from trezor.messages.MoneroTransactionRsigData import MoneroTransactionRsigData - return MoneroTransactionRsigData(rsig=rsig) + if isinstance(rsig, list): + return MoneroTransactionRsigData(rsig_parts=rsig) + else: + return MoneroTransactionRsigData(rsig=rsig) def _range_proof(self, idx, amount, rsig_data=None): """ @@ -929,14 +932,8 @@ def _range_proof(self, idx, amount, rsig_data=None): ) elif not self.rsig_offload and not self.use_bulletproof: - rsig_buff = bytearray(32 * (64 + 64 + 64 + 1)) - rsig_mv = memoryview(rsig_buff) - - C, mask, rsig = ring_ct.prove_range( - amount, mask, backend_impl=True, byte_enc=True, rsig=rsig_mv - ) - rsig = memoryview(rsig) - del (rsig_buff, rsig_mv, ring_ct) + C, mask, rsig = ring_ct.prove_range_chunked(amount, mask) + del (ring_ct) # Incremental hashing self.full_message_hasher.rsig_val(rsig, False, raw=True) diff --git a/src/apps/monero/xmr/crypto.py b/src/apps/monero/xmr/crypto.py index 9b58a8f54..d9802ffbb 100644 --- a/src/apps/monero/xmr/crypto.py +++ b/src/apps/monero/xmr/crypto.py @@ -153,6 +153,10 @@ def point_double(P): return tcry.ge25519_double(P) +def point_double_into(r, P): + return tcry.ge25519_double(r, P) + + def point_mul8(P): return tcry.ge25519_mul8(P) diff --git a/src/apps/monero/xmr/ring_ct.py b/src/apps/monero/xmr/ring_ct.py index 32c9df3c7..f77c3a58b 100644 --- a/src/apps/monero/xmr/ring_ct.py +++ b/src/apps/monero/xmr/ring_ct.py @@ -61,36 +61,102 @@ def verify_bp(bp_proof, amounts=None, masks=None): return res -def prove_range( - amount, last_mask=None, decode=False, backend_impl=True, byte_enc=True, rsig=None -): - """ - Range proof generator. - In order to minimize the memory consumption and CPU usage during transaction generation the returned values - are returned encoded. - """ - if not backend_impl or not byte_enc or decode: - raise ValueError("Unsupported params") +def prove_range_chunked(amount, last_mask=None): + a = crypto.sc_init(0) + si = crypto.sc_init(0) + c = crypto.sc_init(0) + ee = crypto.sc_init(0) + tmp_ai = crypto.sc_init(0) + tmp_alpha = crypto.sc_init(0) + + C_acc = crypto.identity() + C_h = crypto.gen_H() + C_tmp = crypto.identity() + L = crypto.identity() + Zero = crypto.identity() + kck = crypto.get_keccak() + + ai = bytearray(32 * 64) + alphai = bytearray(32 * 64) + buff = bytearray(32) + + Cis = bytearray(32 * 64) + s0s = bytearray(32 * 64) + s1s = bytearray(32 * 64) + ee_bin = bytearray(32) + + for ii in range(64): + crypto.random_scalar_into(tmp_ai) + if last_mask is not None and ii == 63: + crypto.sc_sub_into(tmp_ai, last_mask, a) + + crypto.sc_add_into(a, a, tmp_ai) + crypto.random_scalar_into(tmp_alpha) + + crypto.scalarmult_base_into(L, tmp_alpha) + crypto.scalarmult_base_into(C_tmp, tmp_ai) + + # C_tmp += &Zero if BB(ii) == 0 else &C_h + crypto.point_add_into(C_tmp, C_tmp, Zero if ((amount >> ii) & 1) == 0 else C_h) + crypto.point_add_into(C_acc, C_acc, C_tmp) + + # Set Ci[ii] to sigs + crypto.encodepoint_into(Cis, C_tmp, ii << 5) + crypto.encodeint_into(ai, tmp_ai, ii << 5) + crypto.encodeint_into(alphai, tmp_alpha, ii << 5) + + if ((amount >> ii) & 1) == 0: + crypto.random_scalar_into(si) + crypto.encodepoint_into(buff, L) + crypto.hash_to_scalar_into(c, buff) + + crypto.point_sub_into(C_tmp, C_tmp, C_h) + crypto.add_keys2_into(L, si, c, C_tmp) + + crypto.encodeint_into(s1s, si, ii << 5) + + crypto.encodepoint_into(buff, L) + kck.update(buff) + + crypto.point_double_into(C_h, C_h) + + # Compute ee + tmp_ee = kck.digest() + crypto.decodeint_into(ee, tmp_ee) + del (tmp_ee, kck) + + C_h = crypto.gen_H() + gc.collect() + + # Second pass, s0, s1 + for ii in range(64): + crypto.decodeint_into(tmp_alpha, alphai, ii << 5) + crypto.decodeint_into(tmp_ai, ai, ii << 5) - C, a, R = None, None, None - try: - if rsig is None: - rsig = bytearray(32 * (64 + 64 + 64 + 1)) + if ((amount >> ii) & 1) == 0: + crypto.sc_mulsub_into(si, tmp_ai, ee, tmp_alpha) + crypto.encodeint_into(s0s, si, ii << 5) - buf_ai = bytearray(4 * 9 * 64) - buf_alpha = bytearray(4 * 9 * 64) - C, a, R = crypto.prove_range( - rsig, amount, last_mask, buf_ai, buf_alpha - ) # backend returns encoded + else: + crypto.random_scalar_into(si) + crypto.encodeint_into(s0s, si, ii << 5) + + crypto.decodepoint_into(C_tmp, Cis, ii << 5) + crypto.add_keys2_into(L, si, ee, C_tmp) + crypto.encodepoint_into(buff, L) + crypto.hash_to_scalar_into(c, buff) + + crypto.sc_mulsub_into(si, tmp_ai, c, tmp_alpha) + crypto.encodeint_into(s1s, si, ii << 5) - finally: - import gc + crypto.point_double_into(C_h, C_h) - buf_ai = None - buf_alpha = None - gc.collect() + crypto.encodeint_into(ee_bin, ee) + + del (ai, alphai, buff, tmp_ai, tmp_alpha, si, c, ee, C_tmp, C_h, L, Zero) + gc.collect() - return C, a, R + return C_acc, a, [s0s, s1s, ee_bin, Cis] # Ring-ct MG sigs diff --git a/src/apps/monero/xmr/sub/mlsag_hasher.py b/src/apps/monero/xmr/sub/mlsag_hasher.py index 71c145734..25f19430e 100644 --- a/src/apps/monero/xmr/sub/mlsag_hasher.py +++ b/src/apps/monero/xmr/sub/mlsag_hasher.py @@ -92,7 +92,11 @@ def rsig_val(self, p, bulletproof, raw=False): raise ValueError("State error") if raw: - self.rsig_hasher.update(p) + if isinstance(p, list): + for x in p: + self.rsig_hasher.update(x) + else: + self.rsig_hasher.update(p) return if bulletproof: