Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -41,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
Expand Down
9 changes: 0 additions & 9 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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 }}
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions include_gif/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion include_gif/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "include_gif"
version = "1.3.0"
version = "1.3.1"
edition = "2024"
license.workspace = true
repository.workspace = true
Expand Down
8 changes: 4 additions & 4 deletions include_gif/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ fn image_to_packed_buffer(frame: &mut GrayImage, invert: bool) -> (Vec<u8>, 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<u8> = Vec::new();

for x in (0..width).rev() {
Expand All @@ -180,14 +180,14 @@ fn image_to_packed_buffer(frame: &mut GrayImage, invert: bool) -> (Vec<u8>, 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)
}
Expand Down
6 changes: 6 additions & 0 deletions ledger_device_sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions ledger_device_sdk/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ledger_device_sdk"
version = "1.35.0"
version = "1.35.1"
authors = ["Ledger"]
edition = "2024"
license.workspace = true
Expand All @@ -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"]
Expand Down
105 changes: 93 additions & 12 deletions ledger_device_sdk/build.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -20,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");

Expand Down Expand Up @@ -61,15 +65,15 @@ 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::<Vec<_>>();
println!("cargo:warning=curves are {:x?}", curves);

let paths = metadata_ledger["path"]
.as_array()
.expect("paths not found")
.iter()
.map(|v| format!("{}", v.as_str().unwrap()))
.map(|v| v.as_str().unwrap().to_string())
.collect::<Vec<_>>();
println!("cargo:warning=paths are {:x?}", paths);

Expand All @@ -89,16 +93,35 @@ 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
.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);
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")
Expand All @@ -116,6 +139,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");
Expand Down Expand Up @@ -197,6 +224,60 @@ 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" => "NANOSP_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("python3");
cmd.arg(&icon2glyph);
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()
);
}
std::fs::read_to_string(&icon_hex_file)
.expect("Failed to read icon hex file")
.trim()
.to_string()
}

fn main() {
println!("cargo:rerun-if-changed=Cargo.toml");
generate_install_parameters();
Expand Down
1 change: 1 addition & 0 deletions ledger_device_sdk/src/ecc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ impl<const N: usize, const TY: char> ECPrivateKey<N, TY> {
#[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());
Expand Down
1 change: 1 addition & 0 deletions ledger_device_sdk/src/ecc/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<bool, CxError> {
let mut is_equal = false;
check_cx_ok!(cx_ecpoint_cmp(&self.inner, &other.inner, &mut is_equal));
Expand Down
6 changes: 4 additions & 2 deletions ledger_device_sdk/src/io_callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
}
Expand Down
Loading
Loading