What changed, and why it matters
This commit adds a new local simulator for the BitBox03 hardware wallet. It is purely test/development tooling: it wires up fake hardware components (fake memory, fake secure chip, fake SD card, etc.) and leaves many simulator functions as unimplemented 'todo!()' stubs. There is no indication this change affects real device firmware or introduces a security vulnerability.
No security action required. If reviewing for quality, ensure the todo!() stubs in the simulator are completed before the simulator is used for security-sensitive testing, and verify that simulator-only code cannot be compiled into production firmware builds.
Security signals we found
No security-relevant code changes to production firmware
New code is confined to test/simulator-graphical-bb03
Random generation is explicitly stubbed and will panic if called
Uses fake/test hardware abstractions already present in bitbox-platform-host
Evidence from the diff
The commit introduces a simulator HAL (Hardware Abstraction Layer) under test/simulator-graphical-bb03/src/hal.rs, reusing bitbox-platform-host fake subsystems and the real bitbox03 UI module. It exposes a static singleton BitBox03State and implements the hal::Hal trait. Several methods—notably random_32_bytes, mcu_32_bytes, reboot, reboot_to_bootloader, reset_ble, and communication_timeout_reset—are stubbed with todo!(). The bitbox03::ui module visibility is changed from private to pub so the simulator can use it. This is scaffolding for a graphical simulator, not a production code change.
Changed components
test/simulator-graphical-bb03src/rust/bitbox03/src/lib.rs (ui module visibility only)Inspect captured patch +181 / −2
diff --git a/src/rust/bitbox03/src/lib.rs b/src/rust/bitbox03/src/lib.rs
index a57b8df..cd49238 100644
--- a/src/rust/bitbox03/src/lib.rs
+++ b/src/rust/bitbox03/src/lib.rs
@@ -11,7 +11,7 @@ mod random;
mod sd;
mod securechip;
mod system;
-mod ui;
+pub mod ui;
use bitbox_hal as hal;
use bitbox_lvgl::LvDisplay;
diff --git a/test/simulator-graphical-bb03/Cargo.lock b/test/simulator-graphical-bb03/Cargo.lock
index 8d21a86..1e9ec6b 100644
--- a/test/simulator-graphical-bb03/Cargo.lock
+++ b/test/simulator-graphical-bb03/Cargo.lock
@@ -372,6 +372,16 @@ dependencies = [
"cmake",
]
+[[package]]
+name = "bitbox-platform-host"
+version = "0.1.0"
+dependencies = [
+ "bitbox-hal",
+ "bitcoin",
+ "hex_lit",
+ "zeroize",
+]
+
[[package]]
name = "bitbox-secp256k1"
version = "0.1.0"
@@ -2809,6 +2819,7 @@ dependencies = [
"bitbox-aes",
"bitbox-hal",
"bitbox-lvgl",
+ "bitbox-platform-host",
"bitbox-usb-report-queue",
"bitbox02-rust",
"bitbox03",
@@ -2823,6 +2834,7 @@ dependencies = [
"tracing-subscriber",
"util",
"winit",
+ "zeroize",
]
[[package]]
diff --git a/test/simulator-graphical-bb03/Cargo.toml b/test/simulator-graphical-bb03/Cargo.toml
index d1baac9..577ce82 100644
--- a/test/simulator-graphical-bb03/Cargo.toml
+++ b/test/simulator-graphical-bb03/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2024"
[dependencies]
bitbox-hal = { path = "../../src/rust/bitbox-hal" }
+bitbox-platform-host = { path = "../../src/rust/bitbox-platform-host" }
bitbox-usb-report-queue = { path = "../../src/rust/bitbox-usb-report-queue" }
bitbox02-rust = { path = "../../src/rust/bitbox02-rust", features = ["simulator-graphical"] }
bitbox-aes = { path = "../../src/rust/bitbox-aes" }
@@ -21,3 +22,4 @@ util = { path = "../../src/rust/util" }
critical-section = { version = "1.2", features = ["std"] }
bitbox03 = { path = "../../src/rust/bitbox03" }
bitbox-lvgl = { path = "../../src/rust/bitbox-lvgl" }
+zeroize = "1.7.0"
diff --git a/test/simulator-graphical-bb03/src/hal.rs b/test/simulator-graphical-bb03/src/hal.rs
new file mode 100644
index 0000000..16f8e06
--- /dev/null
+++ b/test/simulator-graphical-bb03/src/hal.rs
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: Apache-2.0
+
+extern crate alloc;
+
+use bitbox_hal as hal;
+use bitbox_lvgl::LvDisplay;
+use bitbox_platform_host::{
+ eeprom::FakeEeprom, memory::FakeMemory, sd::FakeSd, securechip::FakeSecureChip,
+};
+use bitbox03::ui;
+use core::cell::UnsafeCell;
+use core::mem::MaybeUninit;
+use std::sync::Once;
+
+mod random;
+mod system;
+
+struct BitBox03State {
+ ui: ui::BitBox03Ui,
+ random: random::BitBox03Random,
+ sd: FakeSd,
+ securechip: FakeSecureChip,
+ memory: FakeMemory,
+ eeprom: FakeEeprom,
+ system: system::BitBox03System,
+}
+
+impl BitBox03State {
+ fn new() -> Self {
+ let mut sd = FakeSd::new();
+ sd.inserted = Some(true);
+
+ let mut memory = FakeMemory::new();
+ memory.set_platform(bitbox_hal::memory::Platform::BitBox03);
+
+ Self {
+ ui: ui::BitBox03Ui::new(),
+ random: random::BitBox03Random {},
+ sd,
+ securechip: FakeSecureChip::new(),
+ memory,
+ eeprom: FakeEeprom::new(),
+ system: system::BitBox03System {},
+ }
+ }
+}
+
+struct Singleton<T>(UnsafeCell<T>);
+
+impl<T> Singleton<T> {
+ const fn new(value: T) -> Self {
+ Self(UnsafeCell::new(value))
+ }
+
+ fn get(&self) -> *mut T {
+ self.0.get()
+ }
+}
+
+unsafe impl<T> Sync for Singleton<T> {}
+
+static BITBOX03_INIT: Once = Once::new();
+static BITBOX03: Singleton<MaybeUninit<BitBox03State>> = Singleton::new(MaybeUninit::uninit());
+
+fn state() -> &'static mut BitBox03State {
+ BITBOX03_INIT.call_once(|| unsafe {
+ (*BITBOX03.get()).write(BitBox03State::new());
+ });
+ unsafe { (&mut *BITBOX03.get()).assume_init_mut() }
+}
+
+#[derive(Copy, Clone, Default)]
+pub struct BitBox03;
+
+impl BitBox03 {
+ pub const fn new() -> BitBox03 {
+ BitBox03
+ }
+
+ pub fn init(&mut self, display: LvDisplay) {
+ state().ui.init(display);
+ }
+}
+
+impl hal::Hal for BitBox03 {
+ type Ui = ui::BitBox03Ui;
+ type Random = random::BitBox03Random;
+ type Sd = FakeSd;
+ type SecureChip = FakeSecureChip;
+ type Memory = FakeMemory;
+ type Eeprom = FakeEeprom;
+ type System = system::BitBox03System;
+
+ fn as_mut(
+ &mut self,
+ ) -> hal::HalSubsystems<
+ '_,
+ Self::Ui,
+ Self::Random,
+ Self::Sd,
+ Self::SecureChip,
+ Self::Memory,
+ Self::Eeprom,
+ Self::System,
+ > {
+ let state = state();
+ hal::HalSubsystems {
+ ui: &mut state.ui,
+ random: &mut state.random,
+ sd: &mut state.sd,
+ securechip: &mut state.securechip,
+ memory: &mut state.memory,
+ eeprom: &mut state.eeprom,
+ system: &mut state.system,
+ }
+ }
+}
diff --git a/test/simulator-graphical-bb03/src/hal/random.rs b/test/simulator-graphical-bb03/src/hal/random.rs
new file mode 100644
index 0000000..a9b87e3
--- /dev/null
+++ b/test/simulator-graphical-bb03/src/hal/random.rs
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: Apache-2.0
+
+use bitbox_hal as hal;
+
+pub struct BitBox03Random;
+
+impl hal::random::Random for BitBox03Random {
+ fn random_32_bytes(&mut self) -> alloc::boxed::Box<zeroize::Zeroizing<[u8; 32]>> {
+ todo!()
+ }
+
+ fn mcu_32_bytes(&mut self, _out: &mut [u8; 32]) {
+ todo!()
+ }
+}
diff --git a/test/simulator-graphical-bb03/src/hal/system.rs b/test/simulator-graphical-bb03/src/hal/system.rs
new file mode 100644
index 0000000..eb20c86
--- /dev/null
+++ b/test/simulator-graphical-bb03/src/hal/system.rs
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+
+use bitbox_hal as hal;
+
+pub struct BitBox03System;
+
+impl hal::system::System for BitBox03System {
+ async fn startup() {}
+
+ fn is_btconly(&mut self) -> bool {
+ false
+ }
+
+ fn reboot(&mut self) -> ! {
+ todo!()
+ }
+
+ fn reboot_to_bootloader(&mut self) -> ! {
+ todo!()
+ }
+
+ fn reset_ble(&mut self) {
+ todo!()
+ }
+
+ fn communication_timeout_reset(&mut self, _value: i16) {
+ todo!()
+ }
+}
diff --git a/test/simulator-graphical-bb03/src/main.rs b/test/simulator-graphical-bb03/src/main.rs
index 070f722..11ad687 100644
--- a/test/simulator-graphical-bb03/src/main.rs
+++ b/test/simulator-graphical-bb03/src/main.rs
@@ -1,5 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
+extern crate alloc;
+
+mod hal;
+
use clap::Parser;
use femtovg::{Canvas, ImageFlags, ImageId, ImageSource, Paint, Path, renderer::OpenGl};
use image::{DynamicImage, Rgba, RgbaImage};
@@ -40,8 +44,8 @@ use tracing_subscriber::{EnvFilter, filter::LevelFilter, fmt, prelude::*};
use bitbox_hal::{Hal, Ui, system::System};
-use bitbox03::BitBox03;
use bitbox03::io::touchscreen::{TouchScreen, TouchScreenEvent};
+use hal::BitBox03;
use bitbox_lvgl as lvgl;
use lvgl::LvDisplayRenderMode;
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.