diff --git a/core/src/apps/base.py b/core/src/apps/base.py index 1bbcaaeb2..ae05cf044 100644 --- a/core/src/apps/base.py +++ b/core/src/apps/base.py @@ -65,12 +65,10 @@ def get_features() -> Features: Capability.PassphraseEntry, ] f.sd_card_present = sdcard.is_present() + f.initialized = storage.device.is_initialized() # private fields: if config.is_unlocked(): - # While this is technically not private, we can't reliably find the value while - # locked. Instead of sending always False, we choose to not send it. - f.initialized = storage.is_initialized() f.needs_backup = storage.device.needs_backup() f.unfinished_backup = storage.device.unfinished_backup() diff --git a/core/src/apps/cardano/seed.py b/core/src/apps/cardano/seed.py index 96997d10f..9c87b4599 100644 --- a/core/src/apps/cardano/seed.py +++ b/core/src/apps/cardano/seed.py @@ -1,5 +1,4 @@ -import storage -from storage import cache +from storage import cache, device from trezor import wire from trezor.crypto import bip32 @@ -39,7 +38,7 @@ class Keychain: @cache.stored_async(cache.APP_CARDANO_ROOT) async def get_keychain(ctx: wire.Context) -> Keychain: - if not storage.is_initialized(): + if not device.is_initialized(): raise wire.NotInitialized("Device is not initialized") passphrase = await get_passphrase(ctx) diff --git a/core/src/apps/common/seed.py b/core/src/apps/common/seed.py index bcf4d2417..988899dbf 100644 --- a/core/src/apps/common/seed.py +++ b/core/src/apps/common/seed.py @@ -1,5 +1,4 @@ -import storage -from storage import cache +from storage import cache, device from trezor import wire from trezor.crypto import bip32, hashlib, hmac @@ -113,7 +112,7 @@ class Keychain: @cache.stored_async(cache.APP_COMMON_SEED) async def _get_seed(ctx: wire.Context) -> bytes: - if not storage.is_initialized(): + if not device.is_initialized(): raise wire.NotInitialized("Device is not initialized") passphrase = await get_passphrase(ctx) return mnemonic.get_seed(passphrase) @@ -121,7 +120,7 @@ async def _get_seed(ctx: wire.Context) -> bytes: @cache.stored(cache.APP_COMMON_SEED_WITHOUT_PASSPHRASE) def _get_seed_without_passphrase() -> bytes: - if not storage.is_initialized(): + if not device.is_initialized(): raise Exception("Device is not initialized") return mnemonic.get_seed(progress_bar=False) diff --git a/core/src/apps/debug/load_device.py b/core/src/apps/debug/load_device.py index e47b9cc09..9a8000224 100644 --- a/core/src/apps/debug/load_device.py +++ b/core/src/apps/debug/load_device.py @@ -54,7 +54,7 @@ async def load_device(ctx, msg): def _validate(msg) -> int: - if storage.is_initialized(): + if storage.device.is_initialized(): raise wire.UnexpectedMessage("Already initialized") if not msg.mnemonics: diff --git a/core/src/apps/homescreen/homescreen.py b/core/src/apps/homescreen/homescreen.py index 5bca10549..7bc74a0a3 100644 --- a/core/src/apps/homescreen/homescreen.py +++ b/core/src/apps/homescreen/homescreen.py @@ -12,18 +12,18 @@ async def homescreen() -> None: class Homescreen(HomescreenBase): def __init__(self) -> None: super().__init__() - if not storage.is_initialized(): + if not storage.device.is_initialized(): self.label = "Go to trezor.io/start" def on_render(self) -> None: # warning bar on top - if storage.is_initialized() and storage.device.no_backup(): + if storage.device.is_initialized() and storage.device.no_backup(): ui.header_error("SEEDLESS") - elif storage.is_initialized() and storage.device.unfinished_backup(): + elif storage.device.is_initialized() and storage.device.unfinished_backup(): ui.header_error("BACKUP FAILED!") - elif storage.is_initialized() and storage.device.needs_backup(): + elif storage.device.is_initialized() and storage.device.needs_backup(): ui.header_warning("NEEDS BACKUP!") - elif storage.is_initialized() and not config.has_pin(): + elif storage.device.is_initialized() and not config.has_pin(): ui.header_warning("PIN NOT SET!") else: ui.display.bar(0, 0, ui.WIDTH, ui.HEIGHT, ui.BG) diff --git a/core/src/apps/management/apply_flags.py b/core/src/apps/management/apply_flags.py index 0f7b48b2d..679826a71 100644 --- a/core/src/apps/management/apply_flags.py +++ b/core/src/apps/management/apply_flags.py @@ -1,12 +1,11 @@ import storage.device from storage.device import set_flags +from trezor import wire from trezor.messages.Success import Success -import wire - async def apply_flags(ctx, msg): - if not storage.is_initialized(): + if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") set_flags(msg.flags) return Success(message="Flags applied") diff --git a/core/src/apps/management/apply_settings.py b/core/src/apps/management/apply_settings.py index 4f2aa88f4..434315be9 100644 --- a/core/src/apps/management/apply_settings.py +++ b/core/src/apps/management/apply_settings.py @@ -12,7 +12,7 @@ if False: async def apply_settings(ctx: wire.Context, msg: ApplySettings): - if not storage.is_initialized(): + if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if ( msg.homescreen is None diff --git a/core/src/apps/management/backup_device.py b/core/src/apps/management/backup_device.py index 5de5db95d..d7f2c4c28 100644 --- a/core/src/apps/management/backup_device.py +++ b/core/src/apps/management/backup_device.py @@ -8,7 +8,7 @@ from apps.management.reset_device import backup_seed, layout async def backup_device(ctx, msg): - if not storage.is_initialized(): + if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if not storage.device.needs_backup(): raise wire.ProcessError("Seed already backed up") diff --git a/core/src/apps/management/change_pin.py b/core/src/apps/management/change_pin.py index 1858d9457..1b47f2cdc 100644 --- a/core/src/apps/management/change_pin.py +++ b/core/src/apps/management/change_pin.py @@ -1,4 +1,4 @@ -from storage import is_initialized +from storage.device import is_initialized from trezor import config, ui, wire from trezor.messages.Success import Success from trezor.pin import pin_to_int diff --git a/core/src/apps/management/change_wipe_code.py b/core/src/apps/management/change_wipe_code.py index 9ac59114f..4c4877812 100644 --- a/core/src/apps/management/change_wipe_code.py +++ b/core/src/apps/management/change_wipe_code.py @@ -1,4 +1,4 @@ -from storage import is_initialized +from storage.device import is_initialized from trezor import config, ui, wire from trezor.messages.Success import Success from trezor.pin import pin_to_int diff --git a/core/src/apps/management/get_next_u2f_counter.py b/core/src/apps/management/get_next_u2f_counter.py index 0389bb9ab..c7d842dc1 100644 --- a/core/src/apps/management/get_next_u2f_counter.py +++ b/core/src/apps/management/get_next_u2f_counter.py @@ -11,7 +11,7 @@ from apps.common.confirm import require_confirm async def get_next_u2f_counter( ctx: wire.Context, msg: GetNextU2FCounter ) -> NextU2FCounter: - if not storage.is_initialized(): + if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") text = Text("Get next U2F counter", ui.ICON_CONFIG) text.normal("Do you really want to") diff --git a/core/src/apps/management/recovery_device/__init__.py b/core/src/apps/management/recovery_device/__init__.py index 0aba6736e..0757c2c1a 100644 --- a/core/src/apps/management/recovery_device/__init__.py +++ b/core/src/apps/management/recovery_device/__init__.py @@ -42,6 +42,10 @@ async def recovery_device(ctx: wire.Context, msg: RecoveryDevice) -> Success: await _continue_dialog(ctx, msg) + if not msg.dry_run: + # wipe storage to make sure the device is in a clear state + storage.reset() + # for dry run pin needs to be entered if msg.dry_run: curpin, salt = await request_pin_and_sd_salt(ctx, "Enter PIN") @@ -68,9 +72,9 @@ async def recovery_device(ctx: wire.Context, msg: RecoveryDevice) -> Success: def _validate(msg: RecoveryDevice) -> None: - if not msg.dry_run and storage.is_initialized(): + if not msg.dry_run and storage.device.is_initialized(): raise wire.UnexpectedMessage("Already initialized") - if msg.dry_run and not storage.is_initialized(): + if msg.dry_run and not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if msg.enforce_wordlist is False: diff --git a/core/src/apps/management/reset_device/__init__.py b/core/src/apps/management/reset_device/__init__.py index e15c848d6..8f2328752 100644 --- a/core/src/apps/management/reset_device/__init__.py +++ b/core/src/apps/management/reset_device/__init__.py @@ -28,6 +28,9 @@ async def reset_device(ctx: wire.Context, msg: ResetDevice) -> Success: # make sure user knows they're setting up a new wallet await layout.show_reset_device_warning(ctx, msg.backup_type) + # wipe storage to make sure the device is in a clear state + storage.reset() + # request and set new PIN if msg.pin_protection: newpin = await request_pin_confirm(ctx) @@ -164,7 +167,7 @@ def _validate_reset_device(msg: ResetDevice) -> None: raise wire.ProcessError("Invalid strength (has to be 128, 192 or 256 bits)") if msg.display_random and (msg.skip_backup or msg.no_backup): raise wire.ProcessError("Can't show internal entropy when backup is skipped") - if storage.is_initialized(): + if storage.device.is_initialized(): raise wire.UnexpectedMessage("Already initialized") diff --git a/core/src/apps/management/sd_protect.py b/core/src/apps/management/sd_protect.py index 877a75c2e..8da0deab9 100644 --- a/core/src/apps/management/sd_protect.py +++ b/core/src/apps/management/sd_protect.py @@ -41,7 +41,7 @@ async def _set_salt( async def sd_protect(ctx: wire.Context, msg: SdProtect) -> Success: - if not storage.is_initialized(): + if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if msg.operation == SdProtectOperationType.ENABLE: diff --git a/core/src/apps/management/set_u2f_counter.py b/core/src/apps/management/set_u2f_counter.py index e4f9cc339..2e43a1409 100644 --- a/core/src/apps/management/set_u2f_counter.py +++ b/core/src/apps/management/set_u2f_counter.py @@ -9,7 +9,7 @@ from apps.common.confirm import require_confirm async def set_u2f_counter(ctx: wire.Context, msg: SetU2FCounter) -> Success: - if not storage.is_initialized(): + if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if msg.u2f_counter is None: raise wire.ProcessError("No value provided") diff --git a/core/src/apps/webauthn/add_resident_credential.py b/core/src/apps/webauthn/add_resident_credential.py index 8fe1b0d54..acbc72360 100644 --- a/core/src/apps/webauthn/add_resident_credential.py +++ b/core/src/apps/webauthn/add_resident_credential.py @@ -1,4 +1,4 @@ -import storage +import storage.device from trezor import ui, wire from trezor.messages.Success import Success from trezor.messages.WebAuthnAddResidentCredential import WebAuthnAddResidentCredential @@ -31,7 +31,7 @@ class ConfirmAddCredential(ConfirmInfo): async def add_resident_credential( ctx: wire.Context, msg: WebAuthnAddResidentCredential ) -> Success: - if not storage.is_initialized(): + if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if not msg.credential_id: raise wire.ProcessError("Missing credential ID parameter.") diff --git a/core/src/apps/webauthn/fido2.py b/core/src/apps/webauthn/fido2.py index aef8d20e0..1bce26113 100644 --- a/core/src/apps/webauthn/fido2.py +++ b/core/src/apps/webauthn/fido2.py @@ -1221,7 +1221,7 @@ def msg_register(req: Msg, dialog_mgr: DialogManager) -> Cmd: dialog_mgr.set_state(new_state) return msg_error(req.cid, _SW_CONDITIONS_NOT_SATISFIED) - if not storage.is_initialized(): + if not storage.device.is_initialized(): if __debug__: log.warning(__name__, "not initialized") # There is no standard way to decline a U2F request, but responding with ERR_CHANNEL_BUSY @@ -1302,7 +1302,7 @@ def msg_authenticate(req: Msg, dialog_mgr: DialogManager) -> Cmd: dialog_mgr.set_state(new_state) return msg_error(req.cid, _SW_CONDITIONS_NOT_SATISFIED) - if not storage.is_initialized(): + if not storage.device.is_initialized(): if __debug__: log.warning(__name__, "not initialized") # Device is not registered with the RP. @@ -1483,7 +1483,7 @@ def cbor_make_credential_process( ) -> Union[State, Cmd]: from apps.webauthn import knownapps - if not storage.is_initialized(): + if not storage.device.is_initialized(): if __debug__: log.warning(__name__, "not initialized") return cbor_error(req.cid, _ERR_OTHER) @@ -1663,7 +1663,7 @@ def cbor_get_assertion(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]: def cbor_get_assertion_process( req: Cmd, dialog_mgr: DialogManager ) -> Union[State, Cmd]: - if not storage.is_initialized(): + if not storage.device.is_initialized(): if __debug__: log.warning(__name__, "not initialized") return cbor_error(req.cid, _ERR_OTHER) @@ -1924,7 +1924,7 @@ def cbor_client_pin(req: Cmd) -> Cmd: def cbor_reset(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]: - if not storage.is_initialized(): + if not storage.device.is_initialized(): if __debug__: log.warning(__name__, "not initialized") # Return success, because the authenticator is already in factory default state. diff --git a/core/src/apps/webauthn/remove_resident_credential.py b/core/src/apps/webauthn/remove_resident_credential.py index e03c23756..5d55e8f72 100644 --- a/core/src/apps/webauthn/remove_resident_credential.py +++ b/core/src/apps/webauthn/remove_resident_credential.py @@ -1,3 +1,4 @@ +import storage.device import storage.resident_credentials from trezor import wire from trezor.messages.Success import Success @@ -32,7 +33,7 @@ class ConfirmRemoveCredential(ConfirmInfo): async def remove_resident_credential( ctx: wire.Context, msg: WebAuthnRemoveResidentCredential ) -> Success: - if not storage.is_initialized(): + if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if msg.index is None: raise wire.ProcessError("Missing credential index parameter.") diff --git a/core/src/storage/__init__.py b/core/src/storage/__init__.py index df4888bd4..2539c2f6d 100644 --- a/core/src/storage/__init__.py +++ b/core/src/storage/__init__.py @@ -6,10 +6,6 @@ def set_current_version() -> None: device.set_version(common.STORAGE_VERSION_CURRENT) -def is_initialized() -> bool: - return device.is_version_stored() - - def wipe() -> None: config.wipe() cache.clear_all() @@ -21,6 +17,20 @@ def init_unlocked() -> None: if version == common.STORAGE_VERSION_01: _migrate_from_version_01() + # In FWs <= 2.3.1 'version' denoted whether the device is initialized or not. + # In 2.3.2 we have introduced a new field 'initialized' for that. + if device.is_version_stored() and not device.is_initialized(): + common.set_bool(common.APP_DEVICE, device.INITIALIZED, True, public=True) + + +def reset() -> None: + """ + Wipes storage but keeps the device id unchanged. + """ + device_id = device.get_device_id() + wipe() + common.set(common.APP_DEVICE, device.DEVICE_ID, device_id.encode(), public=True) + def _migrate_from_version_01() -> None: # Make the U2F counter public and writable even when storage is locked. diff --git a/core/src/storage/device.py b/core/src/storage/device.py index 0c6040d4d..6a66de9c7 100644 --- a/core/src/storage/device.py +++ b/core/src/storage/device.py @@ -14,7 +14,7 @@ _NAMESPACE = common.APP_DEVICE # fmt: off # Keys: -_DEVICE_ID = const(0x00) # bytes +DEVICE_ID = const(0x00) # bytes _VERSION = const(0x01) # int _MNEMONIC_SECRET = const(0x02) # bytes _LANGUAGE = const(0x03) # str @@ -33,6 +33,7 @@ _ROTATION = const(0x0F) # int _SLIP39_IDENTIFIER = const(0x10) # bool _SLIP39_ITERATION_EXPONENT = const(0x11) # int _SD_SALT_AUTH_KEY = const(0x12) # bytes +INITIALIZED = const(0x13) # bool (0x01 or empty) _DEFAULT_BACKUP_TYPE = BackupType.Bip39 # fmt: on @@ -60,15 +61,19 @@ def set_version(version: bytes) -> None: common.set(_NAMESPACE, _VERSION, version) +def is_initialized() -> bool: + return common.get_bool(_NAMESPACE, INITIALIZED, public=True) + + def _new_device_id() -> str: return hexlify(random.bytes(12)).decode().upper() def get_device_id() -> str: - dev_id = common.get(_NAMESPACE, _DEVICE_ID, True) # public + dev_id = common.get(_NAMESPACE, DEVICE_ID, public=True) if not dev_id: dev_id = _new_device_id().encode() - common.set(_NAMESPACE, _DEVICE_ID, dev_id, True) # public + common.set(_NAMESPACE, DEVICE_ID, dev_id, public=True) return dev_id.decode() @@ -123,6 +128,7 @@ def store_mnemonic_secret( common.set(_NAMESPACE, _MNEMONIC_SECRET, secret) common.set_uint8(_NAMESPACE, _BACKUP_TYPE, backup_type) common.set_true_or_delete(_NAMESPACE, _NO_BACKUP, no_backup) + common.set_bool(_NAMESPACE, INITIALIZED, True, public=True) if not no_backup: common.set_true_or_delete(_NAMESPACE, _NEEDS_BACKUP, needs_backup) diff --git a/core/src1/main.py b/core/src1/main.py index d53c22c0f..14c85bc8b 100644 --- a/core/src1/main.py +++ b/core/src1/main.py @@ -17,7 +17,7 @@ salt = None config.unlock(1, salt) storage.init_unlocked() storage.cache.start_session() -print("is_initialized: ", storage.is_initialized()) +print("is_initialized: ", storage.device.is_initialized()) print("version: ", storage.device.is_version_stored()) print("version: ", storage.device.get_version()) print("needs backup: ", storage.device.needs_backup()) diff --git a/core/tests/test_apps.webauthn.credential.py b/core/tests/test_apps.webauthn.credential.py index 78085d5ba..70800099e 100644 --- a/core/tests/test_apps.webauthn.credential.py +++ b/core/tests/test_apps.webauthn.credential.py @@ -1,5 +1,6 @@ from common import * import storage +import storage.device from apps.common import mnemonic from apps.webauthn.credential import Fido2Credential, U2fCredential, NAME_MAX_LENGTH from apps.webauthn.fido2 import distinguishable_cred_list @@ -11,7 +12,7 @@ class TestCredential(unittest.TestCase): def test_fido2_credential_decode(self): mnemonic_secret = b"all all all all all all all all all all all all" mnemonic.get_secret = lambda: mnemonic_secret - storage.is_initialized = lambda: True + storage.device.is_initialized = lambda: True cred_id = ( b"f1d0020013e65c865634ad8abddf7a66df56ae7d8c3afd356f76426801508b2e" diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index 99eeb8fe0..3b28bc939 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -169,38 +169,38 @@ "test_msg_recoverydevice_bip39_dryrun.py::test_seed_mismatch": "85c61f5304a32e8b84a37ef80d035cfdcbf89a8631bde53409b1ec7f1013740c", "test_msg_recoverydevice_bip39_dryrun.py::test_uninitialized": "14fcdd2ded299ca099a35966cc9f21204b31de8d6bab9ec91cb64537bd70440c", "test_msg_recoverydevice_bip39_t2.py::test_already_initialized": "5a80508a71a9ef64f94762b07636f90e464832f0f4a3102af8fa1a8c69e94586", -"test_msg_recoverydevice_bip39_t2.py::test_tt_nopin_nopassphrase": "48e9e30277913b9c2a7a2bfcb51cadad20a888e31d08208e87ad1f5e90c0d807", -"test_msg_recoverydevice_bip39_t2.py::test_tt_pin_passphrase": "f0106d33287cd438298c8b56b08cfc8593a442b90e9414c59af6a1cff8efbd5a", -"test_msg_recoverydevice_slip39_advanced.py::test_abort": "793dde7fb47e9c4ad36369be396da20332560f29083d7f9a2b0582173371c9ed", -"test_msg_recoverydevice_slip39_advanced.py::test_extra_share_entered": "00a94e20b786346c45f987860b2465f299075d7c6de4971f42a4749e1cc8bfc0", -"test_msg_recoverydevice_slip39_advanced.py::test_group_threshold_reached": "3b075a276c4e0d53fbc51ce1f29594bbd474d25f47c0f6a32caac41ba0ba2138", -"test_msg_recoverydevice_slip39_advanced.py::test_noabort": "d2d17674ec4bbfdc922570148281903abfd57f0354f21eae21079253fb301bf8", -"test_msg_recoverydevice_slip39_advanced.py::test_same_share": "de288365352fc0676b94df3e2c78b28893b1821c505b36f9c1a28dc117af2954", -"test_msg_recoverydevice_slip39_advanced.py::test_secret[shares0-c2d2e26ad06023c60145f150abe2dd2b]": "3a0803601280ca9eb72bccabc0328637ce4b7c20323ffcdde82341b09e170763", -"test_msg_recoverydevice_slip39_advanced.py::test_secret[shares1-c41d5cf80fed71a008a3a0ae0458ff0c6d62": "147fe87091f2b1a1e2cca6bd96432273a2ee98fd73bcd0f8503c578c1d101e5b", +"test_msg_recoverydevice_bip39_t2.py::test_tt_nopin_nopassphrase": "86e52bb95d0f53193cc83e828f6e6baea59ebcaa26e06784bbb4f6873ee442ac", +"test_msg_recoverydevice_bip39_t2.py::test_tt_pin_passphrase": "7a7b9d20cc5b2d6fcdf0e35d90cfcd46bfe536067becdea5568fd7f3d102306f", +"test_msg_recoverydevice_slip39_advanced.py::test_abort": "a54d4f29cf1fc3ce26831f52d0ae98a30a2f3e108f822cce08a9bfdd3319356e", +"test_msg_recoverydevice_slip39_advanced.py::test_extra_share_entered": "c972403fc15f00527f12b3226bdb918a5c29315ba88e496982f09a4fdac43218", +"test_msg_recoverydevice_slip39_advanced.py::test_group_threshold_reached": "137427360db303e288035972866df29ab0b272d30c8b11108bc68252f1aef748", +"test_msg_recoverydevice_slip39_advanced.py::test_noabort": "78a8cc92a79f90b45c3e14f01c1c57ba0fbef63438c9abe9cd1feb35b0e03c0a", +"test_msg_recoverydevice_slip39_advanced.py::test_same_share": "1ed63220ab59dd2feab4a42ffa565a9ff50980a72da022c35f6134869534c0fe", +"test_msg_recoverydevice_slip39_advanced.py::test_secret[shares0-c2d2e26ad06023c60145f150abe2dd2b]": "c69e74416015afdeb589d257511c3a8a693c1f584717d948f93a3250d6713ef6", +"test_msg_recoverydevice_slip39_advanced.py::test_secret[shares1-c41d5cf80fed71a008a3a0ae0458ff0c6d62": "9131fad9e499bb4cb3ee18c5535b89647d149746464334e0854052410b6a33d8", "test_msg_recoverydevice_slip39_advanced_dryrun.py::test_2of3_dryrun": "fdf2733eac6e1cc6f5758cf599dc6a02e3000145cd83150f0727602d98744b8d", "test_msg_recoverydevice_slip39_advanced_dryrun.py::test_2of3_invalid_seed_dryrun": "950a00e2a14070cb9c78658dd13064cf860cd125d604df242cf8a22ce9cf7a5e", -"test_msg_recoverydevice_slip39_basic.py::test_1of1": "a72967338372da0829b521e384ffea4087a088cd0a461748bbe5581cb1894082", -"test_msg_recoverydevice_slip39_basic.py::test_abort": "793dde7fb47e9c4ad36369be396da20332560f29083d7f9a2b0582173371c9ed", -"test_msg_recoverydevice_slip39_basic.py::test_ask_word_number": "8e9d9fd75e17f6b44829ae2d7b0eb9e60b48577f975abc6d75116f8365241082", -"test_msg_recoverydevice_slip39_basic.py::test_noabort": "d374a9b85c03a0cc1bbb59130e454406513fc35f4f43b968db4920414de1bb72", -"test_msg_recoverydevice_slip39_basic.py::test_recover_with_pin_passphrase": "59de0866cceef43519b01ebec5f4575b21df13628d878479b21c9899234bb773", -"test_msg_recoverydevice_slip39_basic.py::test_same_share": "e6a54429fdbedea9efca9cbed736aada07f95f3b20f895f9c1c5ec056a2be014", -"test_msg_recoverydevice_slip39_basic.py::test_secret[shares0-491b795b80fc21ccdf466c0fbc98c8fc]": "54581a91b55ab531b215cba61052fd77c505232c510f170080760605eb9b8c46", -"test_msg_recoverydevice_slip39_basic.py::test_secret[shares1-b770e0da1363247652de97a39bdbf2463be0878": "f73bef254762d761db27df46bff62641a9d2ac0602c34fc4e465262bf26ed08f", -"test_msg_recoverydevice_slip39_basic.py::test_wrong_nth_word[0]": "df88cf7855ebf39f1742b6e5c49a1c9e3394564903de1935e19555d22f818cfc", -"test_msg_recoverydevice_slip39_basic.py::test_wrong_nth_word[1]": "bd8f5062e0e48c8c29add65a6308c6ead84ae3fdce332506900ea52f8c941890", -"test_msg_recoverydevice_slip39_basic.py::test_wrong_nth_word[2]": "d8feb5ab8f9c5ca9bbe9830a68237d5b621bff8b6d1736ebd04ca678c050a08b", +"test_msg_recoverydevice_slip39_basic.py::test_1of1": "de184147e0786f76c324019964ffebd0f170474d0e1a72b0aa120daa36c624d7", +"test_msg_recoverydevice_slip39_basic.py::test_abort": "a54d4f29cf1fc3ce26831f52d0ae98a30a2f3e108f822cce08a9bfdd3319356e", +"test_msg_recoverydevice_slip39_basic.py::test_ask_word_number": "01b6945fab5f321da8858b58e7ea9f2fb1e7391884545cb563d1a34aab0c3e7a", +"test_msg_recoverydevice_slip39_basic.py::test_noabort": "3db993abfb7e8d35e4a0acf1d8975d42fe51d1bee630639238f642b5c6c5f26d", +"test_msg_recoverydevice_slip39_basic.py::test_recover_with_pin_passphrase": "45330e1d06ad7b4fc5710c0cd44fdd40afd9bbb7ce1e1c291eadb0306536719a", +"test_msg_recoverydevice_slip39_basic.py::test_same_share": "3a5317f3bcf96931bb9b262f31fd3461d14560dce0a6c068e545283e9bf526a0", +"test_msg_recoverydevice_slip39_basic.py::test_secret[shares0-491b795b80fc21ccdf466c0fbc98c8fc]": "c3cbc4aa0243f89d421de05ee02a941b44e0794ae1f9ca064d7ecea6b3dd4176", +"test_msg_recoverydevice_slip39_basic.py::test_secret[shares1-b770e0da1363247652de97a39bdbf2463be0878": "c7151e24b74ddb70ce6d10459f5ba318e8a7947cbc8abecc90df97d5abdb7609", +"test_msg_recoverydevice_slip39_basic.py::test_wrong_nth_word[0]": "3164a3744b29cdd345cbae18b8963a008e89c4d4bcebe98d2c320bf714c9c299", +"test_msg_recoverydevice_slip39_basic.py::test_wrong_nth_word[1]": "b85543b48047ebb93b1b8c509d0596205d193bf99b3cd1c6650b24d97f6bd6d4", +"test_msg_recoverydevice_slip39_basic.py::test_wrong_nth_word[2]": "6fff99c5997b08bc18d6f6dbfe67a141eda00a848168af5927b46eff48e46770", "test_msg_recoverydevice_slip39_basic_dryrun.py::test_2of3_dryrun": "d84427489f691ecc222b62f83af3e97fa09097404dcba07772a43b5eb0c689e8", "test_msg_recoverydevice_slip39_basic_dryrun.py::test_2of3_invalid_seed_dryrun": "55f2dd6b4958659f071c3f57e06286f872ac38af4828f446a0f4e91c657dfccc", "test_msg_resetdevice_bip39_t2.py-test_already_initialized": "5a80508a71a9ef64f94762b07636f90e464832f0f4a3102af8fa1a8c69e94586", -"test_msg_resetdevice_bip39_t2.py-test_failed_pin": "6b13f98de76ce3b75670e6e5fee7b11b4017165e25aa8d17e5c2f3fdca3846a3", -"test_msg_resetdevice_bip39_t2.py-test_reset_device": "c5fc35eab68889c0b3315cad09afd573ce32c1e94c2cb942388638414145f631", -"test_msg_resetdevice_bip39_t2.py-test_reset_device_192": "febbacc3370cf9219faa49bbc542a7aa1280d9fc3e6e9776dacbcd2f09231636", -"test_msg_resetdevice_bip39_t2.py-test_reset_device_pin": "cdc6e4d80a0988b367c4e37fb10e122f72507ba3cce75b0d8e4b3cbfeb4fd32a", -"test_msg_resetdevice_slip39_advanced.py-test_reset_device_slip39_advanced": "77fae06d2427b6626debb71448e0b79c81afb99da10df9b9e987259eb045edf2", -"test_msg_resetdevice_slip39_basic.py-test_reset_device_slip39_basic": "ad0d71e21112456fa99fdbd36563aa1ccbf49343a94ca1ed74068b2ec04ebd61", -"test_msg_resetdevice_slip39_basic.py-test_reset_device_slip39_basic_256": "5f21f628ada58d9b519aec96f99a087df1098825de33421ddb36777dc4f578f1", +"test_msg_resetdevice_bip39_t2.py-test_failed_pin": "ff7fe2e2d69a8e0dda7d9ec811ff0164aa5f85f9c56fe693932749b9be92c868", +"test_msg_resetdevice_bip39_t2.py-test_reset_device": "5f1b6cdc46e416430df1afd114bceda57fb644108d594ce1f466460ba4917b41", +"test_msg_resetdevice_bip39_t2.py-test_reset_device_192": "d304d9902accbe23af2dcf73758a2e81b00da17e89f754ca83f209bac8eb8ee1", +"test_msg_resetdevice_bip39_t2.py-test_reset_device_pin": "1e4cef983f25b66931db5a8286c83f8faa3e09eb865896c7e946d2c8992e6d28", +"test_msg_resetdevice_slip39_advanced.py-test_reset_device_slip39_advanced": "92dde100ab37934b7c39a9bfff15a4e73419b4f029c377f25f0b428c6e4a005c", +"test_msg_resetdevice_slip39_basic.py-test_reset_device_slip39_basic": "650ebacd885fe8c34237aceb835827472a845d8951f2ee573d94c97030603db3", +"test_msg_resetdevice_slip39_basic.py-test_reset_device_slip39_basic_256": "aa7f19f34dafbd5bf205858cd8f694f3278b309a3c8837e6596759d6a1066634", "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", @@ -349,12 +349,12 @@ "test_passphrase_slip39_advanced.py::test_256bit_passphrase": "3a92115b6bfb2d53f2445a67c9c5df6b6b5ff97769de98e3fac9e1bf424c5669", "test_passphrase_slip39_basic.py::test_2of5_passphrase": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "test_passphrase_slip39_basic.py::test_3of6_passphrase": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", -"test_reset_backup.py::test_skip_backup_manual[0-backup_flow_bip39]": "80a614b20d172be640c28cdcee6ba7fc7dadd5329fa08e1ec8f6a55a80ceb2f9", -"test_reset_backup.py::test_skip_backup_manual[1-backup_flow_slip39_basic]": "7695c4ffca95c263baa82ae17ce6faf9335bd07c6964beb900a75b61a515c245", -"test_reset_backup.py::test_skip_backup_manual[2-backup_flow_slip39_advanced]": "e0a4139cfc344909deb2b6b2398d223ce4ddf0cdb2d9975d03454537d9be2152", -"test_reset_backup.py::test_skip_backup_msg[0-backup_flow_bip39]": "30a8d39c13b89aa0bf2820bf780b8962829c9d8cd70b8c95fc98b6ef7b3ead9c", -"test_reset_backup.py::test_skip_backup_msg[1-backup_flow_slip39_basic]": "e08feca49017cbe4a2ff22b7255fb9f8db659c79709affcf2954f2ade6924a57", -"test_reset_backup.py::test_skip_backup_msg[2-backup_flow_slip39_advanced]": "b980c758e8c0aacf6cbb047a9f1acaf3a1d1f3ab84a01ee9e52e5c466caf344c", +"test_reset_backup.py::test_skip_backup_manual[0-backup_flow_bip39]": "9c5cded50e6ebe51dc6ecdaa6b793da9ec5527df582acbdc189494b809ee9f47", +"test_reset_backup.py::test_skip_backup_manual[1-backup_flow_slip39_basic]": "bf9ea5281234d622b39f388715dad86e95f0a0e1efbd3d4d6b60478a79edcc23", +"test_reset_backup.py::test_skip_backup_manual[2-backup_flow_slip39_advanced]": "e3fb56f53d04edde94aa11e5eac1e2dc732bddcd39def3981e03cffcbef1a96c", +"test_reset_backup.py::test_skip_backup_msg[0-backup_flow_bip39]": "913ab51cbefc22938190a86865793e7e99420e9c99d6714ab94c8aba6edab3ea", +"test_reset_backup.py::test_skip_backup_msg[1-backup_flow_slip39_basic]": "189a01dbe3f11061b13562d5773971ec44c0737695bfe1a4dc1c5dc1b3ffd8c0", +"test_reset_backup.py::test_skip_backup_msg[2-backup_flow_slip39_advanced]": "cd6c1248d9ee4d6416c57026a96190a84ac8608af04fd42c9c8c6b7275226aba", "test_sdcard.py::test_sd_format": "6bb7486932a5d38cdbb9b1368ee92aca3fad384115c744feadfade80c1605dd8", "test_sdcard.py::test_sd_no_format": "f47e897caee95cf98c1b4506732825f853c4b8afcdc2713e38e3b4055973c9ac", "test_sdcard.py::test_sd_protect_unlock": "9b98ad83499e38acaa9d73b0ef3261abde6e3b4b46194c32f323f28a79705077",