2016-08-05 10:37:26 +00:00
|
|
|
from trezor import wire, ui
|
2016-09-21 12:24:12 +00:00
|
|
|
from trezor.messages.wire_types import EntropyAck
|
2016-06-09 17:01:43 +00:00
|
|
|
from trezor.ui.button import Button, CONFIRM_BUTTON, CONFIRM_BUTTON_ACTIVE
|
2016-08-05 10:37:26 +00:00
|
|
|
from trezor.ui.scroll import paginate, render_scrollbar, animate_swipe
|
2016-06-09 14:28:34 +00:00
|
|
|
from trezor.crypto import hashlib, random, bip39
|
2016-09-21 12:24:12 +00:00
|
|
|
from trezor.utils import unimport, chunks
|
2016-06-09 14:28:34 +00:00
|
|
|
|
|
|
|
|
2016-09-21 12:24:12 +00:00
|
|
|
async def generate_mnemonic(strength, display_random, session_id):
|
2016-06-09 14:28:34 +00:00
|
|
|
from trezor.messages.EntropyRequest import EntropyRequest
|
|
|
|
|
2016-09-21 12:24:12 +00:00
|
|
|
await wire.write_message(session_id, EntropyRequest())
|
|
|
|
ack = await wire.read_message(session_id, EntropyAck)
|
2016-06-09 14:28:34 +00:00
|
|
|
|
|
|
|
ctx = hashlib.sha256()
|
|
|
|
ctx.update(random.bytes(32))
|
|
|
|
ctx.update(ack.entropy)
|
|
|
|
entropy = ctx.digest()
|
|
|
|
|
|
|
|
# TODO: handle strength
|
|
|
|
# TODO: handle display_random
|
|
|
|
|
|
|
|
return bip39.from_data(entropy)
|
|
|
|
|
|
|
|
|
2016-09-21 12:24:12 +00:00
|
|
|
async def request_new_pin():
|
2016-06-17 18:52:36 +00:00
|
|
|
from trezor.workflows.request_pin import request_pin
|
2016-06-09 14:28:34 +00:00
|
|
|
|
2016-09-21 12:24:12 +00:00
|
|
|
pin = await request_pin()
|
|
|
|
pin_again = await request_pin('Enter PIN again')
|
2016-06-09 14:28:34 +00:00
|
|
|
|
|
|
|
if pin == pin_again:
|
|
|
|
return pin
|
|
|
|
else:
|
|
|
|
raise Exception() # TODO: wrong PIN should be handled in unified way
|
|
|
|
|
|
|
|
|
2016-09-21 12:24:12 +00:00
|
|
|
async def show_mnemonic(mnemonic):
|
2016-06-09 14:28:34 +00:00
|
|
|
words_per_page = const(4)
|
2016-06-17 18:52:36 +00:00
|
|
|
mnemonic_words = list(enumerate(mnemonic.split()))
|
|
|
|
mnemonic_pages = list(chunks(mnemonic_words, words_per_page))
|
|
|
|
|
2016-09-21 12:24:12 +00:00
|
|
|
async def render(page, page_count):
|
2016-06-09 14:28:34 +00:00
|
|
|
|
2016-09-21 12:24:12 +00:00
|
|
|
# render header & scrollbar
|
2016-06-09 14:28:34 +00:00
|
|
|
ui.clear()
|
2016-09-21 12:24:12 +00:00
|
|
|
ui.display.text(10, 30, 'Write down your seed',
|
|
|
|
ui.BOLD, ui.LIGHT_GREEN, ui.BLACK)
|
2016-06-17 18:52:36 +00:00
|
|
|
render_scrollbar(page, page_count)
|
2016-06-10 13:35:22 +00:00
|
|
|
|
2016-09-21 12:24:12 +00:00
|
|
|
# render mnemonic page
|
2016-06-17 18:52:36 +00:00
|
|
|
for pi, (wi, word) in enumerate(mnemonic_pages[page]):
|
|
|
|
top = pi * 30 + 74
|
|
|
|
pos = wi + 1
|
2016-09-21 12:24:12 +00:00
|
|
|
ui.display.text_right(40, top, '%d.' %
|
|
|
|
pos, ui.BOLD, ui.LIGHT_GREEN, ui.BLACK)
|
2016-06-09 16:31:48 +00:00
|
|
|
ui.display.text(45, top, '%s' % word, ui.BOLD, ui.WHITE, ui.BLACK)
|
2016-06-10 13:35:22 +00:00
|
|
|
|
2016-06-17 18:52:36 +00:00
|
|
|
if page + 1 == page_count:
|
2016-09-21 12:24:12 +00:00
|
|
|
# wait for the finish button
|
2016-06-17 18:52:36 +00:00
|
|
|
finish = Button((0, 240 - 48, 240, 48), 'Finish',
|
|
|
|
normal_style=CONFIRM_BUTTON,
|
|
|
|
active_style=CONFIRM_BUTTON_ACTIVE)
|
2016-09-21 12:24:12 +00:00
|
|
|
await finish.wait()
|
2016-06-17 18:52:36 +00:00
|
|
|
else:
|
2016-09-21 12:24:12 +00:00
|
|
|
await animate_swipe()
|
2016-06-17 18:52:36 +00:00
|
|
|
|
2016-09-21 12:24:12 +00:00
|
|
|
await paginate(render, len(mnemonic_pages))
|
2016-06-17 18:52:36 +00:00
|
|
|
|
|
|
|
|
2016-09-21 12:24:12 +00:00
|
|
|
async def layout_reset_device(message, session_id):
|
2016-06-17 18:52:36 +00:00
|
|
|
# TODO: Failure if not empty
|
|
|
|
|
2016-09-21 12:24:12 +00:00
|
|
|
mnemonic = await generate_mnemonic(
|
|
|
|
message.strength, message.display_random, session_id)
|
2016-06-17 18:52:36 +00:00
|
|
|
|
|
|
|
# if m.pin_protection:
|
|
|
|
# pin = yield from request_new_pin()
|
|
|
|
# else:
|
|
|
|
# pin = None
|
|
|
|
|
2016-09-21 12:24:12 +00:00
|
|
|
await show_mnemonic(mnemonic)
|