diff --git a/.ci/check-style b/.ci/check-style index 1e4f025f4..117a122ae 100755 --- a/.ci/check-style +++ b/.ci/check-style @@ -9,6 +9,7 @@ set -e set -o pipefail CLANGFORMAT=${CLANGFORMAT:-clang-format-18} +RUSTFMT=${RUSTFMT:-rustfmt} command -v git >/dev/null 2>&1 || { echo >&2 "git is missing"; exit 1; } command -v xargs >/dev/null 2>&1 || { echo >&2 "xargs is missing"; exit 1; } @@ -37,3 +38,9 @@ if git --no-pager diff --diff-filter=d --name-only ${TARGET_BRANCH} HEAD | grep git --no-pager diff exit 1 fi + +RUST_SOURCES=$(git --no-pager diff --diff-filter=d --name-only ${TARGET_BRANCH} HEAD | grep -E "^src/rust.*\.rs\$" | grep -v -E "^src/rust/vendor" || true) +if [ -n "$RUST_SOURCES" ] ; then + echo $RUST_SOURCES + "$RUSTFMT" --check $RUST_SOURCES +fi diff --git a/.ci/ci b/.ci/ci index 301122ae7..abfd7d2e2 100755 --- a/.ci/ci +++ b/.ci/ci @@ -6,7 +6,7 @@ set -e # Deny warnings in rust. CI will fail to compile any code with warnings in it. export RUSTFLAGS="-Dwarnings" -# Check style for C +# Check style for C and Rust ./.ci/check-style # Check that we can generate protobuf definitions for python diff --git a/src/rust/bitbox02-rust/src/hww/api/ethereum/address.rs b/src/rust/bitbox02-rust/src/hww/api/ethereum/address.rs index 36bec4a3b..4b9fe2a11 100644 --- a/src/rust/bitbox02-rust/src/hww/api/ethereum/address.rs +++ b/src/rust/bitbox02-rust/src/hww/api/ethereum/address.rs @@ -44,10 +44,10 @@ pub fn from_pubkey_hash(recipient: &[u8; 20], address_case: pb::EthAddressCase) // valid utf8 because hex and the uppercasing above is correct. core::str::from_utf8_unchecked(&hex[..]) }) - }, + } pb::EthAddressCase::Upper => { format!("0x{}", hex::encode_upper(recipient)) - }, + } pb::EthAddressCase::Lower => { format!("0x{}", hex::encode(recipient)) } @@ -58,7 +58,10 @@ pub fn from_pubkey_hash(recipient: &[u8; 20], address_case: pb::EthAddressCase) /// `recipient` - 20 byte tail (last 20 bytes of the pubkeyhash). pub fn from_pubkey(pubkey_uncompressed: &[u8; 65]) -> String { let hash = sha3::Keccak256::digest(&pubkey_uncompressed[1..]); - from_pubkey_hash(hash[hash.len() - 20..].try_into().unwrap(), pb::EthAddressCase::Mixed) + from_pubkey_hash( + hash[hash.len() - 20..].try_into().unwrap(), + pb::EthAddressCase::Mixed, + ) } #[cfg(test)] diff --git a/src/rust/bitbox02-rust/src/hww/api/ethereum/sign.rs b/src/rust/bitbox02-rust/src/hww/api/ethereum/sign.rs index 825cbaad0..2c2486d00 100644 --- a/src/rust/bitbox02-rust/src/hww/api/ethereum/sign.rs +++ b/src/rust/bitbox02-rust/src/hww/api/ethereum/sign.rs @@ -93,7 +93,9 @@ impl<'a> Transaction<'a> { fn case(&self) -> Result { match self { Transaction::Legacy(legacy) => Ok(pb::EthAddressCase::try_from(legacy.address_case)?), - Transaction::Eip1559(eip1559) => Ok(pb::EthAddressCase::try_from(eip1559.address_case)?), + Transaction::Eip1559(eip1559) => { + Ok(pb::EthAddressCase::try_from(eip1559.address_case)?) + } } } } @@ -268,7 +270,7 @@ async fn verify_standard_transaction( }) .await?; } - + let address = super::address::from_pubkey_hash(&recipient, request.case()?); let amount = Amount { unit: params.unit, diff --git a/src/rust/bitbox02-rust/src/hww/api/sdcard.rs b/src/rust/bitbox02-rust/src/hww/api/sdcard.rs index c18686af1..a93d7ae46 100644 --- a/src/rust/bitbox02-rust/src/hww/api/sdcard.rs +++ b/src/rust/bitbox02-rust/src/hww/api/sdcard.rs @@ -25,11 +25,10 @@ pub async fn process( ) -> Result { let inserted = bitbox02::sd::sdcard_inserted(); match SdCardAction::try_from(action) { - Ok(SdCardAction::InsertCard) => {}, + Ok(SdCardAction::InsertCard) => {} _ => return Ok(Response::Success(pb::Success {})), }; - if inserted - { + if inserted { return Ok(Response::Success(pb::Success {})); } sdcard::sdcard().await?; diff --git a/src/rust/bitbox02-rust/src/workflow/mnemonic.rs b/src/rust/bitbox02-rust/src/workflow/mnemonic.rs index 0b003f1c8..075b28384 100644 --- a/src/rust/bitbox02-rust/src/workflow/mnemonic.rs +++ b/src/rust/bitbox02-rust/src/workflow/mnemonic.rs @@ -502,4 +502,4 @@ mod tests { &bruteforce_lastword(&mnemonic) ); } -} \ No newline at end of file +} diff --git a/src/rust/bitbox02-rust/src/workflow/mnemonic_c_unit_tests.rs b/src/rust/bitbox02-rust/src/workflow/mnemonic_c_unit_tests.rs index 783dee5f2..c435daeb8 100644 --- a/src/rust/bitbox02-rust/src/workflow/mnemonic_c_unit_tests.rs +++ b/src/rust/bitbox02-rust/src/workflow/mnemonic_c_unit_tests.rs @@ -30,9 +30,6 @@ pub async fn get() -> Result, CancelError> { let words = "boring mistake dish oyster truth pigeon viable emerge sort crash wire portion cannon couple enact box walk height pull today solid off enable tide"; bitbox02::println_stdout("Restored from recovery words below:"); bitbox02::println_stdout(words); - - Ok(zeroize::Zeroizing::new( - words - .to_string() - )) -} \ No newline at end of file + + Ok(zeroize::Zeroizing::new(words.to_string())) +} diff --git a/src/rust/bitbox02-sys/build.rs b/src/rust/bitbox02-sys/build.rs index cc3b4e445..f5382e98b 100644 --- a/src/rust/bitbox02-sys/build.rs +++ b/src/rust/bitbox02-sys/build.rs @@ -12,10 +12,148 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::process::Command; use std::env; -use std::path::PathBuf; use std::io::ErrorKind; +use std::path::PathBuf; +use std::process::Command; + +const ALLOWLIST_VARS: &[&str] = &[ + "BASE58_CHECKSUM_LEN", + "BIP32_SERIALIZED_LEN", + "BIP39_WORDLIST_LEN", + "EC_PUBLIC_KEY_LEN", + "EC_PUBLIC_KEY_UNCOMPRESSED_LEN", + "INPUT_STRING_MAX_SIZE", + "KEYSTORE_MAX_SEED_LENGTH", + "MAX_LABEL_SIZE", + "MAX_PK_SCRIPT_SIZE", + "MAX_VARINT_SIZE", + "MEMORY_DEVICE_NAME_MAX_LEN", + "MEMORY_MULTISIG_NAME_MAX_LEN", + "SD_MAX_FILE_SIZE", + "XPUB_ENCODED_LEN", + "font_font_a_11X10", + "font_font_a_9X9", + "font_monogram_5X9", + "font_password_11X12", +]; + +const ALLOWLIST_TYPES: &[&str] = &[ + "buffer_t", + "component_t", + "confirm_params_t", + "trinary_input_string_params_t", +]; + +const ALLOWLIST_FNS: &[&str] = &[ + "UG_ClearBuffer", + "UG_FontSelect", + "UG_PutString", + "UG_SendBuffer", + "bip32_derive_xpub", + "bitbox02_smarteeprom_init", + "bitbox_secp256k1_dleq_prove", + "bitbox_secp256k1_dleq_verify", + "confirm_create", + "confirm_transaction_address_create", + "confirm_transaction_fee_create", + "delay_ms", + "delay_us", + "empty_create", + "keystore_bip39_mnemonic_to_seed", + "keystore_bip85_bip39", + "keystore_bip85_ln", + "keystore_copy_seed", + "keystore_create_and_store_seed", + "keystore_encode_xpub_at_keypath", + "keystore_encrypt_and_store_seed", + "keystore_get_bip39_mnemonic", + "keystore_get_bip39_word", + "keystore_get_ed25519_seed", + "keystore_is_locked", + "keystore_lock", + "keystore_mock_unlocked", + "keystore_secp256k1_compressed_to_uncompressed", + "keystore_secp256k1_get_private_key", + "keystore_secp256k1_nonce_commit", + "keystore_secp256k1_schnorr_bip86_pubkey", + "keystore_secp256k1_schnorr_bip86_sign", + "keystore_secp256k1_sign", + "keystore_unlock", + "keystore_unlock_bip39", + "label_create", + "localtime", + "lock_animation_start", + "lock_animation_stop", + "memory_add_noise_remote_static_pubkey", + "memory_bootloader_hash", + "memory_check_noise_remote_static_pubkey", + "memory_get_attestation_bootloader_hash", + "memory_get_attestation_pubkey_and_certificate", + "memory_get_device_name", + "memory_get_noise_static_private_key", + "memory_get_seed_birthdate", + "memory_is_initialized", + "memory_is_mnemonic_passphrase_enabled", + "memory_is_seeded", + "memory_multisig_get_by_hash", + "memory_multisig_set_by_hash", + "memory_set_device_name", + "memory_set_initialized", + "memory_set_mnemonic_passphrase_enabled", + "memory_set_seed_birthdate", + "memory_setup", + "menu_create", + "mock_memory_factoryreset", + "printf", + "progress_create", + "progress_set", + "random_32_bytes_mcu", + "random_mock_reset", + "reboot", + "reset_reset", + "screen_print_debug", + "screen_process", + "screen_saver_disable", + "screen_saver_enable", + "sd_card_inserted", + "sd_erase_file_in_subdir", + "sd_format", + "sd_free_list", + "sd_list_subdir", + "sd_load_bin", + "sd_write_bin", + "sdcard_create", + "secp256k1_ecdsa_anti_exfil_host_commit", + "securechip_attestation_sign", + "securechip_model", + "securechip_monotonic_increments_remaining", + "securechip_u2f_counter_set", + "smarteeprom_bb02_config", + "status_create", + "trinary_choice_create", + "trinary_input_string_create", + "trinary_input_string_set_input", + "ui_screen_stack_pop", + "ui_screen_stack_pop_all", + "ui_screen_stack_push", + "util_format_datetime", + "wally_free_string", + "wally_get_secp_context", + "wally_hash160", + "wally_sha512", +]; + +const RUSTIFIED_ENUMS: &[&str] = &[ + "keystore_error_t", + "keystore_secp256k1_pubkey_format", + "memory_result_t", + "multisig_script_type_t", + "output_type_t", + "securechip_model_t", + "simple_type_t", + "trinary_choice_t", +]; pub fn main() -> Result<(), &'static str> { // We could theoretically list every header file that we end up depending on, but that is hard @@ -25,7 +163,7 @@ pub fn main() -> Result<(), &'static str> { // Check if we have `bindgen` executable if let Err(e) = Command::new("bindgen").spawn() { if e.kind() == ErrorKind::NotFound { - return Err("`bindgen` was not found! Check your PATH!") + return Err("`bindgen` was not found! Check your PATH!"); } } @@ -38,8 +176,15 @@ pub fn main() -> Result<(), &'static str> { let extra_flags = if cross_compiling { // APP_ vars active when generating rust declarations from C headers. It is okay to // activate all of them here - Rust's 'app-' features control usage/compilation. - vec!["-D__SAMD51J20A__", "--target=thumbv7em-none-eabi", "-mcpu=cortex-m4", "-mthumb", - "-mfloat-abi=soft", &arm_sysroot, "-DAPP_U2F=1"] + vec![ + "-D__SAMD51J20A__", + "--target=thumbv7em-none-eabi", + "-mcpu=cortex-m4", + "-mthumb", + "-mfloat-abi=soft", + &arm_sysroot, + "-DAPP_U2F=1", + ] } else { vec!["-DTESTING=1"] }; @@ -101,132 +246,14 @@ pub fn main() -> Result<(), &'static str> { .arg("--use-core") .arg("--with-derive-default") .args(["--ctypes-prefix", "util::c_types"]) - .args(["--allowlist-function", "bip32_derive_xpub"]) - .args(["--allowlist-function", "localtime"]) - .args(["--allowlist-function", "wally_free_string"]) - .args(["--allowlist-function", "mock_memory_factoryreset"]) - .args(["--allowlist-function", "memory_setup"]) - .args(["--allowlist-function", "memory_is_initialized"]) - .args(["--allowlist-function", "memory_set_initialized"]) - .args(["--allowlist-function", "memory_is_seeded"]) - .args(["--allowlist-function", "memory_is_mnemonic_passphrase_enabled"]) - .args(["--allowlist-function", "memory_get_attestation_pubkey_and_certificate"]) - .args(["--allowlist-function", "memory_get_attestation_bootloader_hash"]) - .args(["--allowlist-function", "memory_bootloader_hash"]) - .args(["--allowlist-function", "memory_get_noise_static_private_key"]) - .args(["--allowlist-function", "memory_check_noise_remote_static_pubkey"]) - .args(["--allowlist-function", "memory_add_noise_remote_static_pubkey"]) - .args(["--allowlist-function", "memory_get_device_name"]) - .args(["--allowlist-function", "memory_set_device_name"]) - .args(["--allowlist-function", "memory_set_mnemonic_passphrase_enabled"]) - .args(["--allowlist-var", "MEMORY_MULTISIG_NAME_MAX_LEN"]) - .args(["--allowlist-function", "memory_set_seed_birthdate"]) - .args(["--allowlist-function", "memory_get_seed_birthdate"]) - .args(["--allowlist-function", "memory_multisig_get_by_hash"]) - .args(["--allowlist-function", "memory_multisig_set_by_hash"]) - .args(["--allowlist-function", "smarteeprom_bb02_config"]) - .args(["--allowlist-function", "bitbox02_smarteeprom_init"]) - .args(["--rustified-enum", "memory_result_t"]) - .args(["--allowlist-var", "MEMORY_DEVICE_NAME_MAX_LEN"]) - .args(["--allowlist-function", "securechip_attestation_sign"]) - .args(["--allowlist-function", "securechip_monotonic_increments_remaining"]) - .args(["--allowlist-function", "securechip_u2f_counter_set"]) - .args(["--allowlist-function", "securechip_model"]) - .args(["--rustified-enum", "securechip_model_t"]) - .args(["--allowlist-var", "KEYSTORE_MAX_SEED_LENGTH"]) - .args(["--allowlist-function", "keystore_is_locked"]) - .args(["--allowlist-function", "keystore_unlock"]) - .args(["--allowlist-function", "keystore_unlock_bip39"]) - .args(["--allowlist-function", "keystore_lock"]) - .args(["--allowlist-function", "keystore_create_and_store_seed"]) - .args(["--allowlist-function", "keystore_copy_seed"]) - .args(["--allowlist-function", "keystore_secp256k1_get_private_key"]) - .args(["--allowlist-function", "keystore_get_bip39_mnemonic"]) - .args(["--allowlist-function", "keystore_get_bip39_word"]) - .args(["--allowlist-function", "keystore_get_ed25519_seed"]) - .args(["--allowlist-function", "keystore_bip85_bip39"]) - .args(["--allowlist-function", "keystore_bip85_ln"]) - .args(["--allowlist-function", "keystore_secp256k1_compressed_to_uncompressed"]) - .args(["--allowlist-function", "keystore_secp256k1_nonce_commit"]) - .args(["--allowlist-function", "keystore_secp256k1_sign"]) - .args(["--allowlist-function", "keystore_secp256k1_schnorr_bip86_sign"]) - .args(["--allowlist-function", "keystore_bip39_mnemonic_to_seed"]) - .args(["--allowlist-function", "keystore_mock_unlocked"]) - .args(["--allowlist-var", "EC_PUBLIC_KEY_UNCOMPRESSED_LEN"]) - .args(["--allowlist-var", "EC_PUBLIC_KEY_LEN"]) - .args(["--allowlist-function", "keystore_encode_xpub_at_keypath"]) - .args(["--allowlist-function", "keystore_encrypt_and_store_seed"]) - .args(["--allowlist-var", "XPUB_ENCODED_LEN"]) - .args(["--allowlist-var", "BIP32_SERIALIZED_LEN"]) - .args(["--allowlist-function", "lock_animation_start"]) - .args(["--allowlist-function", "lock_animation_stop"]) - .args(["--allowlist-function", "delay_us"]) - .args(["--rustified-enum", "keystore_error_t"]) - .args(["--rustified-enum", "keystore_secp256k1_pubkey_format"]) - .args(["--allowlist-function", "keystore_secp256k1_schnorr_bip86_pubkey"]) - .args(["--allowlist-function", "util_format_datetime"]) - .args(["--allowlist-type", "buffer_t"]) - .args(["--allowlist-function", "delay_ms"]) - .args(["--allowlist-function", "UG_PutString"]) - .args(["--allowlist-function", "UG_FontSelect"]) - .args(["--allowlist-function", "UG_ClearBuffer"]) - .args(["--allowlist-function", "UG_SendBuffer"]) - .args(["--allowlist-function", "screen_print_debug"]) - .args(["--allowlist-function", "ui_screen_stack_push"]) - .args(["--allowlist-function", "ui_screen_stack_pop"]) - .args(["--allowlist-function", "ui_screen_stack_pop_all"]) - .args(["--allowlist-function", "screen_saver_disable"]) - .args(["--allowlist-function", "screen_saver_enable"]) - .args(["--allowlist-function", "screen_process"]) - .args(["--allowlist-function", "label_create"]) - .args(["--allowlist-function", "confirm_create"]) - .args(["--allowlist-function", "status_create"]) - .args(["--allowlist-function", "sdcard_create"]) - .args(["--allowlist-function", "menu_create"]) - .args(["--allowlist-function", "trinary_choice_create"]) - .args(["--rustified-enum", "trinary_choice_t"]) - .args(["--allowlist-var", "BASE58_CHECKSUM_LEN"]) - .args(["--allowlist-function", "random_32_bytes_mcu"]) - .args(["--allowlist-function", "random_mock_reset"]) - .args(["--allowlist-type", "component_t"]) - .args(["--allowlist-type", "confirm_params_t"]) - .args(["--allowlist-var", "MAX_LABEL_SIZE"]) - .args(["--allowlist-var", "font_font_a_9X9"]) - .args(["--allowlist-var", "font_font_a_11X10"]) - .args(["--allowlist-var", "font_monogram_5X9"]) - .args(["--allowlist-var", "font_password_11X12"]) - .args(["--allowlist-type", "trinary_input_string_params_t"]) - .args(["--allowlist-var", "INPUT_STRING_MAX_SIZE"]) - .args(["--allowlist-function", "trinary_input_string_create"]) - .args(["--allowlist-function", "trinary_input_string_set_input"]) - .args(["--allowlist-function", "confirm_transaction_address_create"]) - .args(["--allowlist-function", "confirm_transaction_fee_create"]) - .args(["--allowlist-function", "progress_create"]) - .args(["--allowlist-function", "progress_set"]) - .args(["--allowlist-function", "empty_create"]) - .args(["--allowlist-function", "reset_reset"]) - .args(["--allowlist-function", "sd_card_inserted"]) - .args(["--allowlist-function", "sd_format"]) - .args(["--allowlist-function", "sd_list_subdir"]) - .args(["--allowlist-function", "sd_erase_file_in_subdir"]) - .args(["--allowlist-function", "sd_load_bin"]) - .args(["--allowlist-function", "sd_write_bin"]) - .args(["--allowlist-var", "SD_MAX_FILE_SIZE"]) - .args(["--allowlist-function", "sd_free_list"]) - .args(["--allowlist-var", "BIP39_WORDLIST_LEN"]) - .args(["--rustified-enum", "simple_type_t"]) - .args(["--rustified-enum", "multisig_script_type_t"]) - .args(["--rustified-enum", "output_type_t"]) - .args(["--allowlist-var", "MAX_VARINT_SIZE"]) - .args(["--allowlist-var", "MAX_PK_SCRIPT_SIZE"]) - .args(["--allowlist-function", "reboot"]) - .args(["--allowlist-function", "secp256k1_ecdsa_anti_exfil_host_commit"]) - .args(["--allowlist-function", "wally_get_secp_context"]) - .args(["--allowlist-function", "wally_hash160"]) - .args(["--allowlist-function", "wally_sha512"]) - .args(["--allowlist-function", "printf"]) - .args(["--allowlist-function", "bitbox_secp256k1_dleq_prove"]) - .args(["--allowlist-function", "bitbox_secp256k1_dleq_verify"]) + .args( + ALLOWLIST_FNS + .iter() + .flat_map(|s| ["--allowlist-function", s]), + ) + .args(ALLOWLIST_TYPES.iter().flat_map(|s| ["--allowlist-type", s])) + .args(ALLOWLIST_VARS.iter().flat_map(|s| ["--allowlist-var", s])) + .args(RUSTIFIED_ENUMS.iter().flat_map(|s| ["--rustified-enum", s])) .arg("wrapper.h") .arg("--") .arg("-DPB_NO_PACKED_STRUCTS=1") @@ -236,8 +263,12 @@ pub fn main() -> Result<(), &'static str> { .args(includes.iter().map(|s| format!("-I{s}"))) .output() .expect("Failed to run bindgen"); - if ! res.status.success() { - println!("bindgen-out:\n{}\n\nbindgen-err:\n{}", std::str::from_utf8(&res.stdout).unwrap(), std::str::from_utf8(&res.stderr).unwrap()); + if !res.status.success() { + println!( + "bindgen-out:\n{}\n\nbindgen-err:\n{}", + std::str::from_utf8(&res.stdout).unwrap(), + std::str::from_utf8(&res.stderr).unwrap() + ); return Err("Bindgen failed"); } Ok(()) diff --git a/src/rust/bitbox02/build.rs b/src/rust/bitbox02/build.rs index 34d244717..84c35e5b5 100644 --- a/src/rust/bitbox02/build.rs +++ b/src/rust/bitbox02/build.rs @@ -23,7 +23,9 @@ fn main() { } else { // This is useful in case project is built by tool that doesn't need to link the final // target, like rust-analyzer and clippy. - println!("cargo::warning=Missing env variable CMAKE_CURRENT_BINARY_DIR, linking will fail"); + println!( + "cargo::warning=Missing env variable CMAKE_CURRENT_BINARY_DIR, linking will fail" + ); } } }