rust/keystore: wrap is_locked() in bitbox02-rust
What changed, and why it matters
This commit is a routine internal code reorganization. It moves the keystore's `is_locked()` check from a low-level C-binding module into a higher-level Rust wrapper, renaming the original function to `_is_locked()` so the compiler flags any leftover direct uses. There is no change to what the function does or to any security behavior.
No security action required; treat as normal refactoring review.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch wraps bitbox02::keystore::is_locked() as bitbox02_rust::keystore::is_locked(), delegating to a renamed keystore::_is_locked(). All call sites in production and test code are updated to use the new wrapper. The logic and return value remain identical; this is purely an abstraction-layer refactor to prepare for future native Rust implementations.
Changed components
src/rust/bitbox02-rust/src/keystore.rssrc/rust/bitbox02/src/keystore.rssrc/rust/bitbox02-rust/src/hww.rssrc/rust/bitbox02-rust/src/hww/api.rssrc/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rssrc/rust/bitbox02-rust/src/hww/api/restore.rssrc/rust/bitbox02-rust/src/hww/api/set_password.rssrc/rust/bitbox02-rust/src/workflow/unlock.rsInspect captured patch +27 / −22
diff --git a/src/rust/bitbox02-rust/src/hww.rs b/src/rust/bitbox02-rust/src/hww.rs
index 43e33ff..18766ce 100644
--- a/src/rust/bitbox02-rust/src/hww.rs
+++ b/src/rust/bitbox02-rust/src/hww.rs
@@ -329,7 +329,7 @@ mod tests {
}]
);
- assert!(!bitbox02::keystore::is_locked());
+ assert!(!crate::keystore::is_locked());
assert!(bitbox02::memory::is_seeded());
assert!(!bitbox02::memory::is_initialized());
@@ -391,7 +391,7 @@ mod tests {
.as_ref(),
)
.unwrap();
- assert!(!bitbox02::keystore::is_locked());
+ assert!(!crate::keystore::is_locked());
assert!(!bitbox02::memory::is_initialized());
let mut mock_hal = TestingHal::new();
mock_hal.sd.inserted = Some(true);
@@ -456,7 +456,7 @@ mod tests {
block_on(_process_packet(&mut mock_hal, vec![OP_UNLOCK])),
[OP_STATUS_SUCCESS].to_vec()
);
- assert!(!bitbox02::keystore::is_locked());
+ assert!(!crate::keystore::is_locked());
// Since in the previous request the msg was encrypted but not decrypted (query was
// rejected), the noise states are out of sync and we need to make a new channel.
diff --git a/src/rust/bitbox02-rust/src/hww/api.rs b/src/rust/bitbox02-rust/src/hww/api.rs
index 025ad60..30b5741 100644
--- a/src/rust/bitbox02-rust/src/hww/api.rs
+++ b/src/rust/bitbox02-rust/src/hww/api.rs
@@ -110,7 +110,7 @@ fn can_call(request: &Request) -> bool {
InitializedAndUnlocked,
}
let state: State = if bitbox02::memory::is_initialized() {
- if bitbox02::keystore::is_locked() {
+ if crate::keystore::is_locked() {
State::InitializedAndLocked
} else {
State::InitializedAndUnlocked
diff --git a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs
index 629f386..19a1fec 100644
--- a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs
@@ -661,7 +661,7 @@ async fn _process(
hal: &mut impl crate::hal::Hal,
request: &pb::BtcSignInitRequest,
) -> Result<Response, Error> {
- if bitbox02::keystore::is_locked() {
+ if crate::keystore::is_locked() {
return Err(Error::InvalidState);
}
// Validate the coin.
diff --git a/src/rust/bitbox02-rust/src/hww/api/restore.rs b/src/rust/bitbox02-rust/src/hww/api/restore.rs
index 52dd088..3e0d13e 100644
--- a/src/rust/bitbox02-rust/src/hww/api/restore.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/restore.rs
@@ -203,7 +203,7 @@ mod tests {
assert_eq!(bitbox02::securechip::fake_event_counter(), 8);
drop(mock_hal); // to remove mutable borrow of counter
assert_eq!(counter, 2);
- assert!(!keystore::is_locked());
+ assert!(!crate::keystore::is_locked());
assert!(memory::is_initialized());
// Seed of hardcoded phrase used in unit tests:
// boring mistake dish oyster truth pigeon viable emerge sort crash wire portion cannon couple enact box walk height pull today solid off enable tide
diff --git a/src/rust/bitbox02-rust/src/hww/api/set_password.rs b/src/rust/bitbox02-rust/src/hww/api/set_password.rs
index cb88984..21a5859 100644
--- a/src/rust/bitbox02-rust/src/hww/api/set_password.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/set_password.rs
@@ -83,7 +83,7 @@ mod tests {
assert_eq!(bitbox02::securechip::fake_event_counter(), 9);
drop(mock_hal); // to remove mutable borrow of counter
assert_eq!(counter, 2);
- assert!(!keystore::is_locked());
+ assert!(!crate::keystore::is_locked());
assert!(crate::keystore::copy_seed().unwrap().len() == 32);
}
@@ -105,7 +105,7 @@ mod tests {
)),
Ok(Response::Success(pb::Success {}))
);
- assert!(!keystore::is_locked());
+ assert!(!crate::keystore::is_locked());
assert!(crate::keystore::copy_seed().unwrap().len() == 16);
}
@@ -118,7 +118,7 @@ mod tests {
mock_hal
.ui
.set_enter_string(Box::new(|_params| Ok("password".into())));
- assert!(keystore::is_locked());
+ assert!(crate::keystore::is_locked());
assert_eq!(
block_on(process(
&mut mock_hal,
@@ -128,7 +128,7 @@ mod tests {
)),
Err(Error::InvalidInput),
);
- assert!(keystore::is_locked());
+ assert!(crate::keystore::is_locked());
}
#[test]
@@ -154,6 +154,6 @@ mod tests {
)),
Err(Error::Generic),
);
- assert!(keystore::is_locked());
+ assert!(crate::keystore::is_locked());
}
}
diff --git a/src/rust/bitbox02-rust/src/keystore.rs b/src/rust/bitbox02-rust/src/keystore.rs
index e325f46..c60f65f 100644
--- a/src/rust/bitbox02-rust/src/keystore.rs
+++ b/src/rust/bitbox02-rust/src/keystore.rs
@@ -36,6 +36,11 @@ pub fn lock() {
keystore::_lock();
}
+/// Returns false if the keystore is unlocked (unlock() followed by unlock_bip39()), true otherwise.
+pub fn is_locked() -> bool {
+ keystore::_is_locked()
+}
+
/// Returns a copy of the retained seed. Errors if the keystore is locked.
pub fn copy_seed() -> Result<zeroize::Zeroizing<Vec<u8>>, ()> {
keystore::_copy_seed()
@@ -101,7 +106,7 @@ pub fn get_xpub_twice(keypath: &[u32]) -> Result<bip32::Xpub, ()> {
/// Gets multiple xpubs at once. This is better than multiple calls to `get_xpub_twice()` as it only
/// uses two secure chip operations in total, instead of two per xpub.
pub fn get_xpubs_twice(keypaths: &[&[u32]]) -> Result<Vec<bip32::Xpub>, ()> {
- if keystore::is_locked() {
+ if is_locked() {
return Err(());
}
if keypaths.is_empty() {
@@ -433,12 +438,12 @@ mod tests {
#[test]
fn test_lock() {
lock();
- assert!(keystore::is_locked());
+ assert!(is_locked());
let seed = hex::decode("cb33c20cea62a5c277527e2002da82e6e2b37450a755143a540a54cea8da9044")
.unwrap();
assert!(keystore::encrypt_and_store_seed(&seed, "password").is_ok());
- assert!(keystore::is_locked()); // still locked, it is only unlocked after unlock_bip39.
+ assert!(is_locked()); // still locked, it is only unlocked after unlock_bip39.
assert!(
block_on(keystore::unlock_bip39(
&secp256k1::Secp256k1::new(),
@@ -448,9 +453,9 @@ mod tests {
))
.is_ok()
);
- assert!(!keystore::is_locked());
+ assert!(!is_locked());
lock();
- assert!(keystore::is_locked());
+ assert!(is_locked());
}
#[test]
@@ -836,7 +841,7 @@ mod tests {
assert!(keystore::encrypt_and_store_seed(seed, "foo").is_ok());
assert_eq!(bitbox02::securechip::fake_event_counter(), 7);
- assert!(keystore::is_locked());
+ assert!(is_locked());
bitbox02::securechip::fake_event_counter_reset();
assert!(
@@ -850,7 +855,7 @@ mod tests {
);
assert_eq!(bitbox02::securechip::fake_event_counter(), 1);
- assert!(!keystore::is_locked());
+ assert!(!is_locked());
assert_eq!(
get_bip39_mnemonic().unwrap().as_str(),
test.expected_mnemonic,
diff --git a/src/rust/bitbox02-rust/src/workflow/unlock.rs b/src/rust/bitbox02-rust/src/workflow/unlock.rs
index ad346ca..9e85e10 100644
--- a/src/rust/bitbox02-rust/src/workflow/unlock.rs
+++ b/src/rust/bitbox02-rust/src/workflow/unlock.rs
@@ -168,7 +168,7 @@ pub async fn unlock(hal: &mut impl crate::hal::Hal) -> Result<(), ()> {
if !bitbox02::memory::is_initialized() {
return Err(());
}
- if !bitbox02::keystore::is_locked() {
+ if !crate::keystore::is_locked() {
return Ok(());
}
@@ -221,7 +221,7 @@ mod tests {
// 6 for keystore unlock, 1 for keystore bip39 unlock.
assert_eq!(bitbox02::securechip::fake_event_counter(), 7);
- assert!(!bitbox02::keystore::is_locked());
+ assert!(!crate::keystore::is_locked());
assert_eq!(
bitbox02::keystore::copy_bip39_seed().unwrap().as_slice(),
diff --git a/src/rust/bitbox02/src/keystore.rs b/src/rust/bitbox02/src/keystore.rs
index 8d2b46f..e722896 100644
--- a/src/rust/bitbox02/src/keystore.rs
+++ b/src/rust/bitbox02/src/keystore.rs
@@ -32,7 +32,7 @@ pub const MAX_SEED_LENGTH: usize = bitbox02_sys::KEYSTORE_MAX_SEED_LENGTH as usi
static ROOT_FINGERPRINT: SyncUnsafeCell<Option<[u8; 4]>> = SyncUnsafeCell::new(None);
-pub fn is_locked() -> bool {
+pub fn _is_locked() -> bool {
unsafe { bitbox02_sys::keystore_is_locked() }
}
@@ -171,7 +171,7 @@ pub async fn unlock_bip39(
}
pub fn root_fingerprint() -> Result<Vec<u8>, ()> {
- if is_locked() {
+ if _is_locked() {
return Err(());
}
unsafe { ROOT_FINGERPRINT.read().ok_or(()).map(|fp| fp.to_vec()) }
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.