diff --git a/tests/device_tests/test_msg_resetdevice_bip39.py b/tests/device_tests/test_msg_resetdevice_bip39.py index eab5c0d34d..7f2d3c932f 100644 --- a/tests/device_tests/test_msg_resetdevice_bip39.py +++ b/tests/device_tests/test_msg_resetdevice_bip39.py @@ -22,79 +22,86 @@ from trezorlib import device, messages as proto from ..common import generate_entropy +def reset_device(client, strength): + # No PIN, no passphrase + external_entropy = b"zlutoucky kun upel divoke ody" * 2 + + ret = client.call_raw( + proto.ResetDevice( + display_random=False, + strength=strength, + passphrase_protection=False, + pin_protection=False, + language="en-US", + label="test", + ) + ) + + assert isinstance(ret, proto.ButtonRequest) + client.debug.press_yes() + ret = client.call_raw(proto.ButtonAck()) + + # Provide entropy + assert isinstance(ret, proto.EntropyRequest) + internal_entropy = client.debug.read_reset_entropy() + ret = client.call_raw(proto.EntropyAck(entropy=external_entropy)) + + # Generate mnemonic locally + entropy = generate_entropy(strength, internal_entropy, external_entropy) + expected_mnemonic = Mnemonic("english").to_mnemonic(entropy) + + mnemonic = [] + for _ in range(strength // 32 * 3): + assert isinstance(ret, proto.ButtonRequest) + mnemonic.append(client.debug.read_reset_word()) + client.debug.press_yes() + client.call_raw(proto.ButtonAck()) + + mnemonic = " ".join(mnemonic) + + # Compare that device generated proper mnemonic for given entropies + assert mnemonic == expected_mnemonic + + mnemonic = [] + for _ in range(strength // 32 * 3): + assert isinstance(ret, proto.ButtonRequest) + mnemonic.append(client.debug.read_reset_word()) + client.debug.press_yes() + resp = client.call_raw(proto.ButtonAck()) + + assert isinstance(resp, proto.Success) + + mnemonic = " ".join(mnemonic) + + # Compare that second pass printed out the same mnemonic once again + assert mnemonic == expected_mnemonic + + # Check if device is properly initialized + resp = client.call_raw(proto.Initialize()) + assert resp.initialized is True + assert resp.needs_backup is False + assert resp.pin_protection is False + assert resp.passphrase_protection is False + + # Do pin & passphrase-protected action, PassphraseRequest should NOT be raised + resp = client.call_raw(proto.GetAddress()) + assert isinstance(resp, proto.Address) + + @pytest.mark.skip_t2 class TestMsgResetDevice: @pytest.mark.setup_client(uninitialized=True) - def test_reset_device(self, client): - # No PIN, no passphrase - external_entropy = b"zlutoucky kun upel divoke ody" * 2 - strength = 128 - - ret = client.call_raw( - proto.ResetDevice( - display_random=False, - strength=strength, - passphrase_protection=False, - pin_protection=False, - language="en-US", - label="test", - ) - ) - - assert isinstance(ret, proto.ButtonRequest) - client.debug.press_yes() - ret = client.call_raw(proto.ButtonAck()) - - # Provide entropy - assert isinstance(ret, proto.EntropyRequest) - internal_entropy = client.debug.read_reset_entropy() - ret = client.call_raw(proto.EntropyAck(entropy=external_entropy)) - - # Generate mnemonic locally - entropy = generate_entropy(strength, internal_entropy, external_entropy) - expected_mnemonic = Mnemonic("english").to_mnemonic(entropy) - - mnemonic = [] - for _ in range(strength // 32 * 3): - assert isinstance(ret, proto.ButtonRequest) - mnemonic.append(client.debug.read_reset_word()) - client.debug.press_yes() - client.call_raw(proto.ButtonAck()) - - mnemonic = " ".join(mnemonic) - - # Compare that device generated proper mnemonic for given entropies - assert mnemonic == expected_mnemonic - - mnemonic = [] - for _ in range(strength // 32 * 3): - assert isinstance(ret, proto.ButtonRequest) - mnemonic.append(client.debug.read_reset_word()) - client.debug.press_yes() - resp = client.call_raw(proto.ButtonAck()) - - assert isinstance(resp, proto.Success) - - mnemonic = " ".join(mnemonic) - - # Compare that second pass printed out the same mnemonic once again - assert mnemonic == expected_mnemonic - - # Check if device is properly initialized - resp = client.call_raw(proto.Initialize()) - assert resp.initialized is True - assert resp.needs_backup is False - assert resp.pin_protection is False - assert resp.passphrase_protection is False - - # Do pin & passphrase-protected action, PassphraseRequest should NOT be raised - resp = client.call_raw(proto.GetAddress()) - assert isinstance(resp, proto.Address) + def test_reset_device_128(self, client): + reset_device(client, 128) @pytest.mark.setup_client(uninitialized=True) - def test_reset_device_pin(self, client): + def test_reset_device_192(self, client): + reset_device(client, 192) + + @pytest.mark.setup_client(uninitialized=True) + def test_reset_device_256_pin(self, client): external_entropy = b"zlutoucky kun upel divoke ody" * 2 - strength = 128 + strength = 256 ret = client.call_raw( proto.ResetDevice( diff --git a/tests/device_tests/test_msg_resetdevice_bip39_t2.py b/tests/device_tests/test_msg_resetdevice_bip39_t2.py index f44853de8f..5eb192ede2 100644 --- a/tests/device_tests/test_msg_resetdevice_bip39_t2.py +++ b/tests/device_tests/test_msg_resetdevice_bip39_t2.py @@ -31,89 +31,98 @@ from ..common import ( ) EXTERNAL_ENTROPY = b"zlutoucky kun upel divoke ody" * 2 +STRENGTH_TO_WORDS = {128: 12, 192: 18, 256: 24} + + +def reset_device(client, strength): + words = STRENGTH_TO_WORDS[strength] + mnemonic = None + + def input_flow(): + nonlocal mnemonic + # 1. Confirm Reset + # 2. Backup your seed + # 3. Confirm warning + yield from click_through(client.debug, screens=3, code=B.ResetDevice) + + # mnemonic phrases + btn_code = yield + assert btn_code == B.ResetDevice + mnemonic = read_and_confirm_mnemonic(client.debug, words=words) + + # confirm recovery seed check + btn_code = yield + assert btn_code == B.Success + client.debug.press_yes() + + # confirm success + btn_code = yield + assert btn_code == B.Success + client.debug.press_yes() + + os_urandom = mock.Mock(return_value=EXTERNAL_ENTROPY) + with mock.patch("os.urandom", os_urandom), client: + client.set_expected_responses( + [ + proto.ButtonRequest(code=B.ResetDevice), + proto.EntropyRequest(), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.Success), + proto.ButtonRequest(code=B.Success), + proto.Success(), + proto.Features(), + ] + ) + client.set_input_flow(input_flow) + + # No PIN, no passphrase, don't display random + device.reset( + client, + display_random=False, + strength=strength, + passphrase_protection=False, + pin_protection=False, + label="test", + language="en-US", + ) + + # generate mnemonic locally + internal_entropy = client.debug.state().reset_entropy + entropy = generate_entropy(strength, internal_entropy, EXTERNAL_ENTROPY) + expected_mnemonic = Mnemonic("english").to_mnemonic(entropy) + + # Compare that device generated proper mnemonic for given entropies + assert mnemonic == expected_mnemonic + + # Check if device is properly initialized + resp = client.call_raw(proto.Initialize()) + assert resp.initialized is True + assert resp.needs_backup is False + assert resp.pin_protection is False + assert resp.passphrase_protection is False + assert resp.backup_type is proto.BackupType.Bip39 + + # backup attempt fails because backup was done in reset + with pytest.raises(TrezorFailure, match="ProcessError: Seed already backed up"): + device.backup(client) @pytest.mark.skip_t1 class TestMsgResetDeviceT2: @pytest.mark.setup_client(uninitialized=True) def test_reset_device(self, client): - mnemonic = None - strength = 128 + reset_device(client, 128) # 12 words - def input_flow(): - nonlocal mnemonic - # 1. Confirm Reset - # 2. Backup your seed - # 3. Confirm warning - yield from click_through(client.debug, screens=3, code=B.ResetDevice) - - # mnemonic phrases - btn_code = yield - assert btn_code == B.ResetDevice - mnemonic = read_and_confirm_mnemonic(client.debug, words=12) - - # confirm recovery seed check - btn_code = yield - assert btn_code == B.Success - client.debug.press_yes() - - # confirm success - btn_code = yield - assert btn_code == B.Success - client.debug.press_yes() - - os_urandom = mock.Mock(return_value=EXTERNAL_ENTROPY) - with mock.patch("os.urandom", os_urandom), client: - client.set_expected_responses( - [ - proto.ButtonRequest(code=B.ResetDevice), - proto.EntropyRequest(), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.Success), - proto.ButtonRequest(code=B.Success), - proto.Success(), - proto.Features(), - ] - ) - client.set_input_flow(input_flow) - - # No PIN, no passphrase, don't display random - device.reset( - client, - display_random=False, - strength=strength, - passphrase_protection=False, - pin_protection=False, - label="test", - language="en-US", - ) - - # generate mnemonic locally - internal_entropy = client.debug.state().reset_entropy - entropy = generate_entropy(strength, internal_entropy, EXTERNAL_ENTROPY) - expected_mnemonic = Mnemonic("english").to_mnemonic(entropy) - - # Compare that device generated proper mnemonic for given entropies - assert mnemonic == expected_mnemonic - - # Check if device is properly initialized - resp = client.call_raw(proto.Initialize()) - assert resp.initialized is True - assert resp.needs_backup is False - assert resp.pin_protection is False - assert resp.passphrase_protection is False - assert resp.backup_type is proto.BackupType.Bip39 - - # backup attempt fails because backup was done in reset - with pytest.raises(TrezorFailure, match="ProcessError: Seed already backed up"): - device.backup(client) + @pytest.mark.setup_client(uninitialized=True) + def test_reset_device_192(self, client): + reset_device(client, 192) # 18 words @pytest.mark.setup_client(uninitialized=True) def test_reset_device_pin(self, client): mnemonic = None - strength = 128 + strength = 256 # 24 words def input_flow(): nonlocal mnemonic @@ -149,7 +158,7 @@ class TestMsgResetDeviceT2: # mnemonic phrases btn_code = yield assert btn_code == B.ResetDevice - mnemonic = read_and_confirm_mnemonic(client.debug, words=12) + mnemonic = read_and_confirm_mnemonic(client.debug, words=24) # confirm recovery seed check btn_code = yield diff --git a/tests/device_tests/test_msg_resetdevice_slip39_basic.py b/tests/device_tests/test_msg_resetdevice_slip39_basic.py index 322cc61b61..a600f11d3f 100644 --- a/tests/device_tests/test_msg_resetdevice_slip39_basic.py +++ b/tests/device_tests/test_msg_resetdevice_slip39_basic.py @@ -32,104 +32,113 @@ from ..common import ( read_and_confirm_mnemonic, ) +STRENGTH_TO_WORDS = {128: 20, 256: 33} -@pytest.mark.skip_t1 -class TestMsgResetDeviceT2: - # TODO: test with different options - @pytest.mark.setup_client(uninitialized=True) - def test_reset_device_slip39_basic(self, client): - strength = 128 - member_threshold = 3 - all_mnemonics = [] - def input_flow(): - # 1. Confirm Reset - # 2. Backup your seed - # 3. Confirm warning - # 4. shares info - # 5. Set & Confirm number of shares - # 6. threshold info - # 7. Set & confirm threshold value - # 8. Confirm show seeds - yield from click_through(client.debug, screens=8, code=B.ResetDevice) +def reset_device(client, strength): + words = STRENGTH_TO_WORDS[strength] + member_threshold = 3 + all_mnemonics = [] - # show & confirm shares - for h in range(5): - # mnemonic phrases - btn_code = yield - assert btn_code == B.ResetDevice - mnemonic = read_and_confirm_mnemonic(client.debug, words=20) - all_mnemonics.append(mnemonic) + def input_flow(): + # 1. Confirm Reset + # 2. Backup your seed + # 3. Confirm warning + # 4. shares info + # 5. Set & Confirm number of shares + # 6. threshold info + # 7. Set & confirm threshold value + # 8. Confirm show seeds + yield from click_through(client.debug, screens=8, code=B.ResetDevice) - # Confirm continue to next share - btn_code = yield - assert btn_code == B.Success - client.debug.press_yes() + # show & confirm shares + for h in range(5): + # mnemonic phrases + btn_code = yield + assert btn_code == B.ResetDevice + mnemonic = read_and_confirm_mnemonic(client.debug, words=words) + all_mnemonics.append(mnemonic) - # safety warning + # Confirm continue to next share btn_code = yield assert btn_code == B.Success client.debug.press_yes() - os_urandom = mock.Mock(return_value=EXTERNAL_ENTROPY) - with mock.patch("os.urandom", os_urandom), client: - client.set_expected_responses( - [ - proto.ButtonRequest(code=B.ResetDevice), - proto.EntropyRequest(), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.Success), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.Success), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.Success), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.Success), - proto.ButtonRequest(code=B.ResetDevice), - proto.ButtonRequest(code=B.Success), - proto.ButtonRequest(code=B.Success), - proto.Success(), - proto.Features(), - ] - ) - client.set_input_flow(input_flow) + # safety warning + btn_code = yield + assert btn_code == B.Success + client.debug.press_yes() - # No PIN, no passphrase, don't display random - device.reset( - client, - display_random=False, - strength=strength, - passphrase_protection=False, - pin_protection=False, - label="test", - language="en-US", - backup_type=BackupType.Slip39_Basic, - ) + os_urandom = mock.Mock(return_value=EXTERNAL_ENTROPY) + with mock.patch("os.urandom", os_urandom), client: + client.set_expected_responses( + [ + proto.ButtonRequest(code=B.ResetDevice), + proto.EntropyRequest(), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.Success), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.Success), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.Success), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.Success), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.Success), + proto.ButtonRequest(code=B.Success), + proto.Success(), + proto.Features(), + ] + ) + client.set_input_flow(input_flow) - # generate secret locally - internal_entropy = client.debug.state().reset_entropy - secret = generate_entropy(strength, internal_entropy, EXTERNAL_ENTROPY) + # No PIN, no passphrase, don't display random + device.reset( + client, + display_random=False, + strength=strength, + passphrase_protection=False, + pin_protection=False, + label="test", + language="en-US", + backup_type=BackupType.Slip39_Basic, + ) - # validate that all combinations will result in the correct master secret - validate_mnemonics(all_mnemonics, member_threshold, secret) + # generate secret locally + internal_entropy = client.debug.state().reset_entropy + secret = generate_entropy(strength, internal_entropy, EXTERNAL_ENTROPY) - # Check if device is properly initialized - assert client.features.initialized is True - assert client.features.needs_backup is False - assert client.features.pin_protection is False - assert client.features.passphrase_protection is False - assert client.features.backup_type is BackupType.Slip39_Basic + # validate that all combinations will result in the correct master secret + validate_mnemonics(all_mnemonics, member_threshold, secret) - # backup attempt fails because backup was done in reset - with pytest.raises(TrezorFailure, match="ProcessError: Seed already backed up"): - device.backup(client) + # Check if device is properly initialized + assert client.features.initialized is True + assert client.features.needs_backup is False + assert client.features.pin_protection is False + assert client.features.passphrase_protection is False + assert client.features.backup_type is BackupType.Slip39_Basic + + # backup attempt fails because backup was done in reset + with pytest.raises(TrezorFailure, match="ProcessError: Seed already backed up"): + device.backup(client) + + +@pytest.mark.skip_t1 +class TestMsgResetDeviceT2: + @pytest.mark.setup_client(uninitialized=True) + def test_reset_device_slip39_basic(self, client): + reset_device(client, 128) + + @pytest.mark.setup_client(uninitialized=True) + def test_reset_device_slip39_basic_256(self, client): + reset_device(client, 256) def validate_mnemonics(mnemonics, threshold, expected_ems): diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index fab7f714e5..1d6e4183d7 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -220,9 +220,11 @@ "test_msg_resetdevice_bip39_t2.py-test_already_initialized": "5a80508a71a9ef64f94762b07636f90e464832f0f4a3102af8fa1a8c69e94586", "test_msg_resetdevice_bip39_t2.py-test_failed_pin": "f284b630fef6ae437c9726cd0ee0d1728a77f677f37cd5f88aabb21e596f589e", "test_msg_resetdevice_bip39_t2.py-test_reset_device": "aaa37f33897fbdf33858a9cbb8982be1b1c1d1e2cbff83ebfd4c49fa8fc4b342", -"test_msg_resetdevice_bip39_t2.py-test_reset_device_pin": "8cf79b65a37d6680f351a203f32f49b41425531be77ddcc8db894959aada7cd9", +"test_msg_resetdevice_bip39_t2.py-test_reset_device_192": "febbacc3370cf9219faa49bbc542a7aa1280d9fc3e6e9776dacbcd2f09231636", +"test_msg_resetdevice_bip39_t2.py-test_reset_device_pin": "dd95b1f1e7b496828314a4baf77f5f9f3aa54fc11754236e35f7519da9fd44c8", "test_msg_resetdevice_slip39_advanced.py-test_reset_device_slip39_advanced": "b1ca19a20f4d2be96847c8d2373921a68c5c9bd1292790229c64f93a0319cb69", "test_msg_resetdevice_slip39_basic.py-test_reset_device_slip39_basic": "77e9d45a9fb16a8759478ac1d433bb86ce58c01fa135bc4524596955de20552d", +"test_msg_resetdevice_slip39_basic.py-test_reset_device_slip39_basic_256": "5f21f628ada58d9b519aec96f99a087df1098825de33421ddb36777dc4f578f1", "test_msg_ripple_get_address.py-test_ripple_get_address": "2bb7d7bf48f1218530b4d7045d48480cad6411e110df537551b2f80b342007f2", "test_msg_ripple_get_address.py-test_ripple_get_address_other": "2bb7d7bf48f1218530b4d7045d48480cad6411e110df537551b2f80b342007f2", "test_msg_ripple_sign_tx.py-test_ripple_sign_invalid_fee": "1c0ca08b857da6121f43cfb1632c7f7e1d189ef1fdb665db7ba2cdfa7a59ea7c",