Skip to content

Commit

Permalink
Merge pull request Zondax#57 from Zondax/dev
Browse files Browse the repository at this point in the history
Update rslib
  • Loading branch information
chcmedeiros authored Aug 1, 2024
2 parents 1e7d3b4 + 90df39e commit 6e0ac0f
Show file tree
Hide file tree
Showing 13 changed files with 485 additions and 38 deletions.
2 changes: 1 addition & 1 deletion app/Makefile.version
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ APPVERSION_M=0
# This is the `spec_version` field of `Runtime`
APPVERSION_N=0
# This is the patch version of this release
APPVERSION_P=26
APPVERSION_P=27
315 changes: 312 additions & 3 deletions rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,16 @@ use std::collections::HashMap;
pub use ledger_zondax_generic::LedgerAppError;

mod params;
use params::SALT_LEN;
pub use params::{
InstructionCode, ADDRESS_LEN, CLA, ED25519_PUBKEY_LEN, PK_LEN_PLUS_TAG, SIG_LEN_PLUS_TAG,
InstructionCode, KeyResponse, NamadaKeys, ADDRESS_LEN, CLA, ED25519_PUBKEY_LEN,
PK_LEN_PLUS_TAG, SIG_LEN_PLUS_TAG,
};
use params::{KEY_LEN, SALT_LEN};
use utils::{
ResponseAddress, ResponseGetConvertRandomness, ResponseGetOutputRandomness,
ResponseGetSpendRandomness, ResponseMaspSign, ResponseProofGenKey, ResponsePubAddress,
ResponseSignature, ResponseSpendSignature, ResponseViewKey,
};
use utils::{ResponseAddress, ResponseSignature};

use std::convert::TryInto;
use std::str;
Expand Down Expand Up @@ -311,4 +316,308 @@ where

raw_sig && wrapper_sig
}

/// Retrieve masp keys from the Namada app
pub async fn retrieve_keys(
&self,
path: &BIP44Path,
key_type: NamadaKeys,
require_confirmation: bool,
) -> Result<KeyResponse, NamError<E::Error>> {
let serialized_path = path.serialize_path().unwrap();
let p1: u8 = if require_confirmation { 1 } else { 0 };

let p2: u8 = match key_type {
NamadaKeys::PublicAddress => 0,
NamadaKeys::ViewKey => 1,
NamadaKeys::ProofGenerationKey => 2,
};

let command = APDUCommand {
cla: CLA,
ins: InstructionCode::GetKeys as _,
p1,
p2,
data: serialized_path,
};

let response = self
.apdu_transport
.exchange(&command)
.await
.map_err(LedgerAppError::TransportError)?;

match response.error_code() {
Ok(APDUErrorCode::NoError) => {}
Ok(err) => {
return Err(NamError::Ledger(LedgerAppError::AppSpecific(
err as _,
err.description(),
)))
}
Err(err) => {
return Err(NamError::Ledger(LedgerAppError::AppSpecific(
err,
"[APDU_ERROR] Unknown".to_string(),
)))
}
}

let response_data = response.apdu_data();
match key_type {
NamadaKeys::PublicAddress => Ok(KeyResponse::Address(ResponsePubAddress {
public_address: response_data[..KEY_LEN].try_into().unwrap(),
})),
NamadaKeys::ViewKey => {
let (view_key, rest) = response_data.split_at(2 * KEY_LEN);
let (ovk, rest) = rest.split_at(KEY_LEN);
let (ivk, _) = rest.split_at(KEY_LEN);
Ok(KeyResponse::ViewKey(ResponseViewKey {
view_key: view_key.try_into().unwrap(),
ovk: ovk.try_into().unwrap(),
ivk: ivk.try_into().unwrap(),
}))
}
NamadaKeys::ProofGenerationKey => {
let (ak, rest) = response_data.split_at(KEY_LEN);
let (nsk, _) = rest.split_at(KEY_LEN);
Ok(KeyResponse::ProofGenKey(ResponseProofGenKey {
ak: ak.try_into().unwrap(),
nsk: nsk.try_into().unwrap(),
}))
}
}
}

/// Get Randomness for Spend
pub async fn get_spend_randomness(
&self,
) -> Result<ResponseGetSpendRandomness, NamError<E::Error>> {
let arr: &[u8] = &[];
let command = APDUCommand {
cla: CLA,
ins: InstructionCode::GetSpendRandomness as _,
p1: 0x00,
p2: 0x00,
data: arr, // Send empty data
};

let response = self
.apdu_transport
.exchange(&command)
.await
.map_err(LedgerAppError::TransportError)?;

match response.error_code() {
Ok(APDUErrorCode::NoError) => {}
Ok(err) => {
return Err(NamError::Ledger(LedgerAppError::AppSpecific(
err as _,
err.description(),
)))
}
Err(err) => {
return Err(NamError::Ledger(LedgerAppError::AppSpecific(
err,
"[APDU_ERROR] Unknown".to_string(),
)))
}
}

let response_data = response.apdu_data();
if response_data.len() < 2 * KEY_LEN {
return Err(NamError::Ledger(LedgerAppError::InvalidMessageSize));
}

let (rcv, rest) = response_data.split_at(KEY_LEN);
let (alpha, _) = rest.split_at(KEY_LEN);
Ok(ResponseGetSpendRandomness {
rcv: rcv.try_into().unwrap(),
alpha: alpha.try_into().unwrap(),
})
}

/// Get Randomness for convert
pub async fn get_convert_randomness(
&self,
) -> Result<ResponseGetConvertRandomness, NamError<E::Error>> {
let arr: &[u8] = &[];
let command = APDUCommand {
cla: CLA,
ins: InstructionCode::GetConvertRandomness as _,
p1: 0x00,
p2: 0x00,
data: arr, // Send empty data
};

let response = self
.apdu_transport
.exchange(&command)
.await
.map_err(LedgerAppError::TransportError)?;

match response.error_code() {
Ok(APDUErrorCode::NoError) => {}
Ok(err) => {
return Err(NamError::Ledger(LedgerAppError::AppSpecific(
err as _,
err.description(),
)))
}
Err(err) => {
return Err(NamError::Ledger(LedgerAppError::AppSpecific(
err,
"[APDU_ERROR] Unknown".to_string(),
)))
}
}

let response_data = response.apdu_data();
if response_data.len() < KEY_LEN {
return Err(NamError::Ledger(LedgerAppError::InvalidMessageSize));
}

let (rcv, _) = response_data.split_at(KEY_LEN);
Ok(ResponseGetConvertRandomness {
rcv: rcv.try_into().unwrap(),
})
}

/// Get Randomness for output
pub async fn get_output_randomness(
&self,
) -> Result<ResponseGetOutputRandomness, NamError<E::Error>> {
let arr: &[u8] = &[];
let command = APDUCommand {
cla: CLA,
ins: InstructionCode::GetOutputRandomness as _,
p1: 0x00,
p2: 0x00,
data: arr, // Send empty data
};

let response = self
.apdu_transport
.exchange(&command)
.await
.map_err(LedgerAppError::TransportError)?;

match response.error_code() {
Ok(APDUErrorCode::NoError) => {}
Ok(err) => {
return Err(NamError::Ledger(LedgerAppError::AppSpecific(
err as _,
err.description(),
)))
}
Err(err) => {
return Err(NamError::Ledger(LedgerAppError::AppSpecific(
err,
"[APDU_ERROR] Unknown".to_string(),
)))
}
}

let response_data = response.apdu_data();
if response_data.len() < 2 * KEY_LEN {
return Err(NamError::Ledger(LedgerAppError::InvalidMessageSize));
}

let (rcv, rest) = response_data.split_at(KEY_LEN);
let (rcm, _) = rest.split_at(KEY_LEN);
Ok(ResponseGetOutputRandomness {
rcv: rcv.try_into().unwrap(),
rcm: rcm.try_into().unwrap(),
})
}

/// Get Spend signature
pub async fn get_spend_signature(&self) -> Result<ResponseSpendSignature, NamError<E::Error>> {
let arr: &[u8] = &[];
let command = APDUCommand {
cla: CLA,
ins: InstructionCode::ExtractSpendSignature as _,
p1: 0x00,
p2: 0x00,
data: arr, // Send empty data
};

let response = self
.apdu_transport
.exchange(&command)
.await
.map_err(LedgerAppError::TransportError)?;

match response.error_code() {
Ok(APDUErrorCode::NoError) => {}
Ok(err) => {
return Err(NamError::Ledger(LedgerAppError::AppSpecific(
err as _,
err.description(),
)))
}
Err(err) => {
return Err(NamError::Ledger(LedgerAppError::AppSpecific(
err,
"[APDU_ERROR] Unknown".to_string(),
)))
}
}

let response_data = response.apdu_data();
if response_data.len() < 2 * KEY_LEN {
return Err(NamError::Ledger(LedgerAppError::InvalidMessageSize));
}

let (rbar, rest) = response_data.split_at(KEY_LEN);
let (sbar, _) = rest.split_at(KEY_LEN);
Ok(ResponseSpendSignature {
rbar: rbar.try_into().unwrap(),
sbar: sbar.try_into().unwrap(),
})
}

/// Sign Masp signing
pub async fn sign_masp(
&self,
path: &BIP44Path,
blob: &[u8],
) -> Result<ResponseMaspSign, NamError<E::Error>> {
let first_chunk = path.serialize_path().unwrap();

let start_command = APDUCommand {
cla: CLA,
ins: InstructionCode::SignMasp as _,
p1: ChunkPayloadType::Init as u8,
p2: 0x00,
data: first_chunk,
};

let response =
<Self as AppExt<E>>::send_chunks(&self.apdu_transport, start_command, blob).await?;

match response.error_code() {
Ok(APDUErrorCode::NoError) => {}
Ok(err) => {
return Err(NamError::Ledger(LedgerAppError::AppSpecific(
err as _,
err.description(),
)))
}
Err(err) => {
return Err(NamError::Ledger(LedgerAppError::AppSpecific(
err,
"[APDU_ERROR] Unknown".to_string(),
)))
}
}

// Transactions is signed - Retrieve signatures
let rest = response.apdu_data();
let (hash, _) = rest.split_at(KEY_LEN);

Ok(ResponseMaspSign {
hash: hash.try_into().unwrap(),
})
}
}
37 changes: 37 additions & 0 deletions rs/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@
#![deny(unused_import_braces, unused_qualifications)]
#![deny(missing_docs)]

use crate::utils::{ResponseProofGenKey, ResponsePubAddress, ResponseViewKey};

/// App identifier
pub const CLA: u8 = 0x57;

/// MASP keys len
pub const KEY_LEN: usize = 32;
/// Public Key Length
pub const ED25519_PUBKEY_LEN: usize = 32;
/// Public Key + Tag Length
Expand All @@ -41,7 +45,40 @@ pub enum InstructionCode {
GetAddressAndPubkey = 1,
/// Instruction to sign a transaction
Sign = 2,
/// Instruction to retrieve MASP keys
GetKeys = 3,
/// Instruction to generate spend randomness values
GetSpendRandomness = 4,
/// Instruction to generate output randomness values
GetOutputRandomness = 5,
/// Instruction to generate spend convert values
GetConvertRandomness = 6,
/// Instruction to sign masp
SignMasp = 7,
/// Instruction to retrieve spend signatures
ExtractSpendSignature = 8,

/// Instruction to retrieve a signed section
GetSignature = 0x0a,
}

#[derive(Clone, Debug)]
/// Masp keys return types
pub enum NamadaKeys {
/// Public address key
PublicAddress = 0x00,
/// View key
ViewKey = 0x01,
/// Proof generation key
ProofGenerationKey = 0x02,
}

/// Types of Keys Response
pub enum KeyResponse {
/// Address response
Address(ResponsePubAddress),
/// View key response
ViewKey(ResponseViewKey),
/// Proof generation key response
ProofGenKey(ResponseProofGenKey),
}
Loading

0 comments on commit 6e0ac0f

Please sign in to comment.