Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use of heap feature for simpler code #58

Merged
merged 5 commits into from
Jun 12, 2024
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
2 changes: 1 addition & 1 deletion .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ runner = "speculos -a=1 --model=nanosp"
target = "nanosplus"

[unstable]
build-std = ["core"]
build-std = ["core", "alloc"]
build-std-features = ["compiler-builtins-mem"]
42 changes: 33 additions & 9 deletions Cargo.lock

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

11 changes: 4 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
[package]
name = "app-boilerplate-rust"
version = "1.3.0"
version = "1.4.0"
authors = ["yhql", "agrojean-ledger"]
edition = "2021"

[dependencies]
ledger_device_sdk = "1.9.2"
ledger_device_sdk = { version="1.10.1", features = ["heap"] }
include_gif = "1.1.0"
serde = {version="1.0.192", default_features = false, features = ["derive"]}
serde-json-core = { git = "https://github.com/rust-embedded-community/serde-json-core"}
hex = { version = "0.4.3", default-features = false, features = ["serde"] }
hex = { version = "0.4.3", default-features = false, features = ["serde", "alloc"] }
numtoa = "0.2.4"

[profile.release]
Expand All @@ -26,9 +26,6 @@ flags = "0"
path = ["44'/1'"]
name = "Rust Boilerplate"

[package.metadata.ledger.nanos]
icon = "crab.gif"

[package.metadata.ledger.nanox]
icon = "crab_14x14.gif"

Expand All @@ -39,4 +36,4 @@ icon = "crab_14x14.gif"
icon = "crab_32x32.gif"

[package.metadata.ledger.flex]
icon = "crab_40x40.gif"
icon = "crab_40x40.gif"
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

![Rule enforcer](https://github.com/LedgerHQ/app-boilerplate-rust/actions/workflows/guidelines_enforcer.yml/badge.svg) ![Build and tests](https://github.com/LedgerHQ/app-boilerplate-rust/actions/workflows/build_and_functional_tests.yml/badge.svg)

This is a boilerplate application written in Rust which can be forked to start a new project for the Ledger Nano S/X/SP, Stax and Flex devices.
This is a boilerplate application written in Rust which can be forked to start a new project for the Ledger Nano X/SP, Stax and Flex devices.

:warning: Nano S is not supported

* Implements standard features (display address, transaction signature...),
* Has functional tests using [Ragger](https://github.com/LedgerHQ/ragger),
Expand Down Expand Up @@ -82,7 +84,7 @@ Now that you have followed the [prerequisites](#prerequisites) guide, you can bu
cargo ledger build nanox
```

This command will build the app for the Nano X, but you can use any supported device (`nanos`, `nanox`, `nanosplus`)
This command will build the app for the Nano X, but you can use any supported device (`nanox`, `nanosplus`, `stax`, `flex`)

### Loading

Expand All @@ -94,7 +96,7 @@ This command will build the app for the Nano X, but you can use any supported de
cargo ledger build nanox --load
```

As for the build command, you can replace `nanos` with `nanox` or `nanosplus`.
As for the build command, you can replace `nanox` with `nanosplus`, `stax` or `flex`.

## Test

Expand All @@ -111,7 +113,7 @@ pip install -r tests/requirements.txt
* Run the functional tests :

```shell
pytest tests/ --tb=short -v --device {nanos | nanosp | nanox}
pytest tests/ --tb=short -v --device {nanosp | nanox | stax | flex}
```

### Emulator
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+", "stax", "flex"]
devices = ["nanox", "nanos+", "stax", "flex"]

[tests]
pytest_directory = "./tests/"
19 changes: 7 additions & 12 deletions src/app_ui/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*****************************************************************************/

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

#[cfg(not(any(target_os = "stax", target_os = "flex")))]
use ledger_device_sdk::ui::{
Expand All @@ -34,21 +34,16 @@ use include_gif::include_gif;
const DISPLAY_ADDR_BYTES_LEN: usize = 20;

pub fn ui_display_pk(addr: &[u8]) -> Result<bool, AppSW> {
let mut addr_hex = [0u8; DISPLAY_ADDR_BYTES_LEN * 2 + 2];
addr_hex[..2].copy_from_slice("0x".as_bytes());
hex::encode_to_slice(
&addr[addr.len() - DISPLAY_ADDR_BYTES_LEN..],
&mut addr_hex[2..],
)
.unwrap();
let addr_hex = from_utf8_mut(&mut addr_hex).unwrap();
addr_hex[2..].make_ascii_uppercase();
let addr_hex = format!(
"0x{}",
hex::encode(&addr[addr.len() - DISPLAY_ADDR_BYTES_LEN..]).to_uppercase()
);

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

let my_review = MultiFieldReview::new(
Expand All @@ -72,6 +67,6 @@ pub fn ui_display_pk(addr: &[u8]) -> Result<bool, AppSW> {
Ok(NbglAddressReview::new()
.glyph(&FERRIS)
.verify_str("Verify CRAB address")
.show(addr_hex))
.show(&addr_hex))
}
}
26 changes: 5 additions & 21 deletions src/app_ui/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
* limitations under the License.
*****************************************************************************/
use crate::handlers::sign_tx::Tx;
use crate::utils::concatenate;
use crate::AppSW;

#[cfg(not(any(target_os = "stax", target_os = "flex")))]
Expand All @@ -31,9 +30,7 @@ use include_gif::include_gif;
#[cfg(any(target_os = "stax", target_os = "flex"))]
use ledger_device_sdk::nbgl::{Field, NbglGlyph, NbglReview};

use numtoa::NumToA;

const MAX_COIN_LENGTH: usize = 10;
use alloc::format;

/// Displays a transaction and returns true if user approved it.
///
Expand All @@ -43,31 +40,18 @@ const MAX_COIN_LENGTH: usize = 10;
///
/// * `tx` - Transaction to be displayed for validation
pub fn ui_display_tx(tx: &Tx) -> Result<bool, AppSW> {
// Generate string for amount
let mut numtoa_buf = [0u8; 20];
let mut value_buf = [0u8; 20 + MAX_COIN_LENGTH + 1];

let value_str = concatenate(
&[tx.coin, " ", tx.value.numtoa_str(10, &mut numtoa_buf)],
&mut value_buf,
)
.map_err(|_| AppSW::TxDisplayFail)?; // Fails if value_buf is too small

// Generate destination address string in hexadecimal format.
let mut to_str = [0u8; 42];
to_str[..2].copy_from_slice("0x".as_bytes());
hex::encode_to_slice(tx.to, &mut to_str[2..]).unwrap();
to_str[2..].make_ascii_uppercase();
let value_str = format!("{} {}", tx.coin, tx.value);
let to_str = format!("0x{}", hex::encode(tx.to).to_uppercase());

// Define transaction review fields
let my_fields = [
Field {
name: "Amount",
value: value_str,
value: value_str.as_str(),
},
Field {
name: "Destination",
value: core::str::from_utf8(&to_str).unwrap(),
value: to_str.as_str(),
},
Field {
name: "Memo",
Expand Down
20 changes: 8 additions & 12 deletions src/handlers/sign_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use crate::app_ui::sign::ui_display_tx;
use crate::utils::Bip32Path;
use crate::AppSW;
use alloc::vec::Vec;
use ledger_device_sdk::ecc::{Secp256k1, SeedDerive};
use ledger_device_sdk::hash::{sha3::Keccak256, HashInit};
use ledger_device_sdk::io::Comm;
Expand All @@ -38,24 +39,21 @@ pub struct Tx<'a> {
}

pub struct TxContext {
raw_tx: [u8; MAX_TRANSACTION_LEN], // raw transaction serialized
raw_tx_len: usize, // length of raw transaction
raw_tx: Vec<u8>,
path: Bip32Path,
}

// Implement constructor for TxInfo with default values
impl TxContext {
pub fn new() -> TxContext {
TxContext {
raw_tx: [0u8; MAX_TRANSACTION_LEN],
raw_tx_len: 0,
raw_tx: Vec::new(),
path: Default::default(),
}
}
// Implement reset for TxInfo
fn reset(&mut self) {
self.raw_tx = [0u8; MAX_TRANSACTION_LEN];
self.raw_tx_len = 0;
self.raw_tx.clear();
self.path = Default::default();
}
}
Expand All @@ -78,22 +76,20 @@ pub fn handler_sign_tx(
// Next chunks, append data to raw_tx and return or parse
// the transaction if it is the last chunk.
} else {
if ctx.raw_tx_len + data.len() > MAX_TRANSACTION_LEN {
if ctx.raw_tx.len() + data.len() > MAX_TRANSACTION_LEN {
return Err(AppSW::TxWrongLength);
}

// Append data to raw_tx
ctx.raw_tx[ctx.raw_tx_len..ctx.raw_tx_len + data.len()].copy_from_slice(data);
ctx.raw_tx_len += data.len();
ctx.raw_tx.extend(data);

// If we expect more chunks, return
if more {
Ok(())
// Otherwise, try to parse the transaction
} else {
// Try to deserialize the transaction
let (tx, _): (Tx, usize) =
from_slice(&ctx.raw_tx[..ctx.raw_tx_len]).map_err(|_| AppSW::TxParsingFail)?;
let (tx, _): (Tx, usize) = from_slice(&ctx.raw_tx).map_err(|_| AppSW::TxParsingFail)?;
// Display transaction. If user approves
// the transaction, sign it. Otherwise,
// return a "deny" status word.
Expand All @@ -110,7 +106,7 @@ fn compute_signature_and_append(comm: &mut Comm, ctx: &mut TxContext) -> Result<
let mut keccak256 = Keccak256::new();
let mut message_hash: [u8; 32] = [0u8; 32];

let _ = keccak256.hash(&ctx.raw_tx[..ctx.raw_tx_len], &mut message_hash);
let _ = keccak256.hash(&ctx.raw_tx, &mut message_hash);

let (sig, siglen, parity) = Secp256k1::derive_from_path(ctx.path.as_ref())
.deterministic_sign(&message_hash)
Expand Down
5 changes: 4 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@ use ledger_device_sdk::io::{ApduHeader, Comm, Event, Reply, StatusWords};
#[cfg(feature = "pending_review_screen")]
#[cfg(not(any(target_os = "stax", target_os = "flex")))]
use ledger_device_sdk::ui::gadgets::display_pending_review;
#[cfg(not(any(target_os = "stax", target_os = "flex")))]

ledger_device_sdk::set_panic!(ledger_device_sdk::exiting_panic);

// Required for using String, Vec, format!...
extern crate alloc;

#[cfg(any(target_os = "stax", target_os = "flex"))]
use ledger_device_sdk::nbgl::init_comm;

Expand Down
Loading
Loading