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

Update rslib #57

Merged
merged 2 commits into from
Aug 1, 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 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
Loading