refactor(core): refactoring the function calls of display backlight driver in RUST so that the u16 data types have been converted to u8 ones. The code has been reviewed whether it's safe - no problems detected.
What changed, and why it matters
This is a code cleanup change in the Trezor hardware wallet's screen-brightness controls. It changes internal number types from 16-bit to 8-bit to match the display driver, and removes temporary workarounds that converted the values. The commit message says the code was reviewed and no safety problems were found. There is no indication this fixes an active security bug; it is a defensive type-safety refactor.
Treat as a normal refactor. No urgent action required. If auditing, verify that `theme::backlight::get_backlight_min/max/normal` always return values within `u8` range and that downstream consumers of `NumberInputSliderDialogMsg::Changed` expect `u8`.
Security signals we found
Type narrowing from u16 to u8 to match driver API, reducing risk of out-of-range backlight values
Removal of fallback `display::set_backlight(255)` branches that previously executed on conversion failure
Addition of debug_assert!(min < max) in NumberInputSliderDialog::new
Intermediate arithmetic still uses u16 to avoid 8-bit overflow during percentage scaling
Evidence from the diff
The commit refactors Rust UI components that handle display backlight brightness. It converts NumberInputSliderDialog, NumberInputSlider, SetBrightnessScreen, and VerticalSlider from u16 to u8 for min/max/value/percentage fields, matching the display::set_backlight(u8) driver signature. It removes explicit try_into() fallbacks and .into() casts in set_brightness.rs, brightness_screen.rs, and ui_firmware.rs. A debug_assert!(min < max) is added to NumberInputSliderDialog. The calculations that mix percentages and values now cast to u16 for intermediate arithmetic and truncate back to u8.
Changed components
core/embed/rust/src/ui/layout_bolt/component/number_input_slider.rscore/embed/rust/src/ui/layout_bolt/component/set_brightness.rscore/embed/rust/src/ui/layout_eckhart/firmware/brightness_screen.rscore/embed/rust/src/ui/layout_eckhart/ui_firmware.rsInspect captured patch +30 / −44
diff --git a/core/embed/rust/src/ui/layout_bolt/component/number_input_slider.rs b/core/embed/rust/src/ui/layout_bolt/component/number_input_slider.rs
index e652f8ec..7b40a4b0 100644
--- a/core/embed/rust/src/ui/layout_bolt/component/number_input_slider.rs
+++ b/core/embed/rust/src/ui/layout_bolt/component/number_input_slider.rs
@@ -9,7 +9,7 @@ use crate::ui::{
use super::{theme, Button, ButtonMsg};
pub enum NumberInputSliderDialogMsg {
- Changed(u16),
+ Changed(u8),
Confirmed,
Cancelled,
}
@@ -22,7 +22,8 @@ pub struct NumberInputSliderDialog {
}
impl NumberInputSliderDialog {
- pub fn new(min: u16, max: u16, init_value: u16) -> Self {
+ pub fn new(min: u8, max: u8, init_value: u8) -> Self {
+ debug_assert!(min < max);
Self {
area: Rect::zero(),
input: NumberInputSlider::new(min, max, init_value).into_child(),
@@ -35,7 +36,7 @@ impl NumberInputSliderDialog {
}
}
- pub fn value(&self) -> u16 {
+ pub fn value(&self) -> u8 {
self.input.inner().value
}
}
@@ -91,13 +92,13 @@ impl crate::trace::Trace for NumberInputSliderDialog {
pub struct NumberInputSlider {
area: Rect,
touch_area: Rect,
- min: u16,
- max: u16,
- value: u16,
+ min: u8,
+ max: u8,
+ value: u8,
}
impl NumberInputSlider {
- pub fn new(min: u16, max: u16, value: u16) -> Self {
+ pub fn new(min: u8, max: u8, value: u8) -> Self {
let value = value.clamp(min, max);
Self {
area: Rect::zero(),
@@ -108,12 +109,12 @@ impl NumberInputSlider {
}
}
- pub fn slider_eval(&mut self, pos: Point, ctx: &mut EventCtx) -> Option<u16> {
+ pub fn slider_eval(&mut self, pos: Point, ctx: &mut EventCtx) -> Option<u8> {
if self.touch_area.contains(pos) {
let filled = pos.x - self.area.x0;
let filled = filled.clamp(0, self.area.width());
let val_pct = (filled as u16 * 100) / self.area.width() as u16;
- let val = (val_pct * (self.max - self.min)) / 100 + self.min;
+ let val = ((val_pct * (self.max - self.min) as u16) / 100) as u8 + self.min;
if val != self.value {
self.value = val;
@@ -126,7 +127,7 @@ impl NumberInputSlider {
}
impl Component for NumberInputSlider {
- type Msg = u16;
+ type Msg = u8;
fn place(&mut self, bounds: Rect) -> Rect {
self.area = bounds;
@@ -146,7 +147,7 @@ impl Component for NumberInputSlider {
}
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
- let val_pct = (100 * (self.value - self.min)) / (self.max - self.min);
+ let val_pct = (100 * (self.value - self.min) as u16) / (self.max - self.min) as u16;
shape::Bar::new(self.area)
.with_radius(2)
diff --git a/core/embed/rust/src/ui/layout_bolt/component/set_brightness.rs b/core/embed/rust/src/ui/layout_bolt/component/set_brightness.rs
index 3f9075ae..dd644f29 100644
--- a/core/embed/rust/src/ui/layout_bolt/component/set_brightness.rs
+++ b/core/embed/rust/src/ui/layout_bolt/component/set_brightness.rs
@@ -19,9 +19,9 @@ pub struct SetBrightnessDialog(NumberInputSliderDialog);
impl SetBrightnessDialog {
pub fn new(current: u8) -> Self {
Self(NumberInputSliderDialog::new(
- theme::backlight::get_backlight_min().into(),
- theme::backlight::get_backlight_max().into(),
- current.into(),
+ theme::backlight::get_backlight_min(),
+ theme::backlight::get_backlight_max(),
+ current,
))
}
}
@@ -36,15 +36,7 @@ impl Component for SetBrightnessDialog {
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
match self.0.event(ctx, event) {
Some(NumberInputSliderDialogMsg::Changed(value)) => {
- // TODO: needs more analysis; why is "value" u16? Can it be changed to u8?
- // Original code: display::set_backlight(value.into());
- // Possible solution: display::set_backlight(value.try_into().unwrap());
- // It's not save. To rather use unwrap!() macro? Another solution below.
- if let Ok(val) = value.try_into() {
- display::set_backlight(val);
- } else {
- display::set_backlight(255);
- }
+ display::set_backlight(value);
None
}
Some(NumberInputSliderDialogMsg::Cancelled) => Some(CancelConfirmMsg::Cancelled),
diff --git a/core/embed/rust/src/ui/layout_eckhart/firmware/brightness_screen.rs b/core/embed/rust/src/ui/layout_eckhart/firmware/brightness_screen.rs
index 59598a54..371111f1 100644
--- a/core/embed/rust/src/ui/layout_eckhart/firmware/brightness_screen.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/firmware/brightness_screen.rs
@@ -25,7 +25,7 @@ pub struct SetBrightnessScreen {
impl SetBrightnessScreen {
const SLIDER_HEIGHT: i16 = 392;
- pub fn new(min: u16, max: u16, init_value: u16) -> Self {
+ pub fn new(min: u8, max: u8, init_value: u8) -> Self {
Self {
header: Header::new(TR::brightness__title.into()).with_right_button(
Button::with_icon(theme::ICON_CHECKMARK).styled(theme::button_header()),
@@ -87,17 +87,17 @@ impl crate::trace::Trace for SetBrightnessScreen {
struct VerticalSlider {
area: Rect,
touch_area: Rect,
- min: u16,
- max: u16,
- value: u16,
- val_pct: u16,
+ min: u8,
+ max: u8,
+ value: u8,
+ val_pct: u8,
touching: bool,
}
impl VerticalSlider {
const SLIDER_WIDTH: i16 = 120;
- pub fn new(min: u16, max: u16, value: u16) -> Self {
+ pub fn new(min: u8, max: u8, value: u8) -> Self {
debug_assert!(min < max);
let value = value.clamp(min, max);
Self {
@@ -113,15 +113,7 @@ impl VerticalSlider {
fn handle_touch(&mut self, pos: Point, ctx: &mut EventCtx) {
self.update_value(pos, ctx);
- // TODO: needs more analysis; why is "self.value" u16? Can it be changed to u8?
- // Original code: display::set_backlight(self.value.into());
- // Possible solution: display::set_backlight(self.value.try_into().unwrap());
- // It's not save. To rather use unwrap!() macro? Another solution below.
- if let Ok(val) = self.value.try_into() {
- display::set_backlight(val);
- } else {
- display::set_backlight(255);
- }
+ display::set_backlight(self.value);
ctx.request_paint();
}
@@ -136,7 +128,7 @@ impl VerticalSlider {
let filled = (proportional_area.y1 - pos.y).clamp(0, proportional_area.height());
let val_pct = (filled as u16 * 100) / proportional_area.height() as u16;
- let val = (val_pct * (self.max - self.min)) / 100 + self.min;
+ let val = ((val_pct * (self.max - self.min) as u16) / 100) as u8 + self.min;
if val != self.value {
ctx.request_paint();
@@ -184,7 +176,8 @@ impl Component for VerticalSlider {
}
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
- let val_pct = ((100 * (self.value - self.min)) / (self.max - self.min)).clamp(0, 100);
+ let val_pct =
+ ((100 * (self.value - self.min) as u16) / (self.max - self.min) as u16).clamp(0, 100);
// Square area for the slider
let (_, small_area) = self.area.split_bottom(Self::SLIDER_WIDTH);
diff --git a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs
index 4eba7684..18cff5ec 100644
--- a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs
@@ -1051,12 +1051,12 @@ impl FirmwareUI for UIEckhart {
// Set the brightness immediately so it is applied in the `_first_paint` UI
// layout function
unwrap!(storage::set_brightness(value));
- value.into()
+ value
}
- None => theme::backlight::get_backlight_normal().into(),
+ None => theme::backlight::get_backlight_normal(),
};
- let min = theme::backlight::get_backlight_min().into();
- let max = theme::backlight::get_backlight_max().into();
+ let min = theme::backlight::get_backlight_min();
+ let max = theme::backlight::get_backlight_max();
let screen = SetBrightnessScreen::new(min, max, init_value);
let layout = RootComponent::new(screen);
Why this scored 18/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.