From d122d05df1261312198e35f144ae38b9423b5e23 Mon Sep 17 00:00:00 2001 From: GroM Date: Fri, 27 Mar 2026 17:41:30 +0100 Subject: [PATCH 01/13] Embed icon in install_params --- ledger_device_sdk/build.rs | 90 ++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 9 deletions(-) diff --git a/ledger_device_sdk/build.rs b/ledger_device_sdk/build.rs index 865058b7..1f2becea 100644 --- a/ledger_device_sdk/build.rs +++ b/ledger_device_sdk/build.rs @@ -1,3 +1,7 @@ +use std::env; +use std::path::PathBuf; +use std::process::Command; + fn generate_install_parameters() { // Find the root package directory by looking at OUT_DIR // OUT_DIR is something like: /path/to/app/target/nanosplus/debug/build/ledger_device_sdk-xxx/out @@ -89,16 +93,25 @@ fn generate_install_parameters() { println!("cargo:warning=paths_slip21 are {:x?}", paths_slip21); } - let install_params_exe = match std::env::var("LEDGER_SDK_PATH") { - Ok(path) => format!("{}/install_params.py", path), - Err(_) => { - let device_os = std::env::var_os("CARGO_CFG_TARGET_OS").unwrap(); - let device_os = device_os.to_str().unwrap().split('_').next().unwrap(); - format!("/opt/{}-secure-sdk/install_params.py", device_os) - } - }; + // Handle icon + let device = env::var_os("CARGO_CFG_TARGET_OS").unwrap(); + let device_name = device.to_str().unwrap(); + println!("cargo:warning=Device is {}", device_name); + + let icon = metadata_ledger[device_name]["icon"] + .as_str() + .expect("icon not found"); + println!("cargo:warning=APP_ICON is {}", icon); + + let c_sdk_path = resolve_c_sdk_path(device_name); + println!("cargo:warning=C SDK path is {}", c_sdk_path.display()); + + let icon_hex_string = convert_icon_to_hex(&c_sdk_path, device_name, root_dir, icon); + + // Now we have all the parameters, we can call the install_params.py script to generate the TLV blob + let install_params_exe = c_sdk_path.join("install_params.py"); let mut generate_tlv_install_params = std::process::Command::new("python3"); - generate_tlv_install_params.arg(install_params_exe.as_str()); + generate_tlv_install_params.arg(&install_params_exe); generate_tlv_install_params.arg("--appName").arg(app_name); generate_tlv_install_params .arg("--appVersion") @@ -116,6 +129,10 @@ fn generate_install_parameters() { .arg("--path_slip21") .arg(p.as_str()); }); + generate_tlv_install_params + .arg("--icon") + .arg(icon_hex_string); + let output = generate_tlv_install_params .output() .expect("Failed to execute install_params_generator"); @@ -197,6 +214,61 @@ fn generate_install_parameters() { .unwrap(); } +/// Resolve the C SDK root path for the given device. +/// +/// Uses `LEDGER_SDK_PATH` if set, otherwise falls back to the +/// device-specific environment variable (e.g. `NANOSPLUS_SDK`). +fn resolve_c_sdk_path(device_name: &str) -> PathBuf { + PathBuf::from(env::var("LEDGER_SDK_PATH").unwrap_or_else(|_| { + let var = match device_name { + "nanosplus" => "NANOSPLUS_SDK", + "nanox" => "NANOX_SDK", + "stax" => "STAX_SDK", + "flex" => "FLEX_SDK", + "apex_p" => "APEX_P_SDK", + _ => panic!("Unsupported device: {}", device_name), + }; + env::var(var).unwrap_or_else(|_| panic!("{} not set", var)) + })) +} + +/// Run `icon2glyph.py` to convert the app icon into a hex string +/// suitable for the install-parameters TLV blob. +fn convert_icon_to_hex( + c_sdk_path: &std::path::Path, + device_name: &str, + root_dir: &std::path::Path, + icon: &str, +) -> String { + let icon_hex_file = PathBuf::from(env::var("OUT_DIR").unwrap()).join("icon.hex"); + println!( + "cargo:warning=Output file for icon2glyph is {}", + icon_hex_file.display() + ); + + let icon2glyph = c_sdk_path.join("lib_nbgl/tools/icon2glyph.py"); + let mut cmd = Command::new(icon2glyph.as_os_str()); + cmd.arg("--hexbitmap").arg(&icon_hex_file); + if device_name == "nanosplus" || device_name == "nanox" { + cmd.arg("--reverse"); + } + cmd.arg(root_dir.join(icon)); + + let output = cmd.output().expect("Failed to execute icon2glyph.py"); + if !output.status.success() { + panic!( + "call to icon2glyph.py failed: {}", + std::str::from_utf8(&output.stderr).unwrap() + ); + } + + let icon_bytes = std::fs::read(&icon_hex_file).expect("Failed to read icon hex file"); + icon_bytes + .iter() + .map(|b| format!("{:02x}", b)) + .collect::() +} + fn main() { println!("cargo:rerun-if-changed=Cargo.toml"); generate_install_parameters(); From 4e86c5e76ea91e253a5b11b3f12940d264592d8c Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 1 Apr 2026 15:45:35 +0200 Subject: [PATCH 02/13] Fix typos --- ledger_device_sdk/src/io_legacy.rs | 2 +- ledger_device_sdk/src/nvm.rs | 10 +++++----- ledger_secure_sdk_sys/link.ld | 4 ++-- ledger_secure_sdk_sys/src/c/src.c | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ledger_device_sdk/src/io_legacy.rs b/ledger_device_sdk/src/io_legacy.rs index efe3aabe..6811516e 100644 --- a/ledger_device_sdk/src/io_legacy.rs +++ b/ledger_device_sdk/src/io_legacy.rs @@ -266,7 +266,7 @@ impl Comm { } /// Send the currently held APDU - // This is private. Users should call reply to set the satus word and + // This is private. Users should call reply to set the status word and // transmit the response. fn apdu_send(&mut self) { #[cfg(any( diff --git a/ledger_device_sdk/src/nvm.rs b/ledger_device_sdk/src/nvm.rs index 20416b4c..14b12776 100644 --- a/ledger_device_sdk/src/nvm.rs +++ b/ledger_device_sdk/src/nvm.rs @@ -73,7 +73,7 @@ pub trait SingleStorage { /// unfinished write detection in SafeStorage and atomic operations in /// AtomicStorage). /// -/// Warning: this wrapper does not provide any garantee about update atomicity. +/// Warning: this wrapper does not provide any guarantee about update atomicity. #[repr(align(64))] #[derive(Copy, Clone)] pub struct AlignedStorage { @@ -99,7 +99,7 @@ impl SingleStorage for AlignedStorage { &self.value } - /// Update the value by writting to the NVM memory. + /// Update the value by writing to the NVM memory. /// Warning: this can be vulnerable to tearing - leading to partial write. fn update(&mut self, value: &T) { unsafe { @@ -114,7 +114,7 @@ impl SingleStorage for AlignedStorage { } /// Just a non-zero magic to mark a storage as valid, when the update procedure -/// has not been interupted. Any value excepted 0 and 0xff may work. +/// has not been interrupted. Any value excepted 0 and 0xff may work. const STORAGE_VALID: u8 = 0xa5; /// Non-Volatile data storage, with a flag to detect corruption if the update @@ -175,7 +175,7 @@ macro_rules! atomic_storage { pub struct AtomicStorage { // We must keep the storage B in another page, so when we update the // storage A, erasing the page of A won't modify the storage for B. - // This is currently garanteed by the alignment of AlignedStorage. + // This is currently guaranteed by the alignment of AlignedStorage. storage_a: SafeStorage, storage_b: SafeStorage, // We also accept situations where both storages are marked as valid, which // can happen with tearing. This is not a problem, and we consider the first @@ -240,7 +240,7 @@ where } } - /// Update the value by writting to the NVM memory. + /// Update the value by writing to the NVM memory. /// Warning: this can be vulnerable to tearing - leading to partial write. fn update(&mut self, value: &T) { match self.which() { diff --git a/ledger_secure_sdk_sys/link.ld b/ledger_secure_sdk_sys/link.ld index eff3cce6..e041b5ba 100644 --- a/ledger_secure_sdk_sys/link.ld +++ b/ledger_secure_sdk_sys/link.ld @@ -30,7 +30,7 @@ SECTIONS _etext = .; } > FLASH :flash0 - /* Relocations, read only, no relocations aginst the relocations themselves + /* Relocations, read only, no relocations against the relocations themselves needed! */ _reloc_size = SIZEOF(.rel.rodata) + SIZEOF(.rel.data) + SIZEOF(.rel.nvm_data); .rel_flash : ALIGN(PAGE_SIZE) @@ -52,7 +52,7 @@ SECTIONS relocations are needed. (So not read-only completely.) */ .rodata : ALIGN(PAGE_SIZE) { - /* Moved here from .text so we can permantly apply relocations to it with + /* Moved here from .text so we can permanently apply relocations to it with nvm_write() */ . = ALIGN(PAGE_SIZE); _rodata = .; diff --git a/ledger_secure_sdk_sys/src/c/src.c b/ledger_secure_sdk_sys/src/c/src.c index 3cca01cb..c75ccc41 100644 --- a/ledger_secure_sdk_sys/src/c/src.c +++ b/ledger_secure_sdk_sys/src/c/src.c @@ -111,7 +111,7 @@ void link_pass( PRINTHEXC("First reloc: ", reloc_start->r_offset); // Loop over the rodata entries - we could loop over the - // correct seciton, but this also works. + // correct section, but this also works. for (Elf32_Rel* reloc = reloc_start; reloc < reloc_end; reloc++) { // This is the (absolute) elf *load* address of the relocation. link_addr_t abs_offset = reloc->r_offset; From 69eae64c519cdcddf7fd45e921fd00550c391956 Mon Sep 17 00:00:00 2001 From: GroM Date: Tue, 28 Apr 2026 14:32:22 +0200 Subject: [PATCH 03/13] Fix icon generation + linker script --- ledger_device_sdk/build.rs | 10 ++++------ ledger_secure_sdk_sys/link.ld | 8 ++++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/ledger_device_sdk/build.rs b/ledger_device_sdk/build.rs index 1f2becea..0e247461 100644 --- a/ledger_device_sdk/build.rs +++ b/ledger_device_sdk/build.rs @@ -261,12 +261,10 @@ fn convert_icon_to_hex( std::str::from_utf8(&output.stderr).unwrap() ); } - - let icon_bytes = std::fs::read(&icon_hex_file).expect("Failed to read icon hex file"); - icon_bytes - .iter() - .map(|b| format!("{:02x}", b)) - .collect::() + std::fs::read_to_string(&icon_hex_file) + .expect("Failed to read icon hex file") + .trim() + .to_string() } fn main() { diff --git a/ledger_secure_sdk_sys/link.ld b/ledger_secure_sdk_sys/link.ld index e041b5ba..2a213252 100644 --- a/ledger_secure_sdk_sys/link.ld +++ b/ledger_secure_sdk_sys/link.ld @@ -22,10 +22,6 @@ SECTIONS *(.text*) /* .rodata is moved out so we can update it */ - _install_parameters = .; - *(.install_parameters) - KEEP(*(.install_parameters)) - _einstall_parameters = .; . = ALIGN(PAGE_SIZE); _etext = .; } > FLASH :flash0 @@ -96,6 +92,10 @@ SECTIONS /* This symbol is used by the mutable portion of flash calculations. */ _envram_data = .; + _install_parameters = .; + *(.install_parameters) + KEEP(*(.install_parameters)) + _einstall_parameters = .; /* This symbol is used by the ideompotent `pic` function as the upper bound of addressed to relocate. */ _nvram_end = .; From 1a03d6933f36f5eb87e9bb2d392ef78d023c5020 Mon Sep 17 00:00:00 2001 From: GroM Date: Tue, 28 Apr 2026 14:56:51 +0200 Subject: [PATCH 04/13] Use ledgerblue-support cargo-ledger --- .github/workflows/reusable_build_all_apps.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/reusable_build_all_apps.yml b/.github/workflows/reusable_build_all_apps.yml index f27865ec..cf496fde 100644 --- a/.github/workflows/reusable_build_all_apps.yml +++ b/.github/workflows/reusable_build_all_apps.yml @@ -118,6 +118,9 @@ jobs: echo "Cargo.toml:" cat $cargo_toml_path + - name: Install test cargo-ledger + run: cargo install --git https://github.com/LedgerHQ/cargo-ledger --branch y333/ledgerblue_support --force cargo-ledger + - name: Build shell: bash run: | From f682004591b3f919167ae5829c047809c8b6ff6d Mon Sep 17 00:00:00 2001 From: GroM Date: Tue, 28 Apr 2026 15:05:06 +0200 Subject: [PATCH 05/13] fix typo for Nano S+ C SDK --- ledger_device_sdk/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ledger_device_sdk/build.rs b/ledger_device_sdk/build.rs index 0e247461..d6cc62f8 100644 --- a/ledger_device_sdk/build.rs +++ b/ledger_device_sdk/build.rs @@ -221,7 +221,7 @@ fn generate_install_parameters() { fn resolve_c_sdk_path(device_name: &str) -> PathBuf { PathBuf::from(env::var("LEDGER_SDK_PATH").unwrap_or_else(|_| { let var = match device_name { - "nanosplus" => "NANOSPLUS_SDK", + "nanosplus" => "NANOSP_SDK", "nanox" => "NANOX_SDK", "stax" => "STAX_SDK", "flex" => "FLEX_SDK", From bd2b83fdfe51aad8005b6cd87f9f22217bed04a4 Mon Sep 17 00:00:00 2001 From: GroM Date: Tue, 28 Apr 2026 15:29:13 +0200 Subject: [PATCH 06/13] Update after Copilot review --- ledger_device_sdk/build.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/ledger_device_sdk/build.rs b/ledger_device_sdk/build.rs index d6cc62f8..0789c8c3 100644 --- a/ledger_device_sdk/build.rs +++ b/ledger_device_sdk/build.rs @@ -98,9 +98,19 @@ fn generate_install_parameters() { let device_name = device.to_str().unwrap(); println!("cargo:warning=Device is {}", device_name); - let icon = metadata_ledger[device_name]["icon"] - .as_str() - .expect("icon not found"); + let icon = metadata_ledger + .get(device_name) + .and_then(|device_metadata| device_metadata.get("icon")) + .and_then(|icon| icon.as_str()) + .unwrap_or_else(|| { + panic!( + "missing Ledger app icon metadata for device `{}`; expected \ + `package.metadata.ledger.{device}.icon` to be a string, for \ + example: [package.metadata.ledger.{device}] icon = \"path/to/icon.gif\"", + device_name, + device = device_name + ) + }); println!("cargo:warning=APP_ICON is {}", icon); let c_sdk_path = resolve_c_sdk_path(device_name); @@ -247,7 +257,8 @@ fn convert_icon_to_hex( ); let icon2glyph = c_sdk_path.join("lib_nbgl/tools/icon2glyph.py"); - let mut cmd = Command::new(icon2glyph.as_os_str()); + let mut cmd = Command::new("python3"); + cmd.arg(&icon2glyph); cmd.arg("--hexbitmap").arg(&icon_hex_file); if device_name == "nanosplus" || device_name == "nanox" { cmd.arg("--reverse"); From 9dc4de38f1cceb6e55c58c45aa5a030d0e93af9c Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 29 Apr 2026 13:34:23 +0200 Subject: [PATCH 07/13] fix all clippy warnings --- include_gif/src/lib.rs | 8 +-- ledger_device_sdk/build.rs | 6 +- ledger_device_sdk/src/ecc.rs | 1 + ledger_device_sdk/src/ecc/math.rs | 1 + ledger_device_sdk/src/io_callbacks.rs | 6 +- ledger_device_sdk/src/io_legacy.rs | 41 +++++++------ ledger_device_sdk/src/libcall/string.rs | 6 +- ledger_device_sdk/src/libcall/swap.rs | 2 +- ledger_device_sdk/src/math.rs | 20 +++---- ledger_device_sdk/src/nbgl.rs | 23 ++++--- ledger_device_sdk/src/nbgl/nbgl_action.rs | 6 ++ .../src/nbgl/nbgl_address_review.rs | 16 ++--- .../src/nbgl/nbgl_advance_review.rs | 4 +- ledger_device_sdk/src/nbgl/nbgl_choice.rs | 26 ++++---- .../src/nbgl/nbgl_generic_review.rs | 60 ++++++++++--------- .../src/nbgl/nbgl_generic_settings.rs | 24 ++++++-- .../src/nbgl/nbgl_home_and_settings.rs | 50 ++++++++-------- ledger_device_sdk/src/nbgl/nbgl_keypad.rs | 25 ++++++-- ledger_device_sdk/src/nbgl/nbgl_review.rs | 17 +++--- .../src/nbgl/nbgl_review_extended.rs | 8 ++- .../src/nbgl/nbgl_review_status.rs | 8 ++- ledger_device_sdk/src/nbgl/nbgl_status.rs | 6 ++ .../src/nbgl/nbgl_streaming_review.rs | 49 +++++---------- ledger_device_sdk/src/nvm.rs | 2 +- ledger_device_sdk/src/pki.rs | 4 +- ledger_device_sdk/src/seph.rs | 45 +++++++------- ledger_device_sdk/src/testing.rs | 2 +- .../src/tlv/tlv_dynamic_token.rs | 6 +- ledger_device_sdk/src/tlv/tlv_trusted_name.rs | 18 +++--- ledger_device_sdk/src/ui/bagls.rs | 6 ++ ledger_device_sdk/src/ui/gadgets.rs | 23 ++++--- ledger_secure_sdk_sys/build.rs | 57 +++++++++--------- ledger_secure_sdk_sys/src/lib.rs | 10 ++-- 33 files changed, 314 insertions(+), 272 deletions(-) diff --git a/include_gif/src/lib.rs b/include_gif/src/lib.rs index 86610423..788d3540 100644 --- a/include_gif/src/lib.rs +++ b/include_gif/src/lib.rs @@ -166,8 +166,8 @@ fn image_to_packed_buffer(frame: &mut GrayImage, invert: bool) -> (Vec, u8) let height = frame.height(); let base_threshold = (256 / colors as u32) as u8; let half_threshold = base_threshold / 2; - let mut current_byte = 0 as u16; - let mut current_bit = 0 as u16; + let mut current_byte = 0u16; + let mut current_bit = 0u16; let mut packed: Vec = Vec::new(); for x in (0..width).rev() { @@ -180,14 +180,14 @@ fn image_to_packed_buffer(frame: &mut GrayImage, invert: bool) -> (Vec, u8) current_byte += color << ((8 - bits_per_pixel as u16) - current_bit); current_bit += bits_per_pixel as u16; if current_bit >= 8 { - packed.push(current_byte as u8 & 0xFF); + packed.push(current_byte as u8); current_byte = 0; current_bit = 0; } } } if current_bit > 0 { - packed.push(current_byte as u8 & 0xFF); + packed.push(current_byte as u8); } (packed, bits_per_pixel) } diff --git a/ledger_device_sdk/build.rs b/ledger_device_sdk/build.rs index 0789c8c3..168205fb 100644 --- a/ledger_device_sdk/build.rs +++ b/ledger_device_sdk/build.rs @@ -24,7 +24,7 @@ fn generate_install_parameters() { // Now run cargo metadata from the root directory let output = std::process::Command::new("cargo") .current_dir(root_dir) - .args(&["metadata", "--format-version", "1", "--no-deps"]) + .args(["metadata", "--format-version", "1", "--no-deps"]) .output() .expect("Failed to execute cargo metadata"); @@ -65,7 +65,7 @@ fn generate_install_parameters() { .as_array() .expect("curves not found") .iter() - .map(|v| format!("{}", v.as_str().unwrap())) + .map(|v| v.as_str().unwrap().to_string()) .collect::>(); println!("cargo:warning=curves are {:x?}", curves); @@ -73,7 +73,7 @@ fn generate_install_parameters() { .as_array() .expect("paths not found") .iter() - .map(|v| format!("{}", v.as_str().unwrap())) + .map(|v| v.as_str().unwrap().to_string()) .collect::>(); println!("cargo:warning=paths are {:x?}", paths); diff --git a/ledger_device_sdk/src/ecc.rs b/ledger_device_sdk/src/ecc.rs index e7ddba0e..2f921525 100644 --- a/ledger_device_sdk/src/ecc.rs +++ b/ledger_device_sdk/src/ecc.rs @@ -260,6 +260,7 @@ impl ECPrivateKey { #[macro_export] macro_rules! check_cx_ok { ($fn_call:expr) => {{ + #[allow(clippy::macro_metavars_in_unsafe)] let err = unsafe { $fn_call }; if err != CX_OK { return Err(err.into()); diff --git a/ledger_device_sdk/src/ecc/math.rs b/ledger_device_sdk/src/ecc/math.rs index c425f10b..730b22b0 100644 --- a/ledger_device_sdk/src/ecc/math.rs +++ b/ledger_device_sdk/src/ecc/math.rs @@ -298,6 +298,7 @@ impl EcPoint { /// * `other` - The second `EcPoint` instance /// # Returns /// Returns `Ok(true)` if the points are equal, `Ok(false)` if they are not, or a `CxError` if the comparison fails. + #[allow(clippy::should_implement_trait)] pub fn cmp(&self, other: &EcPoint) -> Result { let mut is_equal = false; check_cx_ok!(cx_ecpoint_cmp(&self.inner, &other.inner, &mut is_equal)); diff --git a/ledger_device_sdk/src/io_callbacks.rs b/ledger_device_sdk/src/io_callbacks.rs index e3f5868b..0887fca3 100644 --- a/ledger_device_sdk/src/io_callbacks.rs +++ b/ledger_device_sdk/src/io_callbacks.rs @@ -3,6 +3,9 @@ // communication interface without holding a reference to it. // This decouples the NBGL layer from the concrete communication backend. +// Items here are used under NBGL target configurations; suppress dead_code for BAGL targets. +#![allow(dead_code)] + use crate::io::{ApduHeader, Reply}; pub type NbglNextEventAheadCb = fn() -> bool; // returns true if APDU detected @@ -38,8 +41,7 @@ pub fn nbgl_register_callbacks( fn get_callbacks() -> &'static NbglCallbacks { unsafe { - #[allow(static_mut_refs)] - NBGL_CALLBACKS + (*core::ptr::addr_of!(NBGL_CALLBACKS)) .as_ref() .expect("NBGL callbacks not registered") } diff --git a/ledger_device_sdk/src/io_legacy.rs b/ledger_device_sdk/src/io_legacy.rs index 6811516e..9476c7c9 100644 --- a/ledger_device_sdk/src/io_legacy.rs +++ b/ledger_device_sdk/src/io_legacy.rs @@ -234,6 +234,7 @@ impl Comm { } } + #[allow(dead_code)] pub(crate) fn nbgl_register_comm(&mut self) { // Register NBGL callbacks if not already set and record current Comm singleton. unsafe { @@ -281,11 +282,12 @@ impl Comm { if status > 0 { let packet_type = seph::PacketTypes::from(buffer[0]); let event = seph::Events::from(buffer[1]); - match (packet_type, event) { - (seph::PacketTypes::PacketTypeSeph, seph::Events::TickerEvent) => unsafe { + if let (seph::PacketTypes::PacketTypeSeph, seph::Events::TickerEvent) = + (packet_type, event) + { + unsafe { ux_process_ticker_event(); - }, - (_, _) => {} + } } } } @@ -345,10 +347,10 @@ impl Comm { loop { let status = sys_seph::io_rx(&mut self.io_buffer, true); - if status > 0 { - if let Some(value) = self.decode_event(status) { - return value; - } + if status > 0 + && let Some(value) = self.decode_event(status) + { + return value; } } } @@ -363,7 +365,7 @@ impl Comm { if status > 0 { return self.detect_apdu::(status); } - return false; + false } pub fn check_event(&mut self) -> Option> @@ -401,11 +403,11 @@ impl Comm { } // If CLA filtering is enabled, automatically reject APDUs with wrong CLA - if let Some(cla) = self.expected_cla { - if self.io_buffer[1] != cla { - self.reply(StatusWords::BadCla); - return None; - } + if let Some(cla) = self.expected_cla + && self.io_buffer[1] != cla + { + self.reply(StatusWords::BadCla); + return None; } let res = T::try_from(*self.get_apdu_metadata()); @@ -424,6 +426,7 @@ impl Comm { None } + #[allow(unused_mut)] pub fn process_event(&mut self, mut seph_buffer: [u8; 272], length: i32) -> Option> where T: TryFrom, @@ -487,7 +490,7 @@ impl Comm { G_ux_params.u.pairing_request.type_ = seph_buffer[4]; G_ux_params.u.pairing_request.pairing_info_len = (_len - 2) as u32; for i in 0..G_ux_params.u.pairing_request.pairing_info_len as usize { - G_ux_params.u.pairing_request.pairing_info[i as usize] = + G_ux_params.u.pairing_request.pairing_info[i] = seph_buffer[5 + i] as core::ffi::c_char; } G_ux_params.u.pairing_request.pairing_info @@ -593,9 +596,9 @@ impl Comm { self.rx_length = length as usize; self.rx = self.rx_length - 1; self.event_pending = true; - return true; + true } - _ => return false, + _ => false, } } @@ -717,8 +720,10 @@ impl Comm { } } +#[allow(dead_code)] static mut CURRENT_COMM: *mut Comm = core::ptr::null_mut(); +#[allow(dead_code)] fn default_nbgl_next_event_ahead() -> bool { unsafe { if CURRENT_COMM.is_null() { @@ -728,6 +733,7 @@ fn default_nbgl_next_event_ahead() -> bool { } } +#[allow(dead_code)] fn default_nbgl_fetch_apdu_header() -> Option { unsafe { if CURRENT_COMM.is_null() { @@ -741,6 +747,7 @@ fn default_nbgl_fetch_apdu_header() -> Option { } } +#[allow(dead_code)] fn default_nbgl_reply_status(reply: Reply) { unsafe { if CURRENT_COMM.is_null() { diff --git a/ledger_device_sdk/src/libcall/string.rs b/ledger_device_sdk/src/libcall/string.rs index 67ab680a..e9cec163 100644 --- a/ledger_device_sdk/src/libcall/string.rs +++ b/ledger_device_sdk/src/libcall/string.rs @@ -142,9 +142,9 @@ pub fn uint256_to_integer(value: &[u8; 32]) -> CustomString<79> { pos -= 1; let mut carry = 0u32; let mut rem: u32; - for i in 0..16 { - rem = ((carry << 16) | u32::from(n[i])) % 10; - n[i] = (((carry << 16) | u32::from(n[i])) / 10) as u16; + for item in n.iter_mut() { + rem = ((carry << 16) | u32::from(*item)) % 10; + *item = (((carry << 16) | u32::from(*item)) / 10) as u16; carry = rem; } s.arr[pos] = u8::try_from(char::from_digit(carry, 10).unwrap()).unwrap(); diff --git a/ledger_device_sdk/src/libcall/swap.rs b/ledger_device_sdk/src/libcall/swap.rs index 81795bba..0675e9e5 100644 --- a/ledger_device_sdk/src/libcall/swap.rs +++ b/ledger_device_sdk/src/libcall/swap.rs @@ -552,7 +552,7 @@ pub fn get_printable_amount_params< } crate::log::info!("==> GET_IS_FEE"); - printable_amount_params.is_fee = params.is_fee == true; + printable_amount_params.is_fee = params.is_fee; crate::log::info!("==> GET_AMOUNT_LENGTH"); printable_amount_params.amount_len = AMOUNT_BUF_SIZE.min(params.amount_length as usize); diff --git a/ledger_device_sdk/src/math.rs b/ledger_device_sdk/src/math.rs index 2e73aa7c..28d5b06c 100644 --- a/ledger_device_sdk/src/math.rs +++ b/ledger_device_sdk/src/math.rs @@ -62,6 +62,10 @@ impl BigUint { N } + pub fn is_empty(&self) -> bool { + N == 0 + } + pub fn addm(&self, other: &Self, modulus: &Self) -> Self { if self >= modulus || other >= modulus { panic!("Operands must be less than modulus"); @@ -167,9 +171,7 @@ impl BigUint { unsafe { let err = cx_math_is_prime_no_throw(self.data.as_ptr(), N, &mut is_prime as *mut bool); match err { - CX_OK => { - return is_prime; - } + CX_OK => is_prime, _ => panic!( "Error checking primality of BigUint with error code: {}", err @@ -179,7 +181,7 @@ impl BigUint { } pub fn next_prime(&self) -> Self { - let mut res = self.clone(); + let mut res = *self; unsafe { let err = cx_math_next_prime_no_throw(res.data.as_mut_ptr(), res.len() as u32); match err { @@ -315,7 +317,7 @@ impl Rem for BigUint { unsafe { let err = cx_math_modm_no_throw(res.data.as_mut_ptr(), N, modulus.data.as_ptr(), N); match err { - CX_OK => return res, + CX_OK => res, _ => panic!( "Error computing modulus of BigUint with error code: {}", err @@ -351,13 +353,7 @@ impl PartialEq> for BigUint { &mut diff as *mut i32, ); match err { - CX_OK => { - if diff != 0 { - return false; - } else { - return true; - } - } + CX_OK => diff == 0, _ => panic!("Error comparing BigUint with error code: {}", err), } } diff --git a/ledger_device_sdk/src/nbgl.rs b/ledger_device_sdk/src/nbgl.rs index 26bd5a08..a8ec6f38 100644 --- a/ledger_device_sdk/src/nbgl.rs +++ b/ledger_device_sdk/src/nbgl.rs @@ -12,7 +12,6 @@ extern crate alloc; use alloc::ffi::CString; use alloc::{vec, vec::Vec}; use core::ffi::{c_char, c_int}; -use core::mem::transmute; use ledger_secure_sdk_sys::*; pub mod nbgl_action; @@ -243,8 +242,8 @@ struct CField { impl From<&Field<'_>> for CField { fn from(field: &Field) -> CField { CField { - name: CString::new((*field).name).unwrap(), - value: CString::new((*field).value).unwrap(), + name: CString::new(field.name).unwrap(), + value: CString::new(field.value).unwrap(), } } } @@ -252,8 +251,8 @@ impl From<&Field<'_>> for CField { impl From<&CField> for nbgl_contentTagValue_t { fn from(field: &CField) -> nbgl_contentTagValue_t { nbgl_contentTagValue_t { - item: (*field).name.as_ptr() as *const ::core::ffi::c_char, - value: (*field).value.as_ptr() as *const ::core::ffi::c_char, + item: field.name.as_ptr() as *const ::core::ffi::c_char, + value: field.value.as_ptr() as *const ::core::ffi::c_char, ..Default::default() } } @@ -316,20 +315,20 @@ impl<'a> NbglGlyph<'a> { } } -impl<'a> Into for &NbglGlyph<'a> { - fn into(self) -> nbgl_icon_details_t { - let bpp = match self.bpp { +impl<'a> From<&NbglGlyph<'a>> for nbgl_icon_details_t { + fn from(val: &NbglGlyph<'a>) -> Self { + let bpp = match val.bpp { 1 => NBGL_BPP_1, 2 => NBGL_BPP_2, 4 => NBGL_BPP_4, _ => panic!("Invalid bpp"), }; nbgl_icon_details_t { - width: self.width, - height: self.height, + width: val.width, + height: val.height, bpp, - isFile: self.is_file, - bitmap: self.bitmap.as_ptr() as *const u8, + isFile: val.is_file, + bitmap: val.bitmap.as_ptr(), } } } diff --git a/ledger_device_sdk/src/nbgl/nbgl_action.rs b/ledger_device_sdk/src/nbgl/nbgl_action.rs index 2c340ae6..cd5a7f69 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_action.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_action.rs @@ -14,6 +14,12 @@ pub struct NbglAction<'a> { impl SyncNBGL for NbglAction<'_> {} +impl<'a> Default for NbglAction<'a> { + fn default() -> Self { + Self::new() + } +} + impl<'a> NbglAction<'a> { /// Creates a new action page builder. pub fn new() -> NbglAction<'a> { diff --git a/ledger_device_sdk/src/nbgl/nbgl_address_review.rs b/ledger_device_sdk/src/nbgl/nbgl_address_review.rs index 3c182432..c8437982 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_address_review.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_address_review.rs @@ -16,6 +16,12 @@ pub struct NbglAddressReview<'a> { impl SyncNBGL for NbglAddressReview<'_> {} +impl<'a> Default for NbglAddressReview<'a> { + fn default() -> Self { + Self::new() + } +} + impl<'a> NbglAddressReview<'a> { /// Creates a new address review flow builder. pub fn new() -> NbglAddressReview<'a> { @@ -98,7 +104,7 @@ impl<'a> NbglAddressReview<'a> { } let tag_value_list = nbgl_contentTagValueList_t { - pairs: tag_value_array.as_ptr() as *const nbgl_contentTagValue_t, + pairs: tag_value_array.as_ptr(), nbPairs: tag_value_array.len() as u8, ..Default::default() }; @@ -122,12 +128,8 @@ impl<'a> NbglAddressReview<'a> { // Return true if the user approved the address, false otherwise. match sync_ret { - SyncNbgl::UxSyncRetApproved => { - return true; - } - SyncNbgl::UxSyncRetRejected => { - return false; - } + SyncNbgl::UxSyncRetApproved => true, + SyncNbgl::UxSyncRetRejected => false, _ => { panic!("Unexpected return value from ux_sync_addressReview"); } diff --git a/ledger_device_sdk/src/nbgl/nbgl_advance_review.rs b/ledger_device_sdk/src/nbgl/nbgl_advance_review.rs index b10463c6..c122be32 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_advance_review.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_advance_review.rs @@ -38,7 +38,7 @@ impl<'a> NbglAdvanceReview<'a> { /// Returns a new instance of `NbglAdvanceReview`. pub fn new(operation_type: TransactionType) -> NbglAdvanceReview<'a> { NbglAdvanceReview { - operation_type: operation_type, + operation_type, review_title: CString::default(), review_subtitle: CString::default(), finish_title: CString::default(), @@ -143,7 +143,7 @@ impl<'a> NbglAdvanceReview<'a> { tag_value_array.push(val); } let tag_value_list = nbgl_contentTagValueList_t { - pairs: tag_value_array.as_ptr() as *const nbgl_contentTagValue_t, + pairs: tag_value_array.as_ptr(), nbPairs: fields.len() as u8, ..Default::default() }; diff --git a/ledger_device_sdk/src/nbgl/nbgl_choice.rs b/ledger_device_sdk/src/nbgl/nbgl_choice.rs index 6a0338ea..0a3ae1ce 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_choice.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_choice.rs @@ -11,6 +11,12 @@ pub struct NbglChoice<'a> { impl SyncNBGL for NbglChoice<'_> {} +impl<'a> Default for NbglChoice<'a> { + fn default() -> Self { + Self::new() + } +} + impl<'a> NbglChoice<'a> { /// Creates a new choice flow builder. pub fn new() -> NbglChoice<'a> { @@ -23,10 +29,7 @@ impl<'a> NbglChoice<'a> { /// # Returns /// Returns the builder itself to allow method chaining. pub fn glyph(self, glyph: &'a NbglGlyph) -> NbglChoice<'a> { - NbglChoice { - glyph: Some(glyph), - ..self - } + NbglChoice { glyph: Some(glyph) } } /// Configures the confirmation dialog to be shown when the user accepts or rejects the choice. @@ -36,7 +39,7 @@ impl<'a> NbglChoice<'a> { /// * `ok_text` - The text to display on the confirmation button. If `None`, a default text is used. /// * `ko_text` - The text to display on the cancellation button. If `None`, a default text is used. /// * `if_accept` - The `if_accept` parameter determines whether the dialog is shown when the user accepts (`true`) - /// or rejects (`false`) the choice. + /// or rejects (`false`) the choice. /// # Returns /// Returns the builder itself to allow method chaining. pub fn ask_confirmation( @@ -70,14 +73,14 @@ impl<'a> NbglChoice<'a> { G_CONFIRM_ASK_WHEN_TRUE = true; G_CONFIRM_SCREEN[G_CONFIRM_SCREEN_WHEN_TRUE_IDX] = Some(screen); } - return self; + self } else { #[allow(static_mut_refs)] unsafe { G_CONFIRM_ASK_WHEN_FALSE = true; G_CONFIRM_SCREEN[G_CONFIRM_SCREEN_WHEN_FALSE_IDX] = Some(screen); } - return self; + self } } @@ -122,14 +125,7 @@ impl<'a> NbglChoice<'a> { let sync_ret = self.ux_sync_wait(false); // Return true if the user approved the transaction, false otherwise. - match sync_ret { - SyncNbgl::UxSyncRetApproved => { - return true; - } - _ => { - return false; - } - } + matches!(sync_ret, SyncNbgl::UxSyncRetApproved) } } diff --git a/ledger_device_sdk/src/nbgl/nbgl_generic_review.rs b/ledger_device_sdk/src/nbgl/nbgl_generic_review.rs index 3038fa35..f4758d84 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_generic_review.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_generic_review.rs @@ -106,15 +106,16 @@ impl CenteredInfo { text2: CString::new(text2).unwrap(), #[cfg(any(target_os = "stax", target_os = "flex", target_os = "apex_p"))] text3: CString::new(text3).unwrap(), - icon: icon.map_or(None, |g| Some(g.into())), - on_top: on_top, - style: style, + icon: icon.map(|g| g.into()), + on_top, + style, #[cfg(any(target_os = "stax", target_os = "flex", target_os = "apex_p"))] - offset_y: offset_y, + offset_y, } } } +#[allow(clippy::needless_update)] impl From<&CenteredInfo> for nbgl_contentCenteredInfo_t { fn from(info: &CenteredInfo) -> nbgl_contentCenteredInfo_t { nbgl_contentCenteredInfo_t { @@ -165,13 +166,14 @@ impl InfoLongPress { ) -> InfoLongPress { InfoLongPress { text: CString::new(text).unwrap(), - icon: icon.map_or(None, |g| Some(g.into())), + icon: icon.map(|g| g.into()), long_press_text: CString::new(long_press_text).unwrap(), - tune_id: tune_id, + tune_id, } } } +#[allow(clippy::needless_update)] impl From<&InfoLongPress> for nbgl_contentInfoLongPress_t { fn from(info: &InfoLongPress) -> nbgl_contentInfoLongPress_t { nbgl_contentInfoLongPress_t { @@ -218,13 +220,14 @@ impl InfoButton { ) -> InfoButton { InfoButton { text: CString::new(text).unwrap(), - icon: icon.map_or(None, |g| Some(g.into())), + icon: icon.map(|g| g.into()), button_text: CString::new(button_text).unwrap(), - tune_id: tune_id, + tune_id, } } } +#[allow(clippy::needless_update)] impl From<&InfoButton> for nbgl_contentInfoButton_t { fn from(info: &InfoButton) -> nbgl_contentInfoButton_t { nbgl_contentInfoButton_t { @@ -281,7 +284,7 @@ impl TagValueList { let pairs: Vec = cfields.iter().map(|pair| pair.into()).collect(); TagValueList { _cfields: cfields, - pairs: pairs, + pairs, nb_max_lines_for_value, small_case_for_value, wrapping, @@ -289,18 +292,18 @@ impl TagValueList { } } +#[allow(clippy::needless_update)] impl From<&TagValueList> for nbgl_contentTagValueList_t { fn from(tvl: &TagValueList) -> nbgl_contentTagValueList_t { - let nbgl_content_tvl = nbgl_contentTagValueList_t { - pairs: tvl.pairs.as_ptr() as *const nbgl_contentTagValue_t, + nbgl_contentTagValueList_t { + pairs: tvl.pairs.as_ptr(), nbPairs: tvl.pairs.len() as u8, nbMaxLinesForValue: tvl.nb_max_lines_for_value, token: FIRST_USER_TOKEN as u8, smallCaseForValue: tvl.small_case_for_value, wrapping: tvl.wrapping, ..Default::default() - }; - nbgl_content_tvl + } } } @@ -338,13 +341,14 @@ impl TagValueConfirm { let cancel_text_cstring = CString::new(cancel_text).unwrap(); TagValueConfirm { tag_value_list: tag_value_list.into(), - tune_id: tune_id, + tune_id, confirmation_text: confirmation_text_cstring, cancel_text: cancel_text_cstring, } } } +#[allow(clippy::needless_update)] impl From<&TagValueConfirm> for nbgl_contentTagValueConfirm_t { fn from(tvc: &TagValueConfirm) -> nbgl_contentTagValueConfirm_t { nbgl_contentTagValueConfirm_t { @@ -394,19 +398,20 @@ impl InfosList { let info_contents_ptr: Vec<*const c_char> = info_contents_cstrings.iter().map(|s| s.as_ptr()).collect(); InfosList { - info_types_cstrings: info_types_cstrings, + info_types_cstrings, _info_contents_cstrings: info_contents_cstrings, - info_types_ptr: info_types_ptr, - info_contents_ptr: info_contents_ptr, + info_types_ptr, + info_contents_ptr, } } } +#[allow(clippy::needless_update)] impl From<&InfosList> for nbgl_contentInfoList_t { fn from(infos_list: &InfosList) -> nbgl_contentInfoList_t { nbgl_contentInfoList_t { - infoTypes: infos_list.info_types_ptr.as_ptr() as *const *const c_char, - infoContents: infos_list.info_contents_ptr.as_ptr() as *const *const c_char, + infoTypes: infos_list.info_types_ptr.as_ptr(), + infoContents: infos_list.info_contents_ptr.as_ptr(), nbInfos: infos_list.info_types_cstrings.len() as u8, ..Default::default() } @@ -525,6 +530,12 @@ pub struct NbglGenericReview { impl SyncNBGL for NbglGenericReview {} +impl Default for NbglGenericReview { + fn default() -> Self { + Self::new() + } +} + impl NbglGenericReview { /// Creates an empty [`NbglGenericReview`] with no content pages. pub fn new() -> NbglGenericReview { @@ -563,7 +574,7 @@ impl NbglGenericReview { let content_struct = nbgl_genericContents_t { callbackCallNeeded: false, __bindgen_anon_1: nbgl_genericContents_t__bindgen_ty_1 { - contentsList: c_content_list.as_ptr() as *const nbgl_content_t, + contentsList: c_content_list.as_ptr(), }, nbContents: self.content_list.len() as u8, }; @@ -579,14 +590,7 @@ impl NbglGenericReview { let sync_ret = self.ux_sync_wait(false); // Return true if the user approved the transaction, false otherwise. - match sync_ret { - SyncNbgl::UxSyncRetApproved => { - return true; - } - _ => { - return false; - } - } + matches!(sync_ret, SyncNbgl::UxSyncRetApproved) } } diff --git a/ledger_device_sdk/src/nbgl/nbgl_generic_settings.rs b/ledger_device_sdk/src/nbgl/nbgl_generic_settings.rs index dca2f19a..75df6c7b 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_generic_settings.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_generic_settings.rs @@ -1,6 +1,8 @@ use super::*; +use core::sync::atomic::{AtomicPtr, Ordering}; -static mut NVM_REF: Option<&mut AtomicStorage<[u8; SETTINGS_SIZE]>> = None; +static NVM_REF: AtomicPtr> = + AtomicPtr::new(core::ptr::null_mut()); static mut SWITCH_ARRAY: [nbgl_contentSwitch_t; SETTINGS_SIZE] = [unsafe { const_zero!(nbgl_contentSwitch_t) }; SETTINGS_SIZE]; @@ -20,7 +22,9 @@ unsafe extern "C" fn settings_callback(token: c_int, _index: u8, _page: c_int) { _ => panic!("Invalid state."), } - if let Some(data) = (*(&raw mut NVM_REF)).as_mut() { + let ptr = NVM_REF.load(Ordering::Relaxed); + if !ptr.is_null() { + let data = &mut *ptr; let mut switch_values: [u8; SETTINGS_SIZE] = *data.get_ref(); if switch_values[setting_idx] == OFF_STATE { switch_values[setting_idx] = ON_STATE; @@ -52,6 +56,12 @@ pub struct NbglGenericSettings { impl SyncNBGL for NbglGenericSettings {} +impl Default for NbglGenericSettings { + fn default() -> Self { + Self::new() + } +} + impl NbglGenericSettings { pub fn new() -> NbglGenericSettings { NbglGenericSettings { @@ -113,13 +123,17 @@ impl NbglGenericSettings { .map(|s| [CString::new(s[0]).unwrap(), CString::new(s[1]).unwrap()]) .collect(); + NVM_REF.store( + nvm_data as *mut AtomicStorage<[u8; SETTINGS_SIZE]>, + Ordering::Relaxed, + ); unsafe { - NVM_REF = Some(transmute(nvm_data)); for (i, setting) in self.settings_title_subtitle.iter().enumerate() { SWITCH_ARRAY[i].text = setting[0].as_ptr(); SWITCH_ARRAY[i].subText = setting[1].as_ptr(); - let state = if let Some(data) = (*(&raw mut NVM_REF)).as_mut() { - data.get_ref()[i] + let ptr = NVM_REF.load(Ordering::Relaxed); + let state = if !ptr.is_null() { + (&*ptr).get_ref()[i] } else { OFF_STATE }; diff --git a/ledger_device_sdk/src/nbgl/nbgl_home_and_settings.rs b/ledger_device_sdk/src/nbgl/nbgl_home_and_settings.rs index 4033cca7..b72cc4d0 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_home_and_settings.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_home_and_settings.rs @@ -6,9 +6,11 @@ use super::*; use crate::io::{Reply, StatusWords}; use crate::io_callbacks::{nbgl_fetch_apdu_header, nbgl_reply_status}; +use core::sync::atomic::{AtomicPtr, Ordering}; pub const SETTINGS_SIZE: usize = 10; -static mut NVM_REF: Option<&mut AtomicStorage<[u8; SETTINGS_SIZE]>> = None; +static NVM_REF: AtomicPtr> = + AtomicPtr::new(core::ptr::null_mut()); static mut SWITCH_ARRAY: [nbgl_contentSwitch_t; SETTINGS_SIZE] = [unsafe { const_zero!(nbgl_contentSwitch_t) }; SETTINGS_SIZE]; @@ -27,8 +29,9 @@ unsafe extern "C" fn settings_callback(token: c_int, _index: u8, _page: c_int) { ON_STATE => SWITCH_ARRAY[setting_idx].initState = OFF_STATE, _ => panic!("Invalid state."), } - - if let Some(data) = (*(&raw mut NVM_REF)).as_mut() { + let ptr = NVM_REF.load(Ordering::Relaxed); + if !ptr.is_null() { + let data = &mut *ptr; let mut switch_values: [u8; SETTINGS_SIZE] = *data.get_ref(); if switch_values[setting_idx] == OFF_STATE { switch_values[setting_idx] = ON_STATE; @@ -42,10 +45,7 @@ unsafe extern "C" fn settings_callback(token: c_int, _index: u8, _page: c_int) { /// Informations fields name to display in the dedicated /// page of the home screen. -const INFO_FIELDS: [*const c_char; 2] = [ - "Version\0".as_ptr() as *const c_char, - "Developer\0".as_ptr() as *const c_char, -]; +const INFO_FIELDS: [*const c_char; 2] = [c"Version".as_ptr(), c"Developer".as_ptr()]; /// Initial page to display when showing the home and settings screen. pub enum PageIndex { @@ -74,13 +74,13 @@ unsafe extern "C" fn quit_cb() { exit_app(0); } -impl<'a> Default for NbglHomeAndSettings { +impl Default for NbglHomeAndSettings { fn default() -> Self { Self::new() } } -impl<'a> NbglHomeAndSettings { +impl NbglHomeAndSettings { /// Creates a new home and settings page builder. /// # Returns /// Returns a new instance of `NbglHomeAndSettings`. @@ -105,7 +105,7 @@ impl<'a> NbglHomeAndSettings { /// * `glyph` - The icon to display in the center of the page. /// # Returns /// Returns the builder itself to allow method chaining. - pub fn glyph(self, glyph: &'a NbglGlyph) -> NbglHomeAndSettings { + pub fn glyph(self, glyph: &NbglGlyph) -> NbglHomeAndSettings { let icon = glyph.into(); NbglHomeAndSettings { icon, ..self } } @@ -118,12 +118,7 @@ impl<'a> NbglHomeAndSettings { /// * `author` - The author of the application. /// # Returns /// Returns the builder itself to allow method chaining. - pub fn infos( - self, - app_name: &'a str, - version: &'a str, - author: &'a str, - ) -> NbglHomeAndSettings { + pub fn infos(self, app_name: &str, version: &str, author: &str) -> NbglHomeAndSettings { let v: Vec = vec![ CString::new(version).unwrap(), CString::new(author).unwrap(), @@ -141,7 +136,7 @@ impl<'a> NbglHomeAndSettings { /// * `tagline` - The tagline to display below the application name on the home screen. /// # Returns /// Returns the builder itself to allow method chaining. - pub fn tagline(self, tagline: &'a str) -> NbglHomeAndSettings { + pub fn tagline(self, tagline: &str) -> NbglHomeAndSettings { NbglHomeAndSettings { tag_line: Some(CString::new(tagline).unwrap()), ..self @@ -158,12 +153,13 @@ impl<'a> NbglHomeAndSettings { /// Returns the builder itself to allow method chaining. pub fn settings( self, - nvm_data: &'a mut AtomicStorage<[u8; SETTINGS_SIZE]>, - settings_strings: &[[&'a str; 2]], + nvm_data: &mut AtomicStorage<[u8; SETTINGS_SIZE]>, + settings_strings: &[[&str; 2]], ) -> NbglHomeAndSettings { - unsafe { - NVM_REF = Some(transmute(nvm_data)); - } + NVM_REF.store( + nvm_data as *mut AtomicStorage<[u8; SETTINGS_SIZE]>, + Ordering::Relaxed, + ); if settings_strings.len() > SETTINGS_SIZE { panic!("Too many settings."); @@ -215,8 +211,9 @@ impl<'a> NbglHomeAndSettings { for (i, setting) in self.setting_contents.iter().enumerate() { SWITCH_ARRAY[i].text = setting[0].as_ptr(); SWITCH_ARRAY[i].subText = setting[1].as_ptr(); - let state = if let Some(data) = (*(&raw mut NVM_REF)).as_mut() { - data.get_ref()[i] + let ptr = NVM_REF.load(Ordering::Relaxed); + let state = if !ptr.is_null() { + (&*ptr).get_ref()[i] } else { OFF_STATE }; @@ -345,8 +342,9 @@ impl<'a> NbglHomeAndSettings { for (i, setting) in self.setting_contents.iter().enumerate() { SWITCH_ARRAY[i].text = setting[0].as_ptr(); SWITCH_ARRAY[i].subText = setting[1].as_ptr(); - let state = if let Some(data) = (*(&raw mut NVM_REF)).as_mut() { - data.get_ref()[i] + let ptr = NVM_REF.load(Ordering::Relaxed); + let state = if !ptr.is_null() { + (&*ptr).get_ref()[i] } else { OFF_STATE }; diff --git a/ledger_device_sdk/src/nbgl/nbgl_keypad.rs b/ledger_device_sdk/src/nbgl/nbgl_keypad.rs index d382f154..e23e2878 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_keypad.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_keypad.rs @@ -2,6 +2,7 @@ //! //! Draws a keypad for user input, allowing for PIN entry and other numeric input. use super::*; +use core::sync::atomic::{AtomicPtr, Ordering}; /// A builder to create and show a keypad for user input. pub struct NbglKeypad { @@ -14,14 +15,21 @@ pub struct NbglKeypad { impl SyncNBGL for NbglKeypad {} +impl Default for NbglKeypad { + fn default() -> Self { + Self::new() + } +} + const PIN_BUFFER_SIZE: usize = 16; -static mut PIN_BUFFER: [u8; PIN_BUFFER_SIZE] = [0x00; PIN_BUFFER_SIZE]; +static PIN_BUFFER_PTR: AtomicPtr = AtomicPtr::new(core::ptr::null_mut()); unsafe extern "C" fn pin_callback(pin: *const u8, pin_len: u8) { unsafe { let len = (pin_len as usize).min(PIN_BUFFER_SIZE); - for i in 0..len { - PIN_BUFFER[i] = *pin.add(i); + let buf = PIN_BUFFER_PTR.load(Ordering::Relaxed); + if !buf.is_null() { + core::ptr::copy_nonoverlapping(pin, buf, len); } G_ENDED = true; } @@ -108,6 +116,9 @@ impl NbglKeypad { fn ask_internal(self, pin: &[u8]) -> SyncNbgl { unsafe { + let mut buffer = [0u8; PIN_BUFFER_SIZE]; + PIN_BUFFER_PTR.store(buffer.as_mut_ptr(), Ordering::Relaxed); + self.ux_sync_init(); nbgl_useCaseKeypad( self.title.as_ptr() as *const c_char, @@ -119,11 +130,13 @@ impl NbglKeypad { Some(action_callback), ); self.ux_sync_wait(false); + PIN_BUFFER_PTR.store(core::ptr::null_mut(), Ordering::Relaxed); + // Compare with set pin code - if pin == &PIN_BUFFER[..pin.len()] { - return SyncNbgl::UxSyncRetPinValidated; + if pin == &buffer[..pin.len()] { + SyncNbgl::UxSyncRetPinValidated } else { - return SyncNbgl::UxSyncRetPinRejected; + SyncNbgl::UxSyncRetPinRejected } } } diff --git a/ledger_device_sdk/src/nbgl/nbgl_review.rs b/ledger_device_sdk/src/nbgl/nbgl_review.rs index 0c472df2..1498b782 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_review.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_review.rs @@ -16,6 +16,12 @@ pub struct NbglReview<'a> { impl SyncNBGL for NbglReview<'_> {} +impl<'a> Default for NbglReview<'a> { + fn default() -> Self { + Self::new() + } +} + impl<'a> NbglReview<'a> { /// Creates a new review flow builder. /// # Returns @@ -117,7 +123,7 @@ impl<'a> NbglReview<'a> { // Create the tag_value_list with the tag_value_array. let tag_value_list = nbgl_contentTagValueList_t { - pairs: tag_value_array.as_ptr() as *const nbgl_contentTagValue_t, + pairs: tag_value_array.as_ptr(), nbPairs: fields.len() as u8, ..Default::default() }; @@ -196,14 +202,7 @@ impl<'a> NbglReview<'a> { let sync_ret = self.ux_sync_wait(false); // Return true if the user approved the transaction, false otherwise. - match sync_ret { - SyncNbgl::UxSyncRetApproved => { - return true; - } - _ => { - return false; - } - } + matches!(sync_ret, SyncNbgl::UxSyncRetApproved) } } diff --git a/ledger_device_sdk/src/nbgl/nbgl_review_extended.rs b/ledger_device_sdk/src/nbgl/nbgl_review_extended.rs index 4f87f6bc..a80ea844 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_review_extended.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_review_extended.rs @@ -18,6 +18,12 @@ pub struct NbglReviewExtended<'a> { impl SyncNBGL for NbglReviewExtended<'_> {} +impl<'a> Default for NbglReviewExtended<'a> { + fn default() -> Self { + Self::new() + } +} + impl<'a> NbglReviewExtended<'a> { /// Creates a new extended review flow builder. /// # Returns @@ -138,7 +144,7 @@ impl<'a> NbglReviewExtended<'a> { tag_value_array.push(val); } let tag_value_list = nbgl_contentTagValueList_t { - pairs: tag_value_array.as_ptr() as *const nbgl_contentTagValue_t, + pairs: tag_value_array.as_ptr(), nbPairs: fields.len() as u8, ..Default::default() }; diff --git a/ledger_device_sdk/src/nbgl/nbgl_review_status.rs b/ledger_device_sdk/src/nbgl/nbgl_review_status.rs index 1b999805..8d43fbc3 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_review_status.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_review_status.rs @@ -10,7 +10,13 @@ pub struct NbglReviewStatus { impl SyncNBGL for NbglReviewStatus {} -impl<'a> NbglReviewStatus { +impl Default for NbglReviewStatus { + fn default() -> Self { + Self::new() + } +} + +impl NbglReviewStatus { /// Creates a new status review page builder. /// # Returns /// Returns a new instance of `NbglReviewStatus`. diff --git a/ledger_device_sdk/src/nbgl/nbgl_status.rs b/ledger_device_sdk/src/nbgl/nbgl_status.rs index 07a1014f..a62da83c 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_status.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_status.rs @@ -10,6 +10,12 @@ pub struct NbglStatus { impl SyncNBGL for NbglStatus {} +impl Default for NbglStatus { + fn default() -> Self { + Self::new() + } +} + impl NbglStatus { /// Creates a new status page builder. pub fn new() -> NbglStatus { diff --git a/ledger_device_sdk/src/nbgl/nbgl_streaming_review.rs b/ledger_device_sdk/src/nbgl/nbgl_streaming_review.rs index 4c2a4d37..e65ebef0 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_streaming_review.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_streaming_review.rs @@ -28,6 +28,12 @@ pub struct NbglStreamingReview { impl SyncNBGL for NbglStreamingReview {} +impl Default for NbglStreamingReview { + fn default() -> Self { + Self::new() + } +} + /// Status returned by the `next` method. pub enum NbglStreamingReviewStatus { Next, @@ -195,14 +201,7 @@ impl NbglStreamingReview { let sync_ret = self.ux_sync_wait(false); // Return true if the user approved the transaction, false otherwise. - match sync_ret { - SyncNbgl::UxSyncRetApproved => { - return true; - } - _ => { - return false; - } - } + matches!(sync_ret, SyncNbgl::UxSyncRetApproved) } } @@ -230,7 +229,7 @@ impl NbglStreamingReview { // Create the tag_value_list with the tag_value_array. let tag_value_list = nbgl_contentTagValueList_t { - pairs: tag_value_array.as_ptr() as *const nbgl_contentTagValue_t, + pairs: tag_value_array.as_ptr(), nbPairs: fields.len() as u8, ..Default::default() }; @@ -243,14 +242,7 @@ impl NbglStreamingReview { let sync_ret = self.ux_sync_wait(false); // Return true if the user approved the transaction, false otherwise. - match sync_ret { - SyncNbgl::UxSyncRetApproved => { - return true; - } - _ => { - return false; - } - } + matches!(sync_ret, SyncNbgl::UxSyncRetApproved) } } @@ -283,7 +275,7 @@ impl NbglStreamingReview { // Create the tag_value_list with the tag_value_array. let tag_value_list = nbgl_contentTagValueList_t { - pairs: tag_value_array.as_ptr() as *const nbgl_contentTagValue_t, + pairs: tag_value_array.as_ptr(), nbPairs: fields.len() as u8, ..Default::default() }; @@ -298,15 +290,9 @@ impl NbglStreamingReview { // Return true if the user approved the transaction, false otherwise. match sync_ret { - SyncNbgl::UxSyncRetApproved => { - return NbglStreamingReviewStatus::Next; - } - SyncNbgl::UxSyncRetSkipped => { - return NbglStreamingReviewStatus::Skipped; - } - _ => { - return NbglStreamingReviewStatus::Rejected; - } + SyncNbgl::UxSyncRetApproved => NbglStreamingReviewStatus::Next, + SyncNbgl::UxSyncRetSkipped => NbglStreamingReviewStatus::Skipped, + _ => NbglStreamingReviewStatus::Rejected, } } } @@ -328,14 +314,7 @@ impl NbglStreamingReview { let sync_ret = self.ux_sync_wait(false); // Return true if the user approved the transaction, false otherwise. - match sync_ret { - SyncNbgl::UxSyncRetApproved => { - return true; - } - _ => { - return false; - } - } + matches!(sync_ret, SyncNbgl::UxSyncRetApproved) } } } diff --git a/ledger_device_sdk/src/nvm.rs b/ledger_device_sdk/src/nvm.rs index 14b12776..0c0be837 100644 --- a/ledger_device_sdk/src/nvm.rs +++ b/ledger_device_sdk/src/nvm.rs @@ -333,7 +333,7 @@ where /// Returns true if collection is empty pub fn is_empty(&self) -> bool { - !self.flags.get_ref().iter().any(|v| *v == STORAGE_VALID) + !self.flags.get_ref().contains(&STORAGE_VALID) } /// Returns the maximum number of items the collection can store. diff --git a/ledger_device_sdk/src/pki.rs b/ledger_device_sdk/src/pki.rs index 4b5d4947..6ba8a3c0 100644 --- a/ledger_device_sdk/src/pki.rs +++ b/ledger_device_sdk/src/pki.rs @@ -69,9 +69,9 @@ pub fn pki_check_signature( let err = unsafe { os_pki_verify( - hash.as_mut_ptr() as *mut u8, + hash.as_mut_ptr(), hash.len(), - signature.as_mut_ptr() as *mut u8, + signature.as_mut_ptr(), signature.len(), ) }; diff --git a/ledger_device_sdk/src/seph.rs b/ledger_device_sdk/src/seph.rs index d1ee23d2..5e932087 100644 --- a/ledger_device_sdk/src/seph.rs +++ b/ledger_device_sdk/src/seph.rs @@ -7,20 +7,20 @@ use ledger_secure_sdk_sys::*; #[repr(u8)] pub enum PacketTypes { - PacketTypeNone = OS_IO_PACKET_TYPE_NONE as u8, - PacketTypeSeph = OS_IO_PACKET_TYPE_SEPH as u8, - PacketTypeSeEvent = OS_IO_PACKET_TYPE_SE_EVT as u8, + PacketTypeNone = OS_IO_PACKET_TYPE_NONE, + PacketTypeSeph = OS_IO_PACKET_TYPE_SEPH, + PacketTypeSeEvent = OS_IO_PACKET_TYPE_SE_EVT, - PacketTypeRawApdu = OS_IO_PACKET_TYPE_RAW_APDU as u8, - PacketTypeUsbHidApdu = OS_IO_PACKET_TYPE_USB_HID_APDU as u8, - PacketTypeUsbWebusbApdu = OS_IO_PACKET_TYPE_USB_WEBUSB_APDU as u8, + PacketTypeRawApdu = OS_IO_PACKET_TYPE_RAW_APDU, + PacketTypeUsbHidApdu = OS_IO_PACKET_TYPE_USB_HID_APDU, + PacketTypeUsbWebusbApdu = OS_IO_PACKET_TYPE_USB_WEBUSB_APDU, - PacketTypeBleApdu = OS_IO_PACKET_TYPE_BLE_APDU as u8, + PacketTypeBleApdu = OS_IO_PACKET_TYPE_BLE_APDU, } impl From for PacketTypes { fn from(v: u8) -> PacketTypes { - match v as u8 { + match v { OS_IO_PACKET_TYPE_NONE => PacketTypes::PacketTypeNone, OS_IO_PACKET_TYPE_SEPH => PacketTypes::PacketTypeSeph, OS_IO_PACKET_TYPE_SE_EVT => PacketTypes::PacketTypeSeEvent, @@ -56,15 +56,15 @@ impl From for Events { #[repr(u8)] pub enum ItcUxEvent { - AskBlePairing = ITC_UX_ASK_BLE_PAIRING as u8, - BlePairingStatus = ITC_UX_BLE_PAIRING_STATUS as u8, - Redisplay = ITC_UX_REDISPLAY as u8, + AskBlePairing = ITC_UX_ASK_BLE_PAIRING, + BlePairingStatus = ITC_UX_BLE_PAIRING_STATUS, + Redisplay = ITC_UX_REDISPLAY, Unknown = 0xff, } impl From for ItcUxEvent { fn from(v: u8) -> ItcUxEvent { - match v as u8 { + match v { ITC_UX_ASK_BLE_PAIRING => ItcUxEvent::AskBlePairing, ITC_UX_BLE_PAIRING_STATUS => ItcUxEvent::BlePairingStatus, ITC_UX_REDISPLAY => ItcUxEvent::Redisplay, @@ -91,18 +91,15 @@ pub type ApduBufferT = apdu_buffer_s; pub fn handle_event(_apdu_buffer: &mut [u8], spi_buffer: &[u8]) { let _len = u16::from_be_bytes([spi_buffer[1], spi_buffer[2]]); - match Events::from(spi_buffer[0]) { - Events::TickerEvent => { - #[cfg(any( - target_os = "apex_p", - target_os = "stax", - target_os = "flex", - feature = "nano_nbgl" - ))] - unsafe { - ux_process_ticker_event(); - } + if let Events::TickerEvent = Events::from(spi_buffer[0]) { + #[cfg(any( + target_os = "apex_p", + target_os = "stax", + target_os = "flex", + feature = "nano_nbgl" + ))] + unsafe { + ux_process_ticker_event(); } - _ => (), } } diff --git a/ledger_device_sdk/src/testing.rs b/ledger_device_sdk/src/testing.rs index ba94056a..e36edcff 100644 --- a/ledger_device_sdk/src/testing.rs +++ b/ledger_device_sdk/src/testing.rs @@ -207,7 +207,7 @@ fn to_dec(v: u32) -> [u8; 10] { let mut i = 0; while fact != 0 { let d = val / fact; - let c = char::from_digit(d.into(), 10).unwrap(); + let c = char::from_digit(d, 10).unwrap(); dec[i] = c as u8; i += 1; val -= d * fact; diff --git a/ledger_device_sdk/src/tlv/tlv_dynamic_token.rs b/ledger_device_sdk/src/tlv/tlv_dynamic_token.rs index 352129aa..fbb752d5 100644 --- a/ledger_device_sdk/src/tlv/tlv_dynamic_token.rs +++ b/ledger_device_sdk/src/tlv/tlv_dynamic_token.rs @@ -171,8 +171,10 @@ static HANDLERS: &[Handler] = &[ /// # Returns /// Returns `Ok(())` if parsing was successful, or a `TlvError` otherwise. pub fn parse_dynamic_token_tlv(payload: &[u8], out: &mut DynamicTokenOut) -> Result<()> { - let mut extracted = DynamicTokenExtracted::default(); - extracted.hash_ctx = Sha2_256::new(); + let mut extracted = DynamicTokenExtracted { + hash_ctx: Sha2_256::new(), + ..DynamicTokenExtracted::default() + }; let mut received = Received::new(tag_to_flag_u64); diff --git a/ledger_device_sdk/src/tlv/tlv_trusted_name.rs b/ledger_device_sdk/src/tlv/tlv_trusted_name.rs index 0d83fed4..b3e94502 100644 --- a/ledger_device_sdk/src/tlv/tlv_trusted_name.rs +++ b/ledger_device_sdk/src/tlv/tlv_trusted_name.rs @@ -27,6 +27,7 @@ extern crate alloc; use alloc::string::String; use alloc::vec::Vec; +#[allow(clippy::enum_variant_names)] enum TlvTrustedNameSignerAlgorithm { TlvTrustedNameSignerAlgorithmEcdsaSha256 = 0x01, TlvTrustedNameSignerAlgorithmEcdsaSha3_256 = 0x02, @@ -304,14 +305,15 @@ static HANDLERS: &[Handler] = &[ /// # Returns /// * `Result<()>` - Ok(()) if parsing and verification succeed, Err(TlvError) otherwise pub fn parse_trusted_name_tlv(payload: &[u8], out: &mut TrustedNameOut) -> Result<()> { - let mut extracted = TrustedNameExtracted::default(); - - extracted.hash_ctx = MultipleHashContext { - hash_sha2_256: Sha2_256::new(), - hash_sha2_512: Sha2_512::new(), - hash_sha3_256: Sha3_256::new(), - hash_keccak_256: Keccak256::new(), - hash_ripemd_160: Ripemd160::new(), + let mut extracted = TrustedNameExtracted { + hash_ctx: MultipleHashContext { + hash_sha2_256: Sha2_256::new(), + hash_sha2_512: Sha2_512::new(), + hash_sha3_256: Sha3_256::new(), + hash_keccak_256: Keccak256::new(), + hash_ripemd_160: Ripemd160::new(), + }, + ..TrustedNameExtracted::default() }; let mut received = Received::new(tag_to_flag_u64); diff --git a/ledger_device_sdk/src/ui/bagls.rs b/ledger_device_sdk/src/ui/bagls.rs index c5cf9822..13d48422 100644 --- a/ledger_device_sdk/src/ui/bagls.rs +++ b/ledger_device_sdk/src/ui/bagls.rs @@ -9,6 +9,12 @@ pub struct RectFull { height: u32, } +impl Default for RectFull { + fn default() -> Self { + Self::new() + } +} + impl RectFull { pub const fn new() -> RectFull { RectFull { diff --git a/ledger_device_sdk/src/ui/gadgets.rs b/ledger_device_sdk/src/ui/gadgets.rs index 7fc24810..71805197 100644 --- a/ledger_device_sdk/src/ui/gadgets.rs +++ b/ledger_device_sdk/src/ui/gadgets.rs @@ -730,7 +730,7 @@ impl<'a> Field<'a> { let count_str = page_count.numtoa_str(10, &mut buf_count); concatenate( - &[&self.name, " (", &page_str, "/", &count_str, ")"], + &[self.name, " (", page_str, "/", count_str, ")"], &mut header_buf, ); } @@ -953,20 +953,17 @@ impl<'a> MultiFieldReview<'a> { } fn display_first_page(page_opt: &Option) { - match page_opt { - Some(page) => { - clear_screen(); - RIGHT_ARROW.display(); - page.place(); - crate::ui::screen_util::screen_update(); + if let Some(page) = page_opt { + clear_screen(); + RIGHT_ARROW.display(); + page.place(); + crate::ui::screen_util::screen_update(); - let mut buttons = ButtonsState::new(); - loop { - if let Some(ButtonEvent::RightButtonRelease) = get_event(&mut buttons) { - return; - } + let mut buttons = ButtonsState::new(); + loop { + if let Some(ButtonEvent::RightButtonRelease) = get_event(&mut buttons) { + return; } } - None => (), } } diff --git a/ledger_secure_sdk_sys/build.rs b/ledger_secure_sdk_sys/build.rs index 6b3afa2d..9d15ef7d 100644 --- a/ledger_secure_sdk_sys/build.rs +++ b/ledger_secure_sdk_sys/build.rs @@ -117,7 +117,7 @@ impl SDKBuilder<'_> { // path for Debian-based systems String::from("/usr/lib/arm-none-eabi") } else { - format!("{sysroot}") + sysroot.to_string() }; self.gcc_toolchain = PathBuf::from(gcc_toolchain); Ok(()) @@ -153,7 +153,7 @@ impl SDKBuilder<'_> { v.push((String::from("NBGL_USE_CASE"), None)); } else { println!("cargo:warning=BAGL is built"); - println!("cargo:rustc-env=C_SDK_GRAPHICS={}", "bagl"); + println!("cargo:rustc-env=C_SDK_GRAPHICS=bagl"); v.push((String::from("HAVE_BAGL"), None)); v.push((String::from("HAVE_UX_FLOW"), None)); } @@ -169,7 +169,7 @@ impl SDKBuilder<'_> { let reader = BufReader::new(f); reader .lines() - .filter_map(|line| line.ok()) + .map_while(Result::ok) .collect::>() }, glyphs_folders: Vec::new(), @@ -201,7 +201,7 @@ impl SDKBuilder<'_> { v.push((String::from("NBGL_USE_CASE"), None)); } else { println!("cargo:warning=BAGL is built"); - println!("cargo:rustc-env=C_SDK_GRAPHICS={}", "bagl"); + println!("cargo:rustc-env=C_SDK_GRAPHICS=bagl"); v.push((String::from("HAVE_BAGL"), None)); v.push((String::from("HAVE_UX_FLOW"), None)); } @@ -217,7 +217,7 @@ impl SDKBuilder<'_> { let reader = BufReader::new(f); reader .lines() - .filter_map(|line| line.ok()) + .map_while(Result::ok) .collect::>() }, glyphs_folders: Vec::new(), @@ -251,7 +251,7 @@ impl SDKBuilder<'_> { let reader = BufReader::new(f); reader .lines() - .filter_map(|line| line.ok()) + .map_while(Result::ok) .collect::>() }, glyphs_folders: Vec::new(), @@ -285,7 +285,7 @@ impl SDKBuilder<'_> { let reader = BufReader::new(f); reader .lines() - .filter_map(|line| line.ok()) + .map_while(Result::ok) .collect::>() }, glyphs_folders: Vec::new(), @@ -319,7 +319,7 @@ impl SDKBuilder<'_> { let reader = BufReader::new(f); reader .lines() - .filter_map(|line| line.ok()) + .map_while(Result::ok) .collect::>() }, glyphs_folders: Vec::new(), @@ -691,13 +691,12 @@ impl SDKBuilder<'_> { if entry.is_empty() { continue; } - if let Some((k, v_str)) = entry.split_once(':') { - if k.trim() == target_os { - if let Ok(v) = v_str.trim().parse::() { - selected = Some(v); - break; - } - } + if let Some((k, v_str)) = entry.split_once(':') + && k.trim() == target_os + && let Ok(v) = v_str.trim().parse::() + { + selected = Some(v); + break; } } selected.unwrap_or(DEFAULT_HEAP_SIZE) @@ -803,7 +802,7 @@ fn configure_lib_ble(command: &mut cc::Build, c_sdk: &Path) { } fn configure_lib_nbgl(command: &mut cc::Build, c_sdk: &Path) { - println!("cargo:rustc-env=C_SDK_GRAPHICS={}", "nbgl"); + println!("cargo:rustc-env=C_SDK_GRAPHICS=nbgl"); let glyphs_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("glyphs"); command @@ -848,7 +847,7 @@ fn configure_lib_nbgl(command: &mut cc::Build, c_sdk: &Path) { .file(glyphs_path.join("glyphs.c")); } -fn retrieve_csdk_info(device: &Device, path: &PathBuf) -> Result { +fn retrieve_csdk_info(device: &Device, path: &Path) -> Result { let mut csdk_info = CSDKInfo::new(); (csdk_info.api_level, csdk_info.c_sdk_name) = retrieve_makefile_infos(path)?; (csdk_info.target_id, csdk_info.target_name) = retrieve_target_file_infos(device, path)?; @@ -906,11 +905,12 @@ fn retrieve_makefile_infos(c_sdk: &Path) -> Result<(Option, String), SDKBui let makefile = File::open(c_sdk.join("Makefile.defines")).expect("Could not find Makefile.defines"); let mut api_level: Option = None; - for line in BufReader::new(makefile).lines().flatten() { - if let Some(value) = line.split(":=").nth(1).map(str::trim) { - if line.contains("API_LEVEL") && api_level.is_none() { - api_level = Some(value.parse().map_err(|_| SDKBuildError::InvalidAPILevel)?); - } + for line in BufReader::new(makefile).lines().map_while(Result::ok) { + if let Some(value) = line.split(":=").nth(1).map(str::trim) + && line.contains("API_LEVEL") + && api_level.is_none() + { + api_level = Some(value.parse().map_err(|_| SDKBuildError::InvalidAPILevel)?); } if api_level.is_some() { // Key found, break out of the loop @@ -920,11 +920,12 @@ fn retrieve_makefile_infos(c_sdk: &Path) -> Result<(Option, String), SDKBui let makefile = File::open(c_sdk.join("Makefile.target")).expect("Could not find Makefile.defines"); let mut sdk_name: Option = None; - for line in BufReader::new(makefile).lines().flatten() { - if let Some(value) = line.split(":=").nth(1).map(str::trim) { - if line.contains("SDK_NAME") && sdk_name.is_none() { - sdk_name = Some(value.to_string().replace('\"', "")); - } + for line in BufReader::new(makefile).lines().map_while(Result::ok) { + if let Some(value) = line.split(":=").nth(1).map(str::trim) + && line.contains("SDK_NAME") + && sdk_name.is_none() + { + sdk_name = Some(value.to_string().replace('\"', "")); } if sdk_name.is_some() { // Key found, break out of the loop @@ -947,7 +948,7 @@ fn retrieve_target_file_infos( let mut target_id: Option = None; let mut target_name: Option = None; - for line in BufReader::new(target_file).lines().flatten() { + for line in BufReader::new(target_file).lines().map_while(Result::ok) { if target_id.is_none() && line.contains("#define TARGET_ID") { target_id = Some( line.split_whitespace() diff --git a/ledger_secure_sdk_sys/src/lib.rs b/ledger_secure_sdk_sys/src/lib.rs index 3f65c580..cfd00c82 100644 --- a/ledger_secure_sdk_sys/src/lib.rs +++ b/ledger_secure_sdk_sys/src/lib.rs @@ -3,9 +3,13 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(unnecessary_transmutes)] +#![allow(clippy::useless_transmute)] +#![allow(clippy::missing_safety_doc)] +#![allow(clippy::ptr_offset_with_cast)] +#![allow(clippy::too_many_arguments)] use core::ffi::c_void; -#[cfg(all(feature = "heap"))] +#[cfg(feature = "heap")] use core::mem::MaybeUninit; pub mod buttons; @@ -53,9 +57,7 @@ critical_section::set_impl!(CriticalSection); /// Default no-op implementation as we don't have concurrency. #[cfg(feature = "heap")] unsafe impl critical_section::Impl for CriticalSection { - unsafe fn acquire() -> RawRestoreState { - () - } + unsafe fn acquire() -> RawRestoreState {} unsafe fn release(_restore_state: RawRestoreState) {} } From ea0e5367099031646c8d710ee04a619577f12ffe Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 29 Apr 2026 13:54:04 +0200 Subject: [PATCH 08/13] Trigger CI on every PR or push --- .github/workflows/ci.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a73df21..fe94b93e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,13 +2,7 @@ name: Run cargo clippy, cargo fmt, build and Unit+Integration tests on: push: - branches: - - develop - - master pull_request: - branches: - - master - - develop workflow_dispatch: inputs: name: From 0543490c2b28be5c8321f7d49b6efa85ef7b93f9 Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 29 Apr 2026 14:51:50 +0200 Subject: [PATCH 09/13] Promotes any clippy warning to error --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe94b93e..d9e65cd4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: - name: Cargo clippy working-directory: ${{ matrix.package }} run: | - cargo clippy --target ${{ matrix.target }} + cargo clippy --target ${{ matrix.target }} -- -D warnings format: name: Check code formatting From 9d97131b47c5cc6f5a89ecddf17efcfe6c7aa6a9 Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 29 Apr 2026 16:10:59 +0200 Subject: [PATCH 10/13] Fixes after Copilot review --- ledger_device_sdk/src/nbgl/nbgl_keypad.rs | 17 +++++++++++---- ledger_secure_sdk_sys/build.rs | 25 +++++++++++++++-------- ledger_secure_sdk_sys/src/lib.rs | 24 ++++++++++++++-------- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/ledger_device_sdk/src/nbgl/nbgl_keypad.rs b/ledger_device_sdk/src/nbgl/nbgl_keypad.rs index e23e2878..5f689c4f 100644 --- a/ledger_device_sdk/src/nbgl/nbgl_keypad.rs +++ b/ledger_device_sdk/src/nbgl/nbgl_keypad.rs @@ -24,10 +24,19 @@ impl Default for NbglKeypad { const PIN_BUFFER_SIZE: usize = 16; static PIN_BUFFER_PTR: AtomicPtr = AtomicPtr::new(core::ptr::null_mut()); +// RAII guard: clears PIN_BUFFER_PTR when dropped, even on early return or panic. +struct PinBufferGuard; + +impl Drop for PinBufferGuard { + fn drop(&mut self) { + PIN_BUFFER_PTR.store(core::ptr::null_mut(), Ordering::Release); + } +} + unsafe extern "C" fn pin_callback(pin: *const u8, pin_len: u8) { unsafe { let len = (pin_len as usize).min(PIN_BUFFER_SIZE); - let buf = PIN_BUFFER_PTR.load(Ordering::Relaxed); + let buf = PIN_BUFFER_PTR.load(Ordering::Acquire); if !buf.is_null() { core::ptr::copy_nonoverlapping(pin, buf, len); } @@ -117,7 +126,8 @@ impl NbglKeypad { fn ask_internal(self, pin: &[u8]) -> SyncNbgl { unsafe { let mut buffer = [0u8; PIN_BUFFER_SIZE]; - PIN_BUFFER_PTR.store(buffer.as_mut_ptr(), Ordering::Relaxed); + PIN_BUFFER_PTR.store(buffer.as_mut_ptr(), Ordering::Release); + let _guard = PinBufferGuard; self.ux_sync_init(); nbgl_useCaseKeypad( @@ -130,9 +140,8 @@ impl NbglKeypad { Some(action_callback), ); self.ux_sync_wait(false); - PIN_BUFFER_PTR.store(core::ptr::null_mut(), Ordering::Relaxed); - // Compare with set pin code + // Compare with set pin code (_guard clears PIN_BUFFER_PTR on drop below) if pin == &buffer[..pin.len()] { SyncNbgl::UxSyncRetPinValidated } else { diff --git a/ledger_secure_sdk_sys/build.rs b/ledger_secure_sdk_sys/build.rs index 9d15ef7d..498ae67a 100644 --- a/ledger_secure_sdk_sys/build.rs +++ b/ledger_secure_sdk_sys/build.rs @@ -169,7 +169,7 @@ impl SDKBuilder<'_> { let reader = BufReader::new(f); reader .lines() - .map_while(Result::ok) + .map(|l| l.expect("Failed to read line")) .collect::>() }, glyphs_folders: Vec::new(), @@ -217,7 +217,7 @@ impl SDKBuilder<'_> { let reader = BufReader::new(f); reader .lines() - .map_while(Result::ok) + .map(|l| l.expect("Failed to read line")) .collect::>() }, glyphs_folders: Vec::new(), @@ -251,7 +251,7 @@ impl SDKBuilder<'_> { let reader = BufReader::new(f); reader .lines() - .map_while(Result::ok) + .map(|l| l.expect("Failed to read line")) .collect::>() }, glyphs_folders: Vec::new(), @@ -285,7 +285,7 @@ impl SDKBuilder<'_> { let reader = BufReader::new(f); reader .lines() - .map_while(Result::ok) + .map(|l| l.expect("Failed to read line")) .collect::>() }, glyphs_folders: Vec::new(), @@ -319,7 +319,7 @@ impl SDKBuilder<'_> { let reader = BufReader::new(f); reader .lines() - .map_while(Result::ok) + .map(|l| l.expect("Failed to read line")) .collect::>() }, glyphs_folders: Vec::new(), @@ -905,7 +905,10 @@ fn retrieve_makefile_infos(c_sdk: &Path) -> Result<(Option, String), SDKBui let makefile = File::open(c_sdk.join("Makefile.defines")).expect("Could not find Makefile.defines"); let mut api_level: Option = None; - for line in BufReader::new(makefile).lines().map_while(Result::ok) { + for line in BufReader::new(makefile) + .lines() + .map(|l| l.expect("Failed to read line")) + { if let Some(value) = line.split(":=").nth(1).map(str::trim) && line.contains("API_LEVEL") && api_level.is_none() @@ -920,7 +923,10 @@ fn retrieve_makefile_infos(c_sdk: &Path) -> Result<(Option, String), SDKBui let makefile = File::open(c_sdk.join("Makefile.target")).expect("Could not find Makefile.defines"); let mut sdk_name: Option = None; - for line in BufReader::new(makefile).lines().map_while(Result::ok) { + for line in BufReader::new(makefile) + .lines() + .map(|l| l.expect("Failed to read line")) + { if let Some(value) = line.split(":=").nth(1).map(str::trim) && line.contains("SDK_NAME") && sdk_name.is_none() @@ -948,7 +954,10 @@ fn retrieve_target_file_infos( let mut target_id: Option = None; let mut target_name: Option = None; - for line in BufReader::new(target_file).lines().map_while(Result::ok) { + for line in BufReader::new(target_file) + .lines() + .map(|l| l.expect("Failed to read line")) + { if target_id.is_none() && line.contains("#define TARGET_ID") { target_id = Some( line.split_whitespace() diff --git a/ledger_secure_sdk_sys/src/lib.rs b/ledger_secure_sdk_sys/src/lib.rs index cfd00c82..18976e63 100644 --- a/ledger_secure_sdk_sys/src/lib.rs +++ b/ledger_secure_sdk_sys/src/lib.rs @@ -1,12 +1,4 @@ #![no_std] -#![allow(non_upper_case_globals)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(unnecessary_transmutes)] -#![allow(clippy::useless_transmute)] -#![allow(clippy::missing_safety_doc)] -#![allow(clippy::ptr_offset_with_cast)] -#![allow(clippy::too_many_arguments)] use core::ffi::c_void; #[cfg(feature = "heap")] @@ -77,5 +69,19 @@ extern "C" fn heap_init() { #[cfg(not(feature = "heap"))] extern "C" fn heap_init() {} -include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +// Scope all bindgen-generated lint suppressions to the generated code only, +// so clippy remains effective on the hand-written code above. +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(non_snake_case)] +#[allow(unnecessary_transmutes)] +#[allow(clippy::useless_transmute)] +#[allow(clippy::missing_safety_doc)] +#[allow(clippy::ptr_offset_with_cast)] +#[allow(clippy::too_many_arguments)] +mod bindings { + include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +} +pub use bindings::*; + include!(concat!(env!("OUT_DIR"), "/heap_size.rs")); From 34de78cf33a89a33ee9100c035def9e2fcc6947a Mon Sep 17 00:00:00 2001 From: GroM Date: Thu, 30 Apr 2026 16:45:42 +0200 Subject: [PATCH 11/13] Revert "Use ledgerblue-support cargo-ledger" This reverts commit 1a03d6933f36f5eb87e9bb2d392ef78d023c5020. --- .github/workflows/reusable_build_all_apps.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/reusable_build_all_apps.yml b/.github/workflows/reusable_build_all_apps.yml index cf496fde..f27865ec 100644 --- a/.github/workflows/reusable_build_all_apps.yml +++ b/.github/workflows/reusable_build_all_apps.yml @@ -118,9 +118,6 @@ jobs: echo "Cargo.toml:" cat $cargo_toml_path - - name: Install test cargo-ledger - run: cargo install --git https://github.com/LedgerHQ/cargo-ledger --branch y333/ledgerblue_support --force cargo-ledger - - name: Build shell: bash run: | From 5087a65e0602b24b7b21414599ce41cd5a0e6595 Mon Sep 17 00:00:00 2001 From: GroM Date: Thu, 30 Apr 2026 17:00:25 +0200 Subject: [PATCH 12/13] Bump versions --- Cargo.lock | 6 +++--- include_gif/CHANGELOG.md | 5 +++++ include_gif/Cargo.toml | 2 +- ledger_device_sdk/CHANGELOG.md | 6 ++++++ ledger_device_sdk/Cargo.toml | 6 +++--- ledger_secure_sdk_sys/CHANGELOG.md | 6 ++++++ ledger_secure_sdk_sys/Cargo.toml | 2 +- 7 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5c2ab91b..33edb6ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -198,7 +198,7 @@ dependencies = [ [[package]] name = "include_gif" -version = "1.3.0" +version = "1.3.1" dependencies = [ "flate2", "image", @@ -222,7 +222,7 @@ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "ledger_device_sdk" -version = "1.35.0" +version = "1.35.1" dependencies = [ "const-zero", "include_gif", @@ -238,7 +238,7 @@ dependencies = [ [[package]] name = "ledger_secure_sdk_sys" -version = "1.16.0" +version = "1.16.1" dependencies = [ "bindgen", "cc", diff --git a/include_gif/CHANGELOG.md b/include_gif/CHANGELOG.md index 5e14d9fb..e5378fab 100644 --- a/include_gif/CHANGELOG.md +++ b/include_gif/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.3.1] - 2026-04-30 + +### Changed + - Fix clippy warnings + ## [1.3.0] - 2026-04-24 ### Changed diff --git a/include_gif/Cargo.toml b/include_gif/Cargo.toml index 4d207da0..2fcba1f3 100644 --- a/include_gif/Cargo.toml +++ b/include_gif/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "include_gif" -version = "1.3.0" +version = "1.3.1" edition = "2024" license.workspace = true repository.workspace = true diff --git a/ledger_device_sdk/CHANGELOG.md b/ledger_device_sdk/CHANGELOG.md index c8fe6204..8cf9601d 100644 --- a/ledger_device_sdk/CHANGELOG.md +++ b/ledger_device_sdk/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.35.1] - 2026-04-30 + +### Changed + - Fix clippy warnings + - Embed icon in install_params + ## [1.35.0] - 2026-04-24 ### Changed diff --git a/ledger_device_sdk/Cargo.toml b/ledger_device_sdk/Cargo.toml index fc365c8d..0aecbd04 100644 --- a/ledger_device_sdk/Cargo.toml +++ b/ledger_device_sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ledger_device_sdk" -version = "1.35.0" +version = "1.35.1" authors = ["Ledger"] edition = "2024" license.workspace = true @@ -17,13 +17,13 @@ ledger_device_sdk = { path = ".", features = ["unit_test"] } testmacro = { path = "../testmacro"} [dependencies] -include_gif = { path = "../include_gif", version = "1.3.0" } +include_gif = { path = "../include_gif", version = "1.3.1" } num-traits = { version = "0.2.14", default-features = false } rand_core = { version = "0.6.3", default-features = false } zeroize = { version = "1.6.0", default-features = false } numtoa = "0.2.4" const-zero = "0.1.1" -ledger_secure_sdk_sys = { path = "../ledger_secure_sdk_sys", version = "1.16.0" } +ledger_secure_sdk_sys = { path = "../ledger_secure_sdk_sys", version = "1.16.1" } [features] debug = ["log_error"] diff --git a/ledger_secure_sdk_sys/CHANGELOG.md b/ledger_secure_sdk_sys/CHANGELOG.md index ae80135c..b6b93aef 100644 --- a/ledger_secure_sdk_sys/CHANGELOG.md +++ b/ledger_secure_sdk_sys/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.16.1] - 2026-04-30 + +### Changed + - Fix clippy warnings + - Update linker script + ## [1.16.0] - 2026-04-24 ### Changed diff --git a/ledger_secure_sdk_sys/Cargo.toml b/ledger_secure_sdk_sys/Cargo.toml index fa415124..4473cd77 100644 --- a/ledger_secure_sdk_sys/Cargo.toml +++ b/ledger_secure_sdk_sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ledger_secure_sdk_sys" -version = "1.16.0" +version = "1.16.1" authors = ["Ledger"] edition = "2024" license.workspace = true From 201da822175bdbb8339c0b01d3fb238c84c0835f Mon Sep 17 00:00:00 2001 From: GroM Date: Thu, 30 Apr 2026 17:24:41 +0200 Subject: [PATCH 13/13] Update publish workflow --- .github/workflows/publish.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7aa779c3..6108ac49 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -45,10 +45,7 @@ jobs: package_directory: "include_gif" publish: true release: false - jfrog_deployment: true dry_run: ${{ github.event_name == 'workflow_dispatch' }} - secrets: - cargo_token: ${{ secrets.CARGO_CRATES_TOKEN }} deploy_ledger_secure_sdk_sys: name: Deploy ledger_secure_sdk_sys @@ -62,10 +59,7 @@ jobs: package_directory: "ledger_secure_sdk_sys" publish: true release: false - jfrog_deployment: true dry_run: ${{ github.event_name == 'workflow_dispatch' }} - secrets: - cargo_token: ${{ secrets.CARGO_CRATES_TOKEN }} deploy_ledger_device_sdk: name: Deploy ledger_device_sdk @@ -79,7 +73,4 @@ jobs: package_directory: "ledger_device_sdk" publish: true release: false - jfrog_deployment: true dry_run: ${{ github.event_name == 'workflow_dispatch' }} - secrets: - cargo_token: ${{ secrets.CARGO_CRATES_TOKEN }}