From faa9078c2b1473bdc53560fa9dcc8dcf9a549a1a Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Fri, 20 Dec 2019 20:36:59 +0000 Subject: [PATCH 1/4] core/recovery: refactor word checks and add a test --- .../apps/management/recovery_device/layout.py | 86 ++------------- .../recovery_device/word_validity.py | 103 ++++++++++++++++++ .../test_apps.management.recovery_device.py | 47 ++++++++ 3 files changed, 160 insertions(+), 76 deletions(-) create mode 100644 core/src/apps/management/recovery_device/word_validity.py diff --git a/core/src/apps/management/recovery_device/layout.py b/core/src/apps/management/recovery_device/layout.py index cd473c096..897d932bc 100644 --- a/core/src/apps/management/recovery_device/layout.py +++ b/core/src/apps/management/recovery_device/layout.py @@ -1,13 +1,14 @@ import storage.recovery from trezor import ui, wire from trezor.crypto.slip39 import MAX_SHARE_COUNT -from trezor.messages import BackupType, ButtonRequestType +from trezor.messages import ButtonRequestType from trezor.messages.ButtonAck import ButtonAck from trezor.messages.ButtonRequest import ButtonRequest from trezor.ui.scroll import Paginated from trezor.ui.text import Text from trezor.ui.word_select import WordSelector +from . import word_validity from .keyboard_bip39 import Bip39Keyboard from .keyboard_slip39 import Slip39Keyboard from .recover import RecoveryAborted @@ -15,7 +16,6 @@ from .recover import RecoveryAborted from apps.common.confirm import confirm, info_confirm, require_confirm from apps.common.layout import show_success, show_warning from apps.management import backup_types -from apps.management.recovery_device import recover if __debug__: from apps.debug import input_signal @@ -72,7 +72,14 @@ async def request_mnemonic( else: word = await ctx.wait(keyboard) - if not await check_word_validity(ctx, i, word, backup_type, words): + validity = word_validity.check(i, word, backup_type, words) + if validity != word_validity.OK: + if validity == word_validity.NOK_ALREADY_ADDED: + await show_share_already_added(ctx) + elif validity == word_validity.NOK_IDENTIFIER_MISMATCH: + await show_identifier_mismatch(ctx) + elif validity == word_validity.NOK_THRESHOLD_REACHED: + await show_group_threshold_reached(ctx) return None words.append(word) @@ -80,79 +87,6 @@ async def request_mnemonic( return " ".join(words) -async def check_word_validity( - ctx: wire.GenericContext, - current_index: int, - current_word: str, - backup_type: Optional[EnumTypeBackupType], - previous_words: List[str], -) -> bool: - # we can't perform any checks if the backup type was not yet decided - if backup_type is None: - return True - # there are no "on-the-fly" checks for BIP-39 - if backup_type is BackupType.Bip39: - return True - - previous_mnemonics = recover.fetch_previous_mnemonics() - if previous_mnemonics is None: - # this should not happen if backup_type is set - raise RuntimeError - - if backup_type == BackupType.Slip39_Basic: - # check if first 3 words of mnemonic match - # we can check against the first one, others were checked already - if current_index < 3: - share_list = previous_mnemonics[0][0].split(" ") - if share_list[current_index] != current_word: - await show_identifier_mismatch(ctx) - return False - elif current_index == 3: - for share in previous_mnemonics[0]: - share_list = share.split(" ") - # check if the fourth word is different from previous shares - if share_list[current_index] == current_word: - await show_share_already_added(ctx) - return False - elif backup_type == BackupType.Slip39_Advanced: - if current_index < 2: - share_list = next(s for s in previous_mnemonics if s)[0].split(" ") - if share_list[current_index] != current_word: - await show_identifier_mismatch(ctx) - return False - # check if we reached threshold in group - elif current_index == 2: - for i, group in enumerate(previous_mnemonics): - if len(group) > 0: - if current_word == group[0].split(" ")[current_index]: - remaining_shares = ( - storage.recovery.fetch_slip39_remaining_shares() - ) - # if backup_type is not None, some share was already entered -> remaining needs to be set - assert remaining_shares is not None - if remaining_shares[i] == 0: - await show_group_threshold_reached(ctx) - return False - # check if share was already added for group - elif current_index == 3: - # we use the 3rd word from previously entered shares to find the group id - group_identifier_word = previous_words[2] - group_index = None - for i, group in enumerate(previous_mnemonics): - if len(group) > 0: - if group_identifier_word == group[0].split(" ")[2]: - group_index = i - - if group_index is not None: - group = previous_mnemonics[group_index] - for share in group: - if current_word == share.split(" ")[current_index]: - await show_share_already_added(ctx) - return False - - return True - - async def show_remaining_shares( ctx: wire.GenericContext, groups: Iterable[Tuple[int, Tuple[str, ...]]], # remaining + list 3 words diff --git a/core/src/apps/management/recovery_device/word_validity.py b/core/src/apps/management/recovery_device/word_validity.py new file mode 100644 index 000000000..915cb0323 --- /dev/null +++ b/core/src/apps/management/recovery_device/word_validity.py @@ -0,0 +1,103 @@ +from micropython import const + +import storage.recovery +from trezor.messages import BackupType + +from apps.management.recovery_device import recover + +if False: + from typing import List, Optional + from trezor.messages.ResetDevice import EnumTypeBackupType + +OK = const(0) +NOK_IDENTIFIER_MISMATCH = const(1) +NOK_ALREADY_ADDED = const(2) +NOK_THRESHOLD_REACHED = const(3) + + +def check( + current_index: int, + current_word: str, + backup_type: Optional[EnumTypeBackupType], + previous_words: List[str], +) -> int: + # we can't perform any checks if the backup type was not yet decided + if backup_type is None: + return OK + # there are no "on-the-fly" checks for BIP-39 + if backup_type is BackupType.Bip39: + return OK + + previous_mnemonics = recover.fetch_previous_mnemonics() + if previous_mnemonics is None: + # this should not happen if backup_type is set + raise RuntimeError + + if backup_type == BackupType.Slip39_Basic: + return check_slip39_basic(current_index, current_word, previous_mnemonics) + + if backup_type == BackupType.Slip39_Advanced: + return check_slip39_advanced( + current_index, current_word, previous_words, previous_mnemonics + ) + + # there are no other backup types + raise RuntimeError + + +def check_slip39_basic( + current_index: int, current_word: str, previous_mnemonics: List[List[str]] +) -> int: + # check if first 3 words of mnemonic match + # we can check against the first one, others were checked already + if current_index < 3: + share_list = previous_mnemonics[0][0].split(" ") + if share_list[current_index] != current_word: + return NOK_IDENTIFIER_MISMATCH + elif current_index == 3: + for share in previous_mnemonics[0]: + share_list = share.split(" ") + # check if the fourth word is different from previous shares + if share_list[current_index] == current_word: + return NOK_ALREADY_ADDED + + return OK + + +def check_slip39_advanced( + current_index: int, + current_word: str, + previous_words: List[str], + previous_mnemonics: List[List[str]], +) -> int: + if current_index < 2: + share_list = next(s for s in previous_mnemonics if s)[0].split(" ") + if share_list[current_index] != current_word: + return NOK_IDENTIFIER_MISMATCH + # check if we reached threshold in group + elif current_index == 2: + for i, group in enumerate(previous_mnemonics): + if len(group) > 0: + if current_word == group[0].split(" ")[current_index]: + remaining_shares = storage.recovery.fetch_slip39_remaining_shares() + # if backup_type is not None, some share was already entered -> remaining needs to be set + assert remaining_shares is not None + if remaining_shares[i] == 0: + return NOK_THRESHOLD_REACHED + # check if share was already added for group + elif current_index == 3: + # we use the 3rd word from previously entered shares to find the group id + group_identifier_word = previous_words[2] + group_index = None + for i, group in enumerate(previous_mnemonics): + if len(group) > 0: + if group_identifier_word == group[0].split(" ")[2]: + group_index = i + + if group_index is not None: + group = previous_mnemonics[group_index] + for share in group: + if current_word == share.split(" ")[current_index]: + return NOK_ALREADY_ADDED + + return OK diff --git a/core/tests/test_apps.management.recovery_device.py b/core/tests/test_apps.management.recovery_device.py index 5509bccdd..eab24e7e1 100644 --- a/core/tests/test_apps.management.recovery_device.py +++ b/core/tests/test_apps.management.recovery_device.py @@ -140,6 +140,53 @@ class TestSlip39(unittest.TestCase): secret, share = process_slip39(words) self.assertIsNone(secret) + @mock_storage + def test_check_word_validity(self): + from trezor.messages import BackupType + from apps.management.recovery_device.word_validity import check, OK, NOK_IDENTIFIER_MISMATCH, NOK_ALREADY_ADDED, NOK_THRESHOLD_REACHED + + storage.recovery.set_in_progress(True) + + # nothing is stored -> should raise + with self.assertRaises(RuntimeError): + check(0, "ocean", BackupType.Slip39_Advanced, []) + + # if backup type is not set we can not do any checks + result = check(0, "ocean", None, []) + self.assertIs(result, OK) + + # BIP-39 has no "on-the-fly" checks + result = check(0, "ocean", BackupType.Bip39, []) + self.assertIs(result, OK) + + # let's store two shares in the storage + secret, share = process_slip39("trash smug adjust ambition criminal prisoner security math cover pecan response pharmacy center criminal salary elbow bracelet lunar briefing dragon") + self.assertIsNone(secret) + secret, share = process_slip39("trash smug adjust aide benefit temple round clogs devote prevent type cards clogs plastic aspect paper behavior lunar custody intimate") + self.assertIsNone(secret) + + # different identifier + result = check(0, "slush", BackupType.Slip39_Advanced, []) + self.assertIs(result, NOK_IDENTIFIER_MISMATCH) + + # same first word but still a different identifier + result = check(1, "slush", BackupType.Slip39_Advanced, ["trash"]) + self.assertIs(result, NOK_IDENTIFIER_MISMATCH) + + # same mnemonic found out using the index + result = check(3, "ambition", BackupType.Slip39_Advanced, ["trash", "smug", "adjust"]) + self.assertIs(result, NOK_ALREADY_ADDED) + + # Let's store two more. The group is 4/6 so this group is now complete. + secret, share = process_slip39("trash smug adjust arena beard quick language program true hush amount round geology should training practice language diet order ruin") + self.assertIsNone(secret) + secret, share = process_slip39("trash smug adjust beam brave sack magazine radar toxic emission domestic cradle vocal petition mule toxic acid hobo welcome downtown") + self.assertIsNone(secret) + + # If trying to add another one from this group we get a warning. + result = check(2, "adjust", BackupType.Slip39_Advanced, ["trash", "smug"]) + self.assertIs(result, NOK_THRESHOLD_REACHED) + if __name__ == "__main__": unittest.main() From f4e11a9176af83fcdde5b1edc0d584585ca1bfe9 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Fri, 27 Dec 2019 18:46:22 +0000 Subject: [PATCH 2/4] core/recovery: rework arguments --- .../recovery_device/word_validity.py | 24 ++++++++----------- .../test_apps.management.recovery_device.py | 21 ++++++++-------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/core/src/apps/management/recovery_device/word_validity.py b/core/src/apps/management/recovery_device/word_validity.py index 915cb0323..10950e0a6 100644 --- a/core/src/apps/management/recovery_device/word_validity.py +++ b/core/src/apps/management/recovery_device/word_validity.py @@ -16,10 +16,7 @@ NOK_THRESHOLD_REACHED = const(3) def check( - current_index: int, - current_word: str, - backup_type: Optional[EnumTypeBackupType], - previous_words: List[str], + backup_type: Optional[EnumTypeBackupType], partial_mnemonic: List[str] ) -> int: # we can't perform any checks if the backup type was not yet decided if backup_type is None: @@ -34,22 +31,22 @@ def check( raise RuntimeError if backup_type == BackupType.Slip39_Basic: - return check_slip39_basic(current_index, current_word, previous_mnemonics) + return check_slip39_basic(partial_mnemonic, previous_mnemonics) if backup_type == BackupType.Slip39_Advanced: - return check_slip39_advanced( - current_index, current_word, previous_words, previous_mnemonics - ) + return check_slip39_advanced(partial_mnemonic, previous_mnemonics) # there are no other backup types raise RuntimeError def check_slip39_basic( - current_index: int, current_word: str, previous_mnemonics: List[List[str]] + partial_mnemonic: List[str], previous_mnemonics: List[List[str]] ) -> int: # check if first 3 words of mnemonic match # we can check against the first one, others were checked already + current_index = len(partial_mnemonic) - 1 + current_word = partial_mnemonic[-1] if current_index < 3: share_list = previous_mnemonics[0][0].split(" ") if share_list[current_index] != current_word: @@ -65,11 +62,10 @@ def check_slip39_basic( def check_slip39_advanced( - current_index: int, - current_word: str, - previous_words: List[str], - previous_mnemonics: List[List[str]], + partial_mnemonic: List[str], previous_mnemonics: List[List[str]] ) -> int: + current_index = len(partial_mnemonic) - 1 + current_word = partial_mnemonic[-1] if current_index < 2: share_list = next(s for s in previous_mnemonics if s)[0].split(" ") if share_list[current_index] != current_word: @@ -87,7 +83,7 @@ def check_slip39_advanced( # check if share was already added for group elif current_index == 3: # we use the 3rd word from previously entered shares to find the group id - group_identifier_word = previous_words[2] + group_identifier_word = partial_mnemonic[2] group_index = None for i, group in enumerate(previous_mnemonics): if len(group) > 0: diff --git a/core/tests/test_apps.management.recovery_device.py b/core/tests/test_apps.management.recovery_device.py index eab24e7e1..497fa4d6a 100644 --- a/core/tests/test_apps.management.recovery_device.py +++ b/core/tests/test_apps.management.recovery_device.py @@ -4,6 +4,8 @@ from mock_storage import mock_storage import storage import storage.recovery from apps.management.recovery_device.recover import process_slip39 +from trezor.messages import BackupType +from apps.management.recovery_device.word_validity import check, OK, NOK_IDENTIFIER_MISMATCH, NOK_ALREADY_ADDED, NOK_THRESHOLD_REACHED MNEMONIC_SLIP39_BASIC_20_3of6 = [ "extra extend academic bishop cricket bundle tofu goat apart victim enlarge program behavior permit course armed jerky faint language modern", @@ -142,21 +144,18 @@ class TestSlip39(unittest.TestCase): @mock_storage def test_check_word_validity(self): - from trezor.messages import BackupType - from apps.management.recovery_device.word_validity import check, OK, NOK_IDENTIFIER_MISMATCH, NOK_ALREADY_ADDED, NOK_THRESHOLD_REACHED - storage.recovery.set_in_progress(True) - # nothing is stored -> should raise + # We claim to know the backup type, but nothing is stored. That is an invalid state. with self.assertRaises(RuntimeError): - check(0, "ocean", BackupType.Slip39_Advanced, []) + check(BackupType.Slip39_Advanced, ["ocean"]) # if backup type is not set we can not do any checks - result = check(0, "ocean", None, []) + result = check(None, ["ocean"]) self.assertIs(result, OK) # BIP-39 has no "on-the-fly" checks - result = check(0, "ocean", BackupType.Bip39, []) + result = check(BackupType.Bip39, ["ocean"]) self.assertIs(result, OK) # let's store two shares in the storage @@ -166,15 +165,15 @@ class TestSlip39(unittest.TestCase): self.assertIsNone(secret) # different identifier - result = check(0, "slush", BackupType.Slip39_Advanced, []) + result = check(BackupType.Slip39_Advanced, ["slush"]) self.assertIs(result, NOK_IDENTIFIER_MISMATCH) # same first word but still a different identifier - result = check(1, "slush", BackupType.Slip39_Advanced, ["trash"]) + result = check(BackupType.Slip39_Advanced, ["trash", "slush"]) self.assertIs(result, NOK_IDENTIFIER_MISMATCH) # same mnemonic found out using the index - result = check(3, "ambition", BackupType.Slip39_Advanced, ["trash", "smug", "adjust"]) + result = check(BackupType.Slip39_Advanced, ["trash", "smug", "adjust", "ambition"]) self.assertIs(result, NOK_ALREADY_ADDED) # Let's store two more. The group is 4/6 so this group is now complete. @@ -184,7 +183,7 @@ class TestSlip39(unittest.TestCase): self.assertIsNone(secret) # If trying to add another one from this group we get a warning. - result = check(2, "adjust", BackupType.Slip39_Advanced, ["trash", "smug"]) + result = check(BackupType.Slip39_Advanced, ["trash", "smug", "adjust"]) self.assertIs(result, NOK_THRESHOLD_REACHED) From 7f730cb6f9a1635d75409e1a721f9879805c6ba1 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Fri, 27 Dec 2019 19:02:30 +0000 Subject: [PATCH 3/4] core/recovery: refactor to exceptions --- .../apps/management/recovery_device/layout.py | 22 +++---- .../recovery_device/word_validity.py | 60 ++++++++++--------- .../test_apps.management.recovery_device.py | 24 ++++---- 3 files changed, 56 insertions(+), 50 deletions(-) diff --git a/core/src/apps/management/recovery_device/layout.py b/core/src/apps/management/recovery_device/layout.py index 897d932bc..6eea99661 100644 --- a/core/src/apps/management/recovery_device/layout.py +++ b/core/src/apps/management/recovery_device/layout.py @@ -72,18 +72,20 @@ async def request_mnemonic( else: word = await ctx.wait(keyboard) - validity = word_validity.check(i, word, backup_type, words) - if validity != word_validity.OK: - if validity == word_validity.NOK_ALREADY_ADDED: - await show_share_already_added(ctx) - elif validity == word_validity.NOK_IDENTIFIER_MISMATCH: - await show_identifier_mismatch(ctx) - elif validity == word_validity.NOK_THRESHOLD_REACHED: - await show_group_threshold_reached(ctx) - return None - words.append(word) + try: + word_validity.check(backup_type, words) + except word_validity.AlreadyAdded: + await show_share_already_added(ctx) + return None + except word_validity.IdentifierMismatch: + await show_identifier_mismatch(ctx) + return None + except word_validity.ThresholdReached: + await show_group_threshold_reached(ctx) + return None + return " ".join(words) diff --git a/core/src/apps/management/recovery_device/word_validity.py b/core/src/apps/management/recovery_device/word_validity.py index 10950e0a6..01c1c0246 100644 --- a/core/src/apps/management/recovery_device/word_validity.py +++ b/core/src/apps/management/recovery_device/word_validity.py @@ -1,5 +1,3 @@ -from micropython import const - import storage.recovery from trezor.messages import BackupType @@ -9,21 +7,32 @@ if False: from typing import List, Optional from trezor.messages.ResetDevice import EnumTypeBackupType -OK = const(0) -NOK_IDENTIFIER_MISMATCH = const(1) -NOK_ALREADY_ADDED = const(2) -NOK_THRESHOLD_REACHED = const(3) + +class WordValidityResult(BaseException): + pass + + +class IdentifierMismatch(WordValidityResult): + pass + + +class AlreadyAdded(WordValidityResult): + pass + + +class ThresholdReached(WordValidityResult): + pass def check( backup_type: Optional[EnumTypeBackupType], partial_mnemonic: List[str] -) -> int: +) -> None: # we can't perform any checks if the backup type was not yet decided if backup_type is None: - return OK + return # there are no "on-the-fly" checks for BIP-39 if backup_type is BackupType.Bip39: - return OK + return previous_mnemonics = recover.fetch_previous_mnemonics() if previous_mnemonics is None: @@ -31,18 +40,17 @@ def check( raise RuntimeError if backup_type == BackupType.Slip39_Basic: - return check_slip39_basic(partial_mnemonic, previous_mnemonics) - - if backup_type == BackupType.Slip39_Advanced: - return check_slip39_advanced(partial_mnemonic, previous_mnemonics) - - # there are no other backup types - raise RuntimeError + check_slip39_basic(partial_mnemonic, previous_mnemonics) + elif backup_type == BackupType.Slip39_Advanced: + check_slip39_advanced(partial_mnemonic, previous_mnemonics) + else: + # there are no other backup types + raise RuntimeError def check_slip39_basic( partial_mnemonic: List[str], previous_mnemonics: List[List[str]] -) -> int: +) -> None: # check if first 3 words of mnemonic match # we can check against the first one, others were checked already current_index = len(partial_mnemonic) - 1 @@ -50,26 +58,25 @@ def check_slip39_basic( if current_index < 3: share_list = previous_mnemonics[0][0].split(" ") if share_list[current_index] != current_word: - return NOK_IDENTIFIER_MISMATCH + raise IdentifierMismatch elif current_index == 3: for share in previous_mnemonics[0]: share_list = share.split(" ") # check if the fourth word is different from previous shares if share_list[current_index] == current_word: - return NOK_ALREADY_ADDED - - return OK + raise AlreadyAdded def check_slip39_advanced( partial_mnemonic: List[str], previous_mnemonics: List[List[str]] -) -> int: +) -> None: current_index = len(partial_mnemonic) - 1 current_word = partial_mnemonic[-1] + if current_index < 2: share_list = next(s for s in previous_mnemonics if s)[0].split(" ") if share_list[current_index] != current_word: - return NOK_IDENTIFIER_MISMATCH + raise IdentifierMismatch # check if we reached threshold in group elif current_index == 2: for i, group in enumerate(previous_mnemonics): @@ -79,7 +86,8 @@ def check_slip39_advanced( # if backup_type is not None, some share was already entered -> remaining needs to be set assert remaining_shares is not None if remaining_shares[i] == 0: - return NOK_THRESHOLD_REACHED + raise ThresholdReached + # check if share was already added for group elif current_index == 3: # we use the 3rd word from previously entered shares to find the group id @@ -94,6 +102,4 @@ def check_slip39_advanced( group = previous_mnemonics[group_index] for share in group: if current_word == share.split(" ")[current_index]: - return NOK_ALREADY_ADDED - - return OK + raise AlreadyAdded diff --git a/core/tests/test_apps.management.recovery_device.py b/core/tests/test_apps.management.recovery_device.py index 497fa4d6a..22212cf0e 100644 --- a/core/tests/test_apps.management.recovery_device.py +++ b/core/tests/test_apps.management.recovery_device.py @@ -5,7 +5,7 @@ import storage import storage.recovery from apps.management.recovery_device.recover import process_slip39 from trezor.messages import BackupType -from apps.management.recovery_device.word_validity import check, OK, NOK_IDENTIFIER_MISMATCH, NOK_ALREADY_ADDED, NOK_THRESHOLD_REACHED +from apps.management.recovery_device.word_validity import check, IdentifierMismatch, AlreadyAdded, ThresholdReached MNEMONIC_SLIP39_BASIC_20_3of6 = [ "extra extend academic bishop cricket bundle tofu goat apart victim enlarge program behavior permit course armed jerky faint language modern", @@ -151,12 +151,10 @@ class TestSlip39(unittest.TestCase): check(BackupType.Slip39_Advanced, ["ocean"]) # if backup type is not set we can not do any checks - result = check(None, ["ocean"]) - self.assertIs(result, OK) + self.assertIsNone(check(None, ["ocean"])) # BIP-39 has no "on-the-fly" checks - result = check(BackupType.Bip39, ["ocean"]) - self.assertIs(result, OK) + self.assertIsNone(check(BackupType.Bip39, ["ocean"])) # let's store two shares in the storage secret, share = process_slip39("trash smug adjust ambition criminal prisoner security math cover pecan response pharmacy center criminal salary elbow bracelet lunar briefing dragon") @@ -165,16 +163,16 @@ class TestSlip39(unittest.TestCase): self.assertIsNone(secret) # different identifier - result = check(BackupType.Slip39_Advanced, ["slush"]) - self.assertIs(result, NOK_IDENTIFIER_MISMATCH) + with self.assertRaises(IdentifierMismatch): + check(BackupType.Slip39_Advanced, ["slush"]) # same first word but still a different identifier - result = check(BackupType.Slip39_Advanced, ["trash", "slush"]) - self.assertIs(result, NOK_IDENTIFIER_MISMATCH) + with self.assertRaises(IdentifierMismatch): + check(BackupType.Slip39_Advanced, ["trash", "slush"]) # same mnemonic found out using the index - result = check(BackupType.Slip39_Advanced, ["trash", "smug", "adjust", "ambition"]) - self.assertIs(result, NOK_ALREADY_ADDED) + with self.assertRaises(AlreadyAdded): + check(BackupType.Slip39_Advanced, ["trash", "smug", "adjust", "ambition"]) # Let's store two more. The group is 4/6 so this group is now complete. secret, share = process_slip39("trash smug adjust arena beard quick language program true hush amount round geology should training practice language diet order ruin") @@ -183,8 +181,8 @@ class TestSlip39(unittest.TestCase): self.assertIsNone(secret) # If trying to add another one from this group we get a warning. - result = check(BackupType.Slip39_Advanced, ["trash", "smug", "adjust"]) - self.assertIs(result, NOK_THRESHOLD_REACHED) + with self.assertRaises(ThresholdReached): + check(BackupType.Slip39_Advanced, ["trash", "smug", "adjust"]) if __name__ == "__main__": From d8e956fc6d1f4f37b3d5b67c763d322997e97216 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Mon, 30 Dec 2019 11:35:56 +0000 Subject: [PATCH 4/4] core/recovery: change exceptions types; modifications in tests --- core/src/apps/management/recovery_device/word_validity.py | 2 +- core/tests/test_apps.management.recovery_device.py | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/apps/management/recovery_device/word_validity.py b/core/src/apps/management/recovery_device/word_validity.py index 01c1c0246..f1d278cd5 100644 --- a/core/src/apps/management/recovery_device/word_validity.py +++ b/core/src/apps/management/recovery_device/word_validity.py @@ -8,7 +8,7 @@ if False: from trezor.messages.ResetDevice import EnumTypeBackupType -class WordValidityResult(BaseException): +class WordValidityResult(Exception): pass diff --git a/core/tests/test_apps.management.recovery_device.py b/core/tests/test_apps.management.recovery_device.py index 22212cf0e..678fc906a 100644 --- a/core/tests/test_apps.management.recovery_device.py +++ b/core/tests/test_apps.management.recovery_device.py @@ -151,10 +151,10 @@ class TestSlip39(unittest.TestCase): check(BackupType.Slip39_Advanced, ["ocean"]) # if backup type is not set we can not do any checks - self.assertIsNone(check(None, ["ocean"])) + check(None, ["ocean"]) # BIP-39 has no "on-the-fly" checks - self.assertIsNone(check(BackupType.Bip39, ["ocean"])) + check(BackupType.Bip39, ["ocean"]) # let's store two shares in the storage secret, share = process_slip39("trash smug adjust ambition criminal prisoner security math cover pecan response pharmacy center criminal salary elbow bracelet lunar briefing dragon") @@ -170,6 +170,10 @@ class TestSlip39(unittest.TestCase): with self.assertRaises(IdentifierMismatch): check(BackupType.Slip39_Advanced, ["trash", "slush"]) + # same identifier but different group settings for Slip 39 Basic + with self.assertRaises(IdentifierMismatch): + check(BackupType.Slip39_Basic, ["trash", "smug", "slush"]) + # same mnemonic found out using the index with self.assertRaises(AlreadyAdded): check(BackupType.Slip39_Advanced, ["trash", "smug", "adjust", "ambition"])