From accf6a0c0711fedc789e6d37ce4707c13f5ca403 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 26 Apr 2024 13:52:20 +0200 Subject: [PATCH] Calculate offset from ledger --- .../wallet/src/handlers/get_script_offset.rs | 103 +++++++++++++++++- .../minotari_ledger_wallet/wallet/src/main.rs | 15 ++- .../src/transactions/key_manager/inner.rs | 37 +++++-- 3 files changed, 135 insertions(+), 20 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs index 626ce4549b..75cd603fa6 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs @@ -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(()) } diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index 8362057a0e..5bd2442cee 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -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 for Instruction { type Error = AppSW; @@ -127,11 +127,14 @@ impl TryFrom 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), } @@ -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), } } diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index e70e34e229..eae6fa916f 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -696,10 +696,7 @@ where TBackend: KeyManagerBackend + '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; } @@ -724,9 +721,29 @@ where TBackend: KeyManagerBackend + 'static match &self.wallet_type { WalletType::Ledger(ledger) => { - let data: Vec> = 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![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()?; @@ -735,9 +752,7 @@ where TBackend: KeyManagerBackend + '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()), } } @@ -757,9 +772,9 @@ where TBackend: KeyManagerBackend + '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;