Skip to content

Commit 424d1ff

Browse files
committed
[wip] make bip39 unlocking async
1 parent 6c5bacd commit 424d1ff

File tree

6 files changed

+87
-17
lines changed

6 files changed

+87
-17
lines changed

src/rust/bitbox02-rust/src/keystore.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ mod tests {
270270
use bitbox02::testing::{
271271
TEST_MNEMONIC, mock_memory, mock_unlocked, mock_unlocked_using_mnemonic,
272272
};
273+
use util::bb02_async::block_on;
273274

274275
use bitcoin::secp256k1;
275276

@@ -573,7 +574,15 @@ mod tests {
573574
keystore::lock();
574575
let seed = &seed[..test.seed_len];
575576

576-
assert!(keystore::unlock_bip39(SECP256K1, seed, test.mnemonic_passphrase).is_err());
577+
assert!(
578+
block_on(keystore::unlock_bip39(
579+
SECP256K1,
580+
seed,
581+
test.mnemonic_passphrase,
582+
async |_idx| {}
583+
))
584+
.is_err()
585+
);
577586

578587
bitbox02::securechip::fake_event_counter_reset();
579588
assert!(keystore::encrypt_and_store_seed(seed, "foo").is_ok());
@@ -582,7 +591,15 @@ mod tests {
582591
assert!(keystore::is_locked());
583592

584593
bitbox02::securechip::fake_event_counter_reset();
585-
assert!(keystore::unlock_bip39(SECP256K1, seed, test.mnemonic_passphrase).is_ok());
594+
assert!(
595+
block_on(keystore::unlock_bip39(
596+
SECP256K1,
597+
seed,
598+
test.mnemonic_passphrase,
599+
async |_idx| {}
600+
))
601+
.is_ok()
602+
);
586603
assert_eq!(bitbox02::securechip::fake_event_counter(), 1);
587604

588605
assert!(!keystore::is_locked());

src/rust/bitbox02-rust/src/workflow/unlock.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,16 @@ pub async fn unlock_bip39(hal: &mut impl crate::hal::Hal, seed: &[u8]) {
133133
}
134134
}
135135

136-
let result = bitbox02::ui::with_lock_animation(|| {
137-
keystore::unlock_bip39(crate::secp256k1::SECP256K1, seed, &mnemonic_passphrase)
138-
});
136+
let result = bitbox02::ui::with_lock_animation(async || {
137+
keystore::unlock_bip39(
138+
crate::secp256k1::SECP256K1,
139+
seed,
140+
&mnemonic_passphrase,
141+
async |_idx| util::bb02_async::yield_now().await,
142+
)
143+
.await
144+
})
145+
.await;
139146
if result.is_err() {
140147
abort("bip39 unlock failed");
141148
}

src/rust/bitbox02/src/keystore.rs

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,18 @@ fn unlock_bip39_finalize(bip39_seed: &[u8; 64]) -> Result<(), Error> {
111111
}
112112
}
113113

114-
fn derive_bip39_seed(
114+
async fn derive_bip39_seed(
115115
secp: &Secp256k1<All>,
116116
seed: &[u8],
117117
mnemonic_passphrase: &str,
118+
yield_now: impl AsyncFn(usize),
118119
) -> (zeroize::Zeroizing<[u8; 64]>, [u8; 4]) {
119120
let mnemonic = bip39::Mnemonic::from_entropy_in(bip39::Language::English, seed).unwrap();
120-
let bip39_seed: zeroize::Zeroizing<[u8; 64]> =
121-
zeroize::Zeroizing::new(mnemonic.to_seed_normalized(mnemonic_passphrase));
121+
let bip39_seed: zeroize::Zeroizing<[u8; 64]> = zeroize::Zeroizing::new(
122+
mnemonic
123+
.to_seed_normalized_async(mnemonic_passphrase, yield_now)
124+
.await,
125+
);
122126
let root_fingerprint: [u8; 4] =
123127
bitcoin::bip32::Xpriv::new_master(bitcoin::NetworkKind::Main, bip39_seed.as_ref())
124128
.unwrap()
@@ -132,14 +136,16 @@ fn derive_bip39_seed(
132136
/// of `keystore_copy_seed()`).
133137
/// `mnemonic_passphrase` is the bip39 passphrase used in the derivation. Use the empty string if no
134138
/// passphrase is needed or provided.
135-
pub fn unlock_bip39(
139+
pub async fn unlock_bip39(
136140
secp: &Secp256k1<All>,
137141
seed: &[u8],
138142
mnemonic_passphrase: &str,
143+
yield_now: impl AsyncFn(usize),
139144
) -> Result<(), Error> {
140145
unlock_bip39_check(seed)?;
141146

142-
let (bip39_seed, root_fingerprint) = derive_bip39_seed(secp, seed, mnemonic_passphrase);
147+
let (bip39_seed, root_fingerprint) =
148+
derive_bip39_seed(secp, seed, mnemonic_passphrase, yield_now).await;
143149

144150
unlock_bip39_finalize(bip39_seed.as_slice().try_into().unwrap())?;
145151

@@ -279,6 +285,7 @@ mod tests {
279285
use bitcoin::secp256k1;
280286

281287
use crate::testing::{mock_memory, mock_unlocked_using_mnemonic};
288+
use util::bb02_async::block_on;
282289

283290
#[test]
284291
fn test_secp256k1_sign() {
@@ -442,7 +449,15 @@ mod tests {
442449
.unwrap();
443450
assert!(encrypt_and_store_seed(&seed, "password").is_ok());
444451
assert!(is_locked()); // still locked, it is only unlocked after unlock_bip39.
445-
assert!(unlock_bip39(&secp256k1::Secp256k1::new(), &seed, "foo").is_ok());
452+
assert!(
453+
block_on(unlock_bip39(
454+
&secp256k1::Secp256k1::new(),
455+
&seed,
456+
"foo",
457+
async |_idx| {}
458+
))
459+
.is_ok()
460+
);
446461
assert!(!is_locked());
447462
lock();
448463
assert!(is_locked());
@@ -569,7 +584,12 @@ mod tests {
569584
let secp = secp256k1::Secp256k1::new();
570585
for test in tests {
571586
let seed = hex::decode(test.seed).unwrap();
572-
let (bip39_seed, root_fingerprint) = derive_bip39_seed(&secp, &seed, test.passphrase);
587+
let (bip39_seed, root_fingerprint) = block_on(derive_bip39_seed(
588+
&secp,
589+
&seed,
590+
test.passphrase,
591+
async |_idx| {},
592+
));
573593
assert_eq!(hex::encode(bip39_seed).as_str(), test.expected_bip39_seed);
574594
assert_eq!(
575595
hex::encode(root_fingerprint).as_str(),
@@ -597,9 +617,17 @@ mod tests {
597617
assert!(encrypt_and_store_seed(&seed, "password").is_ok());
598618
assert!(root_fingerprint().is_err());
599619
// Incorrect seed passed
600-
assert!(unlock_bip39(&secp, b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "foo").is_err());
620+
assert!(
621+
block_on(unlock_bip39(
622+
&secp,
623+
b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
624+
"foo",
625+
async |_idx| {}
626+
))
627+
.is_err()
628+
);
601629
// Correct seed passed.
602-
assert!(unlock_bip39(&secp, &seed, "foo").is_ok());
630+
assert!(block_on(unlock_bip39(&secp, &seed, "foo", async |_idx| {})).is_ok());
603631
assert_eq!(root_fingerprint(), Ok(vec![0xf1, 0xbc, 0x3c, 0x46]),);
604632

605633
let expected_bip39_seed = hex::decode("2b3c63de86f0f2b13cc6a36c1ba2314fbc1b40c77ab9cb64e96ba4d5c62fc204748ca6626a9f035e7d431bce8c9210ec0bdffc2e7db873dee56c8ac2153eee9a").unwrap();

src/rust/bitbox02/src/testing.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@ pub fn mock_unlocked_using_mnemonic(mnemonic: &str, passphrase: &str) {
2222
unsafe {
2323
bitbox02_sys::keystore_mock_unlocked(seed.as_ptr(), seed.len() as _, core::ptr::null())
2424
}
25-
keystore::unlock_bip39(&bitcoin::secp256k1::Secp256k1::new(), &seed, passphrase).unwrap();
25+
util::bb02_async::block_on(keystore::unlock_bip39(
26+
&bitcoin::secp256k1::Secp256k1::new(),
27+
&seed,
28+
passphrase,
29+
async |_idx| {},
30+
))
31+
.unwrap();
2632
}
2733

2834
pub const TEST_MNEMONIC: &str = "purity concert above invest pigeon category peace tuition hazard vivid latin since legal speak nation session onion library travel spell region blast estate stay";

src/rust/bitbox02/src/ui/ui.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,9 +436,9 @@ pub fn trinary_input_string_set_input(component: &mut Component, word: &str) {
436436
}
437437
}
438438

439-
pub fn with_lock_animation<F: Fn() -> R, R>(f: F) -> R {
439+
pub async fn with_lock_animation<F: AsyncFn() -> R, R>(f: F) -> R {
440440
unsafe { bitbox02_sys::lock_animation_start() };
441-
let result = f();
441+
let result = f().await;
442442
unsafe { bitbox02_sys::lock_animation_stop() };
443443
result
444444
}

src/rust/util/src/bb02_async.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,15 @@ pub fn block_on<O>(task: impl core::future::Future<Output = O>) -> O {
5959
}
6060
}
6161
}
62+
63+
pub fn yield_now() -> impl core::future::Future<Output = ()> {
64+
let mut yielded = false;
65+
core::future::poll_fn(move |_cx| {
66+
if yielded {
67+
core::task::Poll::Ready(())
68+
} else {
69+
yielded = true;
70+
core::task::Poll::Pending
71+
}
72+
})
73+
}

0 commit comments

Comments
 (0)