Skip to content

Commit

Permalink
xmr: aggregated bulletproofs + rsig offloading
Browse files Browse the repository at this point in the history
xmr: change idx fix
xmr: iface refactoring, integrated address (+5 squashed commits)
xmr: layout pagination refactoring
xmr: addr - integrated address
pb: sync
vendor: trezor-common version bump
xmr: style fixes
xmr: handle sweep tsx correctly

- handle dummy change address correctly
xmr: integrated address generation
build: fix after trezor-crypto version bump
xmr: new protocol dispatch handlers
xmr: slip0010
[43cf4c3c] xmr: comment fix
xmr: extmod pointer aritm fix
xmr: _into api unified, result is the first parameter
xmr: bp cleanup
xmr: scalar nullity test fix
xmr: msg registration improved

- lite protocol optional
- diag protocol optional
xmr: unused imports (+33 squashed commits)
[b4d045ae] xmr: bp - noqa flake8 false positive
[2c79d4be] xmr: isort
[8b9d2835] xmr: code cleanup
[eb7496e9] xmr: iface - shorter timeouts for faster tests
[59520b63] xmr: ringct comment
[6b16088e] xmr: signer - comment fixes
[a08958e2] xmr: simple and bulletproof condition fix
[4e0289a9] vendor: trezor-common version bump
[de472e5a] xmr: black
[234d2249] xmr: lightening, fixes, KeccakXmrArchive

- builder keys
- unload mods before memory intensive operation
[abdec665] xmr: sign_tx logging
[989d8687] xmr: serialize lightening
[7d61f056] xmr: tsx sign refactoring, lightening

- wake_up state restore
- minimize import weight
[3a0daa8b] xmr: serialize thinning
[65ad1d2e] xmr: serialize thinning
[501221d5] xmr: bp - thinning
[3d980377] xmr: bp - generalization with proof_v8
[10d11d60] xmr: extended rsig - offloading protocol
[a8f5caa2] xmr: crypto - rsig params fix
[f5e130b8] xmr: crypto - inv8
[dbc3f9d8] xmr: rsig pb sync
[5748a13e] xmr: bp - data for bp4 fix (+18 squashed commits)

Squashed commits:
[5bcd54e3] xmr: bp - black
[e93e97dd] xmr: bp refactoring, large memory optimizations

- memoryview in __getitem__ requires new memory allocation so the refactored version uses to(), read() methods that can operate directly on buffers without need to create memory views.
[c30745a] xmr: bp - black
[f5c4069] xmr: bp - tests extended
[8dae75d] xmr: bp - get_exponent optim
[3e59ff8] xmr: bp - precomputations for 4 statements
[d1d2e29] xmr: bp - gc.collect
[1bb6b5b] xmr: bp - optimizations, streamlining
[2a2b0cb] xmr: bp - verification in log(MN) memory for 1 proof

- not allocating MN vectors
- sequential multiexec added for memory efficient verification
- bulletproofs: maintain -z4, -z5, and -y0 to avoid subtractions [8276d25]
- bulletproofs: merge multiexps as per sarang's new python code [acd64d2b]
[75aa7de] xmr: bp - memory optimization
[a10d05a] xmr: bp - deterministic mask generation init
[5060d6a] xmr: bp optimizations
[dd69eb1] xmr: bp - black
[19f0f64] xmr: bp - optimizations, power key vector
[2ba63f8] xmr: bp - minor cleanup, optimizations, scalarmultH
[31c9ca2] xmr: bp - mem clean
[3fc2c79] xmr: bp - memory save
[5b16c9c] bp: black
[f1040c97] xmr: crypto - memory leak fix
[ff863510] xmr: iface - flake
[6ebf69c2] xmr: lite - flake8, black
[eee55d62] xmr: bp - memory diag
[2767009b] xmr: bulletproofs upgrade, mainnet version, cleaning
[be6ebbd5] xmr: lite protocol
[d603e96d] xmr: pb sync
[5da15da9] vendor: trezor-common fix
[0373b97e] xmr: iface - output confirmation split, subaddr fix
[2cf32176] xmr: monero - subaddress fixed for index (0, 0)
[3bb8f08b] xmr: enc.aescbc added - for lite protocol (+1 squashed commit)
Squashed commits:
[011dbaab] TMP: trezor-common on master, crypto on ph4

- trezor-crypto on ph4r04 fork as it has all required stuff
- Lite protocol not merged in master, thus does not work in the PR
  • Loading branch information
ph4r05 committed Sep 14, 2018
1 parent 795b34e commit cf62047
Show file tree
Hide file tree
Showing 42 changed files with 3,211 additions and 1,417 deletions.
1 change: 0 additions & 1 deletion SConscript.firmware
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ SOURCE_MOD += [
'vendor/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c',
'vendor/trezor-crypto/ed25519-donna/ed25519-keccak.c',
'vendor/trezor-crypto/ed25519-donna/ed25519-sha3.c',
'vendor/trezor-crypto/ed25519-donna/ge25519.c',
'vendor/trezor-crypto/ed25519-donna/modm-donna-32bit.c',
'vendor/trezor-crypto/monero/base58.c',
'vendor/trezor-crypto/monero/serialize.c',
Expand Down
1 change: 0 additions & 1 deletion SConscript.unix
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ SOURCE_MOD += [
'vendor/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c',
'vendor/trezor-crypto/ed25519-donna/ed25519-keccak.c',
'vendor/trezor-crypto/ed25519-donna/ed25519-sha3.c',
'vendor/trezor-crypto/ed25519-donna/ge25519.c',
'vendor/trezor-crypto/ed25519-donna/modm-donna-32bit.c',
'vendor/trezor-crypto/monero/base58.c',
'vendor/trezor-crypto/monero/serialize.c',
Expand Down
77 changes: 41 additions & 36 deletions embed/extmod/modtrezorcrypto/modtrezorcrypto-monero.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,26 +124,26 @@ STATIC mp_obj_t mp_obj_from_ge25519(const ge25519 * in){
return MP_OBJ_FROM_PTR(o);
}

STATIC void mp_unpack_ge25519(ge25519 * r, const mp_obj_t arg){
STATIC void mp_unpack_ge25519(ge25519 * r, const mp_obj_t arg, mp_int_t offset){
mp_buffer_info_t buff;
mp_get_buffer_raise(arg, &buff, MP_BUFFER_READ);
if (buff.len != 32) {
if (buff.len < 32 + offset) {
mp_raise_ValueError("Invalid length of the EC point");
}

const int res = ge25519_unpack_vartime(r, buff.buf);
const int res = ge25519_unpack_vartime(r, ((uint8_t*)buff.buf) + offset);
if (res != 1){
mp_raise_ValueError("Point decoding error");
}
}

STATIC void mp_unpack_scalar(bignum256modm r, const mp_obj_t arg){
STATIC void mp_unpack_scalar(bignum256modm r, const mp_obj_t arg, mp_int_t offset){
mp_buffer_info_t buff;
mp_get_buffer_raise(arg, &buff, MP_BUFFER_READ);
if (buff.len < 32 || buff.len > 64) {
if (buff.len < 32 + offset) {
mp_raise_ValueError("Invalid length of secret key");
}
expand256_modm(r, buff.buf, buff.len);
expand256_modm(r, ((uint8_t*)buff.buf) + offset, 32);
}

#define MP_OBJ_IS_GE25519(o) MP_OBJ_IS_TYPE((o), &mod_trezorcrypto_monero_ge25519_type)
Expand Down Expand Up @@ -184,7 +184,7 @@ STATIC mp_obj_t mod_trezorcrypto_monero_ge25519_make_new(const mp_obj_type_t *ty
} else if (n_args == 1 && MP_OBJ_IS_GE25519(args[0])) {
ge25519_copy(&o->p, &MP_OBJ_C_GE25519(args[0]));
} else if (n_args == 1 && MP_OBJ_IS_STR_OR_BYTES(args[0])) {
mp_unpack_ge25519(&o->p, args[0]);
mp_unpack_ge25519(&o->p, args[0], 0);
} else {
mp_raise_ValueError("Invalid ge25519 constructor");
}
Expand All @@ -209,7 +209,7 @@ STATIC mp_obj_t mod_trezorcrypto_monero_bignum256modm_make_new(const mp_obj_type
} else if (n_args == 1 && MP_OBJ_IS_SCALAR(args[0])) {
copy256_modm(o->p, MP_OBJ_C_SCALAR(args[0]));
} else if (n_args == 1 && MP_OBJ_IS_STR_OR_BYTES(args[0])) {
mp_unpack_scalar(o->p, args[0]);
mp_unpack_scalar(o->p, args[0], 0);
} else if (n_args == 1 && mp_obj_is_integer(args[0])) {
uint64_t v = mp_obj_get_uint64(args[0]);
set256_modm(o->p, v);
Expand Down Expand Up @@ -266,7 +266,7 @@ STATIC mp_obj_t mod_trezorcrypto_monero_init256_modm(size_t n_args, const mp_obj
} else if (n_args > 0 && MP_OBJ_IS_SCALAR(args[1+off])) {
copy256_modm(MP_OBJ_SCALAR(res), MP_OBJ_C_SCALAR(args[1+off]));
} else if (n_args > 0 && MP_OBJ_IS_STR_OR_BYTES(args[1+off])) {
mp_unpack_scalar(MP_OBJ_SCALAR(res), args[1+off]);
mp_unpack_scalar(MP_OBJ_SCALAR(res), args[1+off], 0);
} else if (n_args > 0 && mp_obj_is_integer(args[1+off])) {
uint64_t v = mp_obj_get_uint64(args[1+off]);
set256_modm(MP_OBJ_SCALAR(res), v);
Expand Down Expand Up @@ -412,45 +412,48 @@ STATIC mp_obj_t mod_trezorcrypto_monero_pack256_modm(const mp_obj_t arg){
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_monero_pack256_modm_obj, mod_trezorcrypto_monero_pack256_modm);

//void contract256_modm_r
STATIC mp_obj_t mod_trezorcrypto_monero_pack256_modm_into(const mp_obj_t arg, const mp_obj_t buf){
assert_scalar(arg);
STATIC mp_obj_t mod_trezorcrypto_monero_pack256_modm_into(size_t n_args, const mp_obj_t *args){
assert_scalar(args[1]);
const mp_int_t offset = n_args >= 3 ? mp_obj_get_int(args[2]) : 0;
mp_buffer_info_t bufm;
mp_get_buffer_raise(buf, &bufm, MP_BUFFER_WRITE);
if (bufm.len < 32) {
mp_get_buffer_raise(args[0], &bufm, MP_BUFFER_WRITE);
if (bufm.len < 32 + offset) {
mp_raise_ValueError("Buffer too small");
}

contract256_modm(bufm.buf, MP_OBJ_C_SCALAR(arg));
return buf;
contract256_modm(((uint8_t*)bufm.buf) + offset, MP_OBJ_C_SCALAR(args[1]));
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_monero_pack256_modm_into_obj, mod_trezorcrypto_monero_pack256_modm_into);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_monero_pack256_modm_into_obj, 2, 3, mod_trezorcrypto_monero_pack256_modm_into);

//expand256_modm_r
STATIC mp_obj_t mod_trezorcrypto_monero_unpack256_modm(size_t n_args, const mp_obj_t *args){
mp_obj_t res = n_args == 2 ? args[0] : mp_obj_new_scalar();
const int off = n_args == 2 ? 0 : -1;
mp_obj_t res = n_args >= 2 ? args[0] : mp_obj_new_scalar();
const int off = n_args >= 2 ? 0 : -1;
const mp_int_t offset = n_args >= 3 ? mp_obj_get_int(args[2]) : 0;
assert_scalar(res);
mp_unpack_scalar(MP_OBJ_SCALAR(res), args[1+off]);
mp_unpack_scalar(MP_OBJ_SCALAR(res), args[1+off], offset);
return res;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_monero_unpack256_modm_obj, 1, 2, mod_trezorcrypto_monero_unpack256_modm);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_monero_unpack256_modm_obj, 1, 3, mod_trezorcrypto_monero_unpack256_modm);

//expand256_modm_r
STATIC mp_obj_t mod_trezorcrypto_monero_unpack256_modm_noreduce(size_t n_args, const mp_obj_t *args){
mp_obj_t res = n_args == 2 ? args[0] : mp_obj_new_scalar();
const int off = n_args == 2 ? 0 : -1;
mp_obj_t res = n_args >= 2 ? args[0] : mp_obj_new_scalar();
const int off = n_args >= 2 ? 0 : -1;
const mp_int_t offset = n_args >= 3 ? mp_obj_get_int(args[2]) : 0;
assert_scalar(res);

mp_buffer_info_t buff;
mp_get_buffer_raise(args[1+off], &buff, MP_BUFFER_READ);
if (buff.len != 32) {
if (buff.len != 32 + offset) {
mp_raise_ValueError("Invalid length of secret key");
}

expand_raw256_modm(MP_OBJ_SCALAR(res), buff.buf);
expand_raw256_modm(MP_OBJ_SCALAR(res), ((uint8_t*)buff.buf) + offset);
return res;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_monero_unpack256_modm_noreduce_obj, 1, 2, mod_trezorcrypto_monero_unpack256_modm_noreduce);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_monero_unpack256_modm_noreduce_obj, 1, 3, mod_trezorcrypto_monero_unpack256_modm_noreduce);

//
// GE25519 Defs
Expand Down Expand Up @@ -633,28 +636,30 @@ STATIC mp_obj_t mod_trezorcrypto_monero_ge25519_pack(const mp_obj_t arg){
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_monero_ge25519_pack_obj, mod_trezorcrypto_monero_ge25519_pack);

//void ge25519_pack(unsigned char r[32], const ge25519 *p)
STATIC mp_obj_t mod_trezorcrypto_monero_ge25519_pack_into(const mp_obj_t arg, const mp_obj_t buf){
assert_ge25519(arg);
STATIC mp_obj_t mod_trezorcrypto_monero_ge25519_pack_into(size_t n_args, const mp_obj_t *args){
assert_ge25519(args[1]);
const mp_int_t offset = n_args >= 3 ? mp_obj_get_int(args[2]) : 0;
mp_buffer_info_t bufm;
mp_get_buffer_raise(buf, &bufm, MP_BUFFER_WRITE);
if (bufm.len < 32) {
mp_get_buffer_raise(args[0], &bufm, MP_BUFFER_WRITE);
if (bufm.len < 32 + offset) {
mp_raise_ValueError("Buffer too small");
}

ge25519_pack(bufm.buf, &MP_OBJ_C_GE25519(arg));
return buf;
ge25519_pack(((uint8_t*)bufm.buf) + offset, &MP_OBJ_C_GE25519(args[1]));
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_monero_ge25519_pack_into_obj, mod_trezorcrypto_monero_ge25519_pack_into);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_monero_ge25519_pack_into_obj, 2, 3, mod_trezorcrypto_monero_ge25519_pack_into);

//int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s)
STATIC mp_obj_t mod_trezorcrypto_monero_ge25519_unpack_vartime(size_t n_args, const mp_obj_t *args){
mp_obj_t res = n_args == 2 ? args[0] : mp_obj_new_ge25519();
const int off = n_args == 2 ? 0 : -1;
mp_obj_t res = n_args >= 2 ? args[0] : mp_obj_new_ge25519();
const int off = n_args >= 2 ? 0 : -1;
const mp_int_t offset = n_args >= 3 ? mp_obj_get_int(args[2]) : 0;
assert_ge25519(res);
mp_unpack_ge25519(&MP_OBJ_GE25519(res), args[1+off]);
mp_unpack_ge25519(&MP_OBJ_GE25519(res), args[1+off], offset);
return res;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_monero_ge25519_unpack_vartime_obj, 1, 2, mod_trezorcrypto_monero_ge25519_unpack_vartime);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_monero_ge25519_unpack_vartime_obj, 1, 3, mod_trezorcrypto_monero_ge25519_unpack_vartime);

//
// XMR defs
Expand Down
60 changes: 13 additions & 47 deletions src/apps/monero/__init__.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,27 @@
import gc

from trezor import log
from trezor.messages.MessageType import (
DebugMoneroDiagRequest,
MoneroGetAddress,
MoneroGetWatchKey,
MoneroKeyImageSyncRequest,
MoneroTransactionSignRequest,
)
from trezor.wire import protobuf_workflow, register
from trezor import wire
from trezor.messages import MessageType


# persistent state objects
class Holder(object):
def __init__(self):
self.ctx_sign = None
self.ctx_ki = None
self.ctx_lite = None


STATE = Holder()


def dispatch_MoneroGetAddress(*args, **kwargs):
from apps.monero.get_address import layout_monero_get_address

return layout_monero_get_address(*args, **kwargs)


def dispatch_MoneroGetWatchKey(*args, **kwargs):
from apps.monero.get_watch_only import layout_monero_get_watch_only

return layout_monero_get_watch_only(*args, **kwargs)


def dispatch_MoneroTsxSign(*args, **kwargs):
from apps.monero.sign_tx import layout_sign_tx

return layout_sign_tx(STATE, *args, **kwargs)


def dispatch_MoneroKeyImageSync(*args, **kwargs):
from apps.monero.key_image_sync import layout_key_image_sync

return layout_key_image_sync(STATE, *args, **kwargs)


def dispatch_MoneroDiag(*args, **kwargs):
log.debug(__name__, "----diagnostics")
gc.collect()
from apps.monero.diag import dispatch_diag

return dispatch_diag(*args, **kwargs)
def boot():
wire.add(MessageType.MoneroGetAddress, __name__, "get_address")
wire.add(MessageType.MoneroGetWatchKey, __name__, "get_watch_only")
wire.add(MessageType.MoneroTransactionSignRequest, __name__, "sign_tx", STATE)
wire.add(MessageType.MoneroKeyImageSyncRequest, __name__, "key_image_sync", STATE)

if hasattr(MessageType, "MoneroLiteInitRequest"):
wire.add(MessageType.MoneroLiteInitRequest, "lite_protocol", STATE, 1)
wire.add(MessageType.MoneroLiteRequest, "lite_protocol", STATE, 0)

def boot():
register(MoneroGetAddress, protobuf_workflow, dispatch_MoneroGetAddress)
register(MoneroGetWatchKey, protobuf_workflow, dispatch_MoneroGetWatchKey)
register(MoneroTransactionSignRequest, protobuf_workflow, dispatch_MoneroTsxSign)
register(MoneroKeyImageSyncRequest, protobuf_workflow, dispatch_MoneroKeyImageSync)
register(DebugMoneroDiagRequest, protobuf_workflow, dispatch_MoneroDiag)
if hasattr(MessageType, "DebugMoneroDiagRequest"):
wire.add(MessageType.DebugMoneroDiagRequest, __name__, "diag")
76 changes: 56 additions & 20 deletions src/apps/monero/controller/iface.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,41 @@ async def restore_default(self):

workflow.restartdefault()

async def confirm_out(
self, dst, is_change=False, creds=None, int_payment=None, ctx=None
):
"""
Single transaction destination confirmation
"""
from apps.monero.xmr.sub.addr import encode_addr
from apps.monero.xmr.sub.xmr_net import net_version
from apps.monero import layout

ver = net_version(
creds.network_type, dst.is_subaddress, int_payment is not None
)
addr = encode_addr(
ver, dst.addr.spend_public_key, dst.addr.view_public_key, int_payment
)

await layout.require_confirm_tx(
self.gctx(ctx), addr.decode("ascii"), dst.amount, is_change
)

async def confirm_payment_id(self, payment_id, ctx=None):
"""
Confirm payment ID
:param payment_id:
:param ctx:
:return:
"""
if payment_id is None:
return

from apps.monero import layout

await layout.require_confirm_payment_id(self.gctx(ctx), payment_id)

async def confirm_transaction(self, tsx_data, creds=None, ctx=None):
"""
Ask for confirmation from user
Expand All @@ -23,34 +58,35 @@ async def confirm_transaction(self, tsx_data, creds=None, ctx=None):
:param ctx:
:return:
"""
from apps.monero.xmr.sub.addr import encode_addr, get_change_addr_idx
from apps.monero.xmr.sub.xmr_net import net_version
from apps.monero.xmr.sub.addr import get_change_addr_idx

outs = tsx_data.outputs
change_idx = get_change_addr_idx(outs, tsx_data.change_dts)

if change_idx is not None:
outs = [x for i, x in enumerate(outs) if i != change_idx] + [
outs[change_idx]
]
change_idx = len(outs) - 1

from apps.monero import layout

has_integrated = (
tsx_data.integrated_indices is not None
and len(tsx_data.integrated_indices) > 0
)
has_payment = tsx_data.payment_id is not None and len(tsx_data.payment_id) > 0

for idx, dst in enumerate(outs):
is_change = change_idx and idx == change_idx
is_change = change_idx is not None and idx == change_idx
if is_change:
continue
if change_idx is None and dst.amount == 0 and len(outs) == 2:
continue # sweep, dummy tsx

addr = encode_addr(
net_version(creds.network_type),
dst.addr.spend_public_key,
dst.addr.view_public_key,
cur_payment = (
tsx_data.payment_id
if has_integrated and idx in tsx_data.integrated_indices
else None
)
await self.confirm_out(dst, is_change, creds, cur_payment, ctx)

await layout.require_confirm_tx(
self.gctx(ctx), addr.decode("ascii"), dst.amount, is_change
)
if has_payment and not has_integrated:
await self.confirm_payment_id(tsx_data.payment_id, ctx)

await layout.require_confirm_fee(self.gctx(ctx), tsx_data.fee)

Expand All @@ -69,7 +105,7 @@ async def confirm_transaction(self, tsx_data, creds=None, ctx=None):
text.normal("Signing...")

try:
layout = await layout.simple_text(text, tm=1000)
layout = await layout.simple_text(text, tm=500)
log.debug(__name__, "layout: %s", layout)
workflow.closedefault()
workflow.onlayoutstart(layout)
Expand All @@ -81,7 +117,7 @@ async def confirm_transaction(self, tsx_data, creds=None, ctx=None):
# loop.close(slide)
# workflow.onlayoutclose(layout)

await loop.sleep(500 * 1000)
await loop.sleep(200 * 1000)
return True

async def transaction_error(self, *args, **kwargs):
Expand All @@ -96,7 +132,7 @@ async def transaction_error(self, *args, **kwargs):
text = Text("Error", ui.ICON_SEND, icon_color=ui.RED)
text.normal("Transaction failed")

await layout.ui_text(text, tm=3 * 1000 * 1000)
await layout.ui_text(text, tm=500 * 1000)
await self.restore_default()

async def transaction_signed(self, ctx=None):
Expand All @@ -117,7 +153,7 @@ async def transaction_finished(self, ctx=None):
text = Text("Success", ui.ICON_SEND, icon_color=ui.GREEN)
text.normal("Transaction signed")

await layout.ui_text(text, tm=3 * 1000 * 1000)
await layout.ui_text(text, tm=500 * 1000)
await self.restore_default()

async def transaction_step(self, step, sub_step=None, sub_step_total=None):
Expand Down
Loading

0 comments on commit cf62047

Please sign in to comment.