mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-26 01:18:28 +00:00
Merge pull request #675 from trezor/ciny/shamir_click_tests
tests: click tests for basic and advanced slip39
This commit is contained in:
commit
e30245b96b
@ -21,8 +21,14 @@ INFO = (MID, BOTTOM)
|
||||
|
||||
CONFIRM_WORD = (MID, TOP)
|
||||
|
||||
MINUS = (LEFT, grid(DISPLAY_HEIGHT, 5, 2))
|
||||
PLUS = (RIGHT, grid(DISPLAY_HEIGHT, 5, 2))
|
||||
RESET_MINUS = (LEFT, grid(DISPLAY_HEIGHT, 5, 1))
|
||||
RESET_PLUS = (RIGHT, grid(DISPLAY_HEIGHT, 5, 1))
|
||||
|
||||
RESET_WORD_CHECK = [
|
||||
(MID, grid(DISPLAY_HEIGHT, 6, 3)),
|
||||
(MID, grid(DISPLAY_HEIGHT, 6, 4)),
|
||||
(MID, grid(DISPLAY_HEIGHT, 6, 5)),
|
||||
]
|
||||
|
||||
|
||||
BUTTON_LETTERS = ("ab", "cd", "ef", "ghij", "klm", "nopq", "rs", "tuv", "wxyz")
|
||||
|
71
tests/click_tests/reset.py
Normal file
71
tests/click_tests/reset.py
Normal file
@ -0,0 +1,71 @@
|
||||
import shamir_mnemonic as shamir
|
||||
|
||||
from trezorlib import messages
|
||||
|
||||
from .. import buttons
|
||||
|
||||
|
||||
def confirm_wait(debug, startswith):
|
||||
layout = debug.wait_layout()
|
||||
assert layout.text.startswith(startswith)
|
||||
debug.click(buttons.OK, wait=True)
|
||||
|
||||
|
||||
def confirm_read(debug, startswith):
|
||||
layout = debug.read_layout()
|
||||
assert layout.text.startswith(startswith)
|
||||
debug.click(buttons.OK, wait=True)
|
||||
|
||||
|
||||
def set_selection(debug, button, diff):
|
||||
layout = debug.read_layout()
|
||||
assert layout.text.startswith("Slip39NumInput")
|
||||
for _ in range(diff):
|
||||
debug.click(button, wait=False)
|
||||
debug.click(buttons.OK, wait=True)
|
||||
|
||||
|
||||
def read_words(debug, is_advanced=False):
|
||||
words = []
|
||||
layout = debug.read_layout()
|
||||
if is_advanced:
|
||||
assert layout.text.startswith("Group")
|
||||
else:
|
||||
assert layout.text.startswith("Recovery share")
|
||||
for i in range(6):
|
||||
lines = debug.read_layout().lines
|
||||
if i == 0:
|
||||
words.append(lines[3].split()[1])
|
||||
words.append(lines[4].split()[1])
|
||||
debug.input(swipe=messages.DebugSwipeDirection.UP, wait=True)
|
||||
elif i == 5:
|
||||
words.append(lines[1].split()[1])
|
||||
words.append(lines[2].split()[1])
|
||||
else:
|
||||
words.append(lines[1].split()[1])
|
||||
words.append(lines[2].split()[1])
|
||||
words.append(lines[3].split()[1])
|
||||
words.append(lines[4].split()[1])
|
||||
debug.input(swipe=messages.DebugSwipeDirection.UP, wait=True)
|
||||
debug.press_yes()
|
||||
|
||||
return words
|
||||
|
||||
|
||||
def confirm_words(debug, words):
|
||||
# confirm words
|
||||
layout = debug.wait_layout()
|
||||
layout.text.startswith("Check share")
|
||||
for _ in range(3):
|
||||
word_pos = int(debug.state().layout_lines[1].split()[2])
|
||||
button_pos = debug.state().layout_lines.index(words[word_pos - 1]) - 2
|
||||
debug.click(buttons.RESET_WORD_CHECK[button_pos], wait=True)
|
||||
|
||||
|
||||
def validate_mnemonics(mnemonics, expected_ems):
|
||||
# We expect these combinations to recreate the secret properly
|
||||
# In case of click tests the mnemonics are always XofX so no need for combinations
|
||||
ms = shamir.combine_mnemonics(mnemonics)
|
||||
identifier, iteration_exponent, _, _, _ = shamir._decode_mnemonics(mnemonics)
|
||||
ems = shamir._encrypt(ms, b"", iteration_exponent, identifier)
|
||||
assert ems == expected_ems
|
193
tests/click_tests/test_reset_slip39_advanced.py
Normal file
193
tests/click_tests/test_reset_slip39_advanced.py
Normal file
@ -0,0 +1,193 @@
|
||||
# This file is part of the Trezor project.
|
||||
#
|
||||
# Copyright (C) 2012-2019 SatoshiLabs and contributors
|
||||
#
|
||||
# This library is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License version 3
|
||||
# as published by the Free Software Foundation.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the License along with this library.
|
||||
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from trezorlib import device, messages
|
||||
|
||||
from .. import buttons
|
||||
from ..common import generate_entropy
|
||||
from . import reset
|
||||
|
||||
EXTERNAL_ENTROPY = b"zlutoucky kun upel divoke ody" * 2
|
||||
|
||||
|
||||
@pytest.mark.skip_t1
|
||||
@pytest.mark.setup_client(uninitialized=True)
|
||||
def test_reset_slip39_advanced_2of2groups_2of2shares(device_handler):
|
||||
features = device_handler.features()
|
||||
debug = device_handler.debuglink()
|
||||
|
||||
assert features.initialized is False
|
||||
|
||||
os_urandom = mock.Mock(return_value=EXTERNAL_ENTROPY)
|
||||
with mock.patch("os.urandom", os_urandom), device_handler:
|
||||
device_handler.run(
|
||||
device.reset,
|
||||
strength=128,
|
||||
backup_type=messages.BackupType.Slip39_Advanced,
|
||||
pin_protection=False,
|
||||
)
|
||||
|
||||
# confirm new wallet
|
||||
reset.confirm_wait(debug, "Create new wallet")
|
||||
|
||||
# confirm back up
|
||||
reset.confirm_wait(debug, "Success")
|
||||
|
||||
# confirm checklist
|
||||
reset.confirm_read(debug, "Checklist")
|
||||
|
||||
# set num of groups
|
||||
reset.set_selection(debug, buttons.RESET_MINUS, 3)
|
||||
|
||||
# confirm checklist
|
||||
reset.confirm_read(debug, "Checklist")
|
||||
|
||||
# set group threshold
|
||||
reset.set_selection(debug, buttons.RESET_MINUS, 0)
|
||||
|
||||
# confirm checklist
|
||||
reset.confirm_read(debug, "Checklist")
|
||||
|
||||
# set share num and threshold for groups
|
||||
for _ in range(2):
|
||||
# set num of shares
|
||||
reset.set_selection(debug, buttons.RESET_MINUS, 3)
|
||||
|
||||
# set share threshold
|
||||
reset.set_selection(debug, buttons.RESET_MINUS, 0)
|
||||
|
||||
# confirm backup warning
|
||||
reset.confirm_read(debug, "Caution")
|
||||
|
||||
all_words = []
|
||||
for _ in range(2):
|
||||
for _ in range(2):
|
||||
# read words
|
||||
words = reset.read_words(debug, True)
|
||||
|
||||
# confirm words
|
||||
reset.confirm_words(debug, words)
|
||||
|
||||
# confirm share checked
|
||||
reset.confirm_read(debug, "Success")
|
||||
|
||||
all_words.append(" ".join(words))
|
||||
|
||||
# confirm backup done
|
||||
reset.confirm_read(debug, "Success")
|
||||
|
||||
# generate secret locally
|
||||
internal_entropy = debug.state().reset_entropy
|
||||
secret = generate_entropy(128, internal_entropy, EXTERNAL_ENTROPY)
|
||||
|
||||
# validate that all combinations will result in the correct master secret
|
||||
reset.validate_mnemonics(all_words, secret)
|
||||
|
||||
assert device_handler.result() == "Initialized"
|
||||
|
||||
features = device_handler.features()
|
||||
assert features.initialized is True
|
||||
assert features.needs_backup is False
|
||||
assert features.pin_protection is False
|
||||
assert features.passphrase_protection is False
|
||||
assert features.backup_type is messages.BackupType.Slip39_Advanced
|
||||
|
||||
|
||||
@pytest.mark.skip_t1
|
||||
@pytest.mark.setup_client(uninitialized=True)
|
||||
def test_reset_slip39_advanced_16of16groups_16of16shares(device_handler):
|
||||
features = device_handler.features()
|
||||
debug = device_handler.debuglink()
|
||||
|
||||
assert features.initialized is False
|
||||
|
||||
os_urandom = mock.Mock(return_value=EXTERNAL_ENTROPY)
|
||||
with mock.patch("os.urandom", os_urandom), device_handler:
|
||||
device_handler.run(
|
||||
device.reset,
|
||||
strength=128,
|
||||
backup_type=messages.BackupType.Slip39_Advanced,
|
||||
pin_protection=False,
|
||||
)
|
||||
|
||||
# confirm new wallet
|
||||
reset.confirm_wait(debug, "Create new wallet")
|
||||
|
||||
# confirm back up
|
||||
reset.confirm_wait(debug, "Success")
|
||||
|
||||
# confirm checklist
|
||||
reset.confirm_read(debug, "Checklist")
|
||||
|
||||
# set num of groups
|
||||
reset.set_selection(debug, buttons.RESET_PLUS, 11)
|
||||
|
||||
# confirm checklist
|
||||
reset.confirm_read(debug, "Checklist")
|
||||
|
||||
# set group threshold
|
||||
reset.set_selection(debug, buttons.RESET_PLUS, 11)
|
||||
|
||||
# confirm checklist
|
||||
reset.confirm_read(debug, "Checklist")
|
||||
|
||||
# set share num and threshold for groups
|
||||
for _ in range(16):
|
||||
# set num of shares
|
||||
reset.set_selection(debug, buttons.RESET_PLUS, 11)
|
||||
|
||||
# set share threshold
|
||||
reset.set_selection(debug, buttons.RESET_PLUS, 11)
|
||||
|
||||
# confirm backup warning
|
||||
reset.confirm_read(debug, "Caution")
|
||||
|
||||
all_words = []
|
||||
for _ in range(16):
|
||||
for _ in range(16):
|
||||
# read words
|
||||
words = reset.read_words(debug, True)
|
||||
|
||||
# confirm words
|
||||
reset.confirm_words(debug, words)
|
||||
|
||||
# confirm share checked
|
||||
reset.confirm_read(debug, "Success")
|
||||
|
||||
all_words.append(" ".join(words))
|
||||
|
||||
# confirm backup done
|
||||
reset.confirm_read(debug, "Success")
|
||||
|
||||
# generate secret locally
|
||||
internal_entropy = debug.state().reset_entropy
|
||||
secret = generate_entropy(128, internal_entropy, EXTERNAL_ENTROPY)
|
||||
|
||||
# validate that all combinations will result in the correct master secret
|
||||
reset.validate_mnemonics(all_words, secret)
|
||||
|
||||
assert device_handler.result() == "Initialized"
|
||||
|
||||
features = device_handler.features()
|
||||
assert features.initialized is True
|
||||
assert features.needs_backup is False
|
||||
assert features.pin_protection is False
|
||||
assert features.passphrase_protection is False
|
||||
assert features.backup_type is messages.BackupType.Slip39_Advanced
|
174
tests/click_tests/test_reset_slip39_basic.py
Normal file
174
tests/click_tests/test_reset_slip39_basic.py
Normal file
@ -0,0 +1,174 @@
|
||||
# This file is part of the Trezor project.
|
||||
#
|
||||
# Copyright (C) 2012-2019 SatoshiLabs and contributors
|
||||
#
|
||||
# This library is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License version 3
|
||||
# as published by the Free Software Foundation.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the License along with this library.
|
||||
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from trezorlib import device, messages
|
||||
|
||||
from .. import buttons
|
||||
from ..common import generate_entropy
|
||||
from . import reset
|
||||
|
||||
EXTERNAL_ENTROPY = b"zlutoucky kun upel divoke ody" * 2
|
||||
|
||||
|
||||
@pytest.mark.skip_t1
|
||||
@pytest.mark.setup_client(uninitialized=True)
|
||||
def test_reset_slip39_basic_1of1(device_handler):
|
||||
features = device_handler.features()
|
||||
debug = device_handler.debuglink()
|
||||
|
||||
assert features.initialized is False
|
||||
|
||||
os_urandom = mock.Mock(return_value=EXTERNAL_ENTROPY)
|
||||
with mock.patch("os.urandom", os_urandom), device_handler:
|
||||
device_handler.run(
|
||||
device.reset,
|
||||
strength=128,
|
||||
backup_type=messages.BackupType.Slip39_Basic,
|
||||
pin_protection=False,
|
||||
)
|
||||
|
||||
# confirm new wallet
|
||||
reset.confirm_wait(debug, "Create new wallet")
|
||||
|
||||
# confirm back up
|
||||
reset.confirm_wait(debug, "Success")
|
||||
|
||||
# confirm checklist
|
||||
reset.confirm_read(debug, "Checklist")
|
||||
|
||||
# set num of shares
|
||||
# default is 5 so we press RESET_MINUS 4 times
|
||||
reset.set_selection(debug, buttons.RESET_MINUS, 4)
|
||||
|
||||
# confirm checklist
|
||||
reset.confirm_read(debug, "Checklist")
|
||||
|
||||
# set threshold
|
||||
# threshold will default to 1
|
||||
reset.set_selection(debug, buttons.RESET_MINUS, 0)
|
||||
|
||||
# confirm checklist
|
||||
reset.confirm_read(debug, "Checklist")
|
||||
|
||||
# confirm backup warning
|
||||
reset.confirm_read(debug, "Caution")
|
||||
|
||||
# read words
|
||||
words = reset.read_words(debug)
|
||||
|
||||
# confirm words
|
||||
reset.confirm_words(debug, words)
|
||||
|
||||
# confirm share checked
|
||||
reset.confirm_read(debug, "Success")
|
||||
|
||||
# confirm backup done
|
||||
reset.confirm_read(debug, "Success")
|
||||
|
||||
# generate secret locally
|
||||
internal_entropy = debug.state().reset_entropy
|
||||
secret = generate_entropy(128, internal_entropy, EXTERNAL_ENTROPY)
|
||||
|
||||
# validate that all combinations will result in the correct master secret
|
||||
validate = [" ".join(words)]
|
||||
reset.validate_mnemonics(validate, secret)
|
||||
|
||||
assert device_handler.result() == "Initialized"
|
||||
features = device_handler.features()
|
||||
assert features.initialized is True
|
||||
assert features.needs_backup is False
|
||||
assert features.pin_protection is False
|
||||
assert features.passphrase_protection is False
|
||||
assert features.backup_type is messages.BackupType.Slip39_Basic
|
||||
|
||||
|
||||
@pytest.mark.skip_t1
|
||||
@pytest.mark.setup_client(uninitialized=True)
|
||||
def test_reset_slip39_basic_16of16(device_handler):
|
||||
features = device_handler.features()
|
||||
debug = device_handler.debuglink()
|
||||
|
||||
assert features.initialized is False
|
||||
|
||||
os_urandom = mock.Mock(return_value=EXTERNAL_ENTROPY)
|
||||
with mock.patch("os.urandom", os_urandom), device_handler:
|
||||
device_handler.run(
|
||||
device.reset,
|
||||
strength=128,
|
||||
backup_type=messages.BackupType.Slip39_Basic,
|
||||
pin_protection=False,
|
||||
)
|
||||
|
||||
# confirm new wallet
|
||||
reset.confirm_wait(debug, "Create new wallet")
|
||||
|
||||
# confirm back up
|
||||
reset.confirm_wait(debug, "Success")
|
||||
|
||||
# confirm checklist
|
||||
reset.confirm_read(debug, "Checklist")
|
||||
|
||||
# set num of shares
|
||||
# default is 5 so we add 11
|
||||
reset.set_selection(debug, buttons.RESET_PLUS, 11)
|
||||
|
||||
# confirm checklist
|
||||
reset.confirm_read(debug, "Checklist")
|
||||
|
||||
# set threshold
|
||||
# default is 5 so we add 11
|
||||
reset.set_selection(debug, buttons.RESET_PLUS, 11)
|
||||
|
||||
# confirm checklist
|
||||
reset.confirm_read(debug, "Checklist")
|
||||
|
||||
# confirm backup warning
|
||||
reset.confirm_read(debug, "Caution")
|
||||
|
||||
all_words = []
|
||||
for _ in range(16):
|
||||
# read words
|
||||
words = reset.read_words(debug)
|
||||
|
||||
# confirm words
|
||||
reset.confirm_words(debug, words)
|
||||
|
||||
# confirm share checked
|
||||
reset.confirm_read(debug, "Success")
|
||||
|
||||
all_words.append(" ".join(words))
|
||||
|
||||
# confirm backup done
|
||||
reset.confirm_read(debug, "Success")
|
||||
|
||||
# generate secret locally
|
||||
internal_entropy = debug.state().reset_entropy
|
||||
secret = generate_entropy(128, internal_entropy, EXTERNAL_ENTROPY)
|
||||
|
||||
# validate that all combinations will result in the correct master secret
|
||||
reset.validate_mnemonics(all_words, secret)
|
||||
|
||||
assert device_handler.result() == "Initialized"
|
||||
features = device_handler.features()
|
||||
assert features.initialized is True
|
||||
assert features.needs_backup is False
|
||||
assert features.pin_protection is False
|
||||
assert features.passphrase_protection is False
|
||||
assert features.backup_type is messages.BackupType.Slip39_Basic
|
Loading…
Reference in New Issue
Block a user