async def reset_device(ctx, msg): if __debug__: global internal_entropy # validate parameters and device state if msg.strength not in (128, 192, 256): raise wire.FailureError( FailureType.ProcessError, 'Invalid strength (has to be 128, 192 or 256 bits)') if storage.is_initialized(): raise wire.FailureError( FailureType.UnexpectedMessage, 'Already initialized') if msg.pin_protection: # request new PIN newpin = await request_pin_confirm(ctx) else: # new PIN is empty newpin = '' # generate and display internal entropy internal_entropy = random.bytes(32) if msg.display_random: await show_entropy(ctx, internal_entropy) # request external entropy and compute mnemonic ack = await ctx.call(EntropyRequest(), wire_types.EntropyAck) mnemonic = generate_mnemonic( msg.strength, internal_entropy, ack.entropy) if msg.skip_backup: # let user backup the mnemonic later pass else: # warn user about mnemonic safety await show_warning(ctx) while True: # show mnemonic and require confirmation of a random word await show_mnemonic(ctx, mnemonic) if await check_mnemonic(ctx, mnemonic): break await show_wrong_entry(ctx) # write PIN into storage if not config.change_pin(pin_to_int(''), pin_to_int(newpin), None): raise wire.FailureError( FailureType.ProcessError, 'Could not change PIN') # write settings and mnemonic into storage storage.load_settings( label=msg.label, use_passphrase=msg.passphrase_protection) storage.load_mnemonic( mnemonic=mnemonic, needs_backup=msg.skip_backup) # show success message if not msg.skip_backup: await show_success(ctx) return Success(message='Initialized')
async def sign_tx(ctx, msg): from trezor.messages.RequestType import TXFINISHED from trezor.messages.wire_types import TxAck from apps.common import seed from . import signing from . import layout # TODO: rework this so we don't have to pass root to signing.sign_tx root = await seed.derive_node(ctx, []) signer = signing.sign_tx(msg, root) res = None while True: try: req = signer.send(res) except signing.SigningError as e: raise wire.FailureError(*e.args) except signing.AddressError as e: raise wire.FailureError(*e.args) if req.__qualname__ == 'TxRequest': if req.request_type == TXFINISHED: break res = await ctx.call(req, TxAck) elif req.__qualname__ == 'UiConfirmOutput': res = await layout.confirm_output(ctx, req.output, req.coin) elif req.__qualname__ == 'UiConfirmTotal': res = await layout.confirm_total(ctx, req.spending, req.fee, req.coin) elif req.__qualname__ == 'UiConfirmFeeOverThreshold': res = await layout.confirm_feeoverthreshold(ctx, req.fee, req.coin) else: raise TypeError('Invalid signing instruction') return req
async def load_device(ctx, msg): if storage.is_initialized(): raise wire.FailureError(UnexpectedMessage, 'Already initialized') if msg.node is not None: raise wire.FailureError(ProcessError, 'LoadDevice.node is not supported') if not msg.skip_checksum and not bip39.check(msg.mnemonic): raise wire.FailureError(ProcessError, 'Mnemonic is not valid') await require_confirm( ctx, Text('Loading seed', ui.ICON_DEFAULT, ui.BOLD, 'Loading private seed', 'is not recommended.', ui.NORMAL, 'Continue only if you', 'know what you are doing!')) storage.load_mnemonic(mnemonic=msg.mnemonic, needs_backup=True) storage.load_settings(use_passphrase=msg.passphrase_protection, label=msg.label) if msg.pin: config.change_pin(pin_to_int(''), pin_to_int(msg.pin), None) return Success(message='Device loaded')
async def layout_load_device(session_id, msg): from trezor.crypto import bip39 from trezor.messages.Success import Success from trezor.messages.FailureType import UnexpectedMessage, Other 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') if msg.node is not None: raise wire.FailureError(Other, 'LoadDevice.node is not supported') if not msg.skip_checksum and not bip39.check(msg.mnemonic): raise wire.FailureError(Other, 'Mnemonic is not valid') await require_confirm( session_id, Text('Loading seed', ui.ICON_RESET, ui.BOLD, 'Loading private seed', 'is not recommended.', ui.NORMAL, 'Continue only if you', 'know what you are doing!')) storage.load_mnemonic(msg.mnemonic) storage.load_settings(pin=msg.pin, passphrase_protection=msg.passphrase_protection, language=msg.language, label=msg.label) return Success(message='Device loaded')
async def request_passphrase_ack(ctx, on_device): if not on_device: text = Text( 'Passphrase entry', ui.ICON_CONFIG, 'Please, type passphrase', 'on connected host.') text.render() req = PassphraseRequest(on_device=on_device) ack = await ctx.call(req, wire_types.PassphraseAck, wire_types.Cancel) if ack.MESSAGE_WIRE_TYPE == wire_types.Cancel: raise wire.FailureError(ActionCancelled, 'Passphrase cancelled') if on_device: if ack.passphrase is not None: raise wire.FailureError(ProcessError, 'Passphrase provided when it should not be') keyboard = PassphraseKeyboard('Enter passphrase') passphrase = await ctx.wait(keyboard) if passphrase == CANCELLED: raise wire.FailureError(ActionCancelled, 'Passphrase cancelled') else: if ack.passphrase is None: raise wire.FailureError(ProcessError, 'Passphrase not provided') passphrase = ack.passphrase req = PassphraseStateRequest(state=get_state(state=ack.state, passphrase=passphrase)) ack = await ctx.call(req, wire_types.PassphraseStateAck, wire_types.Cancel) return passphrase
async def reset_device(ctx, msg): # validate parameters and device state if msg.strength not in (128, 192, 256): raise wire.FailureError( FailureType.ProcessError, 'Invalid strength (has to be 128, 192 or 256 bits)') if storage.is_initialized(): raise wire.FailureError(FailureType.UnexpectedMessage, 'Already initialized') # request new PIN if msg.pin_protection: newpin = await request_pin_confirm(ctx) else: newpin = '' # generate and display internal entropy internal_ent = random.bytes(32) if __debug__: debug.reset_internal_entropy = internal_ent if msg.display_random: await show_entropy(ctx, internal_ent) # request external entropy and compute mnemonic ent_ack = await ctx.call(EntropyRequest(), wire_types.EntropyAck) mnemonic = generate_mnemonic(msg.strength, internal_ent, ent_ack.entropy) if not msg.skip_backup: # require confirmation of the mnemonic safety await show_warning(ctx) # show mnemonic and require confirmation of a random word while True: await show_mnemonic(ctx, mnemonic) if await check_mnemonic(ctx, mnemonic): break await show_wrong_entry(ctx) # write PIN into storage if not config.change_pin(pin_to_int(''), pin_to_int(newpin), None): raise wire.FailureError(FailureType.ProcessError, 'Could not change PIN') # write settings and mnemonic into storage storage.load_settings(label=msg.label, use_passphrase=msg.passphrase_protection) storage.load_mnemonic(mnemonic=mnemonic, needs_backup=msg.skip_backup) # show success message. if we skipped backup, it's possible that homescreen # is still running, uninterrupted. restart it to pick up new label. if not msg.skip_backup: await show_success(ctx) else: workflow.restartdefault() return Success(message='Initialized')
async def layout_reset_device(session_id, msg): from trezor.ui.text import Text from trezor.crypto import hashlib, random, bip39 from trezor.messages.EntropyRequest import EntropyRequest from trezor.messages.Success import Success from trezor.messages import FailureType from trezor.messages import ButtonRequestType from trezor.messages.wire_types import EntropyAck from apps.common.request_pin import request_pin_twice from apps.common.confirm import require_confirm from apps.common import storage if __debug__: global internal_entropy if msg.strength not in (128, 192, 256): raise wire.FailureError( FailureType.Other, 'Invalid strength (has to be 128, 192 or 256 bits)') if storage.is_initialized(): raise wire.FailureError(FailureType.UnexpectedMessage, 'Already initialized') internal_entropy = random.bytes(32) if msg.display_random: entropy_lines = chunks(ubinascii.hexlify(internal_entropy), 16) entropy_content = Text('Internal entropy', ui.ICON_RESET, *entropy_lines) await require_confirm(session_id, entropy_content, ButtonRequestType.ResetDevice) if msg.pin_protection: pin = await request_pin_twice(session_id) else: pin = None external_entropy_ack = await wire.call(session_id, EntropyRequest(), EntropyAck) ctx = hashlib.sha256() ctx.update(internal_entropy) ctx.update(external_entropy_ack.entropy) entropy = ctx.digest() mnemonic = bip39.from_data(entropy[:msg.strength // 8]) await show_mnemonic_by_word(session_id, mnemonic) storage.load_mnemonic(mnemonic) storage.load_settings(pin=pin, passphrase_protection=msg.passphrase_protection, language=msg.language, label=msg.label) return Success(message='Initialized')
async def apply_settings(ctx, msg): if msg.homescreen is None and msg.label is None and msg.use_passphrase is None and msg.passphrase_source is None: raise wire.FailureError(FailureType.ProcessError, 'No setting provided') if msg.homescreen is not None: if len(msg.homescreen) > storage.HOMESCREEN_MAXSIZE: raise wire.FailureError(FailureType.DataError, 'Homescreen is too complex') await require_confirm(ctx, Text('Change homescreen', ui.ICON_CONFIG, 'Do you really want to', 'change homescreen?'), code=ButtonRequestType.ProtectCall) # TODO: split label (bold) and '?' (normal) once we support mixed styles on one line if msg.label is not None: await require_confirm(ctx, Text('Change label', ui.ICON_CONFIG, 'Do you really want to', 'change label to', ui.BOLD, '%s?' % msg.label), code=ButtonRequestType.ProtectCall) if msg.use_passphrase is not None: await require_confirm(ctx, Text( 'Enable passphrase' if msg.use_passphrase else 'Disable passphrase', ui.ICON_CONFIG, 'Do you really want to', 'enable passphrase' if msg.use_passphrase else 'disable passphrase', 'encryption?'), code=ButtonRequestType.ProtectCall) if msg.passphrase_source is not None: if msg.passphrase_source == PassphraseSourceType.DEVICE: desc = 'ON DEVICE' elif msg.passphrase_source == PassphraseSourceType.HOST: desc = 'ON HOST' else: desc = 'ASK' await require_confirm(ctx, Text('Passphrase source', ui.ICON_CONFIG, 'Do you really want to', 'change the passphrase', 'source to', ui.BOLD, 'ALWAYS %s?' % desc), code=ButtonRequestType.ProtectCall) storage.load_settings(label=msg.label, use_passphrase=msg.use_passphrase, homescreen=msg.homescreen, passphrase_source=msg.passphrase_source) return Success(message='Settings applied')
async def request_passphrase(ctx): from trezor.ui.text import Text from trezor.ui.entry_select import EntrySelector ui.display.clear() text = Text('Enter passphrase', ui.ICON_RESET, 'Where to enter your', 'passphrase?') entry = EntrySelector(text) entry_type = await entry on_device = (entry_type == 0) from trezor.messages.FailureType import ActionCancelled, ProcessError from trezor.messages.PassphraseRequest import PassphraseRequest from trezor.messages.wire_types import PassphraseAck, Cancel ui.display.clear() pass_req = PassphraseRequest() if on_device: pass_req.on_device = True else: from trezor.ui.text import Text text = Text('Passphrase entry', ui.ICON_RESET, 'Please, type passphrase', 'on connected host.') text.render() ack = await ctx.call(pass_req, PassphraseAck, Cancel) if ack.MESSAGE_WIRE_TYPE == Cancel: raise wire.FailureError(ActionCancelled, 'Passphrase cancelled') if on_device: if ack.passphrase is not None: raise wire.FailureError( ProcessError, 'Passphrase provided when it should not be') from trezor.ui.passphrase import PassphraseKeyboard, CANCELLED passphrase = await PassphraseKeyboard('Enter passphrase') if passphrase == CANCELLED: raise wire.FailureError(ActionCancelled, 'Passphrase cancelled') else: if ack.passphrase is None: raise wire.FailureError(ProcessError, 'Passphrase not provided') passphrase = ack.passphrase # TODO: process ack.state and check against the current device state, throw error if different return passphrase
async def request_pin_ack(ctx, *args, **kwargs): # TODO: send PinMatrixRequest here, with specific code? await ctx.call(ButtonRequest(code=Other), wire_types.ButtonAck) try: return await request_pin(*args, **kwargs) except PinCancelled: raise wire.FailureError(FailureType.ActionCancelled, 'Cancelled')
async def layout_get_address(ctx, msg): from trezor.messages.Address import Address from trezor.messages.FailureType import ProcessError from ..common import coins from ..common import seed from ..wallet.sign_tx import addresses if msg.multisig: raise wire.FailureError(ProcessError, 'GetAddress.multisig is unsupported') 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) address = addresses.get_address(msg.script_type, coin, node) if msg.show_display: while True: if await _show_address(ctx, address): break if await _show_qr(ctx, address): break return Address(address=address)
async def apply_settings(ctx, msg): if msg.homescreen is None and msg.label is None and msg.use_passphrase is None: raise wire.FailureError(FailureType.ProcessError, 'No setting provided') if msg.homescreen is not None: await require_confirm(ctx, Text('Change homescreen', ui.ICON_CONFIG, 'Do you really want to', 'change homescreen?'), code=ButtonRequestType.ProtectCall) # TODO: split label (bold) and '?' (normal) once we support mixed styles on one line if msg.label is not None: await require_confirm(ctx, Text('Change label', ui.ICON_CONFIG, 'Do you really want to', 'change label to', ui.BOLD, '%s?' % msg.label), code=ButtonRequestType.ProtectCall) if msg.use_passphrase is not None: await require_confirm(ctx, Text( 'Enable passphrase' if msg.use_passphrase else 'Disable passphrase', ui.ICON_CONFIG, 'Do you really want to', 'enable passphrase' if msg.use_passphrase else 'disable passphrase', 'encryption?'), code=ButtonRequestType.ProtectCall) storage.load_settings(label=msg.label, use_passphrase=msg.use_passphrase, homescreen=msg.homescreen) return Success(message='Settings applied')
async def sign_tx(session_id, msg): from trezor.messages.RequestType import TXFINISHED from trezor.messages.wire_types import TxAck from apps.common import seed from . import signing from . import layout root = await seed.get_root(session_id) signer = signing.sign_tx(msg, root) res = None while True: try: req = signer.send(res) except signing.SigningError as e: raise wire.FailureError(*e.args) if req.__qualname__ == 'TxRequest': if req.request_type == TXFINISHED: break res = await wire.call(session_id, req, TxAck) elif req.__qualname__ == 'UiConfirmOutput': res = await layout.confirm_output(session_id, req.output, req.coin) elif req.__qualname__ == 'UiConfirmTotal': res = await layout.confirm_total(session_id, req.spending, req.fee, req.coin) elif req.__qualname__ == 'UiConfirmFeeOverThreshold': res = await layout.confirm_feeoverthreshold( session_id, req.fee, req.coin) else: raise TypeError('Invalid signing instruction') return req
async def request_pin_on_display(ctx: wire.Context, code: int=None) -> str: from trezor.messages.ButtonRequest import ButtonRequest from trezor.messages.ButtonRequestType import ProtectCall from trezor.messages.FailureType import PinCancelled from trezor.messages.wire_types import ButtonAck from trezor.ui.confirm import ConfirmDialog, CONFIRMED from trezor.ui.pin import PinMatrix if __debug__: global matrix _, label = _get_code_and_label(code) await ctx.call(ButtonRequest(code=ProtectCall), ButtonAck) ui.display.clear() matrix = PinMatrix(label) dialog = ConfirmDialog(matrix) pin = matrix.pin matrix = None if await dialog != CONFIRMED: raise wire.FailureError(PinCancelled, 'PIN cancelled') return pin
async def request_passphrase(ctx): on_device = await request_passphrase_entry(ctx) == DEVICE state, passphrase = await request_passphrase_ack(ctx, on_device) if state is not None: if state != get_state(salt=state[:32], passphrase=passphrase): raise wire.FailureError(ProcessError, 'Passphrase mismatch') return passphrase
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')
async def request_passphrase_on_display(ctx): from trezor.messages.FailureType import ActionCancelled from trezor.ui.passphrase import PassphraseKeyboard, CANCELLED ui.display.clear() passphrase = await PassphraseKeyboard('Enter passphrase') if passphrase == CANCELLED: raise wire.FailureError(ActionCancelled, 'Passphrase cancelled') return passphrase
async def protect_by_pin_or_fail(ctx: wire.Context, at_least_once: bool=False): from trezor.messages.FailureType import PinInvalid from . import storage locked = storage.is_locked() or at_least_once if locked: pin = await request_pin(ctx) if not storage.unlock(pin, _render_pin_failure): raise wire.FailureError(PinInvalid, 'PIN invalid')
async def recovery_device(ctx, msg): ''' Recover BIP39 seed into empty device. 1. Ask for the number of words in recovered seed. 2. Let user type in the mnemonic words one by one. 3. Optionally check the seed validity. 4. Optionally ask for the PIN, with confirmation. 5. Save into storage. ''' if not msg.dry_run and storage.is_initialized(): raise wire.FailureError(UnexpectedMessage, 'Already initialized') # ask for the number of words wordcount = await request_wordcount(ctx) # ask for mnemonic words one by one mnemonic = await request_mnemonic(ctx, wordcount) # check mnemonic validity if msg.enforce_wordlist or msg.dry_run: if not bip39.check(mnemonic): raise wire.FailureError(ProcessError, 'Mnemonic is not valid') # ask for pin repeatedly if msg.pin_protection: newpin = await request_pin_confirm(ctx, cancellable=False) # save into storage if not msg.dry_run: if msg.pin_protection: config.change_pin(pin_to_int(''), pin_to_int(newpin), None) storage.load_settings(label=msg.label, use_passphrase=msg.passphrase_protection) storage.load_mnemonic(mnemonic=mnemonic, needs_backup=False) return Success(message='Device recovered') else: if storage.get_mnemonic() == mnemonic: return Success( message='The seed is valid and matches the one in the device') else: raise wire.FailureError( ProcessError, 'The seed is valid but does not match the one in the device')
async def layout_apply_settings(session_id, msg): from trezor.messages.Success import Success from trezor.messages.FailureType import Other from trezor.ui.text import Text from ..common.confirm import require_confirm from ..common.request_pin import protect_by_pin from ..common import storage await protect_by_pin(session_id) if msg.homescreen is not None: raise wire.FailureError(Other, 'ApplySettings.homescreen is not supported') if msg.label is None and msg.language is None and msg.use_passphrase is None: raise wire.FailureError(Other, 'No setting provided') if msg.label is not None: await require_confirm( session_id, Text('Change label', ui.ICON_RESET, 'Do you really want to', 'change label to', ui.BOLD, '%s' % msg.label, ui.NORMAL, '?')) if msg.language is not None: await require_confirm( session_id, Text('Change language', ui.ICON_RESET, 'Do you really want to', 'change language to', ui.BOLD, '%s' % msg.language, ui.NORMAL, '?')) if msg.use_passphrase is not None: await require_confirm( session_id, Text( 'Enable passphrase' if msg.use_passphrase else 'Disable passphrase', ui.ICON_RESET, 'Do you really want to', 'enable passphrase' if msg.use_passphrase else 'disable passphrase', 'encryption?')) storage.load_settings(label=msg.label, language=msg.language, passphrase_protection=msg.use_passphrase) return Success(message='Settings applied')
async def compute_seed(ctx: wire.Context) -> bytes: 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') passphrase = await protect_by_passphrase(ctx) return bip39.seed(storage.get_mnemonic(), passphrase)
async def verify_message(ctx, msg): message = msg.message address = msg.address signature = msg.signature coin_name = msg.coin_name or 'Bitcoin' coin = coins.by_name(coin_name) digest = message_digest(coin, message) script_type = None recid = signature[0] if recid >= 27 and recid <= 34: script_type = SPENDADDRESS # p2pkh elif recid >= 35 and recid <= 38: script_type = SPENDP2SHWITNESS # segwit-in-p2sh signature = bytes([signature[0] - 4]) + signature[1:] elif recid >= 39 and recid <= 42: script_type = SPENDWITNESS # native segwit signature = bytes([signature[0] - 8]) + signature[1:] else: raise wire.FailureError(ProcessError, 'Invalid signature') pubkey = secp256k1.verify_recover(signature, digest) if not pubkey: raise wire.FailureError(ProcessError, 'Invalid signature') if script_type == SPENDADDRESS: addr = address_pkh(pubkey, coin.address_type) elif script_type == SPENDP2SHWITNESS: addr = address_p2wpkh_in_p2sh(pubkey, coin.address_type_p2sh) elif script_type == SPENDWITNESS: addr = address_p2wpkh(pubkey, coin.bech32_prefix) else: raise wire.FailureError(ProcessError, 'Invalid signature') if addr != address: raise wire.FailureError(ProcessError, 'Invalid signature') await require_confirm_verify_message(ctx, address, message) return Success(message='Message verified')
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') mnemonic = storage.get_mnemonic() storage.set_backed_up() # warn user about mnemonic safety await show_warning(ctx) while True: # show mnemonic and require confirmation of a random word await show_mnemonic(ctx, mnemonic) if await check_mnemonic(ctx, mnemonic): break await show_wrong_entry(ctx) return Success(message='Seed successfully backed up')
async def request_pin_twice(ctx: wire.Context) -> str: from trezor.messages.FailureType import ActionCancelled from trezor.messages import PinMatrixRequestType pin_first = await request_pin(ctx, PinMatrixRequestType.NewFirst) pin_again = await request_pin(ctx, PinMatrixRequestType.NewSecond) if pin_first != pin_again: # changed message due to consistency with T1 msgs raise wire.FailureError(ActionCancelled, 'PIN change failed') return pin_first
async def request_passphrase_entry(ctx): text = Text('Enter passphrase', ui.ICON_CONFIG, 'Where to enter your', 'passphrase?') text.render() ack = await ctx.call(ButtonRequest(code=ButtonRequestType.PassphraseType), wire_types.ButtonAck, wire_types.Cancel) if ack.MESSAGE_WIRE_TYPE == wire_types.Cancel: raise wire.FailureError(ActionCancelled, 'Passphrase cancelled') selector = EntrySelector(text) return await ctx.wait(selector)
async def compute_seed(session_id: int) -> bytes: from trezor.messages.FailureType import Other from .request_passphrase import protect_by_passphrase from .request_pin import protect_by_pin from . import storage if not storage.is_initialized(): raise wire.FailureError(Other, 'Device is not initialized') await protect_by_pin(session_id) passphrase = await protect_by_passphrase(session_id) return bip39.seed(storage.get_mnemonic(), passphrase)
async def sign_tx(ctx, msg): from apps.wallet.sign_tx import layout, progress, signing # TODO: rework this so we don't have to pass root to signing.sign_tx root = await seed.derive_node(ctx, []) signer = signing.sign_tx(msg, root) res = None while True: try: req = signer.send(res) except signing.SigningError as e: raise wire.FailureError(*e.args) except signing.MultisigError as e: raise wire.FailureError(*e.args) except signing.AddressError as e: raise wire.FailureError(*e.args) except signing.ScriptsError as e: raise wire.FailureError(*e.args) except signing.Bip143Error as e: raise wire.FailureError(*e.args) if req.__qualname__ == 'TxRequest': if req.request_type == TXFINISHED: break res = await ctx.call(req, TxAck) elif req.__qualname__ == 'UiConfirmOutput': res = await layout.confirm_output(ctx, req.output, req.coin) progress.report_init() elif req.__qualname__ == 'UiConfirmTotal': res = await layout.confirm_total(ctx, req.spending, req.fee, req.coin) progress.report_init() elif req.__qualname__ == 'UiConfirmFeeOverThreshold': res = await layout.confirm_feeoverthreshold(ctx, req.fee, req.coin) progress.report_init() else: raise TypeError('Invalid signing instruction') return req
async def recovery_device(ctx, msg): ''' Recover BIP39 seed into empty device. 1. Ask for the number of words in recovered seed. 2. Let user type in the mnemonic words one by one. 3. Optionally check the seed validity. 4. Optionally ask for the PIN, with confirmation. 5. Save into storage. ''' from trezor import config from trezor.crypto import bip39 from trezor.messages.FailureType import UnexpectedMessage, ProcessError from trezor.messages.Success import Success from trezor.ui.text import Text from apps.common import storage from apps.common.request_pin import request_pin from apps.common.request_words import request_words if storage.is_initialized(): raise wire.FailureError(UnexpectedMessage, 'Already initialized') wordcount = await request_words( ctx, Text('Device recovery', ui.ICON_RECOVERY, 'Number of words?')) mnemonic = await request_mnemonic(wordcount, 'Type %s. word') if msg.enforce_wordlist and not bip39.check(mnemonic): raise wire.FailureError(ProcessError, 'Mnemonic is not valid') if msg.pin_protection: curpin = '' newpin = await request_pin(ctx) config.change_pin(curpin, newpin) storage.load_settings(label=msg.label, use_passphrase=msg.passphrase_protection) storage.load_mnemonic(mnemonic) return Success()
async def verify_message(ctx, msg): message = msg.message address = msg.address signature = msg.signature coin_name = msg.coin_name or 'Bitcoin' coin = coins.by_name(coin_name) await confirm_verify_message(ctx, message) digest = message_digest(coin, message) pubkey = secp256k1.verify_recover(signature, digest) if not pubkey: raise wire.FailureError(ProcessError, 'Invalid signature') raw_address = base58.decode_check(address) _, pkh = address_type.split(coin, raw_address) pkh2 = ripemd160(sha256(pubkey).digest()).digest() if pkh != pkh2: raise wire.FailureError(ProcessError, 'Invalid signature') return Success(message='Message verified')
async def set_u2f_counter(ctx, msg): if msg.u2f_counter is None: raise wire.FailureError(FailureType.ProcessError, 'No value provided provided') await require_confirm(ctx, Text('Set U2F counter', ui.ICON_CONFIG, 'Do you really want to', 'set the U2F counter', ui.BOLD, 'to %d?' % msg.u2f_counter), code=ButtonRequestType.ProtectCall) storage.set_u2f_counter(msg.u2f_counter) return Success(message='U2F counter set')