diff --git a/src/apps/common/cache.py b/src/apps/common/cache.py index 2a294f0fe..b5425264e 100644 --- a/src/apps/common/cache.py +++ b/src/apps/common/cache.py @@ -1,6 +1,5 @@ -from trezor.crypto import random, hashlib, hmac -from apps.common.storage import get_device_id - +from trezor.crypto import hashlib, hmac, random +from apps.common import storage memory = {} _seed = None @@ -23,7 +22,7 @@ def get_state(salt: bytes=None, passphrase: str=None): key = _passphrase if _passphrase is not None else '' else: key = passphrase - msg = _state_salt + get_device_id().encode() + msg = _state_salt + storage.get_device_id().encode() state = hmac.new(key.encode(), msg, hashlib.sha256).digest() return _state_salt + state diff --git a/src/apps/common/confirm.py b/src/apps/common/confirm.py index aeadec02b..4560faa95 100644 --- a/src/apps/common/confirm.py +++ b/src/apps/common/confirm.py @@ -1,4 +1,7 @@ -from trezor import wire, ui, loop +from trezor import loop, ui, wire +from trezor.messages import ButtonRequestType, FailureType, wire_types +from trezor.messages.ButtonRequest import ButtonRequest +from trezor.ui.confirm import CONFIRMED, ConfirmDialog, HoldToConfirmDialog from apps.common import cache # used to confirm/cancel the dialogs from outside of this module (i.e. @@ -9,14 +12,9 @@ if __debug__: @ui.layout async def confirm(ctx, content, code=None, *args, **kwargs): - from trezor.ui.confirm import ConfirmDialog, CONFIRMED - from trezor.messages.ButtonRequest import ButtonRequest - from trezor.messages.ButtonRequestType import Other - from trezor.messages.wire_types import ButtonAck - if code is None: - code = Other - await ctx.call(ButtonRequest(code=code), ButtonAck) + code = ButtonRequestType.Other + await ctx.call(ButtonRequest(code=code), wire_types.ButtonAck) dialog = ConfirmDialog(content, *args, **kwargs) @@ -29,14 +27,9 @@ async def confirm(ctx, content, code=None, *args, **kwargs): @ui.layout async def hold_to_confirm(ctx, content, code=None, *args, **kwargs): - from trezor.ui.confirm import HoldToConfirmDialog, CONFIRMED - from trezor.messages.ButtonRequest import ButtonRequest - from trezor.messages.ButtonRequestType import Other - from trezor.messages.wire_types import ButtonAck - if code is None: - code = Other - await ctx.call(ButtonRequest(code=code), ButtonAck) + code = ButtonRequestType.Other + await ctx.call(ButtonRequest(code=code), wire_types.ButtonAck) dialog = HoldToConfirmDialog(content, 'Hold to confirm', *args, **kwargs) @@ -48,9 +41,6 @@ async def hold_to_confirm(ctx, content, code=None, *args, **kwargs): async def require_confirm(*args, **kwargs): - from trezor.messages.FailureType import ActionCancelled - confirmed = await confirm(*args, **kwargs) - if not confirmed: - raise wire.FailureError(ActionCancelled, 'Cancelled') + raise wire.FailureError(FailureType.ActionCancelled, 'Cancelled') diff --git a/src/apps/common/request_pin.py b/src/apps/common/request_pin.py index 572b278d4..7d065b1a0 100644 --- a/src/apps/common/request_pin.py +++ b/src/apps/common/request_pin.py @@ -1,5 +1,7 @@ -from trezor import res -from trezor import ui +from trezor import res, ui +from trezor.messages import PinMatrixRequestType +from trezor.ui.confirm import CONFIRMED, ConfirmDialog +from trezor.ui.pin import PinMatrix class PinCancelled(Exception): @@ -8,10 +10,6 @@ class PinCancelled(Exception): @ui.layout async def request_pin(code: int = None, cancellable: bool = True) -> str: - from trezor.ui.confirm import ConfirmDialog, CONFIRMED - from trezor.ui.pin import PinMatrix - - label = _get_label(code) def onchange(): c = dialog.cancel @@ -30,6 +28,7 @@ async def request_pin(code: int = None, cancellable: bool = True) -> str: c.taint() c.render() + label = _get_label(code) matrix = PinMatrix(label, with_zero=True) matrix.onchange = onchange dialog = ConfirmDialog(matrix) @@ -52,7 +51,6 @@ async def request_pin(code: int = None, cancellable: bool = True) -> str: def _get_label(code: int): - from trezor.messages import PinMatrixRequestType if code is None: code = PinMatrixRequestType.Current if code == PinMatrixRequestType.NewFirst: diff --git a/src/apps/common/seed.py b/src/apps/common/seed.py index 3e3754387..9647a22ad 100644 --- a/src/apps/common/seed.py +++ b/src/apps/common/seed.py @@ -1,20 +1,21 @@ from trezor import wire -from trezor.crypto import bip32 -from trezor.crypto import bip39 +from trezor.crypto import bip32, bip39 +from trezor.messages.FailureType import ProcessError +from apps.common import cache, storage +from apps.common.request_passphrase import protect_by_passphrase _DEFAULT_CURVE = 'secp256k1' -async def derive_node(ctx: wire.Context, path=[], curve_name=_DEFAULT_CURVE): +async def derive_node(ctx: wire.Context, path=(), curve_name=_DEFAULT_CURVE): seed = await _get_seed(ctx) node = bip32.from_seed(seed, curve_name) - if len(path) > 0: + if path: node.derive_path(path) return node async def _get_seed(ctx: wire.Context) -> bytes: - from . import cache if cache.get_seed() is None: seed, passphrase = await _compute_seed(ctx) cache.set_seed(seed, passphrase) @@ -22,10 +23,6 @@ async def _get_seed(ctx: wire.Context) -> bytes: async def _compute_seed(ctx: wire.Context) -> (bytes, str): - from trezor.messages.FailureType import ProcessError - from .request_passphrase import protect_by_passphrase - from . import storage - if not storage.is_initialized(): raise wire.FailureError(ProcessError, 'Device is not initialized') @@ -34,9 +31,9 @@ async def _compute_seed(ctx: wire.Context) -> (bytes, str): def derive_node_without_passphrase(path, curve_name=_DEFAULT_CURVE): - from . import storage if not storage.is_initialized(): raise Exception('Device is not initialized') + seed = bip39.seed(storage.get_mnemonic(), '') node = bip32.from_seed(seed, curve_name) node.derive_path(path) diff --git a/src/apps/common/signverify.py b/src/apps/common/signverify.py index d5168d92b..e0d1f3487 100644 --- a/src/apps/common/signverify.py +++ b/src/apps/common/signverify.py @@ -1,8 +1,8 @@ -from ubinascii import hexlify -from trezor.crypto.hashlib import sha256 from trezor import ui +from trezor.crypto.hashlib import sha256 from trezor.ui.text import TEXT_MARGIN_LEFT -from trezor.utils import chunks, split_words, HashWriter +from trezor.utils import HashWriter, chunks, split_words +from ubinascii import hexlify from apps.wallet.sign_tx.signing import write_varint @@ -16,9 +16,13 @@ def message_digest(coin, message): def split_message(message): + + def measure(s): + return ui.display.text_width(s, ui.NORMAL) + try: m = bytes(message).decode() - lines = split_words(m, ui.WIDTH - 2 * TEXT_MARGIN_LEFT, metric=lambda x: ui.display.text_width(x, ui.NORMAL)) + lines = split_words(m, ui.WIDTH - 2 * TEXT_MARGIN_LEFT, metric=measure) except UnicodeError: m = hexlify(message) lines = chunks(m, 16) diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index a9020cd99..1135cb5df 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -1,6 +1,8 @@ from micropython import const - +from ubinascii import hexlify from trezor import config +from trezor.crypto import random +from apps.common import cache _STORAGE_VERSION = b'\x01' @@ -95,12 +97,9 @@ def set_flags(flags: int) -> None: def wipe(): - from . import cache config.wipe() cache.clear() def new_device_id() -> str: - from ubinascii import hexlify - from trezor.crypto import random return hexlify(random.bytes(12)).decode().upper() diff --git a/src/apps/homescreen/__init__.py b/src/apps/homescreen/__init__.py index 2e5d61952..d8ea14caf 100644 --- a/src/apps/homescreen/__init__.py +++ b/src/apps/homescreen/__init__.py @@ -1,13 +1,14 @@ from trezor import config -from trezor.wire import register, protobuf_workflow from trezor.utils import unimport, symbol -from trezor.messages.wire_types import Initialize, GetFeatures, Ping, ClearSession +from trezor.wire import register, protobuf_workflow +from trezor.messages import wire_types +from trezor.messages.Features import Features +from trezor.messages.Success import Success + +from apps.common import storage, coins, cache -@unimport async def respond_Features(ctx, msg): - from apps.common import storage, coins, cache - from trezor.messages.Features import Features if msg.__qualname__ == 'Initialize': if msg.state is None or msg.state != cache.get_state(salt=msg.state[:32]): @@ -35,12 +36,13 @@ async def respond_Features(ctx, msg): return f +async def respond_ClearSession(ctx, msg): + cache.clear() + return Success(message='Session cleared') + + @unimport async def respond_Pong(ctx, msg): - from trezor.messages.Success import Success - - s = Success() - s.message = msg.message if msg.button_protection: from apps.common.confirm import require_confirm @@ -53,19 +55,11 @@ async def respond_Pong(ctx, msg): from apps.common.request_passphrase import protect_by_passphrase await protect_by_passphrase(ctx) - return s - - -@unimport -async def respond_ClearSession(ctx, msg): - from apps.common import cache - from trezor.messages.Success import Success - cache.clear() - return Success(message='Session cleared') + return Success(messge=msg.message) def boot(): - register(Initialize, protobuf_workflow, respond_Features) - register(GetFeatures, protobuf_workflow, respond_Features) - register(Ping, protobuf_workflow, respond_Pong) - register(ClearSession, protobuf_workflow, respond_ClearSession) + register(wire_types.Initialize, protobuf_workflow, respond_Features) + register(wire_types.GetFeatures, protobuf_workflow, respond_Features) + register(wire_types.ClearSession, protobuf_workflow, respond_ClearSession) + register(wire_types.Ping, protobuf_workflow, respond_Pong) diff --git a/src/apps/homescreen/homescreen.py b/src/apps/homescreen/homescreen.py index 9ef9f9cd3..c27e4623d 100644 --- a/src/apps/homescreen/homescreen.py +++ b/src/apps/homescreen/homescreen.py @@ -1,17 +1,17 @@ from trezor import ui, res -from trezor.utils import unimport +from trezor.ui.swipe import Swipe, degrees +from apps.common import storage -async def swipe_to_rotate(): - from trezor.ui.swipe import Swipe, degrees - - swipe = await Swipe(absolute=True) - ui.display.orientation(degrees(swipe)) +async def homescreen(): + while True: + await ui.backlight_slide(ui.BACKLIGHT_DIM) + display_homescreen() + await ui.backlight_slide(ui.BACKLIGHT_NORMAL) + await swipe_to_rotate() def display_homescreen(): - from apps.common import storage - if not storage.is_initialized(): label = 'Go to trezor.io/start' image = None @@ -32,10 +32,6 @@ def display_homescreen(): ui.display.text_center(120, 220, label, ui.BOLD, ui.FG, ui.BG) -@unimport -async def layout_homescreen(): - while True: - await ui.backlight_slide(ui.BACKLIGHT_DIM) - display_homescreen() - await ui.backlight_slide(ui.BACKLIGHT_NORMAL) - await swipe_to_rotate() +async def swipe_to_rotate(): + swipe = await Swipe(absolute=True) + ui.display.orientation(degrees(swipe)) diff --git a/src/apps/management/apply_flags.py b/src/apps/management/apply_flags.py index 58773a648..7effa2cad 100644 --- a/src/apps/management/apply_flags.py +++ b/src/apps/management/apply_flags.py @@ -1,7 +1,7 @@ -async def apply_flags(ctx, msg): - from trezor.messages.Success import Success - from ..common import storage +from trezor.messages.Success import Success +from apps.common import storage - storage.set_flags(msg.flags) +async def apply_flags(ctx, msg): + storage.set_flags(msg.flags) return Success(message='Flags applied') diff --git a/src/apps/management/apply_settings.py b/src/apps/management/apply_settings.py index 42bda842d..81104d0b0 100644 --- a/src/apps/management/apply_settings.py +++ b/src/apps/management/apply_settings.py @@ -1,13 +1,12 @@ from trezor import ui, wire +from trezor.messages import ButtonRequestType, FailureType +from trezor.messages.Success import Success +from trezor.ui.text import Text +from apps.common import storage +from apps.common.confirm import require_confirm async def apply_settings(ctx, msg): - from trezor.messages.Success import Success - from trezor.messages import ButtonRequestType, FailureType - from trezor.ui.text import Text - from ..common.confirm import require_confirm - from ..common import storage - if msg.homescreen is None and msg.label is None and msg.language is None and msg.use_passphrase is None: raise wire.FailureError(FailureType.ProcessError, 'No setting provided') diff --git a/src/apps/management/backup_device.py b/src/apps/management/backup_device.py index a8362db51..0280c67b4 100644 --- a/src/apps/management/backup_device.py +++ b/src/apps/management/backup_device.py @@ -2,14 +2,13 @@ from trezor import wire from trezor.messages.FailureType import ProcessError from trezor.messages.Success import Success from apps.common import storage -from apps.management.reset_device import show_warning, show_mnemonic, check_mnemonic, show_wrong_entry +from apps.management.reset_device import (check_mnemonic, show_mnemonic, + show_warning, show_wrong_entry) async def backup_device(ctx, msg): - if not storage.is_initialized(): raise wire.FailureError(ProcessError, 'Device is not initialized') - if not storage.needs_backup(): raise wire.FailureError(ProcessError, 'Seed already backed up') diff --git a/src/apps/management/change_pin.py b/src/apps/management/change_pin.py index a4d78d736..f062c06eb 100644 --- a/src/apps/management/change_pin.py +++ b/src/apps/management/change_pin.py @@ -1,51 +1,46 @@ from trezor import config, loop, ui +from trezor.messages import FailureType, PinMatrixRequestType +from trezor.messages.ButtonRequest import ButtonRequest +from trezor.messages.ButtonRequestType import Other +from trezor.messages.Failure import Failure +from trezor.messages.Success import Success +from trezor.messages import wire_types from trezor.pin import pin_to_int, show_pin_timeout +from trezor.ui.text import Text +from apps.common.confirm import require_confirm +from apps.common.request_pin import request_pin -async def request_pin(ctx, code=None, *args, **kwargs): - from trezor.messages.ButtonRequest import ButtonRequest - from trezor.messages.ButtonRequestType import Other - from trezor.messages.wire_types import ButtonAck - from apps.common.request_pin import request_pin - - if code is None: - code = Other - await ctx.call(ButtonRequest(code=code), ButtonAck) - - return await request_pin(*args, **kwargs) - - -@ui.layout -async def pin_mismatch(): - from trezor.ui.text import Text +async def change_pin(ctx, msg): - text = Text( - 'PIN mismatch', ui.ICON_DEFAULT, - 'Entered PINs do not', - 'match each other.', - '', - 'Please, try again...') - text.render() - await loop.sleep(3 * 1000 * 1000) + # confirm that user wants to change the pin + await confirm_change_pin(ctx, msg) + # get current pin, return failure if invalid + if config.has_pin(): + curpin = await request_pin_ack(ctx, PinMatrixRequestType.Current) + if not config.check_pin(pin_to_int(curpin), show_pin_timeout): + return Failure(code=FailureType.PinInvalid, message='PIN invalid') + else: + curpin = '' -async def request_pin_confirm(ctx, *args, **kwargs): - from trezor.messages import PinMatrixRequestType + # get new pin + if not msg.remove: + newpin = await request_pin_confirm(ctx) + else: + newpin = '' - while True: - pin1 = await request_pin( - ctx, code=PinMatrixRequestType.NewFirst, *args, **kwargs) - pin2 = await request_pin( - ctx, code=PinMatrixRequestType.NewSecond, *args, **kwargs) - if pin1 == pin2: - return pin1 - await pin_mismatch() + # write into storage + if config.change_pin(pin_to_int(curpin), pin_to_int(newpin), show_pin_timeout): + if newpin: + return Success(message='PIN changed') + else: + return Success(message='PIN removed') + else: + return Failure(code=FailureType.PinInvalid, message='PIN invalid') def confirm_change_pin(ctx, msg): - from apps.common.confirm import require_confirm - from trezor.ui.text import Text - has_pin = config.has_pin() if msg.remove and has_pin: # removing pin @@ -67,27 +62,31 @@ def confirm_change_pin(ctx, msg): 'set new PIN?')) -async def change_pin(ctx, msg): - from trezor.messages.Success import Success - from trezor.messages.Failure import Failure - from trezor.messages import FailureType, PinMatrixRequestType +async def request_pin_ack(ctx, code=None, *args, **kwargs): + if code is None: + code = Other + await ctx.call(ButtonRequest(code=code), wire_types.ButtonAck) + return await request_pin(*args, **kwargs) - await confirm_change_pin(ctx, msg) - if config.has_pin(): - curr_pin = await request_pin(ctx, PinMatrixRequestType.Current) - if not config.check_pin(pin_to_int(curr_pin), show_pin_timeout): - return Failure(code=FailureType.PinInvalid, message='PIN invalid') - else: - curr_pin = '' - if msg.remove: - new_pin = '' - else: - new_pin = await request_pin_confirm(ctx) - if config.change_pin(pin_to_int(curr_pin), pin_to_int(new_pin), show_pin_timeout): - if new_pin: - return Success(message='PIN changed') - else: - return Success(message='PIN removed') - else: - return Failure(code=FailureType.PinInvalid, message='PIN invalid') +async def request_pin_confirm(ctx, *args, **kwargs): + while True: + pin1 = await request_pin_ack( + ctx, code=PinMatrixRequestType.NewFirst, *args, **kwargs) + pin2 = await request_pin_ack( + ctx, code=PinMatrixRequestType.NewSecond, *args, **kwargs) + if pin1 == pin2: + return pin1 + await pin_mismatch() + + +@ui.layout +async def pin_mismatch(): + text = Text( + 'PIN mismatch', ui.ICON_DEFAULT, + 'Entered PINs do not', + 'match each other.', + '', + 'Please, try again...') + text.render() + await loop.sleep(3 * 1000 * 1000) diff --git a/src/apps/management/load_device.py b/src/apps/management/load_device.py index f2de2ec2f..d4165baaa 100644 --- a/src/apps/management/load_device.py +++ b/src/apps/management/load_device.py @@ -1,14 +1,14 @@ -from trezor import wire, ui, config +from trezor import config, ui, wire +from trezor.crypto import bip39 +from trezor.messages.FailureType import ProcessError, UnexpectedMessage +from trezor.messages.Success import Success from trezor.pin import pin_to_int +from trezor.ui.text import Text +from apps.common import storage +from apps.common.confirm import require_confirm async def load_device(ctx, msg): - from trezor.crypto import bip39 - from trezor.messages.Success import Success - from trezor.messages.FailureType import UnexpectedMessage, ProcessError - from trezor.ui.text import Text - from ..common.confirm import require_confirm - from ..common import storage if storage.is_initialized(): raise wire.FailureError(UnexpectedMessage, 'Already initialized') diff --git a/src/apps/management/reset_device.py b/src/apps/management/reset_device.py index 0a2314a39..cdfabf036 100644 --- a/src/apps/management/reset_device.py +++ b/src/apps/management/reset_device.py @@ -1,6 +1,4 @@ from micropython import const -from ubinascii import hexlify - from trezor import config, ui, wire from trezor.crypto import bip39, hashlib, random from trezor.messages import ButtonRequestType, FailureType, wire_types @@ -13,7 +11,7 @@ from trezor.ui.keyboard import MnemonicKeyboard from trezor.ui.scroll import Scrollpage, animate_swipe, paginate from trezor.ui.text import Text from trezor.utils import chunks, format_ordinal - +from ubinascii import hexlify from apps.common import storage from apps.common.confirm import require_confirm from apps.management.change_pin import request_pin_confirm @@ -23,7 +21,6 @@ if __debug__: current_word = None -@ui.layout async def reset_device(ctx, msg): if __debug__: global internal_entropy diff --git a/src/apps/wallet/get_address.py b/src/apps/wallet/get_address.py index b8849eeda..b999b924e 100644 --- a/src/apps/wallet/get_address.py +++ b/src/apps/wallet/get_address.py @@ -1,58 +1,62 @@ from micropython import const from trezor import ui +from trezor.messages import ButtonRequestType, InputScriptType +from trezor.messages.Address import Address +from trezor.ui.container import Container +from trezor.ui.qr import Qr +from trezor.ui.text import Text +from trezor.utils import chunks +from apps.common import coins, seed +from apps.common.confirm import confirm +from apps.wallet.sign_tx import addresses async def get_address(ctx, msg): - from trezor.messages.Address import Address - from trezor.messages.InputScriptType import SPENDWITNESS - from ..common import coins - from ..common import seed - from ..wallet.sign_tx import addresses - - address_n = msg.address_n or () coin_name = msg.coin_name or 'Bitcoin' coin = coins.by_name(coin_name) - node = await seed.derive_node(ctx, address_n) + node = await seed.derive_node(ctx, msg.address_n) address = addresses.get_address(msg.script_type, coin, node, msg.multisig) if msg.show_display: while True: if await _show_address(ctx, address): break - if await _show_qr(ctx, address if msg.script_type != SPENDWITNESS else address.upper()): + if await _show_qr(ctx, address, msg.script_type): break return Address(address=address) -async def _show_address(ctx, address): - from trezor.messages.ButtonRequestType import Address - from trezor.ui.text import Text - from ..common.confirm import confirm - +async def _show_address(ctx, address: str): lines = _split_address(address) content = Text('Confirm address', ui.ICON_DEFAULT, ui.MONO, *lines) - return await confirm(ctx, content, code=Address, cancel='QR', cancel_style=ui.BTN_KEY) + return await confirm( + ctx, + content, + code=ButtonRequestType.Address, + cancel='QR', + cancel_style=ui.BTN_KEY) -async def _show_qr(ctx, address): - from trezor.messages.ButtonRequestType import Address - from trezor.ui.text import Text - from trezor.ui.qr import Qr - from trezor.ui.container import Container - from ..common.confirm import confirm - +async def _show_qr(ctx, address: str, script_type: int): qr_x = const(120) qr_y = const(115) qr_coef = const(4) + if script_type == InputScriptType.SPENDWITNESS: + address = address.upper() + content = Container( Qr(address, (qr_x, qr_y), qr_coef), Text('Confirm address', ui.ICON_DEFAULT, ui.MONO)) - return await confirm(ctx, content, code=Address, cancel='Address', cancel_style=ui.BTN_KEY) + return await confirm( + ctx, + content, + code=ButtonRequestType.Address, + cancel='Address', + cancel_style=ui.BTN_KEY) -def _split_address(address): - from trezor.utils import chunks +def _split_address(address: str): return chunks(address, 17) diff --git a/src/apps/wallet/get_entropy.py b/src/apps/wallet/get_entropy.py index b2a284045..c726473bf 100644 --- a/src/apps/wallet/get_entropy.py +++ b/src/apps/wallet/get_entropy.py @@ -1,24 +1,20 @@ from trezor import ui +from trezor.crypto import random +from trezor.messages import ButtonRequestType +from trezor.messages.Entropy import Entropy +from trezor.ui.text import Text +from apps.common.confirm import require_confirm async def get_entropy(ctx, msg): - from trezor.messages.Entropy import Entropy - from trezor.crypto import random - - l = min(msg.size, 1024) - - await _show_entropy(ctx) - - return Entropy(entropy=random.bytes(l)) - - -async def _show_entropy(ctx): - from trezor.messages.ButtonRequestType import ProtectCall - from trezor.ui.text import Text - from ..common.confirm import require_confirm await require_confirm(ctx, Text( 'Confirm entropy', ui.ICON_DEFAULT, ui.BOLD, 'Do you really want', 'to send entropy?', ui.NORMAL, 'Continue only if you', 'know what you are doing!'), - code=ProtectCall) + code=ButtonRequestType.ProtectCall) + + size = min(msg.size, 1024) + entropy = random.bytes(size) + + return Entropy(entropy=entropy) diff --git a/src/apps/wallet/get_public_key.py b/src/apps/wallet/get_public_key.py index 9e8a7ceae..2ff144ac5 100644 --- a/src/apps/wallet/get_public_key.py +++ b/src/apps/wallet/get_public_key.py @@ -1,14 +1,12 @@ +from trezor.messages.HDNodeType import HDNodeType +from trezor.messages.PublicKey import PublicKey +from apps.common import coins, seed -async def get_public_key(ctx, msg): - from trezor.messages.HDNodeType import HDNodeType - from trezor.messages.PublicKey import PublicKey - from ..common import coins - from ..common import seed - address_n = msg.address_n or () +async def get_public_key(ctx, msg): coin_name = msg.coin_name or 'Bitcoin' - node = await seed.derive_node(ctx, address_n) + node = await seed.derive_node(ctx, msg.address_n) coin = coins.by_name(coin_name) node_xpub = node.serialize_public(coin.xpub_magic) diff --git a/src/apps/wallet/sign_identity.py b/src/apps/wallet/sign_identity.py index 1ee5b90e9..d44db8f37 100644 --- a/src/apps/wallet/sign_identity.py +++ b/src/apps/wallet/sign_identity.py @@ -1,4 +1,42 @@ from trezor import ui +from trezor.crypto.hashlib import sha256 +from trezor.messages.SignedIdentity import SignedIdentity +from ustruct import pack, unpack + +from ..common import coins, seed + + +async def sign_identity(ctx, msg): + if msg.ecdsa_curve_name is None: + msg.ecdsa_curve_name = 'secp256k1' + + identity = serialize_identity(msg.identity) + display_identity(identity, msg.challenge_visual) + + address_n = get_identity_path(identity, msg.identity.index or 0) + node = await seed.derive_node(ctx, address_n, msg.ecdsa_curve_name) + + coin = coins.by_name('Bitcoin') + if msg.ecdsa_curve_name == 'secp256k1': + address = node.address(coin.address_type) # hardcoded bitcoin address type + else: + address = None + pubkey = node.public_key() + if pubkey[0] == 0x01: + pubkey = b'\x00' + pubkey[1:] + seckey = node.private_key() + + if msg.identity.proto == 'gpg': + signature = sign_challenge( + seckey, msg.challenge_hidden, msg.challenge_visual, 'gpg', msg.ecdsa_curve_name) + elif msg.identity.proto == 'ssh': + signature = sign_challenge( + seckey, msg.challenge_hidden, msg.challenge_visual, 'ssh', msg.ecdsa_curve_name) + else: + signature = sign_challenge( + seckey, msg.challenge_hidden, msg.challenge_visual, coin, msg.ecdsa_curve_name) + + return SignedIdentity(address=address, public_key=pubkey, signature=signature) def serialize_identity(identity): @@ -25,9 +63,6 @@ def display_identity(identity: str, challenge_visual: str): def get_identity_path(identity: str, index: int): - from ustruct import pack, unpack - from trezor.crypto.hashlib import sha256 - identity_hash = sha256(pack('