Skip to content

Commit

Permalink
Calculate offset from ledger
Browse files Browse the repository at this point in the history
  • Loading branch information
brianp committed Apr 26, 2024
1 parent 4c35df4 commit accf6a0
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 20 deletions.
Expand Up @@ -2,16 +2,113 @@
// SPDX-License-Identifier: BSD-3-Clause

use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage};
use tari_crypto::{ristretto::RistrettoSecretKey, tari_utilities::ByteArray};

use crate::{alloc::string::ToString, AppSW, RESPONSE_VERSION};
use crate::{
alloc::string::ToString,
utils::{derive_from_bip32_key, get_key_from_canonical_bytes, mask_a},
AppSW,
RESPONSE_VERSION,
};

pub fn handler_get_script_offset(comm: &mut Comm) -> Result<(), AppSW> {
pub struct ScriptOffsetCtx {
total_sender_offset_private_key: RistrettoSecretKey,
total_script_private_key: RistrettoSecretKey,
account: u64,
total_offset_keys: u64,
total_script_keys: u64,
total_commitment_keys: u64,
}

// Implement constructor for TxInfo with default values
impl ScriptOffsetCtx {
pub fn new() -> Self {
Self {
total_sender_offset_private_key: RistrettoSecretKey::default(),
total_script_private_key: RistrettoSecretKey::default(),
account: 0,
total_offset_keys: 0,
total_script_keys: 0,
total_commitment_keys: 0,
}
}

// Implement reset for TxInfo
fn reset(&mut self) {
self.total_sender_offset_private_key = RistrettoSecretKey::default();
self.total_script_private_key = RistrettoSecretKey::default();
self.account = 0;
self.total_offset_keys = 0;
self.total_script_keys = 0;
self.total_commitment_keys = 0;
}
}

fn read_instructions(offset_ctx: &mut ScriptOffsetCtx, data: &[u8]) {
let mut account_bytes = [0u8; 8];
account_bytes.clone_from_slice(&data[0..8]);
offset_ctx.account = u64::from_le_bytes(account_bytes);

let mut total_offset_keys = [0u8; 8];
total_offset_keys.clone_from_slice(&data[24..32]);
offset_ctx.total_offset_keys = u64::from_le_bytes(total_offset_keys);

let mut total_script_keys = [0u8; 8];
total_script_keys.clone_from_slice(&data[8..16]);
offset_ctx.total_script_keys = u64::from_le_bytes(total_script_keys);

let mut total_commitment_keys = [0u8; 8];
total_commitment_keys.clone_from_slice(&data[16..24]);
offset_ctx.total_commitment_keys = u64::from_le_bytes(total_commitment_keys);
}
pub fn handler_get_script_offset(
comm: &mut Comm,
chunk: u8,
more: bool,
offset_ctx: &mut ScriptOffsetCtx,
) -> Result<(), AppSW> {
let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?;

SingleMessage::new(&"Finished".to_string()).show_and_wait();
if chunk == 0 {
// Reset offset context
offset_ctx.reset();
read_instructions(offset_ctx, data);
}

if (1..offset_ctx.total_offset_keys).contains(&(chunk as u64)) {
let k = get_key_from_canonical_bytes(&data[0..32])?;
offset_ctx.total_sender_offset_private_key = &offset_ctx.total_sender_offset_private_key + &k;
}

if (offset_ctx.total_offset_keys..offset_ctx.total_script_keys).contains(&(chunk as u64)) {
let k = get_key_from_canonical_bytes(&data[0..32])?;
offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + &k;
}

if (offset_ctx.total_script_keys..offset_ctx.total_commitment_keys).contains(&(chunk as u64)) {
let mut index_bytes = [0u8; 8];
index_bytes.clone_from_slice(&data[32..40]);
let index = u64::from_le_bytes(index_bytes);

let alpha = derive_from_bip32_key(offset_ctx.account, index)?;
let commitment = get_key_from_canonical_bytes(&data[0..32])?;
let k = mask_a(alpha, commitment)?;

offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + &k;
}

if more {
return Ok(());
}

let script_offset = &offset_ctx.total_script_private_key - &offset_ctx.total_sender_offset_private_key;

comm.append(&[RESPONSE_VERSION]); // version
comm.append(&script_offset.to_vec());
comm.reply_ok();

SingleMessage::new(&"Finished Offset!".to_string()).show_and_wait();

offset_ctx.reset();
Ok(())
}
15 changes: 9 additions & 6 deletions applications/minotari_ledger_wallet/wallet/src/main.rs
Expand Up @@ -103,10 +103,10 @@ pub enum Instruction {
GetAppName,
GetPublicKey,
GetScriptSignature { chunk: u8, more: bool },
GetScriptOffset,
GetScriptOffset { chunk: u8, more: bool },
}

const P2_SCRIPT_SIG_MORE: u8 = 0x01;
const P2_MORE: u8 = 0x01;

impl TryFrom<ApduHeader> for Instruction {
type Error = AppSW;
Expand All @@ -127,11 +127,14 @@ impl TryFrom<ApduHeader> for Instruction {
(1, 0, 0) => Ok(Instruction::GetVersion),
(2, 0, 0) => Ok(Instruction::GetAppName),
(4, 0, 0) => Ok(Instruction::GetPublicKey),
(5, 0..=6, 0 | P2_SCRIPT_SIG_MORE) => Ok(Instruction::GetScriptSignature {
(5, 0..=6, 0 | P2_MORE) => Ok(Instruction::GetScriptSignature {
chunk: value.p1,
more: value.p2 == P2_SCRIPT_SIG_MORE,
more: value.p2 == P2_MORE,
}),
(6, 0..=6, 0 | P2_MORE) => Ok(Instruction::GetScriptOffset {
chunk: value.p1,
more: value.p2 == P2_MORE,
}),
(6, 0, 0) => Ok(Instruction::GetScriptOffset),
(3..=4, _, _) => Err(AppSW::WrongP1P2),
(_, _, _) => Err(AppSW::InsNotSupported),
}
Expand Down Expand Up @@ -181,6 +184,6 @@ fn handle_apdu(
},
Instruction::GetPublicKey => handler_get_public_key(comm),
Instruction::GetScriptSignature { chunk, more } => handler_get_script_signature(comm, chunk, more, signer_ctx),
Instruction::GetScriptOffset => handler_get_script_offset(comm),
Instruction::GetScriptOffset { chunk, more } => handler_get_script_offset(comm, chunk, more, offset_ctx),
}
}
37 changes: 26 additions & 11 deletions base_layer/core/src/transactions/key_manager/inner.rs
Expand Up @@ -696,10 +696,7 @@ where TBackend: KeyManagerBackend<PublicKey> + 'static
label: _,
index,
} => {
// Early exit
if let WalletType::Software(_, _) = self.wallet_type {
// If this happens we actually expect a panic, so pushing to the array is
// pointless but ya never know eh?
managed_script_keys.push(self.get_private_key(script_key_id).await?);
continue;
}
Expand All @@ -724,9 +721,29 @@ where TBackend: KeyManagerBackend<PublicKey> + 'static

match &self.wallet_type {
WalletType::Ledger(ledger) => {
let data: Vec<Vec<u8>> = vec![
//branch_key.as_bytes().to_vec(),
];
let num_script_keys = managed_script_keys.len() as u64;
let num_commitments = derived_key_commitments.len() as u64;
let num_offset_key = sender_offset_keys.len() as u64;

let mut instructions = num_offset_key.to_le_bytes().to_vec();
instructions.clone_from_slice(&num_script_keys.to_le_bytes());
instructions.clone_from_slice(&num_commitments.to_le_bytes());

let mut data: Vec<Vec<u8>> = vec![instructions.to_vec()];
for sender_offset_key in sender_offset_keys {
data.push(sender_offset_key.to_vec());
}
for managed_script_key in managed_script_keys {
// Managed keys will just be the key in the payload
data.push(managed_script_key.to_vec());
}
for (derived_key_commitment, index) in derived_key_commitments {
// Derived keys will have the commitment and their index in the payload
let mut derived = derived_key_commitment.to_vec();
derived.copy_from_slice(&index.to_le_bytes());

data.push(derived);
}

let commands = ledger.chunk_command(Instruction::GetScriptOffset, data);
let transport = get_transport()?;
Expand All @@ -735,9 +752,7 @@ where TBackend: KeyManagerBackend<PublicKey> + 'static
for command in commands {
match command.execute_with_transport(&transport) {
Ok(r) => result = Some(r),
Err(e) => {
return Err(LedgerDeviceError::Instruction(format!("GetScriptSignature: {}", e)).into())
},
Err(e) => return Err(LedgerDeviceError::Instruction(format!("GetScriptOffset: {}", e)).into()),
}
}

Expand All @@ -757,9 +772,9 @@ where TBackend: KeyManagerBackend<PublicKey> + 'static
.map_err(|e| TransactionError::InvalidSignatureError(e.to_string()));
}

Err(LedgerDeviceError::Instruction("GetScriptSignature failed to process correctly".to_string()).into())
Err(LedgerDeviceError::Instruction("GetScriptOffset failed to process correctly".to_string()).into())
},
WalletType::Software(_p, _pk) => {
WalletType::Software(_, _) => {
let mut total_sender_offset_private_key = PrivateKey::default();
for sender_offset_key_id in sender_offset_keys {
total_sender_offset_private_key = total_sender_offset_private_key + sender_offset_key_id;
Expand Down

0 comments on commit accf6a0

Please sign in to comment.