What changed, and why it matters
This is a routine user-interface code cleanup for the Trezor hardware wallet. It changes how on-screen navigation controls (page counters and action bars) are shown, hiding them when text fits on a single page. There is no indication this fixes a security bug or introduces a security risk.
No security action needed; treat as normal UI refactor.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit refactors TextScreen placement logic in the Rust UI layer for the Eckhart layout. It moves layout code from a generic method into a non-generic free-standing function using dynamic dispatch to reduce flash usage, adds runtime visibility flags for the action bar and page counter, and only renders those elements when the content actually paginates. UI test fixture hashes are updated to match the new rendering behavior.
Changed components
core/embed/rust/src/ui/layout_eckhart/firmware/text_screen.rscore/embed/rust/src/ui/layout_eckhart/firmware/action_bar.rscore/embed/rust/src/ui/layout_eckhart/theme/mod.rstests/ui_tests/fixtures.jsonInspect captured patch +184 / −108
diff --git a/core/embed/rust/src/ui/layout_eckhart/firmware/action_bar.rs b/core/embed/rust/src/ui/layout_eckhart/firmware/action_bar.rs
index a24c2f0a..ac3935ed 100644
--- a/core/embed/rust/src/ui/layout_eckhart/firmware/action_bar.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/firmware/action_bar.rs
@@ -479,6 +479,10 @@ impl ActionBar {
};
None
}
+
+ pub fn is_paginate_only(&self) -> bool {
+ self.mode == Mode::PaginateOnly
+ }
}
impl Component for ActionBar {
diff --git a/core/embed/rust/src/ui/layout_eckhart/firmware/text_screen.rs b/core/embed/rust/src/ui/layout_eckhart/firmware/text_screen.rs
index bf767e8a..ed75b5bd 100644
--- a/core/embed/rust/src/ui/layout_eckhart/firmware/text_screen.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/firmware/text_screen.rs
@@ -11,7 +11,7 @@ use crate::{
Component, Event, EventCtx, FormattedText, Label, Paginate, TextLayout,
},
flow::Swipable,
- geometry::{Insets, Offset, Rect},
+ geometry::{Offset, Rect},
shape::Renderer,
util::Pager,
},
@@ -22,6 +22,9 @@ use super::{
ActionBar, ActionBarMsg, FidoAccountName, FidoCredential, Header, HeaderMsg, Hint,
};
+const SUBTITLE_HEIGHT: i16 = 44;
+const SUBTITLE_DOUBLE_HEIGHT: i16 = 76;
+
/// Full-screen component for rendering text.
///
/// T should be either `Paragraphs` or `FormattedText`.
@@ -38,6 +41,9 @@ pub struct TextScreen<T> {
action_bar: Option<ActionBar>,
page_limit: Option<u16>,
background: Option<ScreenBackground>,
+ // runtime visibility flags
+ show_action_bar: bool,
+ show_page_counter: bool,
// TODO: swipe handling
// TODO: animations
}
@@ -52,8 +58,6 @@ impl<T> TextScreen<T>
where
T: AllowedTextContent,
{
- const SUBTITLE_HEIGHT: i16 = 44;
- const SUBTITLE_DOUBLE_HEIGHT: i16 = 76;
const SUBTITLE_STYLE: TextStyle = theme::TEXT_MEDIUM_EXTRA_LIGHT;
pub fn new(content: T) -> Self {
@@ -65,6 +69,8 @@ where
action_bar: Some(ActionBar::new_paginate_only()),
page_limit: None,
background: None,
+ show_action_bar: false,
+ show_page_counter: false,
}
}
@@ -119,45 +125,6 @@ where
self.content.pager()
}
}
-
- fn place_content_with_hint(&mut self, bounds: Rect) {
- let compute_content_area = |area: Rect, has_header: bool| {
- // Introduce side insets + top padding if the header is not present
- let mut area = area.inset(SIDE_INSETS);
- if !has_header {
- area = area.inset(Insets::top(CONTENT_INSETS_NO_HEADER.top));
- }
- area
- };
-
- if let Some(hint) = &mut self.hint {
- if hint.is_page_counter() {
- let content_area = compute_content_area(bounds, self.header.is_some());
- self.content.place(content_area);
- // place page counter only if the content doesn't fit on a
- // single page
- if self.content.pager().total() > 1 {
- let (rest, hint_area) = bounds.split_bottom(hint.height());
- hint.place(hint_area);
- let content_area = compute_content_area(rest, self.header.is_some());
- // re-place content to account for the reduced area
- self.content.place(content_area);
- } else {
- self.hint = None;
- }
- } else {
- // always place non-page-counter hints at the bottom
- let (content_area, hint_area) = bounds.split_bottom(hint.height());
- let content_area = compute_content_area(content_area, self.header.is_some());
- hint.place(hint_area);
- self.content.place(content_area);
- }
- } else {
- let content_area = compute_content_area(bounds, self.header.is_some());
- self.content.place(content_area);
- }
- self.update_page(0);
- }
}
impl<T> Component for TextScreen<T>
@@ -167,46 +134,18 @@ where
type Msg = TextScreenMsg;
fn place(&mut self, bounds: Rect) -> Rect {
- let rest = if let Some(header) = &mut self.header {
- let (header_area, rest) = bounds.split_top(Header::HEADER_HEIGHT);
- header.place(header_area);
- rest
- } else {
- bounds
- };
-
- let rest = if let Some(action_bar) = &mut self.action_bar {
- let (rest, action_bar_area) = rest.split_bottom(ActionBar::ACTION_BAR_HEIGHT);
- action_bar.place(action_bar_area);
- rest
- } else {
- rest
- };
+ (self.show_action_bar, self.show_page_counter) = place_textscreen(
+ bounds,
+ self.header.as_mut(),
+ self.subtitle.as_mut(),
+ self.hint.as_mut(),
+ self.action_bar.as_mut(),
+ &mut self.content,
+ self.page_limit,
+ );
- let rest = if let Some(subtitle) = &mut self.subtitle {
- // Choose appropriate height for the subtitle
- let subtitle_height = if let LayoutFit::OutOfBounds { .. } =
- subtitle.text().map(|text| {
- TextLayout::new(Self::SUBTITLE_STYLE)
- .with_bounds(
- Rect::from_size(Offset::new(bounds.width(), Self::SUBTITLE_HEIGHT))
- .inset(SIDE_INSETS),
- )
- .fit_text(text)
- }) {
- Self::SUBTITLE_DOUBLE_HEIGHT
- } else {
- Self::SUBTITLE_HEIGHT
- };
-
- let (subtitle_area, rest) = rest.split_top(subtitle_height);
- subtitle.place(subtitle_area.inset(SIDE_INSETS));
- rest
- } else {
- rest
- };
-
- self.place_content_with_hint(rest);
+ // Reset to first page and refresh dependent UI
+ self.update_page(0);
bounds
}
@@ -222,17 +161,20 @@ where
_ => {}
}
}
- if let Some(msg) = self.action_bar.event(ctx, event) {
- match msg {
- ActionBarMsg::Cancelled => return Some(TextScreenMsg::Cancelled),
- ActionBarMsg::Confirmed => return Some(TextScreenMsg::Confirmed),
- ActionBarMsg::Prev => {
- self.update_page(self.content_pager().prev());
- return None;
- }
- ActionBarMsg::Next => {
- self.update_page(self.content_pager().next());
- return None;
+
+ if self.show_action_bar {
+ if let Some(msg) = self.action_bar.event(ctx, event) {
+ match msg {
+ ActionBarMsg::Cancelled => return Some(TextScreenMsg::Cancelled),
+ ActionBarMsg::Confirmed => return Some(TextScreenMsg::Confirmed),
+ ActionBarMsg::Prev => {
+ self.update_page(self.content_pager().prev());
+ return None;
+ }
+ ActionBarMsg::Next => {
+ self.update_page(self.content_pager().next());
+ return None;
+ }
}
}
}
@@ -245,8 +187,22 @@ where
}
self.header.render(target);
self.subtitle.render(target);
- self.hint.render(target);
- self.action_bar.render(target);
+
+ // Render hint conditionally (page counter only if we decided to show it)
+ if let Some(hint) = &self.hint {
+ let is_pc = hint.is_page_counter();
+ if !is_pc || self.show_page_counter {
+ hint.render(target);
+ }
+ }
+
+ // Render ActionBar only if visible
+ if self.show_action_bar {
+ if let Some(ab) = &self.action_bar {
+ ab.render(target);
+ }
+ }
+
self.content.render(target);
}
}
@@ -271,6 +227,123 @@ impl<'a, T> AllowedTextContent for Paragraphs<T> where T: ParagraphSource<'a> {}
impl<'a, T> AllowedTextContent for Checklist<T> where T: ParagraphSource<'a> {}
impl<F> AllowedTextContent for FidoCredential<F> where F: FidoAccountName {}
+// Non-generic helpers to reduce monomorphization of TextScreen<T>::place.
+// Only dynamic dispatch on content is used here.
+trait ContentOps {
+ fn place(&mut self, area: Rect);
+ fn pager(&self) -> Pager;
+}
+
+impl<T> ContentOps for T
+where
+ T: AllowedTextContent,
+{
+ fn place(&mut self, area: Rect) {
+ Component::place(self, area);
+ }
+ fn pager(&self) -> Pager {
+ Paginate::pager(self)
+ }
+}
+
+// Lay out the whole screen and decide which optional elements to show.
+// Returns (show_action_bar, show_page_counter).
+fn place_textscreen(
+ bounds: Rect,
+ header: Option<&mut Header>,
+ subtitle: Option<&mut Label<'static>>,
+ hint: Option<&mut Hint<'static>>,
+ action_bar: Option<&mut ActionBar>,
+ content: &mut dyn ContentOps,
+ page_limit: Option<u16>,
+) -> (bool, bool) {
+ // 1) Header
+ let has_header = header.is_some();
+ let rest = header.map_or(bounds, |h| {
+ let (header_area, rest) = bounds.split_top(Header::HEADER_HEIGHT);
+ h.place(header_area);
+ rest
+ });
+
+ // 2) Subtitle
+ let mut content_footer_area = subtitle.map_or(rest, |s| {
+ let subtitle_height = if let LayoutFit::OutOfBounds { .. } = s.text().map(|text| {
+ TextLayout::new(theme::TEXT_MEDIUM_EXTRA_LIGHT)
+ .with_bounds(
+ Rect::from_size(Offset::new(rest.width(), SUBTITLE_HEIGHT)).inset(SIDE_INSETS),
+ )
+ .fit_text(text)
+ }) {
+ SUBTITLE_DOUBLE_HEIGHT
+ } else {
+ SUBTITLE_HEIGHT
+ };
+ let (subtitle_area, rest) = rest.split_top(subtitle_height);
+ s.place(subtitle_area.inset(SIDE_INSETS));
+ rest
+ });
+
+ // Insets applied to content only
+ let mut content_insets = SIDE_INSETS;
+ if !has_header {
+ content_insets.top += CONTENT_INSETS_NO_HEADER.top;
+ }
+
+ // Helper to place content in area and get pager with optional limit
+ let mut place_and_pager = |area: Rect| -> Pager {
+ let content_area = area.inset(content_insets);
+ content.place(content_area);
+ let mut pager = content.pager();
+ if let Some(limit) = page_limit {
+ pager = pager.with_limit(limit);
+ }
+ pager
+ };
+
+ // 4) Compute pagination without AB/hint
+ let single_page_without_ab = place_and_pager(content_footer_area).total() <= 1;
+
+ // 5) Decide ActionBar visibility
+ let show_action_bar = match action_bar.as_ref() {
+ Some(ab) if !ab.is_paginate_only() => true,
+ Some(_) => !single_page_without_ab,
+ None => false,
+ };
+
+ if show_action_bar {
+ if let Some(ab) = action_bar {
+ let (rest, ab_area) = content_footer_area.split_bottom(ActionBar::ACTION_BAR_HEIGHT);
+ ab.place(ab_area);
+ content_footer_area = rest;
+ }
+ }
+
+ // 6) Recompute pagination after AB
+ let is_paginated_after_ab = place_and_pager(content_footer_area).total() > 1;
+
+ // 7) Page-counter hint decision
+ let hint_is_page_counter = matches!(hint, Some(ref h) if h.is_page_counter());
+ let mut show_page_counter = hint_is_page_counter && is_paginated_after_ab;
+
+ // 8) Place hint (if any) and final content
+ if let Some(h) = hint {
+ let show_hint_now = if hint_is_page_counter {
+ show_page_counter
+ } else {
+ true
+ };
+ if show_hint_now {
+ let (content_top_area, hint_area) = content_footer_area.split_bottom(h.height());
+ h.place(hint_area);
+ let _ = place_and_pager(content_top_area);
+ } else {
+ show_page_counter = false;
+ }
+ }
+
+ (show_action_bar, show_page_counter)
+}
+
#[cfg(feature = "ui_debug")]
impl<T> crate::trace::Trace for TextScreen<T>
where
diff --git a/core/embed/rust/src/ui/layout_eckhart/theme/mod.rs b/core/embed/rust/src/ui/layout_eckhart/theme/mod.rs
index fc9afcc9..b3904fcc 100644
--- a/core/embed/rust/src/ui/layout_eckhart/theme/mod.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/theme/mod.rs
@@ -79,6 +79,12 @@ pub const HEADER_HEIGHT: i16 = 96; // [px]
pub const SIDE_INSETS: Insets = Insets::sides(PADDING);
pub const ACTION_BAR_HEIGHT: i16 = 90; // [px]
pub const TEXT_VERTICAL_SPACING: i16 = 24; // [px]
+/// Where to place main content if no Header is used on the Screen
+pub const CONTENT_INSETS_NO_HEADER: Insets = Insets::new(38, PADDING, ACTION_BAR_HEIGHT, PADDING);
+/// Where to place main text of progress screens of bootloader and firmware
+pub const PROGRESS_TEXT_ORIGIN: Point = super::constant::SCREEN
+ .top_left()
+ .ofs(Offset::new(PADDING, CONTENT_INSETS_NO_HEADER.top));
// checklist settings
pub const CHECKLIST_CHECK_WIDTH: i16 = 32; // [px]
@@ -212,10 +218,3 @@ pub const TEXT_SMALL_GREY_EXTRA_LIGHT: TextStyle = TextStyle {
text_color: GREY_EXTRA_LIGHT,
..TEXT_SMALL
};
-
-/// Where to place main content if no Header is used on the Screen
-pub const CONTENT_INSETS_NO_HEADER: Insets = Insets::new(38, PADDING, ACTION_BAR_HEIGHT, PADDING);
-/// Where to place main text of progress screens of bootloader and firmware
-pub const PROGRESS_TEXT_ORIGIN: Point = super::constant::SCREEN
- .top_left()
- .ofs(Offset::new(PADDING, CONTENT_INSETS_NO_HEADER.top));
diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json
index f1d1f374..2d520ccd 100644
--- a/tests/ui_tests/fixtures.json
+++ b/tests/ui_tests/fixtures.json
@@ -28958,7 +28958,7 @@
"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "bde943df0ccabb0898301124c89abe89f57f8a629302c0cb45fcebc572c8aa3b",
"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_full_completion": "66680bf8dfa2f6ff4616657d0d88d2d919d36c7a1db4287da9d34fa2ba0d4c20",
"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_menu_close": "78cb5f9003ff80d63c162551f29fef295f6ad9b7168fb584ae730b9a7c8eb71f",
-"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "77aeafb12b4c42364a160913c968142b05d6e3a2abdb250d4abf705c476f0e38",
+"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "920b9e94ce8236ce4834eede89c2e20d7dab262841b8e6852b83127467f0e984",
"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_restart": "a604465720404d5fca83bc996e9ea1bda6d2824b02a40ef9ac94714986aaf578",
"T3W1_de_device_menu-test_auto_lock.py::test_auto_lock_battery_cancel": "11d3b157867889bd894fb55be54cc44b2025ea133856abdea6f683315acd21bd",
"T3W1_de_device_menu-test_auto_lock.py::test_auto_lock_battery_change": "77a048baa1f5ea62a256552742b6ed2ce058a06314e61d2eba120b45d31a35c6",
@@ -29062,7 +29062,7 @@
"T3W1_de_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "52cdf61484f9e795f543ab355285b9e5f3d0d0341fe4f300239d6068c20bf14b",
"T3W1_de_test_tutorial_eckhart.py::test_tutorial_full_completion": "f988cf288c3e58d2d5ab4268b26df6c2b584dddf8f3cf3852b5407a4098db35d",
"T3W1_de_test_tutorial_eckhart.py::test_tutorial_menu_close": "7688c261a8b5d78b23334e63aa06527b6a33d3131d34889300f208a2ed2cff79",
-"T3W1_de_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "b478a5c5b8fab845dab87bf1b7e6b58c3e163e42a5a76a08a4994bece47859a1",
+"T3W1_de_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "43e4e228ba0a58bf0c1d2b8ca08bfa45692713c86b0eef10af9e573af0c585ee",
"T3W1_de_test_tutorial_eckhart.py::test_tutorial_restart": "cce1f633042dfbc4dc4d62ff58fb23bfa8f877333fc71466834cd8fa86945c3c",
"T3W1_en_device_menu-test_auto_lock.py::test_auto_lock_battery_cancel": "1fba799e2a25332613e36618a9dd74c55206e93331e38af6699305bacc52fee8",
"T3W1_en_device_menu-test_auto_lock.py::test_auto_lock_battery_change": "1a61349335d26cc96f3618535f374f8bd14e20430e7a67a061712ef0b2c70b67",
@@ -29270,7 +29270,7 @@
"T3W1_es_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "f424d47060bd5918827ef1bd2c461b7507d51fbc60d429649b2cb1bae2eb247c",
"T3W1_es_test_tutorial_eckhart.py::test_tutorial_full_completion": "7e198fdafc3c6eecde77aeeb17ceb50b6c2d2e58a7c80872adbf81beea59bac6",
"T3W1_es_test_tutorial_eckhart.py::test_tutorial_menu_close": "e7afb35ed2282c1698d35e4ed42ff1d21fa5d52fa630ded1d3a1bdafbb27c442",
-"T3W1_es_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "a315c66064496afaf4e4ccb6a7900678470aae7c3462afa32f8b1efb6417f86a",
+"T3W1_es_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "a7fe4f57f9f00652ab0037af956eec07d8305bb7c0ffce514d12933eb08fd4f9",
"T3W1_es_test_tutorial_eckhart.py::test_tutorial_restart": "a40bd2d7b42521e139317fb6fe51507c3ea4c63f5e069632a00ee42a18317202",
"T3W1_fr_device_menu-test_auto_lock.py::test_auto_lock_battery_cancel": "eb59f464f9ee4438479b782580530c6b27bd4f19b3d0d6cd5e1a17eaf5b8e480",
"T3W1_fr_device_menu-test_auto_lock.py::test_auto_lock_battery_change": "a5b662c912fd0ba20ec3c76a55d6e4783c3613958cbde76a30df26105adf954f",
@@ -29374,7 +29374,7 @@
"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "71b49853f50506880f3254fd0cfd8e27693e284018533e54b0e8b77c608517df",
"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_full_completion": "3c5fae188d6e32372b33cb24329eb90e1b29dd93e75bb42d644dd36f513c4547",
"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_menu_close": "701080e2d1fbaf8ce5aa02e0325d118e3497f9cb6f443c87f2084a352fccc30f",
-"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "a78479d4d1728fdb4f33db301e7c77e8a93b3fb1dacdaf056a578b0fb3bb3c0e",
+"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "1639a2fc873968aefb07d38fc744df06e6766d9e355be160419f8f1566df615b",
"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_restart": "dc02c3bfef15c0c89e16ecea9d1d4a52b626a33cbe775673b401e7861bfed24a",
"T3W1_pt_device_menu-test_auto_lock.py::test_auto_lock_battery_cancel": "d13b1589af5355523f27393d9af5cd5ba064ec13427275fd8d00c2e970a2fed4",
"T3W1_pt_device_menu-test_auto_lock.py::test_auto_lock_battery_change": "87af5d356c5837012020f3833a4fbcb48013af9c18d6754d6473f068721f58ef",
@@ -29478,7 +29478,7 @@
"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "44304439ca00b55171fa1f665fe488ab143091da6ea9afd6f267bfac73149d0e",
"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_full_completion": "a2284d3bd87e22ff0a80ea763745ad4506433e0d9b8ca4f0fa9616c3975701b1",
"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_menu_close": "48aeee3f1a0a4ac2313b2b1bf52c43dc1068f3fc1e99fa73e02e7c4ada3a7c8f",
-"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "56ad271b1e3efed07bbe8d02221621ef29c8df849cf66a3d493795f7744a0719",
+"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "670b07e57aa0bed140897585f2bc02e209231da3f4a36ad9453f909bc7bbe18d",
"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_restart": "28ec1cef7cb297133855e19d01cda578ee89a94e8526801dc30b9aeaef8ff177"
},
"device_tests": {
@@ -35102,7 +35102,7 @@
"T3W1_es_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares0-491b795b80fc21ccdf466c0fb-ad8c45c0": "2049aa58a65869929dcd4337cec8aeed8034936475faa8c3c51dac55f1fba6fc",
"T3W1_es_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares1-644c905b0c4da21692f06fff3-30d0f8ca": "5995420e1dfb4927dc0f11409b68f91c86eb0b2b4f03faa3b862f004612984a6",
"T3W1_es_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares2-b770e0da1363247652de97a39-6af744e3": "7e2c7cf7fc072ce21266cd505edfa24013dcdfe8041b562dc11e80b8c6b31dd5",
-"T3W1_es_reset_recovery-test_recovery_slip39_basic.py::test_share_info_between_shares": "223321b2775762fe39f3b36470b68f2e1c4a488499f11ca6b11d72b289b708e7",
+"T3W1_es_reset_recovery-test_recovery_slip39_basic.py::test_share_info_between_shares": "71251f62a4421b8eaa911dcc59820a2772bc2f595f6df9895a74337ca20f2502",
"T3W1_es_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[0]": "d5583a5b408d9b8ac4e7bc2a7cda2317b63de45786cbc1688b663d0ed9517166",
"T3W1_es_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[1]": "1ecab773819453c06734b9c0285ea321925a3cb5252e85d21e5a8829a0f0453f",
"T3W1_es_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[2]": "ec2f170a10e911d1ee21425b0052401637c50087d7a25251f3154da3a0b5468c",
@@ -38109,7 +38109,7 @@
"T3W1_pt_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares0-491b795b80fc21ccdf466c0fb-ad8c45c0": "e0e62da2dddb60b07930534b9c7ffe6f21a2ee1f47ceac5f763bee7de50e379e",
"T3W1_pt_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares1-644c905b0c4da21692f06fff3-30d0f8ca": "bf9a4894cdcd8f67eb3791acc53553285573a75949aa57db390bc3a40c58c708",
"T3W1_pt_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares2-b770e0da1363247652de97a39-6af744e3": "e15c02730b22ce281666039e75c63339ef4eb84bbee78e226319ee4b90fb7d11",
-"T3W1_pt_reset_recovery-test_recovery_slip39_basic.py::test_share_info_between_shares": "3fcf17049744e25e3f5373bd4ba03a7fef9f49b1262041d1350e9f71fba71f28",
+"T3W1_pt_reset_recovery-test_recovery_slip39_basic.py::test_share_info_between_shares": "0e00a7cf403a0adf214b03df8713809b672ab1b28861b748bd7af240540a4f5c",
"T3W1_pt_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[0]": "6a2aa7d066099025661a5a42d914c863912dbc262bf1ae7369137e068e5f1161",
"T3W1_pt_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[1]": "0bfd1e54310062a0a92dbf9037ab451e0548d463e87e81eab7fff6f72253a873",
"T3W1_pt_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[2]": "21c502b30f0a490103c8980662921d2dd1a90b0c35f7d7a2886393e2f6ef5a74",
Why this scored 14/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.