What changed, and why it matters
This commit is a code reorganization: it moves SmartEEPROM handling (a flash-backed memory feature) out of the general Memory and System modules into a new dedicated Eeprom trait in the hardware abstraction layer. The same underlying functions are still called, and the unlock-attempt counter behavior is preserved. There is no obvious security bug introduced, but the change touches code that protects device reset and unlock-attempt limits, so it deserves careful review to confirm no behavior was accidentally dropped.
Review the refactor for accidental behavioral changes, especially: (1) confirm that all previous SmartEEPROM setup/init calls are still invoked at the correct boot stage on BitBox02; (2) verify that unlock-attempt increment/get/reset semantics match the prior Memory-based implementation, including any maximum-attempt enforcement; (3) ensure the new BitBox03 Eeprom implementation's saturating_add matches the intended security policy; (4) run the relevant unit and simulator tests; (5) consider whether the removed bitbox02/src/smarteeprom.rs simulator-graphical functions need replacement calls elsewhere.
Security signals we found
Refactor of unlock-attempt counter persistence from Memory trait to new Eeprom trait
Refactor of SmartEEPROM disable from System trait to new Eeprom trait
BitBox02 implementation still calls same unsafe C SmartEEPROM functions as before
BitBox03 implementation uses saturating_add for unlock attempts, replacing previous todo!() stubs
Testing implementation uses simple u8 counter without explicit max-bound enforcement
Evidence from the diff
The patch refactors SmartEEPROM setup, init, disable, and unlock-attempt persistence into a new bitbox_hal::Eeprom trait with implementations for BitBox02, BitBox03, and the Rust test HAL. It removes these responsibilities from Memory and System traits and updates callers in keystore, reset, and unlock workflows. On BitBox02 the trait delegates to the existing C sys functions (smarteeprom_bb02_config, bitbox02_smarteeprom_init, smarteeprom_is_enabled, smarteeprom_disable, bitbox02_smarteeprom_get/increment/reset_unlock_attempts). On BitBox03 and in tests it uses simple in-memory state. The diff shows no logic changes to the underlying operations; it is purely an architectural move.
Changed components
bitbox-hal Eeprom trait and Hal subsystem plumbingbitbox02/src/hal/eeprom.rs (new BitBox02Eeprom)bitbox02-rust/src/keystore.rs (unlock attempt counter access)bitbox02-rust/src/reset.rs (SmartEEPROM disable on device reset)bitbox02-rust/src/workflow/unlock.rs (keystore hal construction)bitbox03/src/eeprom.rs (new BitBox03Eeprom)bitbox02-rust/src/hal/testing/eeprom.rs (new TestingEeprom)Inspect captured patch +292 / −131
diff --git a/AGENTS.md b/AGENTS.md
index ab9591c..d07d4cd 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -48,7 +48,8 @@ bindings (`cbindgen`, protobuf) when interfaces change.
* For C code changes, run `./scripts/dev_exec.sh ./scripts/format` to format the code.
* For Python changes, run `./scripts/dev_exec.sh ./scripts/format-python` to format the code.
-* For Rust code changes, run `./scripts/dev_exec.sh cargo fmt --manifest-path src/rust/Cargo.toml` to format the code.
+* For Rust code changes, run
+ `./scripts/dev_exec.sh cargo fmt --manifest-path src/rust/Cargo.toml --all` to format the code.
## Testing Guidelines
Place new C specs in `test/unit-test` and add doubles to `test/hardware-fakes` when hardware
@@ -58,13 +59,15 @@ run-unit-tests` and `make run-rust-unit-tests`, and refresh `make coverage` for
security-sensitive areas.
- in Rust unit tests, prefer .unwrap() over .expect().
-- In Rust unit tests, if testing a function foo, name the test `test_foo` (or `test_foo_xyz` if it needs qualifiers).
+- In Rust unit tests, if testing a function foo, name the test `test_foo` (or `test_foo_xyz` if it
+ needs qualifiers).
- in Rust unit tests, prefer .as_slice() instead of `&*` for wrapped/zeroized Vec<u8>.
- in Rust unit tests, prefer `hex!` literals for byte arrays/constants.
## Review Guidelines
-- when reviewing a removed function call, check that the removed behavior was not required and was not dropped by accident during a refactor.
+- when reviewing a removed function call, check that the removed behavior was not required and was
+ not dropped by accident during a refactor.
- when reviewing a removed function call, check if the callee became unused and should also be removed.
- Focus on memory issues
diff --git a/src/rust/bitbox-hal/src/eeprom.rs b/src/rust/bitbox-hal/src/eeprom.rs
new file mode 100644
index 0000000..c65d730
--- /dev/null
+++ b/src/rust/bitbox-hal/src/eeprom.rs
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: Apache-2.0
+
+/// Flash-backed EEPROM emulation required by the BitBox HAL.
+///
+/// Implementations provide two pieces of behavior:
+/// - device-specific EEPROM-emulation bring-up/teardown
+/// - persistent storage for the unlock-attempt counter
+///
+/// The expected lifecycle is to call [`Self::setup`] during startup to ensure the backend is
+/// configured, then [`Self::init`] to initialize or migrate the BitBox-specific data stored in
+/// the emulated EEPROM before accessing the counter.
+pub trait Eeprom {
+ /// Ensures the flash-backed EEPROM backend is configured for BitBox use.
+ ///
+ /// Hardware implementations may update the MCU's EEPROM-emulation configuration and can
+ /// require a reboot before the new configuration takes effect.
+ fn setup(&mut self);
+
+ /// Initializes or migrates the BitBox-specific contents stored in the emulated EEPROM.
+ ///
+ /// This should be safe to call on every boot after [`Self::setup`].
+ fn init(&mut self);
+
+ /// Returns whether the flash-backed EEPROM emulation is currently enabled.
+ fn is_enabled(&mut self) -> bool;
+
+ /// Disables the flash-backed EEPROM emulation.
+ ///
+ /// On hardware, the change may only take effect after a reboot.
+ fn disable(&mut self);
+
+ /// Returns the persisted number of recorded unlock attempts.
+ ///
+ /// This counter is used to enforce the maximum number of allowed unlock attempts. Callers
+ /// increment it before an unlock attempt and reset it after a successful unlock.
+ fn get_unlock_attempts(&mut self) -> u8;
+
+ /// Increments the persisted unlock-attempt counter by one.
+ ///
+ /// Implementations are expected to reject invalid state or increments past the supported
+ /// maximum instead of silently wrapping.
+ fn increment_unlock_attempts(&mut self);
+
+ /// Resets the persisted unlock-attempt counter to zero.
+ fn reset_unlock_attempts(&mut self);
+}
diff --git a/src/rust/bitbox-hal/src/lib.rs b/src/rust/bitbox-hal/src/lib.rs
index 90c9473..52626f0 100644
--- a/src/rust/bitbox-hal/src/lib.rs
+++ b/src/rust/bitbox-hal/src/lib.rs
@@ -4,6 +4,7 @@
extern crate alloc;
+pub mod eeprom;
pub mod memory;
pub mod random;
pub mod sd;
@@ -11,6 +12,7 @@ pub mod securechip;
pub mod system;
pub mod ui;
+pub use eeprom::Eeprom;
pub use memory::Memory;
pub use random::Random;
pub use sd::Sd;
@@ -25,6 +27,7 @@ pub struct HalSubsystems<
Sd: sd::Sd,
SecureChip: securechip::SecureChip,
Memory: memory::Memory,
+ Eeprom: eeprom::Eeprom,
System: system::System,
> {
pub ui: &'a mut Ui,
@@ -32,6 +35,7 @@ pub struct HalSubsystems<
pub sd: &'a mut Sd,
pub securechip: &'a mut SecureChip,
pub memory: &'a mut Memory,
+ pub eeprom: &'a mut Eeprom,
pub system: &'a mut System,
}
@@ -42,6 +46,7 @@ pub trait Hal {
type Sd: sd::Sd;
type SecureChip: securechip::SecureChip;
type Memory: memory::Memory;
+ type Eeprom: eeprom::Eeprom;
type System: system::System;
fn as_mut(
@@ -53,6 +58,7 @@ pub trait Hal {
Self::Sd,
Self::SecureChip,
Self::Memory,
+ Self::Eeprom,
Self::System,
>;
@@ -76,6 +82,10 @@ pub trait Hal {
self.as_mut().memory
}
+ fn eeprom(&mut self) -> &mut Self::Eeprom {
+ self.as_mut().eeprom
+ }
+
fn system(&mut self) -> &mut Self::System {
self.as_mut().system
}
diff --git a/src/rust/bitbox-hal/src/memory.rs b/src/rust/bitbox-hal/src/memory.rs
index 5fc425c..adb525f 100644
--- a/src/rust/bitbox-hal/src/memory.rs
+++ b/src/rust/bitbox-hal/src/memory.rs
@@ -94,9 +94,6 @@ pub trait Memory {
password_stretch_algo: PasswordStretchAlgo,
) -> Result<(), ()>;
fn reset_hww(&mut self) -> Result<(), ()>;
- fn get_unlock_attempts(&mut self) -> u8;
- fn increment_unlock_attempts(&mut self);
- fn reset_unlock_attempts(&mut self);
fn get_io_protection_key(&mut self, out: &mut [u8; 32]);
fn get_salt_root(&mut self) -> Result<zeroize::Zeroizing<Vec<u8>>, ()>;
fn get_attestation_pubkey_and_certificate(
diff --git a/src/rust/bitbox-hal/src/system.rs b/src/rust/bitbox-hal/src/system.rs
index 330b9a8..5384a1c 100644
--- a/src/rust/bitbox-hal/src/system.rs
+++ b/src/rust/bitbox-hal/src/system.rs
@@ -21,5 +21,4 @@ pub trait System {
fn reboot(&mut self) -> !;
fn reboot_to_bootloader(&mut self) -> !;
fn reset_ble(&mut self);
- fn smarteeprom_disable(&mut self);
}
diff --git a/src/rust/bitbox02-rust/src/hal/testing.rs b/src/rust/bitbox02-rust/src/hal/testing.rs
index a2d6848..4698fe1 100644
--- a/src/rust/bitbox02-rust/src/hal/testing.rs
+++ b/src/rust/bitbox02-rust/src/hal/testing.rs
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
+pub mod eeprom;
pub mod memory;
pub mod random;
pub mod sd;
@@ -7,6 +8,7 @@ pub mod securechip;
pub mod system;
pub mod ui;
+pub use eeprom::TestingEeprom;
pub use memory::TestingMemory;
pub use random::TestingRandom;
pub use sd::TestingSd;
@@ -20,6 +22,7 @@ pub struct TestingHal<'a> {
pub random: TestingRandom,
pub securechip: TestingSecureChip,
pub memory: TestingMemory,
+ pub eeprom: TestingEeprom,
pub system: TestingSystem,
}
@@ -31,6 +34,7 @@ impl TestingHal<'_> {
random: TestingRandom::new(),
securechip: TestingSecureChip::new(),
memory: TestingMemory::new(),
+ eeprom: TestingEeprom::new(),
system: TestingSystem::new(),
}
}
@@ -42,6 +46,7 @@ impl<'a> crate::hal::Hal for TestingHal<'a> {
type Sd = TestingSd;
type SecureChip = TestingSecureChip;
type Memory = TestingMemory;
+ type Eeprom = TestingEeprom;
type System = TestingSystem;
fn as_mut(
@@ -53,6 +58,7 @@ impl<'a> crate::hal::Hal for TestingHal<'a> {
Self::Sd,
Self::SecureChip,
Self::Memory,
+ Self::Eeprom,
Self::System,
> {
crate::hal::HalSubsystems {
@@ -61,6 +67,7 @@ impl<'a> crate::hal::Hal for TestingHal<'a> {
sd: &mut self.sd,
securechip: &mut self.securechip,
memory: &mut self.memory,
+ eeprom: &mut self.eeprom,
system: &mut self.system,
}
}
diff --git a/src/rust/bitbox02-rust/src/hal/testing/eeprom.rs b/src/rust/bitbox02-rust/src/hal/testing/eeprom.rs
new file mode 100644
index 0000000..dc681a5
--- /dev/null
+++ b/src/rust/bitbox02-rust/src/hal/testing/eeprom.rs
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: Apache-2.0
+
+pub struct TestingEeprom {
+ pub enabled: bool,
+ unlock_attempts: u8,
+}
+
+impl TestingEeprom {
+ pub fn new() -> Self {
+ Self {
+ enabled: true,
+ unlock_attempts: 0,
+ }
+ }
+
+ pub fn set_unlock_attempts_for_testing(&mut self, attempts: u8) {
+ self.unlock_attempts = attempts;
+ }
+}
+
+impl crate::hal::Eeprom for TestingEeprom {
+ fn setup(&mut self) {
+ self.enabled = true;
+ self.unlock_attempts = 0;
+ }
+
+ fn init(&mut self) {}
+
+ fn is_enabled(&mut self) -> bool {
+ self.enabled
+ }
+
+ fn disable(&mut self) {
+ self.enabled = false;
+ }
+
+ fn get_unlock_attempts(&mut self) -> u8 {
+ self.unlock_attempts
+ }
+
+ fn increment_unlock_attempts(&mut self) {
+ self.unlock_attempts += 1;
+ }
+
+ fn reset_unlock_attempts(&mut self) {
+ self.unlock_attempts = 0;
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use crate::hal::Eeprom;
+
+ #[test]
+ fn test_disable() {
+ let mut eeprom = TestingEeprom::new();
+ assert!(eeprom.enabled);
+ eeprom.disable();
+ assert!(!eeprom.enabled);
+ eeprom.setup();
+ assert!(eeprom.enabled);
+ }
+
+ #[test]
+ fn test_unlock_attempts() {
+ let mut eeprom = TestingEeprom::new();
+ assert_eq!(eeprom.get_unlock_attempts(), 0);
+ eeprom.increment_unlock_attempts();
+ eeprom.increment_unlock_attempts();
+ assert_eq!(eeprom.get_unlock_attempts(), 2);
+ eeprom.reset_unlock_attempts();
+ assert_eq!(eeprom.get_unlock_attempts(), 0);
+ }
+
+ #[test]
+ fn test_is_enabled() {
+ let mut eeprom = TestingEeprom::new();
+ assert!(eeprom.is_enabled());
+ eeprom.disable();
+ assert!(!eeprom.is_enabled());
+ }
+}
diff --git a/src/rust/bitbox02-rust/src/hal/testing/memory.rs b/src/rust/bitbox02-rust/src/hal/testing/memory.rs
index 5f207eb..3ebc6f5 100644
--- a/src/rust/bitbox02-rust/src/hal/testing/memory.rs
+++ b/src/rust/bitbox02-rust/src/hal/testing/memory.rs
@@ -22,7 +22,6 @@ pub struct TestingMemory {
seed_birthdate: u32,
encrypted_seed_and_hmac: Option<(Vec<u8>, PasswordStretchAlgo)>,
device_name: Option<String>,
- unlock_attempts: u8,
salt_root: [u8; 32],
attestation_device_pubkey: Option<[u8; 64]>,
attestation_certificate: Option<[u8; 64]>,
@@ -58,7 +57,6 @@ impl TestingMemory {
seed_birthdate: 0,
encrypted_seed_and_hmac: None,
device_name: None,
- unlock_attempts: 0,
salt_root: *b"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
attestation_device_pubkey: None,
attestation_certificate: None,
@@ -76,10 +74,6 @@ impl TestingMemory {
self.platform = platform;
}
- pub fn set_unlock_attempts_for_testing(&mut self, attempts: u8) {
- self.unlock_attempts = attempts;
- }
-
pub fn set_salt_root(&mut self, salt_root: &[u8; 32]) {
self.salt_root = *salt_root;
}
@@ -250,18 +244,6 @@ impl crate::hal::Memory for TestingMemory {
Ok(())
}
- fn get_unlock_attempts(&mut self) -> u8 {
- self.unlock_attempts
- }
-
- fn increment_unlock_attempts(&mut self) {
- self.unlock_attempts += 1;
- }
-
- fn reset_unlock_attempts(&mut self) {
- self.unlock_attempts = 0;
- }
-
fn get_io_protection_key(&mut self, _out: &mut [u8; 32]) {
panic!("unused")
}
diff --git a/src/rust/bitbox02-rust/src/hal/testing/system.rs b/src/rust/bitbox02-rust/src/hal/testing/system.rs
index 1a4cd8a..9337241 100644
--- a/src/rust/bitbox02-rust/src/hal/testing/system.rs
+++ b/src/rust/bitbox02-rust/src/hal/testing/system.rs
@@ -1,16 +1,12 @@
// SPDX-License-Identifier: Apache-2.0
pub struct TestingSystem {
- pub(crate) smarteeprom_enabled: bool,
ble_reset_count: u32,
}
impl TestingSystem {
pub fn new() -> Self {
- Self {
- smarteeprom_enabled: true,
- ble_reset_count: 0,
- }
+ Self { ble_reset_count: 0 }
}
pub fn ble_reset_count(&self) -> u32 {
@@ -34,10 +30,6 @@ impl crate::hal::System for TestingSystem {
fn reset_ble(&mut self) {
self.ble_reset_count += 1;
}
-
- fn smarteeprom_disable(&mut self) {
- self.smarteeprom_enabled = false;
- }
}
#[cfg(test)]
@@ -46,14 +38,6 @@ mod tests {
use crate::hal::System;
- #[test]
- fn test_smarteeprom_disable() {
- let mut system = TestingSystem::new();
- assert!(system.smarteeprom_enabled);
- system.smarteeprom_disable();
- assert!(!system.smarteeprom_enabled);
- }
-
#[test]
fn test_reset_ble() {
let mut system = TestingSystem::new();
diff --git a/src/rust/bitbox02-rust/src/keystore.rs b/src/rust/bitbox02-rust/src/keystore.rs
index 50f4a1d..e66435c 100644
--- a/src/rust/bitbox02-rust/src/keystore.rs
+++ b/src/rust/bitbox02-rust/src/keystore.rs
@@ -7,7 +7,7 @@ use alloc::string::String;
use alloc::vec::Vec;
use crate::bip32;
-use crate::hal::{Memory, Random, SecureChip, System, memory, securechip};
+use crate::hal::{Eeprom, Memory, Random, SecureChip, System, memory, securechip};
use util::bip32::HARDENED;
use util::cell::SyncCell;
@@ -27,24 +27,33 @@ const LONG_TIMEOUT: i16 = -70;
pub const MAX_UNLOCK_ATTEMPTS: u8 = 10;
pub trait KeystoreHal {
+ type Eeprom: Eeprom;
type Memory: Memory;
type Random: Random;
type SecureChip: SecureChip;
+ fn eeprom(&mut self) -> &mut Self::Eeprom;
fn memory(&mut self) -> &mut Self::Memory;
fn random(&mut self) -> &mut Self::Random;
fn securechip(&mut self) -> &mut Self::SecureChip;
}
-pub struct KeystoreHalImpl<'a, M: Memory, R: Random, S: SecureChip> {
+pub struct KeystoreHalImpl<'a, E: Eeprom, M: Memory, R: Random, S: SecureChip> {
+ eeprom: &'a mut E,
memory: &'a mut M,
random: &'a mut R,
securechip: &'a mut S,
}
-impl<'a, M: Memory, R: Random, S: SecureChip> KeystoreHalImpl<'a, M, R, S> {
- pub fn new(memory: &'a mut M, random: &'a mut R, securechip: &'a mut S) -> Self {
+impl<'a, E: Eeprom, M: Memory, R: Random, S: SecureChip> KeystoreHalImpl<'a, E, M, R, S> {
+ pub fn new(
+ eeprom: &'a mut E,
+ memory: &'a mut M,
+ random: &'a mut R,
+ securechip: &'a mut S,
+ ) -> Self {
Self {
+ eeprom,
memory,
random,
securechip,
@@ -53,23 +62,31 @@ impl<'a, M: Memory, R: Random, S: SecureChip> KeystoreHalImpl<'a, M, R, S> {
pub fn from_hal<H>(hal: &'a mut H) -> Self
where
- H: crate::hal::Hal<Memory = M, Random = R, SecureChip = S>,
+ H: crate::hal::Hal<Eeprom = E, Memory = M, Random = R, SecureChip = S>,
{
let crate::hal::HalSubsystems {
+ eeprom,
random,
securechip,
memory,
..
} = hal.as_mut();
- Self::new(memory, random, securechip)
+ Self::new(eeprom, memory, random, securechip)
}
}
-impl<M: Memory, R: Random, S: SecureChip> KeystoreHal for KeystoreHalImpl<'_, M, R, S> {
+impl<E: Eeprom, M: Memory, R: Random, S: SecureChip> KeystoreHal
+ for KeystoreHalImpl<'_, E, M, R, S>
+{
+ type Eeprom = E;
type Memory = M;
type Random = R;
type SecureChip = S;
+ fn eeprom(&mut self) -> &mut Self::Eeprom {
+ self.eeprom
+ }
+
fn memory(&mut self) -> &mut Self::Memory {
self.memory
}
@@ -429,7 +446,7 @@ pub async fn unlock(
return Err(Error::MaxAttemptsExceeded);
}
hal.system().communication_timeout_reset(LONG_TIMEOUT);
- hal.memory().increment_unlock_attempts();
+ hal.eeprom().increment_unlock_attempts();
let seed = match get_and_decrypt_seed(hal, password) {
Ok(seed) => seed,
err @ Err(_) => {
@@ -449,14 +466,14 @@ pub async fn unlock(
} else {
migrate_password_algo_and_retain_seed(hal, &seed, password)?;
}
- hal.memory().reset_unlock_attempts();
+ hal.eeprom().reset_unlock_attempts();
Ok(seed)
}
/// Returns the number of remaining unlock attempts (calls to `unlock()`) that are allowed before
/// the device resets itself.
pub fn get_remaining_unlock_attempts(hal: &mut impl crate::hal::Hal) -> u8 {
- let failed_attempts: u8 = hal.memory().get_unlock_attempts();
+ let failed_attempts: u8 = hal.eeprom().get_unlock_attempts();
MAX_UNLOCK_ATTEMPTS.saturating_sub(failed_attempts)
}
@@ -1330,11 +1347,11 @@ mod tests {
assert!(is_locked());
mock_hal
- .memory
+ .eeprom
.set_unlock_attempts_for_testing(MAX_UNLOCK_ATTEMPTS);
assert_eq!(get_remaining_unlock_attempts(&mut mock_hal), 0);
- assert_eq!(mock_hal.memory.get_unlock_attempts(), MAX_UNLOCK_ATTEMPTS);
+ assert_eq!(mock_hal.eeprom.get_unlock_attempts(), MAX_UNLOCK_ATTEMPTS);
assert!(matches!(
block_on(unlock(&mut mock_hal, "password")),
diff --git a/src/rust/bitbox02-rust/src/reset.rs b/src/rust/bitbox02-rust/src/reset.rs
index 1209f3b..0b335a9 100644
--- a/src/rust/bitbox02-rust/src/reset.rs
+++ b/src/rust/bitbox02-rust/src/reset.rs
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::general::abort;
-use crate::hal::{Memory, SecureChip, System, Ui, memory};
+use crate::hal::{Eeprom, Memory, SecureChip, System, Ui, memory};
/// Resets the device:
/// - Updates secure chip KDF keys.
@@ -51,7 +51,7 @@ pub(crate) async fn reset(hal: &mut impl crate::hal::Hal, status: bool) {
}
// Disable SmartEEPROM so it will be erased on next reboot.
- hal.system().smarteeprom_disable();
+ hal.eeprom().disable();
// Show "Device reset" status using the UI workflow.
hal.ui().status("Device reset", status).await;
@@ -89,7 +89,7 @@ mod tests {
mock_unlocked();
hal.memory.set_device_name("Custom name").unwrap();
assert!(!keystore::is_locked());
- assert!(hal.system.smarteeprom_enabled);
+ assert!(hal.eeprom.enabled);
// Make the reset keys call fail once, to test that it is retried.
hal.securechip.mock_reset_keys_fails();
@@ -110,7 +110,7 @@ mod tests {
assert_eq!(hal.memory.get_device_name().as_str(), "My BitBox");
// SmartEEPROM was disabled as part of the reset.
- assert!(!hal.system.smarteeprom_enabled);
+ assert!(!hal.eeprom.enabled);
assert_eq!(hal.securechip.get_u2f_counter(), 0);
diff --git a/src/rust/bitbox02-rust/src/workflow/unlock.rs b/src/rust/bitbox02-rust/src/workflow/unlock.rs
index 813c8bd..b320cb9 100644
--- a/src/rust/bitbox02-rust/src/workflow/unlock.rs
+++ b/src/rust/bitbox02-rust/src/workflow/unlock.rs
@@ -159,12 +159,14 @@ pub async fn unlock_bip39(hal: &mut impl crate::hal::Hal, seed: &[u8]) {
let result = {
let crate::hal::HalSubsystems {
ui,
+ eeprom,
random,
securechip,
memory,
..
} = hal.as_mut();
- let mut keystore_hal = crate::keystore::KeystoreHalImpl::new(memory, random, securechip);
+ let mut keystore_hal =
+ crate::keystore::KeystoreHalImpl::new(eeprom, memory, random, securechip);
let ((), result) = futures_lite::future::zip(
ui.unlock_animation(),
@@ -332,7 +334,7 @@ mod tests {
// Lock the keystore to simulate the normal locked state
crate::keystore::lock();
- mock_hal.memory.set_unlock_attempts_for_testing(1);
+ mock_hal.eeprom.set_unlock_attempts_for_testing(1);
let mut password_entered = false;
@@ -370,7 +372,7 @@ mod tests {
let mut mock_hal = TestingHal::new();
mock_hal
- .memory
+ .eeprom
.set_unlock_attempts_for_testing(crate::keystore::MAX_UNLOCK_ATTEMPTS - 1);
mock_hal.ui.abort_nth(0);
diff --git a/src/rust/bitbox02/src/hal.rs b/src/rust/bitbox02/src/hal.rs
index c1ad3be..745aa3a 100644
--- a/src/rust/bitbox02/src/hal.rs
+++ b/src/rust/bitbox02/src/hal.rs
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
+pub mod eeprom;
pub mod memory;
pub mod random;
pub mod sd;
@@ -15,6 +16,7 @@ pub struct BitBox02Hal {
random: random::BitBox02Random,
securechip: securechip::BitBox02SecureChip,
memory: memory::BitBox02Memory,
+ eeprom: eeprom::BitBox02Eeprom,
system: system::BitBox02System,
}
@@ -30,6 +32,7 @@ impl BitBox02Hal {
random: random::BitBox02Random,
securechip: securechip::BitBox02SecureChip,
memory: memory::BitBox02Memory,
+ eeprom: eeprom::BitBox02Eeprom,
system: system::BitBox02System,
}
}
@@ -41,6 +44,7 @@ impl Hal for BitBox02Hal {
type Sd = sd::BitBox02Sd;
type SecureChip = securechip::BitBox02SecureChip;
type Memory = memory::BitBox02Memory;
+ type Eeprom = eeprom::BitBox02Eeprom;
type System = system::BitBox02System;
fn as_mut(
@@ -52,6 +56,7 @@ impl Hal for BitBox02Hal {
Self::Sd,
Self::SecureChip,
Self::Memory,
+ Self::Eeprom,
Self::System,
> {
bitbox_hal::HalSubsystems {
@@ -60,6 +65,7 @@ impl Hal for BitBox02Hal {
sd: &mut self.sd,
securechip: &mut self.securechip,
memory: &mut self.memory,
+ eeprom: &mut self.eeprom,
system: &mut self.system,
}
}
diff --git a/src/rust/bitbox02/src/hal/eeprom.rs b/src/rust/bitbox02/src/hal/eeprom.rs
new file mode 100644
index 0000000..6148e80
--- /dev/null
+++ b/src/rust/bitbox02/src/hal/eeprom.rs
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: Apache-2.0
+
+use bitbox_hal::Eeprom;
+
+pub struct BitBox02Eeprom;
+
+impl Eeprom for BitBox02Eeprom {
+ fn setup(&mut self) {
+ unsafe { bitbox02_sys::smarteeprom_bb02_config() };
+ }
+
+ fn init(&mut self) {
+ unsafe { bitbox02_sys::bitbox02_smarteeprom_init() };
+ }
+
+ fn is_enabled(&mut self) -> bool {
+ unsafe { bitbox02_sys::smarteeprom_is_enabled() }
+ }
+
+ fn disable(&mut self) {
+ unsafe { bitbox02_sys::smarteeprom_disable() };
+ }
+
+ fn get_unlock_attempts(&mut self) -> u8 {
+ unsafe { bitbox02_sys::bitbox02_smarteeprom_get_unlock_attempts() }
+ }
+
+ fn increment_unlock_attempts(&mut self) {
+ unsafe {
+ bitbox02_sys::bitbox02_smarteeprom_increment_unlock_attempts();
+ }
+ }
+
+ fn reset_unlock_attempts(&mut self) {
+ unsafe {
+ bitbox02_sys::bitbox02_smarteeprom_reset_unlock_attempts();
+ }
+ }
+}
diff --git a/src/rust/bitbox02/src/hal/memory.rs b/src/rust/bitbox02/src/hal/memory.rs
index a633353..18f260c 100644
--- a/src/rust/bitbox02/src/hal/memory.rs
+++ b/src/rust/bitbox02/src/hal/memory.rs
@@ -215,18 +215,6 @@ impl Memory for BitBox02Memory {
crate::memory::reset_hww()
}
- fn get_unlock_attempts(&mut self) -> u8 {
- crate::memory::smarteeprom_get_unlock_attempts()
- }
-
- fn increment_unlock_attempts(&mut self) {
- crate::memory::smarteeprom_increment_unlock_attempts()
- }
-
- fn reset_unlock_attempts(&mut self) {
- crate::memory::smarteeprom_reset_unlock_attempts()
- }
-
fn get_io_protection_key(&mut self, out: &mut [u8; 32]) {
crate::memory::get_io_protection_key(out)
}
diff --git a/src/rust/bitbox02/src/hal/system.rs b/src/rust/bitbox02/src/hal/system.rs
index 7332dc1..9d91590 100644
--- a/src/rust/bitbox02/src/hal/system.rs
+++ b/src/rust/bitbox02/src/hal/system.rs
@@ -36,8 +36,4 @@ impl System for BitBox02System {
fn reset_ble(&mut self) {
crate::reset_ble()
}
-
- fn smarteeprom_disable(&mut self) {
- unsafe { bitbox02_sys::smarteeprom_disable() }
- }
}
diff --git a/src/rust/bitbox02/src/lib.rs b/src/rust/bitbox02/src/lib.rs
index 0422c57..9901e19 100644
--- a/src/rust/bitbox02/src/lib.rs
+++ b/src/rust/bitbox02/src/lib.rs
@@ -38,7 +38,6 @@ pub mod screen;
pub mod screen_saver;
pub mod sd;
pub mod securechip;
-pub mod smarteeprom;
pub mod spi_mem;
#[cfg(feature = "app-u2f")]
pub mod u2f;
diff --git a/src/rust/bitbox02/src/memory.rs b/src/rust/bitbox02/src/memory.rs
index 88e94a0..415eea8 100644
--- a/src/rust/bitbox02/src/memory.rs
+++ b/src/rust/bitbox02/src/memory.rs
@@ -163,22 +163,6 @@ pub fn reset_hww() -> Result<(), ()> {
}
}
-pub fn smarteeprom_get_unlock_attempts() -> u8 {
- unsafe { bitbox02_sys::bitbox02_smarteeprom_get_unlock_attempts() }
-}
-
-pub fn smarteeprom_increment_unlock_attempts() {
- unsafe {
- bitbox02_sys::bitbox02_smarteeprom_increment_unlock_attempts();
- }
-}
-
-pub fn smarteeprom_reset_unlock_attempts() {
- unsafe {
- bitbox02_sys::bitbox02_smarteeprom_reset_unlock_attempts();
- }
-}
-
pub fn multisig_set_by_hash(hash: &[u8], name: &str) -> Result<(), MemoryError> {
if hash.len() != 32 {
return Err(MemoryError::MEMORY_ERR_INVALID_INPUT);
diff --git a/src/rust/bitbox02/src/smarteeprom.rs b/src/rust/bitbox02/src/smarteeprom.rs
deleted file mode 100644
index f511c62..0000000
--- a/src/rust/bitbox02/src/smarteeprom.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-#[cfg(feature = "simulator-graphical")]
-pub fn bb02_config() {
- unsafe { bitbox02_sys::smarteeprom_bb02_config() };
-}
-
-#[cfg(feature = "simulator-graphical")]
-pub fn init() {
- unsafe { bitbox02_sys::bitbox02_smarteeprom_init() };
-}
diff --git a/src/rust/bitbox03/src/eeprom.rs b/src/rust/bitbox03/src/eeprom.rs
new file mode 100644
index 0000000..14b0466
--- /dev/null
+++ b/src/rust/bitbox03/src/eeprom.rs
@@ -0,0 +1,43 @@
+use bitbox_hal::Eeprom;
+
+pub struct BitBox03Eeprom {
+ enabled: bool,
+ unlock_attempts: u8,
+}
+
+impl BitBox03Eeprom {
+ pub const fn new() -> Self {
+ Self {
+ enabled: true,
+ unlock_attempts: 0,
+ }
+ }
+}
+
+impl Eeprom for BitBox03Eeprom {
+ fn setup(&mut self) {
+ self.enabled = true;
+ }
+
+ fn init(&mut self) {}
+
+ fn is_enabled(&mut self) -> bool {
+ self.enabled
+ }
+
+ fn disable(&mut self) {
+ self.enabled = false;
+ }
+
+ fn get_unlock_attempts(&mut self) -> u8 {
+ self.unlock_attempts
+ }
+
+ fn increment_unlock_attempts(&mut self) {
+ self.unlock_attempts = self.unlock_attempts.saturating_add(1);
+ }
+
+ fn reset_unlock_attempts(&mut self) {
+ self.unlock_attempts = 0;
+ }
+}
diff --git a/src/rust/bitbox03/src/lib.rs b/src/rust/bitbox03/src/lib.rs
index 2a2944b..a57b8df 100644
--- a/src/rust/bitbox03/src/lib.rs
+++ b/src/rust/bitbox03/src/lib.rs
@@ -4,6 +4,7 @@
extern crate alloc;
use core::cell::UnsafeCell;
+mod eeprom;
pub mod io;
mod memory;
mod random;
@@ -21,6 +22,7 @@ struct BitBox03State {
sd: sd::BitBox03Sd,
securechip: securechip::BitBox03SecureChip,
memory: memory::BitBox03Memory,
+ eeprom: eeprom::BitBox03Eeprom,
system: system::BitBox03System,
}
@@ -32,6 +34,7 @@ impl BitBox03State {
sd: sd::BitBox03Sd {},
securechip: securechip::BitBox03SecureChip {},
memory: memory::BitBox03Memory {},
+ eeprom: eeprom::BitBox03Eeprom::new(),
system: system::BitBox03System {},
}
}
@@ -83,6 +86,8 @@ impl hal::Hal for BitBox03 {
type Memory = memory::BitBox03Memory;
+ type Eeprom = eeprom::BitBox03Eeprom;
+
type System = system::BitBox03System;
fn as_mut(
@@ -94,6 +99,7 @@ impl hal::Hal for BitBox03 {
Self::Sd,
Self::SecureChip,
Self::Memory,
+ Self::Eeprom,
Self::System,
> {
let state = state();
@@ -103,6 +109,7 @@ impl hal::Hal for BitBox03 {
sd: &mut state.sd,
securechip: &mut state.securechip,
memory: &mut state.memory,
+ eeprom: &mut state.eeprom,
system: &mut state.system,
}
}
diff --git a/src/rust/bitbox03/src/memory.rs b/src/rust/bitbox03/src/memory.rs
index 36e07cc..22f38b2 100644
--- a/src/rust/bitbox03/src/memory.rs
+++ b/src/rust/bitbox03/src/memory.rs
@@ -100,19 +100,6 @@ impl hal::memory::Memory for BitBox03Memory {
fn reset_hww(&mut self) -> Result<(), ()> {
todo!()
}
-
- fn get_unlock_attempts(&mut self) -> u8 {
- todo!()
- }
-
- fn increment_unlock_attempts(&mut self) {
- todo!()
- }
-
- fn reset_unlock_attempts(&mut self) {
- todo!()
- }
-
fn get_salt_root(&mut self) -> Result<zeroize::Zeroizing<alloc::vec::Vec<u8>>, ()> {
todo!()
}
diff --git a/src/rust/bitbox03/src/system.rs b/src/rust/bitbox03/src/system.rs
index 389ee96..150d685 100644
--- a/src/rust/bitbox03/src/system.rs
+++ b/src/rust/bitbox03/src/system.rs
@@ -18,11 +18,6 @@ impl hal::system::System for BitBox03System {
fn reset_ble(&mut self) {
todo!()
}
-
- fn smarteeprom_disable(&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 15516a8..0eaabba 100644
--- a/test/simulator-graphical-bb03/src/main.rs
+++ b/test/simulator-graphical-bb03/src/main.rs
@@ -227,10 +227,6 @@ fn init_hww(_bitbox: &mut BitBox03, preseed: bool) -> bool {
//bitbox02_rust::keystore::encrypt_and_store_seed(&mut hal, &seed, "").unwrap();
//bitbox.memory().set_initialized().unwrap();
}
-
- //bitbox02::smarteeprom::bb02_config();
- //bitbox02::smarteeprom::init();
-
true
}
diff --git a/test/simulator-graphical/src/main.rs b/test/simulator-graphical/src/main.rs
index 9ad349a..5b4c041 100644
--- a/test/simulator-graphical/src/main.rs
+++ b/test/simulator-graphical/src/main.rs
@@ -39,7 +39,7 @@ use tracing::{debug, error, info};
use tracing_subscriber::{EnvFilter, filter::LevelFilter, fmt, prelude::*};
use bitbox02::ui::ugui::UG_COLOR;
-use bitbox02_rust::hal::{Hal, Memory, System};
+use bitbox02_rust::hal::{Eeprom, Hal, Memory, System};
// Explicitly link library for its C exports
extern crate bitbox02_rust_c;
@@ -159,16 +159,17 @@ fn init_hww(preseed: bool) -> bool {
bitbox02::memory::fake_nova();
info!("Memory setup: success");
+ let mut hal = bitbox02::hal::BitBox02Hal::new();
+
if preseed {
let mnemonic = "boring mistake dish oyster truth pigeon viable emerge sort crash wire portion cannon couple enact box walk height pull today solid off enable tide";
let seed = bitbox02_rust::bip39::mnemonic_to_seed(&mnemonic).unwrap();
- let mut hal = bitbox02::hal::BitBox02Hal::new();
bitbox02_rust::keystore::encrypt_and_store_seed(&mut hal, &seed, "").unwrap();
hal.memory().set_initialized().unwrap();
}
- bitbox02::smarteeprom::bb02_config();
- bitbox02::smarteeprom::init();
+ hal.eeprom().setup();
+ hal.eeprom().init();
true
}
Why this scored 17/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.