bitbox02_rust/hal: add ui enter string
What changed, and why it matters
This commit is a routine internal code cleanup in the BitBox02 firmware's Rust code. It introduces a new hardware-abstraction-layer (HAL) structure for string-entry screens and updates existing code to use it. There is no indication of a security bug, vulnerability fix, or behavior change affecting users.
No security action required. Review as normal refactoring if desired.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change refactors the UI HAL by adding hal::ui::EnterStringParams and replacing direct use of workflow::trinary_input_string::Params (which was a re-export of bitbox02::ui::TrinaryInputStringParams) with the new HAL type. Implementations in hal::bitbox02::ui and hal::testing::ui are updated, and callsites in bip85.rs, bitcoin/registration.rs, workflow/mnemonic.rs, and workflow/password.rs are adapted. A conversion helper with exhaustive unit tests is added. The trinary_input_string workflow module is reduced to only the CanCancel enum. No functional or security-relevant behavior is altered.
Changed components
src/rust/bitbox02-rust/src/hal/bitbox02/ui.rssrc/rust/bitbox02-rust/src/hal/testing/ui.rssrc/rust/bitbox02-rust/src/hal/ui.rssrc/rust/bitbox02-rust/src/hww/api/bip85.rssrc/rust/bitbox02-rust/src/hww/api/bitcoin/registration.rssrc/rust/bitbox02-rust/src/workflow/mnemonic.rssrc/rust/bitbox02-rust/src/workflow/password.rssrc/rust/bitbox02-rust/src/workflow/trinary_input_string.rsInspect captured patch +87 / −18
diff --git a/src/rust/bitbox02-rust/src/hal/bitbox02/ui.rs b/src/rust/bitbox02-rust/src/hal/bitbox02/ui.rs
index 7f19aa4..39f84a4 100644
--- a/src/rust/bitbox02-rust/src/hal/bitbox02/ui.rs
+++ b/src/rust/bitbox02-rust/src/hal/bitbox02/ui.rs
@@ -3,7 +3,7 @@
use alloc::string::String;
use crate::hal::Ui;
-use crate::hal::ui::{ConfirmParams, Font, UserAbort};
+use crate::hal::ui::{ConfirmParams, EnterStringParams, Font, UserAbort};
use crate::workflow::trinary_input_string;
pub struct BitBox02Ui;
@@ -32,6 +32,21 @@ fn to_bitbox02_confirm_params<'a>(
}
}
+fn to_bitbox02_trinary_input_string_params<'a>(
+ params: &'a EnterStringParams<'a>,
+) -> bitbox02::ui::TrinaryInputStringParams<'a> {
+ bitbox02::ui::TrinaryInputStringParams {
+ title: params.title,
+ wordlist: params.wordlist,
+ number_input: params.number_input,
+ hide: params.hide,
+ special_chars: params.special_chars,
+ longtouch: params.longtouch,
+ cancel_is_backbutton: params.cancel_is_backbutton,
+ default_to_digits: params.default_to_digits,
+ }
+}
+
impl Ui for BitBox02Ui {
#[inline(always)]
async fn confirm(&mut self, params: &ConfirmParams<'_>) -> Result<(), UserAbort> {
@@ -71,15 +86,16 @@ impl Ui for BitBox02Ui {
#[inline(always)]
async fn enter_string(
&mut self,
- params: &trinary_input_string::Params<'_>,
+ params: &EnterStringParams<'_>,
can_cancel: trinary_input_string::CanCancel,
preset: &str,
) -> Result<zeroize::Zeroizing<String>, UserAbort> {
+ let params = to_bitbox02_trinary_input_string_params(params);
let can_cancel = match can_cancel {
trinary_input_string::CanCancel::Yes => true,
trinary_input_string::CanCancel::No => false,
};
- bitbox02::ui::trinary_input_string(params, can_cancel, preset)
+ bitbox02::ui::trinary_input_string(¶ms, can_cancel, preset)
.await
.map_err(|_| UserAbort)
}
@@ -200,4 +216,49 @@ mod tests {
assert_eq!(output.display_size, 42);
}
}
+
+ #[test]
+ fn test_to_bitbox02_trinary_input_string_params() {
+ let input_without_wordlist = EnterStringParams {
+ title: "Enter",
+ wordlist: None,
+ number_input: true,
+ hide: true,
+ special_chars: true,
+ longtouch: true,
+ cancel_is_backbutton: true,
+ default_to_digits: true,
+ };
+ let output_without_wordlist =
+ to_bitbox02_trinary_input_string_params(&input_without_wordlist);
+ assert_eq!(output_without_wordlist.title, "Enter");
+ assert!(output_without_wordlist.wordlist.is_none());
+ assert!(output_without_wordlist.number_input);
+ assert!(output_without_wordlist.hide);
+ assert!(output_without_wordlist.special_chars);
+ assert!(output_without_wordlist.longtouch);
+ assert!(output_without_wordlist.cancel_is_backbutton);
+ assert!(output_without_wordlist.default_to_digits);
+
+ let wordlist = [1u16, 2, 3];
+ let input_with_wordlist = EnterStringParams {
+ title: "Seed",
+ wordlist: Some(&wordlist),
+ number_input: false,
+ hide: false,
+ special_chars: false,
+ longtouch: false,
+ cancel_is_backbutton: false,
+ default_to_digits: false,
+ };
+ let output_with_wordlist = to_bitbox02_trinary_input_string_params(&input_with_wordlist);
+ assert_eq!(output_with_wordlist.title, "Seed");
+ assert_eq!(output_with_wordlist.wordlist.unwrap(), wordlist.as_slice());
+ assert!(!output_with_wordlist.number_input);
+ assert!(!output_with_wordlist.hide);
+ assert!(!output_with_wordlist.special_chars);
+ assert!(!output_with_wordlist.longtouch);
+ assert!(!output_with_wordlist.cancel_is_backbutton);
+ assert!(!output_with_wordlist.default_to_digits);
+ }
}
diff --git a/src/rust/bitbox02-rust/src/hal/testing/ui.rs b/src/rust/bitbox02-rust/src/hal/testing/ui.rs
index 1c352fb..57d36bc 100644
--- a/src/rust/bitbox02-rust/src/hal/testing/ui.rs
+++ b/src/rust/bitbox02-rust/src/hal/testing/ui.rs
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::hal::Ui;
-use crate::hal::ui::{ConfirmParams, UserAbort};
+use crate::hal::ui::{ConfirmParams, EnterStringParams, UserAbort};
use crate::workflow::trinary_input_string;
use alloc::boxed::Box;
@@ -34,10 +34,7 @@ pub enum Screen {
More,
}
-type EnterStringCb<'a> = Box<
- dyn FnMut(&trinary_input_string::Params<'_>) -> Result<String, trinary_input_string::Error>
- + 'a,
->;
+type EnterStringCb<'a> = Box<dyn FnMut(&EnterStringParams<'_>) -> Result<String, UserAbort> + 'a>;
/// A Ui implementation for unit tests. Collects all screens and provides helper functions
/// to verify them.
@@ -116,7 +113,7 @@ impl Ui for TestingUi<'_> {
async fn enter_string(
&mut self,
- params: &trinary_input_string::Params<'_>,
+ params: &EnterStringParams<'_>,
_can_cancel: trinary_input_string::CanCancel,
_preset: &str,
) -> Result<zeroize::Zeroizing<String>, UserAbort> {
diff --git a/src/rust/bitbox02-rust/src/hal/ui.rs b/src/rust/bitbox02-rust/src/hal/ui.rs
index abdb9bf..dc078f4 100644
--- a/src/rust/bitbox02-rust/src/hal/ui.rs
+++ b/src/rust/bitbox02-rust/src/hal/ui.rs
@@ -35,6 +35,20 @@ pub struct ConfirmParams<'a> {
pub display_size: usize,
}
+#[derive(Default)]
+pub struct EnterStringParams<'a> {
+ /// The confirmation title of the screen. Max 200 chars, otherwise **panic**.
+ pub title: &'a str,
+ /// Currently specialized to the BIP39 wordlist: a list of BIP39 word indices. Can be extended if needed.
+ pub wordlist: Option<&'a [u16]>,
+ pub number_input: bool,
+ pub hide: bool,
+ pub special_chars: bool,
+ pub longtouch: bool,
+ pub cancel_is_backbutton: bool,
+ pub default_to_digits: bool,
+}
+
#[allow(async_fn_in_trait)]
pub trait Ui {
/// Returns `Ok(())` if the user accepts, `Err(UserAbort)` if the user rejects.
@@ -56,7 +70,7 @@ pub trait Ui {
/// If `preset` is not empty, it must be part of `params.wordlist` and will be pre-entered.
async fn enter_string(
&mut self,
- params: &trinary_input_string::Params<'_>,
+ params: &EnterStringParams<'_>,
can_cancel: trinary_input_string::CanCancel,
preset: &str,
) -> Result<zeroize::Zeroizing<String>, UserAbort>;
diff --git a/src/rust/bitbox02-rust/src/hww/api/bip85.rs b/src/rust/bitbox02-rust/src/hww/api/bip85.rs
index 4b13884..c79de90 100644
--- a/src/rust/bitbox02-rust/src/hww/api/bip85.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/bip85.rs
@@ -76,7 +76,7 @@ async fn process_bip39(hal: &mut impl crate::hal::Hal) -> Result<(), Error> {
let number_string = hal
.ui()
.enter_string(
- &trinary_input_string::Params {
+ &crate::hal::ui::EnterStringParams {
title: "Enter index",
number_input: true,
longtouch: true,
diff --git a/src/rust/bitbox02-rust/src/hww/api/bitcoin/registration.rs b/src/rust/bitbox02-rust/src/hww/api/bitcoin/registration.rs
index f68520b..40eb0de 100644
--- a/src/rust/bitbox02-rust/src/hww/api/bitcoin/registration.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/bitcoin/registration.rs
@@ -75,7 +75,7 @@ async fn get_name(
let name = hal
.ui()
.enter_string(
- &trinary_input_string::Params {
+ &crate::hal::ui::EnterStringParams {
title: "Enter account name",
longtouch: true,
..Default::default()
diff --git a/src/rust/bitbox02-rust/src/workflow/mnemonic.rs b/src/rust/bitbox02-rust/src/workflow/mnemonic.rs
index 2ed6a12..d54afec 100644
--- a/src/rust/bitbox02-rust/src/workflow/mnemonic.rs
+++ b/src/rust/bitbox02-rust/src/workflow/mnemonic.rs
@@ -237,7 +237,7 @@ async fn get_12th_18th_word(
let choices = lastword_choices(entered_words);
let word = hal_ui
.enter_string(
- &trinary_input_string::Params {
+ &crate::hal::ui::EnterStringParams {
title,
wordlist: Some(&choices),
..Default::default()
@@ -311,7 +311,7 @@ pub async fn get(
} else {
hal_ui
.enter_string(
- &trinary_input_string::Params {
+ &crate::hal::ui::EnterStringParams {
title: &title,
wordlist: Some(&bip39_wordlist),
..Default::default()
diff --git a/src/rust/bitbox02-rust/src/workflow/password.rs b/src/rust/bitbox02-rust/src/workflow/password.rs
index 6087771..b15c42c 100644
--- a/src/rust/bitbox02-rust/src/workflow/password.rs
+++ b/src/rust/bitbox02-rust/src/workflow/password.rs
@@ -46,7 +46,7 @@ pub async fn enter(
password_type: PasswordType,
can_cancel: CanCancel,
) -> Result<zeroize::Zeroizing<String>, EnterError> {
- let params = trinary_input_string::Params {
+ let params = crate::hal::ui::EnterStringParams {
title,
hide: true,
special_chars: match password_type {
diff --git a/src/rust/bitbox02-rust/src/workflow/trinary_input_string.rs b/src/rust/bitbox02-rust/src/workflow/trinary_input_string.rs
index c8e2edd..1b0ceb3 100644
--- a/src/rust/bitbox02-rust/src/workflow/trinary_input_string.rs
+++ b/src/rust/bitbox02-rust/src/workflow/trinary_input_string.rs
@@ -1,8 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
-pub use crate::hal::ui::UserAbort as Error;
-pub use bitbox02::ui::{TrinaryInputStringParams as Params, trinary_input_string};
-
#[derive(Copy, Clone)]
pub enum CanCancel {
No,
Why this scored 15/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.