From 88ef4257cdc5259783cd9a3d1eb32402697e5ff0 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Fri, 9 Mar 2018 11:37:06 +0100 Subject: [PATCH] wallet/nem: init, get_address --- SConscript.firmware | 3 +++ SConscript.unix | 3 +++ .../modtrezorcrypto/modtrezorcrypto-bip32.h | 16 +++++++++++++++ mocks/generated/trezorconfig.py | 6 ++++++ mocks/generated/trezorcrypto.py | 5 +++++ mocks/generated/trezorio.py | 7 +++++-- mocks/generated/trezorui.py | 4 ++-- mocks/generated/trezorutils.py | 18 +++++++++++++++++ src/apps/nem/__init__.py | 13 ++++++++++++ src/apps/nem/get_address.py | 20 +++++++++++++++++++ src/apps/nem/helpers.py | 14 +++++++++++++ src/main.py | 2 ++ 12 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 src/apps/nem/__init__.py create mode 100644 src/apps/nem/get_address.py create mode 100644 src/apps/nem/helpers.py diff --git a/SConscript.firmware b/SConscript.firmware index 805a983783..be4bb8f425 100644 --- a/SConscript.firmware +++ b/SConscript.firmware @@ -27,6 +27,7 @@ CPPDEFINES_MOD += [ 'RAND_PLATFORM_INDEPENDENT', ('USE_KECCAK', '1'), ('USE_ETHEREUM', '1'), + ('USE_NEM', '1'), ] SOURCE_MOD += [ 'embed/extmod/modtrezorcrypto/modtrezorcrypto.c', @@ -38,6 +39,7 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/aes/aes_modes.c', 'vendor/trezor-crypto/aes/aestab.c', 'vendor/trezor-crypto/base58.c', + 'vendor/trezor-crypto/base32.c', 'vendor/trezor-crypto/bignum.c', 'vendor/trezor-crypto/bip32.c', 'vendor/trezor-crypto/bip39.c', @@ -63,6 +65,7 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/hasher.c', 'vendor/trezor-crypto/hmac.c', 'vendor/trezor-crypto/memzero.c', + 'vendor/trezor-crypto/nem.c', 'vendor/trezor-crypto/nist256p1.c', 'vendor/trezor-crypto/pbkdf2.c', 'vendor/trezor-crypto/rand.c', diff --git a/SConscript.unix b/SConscript.unix index 01fdf7d184..818d511aca 100644 --- a/SConscript.unix +++ b/SConscript.unix @@ -25,6 +25,7 @@ CPPDEFINES_MOD += [ 'AES_192', ('USE_KECCAK', '1'), ('USE_ETHEREUM', '1'), + ('USE_NEM', '1'), ] SOURCE_MOD += [ 'embed/extmod/modtrezorcrypto/modtrezorcrypto.c', @@ -35,6 +36,7 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/aes/aes_modes.c', 'vendor/trezor-crypto/aes/aestab.c', 'vendor/trezor-crypto/base58.c', + 'vendor/trezor-crypto/base32.c', 'vendor/trezor-crypto/bignum.c', 'vendor/trezor-crypto/bip32.c', 'vendor/trezor-crypto/bip39.c', @@ -67,6 +69,7 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/secp256k1.c', 'vendor/trezor-crypto/sha2.c', 'vendor/trezor-crypto/sha3.c', + 'vendor/trezor-crypto/nem.c', ] # modtrezorio diff --git a/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h b/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h index 6fc81aa1ca..7dacea55c2 100644 --- a/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h +++ b/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h @@ -39,6 +39,7 @@ STATIC const mp_obj_type_t mod_trezorcrypto_HDNode_type; #define XPUB_MAXLEN 128 #define ADDRESS_MAXLEN 36 +#define NEM_ADDRESS_SIZE 40 /// def __init__(self, /// depth: int, @@ -313,6 +314,20 @@ STATIC mp_obj_t mod_trezorcrypto_HDNode_address(mp_obj_t self, mp_obj_t version) } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_address_obj, mod_trezorcrypto_HDNode_address); +/// def nem_address(self, network: int) -> str: +/// ''' +/// Compute a NEM address string from the HD node. +/// ''' +STATIC mp_obj_t mod_trezorcrypto_HDNode_nem_address(mp_obj_t self, mp_obj_t network) { + mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); + + uint8_t n = mp_obj_get_int_truncated(network); + char address[NEM_ADDRESS_SIZE]; + hdnode_get_nem_address(&o->hdnode, n, address); + return mp_obj_new_str(address, strlen(address), false); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_nem_address_obj, mod_trezorcrypto_HDNode_nem_address); + /// def ethereum_pubkeyhash(self) -> bytes: /// ''' /// Compute an Ethereum pubkeyhash (aka address) from the HD node. @@ -340,6 +355,7 @@ STATIC const mp_rom_map_elem_t mod_trezorcrypto_HDNode_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_private_key), MP_ROM_PTR(&mod_trezorcrypto_HDNode_private_key_obj) }, { MP_ROM_QSTR(MP_QSTR_public_key), MP_ROM_PTR(&mod_trezorcrypto_HDNode_public_key_obj) }, { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&mod_trezorcrypto_HDNode_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_nem_address), MP_ROM_PTR(&mod_trezorcrypto_HDNode_nem_address_obj) }, { MP_ROM_QSTR(MP_QSTR_ethereum_pubkeyhash), MP_ROM_PTR(&mod_trezorcrypto_HDNode_ethereum_pubkeyhash_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_HDNode_locals_dict, mod_trezorcrypto_HDNode_locals_dict_table); diff --git a/mocks/generated/trezorconfig.py b/mocks/generated/trezorconfig.py index ab1462b942..376b5184eb 100644 --- a/mocks/generated/trezorconfig.py +++ b/mocks/generated/trezorconfig.py @@ -7,6 +7,12 @@ def init() -> None: called from this module! ''' +# extmod/modtrezorconfig/modtrezorconfig.c +def check_pin(pin: int, waitcallback: (int, int -> None)) -> bool: + ''' + Check the given PIN. Returns True on success, False on failure. + ''' + # extmod/modtrezorconfig/modtrezorconfig.c def unlock(pin: int, waitcallback: (int, int -> None)) -> bool: ''' diff --git a/mocks/generated/trezorcrypto.py b/mocks/generated/trezorcrypto.py index af87455a75..a110d65afd 100644 --- a/mocks/generated/trezorcrypto.py +++ b/mocks/generated/trezorcrypto.py @@ -93,6 +93,11 @@ class HDNode: Compute a base58-encoded address string from the HD node. ''' + def nem_address(self, network: int) -> str: + ''' + Compute a NEM address string from the HD node. + ''' + def ethereum_pubkeyhash(self) -> bytes: ''' Compute an Ethereum pubkeyhash (aka address) from the HD node. diff --git a/mocks/generated/trezorio.py b/mocks/generated/trezorio.py index 0c79c832c8..e816c89c07 100644 --- a/mocks/generated/trezorio.py +++ b/mocks/generated/trezorio.py @@ -128,14 +128,17 @@ class USB: ''' def __init__(self, + device_class: int=0, + device_subclass: int=0, + device_protocol: int=0, vendor_id: int, product_id: int, release_num: int, manufacturer: str='', product: str='', serial_number: str='', - configuration: str='', - interface: str='') -> None: + interface: str='', + usb21_enabled: bool=True) -> None: ''' ''' diff --git a/mocks/generated/trezorui.py b/mocks/generated/trezorui.py index acec414926..16392fd678 100644 --- a/mocks/generated/trezorui.py +++ b/mocks/generated/trezorui.py @@ -112,7 +112,7 @@ class Display: Call without the xy parameter to just perform the read of the value. ''' - def save(self, filename: str) -> None: + def save(self, prefix: str) -> None: ''' - Saves current display contents to file filename. + Saves current display contents to PNG file with given prefix. ''' diff --git a/mocks/generated/trezorutils.py b/mocks/generated/trezorutils.py index fefe5d3ff0..8c7a3763cd 100644 --- a/mocks/generated/trezorutils.py +++ b/mocks/generated/trezorutils.py @@ -24,3 +24,21 @@ def halt(msg: str = None) -> None: ''' Halts execution. ''' + +# extmod/modtrezorutils/modtrezorutils.c +def set_mode_unprivileged() -> None: + ''' + Set unprivileged mode. + ''' + +# extmod/modtrezorutils/modtrezorutils.c +def symbol(name: str) -> str/int/None: + ''' + Retrieve internal symbol. + ''' + +# extmod/modtrezorutils/modtrezorutils.c +def model() -> str: + ''' + Return which hardware model we are running on. + ''' diff --git a/src/apps/nem/__init__.py b/src/apps/nem/__init__.py new file mode 100644 index 0000000000..02ffd256ca --- /dev/null +++ b/src/apps/nem/__init__.py @@ -0,0 +1,13 @@ +from trezor.wire import register, protobuf_workflow +from trezor.utils import unimport +from trezor.messages.wire_types import NEMGetAddress + + +@unimport +def dispatch_NemGetAddress(*args, **kwargs): + from .get_address import nem_get_address + return nem_get_address(*args, **kwargs) + + +def boot(): + register(NEMGetAddress, protobuf_workflow, dispatch_NemGetAddress) diff --git a/src/apps/nem/get_address.py b/src/apps/nem/get_address.py new file mode 100644 index 0000000000..46bbc25480 --- /dev/null +++ b/src/apps/nem/get_address.py @@ -0,0 +1,20 @@ +from apps.wallet.get_address import _show_address +from apps.common import seed +from trezor.messages.NEMAddress import NEMAddress +from .helpers import * + +_NEM_CURVE = 'ed25519-keccak' + + +async def nem_get_address(ctx, msg): + network = nem_validate_network(msg.network) + node = await seed.derive_node(ctx, msg.address_n, _NEM_CURVE) + address = node.nem_address(network) + + if msg.show_display: + while True: + if await _show_address(ctx, address): + break + + return NEMAddress(address=address) + diff --git a/src/apps/nem/helpers.py b/src/apps/nem/helpers.py new file mode 100644 index 0000000000..1ac0bcb1f8 --- /dev/null +++ b/src/apps/nem/helpers.py @@ -0,0 +1,14 @@ + +from micropython import const + +_NEM_NETWORK_MAINNET = const(0x68) +_NEM_NETWORK_TESTNET = const(0x98) +_NEM_NETWORK_MIJIN = const(0x60) + + +def nem_validate_network(network): + if network in (_NEM_NETWORK_MAINNET, _NEM_NETWORK_TESTNET, _NEM_NETWORK_MIJIN): + return network + if network is None: + return _NEM_NETWORK_MAINNET + raise ValueError('Invalid NEM network') diff --git a/src/main.py b/src/main.py index 5b1fe06c24..0c239327c0 100644 --- a/src/main.py +++ b/src/main.py @@ -12,6 +12,7 @@ import apps.management import apps.wallet import apps.ethereum import apps.lisk +import apps.nem if __debug__: import apps.debug else: @@ -23,6 +24,7 @@ apps.management.boot() apps.wallet.boot() apps.ethereum.boot() apps.lisk.boot() +apps.nem.boot() if __debug__: apps.debug.boot() else: