From 3a6ea60aa5094d08dda1c0cdf2a36eae2786f340 Mon Sep 17 00:00:00 2001 From: Marko Bencun Date: Tue, 21 Apr 2026 19:49:59 +0000 Subject: [PATCH 1/2] rust: box some futures in callers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduces binary size by ~1360b. async fn lowers to a concrete state-machine type. In a function like signtx::_process() in src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs, every directly-awaited child future becomes part of that parent future’s stored state. If the child is large, the parent future gets larger too, and its generated poll() logic has to handle that larger layout. Box::pin(child()).await changes the shape of the parent future: - The child future is still a concrete type. - But the parent no longer stores that full child state inline. - It stores a boxed pointer instead. - So the parent future becomes smaller and simpler. --- src/rust/bitbox02-rust/src/hww/api.rs | 9 +- .../src/hww/api/bitcoin/signtx.rs | 139 +++++++++++------- src/rust/bitbox02-rust/src/keystore.rs | 8 +- 3 files changed, 98 insertions(+), 58 deletions(-) diff --git a/src/rust/bitbox02-rust/src/hww/api.rs b/src/rust/bitbox02-rust/src/hww/api.rs index df1ce5890f..619824b745 100644 --- a/src/rust/bitbox02-rust/src/hww/api.rs +++ b/src/rust/bitbox02-rust/src/hww/api.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::pb; +use alloc::boxed::Box; pub(super) mod error; @@ -64,11 +65,11 @@ async fn process_api_btc( request: &Request, ) -> Result { match request { - Request::BtcPub(request) => bitcoin::process_pub(hal, request).await, - Request::BtcSignInit(request) => bitcoin::signtx::process(hal, request).await, + Request::BtcPub(request) => Box::pin(bitcoin::process_pub(hal, request)).await, + Request::BtcSignInit(request) => Box::pin(bitcoin::signtx::process(hal, request)).await, Request::Btc(pb::BtcRequest { request: Some(request), - }) => bitcoin::process_api(hal, request) + }) => Box::pin(bitcoin::process_api(hal, request)) .await .map(|r| Response::Btc(pb::BtcResponse { response: Some(r) })), _ => Err(Error::Generic), @@ -188,7 +189,7 @@ async fn process_api(hal: &mut impl crate::hal::Hal, request: &Request) -> Resul Request::Fingerprint(pb::RootFingerprintRequest {}) => rootfingerprint::process(), request @ Request::BtcPub(_) | request @ Request::Btc(_) - | request @ Request::BtcSignInit(_) => process_api_btc(hal, request).await, + | request @ Request::BtcSignInit(_) => Box::pin(process_api_btc(hal, request)).await, #[cfg(feature = "app-cardano")] Request::Cardano(pb::CardanoRequest { 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 3f3b3a66a6..a5c4ec75bb 100644 --- a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs +++ b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs @@ -15,6 +15,7 @@ use crate::secp256k1::SECP256K1; use crate::workflow::transaction; use crate::xpubcache::{Bip32XpubCache, Compute}; +use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; @@ -86,7 +87,7 @@ async fn get_tx_input( index: u32, response: &mut NextResponse, ) -> Result { - let request = get_request(NextType::Input, index, None, response).await?; + let request = Box::pin(get_request(NextType::Input, index, None, response)).await?; response.wrap = false; match request { Request::BtcSignInput(request) => Ok(request), @@ -100,7 +101,7 @@ async fn get_prevtx_init( ) -> Result { response.next.r#type = NextType::PrevtxInit as _; response.next.index = index; - let request = get_request(NextType::PrevtxInit, index, None, response).await?; + let request = Box::pin(get_request(NextType::PrevtxInit, index, None, response)).await?; response.wrap = true; match request { Request::Btc(pb::BtcRequest { @@ -115,12 +116,12 @@ async fn get_prevtx_input( prevtx_input_index: u32, response: &mut NextResponse, ) -> Result { - let request = get_request( + let request = Box::pin(get_request( NextType::PrevtxInput, input_index, Some(prevtx_input_index), response, - ) + )) .await?; response.wrap = true; match request { @@ -136,12 +137,12 @@ async fn get_prevtx_output( prevtx_output_index: u32, response: &mut NextResponse, ) -> Result { - let request = get_request( + let request = Box::pin(get_request( NextType::PrevtxOutput, output_index, Some(prevtx_output_index), response, - ) + )) .await?; response.wrap = true; match request { @@ -156,7 +157,7 @@ async fn get_tx_output( index: u32, response: &mut NextResponse, ) -> Result { - let request = get_request(NextType::Output, index, None, response).await?; + let request = Box::pin(get_request(NextType::Output, index, None, response)).await?; response.wrap = false; match request { Request::BtcSignOutput(request) => Ok(request), @@ -168,7 +169,7 @@ async fn get_payment_request( index: u32, response: &mut NextResponse, ) -> Result { - let request = get_request(NextType::PaymentRequest, index, None, response).await?; + let request = Box::pin(get_request(NextType::PaymentRequest, index, None, response)).await?; response.wrap = true; match request { Request::Btc(pb::BtcRequest { @@ -182,7 +183,7 @@ async fn get_antiklepto_host_nonce( index: u32, response: &mut NextResponse, ) -> Result { - let request = get_request(NextType::HostNonce, index, None, response).await?; + let request = Box::pin(get_request(NextType::HostNonce, index, None, response)).await?; response.wrap = true; match request { Request::Btc(pb::BtcRequest { @@ -309,7 +310,9 @@ async fn sighash_script( SimpleType::P2wpkhP2sh | SimpleType::P2wpkh => { // See https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification, item 5: // > For P2WPKH witness program, the scriptCode is 0x1976a914{20-byte-pubkey-hash}88ac. - let pubkey_hash160 = xpub_cache.get_xpub(hal, keypath).await?.pubkey_hash160(); + let pubkey_hash160 = Box::pin(xpub_cache.get_xpub(hal, keypath)) + .await? + .pubkey_hash160(); let mut result = Vec::::new(); result.extend_from_slice(b"\x76\xa9\x14"); result.extend_from_slice(&pubkey_hash160); @@ -347,7 +350,7 @@ async fn handle_prevtx( progress_component: &mut impl Progress, next_response: &mut NextResponse, ) -> Result<(), Error> { - let prevtx_init = get_prevtx_init(input_index, next_response).await?; + let prevtx_init = Box::pin(get_prevtx_init(input_index, next_response)).await?; if prevtx_init.num_inputs < 1 || prevtx_init.num_outputs < 1 @@ -369,7 +372,12 @@ async fn handle_prevtx( (input_index as f32 + subprogress) * step }); - let prevtx_input = get_prevtx_input(input_index, prevtx_input_index, next_response).await?; + let prevtx_input = Box::pin(get_prevtx_input( + input_index, + prevtx_input_index, + next_response, + )) + .await?; hasher.update(prevtx_input.prev_out_hash.as_slice()); hasher.update(prevtx_input.prev_out_index.to_le_bytes()); hasher.update(serialize(&VarInt( @@ -389,8 +397,12 @@ async fn handle_prevtx( (input_index as f32 + subprogress) * step }); - let prevtx_output = - get_prevtx_output(input_index, prevtx_output_index, next_response).await?; + let prevtx_output = Box::pin(get_prevtx_output( + input_index, + prevtx_output_index, + next_response, + )) + .await?; if prevtx_output_index == input.prev_out_index && input.prev_out_value != prevtx_output.value { @@ -438,7 +450,8 @@ async fn validate_script_config<'a>( }), keypath, } => { - let parsed_policy = super::policies::parse(hal, policy, coin_params.coin).await?; + let parsed_policy = + Box::pin(super::policies::parse(hal, policy, coin_params.coin)).await?; let name = parsed_policy .name(hal, coin_params)? .ok_or(Error::InvalidInput)?; @@ -481,7 +494,7 @@ async fn validate_script_configs<'a>( ) -> Result>, Error> { let mut validated = Vec::with_capacity(script_configs.len()); for config in script_configs.iter() { - validated.push(validate_script_config(hal, config, coin_params).await?); + validated.push(Box::pin(validate_script_config(hal, config, coin_params)).await?); } Ok(validated) } @@ -495,7 +508,8 @@ async fn validate_input_script_configs<'a>( return Err(Error::InvalidInput); } - let script_configs = validate_script_configs(hal, coin_params, script_configs).await?; + let script_configs = + Box::pin(validate_script_configs(hal, coin_params, script_configs)).await?; // If there are multiple script configs, only SimpleType (single sig, no additional inputs) // configs are allowed, so e.g. mixing p2wpkh and pw2wpkh-p2sh is okay, but mixing p2wpkh with @@ -710,10 +724,18 @@ async fn _process( if request.num_inputs < 1 || request.num_outputs < 1 { return Err(Error::InvalidInput); } - let validated_script_configs = - validate_input_script_configs(hal, coin_params, &request.script_configs).await?; - let validated_output_script_configs = - validate_script_configs(hal, coin_params, &request.output_script_configs).await?; + let validated_script_configs = Box::pin(validate_input_script_configs( + hal, + coin_params, + &request.script_configs, + )) + .await?; + let validated_output_script_configs = Box::pin(validate_script_configs( + hal, + coin_params, + &request.output_script_configs, + )) + .await?; let mut xpub_cache = Bip32XpubCache::new(Compute::Once); setup_xpub_cache(&mut xpub_cache, &request.script_configs); @@ -761,7 +783,7 @@ async fn _process( .unwrap() .set((input_index as f32) / (request.num_inputs as f32)); - let tx_input = get_tx_input(input_index, &mut next_response).await?; + let tx_input = Box::pin(get_tx_input(input_index, &mut next_response)).await?; let script_config_account = validated_script_configs .get(tx_input.script_config_index as usize) .ok_or(Error::InvalidInput)?; @@ -793,33 +815,37 @@ async fn _process( // https://github.com/bitcoin/bips/blob/bb8dc57da9b3c6539b88378348728a2ff43f7e9c/bip-0341.mediawiki#common-signature-message // accumulate `sha_scriptpubkeys` - let pk_script = common::Payload::from( + let pk_script = Box::pin(common::Payload::from( hal, &mut xpub_cache, coin_params, &tx_input.keypath, script_config_account, - ) + )) .await? .pk_script(coin_params)?; hasher_scriptpubkeys.update(serialize(&VarInt(pk_script.len() as u64))); hasher_scriptpubkeys.update(pk_script.as_slice()); if !taproot_only { - handle_prevtx( + Box::pin(handle_prevtx( input_index, &tx_input, request.num_inputs, progress_component.as_mut().unwrap(), &mut next_response, - ) + )) .await?; } if let Some(ref mut silent_payment) = silent_payment { let keypair = bitcoin::key::UntweakedKeypair::from_seckey_slice( SECP256K1, - &crate::keystore::secp256k1_get_private_key(hal, &tx_input.keypath).await?, + &Box::pin(crate::keystore::secp256k1_get_private_key( + hal, + &tx_input.keypath, + )) + .await?, ) .unwrap(); // For Taproot, only key path spends are allowed in silent payments, and we need to @@ -871,7 +897,7 @@ async fn _process( let mut hasher_outputs = Sha256::new(); for output_index in 0..request.num_outputs { - let tx_output = get_tx_output(output_index, &mut next_response).await?; + let tx_output = Box::pin(get_tx_output(output_index, &mut next_response)).await?; if output_index == 0 { // Stop rendering inputs progress update. drop(progress_component.take()); @@ -913,13 +939,13 @@ async fn _process( keypath::ReceiveSpend::Receive, )?; - common::Payload::from( + Box::pin(common::Payload::from( hal, &mut xpub_cache, coin_params, &tx_output.keypath, script_config_account, - ) + )) .await? } else { // Take payload from provided output. @@ -1001,8 +1027,11 @@ async fn _process( if payment_request_seen { return Err(Error::InvalidInput); } - let payment_request: pb::BtcPaymentRequestRequest = - get_payment_request(output_payment_request_index, &mut next_response).await?; + let payment_request: pb::BtcPaymentRequestRequest = Box::pin(get_payment_request( + output_payment_request_index, + &mut next_response, + )) + .await?; if payment_request::contains_coin_purchase_memo(&payment_request) { validate_swap_source_account(coin, &validated_script_configs)?; } @@ -1010,15 +1039,19 @@ async fn _process( // payment-request total equals the current output value. let total_value = tx_output.value; let displayed_source_amount = format_amount(coin_params, format_unit, total_value)?; - payment_request::user_verify(hal, &payment_request, &displayed_source_amount) - .await?; - match payment_request::validate_btc( + Box::pin(payment_request::user_verify( + hal, + &payment_request, + &displayed_source_amount, + )) + .await?; + match Box::pin(payment_request::validate_btc( hal, coin_params, &payment_request, total_value, &address()?, - ) + )) .await { Ok(()) => {} @@ -1151,12 +1184,12 @@ async fn _process( } else { Some(100. * (fee as f64) / (outputs_sum_out as f64)) }; - transaction::verify_total_fee_maybe_warn( + Box::pin(transaction::verify_total_fee_maybe_warn( hal, &format_amount(coin_params, format_unit, total_out)?, &format_amount(coin_params, format_unit, fee)?, fee_percentage, - ) + )) .await?; hal.ui().status("Transaction\nconfirmed", true).await; @@ -1176,7 +1209,7 @@ async fn _process( // Will contain the sum of all spent output values in the second inputs pass. let mut inputs_sum_pass2: u64 = 0; for input_index in 0..request.num_inputs { - let tx_input = get_tx_input(input_index, &mut next_response).await?; + let tx_input = Box::pin(get_tx_input(input_index, &mut next_response)).await?; let script_config_account = validated_script_configs .get(tx_input.script_config_index as usize) .ok_or(Error::InvalidInput)?; @@ -1202,7 +1235,7 @@ async fn _process( ValidatedScriptConfig::SimpleType(SimpleType::P2tr) => { // This is a BIP-86 spend, so we tweak the private key by the hash of the public // key only, as there is no Taproot merkle root. - let xpub = xpub_cache.get_xpub(hal, &tx_input.keypath).await?; + let xpub = Box::pin(xpub_cache.get_xpub(hal, &tx_input.keypath)).await?; let pubkey = bitcoin::PublicKey::from_slice(xpub.public_key()) .map_err(|_| Error::Generic)?; TaprootSpendInfo::KeySpend(bitcoin::TapTweakHash::from_key_and_tweak( @@ -1216,9 +1249,12 @@ async fn _process( // first tweak the private key to match the Taproot output key. For leaf // scripts, we do not tweak. - parsed_policy - .taproot_spend_info(hal, &mut xpub_cache, &tx_input.keypath) - .await? + Box::pin(parsed_policy.taproot_spend_info( + hal, + &mut xpub_cache, + &tx_input.keypath, + )) + .await? } _ => return Err(Error::Generic), }; @@ -1239,7 +1275,7 @@ async fn _process( }); next_response.next.has_signature = true; - next_response.next.signature = crate::keystore::secp256k1_schnorr_sign( + next_response.next.signature = Box::pin(crate::keystore::secp256k1_schnorr_sign( hal, &tx_input.keypath, &sighash, @@ -1248,7 +1284,7 @@ async fn _process( } else { None }, - ) + )) .await? .to_vec(); } else { @@ -1261,12 +1297,12 @@ async fn _process( hash_sequence: Sha256::digest(hash_sequence).into(), outpoint_hash: tx_input.prev_out_hash.as_slice().try_into().unwrap(), outpoint_index: tx_input.prev_out_index, - sighash_script: &sighash_script( + sighash_script: &Box::pin(sighash_script( hal, &mut xpub_cache, script_config_account, &tx_input.keypath, - ) + )) .await?, prevout_value: tx_input.prev_out_value, sequence: tx_input.sequence, @@ -1275,8 +1311,11 @@ async fn _process( sighash_flags: SIGHASH_ALL, }); - let private_key = - crate::keystore::secp256k1_get_private_key(hal, &tx_input.keypath).await?; + let private_key = Box::pin(crate::keystore::secp256k1_get_private_key( + hal, + &tx_input.keypath, + )) + .await?; // Engage in the Anti-Klepto protocol if the host sends a host nonce commitment. let host_nonce: [u8; 32] = match tx_input.host_nonce_commitment { Some(pb::AntiKleptoHostNonceCommitment { ref commitment }) => { @@ -1293,7 +1332,7 @@ async fn _process( commitment: signer_commitment.to_vec(), }); - get_antiklepto_host_nonce(input_index, &mut next_response) + Box::pin(get_antiklepto_host_nonce(input_index, &mut next_response)) .await? .host_nonce .as_slice() diff --git a/src/rust/bitbox02-rust/src/keystore.rs b/src/rust/bitbox02-rust/src/keystore.rs index 6833d14135..cc33acfc51 100644 --- a/src/rust/bitbox02-rust/src/keystore.rs +++ b/src/rust/bitbox02-rust/src/keystore.rs @@ -182,12 +182,12 @@ impl RetainedEncryptedBuffer { purpose: &'static str, ) -> Result { let rand: [u8; 32] = random_32_bytes(hal).await?.as_slice().try_into().unwrap(); - let encryption_key = stretch_retained_seed_encryption_key( + let encryption_key = Box::pin(stretch_retained_seed_encryption_key( hal, &rand, &format!("{}_in", purpose), &format!("{}_out", purpose), - ) + )) .await?; let iv_rand = random_32_bytes(hal).await?; let iv: &[u8; 16] = iv_rand.first_chunk::<16>().unwrap(); @@ -203,12 +203,12 @@ impl RetainedEncryptedBuffer { &self, hal: &mut impl KeystoreHal, ) -> Result>, Error> { - let encryption_key = stretch_retained_seed_encryption_key( + let encryption_key = Box::pin(stretch_retained_seed_encryption_key( hal, &self.unstretched_encryption_key, &format!("{}_in", self.purpose), &format!("{}_out", self.purpose), - ) + )) .await?; bitbox_aes::decrypt_with_hmac(&encryption_key, self.encrypted_seed.as_slice()) .map_err(|_| Error::Decrypt) From fc3a3c47702c1c0949f048fd4a111d114d0caa13 Mon Sep 17 00:00:00 2001 From: Marko Bencun Date: Wed, 22 Apr 2026 17:30:04 +0000 Subject: [PATCH 2/2] Box top-level HWW API futures The top-level HWW API dispatch function builds one large async state machine that has to cover every request variant. That keeps all of the branch-specific future layouts live in a single monomorphized type and costs a noticeable amount of ROM. Change the top-level dispatch helpers to return boxed futures and box each branch individually. This moves the size cost from code generation into a small runtime allocation at dispatch time, while leaving the API surface and request handling behavior unchanged. Saves 1832 bytes in firmware.bin. --- src/rust/bitbox02-rust/src/hww/api.rs | 119 +++++++++++++++----------- 1 file changed, 68 insertions(+), 51 deletions(-) diff --git a/src/rust/bitbox02-rust/src/hww/api.rs b/src/rust/bitbox02-rust/src/hww/api.rs index 619824b745..faae7493e9 100644 --- a/src/rust/bitbox02-rust/src/hww/api.rs +++ b/src/rust/bitbox02-rust/src/hww/api.rs @@ -1,7 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 use crate::pb; -use alloc::boxed::Box; pub(super) mod error; @@ -32,7 +31,8 @@ mod set_password; mod show_mnemonic; mod system; -use alloc::vec::Vec; +use alloc::{boxed::Box, vec::Vec}; +use core::{future::Future, pin::Pin}; use error::{Error, make_error}; use pb::request::Request; @@ -41,6 +41,8 @@ use prost::Message; use crate::hal::{Memory, Sd}; +type ResponseFuture<'a> = Pin> + 'a>>; + /// Encodes a protobuf Response message. pub fn encode(response: Response) -> Vec { let response = pb::Response { @@ -60,28 +62,30 @@ pub fn decode(input: &[u8]) -> Result { } #[cfg(any(feature = "app-bitcoin", feature = "app-litecoin"))] -async fn process_api_btc( - hal: &mut impl crate::hal::Hal, - request: &Request, -) -> Result { +fn process_api_btc<'a, H>(hal: &'a mut H, request: &'a Request) -> ResponseFuture<'a> +where + H: crate::hal::Hal + 'a, +{ match request { - Request::BtcPub(request) => Box::pin(bitcoin::process_pub(hal, request)).await, - Request::BtcSignInit(request) => Box::pin(bitcoin::signtx::process(hal, request)).await, + Request::BtcPub(request) => Box::pin(bitcoin::process_pub(hal, request)), + Request::BtcSignInit(request) => Box::pin(bitcoin::signtx::process(hal, request)), Request::Btc(pb::BtcRequest { request: Some(request), - }) => Box::pin(bitcoin::process_api(hal, request)) - .await - .map(|r| Response::Btc(pb::BtcResponse { response: Some(r) })), - _ => Err(Error::Generic), + }) => Box::pin(async move { + bitcoin::process_api(hal, request) + .await + .map(|r| Response::Btc(pb::BtcResponse { response: Some(r) })) + }), + _ => Box::pin(async { Err(Error::Generic) }), } } #[cfg(not(any(feature = "app-bitcoin", feature = "app-litecoin")))] -async fn process_api_btc( - _hal: &mut impl crate::hal::Hal, - _request: &Request, -) -> Result { - Err(Error::Disabled) +fn process_api_btc<'a, H>(_hal: &'a mut H, _request: &'a Request) -> ResponseFuture<'a> +where + H: crate::hal::Hal + 'a, +{ + Box::pin(async { Err(Error::Disabled) }) } /// Checks if the device is ready to accept/handle an api endpoint. @@ -154,58 +158,71 @@ fn can_call(hal: &mut impl crate::hal::Hal, request: &Request) -> bool { } /// Handle a protobuf api call. -async fn process_api(hal: &mut impl crate::hal::Hal, request: &Request) -> Result { +fn process_api<'a, H>(hal: &'a mut H, request: &'a Request) -> ResponseFuture<'a> +where + H: crate::hal::Hal + 'a, +{ match request { - Request::Reboot(request) => system::reboot_to_bootloader(hal, request).await, - Request::DeviceInfo(_) => device_info::process(hal).await, - Request::DeviceName(request) => set_device_name::process(hal, request).await, - Request::SetPassword(request) => set_password::process(hal, request).await, - Request::ChangePassword(_) => change_password::process(hal).await, - Request::Reset(_) => reset::process(hal).await, + Request::Reboot(request) => Box::pin(system::reboot_to_bootloader(hal, request)), + Request::DeviceInfo(_) => Box::pin(device_info::process(hal)), + Request::DeviceName(request) => Box::pin(set_device_name::process(hal, request)), + Request::SetPassword(request) => Box::pin(set_password::process(hal, request)), + Request::ChangePassword(_) => Box::pin(change_password::process(hal)), + Request::Reset(_) => Box::pin(reset::process(hal)), Request::SetMnemonicPassphraseEnabled(request) => { - set_mnemonic_passphrase_enabled::process(hal, request).await + Box::pin(set_mnemonic_passphrase_enabled::process(hal, request)) } - Request::InsertRemoveSdcard(request) => sdcard::process(hal, request).await, - Request::ListBackups(_) => backup::list(hal).await, - Request::CheckSdcard(_) => Ok(Response::CheckSdcard(pb::CheckSdCardResponse { - inserted: hal.sd().sdcard_inserted().await, - })), - Request::CheckBackup(request) => backup::check(hal, request).await, - Request::CreateBackup(request) => backup::create(hal, request).await, - Request::RestoreBackup(request) => restore::from_file(hal, request).await, - Request::ShowMnemonic(_) => show_mnemonic::process(hal).await, - Request::RestoreFromMnemonic(request) => restore::from_mnemonic(hal, request).await, - Request::ElectrumEncryptionKey(request) => electrum::process(hal, request).await, + Request::InsertRemoveSdcard(request) => Box::pin(sdcard::process(hal, request)), + Request::ListBackups(_) => Box::pin(backup::list(hal)), + Request::CheckSdcard(_) => Box::pin(async move { + Ok(Response::CheckSdcard(pb::CheckSdCardResponse { + inserted: hal.sd().sdcard_inserted().await, + })) + }), + Request::CheckBackup(request) => Box::pin(backup::check(hal, request)), + Request::CreateBackup(request) => Box::pin(backup::create(hal, request)), + Request::RestoreBackup(request) => Box::pin(restore::from_file(hal, request)), + Request::ShowMnemonic(_) => Box::pin(show_mnemonic::process(hal)), + Request::RestoreFromMnemonic(request) => Box::pin(restore::from_mnemonic(hal, request)), + Request::ElectrumEncryptionKey(request) => Box::pin(electrum::process(hal, request)), #[cfg(feature = "app-ethereum")] Request::Eth(pb::EthRequest { request: Some(request), - }) => ethereum::process_api(hal, request) - .await - .map(|r| Response::Eth(pb::EthResponse { response: Some(r) })), + }) => Box::pin(async move { + ethereum::process_api(hal, request) + .await + .map(|r| Response::Eth(pb::EthResponse { response: Some(r) })) + }), #[cfg(not(feature = "app-ethereum"))] - Request::Eth(_) => Err(Error::Disabled), + Request::Eth(_) => Box::pin(async { Err(Error::Disabled) }), - Request::Fingerprint(pb::RootFingerprintRequest {}) => rootfingerprint::process(), + Request::Fingerprint(pb::RootFingerprintRequest {}) => { + Box::pin(async { rootfingerprint::process() }) + } request @ Request::BtcPub(_) | request @ Request::Btc(_) - | request @ Request::BtcSignInit(_) => Box::pin(process_api_btc(hal, request)).await, + | request @ Request::BtcSignInit(_) => process_api_btc(hal, request), #[cfg(feature = "app-cardano")] Request::Cardano(pb::CardanoRequest { request: Some(request), - }) => cardano::process_api(hal, request) - .await - .map(|r| Response::Cardano(pb::CardanoResponse { response: Some(r) })), + }) => Box::pin(async move { + cardano::process_api(hal, request) + .await + .map(|r| Response::Cardano(pb::CardanoResponse { response: Some(r) })) + }), #[cfg(not(feature = "app-cardano"))] - Request::Cardano(_) => Err(Error::Disabled), - Request::Bip85(request) => bip85::process(hal, request).await, + Request::Cardano(_) => Box::pin(async { Err(Error::Disabled) }), + Request::Bip85(request) => Box::pin(bip85::process(hal, request)), Request::Bluetooth(pb::BluetoothRequest { request: Some(request), - }) => bluetooth::process_api(hal, request) - .await - .map(|r| Response::Bluetooth(pb::BluetoothResponse { response: Some(r) })), - _ => Err(Error::InvalidInput), + }) => Box::pin(async move { + bluetooth::process_api(hal, request) + .await + .map(|r| Response::Bluetooth(pb::BluetoothResponse { response: Some(r) })) + }), + _ => Box::pin(async { Err(Error::InvalidInput) }), } }