refactor(core/rust/ui): layouts for BIP-39 backups

[no changelog]
pull/2496/head
Martin Milata 2 years ago
parent 4ff2c99f0a
commit 4782afbae3

@ -24,6 +24,7 @@ static void _librust_qstrs(void) {
MP_QSTR_confirm_modify_output;
MP_QSTR_confirm_output;
MP_QSTR_confirm_payment_request;
MP_QSTR_confirm_reset_device;
MP_QSTR_confirm_text;
MP_QSTR_confirm_total;
MP_QSTR_show_error;
@ -35,6 +36,8 @@ static void _librust_qstrs(void) {
MP_QSTR_request_passphrase;
MP_QSTR_request_bip39;
MP_QSTR_request_slip39;
MP_QSTR_select_word;
MP_QSTR_show_share_words;
MP_QSTR_attach_timer_fn;
MP_QSTR_touch_event;
@ -70,4 +73,6 @@ static void _librust_qstrs(void) {
MP_QSTR_total_amount;
MP_QSTR_total_fee_new;
MP_QSTR_user_fee_change;
MP_QSTR_words;
MP_QSTR_pages;
}

@ -429,6 +429,31 @@ impl<T> Button<T> {
}),
)
}
pub fn select_word(
words: [T; 3],
) -> CancelInfoConfirm<
T,
impl Fn(ButtonMsg) -> Option<SelectWordMsg>,
impl Fn(ButtonMsg) -> Option<SelectWordMsg>,
impl Fn(ButtonMsg) -> Option<SelectWordMsg>,
>
where
T: AsRef<str>,
{
let btn = move |i, word| {
GridPlaced::new(Button::with_text(word))
.with_grid(3, 1)
.with_spacing(theme::BUTTON_SPACING)
.with_row_col(i, 0)
.map(move |msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| SelectWordMsg::Selected(i))
})
};
let [top, middle, bottom] = words;
(btn(0, top), btn(1, middle), btn(2, bottom))
}
}
type CancelConfirm<T, F0, F1> = (
@ -452,3 +477,7 @@ pub enum CancelInfoConfirmMsg {
Info,
Confirmed,
}
pub enum SelectWordMsg {
Selected(usize),
}

@ -111,7 +111,7 @@ where
}
pub struct CancelHold {
cancel: Button<&'static str>,
cancel: Option<Button<&'static str>>,
hold: Button<&'static str>,
}
@ -123,7 +123,14 @@ pub enum CancelHoldMsg {
impl CancelHold {
pub fn new() -> Self {
Self {
cancel: Button::with_icon(theme::ICON_CANCEL),
cancel: Some(Button::with_icon(theme::ICON_CANCEL)),
hold: Button::with_text("HOLD TO CONFIRM").styled(theme::button_confirm()),
}
}
pub fn without_cancel() -> Self {
Self {
cancel: None,
hold: Button::with_text("HOLD TO CONFIRM").styled(theme::button_confirm()),
}
}
@ -133,10 +140,14 @@ impl Component for CancelHold {
type Msg = CancelHoldMsg;
fn place(&mut self, bounds: Rect) -> Rect {
let grid = Grid::new(bounds, 1, 4).with_spacing(theme::BUTTON_SPACING);
self.cancel.place(grid.row_col(0, 0));
self.hold
.place(grid.row_col(0, 1).union(grid.row_col(0, 3)));
if self.cancel.is_some() {
let grid = Grid::new(bounds, 1, 4).with_spacing(theme::BUTTON_SPACING);
self.cancel.place(grid.row_col(0, 0));
self.hold
.place(grid.row_col(0, 1).union(grid.row_col(0, 3)));
} else {
self.hold.place(bounds);
};
bounds
}

@ -10,7 +10,7 @@ mod swipe;
pub use button::{
Button, ButtonContent, ButtonMsg, ButtonStyle, ButtonStyleSheet, CancelConfirmMsg,
CancelInfoConfirmMsg,
CancelInfoConfirmMsg, SelectWordMsg,
};
pub use dialog::{Dialog, DialogLayout, DialogMsg, IconDialog};
pub use frame::Frame;

@ -237,6 +237,14 @@ where
loader: Loader::new(),
}
}
pub fn without_cancel(content: T, background: Color) -> Self {
let buttons = CancelHold::without_cancel();
Self {
inner: SwipePage::new(content, buttons, background),
loader: Loader::new(),
}
}
}
impl<T> Component for SwipeHoldPage<T>

@ -1,4 +1,5 @@
use core::{convert::TryInto, ops::Deref};
use core::{cmp::Ordering, convert::TryInto, ops::Deref};
use cstr_core::cstr;
use crate::{
error::Error,
@ -13,7 +14,6 @@ use crate::{
},
ui::{
component::{
self,
base::ComponentExt,
paginated::{PageMsg, Paginate},
painter,
@ -30,10 +30,10 @@ use crate::{
use super::{
component::{
Bip39Input, Button, ButtonMsg, CancelConfirmMsg, CancelInfoConfirmMsg, Dialog, DialogMsg,
Frame, HoldToConfirm, HoldToConfirmMsg, IconDialog, MnemonicInput, MnemonicKeyboard,
MnemonicKeyboardMsg, PassphraseKeyboard, PassphraseKeyboardMsg, PinKeyboard,
PinKeyboardMsg, Slip39Input, SwipeHoldPage, SwipePage,
Bip39Input, Button, ButtonMsg, ButtonStyleSheet, CancelConfirmMsg, CancelInfoConfirmMsg,
Dialog, DialogMsg, Frame, HoldToConfirm, HoldToConfirmMsg, IconDialog, MnemonicInput,
MnemonicKeyboard, MnemonicKeyboardMsg, PassphraseKeyboard, PassphraseKeyboardMsg,
PinKeyboard, PinKeyboardMsg, SelectWordMsg, Slip39Input, SwipeHoldPage, SwipePage,
},
theme,
};
@ -61,6 +61,16 @@ impl TryFrom<CancelInfoConfirmMsg> for Obj {
}
}
impl TryFrom<SelectWordMsg> for Obj {
type Error = Error;
fn try_from(value: SelectWordMsg) -> Result<Self, Self::Error> {
match value {
SelectWordMsg::Selected(i) => i.try_into(),
}
}
}
impl<T, U> ComponentMsgObj for Dialog<T, U>
where
T: ComponentMsgObj,
@ -265,6 +275,27 @@ extern "C" fn new_confirm_blob(n_args: usize, args: *const Obj, kwargs: *mut Map
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
}
extern "C" fn new_confirm_reset_device(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
let block = move |_args: &[Obj], kwargs: &Map| {
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
let prompt: StrBuffer = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
let description: StrBuffer = "\nBy continuing you agree to".into();
let url: StrBuffer = "https://trezor.io/tos".into();
let paragraphs = Paragraphs::new()
.add(theme::TEXT_BOLD, prompt)
.add(theme::TEXT_NORMAL, description)
.add(theme::TEXT_BOLD, url);
let buttons = Button::cancel_confirm_text(None, "CONTINUE");
let obj = LayoutObj::new(
Frame::new(title, SwipePage::new(paragraphs, buttons, theme::BG)).into_child(),
)?;
Ok(obj.into())
};
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
}
extern "C" fn new_show_qr(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
let block = move |_args: &[Obj], kwargs: &Map| {
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
@ -601,6 +632,59 @@ extern "C" fn new_request_slip39(n_args: usize, args: *const Obj, kwargs: *mut M
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
}
extern "C" fn new_select_word(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
let block = move |_args: &[Obj], kwargs: &Map| {
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
let description: StrBuffer = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?;
let words_iterable: Obj = kwargs.get(Qstr::MP_QSTR_words)?;
let mut words = [StrBuffer::empty(), StrBuffer::empty(), StrBuffer::empty()];
let mut iter_buf = IterBuf::new();
let mut iter = Iter::try_from_obj_with_buf(words_iterable, &mut iter_buf)?;
let words_err = || Error::ValueError(cstr!("Invalid words count"));
for item in &mut words {
*item = iter.next().ok_or_else(words_err)?.try_into()?;
}
if iter.next().is_some() {
return Err(words_err());
}
let paragraphs = Paragraphs::new().add(theme::TEXT_NORMAL, description);
let buttons = Button::select_word(words);
let obj = LayoutObj::new(
Frame::new(
title,
SwipePage::new(paragraphs, buttons, theme::BG).with_button_rows(3),
)
.into_child(),
)?;
Ok(obj.into())
};
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
}
extern "C" fn new_show_share_words(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
let block = move |_args: &[Obj], kwargs: &Map| {
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
let pages: Obj = kwargs.get(Qstr::MP_QSTR_pages)?;
let mut paragraphs = Paragraphs::new();
let mut iter_buf = IterBuf::new();
let iter = Iter::try_from_obj_with_buf(pages, &mut iter_buf)?;
for page in iter {
let text: StrBuffer = page.try_into()?;
paragraphs = paragraphs.add(theme::TEXT_MONO, text).add_break();
}
let obj = LayoutObj::new(
Frame::new(title, SwipeHoldPage::without_cancel(paragraphs, theme::BG)).into_child(),
)?;
Ok(obj.into())
};
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
}
#[no_mangle]
pub static mp_module_trezorui2: Module = obj_module! {
Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(),
@ -640,6 +724,14 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// """Confirm byte sequence data."""
Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(),
/// def confirm_reset_device(
/// *,
/// title: str,
/// prompt: str,
/// ) -> object:
/// """Confirm TOS before device setup."""
Qstr::MP_QSTR_confirm_reset_device => obj_fn_kw!(0, new_confirm_reset_device).as_obj(),
/// def show_qr(
/// *,
/// title: str,
@ -784,6 +876,24 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// ) -> str:
/// """SLIP39 word input keyboard."""
Qstr::MP_QSTR_request_slip39 => obj_fn_kw!(0, new_request_slip39).as_obj(),
/// def select_word(
/// *,
/// title: str,
/// description: str,
/// words: Iterable[str],
/// ) -> int:
/// """Select mnemonic word from three possibilities - seed check after backup. The
/// iterable must be of exact size. Returns index in range `0..3`."""
Qstr::MP_QSTR_select_word => obj_fn_kw!(0, new_select_word).as_obj(),
/// def show_share_words(
/// *,
/// title: str,
/// pages: Iterable[str],
/// ) -> object:
/// """Show mnemonic for backup. Expects the words pre-divided into individual pages."""
Qstr::MP_QSTR_show_share_words => obj_fn_kw!(0, new_show_share_words).as_obj(),
};
#[cfg(test)]

@ -84,6 +84,15 @@ def confirm_blob(
"""Confirm byte sequence data."""
# rust/src/ui/model_tt/layout.rs
def confirm_reset_device(
*,
title: str,
prompt: str,
) -> object:
"""Confirm TOS before device setup."""
# rust/src/ui/model_tt/layout.rs
def show_qr(
*,
@ -243,3 +252,23 @@ def request_slip39(
prompt: str,
) -> str:
"""SLIP39 word input keyboard."""
# rust/src/ui/model_tt/layout.rs
def select_word(
*,
title: str,
description: str,
words: Iterable[str],
) -> int:
"""Select mnemonic word from three possibilities - seed check after backup. The
iterable must be of exact size. Returns index in range `0..3`."""
# rust/src/ui/model_tt/layout.rs
def show_share_words(
*,
title: str,
pages: Iterable[str],
) -> object:
"""Show mnemonic for backup. Expects the words pre-divided into individual pages."""

@ -1,11 +1,13 @@
from typing import Sequence
from trezor import ui, utils, wire
from trezor.crypto import random
from trezor.enums import ButtonRequestType
from trezor.ui.layouts import confirm_action, confirm_blob, show_success, show_warning
from trezor.ui.layouts import confirm_blob, show_success, show_warning
from trezor.ui.layouts.reset import ( # noqa: F401
confirm_word,
select_word,
show_share_words,
show_warning_backup,
slip39_advanced_prompt_group_threshold,
slip39_advanced_prompt_number_of_groups,
slip39_prompt_number_of_shares,
@ -13,6 +15,11 @@ from trezor.ui.layouts.reset import ( # noqa: F401
slip39_show_checklist,
)
if __debug__:
from apps import debug
NUM_OF_CHOICES = 3
async def show_internal_entropy(ctx: wire.GenericContext, entropy: bytes) -> None:
await confirm_blob(
@ -26,6 +33,38 @@ async def show_internal_entropy(ctx: wire.GenericContext, entropy: bytes) -> Non
)
async def _confirm_word(
ctx: wire.GenericContext,
share_index: int | None,
share_words: Sequence[str],
offset: int,
count: int,
group_index: int | None = None,
) -> bool:
# remove duplicates
non_duplicates = list(set(share_words))
# shuffle list
random.shuffle(non_duplicates)
# take top NUM_OF_CHOICES words
choices = non_duplicates[:NUM_OF_CHOICES]
# select first of them
checked_word = choices[0]
# find its index
checked_index = share_words.index(checked_word) + offset
# shuffle again so the confirmed word is not always the first choice
random.shuffle(choices)
if __debug__:
debug.reset_word_index.publish(checked_index)
# let the user pick a word
selected_word: str = await select_word(
ctx, choices, share_index, checked_index, count, group_index
)
# confirm it is the correct one
return selected_word == checked_word
async def _confirm_share_words(
ctx: wire.GenericContext,
share_index: int | None,
@ -39,7 +78,7 @@ async def _confirm_share_words(
offset = 0
count = len(share_words)
for part in utils.chunks(share_words, third):
if not await confirm_word(ctx, share_index, part, offset, count, group_index):
if not await _confirm_word(ctx, share_index, part, offset, count, group_index):
return False
offset += len(part)
@ -93,20 +132,7 @@ async def _show_confirmation_failure(
async def show_backup_warning(ctx: wire.GenericContext, slip39: bool = False) -> None:
if slip39:
description = "Never make a digital copy of your recovery shares and never upload them online!"
else:
description = "Never make a digital copy of your recovery seed and never upload\nit online!"
await confirm_action(
ctx,
"backup_warning",
"Caution",
description=description,
verb="I understand",
verb_cancel=None,
icon=ui.ICON_NOCOPY,
br_code=ButtonRequestType.ResetDevice,
)
await show_warning_backup(ctx, slip39)
async def show_backup_success(ctx: wire.GenericContext) -> None:

@ -553,7 +553,7 @@ async def should_show_more(
br_code: ButtonRequestType = ButtonRequestType.Other,
icon: str = ui.ICON_DEFAULT,
icon_color: int = ui.ORANGE_ICON,
confirm: ButtonContent = Confirm.DEFAULT_CONFIRM,
confirm: str | bytes | None = None,
major_confirm: bool = False,
) -> bool:
"""Return True if the user wants to show more (they click a special button)
@ -561,6 +561,9 @@ async def should_show_more(
Raises ActionCancelled if the user cancels.
"""
if confirm is None:
confirm = Confirm.DEFAULT_CONFIRM
page = Text(
title,
header_icon=icon,

@ -1,7 +1,6 @@
from typing import TYPE_CHECKING
from trezor import ui, utils, wire
from trezor.crypto import random
from trezor.enums import BackupType, ButtonRequestType
from ...components.common.confirm import is_confirmed, raise_if_cancelled
@ -13,6 +12,7 @@ from ...components.tt.reset import MnemonicWordSelect, Slip39NumInput
from ...components.tt.scroll import Paginated
from ...components.tt.text import Text
from ..common import interact
from . import confirm_action
if TYPE_CHECKING:
from typing import Sequence
@ -100,35 +100,18 @@ async def show_share_words(
)
async def confirm_word(
async def select_word(
ctx: wire.GenericContext,
words: Sequence[str],
share_index: int | None,
share_words: Sequence[str],
offset: int,
checked_index: int,
count: int,
group_index: int | None = None,
) -> bool:
# remove duplicates
non_duplicates = list(set(share_words))
# shuffle list
random.shuffle(non_duplicates)
# take top NUM_OF_CHOICES words
choices = non_duplicates[: MnemonicWordSelect.NUM_OF_CHOICES]
# select first of them
checked_word = choices[0]
# find its index
checked_index = share_words.index(checked_word) + offset
# shuffle again so the confirmed word is not always the first choice
random.shuffle(choices)
if __debug__:
debug.reset_word_index.publish(checked_index)
) -> str:
# let the user pick a word
select = MnemonicWordSelect(choices, share_index, checked_index, count, group_index)
select = MnemonicWordSelect(words, share_index, checked_index, count, group_index)
selected_word: str = await ctx.wait(select)
# confirm it is the correct one
return selected_word == checked_word
return selected_word
def _split_share_into_pages(
@ -361,3 +344,20 @@ async def slip39_advanced_prompt_group_threshold(
await info
return count
async def show_warning_backup(ctx: wire.GenericContext, slip39: bool) -> None:
if slip39:
description = "Never make a digital copy of your recovery shares and never upload them online!"
else:
description = "Never make a digital copy of your recovery seed and never upload\nit online!"
await confirm_action(
ctx,
"backup_warning",
"Caution",
description=description,
verb="I understand",
verb_cancel=None,
icon=ui.ICON_NOCOPY,
br_code=ButtonRequestType.ResetDevice,
)

@ -12,15 +12,18 @@ if TYPE_CHECKING:
from typing import Any, Awaitable, Iterable, NoReturn, Sequence
from ..common import PropertyType, ExceptionType
from ...components.tt.button import ButtonContent
class _RustLayout(ui.Layout):
# pylint: disable=super-init-not-called
def __init__(self, layout: Any):
def __init__(self, layout: Any, is_backup=False):
self.layout = layout
self.timer = loop.Timer()
self.layout.attach_timer_fn(self.set_timer)
self.is_backup = is_backup
if __debug__ and self.is_backup:
self.notify_backup()
def set_timer(self, token: int, deadline: int) -> None:
self.timer.schedule(deadline, token)
@ -78,8 +81,27 @@ class _RustLayout(ui.Layout):
if msg is not None:
raise ui.Result(msg)
if self.is_backup:
self.notify_backup()
notify_layout_change(self)
def notify_backup(self):
from apps.debug import reset_current_words
content = "\n".join(self.read_content())
start = "< Paragraphs "
end = ">"
start_pos = content.index(start)
end_pos = content.index(end, start_pos)
words = []
for line in content[start_pos + len(start) : end_pos].split("\n"):
line = line.strip()
if not line:
continue
space_pos = line.index(" ")
words.append(line[space_pos + 1 :])
reset_current_words.publish(words)
else:
def create_tasks(self) -> tuple[loop.AwaitableTask, ...]:
@ -186,17 +208,60 @@ async def confirm_action(
async def confirm_reset_device(
ctx: wire.GenericContext, prompt: str, recovery: bool = False
) -> None:
return await confirm_action(
if recovery:
title = "RECOVERY MODE"
else:
title = "CREATE NEW WALLET"
result = await interact(
ctx,
_RustLayout(
trezorui2.confirm_reset_device(
title=title.upper(),
prompt=prompt.replace("\n", " "),
)
),
"recover_device" if recovery else "setup_device",
"not implemented",
action="not implemented",
ButtonRequestType.ProtectCall if recovery else ButtonRequestType.ResetDevice,
)
if result is not trezorui2.CONFIRMED:
raise wire.ActionCancelled
# TODO cleanup @ redesign
async def confirm_backup(ctx: wire.GenericContext) -> bool:
raise NotImplementedError
result = await interact(
ctx,
_RustLayout(
trezorui2.confirm_action(
title="SUCCESS",
action="New wallet created successfully.",
description="You should back up your new wallet right now.",
verb="BACK UP",
verb_cancel="SKIP",
)
),
"backup_device",
ButtonRequestType.ResetDevice,
)
if result is trezorui2.CONFIRMED:
return True
result = await interact(
ctx,
_RustLayout(
trezorui2.confirm_action(
title="WARNING",
action="Are you sure you want to skip the backup?",
description="You can back up your Trezor once, at any time.",
verb="BACK UP",
verb_cancel="SKIP",
)
),
"backup_device",
ButtonRequestType.ResetDevice,
)
return result is trezorui2.CONFIRMED
async def confirm_path_warning(
@ -482,7 +547,7 @@ async def should_show_more(
br_code: ButtonRequestType = ButtonRequestType.Other,
icon: str = ui.ICON_DEFAULT,
icon_color: int = ui.ORANGE_ICON,
confirm: ButtonContent = None,
confirm: str | bytes | None = None,
major_confirm: bool = False,
) -> bool:
raise NotImplementedError

@ -58,4 +58,4 @@ async def continue_recovery(
subtext: str | None,
info_func: Callable | None,
) -> bool:
raise NotImplementedError
return False

@ -1,10 +1,35 @@
from typing import TYPE_CHECKING
from trezor import wire
from trezor.enums import ButtonRequestType
import trezorui2
from ..common import interact
from . import _RustLayout
if TYPE_CHECKING:
from trezor.enums import BackupType
from typing import Sequence
from typing import Sequence, List
def _split_share_into_pages(share_words: Sequence[str], per_page: int = 4) -> List[str]:
pages = []
current = ""
for i, word in enumerate(share_words):
if i % per_page == 0:
if i != 0:
pages.append(current)
current = ""
else:
current += "\n"
current += f"{i + 1}. {word}"
if current:
pages.append(current)
return pages
async def show_share_words(
@ -13,18 +38,75 @@ async def show_share_words(
share_index: int | None = None,
group_index: int | None = None,
) -> None:
raise NotImplementedError
async def confirm_word(
if share_index is None:
title = "RECOVERY SEED"
elif group_index is None:
title = f"RECOVERY SHARE #{share_index + 1}"
else:
title = f"GROUP {group_index + 1} - SHARE {share_index + 1}"
# result = await interact(
# ctx,
# _RustLayout(
# trezorui2.show_simple(
# title=title,
# description=f"Write down these {len(share_words)} words in the exact order:",
# button="SHOW WORDS",
# ),
# ),
# "confirm_backup_words",
# ButtonRequestType.ResetDevice,
# )
# if result != trezorui2.CONFIRMED:
# raise wire.ActionCancelled
pages = _split_share_into_pages(share_words)
result = await interact(
ctx,
_RustLayout(
trezorui2.show_share_words(
title=title,
pages=pages,
),
is_backup=True,
),
"backup_words",
ButtonRequestType.ResetDevice,
)
if result != trezorui2.CONFIRMED:
raise wire.ActionCancelled
async def select_word(
ctx: wire.GenericContext,
words: Sequence[str],
share_index: int | None,
share_words: Sequence[str],
offset: int,
checked_index: int,
count: int,
group_index: int | None = None,
) -> bool:
raise NotImplementedError
) -> str:
assert len(words) == 3
if share_index is None:
title: str = "CHECK SEED"
elif group_index is None:
title = f"CHECK SHARE #{share_index + 1}"
else:
title = f"CHECK G{group_index + 1} - SHARE {share_index + 1}"
result = await ctx.wait(
_RustLayout(
trezorui2.select_word(
title=title,
description=f"Select word {checked_index + 1} of {count}:",
words=(words[0].upper(), words[1].upper(), words[2].upper()),
)
)
)
if __debug__ and isinstance(result, str):
return result
assert isinstance(result, int) and 0 <= result <= 2
return words[result]
async def slip39_show_checklist(
@ -53,3 +135,28 @@ async def slip39_advanced_prompt_group_threshold(
ctx: wire.GenericContext, num_of_groups: int
) -> int:
raise NotImplementedError
async def show_warning_backup(ctx: wire.GenericContext, slip39: bool) -> None:
if slip39:
description = (
"Never make a digital copy of your shares and never upload them online."
)
else:
description = (
"Never make a digital copy of your seed and never upload it online."
)
result = await interact(
ctx,
_RustLayout(
trezorui2.show_info(
title=description,
button="OK, I UNDERSTAND",
allow_cancel=False,
)
),
"backup_warning",
ButtonRequestType.ResetDevice,
)
if result != trezorui2.CONFIRMED:
raise wire.ActionCancelled

@ -1724,7 +1724,7 @@
"TTui2_bitcoin-test_getaddress.py::test_ltc": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_bitcoin-test_getaddress.py::test_multisig": "f3c9e4df672d2acb27fc61238df1e2828294a6f1602f52f07deb908cd1eb2cd8",
"TTui2_bitcoin-test_getaddress.py::test_multisig_missing[False]": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_bitcoin-test_getaddress.py::test_multisig_missing[True]": "6ff1829ad3c148f012adffb37eb4bcc7570c10a8b95b0920bdbf6339a1bbc0d8",
"TTui2_bitcoin-test_getaddress.py::test_multisig_missing[True]": "d868aec455776eba425411e94901a649d386cadacbeaa11be2f5864c5f00084a",
"TTui2_bitcoin-test_getaddress.py::test_public_ckd": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_bitcoin-test_getaddress.py::test_tbtc": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_bitcoin-test_getaddress.py::test_tgrs": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
@ -2469,9 +2469,9 @@
"TTui2_nem-test_signtx_others.py::test_nem_signtx_importance_transfer": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_nem-test_signtx_others.py::test_nem_signtx_provision_namespace": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_nem-test_signtx_transfers.py::test_nem_signtx_encrypted_payload": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic": "c135119f81a060eb697e05249bbfcb269e8f8994d5d72f6b54701c7f7aa071fa",
"TTui2_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic_with_levy": "c135119f81a060eb697e05249bbfcb269e8f8994d5d72f6b54701c7f7aa071fa",
"TTui2_nem-test_signtx_transfers.py::test_nem_signtx_multiple_mosaics": "06d2cde39452bacb20743fd760e48b497b2d143b1f6dfeb0c25a1d14a3e8a127",
"TTui2_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic": "2491e0b47ce4509b549cc402916f99832024737700b407ccb51e8f6cd5fa63bf",
"TTui2_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic_with_levy": "2491e0b47ce4509b549cc402916f99832024737700b407ccb51e8f6cd5fa63bf",
"TTui2_nem-test_signtx_transfers.py::test_nem_signtx_multiple_mosaics": "709a7db8f7c70bf31db8050f42512e43ad83be5fc3e5bd710b02e1288bc09890",
"TTui2_nem-test_signtx_transfers.py::test_nem_signtx_simple": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_nem-test_signtx_transfers.py::test_nem_signtx_unknown_mosaic": "f32f3ae5971dc6d1407ec49a4225e3128c67cd1f6298ac588d9e2809a58496cb",
"TTui2_nem-test_signtx_transfers.py::test_nem_signtx_xem_as_mosaic": "08add8db0fa244b5ac5b0ea459a210d6f897df57407351904c9f23d785818140",
@ -2480,55 +2480,55 @@
"TTui2_reset_recovery-test_recovery_bip39_dryrun.py::test_bad_parameters[passphrase_protection-True]": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_reset_recovery-test_recovery_bip39_dryrun.py::test_bad_parameters[pin_protection-True]": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_reset_recovery-test_recovery_bip39_dryrun.py::test_bad_parameters[u2f_counter-1]": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_reset_recovery-test_recovery_bip39_dryrun.py::test_dry_run": "af8dcf90f3fd9e92334af8cbcd966ad08091cc873f1942b07ace3c52b5518b2b",
"TTui2_reset_recovery-test_recovery_bip39_dryrun.py::test_invalid_seed_core": "af8dcf90f3fd9e92334af8cbcd966ad08091cc873f1942b07ace3c52b5518b2b",
"TTui2_reset_recovery-test_recovery_bip39_dryrun.py::test_seed_mismatch": "af8dcf90f3fd9e92334af8cbcd966ad08091cc873f1942b07ace3c52b5518b2b",
"TTui2_reset_recovery-test_recovery_bip39_dryrun.py::test_dry_run": "6163bdd261809e749bcc2eed7882b994eae98b5db28a4a6c27ded2c0ecce4294",
"TTui2_reset_recovery-test_recovery_bip39_dryrun.py::test_invalid_seed_core": "6163bdd261809e749bcc2eed7882b994eae98b5db28a4a6c27ded2c0ecce4294",
"TTui2_reset_recovery-test_recovery_bip39_dryrun.py::test_seed_mismatch": "6163bdd261809e749bcc2eed7882b994eae98b5db28a4a6c27ded2c0ecce4294",
"TTui2_reset_recovery-test_recovery_bip39_dryrun.py::test_uninitialized": "8711e2fa6f7b301add7641e08ffb4bacf29bcd41530b1dd435fdbddb49b4bdf8",
"TTui2_reset_recovery-test_recovery_bip39_t2.py::test_already_initialized": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_reset_recovery-test_recovery_bip39_t2.py::test_tt_nopin_nopassphrase": "6d9ea6360e4dd1cd5d6d52e046be4dd7650337b4abfb5e25be6fe36133d78a4b",
"TTui2_reset_recovery-test_recovery_bip39_t2.py::test_tt_pin_passphrase": "6d9ea6360e4dd1cd5d6d52e046be4dd7650337b4abfb5e25be6fe36133d78a4b",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_abort": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_extra_share_entered": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_group_threshold_reached": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_noabort": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_same_share": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_secret[shares0-c2d2e26ad06023c60145f1-afc2dad5": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_secret[shares1-c41d5cf80fed71a008a3a0-eb47093e": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_secret_click_info_button[shares0-c2d2-850ffa77": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_secret_click_info_button[shares1-c41d-ca9ddec8": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_advanced_dryrun.py::test_2of3_dryrun": "f27a0e59dc9a6a4fe81d202d96996e1e21e674aeab019cebd0dc3d30fa886283",
"TTui2_reset_recovery-test_recovery_slip39_advanced_dryrun.py::test_2of3_invalid_seed_dryrun": "f27a0e59dc9a6a4fe81d202d96996e1e21e674aeab019cebd0dc3d30fa886283",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_1of1": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_abort": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_ask_word_number": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_noabort": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_recover_with_pin_passphrase": "19f6161fb065ed7bbe02591e8d5785bb94158a26dc2529f2afe49e321d52d671",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_same_share": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares0-491b795b80fc21ccdf466c0fbc98c8fc]": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares1-b770e0da1363247652de97a39-a50896b7": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[0]": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[1]": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[2]": "f2ca361222973de3d635839e3a860231077127c4f7d85069d5b64a6728a198da",
"TTui2_reset_recovery-test_recovery_slip39_basic_dryrun.py::test_2of3_dryrun": "f27a0e59dc9a6a4fe81d202d96996e1e21e674aeab019cebd0dc3d30fa886283",
"TTui2_reset_recovery-test_recovery_slip39_basic_dryrun.py::test_2of3_invalid_seed_dryrun": "f27a0e59dc9a6a4fe81d202d96996e1e21e674aeab019cebd0dc3d30fa886283",
"TTui2_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Bip39-backup_flow_bip39]": "82266d0d8b0baaa8212546a0d538d2d54168c874a213a35fabdb4043662982de",
"TTui2_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Slip39_Advanced-bac-f67baa1c": "82266d0d8b0baaa8212546a0d538d2d54168c874a213a35fabdb4043662982de",
"TTui2_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Slip39_Basic-backup-6348e7fe": "82266d0d8b0baaa8212546a0d538d2d54168c874a213a35fabdb4043662982de",
"TTui2_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Bip39-backup_flow_bip39]": "8eefc05a61808386dd4b6ce4f96e7e963d019893c1d9047d8a1b86d7cc2bc1a0",
"TTui2_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Slip39_Advanced-backup-dcbda5cf": "809bc3086a900cc5bc0ee3a9d7218dc9b6b1da52543009e444e0bc3b6bb1571b",
"TTui2_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Slip39_Basic-backup_fl-1577de4d": "809bc3086a900cc5bc0ee3a9d7218dc9b6b1da52543009e444e0bc3b6bb1571b",
"TTui2_reset_recovery-test_recovery_bip39_t2.py::test_tt_nopin_nopassphrase": "3919d9404e9f9a4880bd084edbfa02fbb04641008e04b83458633691e69bf239",
"TTui2_reset_recovery-test_recovery_bip39_t2.py::test_tt_pin_passphrase": "3919d9404e9f9a4880bd084edbfa02fbb04641008e04b83458633691e69bf239",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_abort": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_extra_share_entered": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_group_threshold_reached": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_noabort": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_same_share": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_secret[shares0-c2d2e26ad06023c60145f1-afc2dad5": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_secret[shares1-c41d5cf80fed71a008a3a0-eb47093e": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_secret_click_info_button[shares0-c2d2-850ffa77": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_advanced.py::test_secret_click_info_button[shares1-c41d-ca9ddec8": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_advanced_dryrun.py::test_2of3_dryrun": "7a5048ee96f76bb2e2a6d64fd89dfc22eb6fe792eaa769058249d0f552ee59d3",
"TTui2_reset_recovery-test_recovery_slip39_advanced_dryrun.py::test_2of3_invalid_seed_dryrun": "7a5048ee96f76bb2e2a6d64fd89dfc22eb6fe792eaa769058249d0f552ee59d3",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_1of1": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_abort": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_ask_word_number": "e53306364b3a4cc2d23da5adeafa6f02fd946dcf042c6c77efd1ce221a319ea8",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_noabort": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_recover_with_pin_passphrase": "ff0120b13a8ec8ecfe3a70d3dce62a9eaafa116632284d85983e7d1f040d6d4a",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_same_share": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares0-491b795b80fc21ccdf466c0fbc98c8fc]": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares1-b770e0da1363247652de97a39-a50896b7": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[0]": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[1]": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[2]": "4b94af756dc9288eca587760a32e66abcac622da498d6a9b5bfb5f965f295d2f",
"TTui2_reset_recovery-test_recovery_slip39_basic_dryrun.py::test_2of3_dryrun": "7a5048ee96f76bb2e2a6d64fd89dfc22eb6fe792eaa769058249d0f552ee59d3",
"TTui2_reset_recovery-test_recovery_slip39_basic_dryrun.py::test_2of3_invalid_seed_dryrun": "7a5048ee96f76bb2e2a6d64fd89dfc22eb6fe792eaa769058249d0f552ee59d3",
"TTui2_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Bip39-backup_flow_bip39]": "4f4ba72d808efd3b1c90493dc287fe22d64f1fa28d1b055c05b4b13bb662946e",
"TTui2_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Slip39_Advanced-bac-f67baa1c": "1d2e196f1f194c41aa4ddc6a5968fea311583f2b1447812fee59410fd19aaca0",
"TTui2_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Slip39_Basic-backup-6348e7fe": "b99b45445bb22a6a2954c87c895770580e069d61eebd5bb13f0e7411d69b692e",
"TTui2_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Bip39-backup_flow_bip39]": "19654fc05ca617863fd0788e34bb57a0c209d863f780f16e4ecb952446ca6409",
"TTui2_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Slip39_Advanced-backup-dcbda5cf": "536cf8b5905ed9e36b37bbef57567e3bfc0a48e192073d81e2bfce1da3cb8e03",
"TTui2_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Slip39_Basic-backup_fl-1577de4d": "c36cf19489c96fc349d584d9cd3ba4f9ff86f16ad3d202d55dc0570a5b0b5b9e",
"TTui2_reset_recovery-test_reset_bip39_t2.py::test_already_initialized": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_reset_recovery-test_reset_bip39_t2.py::test_failed_pin": "049ce514a8f8570d1a7fa948930226a2df8b4f3ba6fa823dd54a387a3571437d",
"TTui2_reset_recovery-test_reset_bip39_t2.py::test_reset_device": "6d9ea6360e4dd1cd5d6d52e046be4dd7650337b4abfb5e25be6fe36133d78a4b",
"TTui2_reset_recovery-test_reset_bip39_t2.py::test_reset_device_192": "6d9ea6360e4dd1cd5d6d52e046be4dd7650337b4abfb5e25be6fe36133d78a4b",
"TTui2_reset_recovery-test_reset_bip39_t2.py::test_reset_device_pin": "6d9ea6360e4dd1cd5d6d52e046be4dd7650337b4abfb5e25be6fe36133d78a4b",
"TTui2_reset_recovery-test_reset_bip39_t2.py::test_reset_failed_check": "6d9ea6360e4dd1cd5d6d52e046be4dd7650337b4abfb5e25be6fe36133d78a4b",
"TTui2_reset_recovery-test_reset_recovery_bip39.py::test_reset_recovery": "6d9ea6360e4dd1cd5d6d52e046be4dd7650337b4abfb5e25be6fe36133d78a4b",
"TTui2_reset_recovery-test_reset_recovery_slip39_advanced.py::test_reset_recovery": "6d9ea6360e4dd1cd5d6d52e046be4dd7650337b4abfb5e25be6fe36133d78a4b",
"TTui2_reset_recovery-test_reset_recovery_slip39_basic.py::test_reset_recovery": "6d9ea6360e4dd1cd5d6d52e046be4dd7650337b4abfb5e25be6fe36133d78a4b",
"TTui2_reset_recovery-test_reset_slip39_advanced.py::test_reset_device_slip39_advanced": "6d9ea6360e4dd1cd5d6d52e046be4dd7650337b4abfb5e25be6fe36133d78a4b",
"TTui2_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic": "6d9ea6360e4dd1cd5d6d52e046be4dd7650337b4abfb5e25be6fe36133d78a4b",
"TTui2_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic_256": "6d9ea6360e4dd1cd5d6d52e046be4dd7650337b4abfb5e25be6fe36133d78a4b",
"TTui2_reset_recovery-test_reset_bip39_t2.py::test_failed_pin": "e34eb8420d9e74571c36e39352ba2308d90a021b2f5ef2e78afb167764ea931d",
"TTui2_reset_recovery-test_reset_bip39_t2.py::test_reset_device": "23bf8446c0c9b9f948b9734b0cb4062d004e6b7b02b950e557ad34e47b4b3889",
"TTui2_reset_recovery-test_reset_bip39_t2.py::test_reset_device_192": "44f01af26a3a1a6abde60a60de781b69bab9d7cf41c50ca16522e423e01da9a5",
"TTui2_reset_recovery-test_reset_bip39_t2.py::test_reset_device_pin": "32ce727d1add7d2150296a10332250f768544a088e35a123091c6a5ff7d8b549",
"TTui2_reset_recovery-test_reset_bip39_t2.py::test_reset_failed_check": "79e75a5a75aaae9c05f598e5ef273734d8de3b9416bd747a9d58326d57090b1f",
"TTui2_reset_recovery-test_reset_recovery_bip39.py::test_reset_recovery": "26df7da23999be182499ccafc8252513afdb0d0e288adbe37b393cf80a7e0662",
"TTui2_reset_recovery-test_reset_recovery_slip39_advanced.py::test_reset_recovery": "92a0fd39f25845744194dc1ae04d5eebf268f658161ab7e685b4179d2c092e82",
"TTui2_reset_recovery-test_reset_recovery_slip39_basic.py::test_reset_recovery": "38eacc7bb14cdbd21bcc971cd2916f288b7929bd7b4e9cf2d49c66a81b981126",
"TTui2_reset_recovery-test_reset_slip39_advanced.py::test_reset_device_slip39_advanced": "92a0fd39f25845744194dc1ae04d5eebf268f658161ab7e685b4179d2c092e82",
"TTui2_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic": "38eacc7bb14cdbd21bcc971cd2916f288b7929bd7b4e9cf2d49c66a81b981126",
"TTui2_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic_256": "38eacc7bb14cdbd21bcc971cd2916f288b7929bd7b4e9cf2d49c66a81b981126",
"TTui2_ripple-test_get_address.py::test_ripple_get_address": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_ripple-test_get_address.py::test_ripple_get_address_other": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_ripple-test_sign_tx.py::test_ripple_sign_invalid_fee": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
@ -2619,26 +2619,26 @@
"TTui2_test_msg_backup_device.py::test_interrupt_backup_fails": "a8b5bc47867681b496da4b7473cde4fa43027c01fb071c2b0dcf97804809643f",
"TTui2_test_msg_backup_device.py::test_no_backup_fails": "ffc38ab2b61939fea6883a4805b2a4eb17a0be03afe0fed3b1cca492b50bb25c",
"TTui2_test_msg_backup_device.py::test_no_backup_show_entropy_fails": "8711e2fa6f7b301add7641e08ffb4bacf29bcd41530b1dd435fdbddb49b4bdf8",
"TTui2_test_msg_change_wipe_code_t2.py::test_set_pin_to_wipe_code": "b8e61812384abdef4b074655bd10e8a5166ec066911de7636064b3dd81dc490f",
"TTui2_test_msg_change_wipe_code_t2.py::test_set_remove_wipe_code": "e56192b67b4fd4ee741ea190408b7af0fb95336312898db4cf54d73f752364b1",
"TTui2_test_msg_change_wipe_code_t2.py::test_set_pin_to_wipe_code": "7f9c7e2550d4e515c7c9785a11dfcc2ce583925024ea2f52c859dc96de681afc",
"TTui2_test_msg_change_wipe_code_t2.py::test_set_remove_wipe_code": "b09db51b47e37ec94d4a2d8b063e1ed0ad95cb11215f43acf10453aadf7b7bb2",
"TTui2_test_msg_change_wipe_code_t2.py::test_set_wipe_code_mismatch": "8fd746c535ec5add348b76002a7936cc85c3206edbb59f225ad075912329452d",
"TTui2_test_msg_change_wipe_code_t2.py::test_set_wipe_code_to_pin": "25eac0cb6ea45c0cb9cfcad3b4ac3ec33af9212a7b812370c8132ef9f14c7700",
"TTui2_test_msg_changepin_t2.py::test_change_failed": "e207e2c62f6930e9e112d7a1a31b9a66c14580df8aac82ea40e2f243d987e878",
"TTui2_test_msg_changepin_t2.py::test_change_invalid_current": "1aa0bcb26493a94c4b8c4b6aec4080a00acce8f7fc9e7e9058dc227ebd0d79d1",
"TTui2_test_msg_changepin_t2.py::test_change_pin": "431ef817370e02d85a05d1a96b96f44d034c16303aa41b4ef66eeca664657ae2",
"TTui2_test_msg_changepin_t2.py::test_remove_pin": "9c80fc89ab9a3b9a5cdc9f5017caae777ce7727895a91169e2625d40f7dd88ef",
"TTui2_test_msg_changepin_t2.py::test_change_invalid_current": "9dce14051a6872469af20e9e8d03fe033908e32837df6a9dc31feb2db15bf398",
"TTui2_test_msg_changepin_t2.py::test_change_pin": "bef4ccf69a801159487ac24ff1218953e5592a6da618d4f10bcece03e42283cc",
"TTui2_test_msg_changepin_t2.py::test_remove_pin": "7770b9d9ba1c74f2184bf4413816fd20722996c12b9ed67880a45fd674cf8a16",
"TTui2_test_msg_changepin_t2.py::test_set_failed": "391b309cadaefcaab9086f7e003faec88b7e38c13f2738b5ad1aa4bfd5d89566",
"TTui2_test_msg_changepin_t2.py::test_set_pin": "f66d5c7faffdb91a739061b7f8cc059e1079c379e80e28aef79136f8af0ce96c",
"TTui2_test_msg_changepin_t2.py::test_set_pin": "8240ad8ff105e7cbc3e01e3cc917b55b177f3a7e67643e76678d49f92e7b0a04",
"TTui2_test_msg_loaddevice.py::test_load_device_1": "eeb5afb34b4bbf42b8c635fdd34bae5c1e3693facb16e6d64e629746612a2c3f",
"TTui2_test_msg_loaddevice.py::test_load_device_2": "a95020926a62b4078cb0034f6e7a772e49fc42121c9197b534437e26c306a994",
"TTui2_test_msg_loaddevice.py::test_load_device_slip39_advanced": "eeb5afb34b4bbf42b8c635fdd34bae5c1e3693facb16e6d64e629746612a2c3f",
"TTui2_test_msg_loaddevice.py::test_load_device_slip39_basic": "eeb5afb34b4bbf42b8c635fdd34bae5c1e3693facb16e6d64e629746612a2c3f",
"TTui2_test_msg_loaddevice.py::test_load_device_utf": "7eddfcc018eb3b5847e2617b1a9495632430ca5494f69063082a5063c5702dcf",
"TTui2_test_msg_ping.py::test_ping": "9b44725459426439bc27f2cf72ee926ab7146f3ee1236d197382524cdf9a89a1",
"TTui2_test_msg_sd_protect.py::test_enable_disable": "3d007f86722cf8f74c0544a8f03ef12b5be0e1da880c6d2543527116a2d6aa2c",
"TTui2_test_msg_sd_protect.py::test_refresh": "cef6f6f310d38678b9a70e3d6003f815b5501bb4360de1f47052889c3e0a3c3f",
"TTui2_test_msg_sd_protect.py::test_wipe": "41fc0f48b51daedef1ca19181b336a2b35117727ce64393bd1c2ae2e6b772e55",
"TTui2_test_msg_wipedevice.py::test_autolock_not_retained": "54c7800f784832b08e5505712e4f9e7052f49870ea1c50a66ed6520c97be166d",
"TTui2_test_msg_sd_protect.py::test_enable_disable": "1e64e5d08faac781f2bbba45b114a588c8a63d5a1865deaa0bc11c67ae891ea9",
"TTui2_test_msg_sd_protect.py::test_refresh": "d295a23bfc9b0fdef75d6732a5dd7fea7059a05fc566c599eddef75dfc05fcbb",
"TTui2_test_msg_sd_protect.py::test_wipe": "d6e2c4224f6d6970c9339bb29c08f8e88308fcfd9ef6bac2cd6f56b7a520747a",
"TTui2_test_msg_wipedevice.py::test_autolock_not_retained": "5200f217377bac4a795e1d5bb5963d4bb03a0ec6875a3272faca2572f8c7da2e",
"TTui2_test_msg_wipedevice.py::test_wipe_device": "36fd19373828ac579ae2e0eaf34c050ac9ea95596cfe38c447737acba86ec706",
"TTui2_test_passphrase_slip39_advanced.py::test_128bit_passphrase": "68e7d02ee3038fa20f0ccc226abdc29c422aa0d3b0c54533869276cd08a7a5b8",
"TTui2_test_passphrase_slip39_advanced.py::test_256bit_passphrase": "68e7d02ee3038fa20f0ccc226abdc29c422aa0d3b0c54533869276cd08a7a5b8",
@ -2649,7 +2649,7 @@
"TTui2_test_pin.py::test_incorrect_pin_t2": "cecd9cc23e1fab56f7df9c0a88b309f5fdd9f29ef97e0f5ba0b808cea2d11759",
"TTui2_test_pin.py::test_no_protection": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",
"TTui2_test_protection_levels.py::test_apply_settings": "294a58f6e0222746f27bdf80014de14cf0b2d298bf806456ee94fd814e301cba",
"TTui2_test_protection_levels.py::test_change_pin_t2": "cfcb922326b22471bd868eb355b1e9c18d34a8c425e33f8c5b52fad15f357b0f",
"TTui2_test_protection_levels.py::test_change_pin_t2": "733e6e94ad06fdb8f270a0bc50ba613de7fd40cff2f764f4828f4ffd7c3c285a",
"TTui2_test_protection_levels.py::test_get_address": "ef09d088bf4ca767162d5017748158bb8dda9849ccb0bf9ca5acf32b872e260c",
"TTui2_test_protection_levels.py::test_get_entropy": "7eadf62627e7a2c5a69b94c72eb4daca0153afb93ab8a12fd85d0d4ddc0a5a1d",
"TTui2_test_protection_levels.py::test_get_public_key": "ef09d088bf4ca767162d5017748158bb8dda9849ccb0bf9ca5acf32b872e260c",
@ -2663,7 +2663,7 @@
"TTui2_test_protection_levels.py::test_unlocked": "ed7d5e2c6bac6b7e1ea4f23e8a91a1337e9bb6a03e093d69fb16df686f2fe68a",
"TTui2_test_protection_levels.py::test_verify_message_t2": "23efc0636e09bed8a73ac25ec6f760adbee906e777833c140d12355248959927",
"TTui2_test_protection_levels.py::test_wipe_device": "40fdf3dafe49468bf8f948f36aa510927016f4803c1fb2d1d170fc40dff5c052",
"TTui2_test_sdcard.py::test_sd_format": "25fc8238413dac9aa7ff503d46de66351262400dfa9298b129e32a2e14f8df8c",
"TTui2_test_sdcard.py::test_sd_format": "53a16049a6ab7df7e5eb63f748e0e449f33b82013373ab8658238f9ac13dd3e3",
"TTui2_test_sdcard.py::test_sd_no_format": "e48ac8dc3f81340d89746a9a6bc2b89f8ebce54568c4c1805e626178ff1c509c",
"TTui2_test_sdcard.py::test_sd_protect_unlock": "3ccb135f2a39a727be85f45ce5472c3c7439792239f990264f78848e851cd56d",
"TTui2_test_session.py::test_cannot_resume_ended_session": "f03b50df7f4a161078fa903c44f37272961b70358d4014d30a12888e1fd2caf1",

Loading…
Cancel
Save