Skip to content

Commit

Permalink
Merge pull request #225 from LedgerHQ/y333_241014/swap_support
Browse files Browse the repository at this point in the history
Swap support
  • Loading branch information
yogh333 authored Dec 16, 2024
2 parents e9f8962 + 0c28f1c commit 52bec2a
Show file tree
Hide file tree
Showing 11 changed files with 557 additions and 65 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

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

5 changes: 3 additions & 2 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.18.4"
version = "1.19.0"
authors = ["yhql", "yogh333", "agrojean-ledger", "kingofpayne"]
edition = "2021"
license.workspace = true
Expand All @@ -21,9 +21,10 @@ 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.5.3" }
ledger_secure_sdk_sys = { path = "../ledger_secure_sdk_sys", version = "1.6.0" }

[features]
debug = []
speculos = []
ccid = []
heap = [ "ledger_secure_sdk_sys/heap" ]
Expand Down
31 changes: 25 additions & 6 deletions ledger_device_sdk/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ impl Comm {
/// Send the currently held APDU
// This is private. Users should call reply to set the satus word and
// transmit the response.
fn apdu_send(&mut self) {
fn apdu_send(&mut self, is_swap: bool) {
if !sys_seph::is_status_sent() {
sys_seph::send_general_status()
}
Expand Down Expand Up @@ -203,6 +203,13 @@ impl Comm {
}
_ => (),
}
if is_swap {
if !sys_seph::is_status_sent() {
sys_seph::send_general_status()
}
sys_seph::seph_recv(&mut spi_buffer, 0);
seph::handle_event(&mut self.apdu_buffer, &spi_buffer);
}
self.tx = 0;
self.rx = 0;
unsafe {
Expand Down Expand Up @@ -506,7 +513,17 @@ impl Comm {
self.apdu_buffer[self.tx + 1] = sw as u8;
self.tx += 2;
// Transmit the response
self.apdu_send();
self.apdu_send(false);
}

pub fn swap_reply<T: Into<Reply>>(&mut self, reply: T) {
let sw = reply.into().0;
// Append status word
self.apdu_buffer[self.tx] = (sw >> 8) as u8;
self.apdu_buffer[self.tx + 1] = sw as u8;
self.tx += 2;
// Transmit the response
self.apdu_send(true);
}

/// Set the Status Word of the response to `StatusWords::OK` (which is equal
Expand All @@ -515,6 +532,10 @@ impl Comm {
self.reply(StatusWords::Ok);
}

pub fn swap_reply_ok(&mut self) {
self.swap_reply(StatusWords::Ok);
}

/// Return APDU Metadata
pub fn get_apdu_metadata(&self) -> &ApduHeader {
assert!(self.apdu_buffer.len() >= 4);
Expand Down Expand Up @@ -552,10 +573,8 @@ impl Comm {
}

pub fn append(&mut self, m: &[u8]) {
for c in m.iter() {
self.apdu_buffer[self.tx] = *c;
self.tx += 1;
}
self.apdu_buffer[self.tx..self.tx + m.len()].copy_from_slice(m);
self.tx += m.len();
}
}

Expand Down
1 change: 1 addition & 0 deletions ledger_device_sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod ecc;
pub mod hash;
pub mod hmac;
pub mod io;
pub mod libcall;
pub mod nvm;
pub mod random;
pub mod screen;
Expand Down
35 changes: 35 additions & 0 deletions ledger_device_sdk/src/libcall.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use crate::testing::debug_print;

use ledger_secure_sdk_sys::{libargs_t, CHECK_ADDRESS, GET_PRINTABLE_AMOUNT, SIGN_TRANSACTION};

pub mod string;
pub mod swap;

pub enum LibCallCommand {
SwapSignTransaction,
SwapGetPrintableAmount,
SwapCheckAddress,
}

impl From<u32> for LibCallCommand {
fn from(command: u32) -> Self {
match command {
SIGN_TRANSACTION => LibCallCommand::SwapSignTransaction,
GET_PRINTABLE_AMOUNT => LibCallCommand::SwapGetPrintableAmount,
CHECK_ADDRESS => LibCallCommand::SwapCheckAddress,
_ => panic!("Unknown command"),
}
}
}

pub fn get_command(arg0: u32) -> LibCallCommand {
debug_print("GET_CMD\n");
let mut libarg: libargs_t = libargs_t::default();

let arg = arg0 as *const u32;

libarg.id = unsafe { *arg };
libarg.command = unsafe { *arg.add(1) };
libarg.unused = unsafe { *arg.add(2) };
libarg.command.into()
}
183 changes: 183 additions & 0 deletions ledger_device_sdk/src/libcall/string.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#[derive(Debug, Copy, Clone)]
pub struct CustomString<const N: usize> {
pub arr: [u8; N],
pub capacity: usize,
pub len: usize,
}

impl<const N: usize> Default for CustomString<N> {
fn default() -> Self {
Self {
arr: [b'0'; N],
capacity: N,
len: 0,
}
}
}

impl<const N: usize> CustomString<N> {
pub fn new() -> Self {
Self {
arr: [b'0'; N],
capacity: N,
len: 0,
}
}

pub fn clear(&mut self) {
self.arr.fill(0);
self.len = 0;
}

pub fn as_str(&self) -> &str {
core::str::from_utf8(&self.arr[..self.len]).unwrap()
}

pub fn copy_from(&mut self, s: &CustomString<N>) {
self.arr[..s.len].copy_from_slice(&s.arr[..s.len]);
self.len = s.len;
}
}

impl From<u8> for CustomString<2> {
fn from(val: u8) -> Self {
let mut s = CustomString::<2>::new();
let mut i: usize = 0;
for c in val.to_be_bytes().into_iter() {
let (c0, c1) = byte_to_hex(c);
s.arr[i] = c0 as u8;
s.arr[i + 1] = c1 as u8;
s.len += 2;
i += 2;
}
s
}
}

impl From<u16> for CustomString<4> {
fn from(val: u16) -> Self {
let mut s = CustomString::<4>::new();
let mut i: usize = 0;
for c in val.to_be_bytes().into_iter() {
let (c0, c1) = byte_to_hex(c);
s.arr[i] = c0 as u8;
s.arr[i + 1] = c1 as u8;
s.len += 2;
i += 2;
}
s
}
}

impl From<u32> for CustomString<8> {
fn from(val: u32) -> Self {
let mut s = CustomString::<8>::new();
let mut i: usize = 0;
for c in val.to_be_bytes().into_iter() {
let (c0, c1) = byte_to_hex(c);
s.arr[i] = c0 as u8;
s.arr[i + 1] = c1 as u8;
s.len += 2;
i += 2;
}
s
}
}

impl From<[u8; 32]> for CustomString<64> {
fn from(arr: [u8; 32]) -> Self {
let mut s = CustomString::<64>::new();
let mut i: usize = 0;
for c in arr.into_iter() {
let (c0, c1) = byte_to_hex(c);
s.arr[i] = c0 as u8;
s.arr[i + 1] = c1 as u8;
s.len += 2;
i += 2;
}
s
}
}

impl<const N: usize> TryFrom<&str> for CustomString<N> {
type Error = &'static str;
fn try_from(st: &str) -> Result<Self, Self::Error> {
if N >= st.len() {
let mut s = CustomString::<N>::new();
s.arr[..st.len()].copy_from_slice(st.as_bytes());
s.len = st.len();
Ok(s)
} else {
Err("CustomString's capacity overflow!")
}
}
}

/// Output an uint256 as an decimal CustomString
/// For instance:
///
/// let val: [u8; 32] = token amount (32 bytes / 256 bits);
/// let s: CustomString<79> = uint256_to_integer(&val); // max number of decimal digits for Uint256 = 78 (+ 1 spare for '.')
/// testing::debug_print(s.print().unwrap());
pub fn uint256_to_integer(value: &[u8; 32]) -> CustomString<79> {
let mut s: CustomString<79> = CustomString::new();

// Special case when value is 0
if *value == [0u8; 32] {
s.arr[0] = b'0';
s.len = 1;
return s;
}

let mut n: [u16; 16] = [0u16; 16];
for idx in 0..16 {
n[idx] = u16::from_be_bytes([value[2 * idx], value[2 * idx + 1]]);
}

let mut pos: usize = s.capacity;
while n != [0u16; 16] {
if pos == 0 {
return s;
}
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;
carry = rem;
}
s.arr[pos] = u8::try_from(char::from_digit(carry, 10).unwrap()).unwrap();
}
s.arr.copy_within(pos.., 0);
s.len = s.capacity - pos;
s
}

/// Output an uint256 as a float string
pub fn uint256_to_float(value: &[u8; 32], decimals: usize) -> CustomString<79> {
let mut s: CustomString<79> = uint256_to_integer(value);

if decimals == 0 || s.arr[0] == b'0' {
return s;
}

if s.len <= decimals {
s.arr.copy_within(0..s.len, 2 + decimals - s.len);
s.arr[0..2 + decimals - s.len].fill(b'0');
s.arr[1] = b'.';
s.len += 2 + decimals - s.len;
} else {
s.arr
.copy_within(s.len - decimals..s.len, s.len - decimals + 1);
s.arr[s.len - decimals] = b'.';
s.len += 1;
}
s
}

fn byte_to_hex(b: u8) -> (char, char) {
let c0 = char::from_digit((b >> 4).into(), 16).unwrap();
let c1 = char::from_digit((b & 0xf).into(), 16).unwrap();
(c0, c1)
}
Loading

0 comments on commit 52bec2a

Please sign in to comment.