Skip to content

Commit

Permalink
Add Stax support
Browse files Browse the repository at this point in the history
  • Loading branch information
agrojean-ledger committed Feb 22, 2024
1 parent 45b68d5 commit b85a864
Show file tree
Hide file tree
Showing 35 changed files with 150 additions and 72 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ serde-json-core = { git = "https://github.com/rust-embedded-community/serde-json
hex = { version = "0.4.3", default-features = false, features = ["serde"] }
numtoa = "0.2.4"

[patch.crates-io]
ledger_device_sdk = { path = 'ledger-device-rust-sdk/ledger_device_sdk' }
ledger_secure_sdk_sys = { path = 'ledger-device-rust-sdk/ledger_secure_sdk_sys' }

[profile.release]
opt-level = 'z'
lto = true
Expand Down
2 changes: 1 addition & 1 deletion ledger_app.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[app]
build_directory = "./"
sdk = "Rust"
devices = ["nanos", "nanox", "nanos+"]
devices = ["nanos", "nanox", "nanos+", "stax"]

[tests]
pytest_directory = "./tests/"
47 changes: 31 additions & 16 deletions src/app_ui/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@

use crate::AppSW;
use core::str::from_utf8_mut;

#[cfg(not(target_os = "stax"))]
use ledger_device_sdk::ui::bitmaps::{CROSSMARK, EYE, VALIDATE_14};
#[cfg(not(target_os = "stax"))]
use ledger_device_sdk::ui::gadgets::{Field, MultiFieldReview};

#[cfg(target_os = "stax")]
use ledger_device_sdk::nbgl::NbglAddressConfirm;

// Display only the last 20 bytes of the address
const DISPLAY_ADDR_BYTES_LEN: usize = 20;

Expand All @@ -34,20 +40,29 @@ pub fn ui_display_pk(addr: &[u8]) -> Result<bool, AppSW> {
let addr_hex = from_utf8_mut(&mut addr_hex).unwrap();
addr_hex[2..].make_ascii_uppercase();

let my_field = [Field {
name: "Address",
value: addr_hex,
}];

let my_review = MultiFieldReview::new(
&my_field,
&["Confirm Address"],
Some(&EYE),
"Approve",
Some(&VALIDATE_14),
"Reject",
Some(&CROSSMARK),
);

Ok(my_review.show())
#[cfg(not(target_os = "stax"))]
{
let my_field = [Field {
name: "Address",
value: addr_hex,
}];

let my_review = MultiFieldReview::new(
&my_field,
&["Confirm Address"],
Some(&EYE),
"Approve",
Some(&VALIDATE_14),
"Reject",
Some(&CROSSMARK),
);

Ok(my_review.show())
}

#[cfg(target_os = "stax")]
{
Ok(NbglAddressConfirm.verify_address(addr_hex))
}

}
59 changes: 59 additions & 0 deletions src/app_ui/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,20 @@

use include_gif::include_gif;
use ledger_device_sdk::io::{Comm, Event};

#[cfg(not(target_os = "stax"))]
use ledger_device_sdk::ui::bitmaps::{Glyph, BACK, CERTIFICATE, DASHBOARD_X};
#[cfg(not(target_os = "stax"))]
use ledger_device_sdk::ui::gadgets::{EventOrPageIndex, MultiPageMenu, Page};

#[cfg(target_os = "stax")]
use ledger_device_sdk::nbgl::NbglHome;


use crate::Instruction;


#[cfg(not(target_os = "stax"))]
fn ui_about_menu(comm: &mut Comm) -> Event<Instruction> {
let pages = [
&Page::from((["Rust Boilerplate", "(c) 2023 Ledger"], true)),
Expand All @@ -36,6 +45,7 @@ fn ui_about_menu(comm: &mut Comm) -> Event<Instruction> {
}
}

#[cfg(not(target_os = "stax"))]
pub fn ui_menu_main(comm: &mut Comm) -> Event<Instruction> {
const APP_ICON: Glyph = Glyph::from_include(include_gif!("crab.gif"));
let pages = [
Expand All @@ -55,3 +65,52 @@ pub fn ui_menu_main(comm: &mut Comm) -> Event<Instruction> {
}
}
}

#[cfg(target_os = "stax")]
pub fn ui_menu_main(comm: &mut Comm) -> Event<Instruction> {
NbglHome::new(comm)
.app_name("Boilerplate\0")
.info_contents(env!("CARGO_PKG_VERSION"), env!("CARGO_PKG_AUTHORS"))
.icon(&BTC_BMP)
.show_home()
}

#[cfg(target_os = "stax")]
const BTC_BMP: [u8; 573] = [
0x40, 0x00, 0x40, 0x00, 0x21, 0x35, 0x02, 0x00, 0x33, 0x02, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0xff, 0xbd, 0x55, 0xb9, 0x4e, 0x23, 0x41, 0x10, 0x6d, 0x7b, 0x3c, 0x5c, 0x46,
0x5e, 0x2f, 0x96, 0x20, 0xc3, 0x10, 0x5b, 0x82, 0xdd, 0x6c, 0x1d, 0x2d, 0x64, 0x10, 0x81, 0x88,
0x10, 0x01, 0x87, 0x03, 0x02, 0x84, 0x38, 0x02, 0x62, 0x90, 0x58, 0x44, 0xb0, 0x01, 0xbb, 0xf0,
0x01, 0x26, 0xd9, 0x68, 0x03, 0x10, 0x1f, 0x00, 0xa4, 0x44, 0xfc, 0x02, 0x26, 0x34, 0x88, 0xe1,
0x32, 0x87, 0x8d, 0xa6, 0xe8, 0xee, 0xa9, 0x3e, 0xa6, 0xa7, 0x6d, 0x13, 0x51, 0xc1, 0xa8, 0x67,
0x5e, 0x4f, 0xd7, 0xab, 0xaa, 0x57, 0xd5, 0x00, 0x9f, 0x67, 0x57, 0x5b, 0xfd, 0x84, 0x64, 0x46,
0x4e, 0xec, 0xa8, 0xbf, 0x99, 0x26, 0x81, 0xe5, 0x3d, 0x0b, 0x5c, 0x9b, 0x23, 0xd2, 0xdc, 0xe8,
0x06, 0x7f, 0x88, 0x90, 0x46, 0x1b, 0x56, 0x49, 0xc8, 0x5a, 0x0d, 0xf8, 0x92, 0x18, 0xd6, 0x1b,
0x82, 0x5f, 0xd3, 0x26, 0x1e, 0x2b, 0xea, 0xf8, 0x0a, 0x89, 0x98, 0xee, 0xe1, 0x99, 0x58, 0x6c,
0xbd, 0xe1, 0xef, 0xfa, 0x01, 0x2f, 0xc4, 0x6a, 0x92, 0x41, 0xc9, 0x8e, 0xcb, 0x10, 0xd2, 0x76,
0x3c, 0xde, 0x88, 0x9d, 0xc6, 0xf0, 0xa2, 0x1e, 0x8e, 0x0e, 0xc6, 0xeb, 0xe1, 0x89, 0xa0, 0x32,
0xf2, 0x3d, 0x7f, 0xfd, 0x8f, 0x3e, 0xbf, 0x2a, 0x3a, 0x5c, 0x09, 0x15, 0x3d, 0xe0, 0x12, 0xc9,
0x81, 0xff, 0x57, 0x7c, 0x59, 0x0e, 0xb9, 0x67, 0x74, 0x6a, 0x09, 0x3d, 0x5f, 0x9c, 0xc0, 0x1f,
0x51, 0x11, 0xee, 0x6d, 0x5a, 0x8f, 0xa8, 0x8d, 0xbd, 0x7c, 0xc3, 0x97, 0x76, 0xad, 0x20, 0xf8,
0xcd, 0x61, 0xeb, 0xc0, 0xf7, 0x04, 0xc9, 0x6a, 0xf8, 0x06, 0x1e, 0x49, 0x65, 0x54, 0xe3, 0xab,
0x14, 0x94, 0x8b, 0xe0, 0xcf, 0x9f, 0x43, 0x38, 0x25, 0x27, 0xa2, 0x38, 0x3f, 0x83, 0x3a, 0x74,
0xd0, 0x70, 0xd7, 0x68, 0x5d, 0x6e, 0x11, 0xdf, 0x01, 0x78, 0xe4, 0x8b, 0x9c, 0xc7, 0xeb, 0xe0,
0xb0, 0x4d, 0xae, 0xc2, 0x67, 0x00, 0x1e, 0x90, 0xca, 0x22, 0xf7, 0x04, 0x40, 0x75, 0xec, 0x49,
0x7c, 0x10, 0xe0, 0x4e, 0xc6, 0xc2, 0x12, 0xc5, 0x37, 0x15, 0xa5, 0xff, 0x2c, 0x1e, 0xe5, 0x9c,
0x0d, 0x77, 0xc2, 0x3d, 0x2b, 0x69, 0x85, 0xe3, 0x87, 0x88, 0x7f, 0x41, 0xbc, 0x05, 0xe0, 0x9c,
0xfd, 0x94, 0xe0, 0xc7, 0x1d, 0xc0, 0x91, 0x81, 0x27, 0x19, 0xfd, 0x6a, 0x81, 0x3a, 0x39, 0x0d,
0xa2, 0x2a, 0x17, 0x42, 0xb8, 0xf3, 0x9b, 0x87, 0x5d, 0x5e, 0xe2, 0x99, 0x61, 0xb1, 0x54, 0x05,
0x8e, 0xfc, 0x32, 0xd8, 0x71, 0xbb, 0x8c, 0x84, 0xef, 0xc1, 0x93, 0xe0, 0x77, 0x8f, 0xae, 0x44,
0x47, 0x96, 0x0b, 0xad, 0x50, 0x8d, 0x2f, 0x5c, 0x8a, 0xb4, 0x55, 0xc2, 0x62, 0xa4, 0x76, 0xa3,
0x24, 0x31, 0x26, 0xc5, 0xef, 0xea, 0xed, 0x56, 0x1d, 0x56, 0xf9, 0x0d, 0xea, 0x43, 0x33, 0xff,
0x10, 0x5f, 0x50, 0x5d, 0x7f, 0xd6, 0x27, 0xea, 0xe3, 0xa7, 0xb1, 0x80, 0xfb, 0xd4, 0xc9, 0x94,
0xdc, 0x11, 0xe0, 0x4a, 0x0b, 0x59, 0x98, 0xe5, 0x34, 0xf8, 0x19, 0xff, 0x51, 0xb4, 0x8e, 0xd2,
0x42, 0x6c, 0x14, 0x65, 0x1b, 0x5f, 0xa2, 0x85, 0xcc, 0x6c, 0x2b, 0x49, 0x95, 0x22, 0xaa, 0x7f,
0x13, 0xcb, 0x14, 0xc3, 0x9f, 0x0c, 0xbc, 0x45, 0xf5, 0xf3, 0x0c, 0x1f, 0x6c, 0x06, 0x9e, 0x44,
0xc9, 0xc8, 0x9c, 0x0d, 0x19, 0x73, 0xc1, 0x13, 0x92, 0x70, 0xed, 0xed, 0xef, 0xee, 0xeb, 0xee,
0x9b, 0xf7, 0x37, 0xe6, 0x22, 0x62, 0xb1, 0x8f, 0xce, 0x97, 0x57, 0x3b, 0xbe, 0xf3, 0xd1, 0xf9,
0xd6, 0x74, 0x3e, 0x36, 0x9b, 0xaf, 0xf0, 0xd2, 0x64, 0x3e, 0x47, 0x43, 0x18, 0x30, 0x2e, 0x00,
0xc3, 0x43, 0x4f, 0xe4, 0x7e, 0x09, 0x4d, 0xb9, 0x84, 0xe5, 0x02, 0xd2, 0x36, 0x74, 0xdb, 0xae,
0x38, 0x7f, 0x4f, 0x50, 0xfb, 0xe1, 0xd9, 0x6f, 0xc0, 0xda, 0xaf, 0xef, 0x84, 0x74, 0x4d, 0x1e,
0x7f, 0xe2, 0x95, 0x0c, 0xef, 0xe7, 0x7f, 0x81, 0xae, 0x00, 0x08, 0x00, 0x00,
];
36 changes: 26 additions & 10 deletions src/app_ui/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@
use crate::handlers::sign_tx::Tx;
use crate::utils::concatenate;
use crate::AppSW;

#[cfg(not(target_os = "stax"))]
use ledger_device_sdk::ui::bitmaps::{CROSSMARK, EYE, VALIDATE_14};
#[cfg(not(target_os = "stax"))]
use ledger_device_sdk::ui::gadgets::{Field, MultiFieldReview};

#[cfg(target_os = "stax")]
use ledger_device_sdk::nbgl::{Field, NbglReview};

use numtoa::NumToA;

const MAX_COIN_LENGTH: usize = 10;
Expand Down Expand Up @@ -64,15 +71,24 @@ pub fn ui_display_tx(tx: &Tx) -> Result<bool, AppSW> {
];

// Create transaction review
let my_review = MultiFieldReview::new(
&my_fields,
&["Review ", "Transaction"],
Some(&EYE),
"Approve",
Some(&VALIDATE_14),
"Reject",
Some(&CROSSMARK),
);
#[cfg(not(target_os = "stax"))]
{
let my_review = MultiFieldReview::new(
&my_fields,
&["Review ", "Transaction"],
Some(&EYE),
"Approve",
Some(&VALIDATE_14),
"Reject",
Some(&CROSSMARK),
);

Ok(my_review.show())
}

#[cfg(target_os = "stax")]
{
Ok(NbglReview.review_transaction(&my_fields))
}

Ok(my_review.show())
}
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use handlers::{
};
use ledger_device_sdk::io::{ApduHeader, Comm, Event, Reply, StatusWords};
#[cfg(feature = "pending_review_screen")]
#[cfg(not(target_os = "stax"))]
use ledger_device_sdk::ui::gadgets::display_pending_review;

ledger_device_sdk::set_panic!(ledger_device_sdk::exiting_panic);
Expand Down Expand Up @@ -127,6 +128,7 @@ extern "C" fn sample_main() {
// Developer mode / pending review popup
// must be cleared with user interaction
#[cfg(feature = "pending_review_screen")]
#[cfg(not(target_os = "stax"))]
display_pending_review(&mut comm);

let mut tx_ctx = TxContext::new();
Expand Down
8 changes: 2 additions & 6 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,10 @@
# ragger/conftest/configuration.py
@pytest.fixture(scope="class", autouse=True)
def clear_pending_review(firmware, navigator):
print("Clearing pending review")
# Press a button to clear the pending review
if firmware.device.startswith("nano"):
print("Clearing pending review")
instructions = [
NavInsID.BOTH_CLICK,
]
else:
instructions = [
NavInsID.TAPPABLE_CENTER_TAP,
]
navigator.navigate(instructions,screen_change_before_first_instruction=False)
navigator.navigate(instructions,screen_change_before_first_instruction=False)
Binary file added tests/snapshots/stax/test_app_mainmenu/00000.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/stax/test_app_mainmenu/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/stax/test_app_mainmenu/00002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 12 additions & 22 deletions tests/test_pubkey_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,8 @@ def test_get_public_key_confirm_accepted(firmware, backend, navigator, test_name
else:
instructions = [
NavInsID.USE_CASE_REVIEW_TAP,
NavIns(NavInsID.TOUCH, (200, 335)),
NavInsID.USE_CASE_ADDRESS_CONFIRMATION_EXIT_QR,
NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CONFIRM,
NavInsID.USE_CASE_STATUS_DISMISS
NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CONFIRM
# NavInsID.USE_CASE_STATUS_DISMISS
]
navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH,
test_name,
Expand Down Expand Up @@ -65,23 +63,15 @@ def test_get_public_key_confirm_refused(firmware, backend, navigator, test_name)
assert e.value.status == Errors.SW_DENY
assert len(e.value.data) == 0
else:
instructions_set = [
[
NavInsID.USE_CASE_REVIEW_REJECT,
NavInsID.USE_CASE_STATUS_DISMISS
],
[
instructions = [
NavInsID.USE_CASE_REVIEW_TAP,
NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CANCEL,
NavInsID.USE_CASE_STATUS_DISMISS
]
NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CANCEL
]
for i, instructions in enumerate(instructions_set):
with pytest.raises(ExceptionRAPDU) as e:
with client.get_public_key_with_confirmation(path=path):
navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH,
test_name + f"/part{i}",
instructions)
# Assert that we have received a refusal
assert e.value.status == Errors.SW_DENY
assert len(e.value.data) == 0
with pytest.raises(ExceptionRAPDU) as e:
with client.get_public_key_with_confirmation(path=path):
navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH,
test_name,
instructions)
# Assert that we have received a refusal
assert e.value.status == Errors.SW_DENY
assert len(e.value.data) == 0
30 changes: 13 additions & 17 deletions tests/test_sign_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ def test_sign_tx_short_tx(firmware, backend, navigator, test_name):
test_name)
else:
navigator.navigate_until_text_and_compare(NavInsID.USE_CASE_REVIEW_TAP,
[NavInsID.USE_CASE_REVIEW_CONFIRM,
NavInsID.USE_CASE_STATUS_DISMISS],
[NavInsID.USE_CASE_REVIEW_CONFIRM],
"Hold to sign",
ROOT_SCREENSHOT_PATH,
test_name)
Expand Down Expand Up @@ -89,8 +88,7 @@ def test_sign_tx_long_tx(firmware, backend, navigator, test_name):
test_name)
else:
navigator.navigate_until_text_and_compare(NavInsID.USE_CASE_REVIEW_TAP,
[NavInsID.USE_CASE_REVIEW_CONFIRM,
NavInsID.USE_CASE_STATUS_DISMISS],
[NavInsID.USE_CASE_REVIEW_CONFIRM],
"Hold to sign",
ROOT_SCREENSHOT_PATH,
test_name)
Expand Down Expand Up @@ -130,16 +128,14 @@ def test_sign_tx_refused(firmware, backend, navigator, test_name):
assert e.value.status == Errors.SW_DENY
assert len(e.value.data) == 0
else:
for i in range(3):
instructions = [NavInsID.USE_CASE_REVIEW_TAP] * i
instructions += [NavInsID.USE_CASE_REVIEW_REJECT,
NavInsID.USE_CASE_CHOICE_CONFIRM,
NavInsID.USE_CASE_STATUS_DISMISS]
with pytest.raises(ExceptionRAPDU) as e:
with client.sign_tx(path=path, transaction=transaction):
navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH,
test_name + f"/part{i}",
instructions)
# Assert that we have received a refusal
assert e.value.status == Errors.SW_DENY
assert len(e.value.data) == 0
instructions = [NavInsID.USE_CASE_REVIEW_TAP,
NavInsID.USE_CASE_REVIEW_TAP,
NavInsID.USE_CASE_REVIEW_REJECT]
with pytest.raises(ExceptionRAPDU) as e:
with client.sign_tx(path=path, transaction=transaction):
navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH,
test_name,
instructions)
# Assert that we have received a refusal
assert e.value.status == Errors.SW_DENY
assert len(e.value.data) == 0

0 comments on commit b85a864

Please sign in to comment.