feat(core): Add extendable BackupTypes.

Andrew Kozlik 4 weeks ago
parent 36bdb5911c
commit 5a5b785957

@ -13,9 +13,11 @@ import "messages.proto";
* Type of the mnemonic backup given/received by the device during reset/recovery.
*/
enum BackupType {
Bip39 = 0; // also called "Single Backup", see BIP-0039
Slip39_Basic = 1; // also called "Shamir Backup", see SLIP-0039
Slip39_Advanced = 2; // also called "Super Shamir" or "Shamir with Groups", see SLIP-0039#two-level-scheme
Bip39 = 0; // also called "Single Backup", see BIP-0039
Slip39_Basic = 1; // also called "Shamir Backup", see SLIP-0039
Slip39_Advanced = 2; // also called "Super Shamir" or "Shamir with Groups", see SLIP-0039#two-level-scheme
Slip39_Basic_Extendable = 3; // extendable Shamir backup
Slip39_Advanced_Extendable = 4; // extendable Shamir with groups backup
}
/**

@ -275,6 +275,8 @@ apps.common.address_type
import apps.common.address_type
apps.common.authorization
import apps.common.authorization
apps.common.backup_types
import apps.common.backup_types
apps.common.cbor
import apps.common.cbor
apps.common.coininfo
@ -315,8 +317,6 @@ apps.management.authenticate_device
import apps.management.authenticate_device
apps.management.backup_device
import apps.management.backup_device
apps.management.backup_types
import apps.management.backup_types
apps.management.change_language
import apps.management.change_language
apps.management.change_pin

@ -23,7 +23,26 @@ def is_slip39_word_count(word_count: int) -> bool:
def is_slip39_backup_type(backup_type: BackupType) -> bool:
return backup_type in (BackupType.Slip39_Basic, BackupType.Slip39_Advanced)
return backup_type in (
BackupType.Slip39_Basic,
BackupType.Slip39_Advanced,
BackupType.Slip39_Basic_Extendable,
BackupType.Slip39_Advanced_Extendable,
)
def is_slip39_advanced_backup_type(backup_type: BackupType) -> bool:
return backup_type in (
BackupType.Slip39_Advanced,
BackupType.Slip39_Advanced_Extendable,
)
def is_extendable_backup_type(backup_type: BackupType) -> bool:
return backup_type in (
BackupType.Slip39_Basic_Extendable,
BackupType.Slip39_Advanced_Extendable,
)
def infer_backup_type(is_slip39: bool, share: Share | None = None) -> BackupType:
@ -32,6 +51,12 @@ def infer_backup_type(is_slip39: bool, share: Share | None = None) -> BackupType
elif not share or share.group_count < 1: # invalid parameters
raise RuntimeError
elif share.group_count == 1:
return BackupType.Slip39_Basic
if share.extendable:
return BackupType.Slip39_Basic_Extendable
else:
return BackupType.Slip39_Basic
else:
return BackupType.Slip39_Advanced
if share.extendable:
return BackupType.Slip39_Advanced_Extendable
else:
return BackupType.Slip39_Advanced

@ -3,6 +3,8 @@ from typing import TYPE_CHECKING
import storage.device as storage_device
from trezor import utils
from . import backup_types
if TYPE_CHECKING:
from trezor.enums import BackupType
from trezor.ui.layouts.common import ProgressLayout
@ -49,7 +51,7 @@ def get_seed(passphrase: str = "", progress_bar: bool = True) -> bytes:
from trezor.crypto import slip39
identifier = storage_device.get_slip39_identifier()
extendable = storage_device.get_slip39_extendable()
extendable = backup_types.is_extendable_backup_type(get_type())
iteration_exponent = storage_device.get_slip39_iteration_exponent()
if identifier is None or iteration_exponent is None:
# Identifier or exponent expected but not found

@ -13,7 +13,7 @@ async def load_device(msg: LoadDevice) -> Success:
from trezor.ui.layouts import confirm_action
from trezor.wire import ProcessError, UnexpectedMessage
from apps.management import backup_types
from apps.common import backup_types
mnemonics = msg.mnemonics # local_cache_attribute
@ -55,15 +55,8 @@ async def load_device(msg: LoadDevice) -> Success:
# this must succeed if the recover_ems call succeeded
share = slip39.decode_mnemonic(mnemonics[0])
if share.group_count == 1:
backup_type = BackupType.Slip39_Basic
elif share.group_count > 1:
backup_type = BackupType.Slip39_Advanced
else:
raise ProcessError("Invalid group count")
backup_type = backup_types.infer_backup_type(is_slip39, share)
storage_device.set_slip39_identifier(identifier)
storage_device.set_slip39_extendable(extendable)
storage_device.set_slip39_iteration_exponent(iteration_exponent)
storage_device.store_mnemonic_secret(

@ -14,7 +14,7 @@ async def backup_device(msg: BackupDevice) -> Success:
from trezor import wire
from trezor.messages import Success
from apps.common import mnemonic
from apps.common import backup_types, mnemonic
from .reset_device import backup_seed, backup_slip39_custom, layout
@ -44,7 +44,8 @@ async def backup_device(msg: BackupDevice) -> Success:
storage_device.set_backed_up()
if group_threshold is not None:
await backup_slip39_custom(mnemonic_secret, group_threshold, groups)
extendable = backup_types.is_extendable_backup_type(backup_type)
await backup_slip39_custom(mnemonic_secret, group_threshold, groups, extendable)
else:
await backup_seed(backup_type, mnemonic_secret)

@ -6,7 +6,8 @@ import storage.recovery_shares as storage_recovery_shares
from trezor import TR, wire
from trezor.messages import Success
from .. import backup_types
from apps.common import backup_types
from . import layout, recover
if TYPE_CHECKING:
@ -116,14 +117,14 @@ async def _finish_recovery_dry_run(secret: bytes, backup_type: BackupType) -> Su
result = utils.consteq(digest_stored, digest_input)
is_slip39 = backup_types.is_slip39_backup_type(backup_type)
# Check that the identifier and iteration exponent match as well
# Check that the identifier, extendable backup flag and iteration exponent match as well
if is_slip39:
result &= (
storage_device.get_slip39_identifier()
== storage_recovery.get_slip39_identifier()
)
result &= (
storage_device.get_slip39_extendable()
backup_types.is_extendable_backup_type(storage_device.get_backup_type())
== storage_recovery.get_slip39_extendable()
)
result &= (
@ -142,7 +143,6 @@ async def _finish_recovery_dry_run(secret: bytes, backup_type: BackupType) -> Su
async def _finish_recovery(secret: bytes, backup_type: BackupType) -> Success:
from trezor.enums import BackupType
from trezor.ui.layouts import show_success
if backup_type is None:
@ -153,13 +153,11 @@ async def _finish_recovery(secret: bytes, backup_type: BackupType) -> Success:
)
if backup_types.is_slip39_backup_type(backup_type):
identifier = storage_recovery.get_slip39_identifier()
extendable = storage_recovery.get_slip39_extendable()
exponent = storage_recovery.get_slip39_iteration_exponent()
if identifier is None or extendable is None or exponent is None:
if identifier is None or exponent is None:
# Identifier and exponent need to be stored in storage at this point
raise RuntimeError
storage_device.set_slip39_identifier(identifier)
storage_device.set_slip39_extendable(extendable)
storage_device.set_slip39_iteration_exponent(exponent)
storage_recovery.end_progress()

@ -10,7 +10,7 @@ from trezor.ui.layouts.recovery import ( # noqa: F401
show_remaining_shares,
)
from .. import backup_types
from apps.common import backup_types
if TYPE_CHECKING:
from typing import Callable

@ -95,7 +95,7 @@ if TYPE_CHECKING:
def load_slip39_state() -> Slip39State:
from .. import backup_types
from apps.common import backup_types
previous_mnemonics = fetch_previous_mnemonics()
if not previous_mnemonics:

@ -23,6 +23,8 @@ class ThresholdReached(WordValidityResult):
def check(backup_type: BackupType | None, partial_mnemonic: list[str]) -> None:
from trezor.enums import BackupType
from apps.common import backup_types
from . import recover
# we can't perform any checks if the backup type was not yet decided
@ -37,10 +39,11 @@ def check(backup_type: BackupType | None, partial_mnemonic: list[str]) -> None:
# this should not happen if backup_type is set
raise RuntimeError
if backup_type == BackupType.Slip39_Basic:
_check_slip39_basic(partial_mnemonic, previous_mnemonics)
elif backup_type == BackupType.Slip39_Advanced:
_check_slip39_advanced(partial_mnemonic, previous_mnemonics)
if backup_types.is_slip39_backup_type(backup_type):
if backup_types.is_slip39_advanced_backup_type(backup_type):
_check_slip39_advanced(partial_mnemonic, previous_mnemonics)
else:
_check_slip39_basic(partial_mnemonic, previous_mnemonics)
else:
# there are no other backup types
raise RuntimeError

@ -8,7 +8,8 @@ from trezor.enums import BackupType
from trezor.ui.layouts import confirm_action
from trezor.wire import ProcessError
from .. import backup_types
from apps.common import backup_types
from . import layout
if __debug__:
@ -21,6 +22,8 @@ if TYPE_CHECKING:
BAK_T_BIP39 = BackupType.Bip39 # global_import_cache
BAK_T_SLIP39_BASIC = BackupType.Slip39_Basic # global_import_cache
BAK_T_SLIP39_ADVANCED = BackupType.Slip39_Advanced # global_import_cache
BAK_T_SLIP39_BASIC_EXT = BackupType.Slip39_Basic_Extendable # global_import_cache
BAK_T_SLIP39_ADVANCED_EXT = BackupType.Slip39_Advanced_Extendable # global_import_cache
_DEFAULT_BACKUP_TYPE = BAK_T_BIP39
@ -36,6 +39,13 @@ async def reset_device(msg: ResetDevice) -> Success:
backup_type = msg.backup_type # local_cache_attribute
# Force extendable backup.
if backup_type == BAK_T_SLIP39_BASIC:
backup_type = BAK_T_SLIP39_BASIC_EXT
if backup_type == BAK_T_SLIP39_ADVANCED:
backup_type = BAK_T_SLIP39_ADVANCED_EXT
# validate parameters and device state
_validate_reset_device(msg)
@ -78,7 +88,6 @@ async def reset_device(msg: ResetDevice) -> Success:
elif backup_types.is_slip39_backup_type(backup_type):
# generate and set SLIP39 parameters
storage_device.set_slip39_identifier(slip39.generate_random_identifier())
storage_device.set_slip39_extendable(slip39.DEFAULT_EXTENDABLE_FLAG)
storage_device.set_slip39_iteration_exponent(slip39.DEFAULT_ITERATION_EXPONENT)
else:
# Unknown backup type.
@ -114,7 +123,9 @@ async def reset_device(msg: ResetDevice) -> Success:
return Success(message="Initialized")
async def _backup_slip39_basic(encrypted_master_secret: bytes) -> None:
async def _backup_slip39_basic(
encrypted_master_secret: bytes, extendable: bool
) -> None:
group_threshold = 1
# get number of shares
@ -126,7 +137,10 @@ async def _backup_slip39_basic(encrypted_master_secret: bytes) -> None:
share_threshold = await layout.slip39_prompt_threshold(share_count)
mnemonics = _get_slip39_mnemonics(
encrypted_master_secret, group_threshold, ((share_threshold, share_count),)
encrypted_master_secret,
group_threshold,
((share_threshold, share_count),),
extendable,
)
# show and confirm individual shares
@ -134,7 +148,9 @@ async def _backup_slip39_basic(encrypted_master_secret: bytes) -> None:
await layout.slip39_basic_show_and_confirm_shares(mnemonics[0])
async def _backup_slip39_advanced(encrypted_master_secret: bytes) -> None:
async def _backup_slip39_advanced(
encrypted_master_secret: bytes, extendable: bool
) -> None:
# get number of groups
await layout.slip39_show_checklist(0, advanced=True)
groups_count = await layout.slip39_advanced_prompt_number_of_groups()
@ -151,7 +167,9 @@ async def _backup_slip39_advanced(encrypted_master_secret: bytes) -> None:
share_threshold = await layout.slip39_prompt_threshold(share_count, i)
groups.append((share_threshold, share_count))
mnemonics = _get_slip39_mnemonics(encrypted_master_secret, group_threshold, groups)
mnemonics = _get_slip39_mnemonics(
encrypted_master_secret, group_threshold, groups, extendable
)
# show and confirm individual shares
await layout.slip39_advanced_show_and_confirm_shares(mnemonics)
@ -161,8 +179,11 @@ async def backup_slip39_custom(
encrypted_master_secret: bytes,
group_threshold: int,
groups: Sequence[tuple[int, int]],
extendable: bool,
) -> None:
mnemonics = _get_slip39_mnemonics(encrypted_master_secret, group_threshold, groups)
mnemonics = _get_slip39_mnemonics(
encrypted_master_secret, group_threshold, groups, extendable
)
# show and confirm individual shares
if len(groups) == 1 and groups[0][0] == 1 and groups[0][1] == 1:
@ -187,9 +208,9 @@ def _get_slip39_mnemonics(
encrypted_master_secret: bytes,
group_threshold: int,
groups: Sequence[tuple[int, int]],
extendable: bool,
):
identifier = storage_device.get_slip39_identifier()
extendable = storage_device.get_slip39_extendable()
iteration_exponent = storage_device.get_slip39_iteration_exponent()
if identifier is None or iteration_exponent is None:
raise ValueError
@ -208,8 +229,6 @@ def _get_slip39_mnemonics(
def _validate_reset_device(msg: ResetDevice) -> None:
from trezor.wire import UnexpectedMessage
from .. import backup_types
backup_type = msg.backup_type or _DEFAULT_BACKUP_TYPE
if backup_types.is_slip39_backup_type(backup_type):
if msg.strength not in (128, 256):
@ -243,9 +262,11 @@ def _compute_secret_from_entropy(
async def backup_seed(backup_type: BackupType, mnemonic_secret: bytes) -> None:
if backup_type == BAK_T_SLIP39_BASIC:
await _backup_slip39_basic(mnemonic_secret)
elif backup_type == BAK_T_SLIP39_ADVANCED:
await _backup_slip39_advanced(mnemonic_secret)
if backup_types.is_slip39_backup_type(backup_type):
extendable = backup_types.is_extendable_backup_type(backup_type)
if backup_types.is_slip39_advanced_backup_type(backup_type):
await _backup_slip39_advanced(mnemonic_secret, extendable)
else:
await _backup_slip39_basic(mnemonic_secret, extendable)
else:
await layout.show_and_confirm_mnemonic(mnemonic_secret.decode())

@ -35,7 +35,6 @@ INITIALIZED = const(0x13) # bool (0x01 or empty)
_SAFETY_CHECK_LEVEL = const(0x14) # int
_EXPERIMENTAL_FEATURES = const(0x15) # bool (0x01 or empty)
_HIDE_PASSPHRASE_FROM_HOST = const(0x16) # bool (0x01 or empty)
_SLIP39_EXTENDABLE = const(0x17) # bool (0x01 or empty)
SAFETY_CHECK_LEVEL_STRICT : Literal[0] = const(0)
SAFETY_CHECK_LEVEL_PROMPT : Literal[1] = const(1)
@ -130,6 +129,8 @@ def get_backup_type() -> BackupType:
BackupType.Bip39,
BackupType.Slip39_Basic,
BackupType.Slip39_Advanced,
BackupType.Slip39_Basic_Extendable,
BackupType.Slip39_Advanced_Extendable,
):
# Invalid backup type
raise RuntimeError
@ -261,20 +262,6 @@ def get_slip39_identifier() -> int | None:
return common.get_uint16(_NAMESPACE, _SLIP39_IDENTIFIER)
def set_slip39_extendable(extendable: bool) -> None:
"""
The device's actual SLIP-39 extendable backup flag.
Not to be confused with recovery.extendable, which is stored only during
the recovery process and it is copied here upon success.
"""
common.set_bool(_NAMESPACE, _SLIP39_EXTENDABLE, extendable)
def get_slip39_extendable() -> bool:
"""The device's actual SLIP-39 extendable backup flag."""
return common.get_bool(_NAMESPACE, _SLIP39_EXTENDABLE)
def set_slip39_iteration_exponent(exponent: int) -> None:
"""
The device's actual SLIP-39 iteration exponent used in passphrase derivation.

@ -5,3 +5,5 @@
Bip39 = 0
Slip39_Basic = 1
Slip39_Advanced = 2
Slip39_Basic_Extendable = 3
Slip39_Advanced_Extendable = 4

@ -416,6 +416,8 @@ if TYPE_CHECKING:
Bip39 = 0
Slip39_Basic = 1
Slip39_Advanced = 2
Slip39_Basic_Extendable = 3
Slip39_Advanced_Extendable = 4
class SafetyCheckLevel(IntEnum):
Strict = 0

@ -444,6 +444,8 @@ class BackupType(IntEnum):
Bip39 = 0
Slip39_Basic = 1
Slip39_Advanced = 2
Slip39_Basic_Extendable = 3
Slip39_Advanced_Extendable = 4
class SafetyCheckLevel(IntEnum):

@ -10395,6 +10395,10 @@ pub enum BackupType {
Slip39_Basic = 1,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.management.BackupType.Slip39_Advanced)
Slip39_Advanced = 2,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.management.BackupType.Slip39_Basic_Extendable)
Slip39_Basic_Extendable = 3,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.management.BackupType.Slip39_Advanced_Extendable)
Slip39_Advanced_Extendable = 4,
}
impl ::protobuf::Enum for BackupType {
@ -10409,6 +10413,8 @@ impl ::protobuf::Enum for BackupType {
0 => ::std::option::Option::Some(BackupType::Bip39),
1 => ::std::option::Option::Some(BackupType::Slip39_Basic),
2 => ::std::option::Option::Some(BackupType::Slip39_Advanced),
3 => ::std::option::Option::Some(BackupType::Slip39_Basic_Extendable),
4 => ::std::option::Option::Some(BackupType::Slip39_Advanced_Extendable),
_ => ::std::option::Option::None
}
}
@ -10418,6 +10424,8 @@ impl ::protobuf::Enum for BackupType {
"Bip39" => ::std::option::Option::Some(BackupType::Bip39),
"Slip39_Basic" => ::std::option::Option::Some(BackupType::Slip39_Basic),
"Slip39_Advanced" => ::std::option::Option::Some(BackupType::Slip39_Advanced),
"Slip39_Basic_Extendable" => ::std::option::Option::Some(BackupType::Slip39_Basic_Extendable),
"Slip39_Advanced_Extendable" => ::std::option::Option::Some(BackupType::Slip39_Advanced_Extendable),
_ => ::std::option::Option::None
}
}
@ -10426,6 +10434,8 @@ impl ::protobuf::Enum for BackupType {
BackupType::Bip39,
BackupType::Slip39_Basic,
BackupType::Slip39_Advanced,
BackupType::Slip39_Basic_Extendable,
BackupType::Slip39_Advanced_Extendable,
];
}
@ -10744,13 +10754,14 @@ static file_descriptor_proto_data: &'static [u8] = b"\
\x1b\n\taddress_n\x18\x01\x20\x03(\rR\x08addressN\x12\x10\n\x03mac\x18\
\x02\x20\x01(\x0cR\x03mac\"'\n\x13UnlockedPathRequest\x12\x10\n\x03mac\
\x18\x01\x20\x01(\x0cR\x03mac\"\x14\n\x12ShowDeviceTutorial\"\x12\n\x10U\
nlockBootloader*>\n\nBackupType\x12\t\n\x05Bip39\x10\0\x12\x10\n\x0cSlip\
39_Basic\x10\x01\x12\x13\n\x0fSlip39_Advanced\x10\x02*G\n\x10SafetyCheck\
Level\x12\n\n\x06Strict\x10\0\x12\x10\n\x0cPromptAlways\x10\x01\x12\x15\
\n\x11PromptTemporarily\x10\x02*0\n\x10HomescreenFormat\x12\x08\n\x04Toi\
f\x10\x01\x12\x08\n\x04Jpeg\x10\x02\x12\x08\n\x04ToiG\x10\x03BB\n#com.sa\
toshilabs.trezor.lib.protobufB\x17TrezorMessageManagement\x80\xa6\x1d\
\x01\
nlockBootloader*{\n\nBackupType\x12\t\n\x05Bip39\x10\0\x12\x10\n\x0cSlip\
39_Basic\x10\x01\x12\x13\n\x0fSlip39_Advanced\x10\x02\x12\x1b\n\x17Slip3\
9_Basic_Extendable\x10\x03\x12\x1e\n\x1aSlip39_Advanced_Extendable\x10\
\x04*G\n\x10SafetyCheckLevel\x12\n\n\x06Strict\x10\0\x12\x10\n\x0cPrompt\
Always\x10\x01\x12\x15\n\x11PromptTemporarily\x10\x02*0\n\x10HomescreenF\
ormat\x12\x08\n\x04Toif\x10\x01\x12\x08\n\x04Jpeg\x10\x02\x12\x08\n\x04T\
oiG\x10\x03BB\n#com.satoshilabs.trezor.lib.protobufB\x17TrezorMessageMan\
agement\x80\xa6\x1d\x01\
";
/// `FileDescriptorProto` object which was a source for this generated file

Loading…
Cancel
Save