diff --git a/applications/minotari_ledger_wallet/comms/examples/ledger_demo/main.rs b/applications/minotari_ledger_wallet/comms/examples/ledger_demo/main.rs index b1b4db696e..c5c2699de1 100644 --- a/applications/minotari_ledger_wallet/comms/examples/ledger_demo/main.rs +++ b/applications/minotari_ledger_wallet/comms/examples/ledger_demo/main.rs @@ -3,6 +3,18 @@ //! # Multi-party Ledger - command line example +/// This example demonstrates how to use the Ledger Nano S/X for the Tari wallet. In order to run the example, you +/// need to have the `MinoTari Wallet` application installed on your Ledger device. For that, please follow the +/// instructions in the [README](../../wallet/README.md) file. +/// With this example, you can: +/// - Detect the hardware wallet +/// - Verify that the Ledger application is installed and the version is correct +/// - TBD +/// +/// ----------------------------------------------------------------------------------------------- +/// Example use: +/// `cargo run --release --example ledger_demo` +/// ----------------------------------------------------------------------------------------------- use dialoguer::{theme::ColorfulTheme, Select}; use minotari_ledger_wallet_comms::{ accessor_methods::{ @@ -21,20 +33,7 @@ use minotari_ledger_wallet_comms::{ error::LedgerDeviceError, ledger_wallet::get_transport, }; -use rand::rngs::OsRng; -/// This example demonstrates how to use the Ledger Nano S/X for the Tari wallet. In order to run the example, you -/// need to have the `MinoTari Wallet` application installed on your Ledger device. For that, please follow the -/// instructions in the [README](../../wallet/README.md) file. -/// With this example, you can: -/// - Detect the hardware wallet -/// - Verify that the Ledger application is installed and the version is correct -/// - TBD -/// -/// ----------------------------------------------------------------------------------------------- -/// Example use: -/// `cargo run --release --example ledger_demo` -/// ----------------------------------------------------------------------------------------------- -use rand::RngCore; +use rand::{rngs::OsRng, RngCore}; use tari_common::configuration::Network; use tari_common_types::{ key_branches::TransactionKeyManagerBranch, @@ -181,18 +180,24 @@ fn main() { // GetScriptOffset println!("\ntest: GetScriptOffset"); - let total_script_private_key = PrivateKey::default(); - let mut derived_key_commitments = Vec::new(); + let partial_script_offset = PrivateKey::default(); + let mut derived_script_keys = Vec::new(); + let mut script_key_indexes = Vec::new(); + let mut derived_sender_offsets = Vec::new(); let mut sender_offset_indexes = Vec::new(); for _i in 0..5 { - derived_key_commitments.push(get_random_nonce()); - sender_offset_indexes.push(OsRng.next_u64()); + derived_script_keys.push(get_random_nonce()); + script_key_indexes.push((TransactionKeyManagerBranch::Spend, OsRng.next_u64())); + derived_sender_offsets.push(get_random_nonce()); + sender_offset_indexes.push((TransactionKeyManagerBranch::OneSidedSenderOffset, OsRng.next_u64())); } match ledger_get_script_offset( account, - &total_script_private_key, - &derived_key_commitments, + &partial_script_offset, + &derived_script_keys, + &script_key_indexes, + &derived_sender_offsets, &sender_offset_indexes, ) { Ok(script_offset) => println!("script_offset: {}", script_offset.to_hex()), diff --git a/applications/minotari_ledger_wallet/comms/src/accessor_methods.rs b/applications/minotari_ledger_wallet/comms/src/accessor_methods.rs index 7e8dafc95c..ec08b87cba 100644 --- a/applications/minotari_ledger_wallet/comms/src/accessor_methods.rs +++ b/applications/minotari_ledger_wallet/comms/src/accessor_methods.rs @@ -33,7 +33,7 @@ use tari_common_types::{ }; use tari_crypto::dhke::DiffieHellmanSharedSecret; use tari_script::CheckSigSchnorrSignature; -use tari_utilities::ByteArray; +use tari_utilities::{hex::Hex, ByteArray}; use crate::{ error::LedgerDeviceError, @@ -187,7 +187,7 @@ pub fn ledger_get_version() -> Result { /// Get the public alpha key from the ledger device pub fn ledger_get_public_spend_key(account: u64) -> Result { - debug!(target: LOG_TARGET, "ledger_get_public_spend_key: account {}", account); + debug!(target: LOG_TARGET, "ledger_get_public_spend_key: account '{}'", account); verify_ledger_application()?; match Command::>::build_command(account, Instruction::GetPublicSpendKey, vec![]).execute() { @@ -212,7 +212,11 @@ pub fn ledger_get_public_key( index: u64, branch: TransactionKeyManagerBranch, ) -> Result { - debug!(target: LOG_TARGET, "ledger_get_public_key: account {}, index {}, branch {:?}", account, index, branch); + debug!( + target: LOG_TARGET, + "ledger_get_public_key: account '{}', index '{}', branch '{:?}'", + account, index, branch + ); verify_ledger_application()?; let mut data = Vec::new(); @@ -245,9 +249,9 @@ pub fn ledger_get_script_signature( value: &PrivateKey, commitment_private_key: &PrivateKey, commitment: &Commitment, - script_message: [u8; 32], + message: [u8; 32], ) -> Result { - debug!(target: LOG_TARGET, "ledger_get_script_signature: account {}", account); + debug!(target: LOG_TARGET, "ledger_get_script_signature: account '{}', message '{}'", account, message.to_hex()); verify_ledger_application()?; let mut data = Vec::new(); @@ -263,7 +267,7 @@ pub fn ledger_get_script_signature( data.extend_from_slice(&commitment_private_key); let commitment = commitment.to_vec(); data.extend_from_slice(&commitment); - data.extend_from_slice(&script_message); + data.extend_from_slice(&message); match Command::>::build_command(account, Instruction::GetScriptSignature, data).execute() { Ok(result) => { @@ -291,28 +295,55 @@ pub fn ledger_get_script_signature( /// Get the script offset from the ledger device pub fn ledger_get_script_offset( account: u64, - total_script_private_key: &PrivateKey, - derived_key_commitments: &[PrivateKey], - sender_offset_indexes: &[u64], + partial_script_offset: &PrivateKey, + derived_script_keys: &[PrivateKey], + script_key_indexes: &[(TransactionKeyManagerBranch, u64)], + derived_sender_offsets: &[PrivateKey], + sender_offset_indexes: &[(TransactionKeyManagerBranch, u64)], ) -> Result { - debug!(target: LOG_TARGET, "ledger_get_script_offset: account {}", account); + debug!( + target: LOG_TARGET, + "ledger_get_script_offset: account '{}', partial_script_offset '{}', derived_script_keys: '{:?}', \ + script_key_indexes: '{:?}', derived_sender_offsets '{:?}', sender_offset_indexes '{:?}'", + account, + partial_script_offset.to_hex(), + derived_script_keys, + script_key_indexes, + derived_sender_offsets, + sender_offset_indexes + ); verify_ledger_application()?; - let num_commitments = derived_key_commitments.len() as u64; - let num_offset_key = sender_offset_indexes.len() as u64; - - let mut instructions = num_offset_key.to_le_bytes().to_vec(); - instructions.extend_from_slice(&num_commitments.to_le_bytes()); - + // 1. data sizes + let mut instructions: Vec = Vec::new(); + instructions.extend_from_slice(&(sender_offset_indexes.len() as u64).to_le_bytes()); + instructions.extend_from_slice(&(script_key_indexes.len() as u64).to_le_bytes()); + instructions.extend_from_slice(&(derived_sender_offsets.len() as u64).to_le_bytes()); + instructions.extend_from_slice(&(derived_script_keys.len() as u64).to_le_bytes()); let mut data: Vec> = vec![instructions.to_vec()]; - data.push(total_script_private_key.to_vec()); - for sender_offset_index in sender_offset_indexes { - data.push(sender_offset_index.to_le_bytes().to_vec()); - } + // 2. partial_script_offset + data.push(partial_script_offset.to_vec()); - for derived_key_commitment in derived_key_commitments { - data.push(derived_key_commitment.to_vec()); + // 3. sender_offset_indexes + for (branch, index) in sender_offset_indexes { + let mut payload = u64::from(branch.as_byte()).to_le_bytes().to_vec(); + payload.extend_from_slice(&index.to_le_bytes()); + data.push(payload); + } + // 4. script_key_indexes + for (branch, index) in script_key_indexes { + let mut payload = u64::from(branch.as_byte()).to_le_bytes().to_vec(); + payload.extend_from_slice(&index.to_le_bytes()); + data.push(payload); + } + // 5. derived_sender_offsets + for sender_offset in derived_sender_offsets { + data.push(sender_offset.to_vec()); + } + // 6. derived_script_keys + for script_key in derived_script_keys { + data.push(script_key.to_vec()); } let commands = Command::>::chunk_command(account, Instruction::GetScriptOffset, data); @@ -343,7 +374,7 @@ pub fn ledger_get_script_offset( /// Get the view key from the ledger device pub fn ledger_get_view_key(account: u64) -> Result { - debug!(target: LOG_TARGET, "ledger_get_view_key: account {}", account); + debug!(target: LOG_TARGET, "ledger_get_view_key: account '{}'", account); verify_ledger_application()?; match Command::>::build_command(account, Instruction::GetViewKey, vec![]).execute() { @@ -369,7 +400,11 @@ pub fn ledger_get_dh_shared_secret( branch: TransactionKeyManagerBranch, public_key: &PublicKey, ) -> Result, LedgerDeviceError> { - debug!(target: LOG_TARGET, "ledger_get_dh_shared_secret: account {}, index {}, branch {:?}", account, index, branch); + debug!( + target: LOG_TARGET, + "ledger_get_dh_shared_secret: account '{}', index '{}', branch '{:?}'", + account, index, branch + ); verify_ledger_application()?; let mut data = Vec::new(); @@ -402,8 +437,12 @@ pub fn ledger_get_raw_schnorr_signature( nonce_branch: TransactionKeyManagerBranch, challenge: &[u8; 64], ) -> Result { - debug!(target: LOG_TARGET, "ledger_get_raw_schnorr_signature: account {}, pk index {}, pk branch {:?}, nonce index {}, nonce branch {:?}", - account, private_key_index, private_key_branch, nonce_index, nonce_branch); + debug!( + target: LOG_TARGET, + "ledger_get_raw_schnorr_signature: account '{}', pk index '{}', pk branch '{:?}', nonce index '{}', \ + nonce branch' {:?}', challenge '{}'", + account, private_key_index, private_key_branch, nonce_index, nonce_branch, challenge.to_hex() + ); verify_ledger_application()?; let mut data = Vec::new(); @@ -440,8 +479,11 @@ pub fn ledger_get_script_schnorr_signature( private_key_branch: TransactionKeyManagerBranch, nonce: &[u8], ) -> Result { - debug!(target: LOG_TARGET, "ledger_get_raw_schnorr_signature: account {}, pk index {}, pk branch {:?}", - account, private_key_index, private_key_branch); + debug!( + target: LOG_TARGET, + "ledger_get_raw_schnorr_signature: account '{}', pk index '{}', pk branch '{:?}'", + account, private_key_index, private_key_branch + ); verify_ledger_application()?; let mut data = Vec::new(); @@ -483,8 +525,13 @@ pub fn ledger_get_one_sided_metadata_signature( value: u64, sender_offset_key_index: u64, commitment_mask: &PrivateKey, - metadata_signature_message: &[u8; 32], + message: &[u8; 32], ) -> Result { + debug!( + target: LOG_TARGET, + "ledger_get_one_sided_metadata_signature: account '{}', message '{}'", + account, message.to_hex() + ); verify_ledger_application()?; let mut data = Vec::new(); @@ -493,7 +540,7 @@ pub fn ledger_get_one_sided_metadata_signature( data.extend_from_slice(&sender_offset_key_index.to_le_bytes()); data.extend_from_slice(&value.to_le_bytes()); data.extend_from_slice(&commitment_mask.to_vec()); - data.extend_from_slice(&metadata_signature_message.to_vec()); + data.extend_from_slice(&message.to_vec()); match Command::>::build_command(account, Instruction::GetOneSidedMetadataSignature, data).execute() { Ok(result) => { 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 034c0d8dd3..37ca19316a 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 @@ -19,11 +19,13 @@ use crate::{ const MIN_UNIQUE_KEYS: usize = 2; pub struct ScriptOffsetCtx { - total_sender_offset_private_key: Zeroizing, - total_script_private_key: Zeroizing, + sender_offset_sum: Zeroizing, + script_private_key_sum: Zeroizing, account: u64, total_offset_indexes: u64, - total_commitment_keys: u64, + total_script_indexes: u64, + total_derived_offset_keys: u64, + total_derived_script_keys: u64, unique_keys: Vec>, } @@ -31,22 +33,26 @@ pub struct ScriptOffsetCtx { impl ScriptOffsetCtx { pub fn new() -> Self { Self { - total_sender_offset_private_key: Zeroizing::new(RistrettoSecretKey::default()), - total_script_private_key: Zeroizing::new(RistrettoSecretKey::default()), + sender_offset_sum: Zeroizing::new(RistrettoSecretKey::default()), + script_private_key_sum: Zeroizing::new(RistrettoSecretKey::default()), account: 0, total_offset_indexes: 0, - total_commitment_keys: 0, + total_script_indexes: 0, + total_derived_offset_keys: 0, + total_derived_script_keys: 0, unique_keys: Vec::new(), } } // Implement reset for TxInfo fn reset(&mut self) { - self.total_sender_offset_private_key = Zeroizing::new(RistrettoSecretKey::default()); - self.total_script_private_key = Zeroizing::new(RistrettoSecretKey::default()); + self.sender_offset_sum = Zeroizing::new(RistrettoSecretKey::default()); + self.script_private_key_sum = Zeroizing::new(RistrettoSecretKey::default()); self.account = 0; self.total_offset_indexes = 0; - self.total_commitment_keys = 0; + self.total_script_indexes = 0; + self.total_derived_offset_keys = 0; + self.total_derived_script_keys = 0; self.unique_keys = Vec::new(); } @@ -57,47 +63,83 @@ impl ScriptOffsetCtx { } } -fn read_instructions(offset_ctx: &mut ScriptOffsetCtx, data: &[u8]) { +fn read_instructions(offset_ctx: &mut ScriptOffsetCtx, data: &[u8]) -> Result<(), AppSW> { + if data.len() != 40 { + return Err(AppSW::WrongApduLength); + } + let mut account_bytes = [0u8; 8]; account_bytes.clone_from_slice(&data[0..8]); offset_ctx.account = u64::from_le_bytes(account_bytes); - if data.len() < 16 { - offset_ctx.total_offset_indexes = 0; - } else { - let mut total_offset_keys = [0u8; 8]; - total_offset_keys.clone_from_slice(&data[8..16]); - offset_ctx.total_offset_indexes = u64::from_le_bytes(total_offset_keys); + let mut total_offset_keys = [0u8; 8]; + total_offset_keys.clone_from_slice(&data[8..16]); + offset_ctx.total_offset_indexes = u64::from_le_bytes(total_offset_keys); + + let mut total_script_indexes = [0u8; 8]; + total_script_indexes.clone_from_slice(&data[16..24]); + offset_ctx.total_script_indexes = u64::from_le_bytes(total_script_indexes); + + let mut total_derived_offset_keys = [0u8; 8]; + total_derived_offset_keys.clone_from_slice(&data[24..32]); + offset_ctx.total_derived_offset_keys = u64::from_le_bytes(total_derived_offset_keys); + + let mut total_derived_script_keys = [0u8; 8]; + total_derived_script_keys.clone_from_slice(&data[32..40]); + offset_ctx.total_derived_script_keys = u64::from_le_bytes(total_derived_script_keys); + + Ok(()) +} + +fn extract_branch_and_index(data: &[u8]) -> Result<(KeyType, u64), AppSW> { + if data.len() != 16 { + return Err(AppSW::WrongApduLength); } + let mut branch_bytes = [0u8; 8]; + branch_bytes.clone_from_slice(&data[0..8]); + let branch_int = u64::from_le_bytes(branch_bytes); + let branch = KeyType::from_branch_key(branch_int)?; + + let mut index_bytes = [0u8; 8]; + index_bytes.clone_from_slice(&data[8..16]); + let index = u64::from_le_bytes(index_bytes); - if data.len() < 24 { - offset_ctx.total_commitment_keys = 0; - } else { - 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); + Ok((branch, index)) +} + +fn derive_key_from_alpha(account: u64, data: &[u8]) -> Result, AppSW> { + if data.len() != 32 { + return Err(AppSW::WrongApduLength); } + let alpha = derive_from_bip32_key(account, STATIC_SPEND_INDEX, KeyType::Spend)?; + let blinding_factor: Zeroizing = + get_key_from_canonical_bytes::(&data[0..32])?.into(); + + alpha_hasher(alpha, blinding_factor) } pub fn handler_get_script_offset( comm: &mut Comm, - chunk: u8, + chunk_number: u8, more: bool, offset_ctx: &mut ScriptOffsetCtx, ) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; - if chunk == 0 { + // 1. data sizes + if chunk_number == 0 { // Reset offset context offset_ctx.reset(); - read_instructions(offset_ctx, data); + read_instructions(offset_ctx, data)?; return Ok(()); } - if chunk == 1 { - // The sum of managed private keys - let k: Zeroizing = get_key_from_canonical_bytes::(&data[0..32])?.into(); - offset_ctx.total_script_private_key = Zeroizing::new(offset_ctx.total_script_private_key.deref() + k.deref()); + // 2. partial_script_offset + if chunk_number == 1 { + // Initialize 'script_private_key_sum' with 'partial_script_offset' + let partial_script_offset: Zeroizing = + get_key_from_canonical_bytes::(&data[0..32])?.into(); + offset_ctx.script_private_key_sum = partial_script_offset; return Ok(()); } @@ -105,41 +147,55 @@ pub fn handler_get_script_offset( let payload_offset = 2; let end_offset_indexes = payload_offset + offset_ctx.total_offset_indexes; - if (payload_offset..end_offset_indexes).contains(&(chunk as u64)) { - let mut index_bytes = [0u8; 8]; - index_bytes.clone_from_slice(&data[0..8]); - let index = u64::from_le_bytes(index_bytes); + // 3. Indexed Sender offset + if (payload_offset..end_offset_indexes).contains(&(chunk_number as u64)) { + let (branch, index) = extract_branch_and_index(data)?; + let offset = derive_from_bip32_key(offset_ctx.account, index, branch)?; - let offset = derive_from_bip32_key(offset_ctx.account, index, KeyType::OneSidedSenderOffset)?; offset_ctx.add_unique_key(offset.clone()); - offset_ctx.total_sender_offset_private_key = - Zeroizing::new(offset_ctx.total_sender_offset_private_key.deref() + offset.deref()); + offset_ctx.sender_offset_sum = Zeroizing::new(offset_ctx.sender_offset_sum.deref() + offset.deref()); } - let end_commitment_keys = end_offset_indexes + offset_ctx.total_commitment_keys; + // 4. Indexed Script key + let end_script_indexes = end_offset_indexes + offset_ctx.total_script_indexes; + if (end_offset_indexes..end_script_indexes).contains(&(chunk_number as u64)) { + let (branch, index) = extract_branch_and_index(data)?; + let script_key = derive_from_bip32_key(offset_ctx.account, index, branch)?; - if (end_offset_indexes..end_commitment_keys).contains(&(chunk as u64)) { - let alpha = derive_from_bip32_key(offset_ctx.account, STATIC_SPEND_INDEX, KeyType::Spend)?; - let blinding_factor: Zeroizing = - get_key_from_canonical_bytes::(&data[0..32])?.into(); + offset_ctx.add_unique_key(script_key.clone()); + offset_ctx.script_private_key_sum = + Zeroizing::new(offset_ctx.script_private_key_sum.deref() + script_key.deref()); + } + + // 5. Derived sender offsets key + let end_derived_offset_keys = end_script_indexes + offset_ctx.total_derived_offset_keys; + if (end_script_indexes..end_derived_offset_keys).contains(&(chunk_number as u64)) { + let k = derive_key_from_alpha(offset_ctx.account, data)?; + + offset_ctx.add_unique_key(k.clone()); + offset_ctx.sender_offset_sum = Zeroizing::new(offset_ctx.sender_offset_sum.deref() + k.deref()); + } - let k = alpha_hasher(alpha, blinding_factor)?; + // 6. Derived script key + let end_derived_script_keys = end_derived_offset_keys + offset_ctx.total_derived_script_keys; + if (end_derived_offset_keys..end_derived_script_keys).contains(&(chunk_number as u64)) { + let k = derive_key_from_alpha(offset_ctx.account, data)?; offset_ctx.add_unique_key(k.clone()); - offset_ctx.total_script_private_key = Zeroizing::new(offset_ctx.total_script_private_key.deref() + k.deref()); + offset_ctx.script_private_key_sum = Zeroizing::new(offset_ctx.script_private_key_sum.deref() + k.deref()); } if more { return Ok(()); } + // Guard against attacks to extract the spending private key if offset_ctx.unique_keys.len() < MIN_UNIQUE_KEYS { return Err(AppSW::ScriptOffsetNotUnique); } - let script_offset = Zeroizing::new( - offset_ctx.total_script_private_key.deref() - offset_ctx.total_sender_offset_private_key.deref(), - ); + let script_offset = + Zeroizing::new(offset_ctx.script_private_key_sum.deref() - offset_ctx.sender_offset_sum.deref()); comm.append(&[RESPONSE_VERSION]); // version comm.append(&script_offset.to_vec()); diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index 9fbf390825..f6868efb5d 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -125,7 +125,7 @@ pub enum Instruction { GetPublicKey, GetPublicSpendKey, GetScriptSignature, - GetScriptOffset { chunk: u8, more: bool }, + GetScriptOffset { chunk_number: u8, more: bool }, GetViewKey, GetDHSharedSecret, GetRawSchnorrSignature, @@ -139,7 +139,7 @@ const STATIC_VIEW_INDEX: u64 = 57311; // No significance, just a random number b const MAX_PAYLOADS: u8 = 250; #[repr(u8)] -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum KeyType { Spend = 0x01, Nonce = 0x02, @@ -195,7 +195,7 @@ impl TryFrom for Instruction { (InstructionMapping::GetPublicKey, 0, 0) => Ok(Instruction::GetPublicKey), (InstructionMapping::GetScriptSignature, 0, 0) => Ok(Instruction::GetScriptSignature), (InstructionMapping::GetScriptOffset, 0..=MAX_PAYLOADS, 0 | P2_MORE) => Ok(Instruction::GetScriptOffset { - chunk: value.p1, + chunk_number: value.p1, more: value.p2 == P2_MORE, }), (InstructionMapping::GetViewKey, 0, 0) => Ok(Instruction::GetViewKey), @@ -247,7 +247,9 @@ fn handle_apdu(comm: &mut Comm, ins: Instruction, offset_ctx: &mut ScriptOffsetC Instruction::GetPublicKey => handler_get_public_key(comm), Instruction::GetPublicSpendKey => handler_get_public_spend_key(comm), Instruction::GetScriptSignature => handler_get_script_signature(comm), - Instruction::GetScriptOffset { chunk, more } => handler_get_script_offset(comm, chunk, more, offset_ctx), + Instruction::GetScriptOffset { chunk_number, more } => { + handler_get_script_offset(comm, chunk_number, more, offset_ctx) + }, Instruction::GetViewKey => handler_get_view_key(comm), Instruction::GetDHSharedSecret => handler_get_dh_shared_secret(comm), Instruction::GetRawSchnorrSignature => handler_get_raw_schnorr_signature(comm), diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 93515bec3a..a54b7b2d79 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -173,7 +173,7 @@ where TBackend: KeyManagerBackend + 'static let mut km = self .key_managers .get(branch) - .ok_or(self.unknown_key_branch_error(branch))? + .ok_or_else(|| self.unknown_key_branch_error("get_next_key", branch))? .write() .await; self.db.increment_key_index(branch)?; @@ -188,9 +188,9 @@ where TBackend: KeyManagerBackend + 'static } pub async fn get_random_key(&self) -> Result, KeyManagerServiceError> { + debug!(target: LOG_TARGET, "get_random_key: wallet type {}", self.wallet_type); match &self.wallet_type { WalletType::Ledger(ledger) => { - debug!(target: LOG_TARGET, "get_random_key: {}", self.wallet_type); #[cfg(not(feature = "ledger"))] { Err(KeyManagerServiceError::LedgerError(format!( @@ -202,9 +202,9 @@ where TBackend: KeyManagerBackend + 'static { let random_index = OsRng.next_u64(); - let public_key = - ledger_get_public_key(ledger.account, random_index, TransactionKeyManagerBranch::RandomKey) - .map_err(|e| KeyManagerServiceError::LedgerError(e.to_string()))?; + let branch = TransactionKeyManagerBranch::RandomKey; + let public_key = ledger_get_public_key(ledger.account, random_index, branch) + .map_err(|e| KeyManagerServiceError::LedgerError(e.to_string()))?; Ok(KeyAndId { key_id: KeyId::Managed { branch: TransactionKeyManagerBranch::RandomKey.get_branch_key(), @@ -228,7 +228,7 @@ where TBackend: KeyManagerBackend + 'static pub async fn get_static_key(&self, branch: &str) -> Result { match self.key_managers.get(branch) { - None => Err(self.unknown_key_branch_error(branch)), + None => Err(self.unknown_key_branch_error("get_static_key", branch)), Some(_) => Ok(KeyId::Managed { branch: branch.to_string(), index: 0, @@ -237,12 +237,14 @@ where TBackend: KeyManagerBackend + 'static } pub async fn get_public_key_at_key_id(&self, key_id: &TariKeyId) -> Result { + debug!(target: LOG_TARGET, "get_public_key_at_key_id: key_id {}, wallet type {}", key_id, self.wallet_type); match key_id { KeyId::Managed { branch, index } => { if let WalletType::Ledger(ledger) = &self.wallet_type { match TransactionKeyManagerBranch::from_key(branch) { - TransactionKeyManagerBranch::OneSidedSenderOffset | TransactionKeyManagerBranch::RandomKey => { - debug!(target: LOG_TARGET, "get_public_key_at_key_id: {}", self.wallet_type); + TransactionKeyManagerBranch::OneSidedSenderOffset | + TransactionKeyManagerBranch::RandomKey | + TransactionKeyManagerBranch::PreMine => { #[cfg(not(feature = "ledger"))] { Err(KeyManagerServiceError::LedgerError(format!( @@ -266,14 +268,14 @@ where TBackend: KeyManagerBackend + 'static let view_key = ledger .view_key .clone() - .ok_or(KeyManagerServiceError::LedgerViewKeyInaccessible)?; + .ok_or(KeyManagerServiceError::LedgerViewKeyInaccessible(key_id.to_string()))?; Ok(PublicKey::from_secret_key(&view_key)) }, _ => { let km = self .key_managers .get(branch) - .ok_or_else(|| self.unknown_key_branch_error(branch))? + .ok_or_else(|| self.unknown_key_branch_error("get_public_key_at_key_id", branch))? .read() .await; Ok(km.derive_public_key(*index)?.key) @@ -283,7 +285,7 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(branch) - .ok_or_else(|| self.unknown_key_branch_error(branch))? + .ok_or_else(|| self.unknown_key_branch_error("get_public_key_at_key_id", branch))? .read() .await; Ok(km.derive_public_key(*index)?.key) @@ -312,12 +314,25 @@ where TBackend: KeyManagerBackend + 'static } } - fn unknown_key_branch_error(&self, branch: &str) -> KeyManagerServiceError { - KeyManagerServiceError::UnknownKeyBranch(format!("{}, {}", branch, self.wallet_type)) + fn unknown_key_branch_error(&self, caller: &str, branch: &str) -> KeyManagerServiceError { + KeyManagerServiceError::UnknownKeyBranch(format!( + "{}: branch: {}, wallet_type: {}", + caller, branch, self.wallet_type + )) } - fn branch_not_supported_error(&self, branch: &str) -> KeyManagerServiceError { - KeyManagerServiceError::BranchNotSupported(format!("{}, {}", branch, self.wallet_type)) + fn branch_not_supported_error(&self, caller: &str, branch: &str) -> KeyManagerServiceError { + KeyManagerServiceError::BranchNotSupported(format!( + "{}: branch: {}, wallet_type: {}", + caller, branch, self.wallet_type + )) + } + + fn key_id_not_supported_error(&self, caller: &str, expected: &str, key_id: &TariKeyId) -> TransactionError { + TransactionError::UnsupportedTariKeyId(format!( + "{}: Expected '{}', got {}, wallet_type: {}", + caller, expected, key_id, self.wallet_type + )) } #[allow(clippy::too_many_lines)] @@ -336,14 +351,16 @@ where TBackend: KeyManagerBackend + 'static return wallet .view_key .clone() - .ok_or(KeyManagerServiceError::LedgerViewKeyInaccessible); + .ok_or(KeyManagerServiceError::LedgerViewKeyInaccessible(key_id.to_string())); } // If we're trying to access any of the private keys, just say no bueno if &TransactionKeyManagerBranch::Spend.get_branch_key() == branch || - &TransactionKeyManagerBranch::OneSidedSenderOffset.get_branch_key() == branch + &TransactionKeyManagerBranch::OneSidedSenderOffset.get_branch_key() == branch || + &TransactionKeyManagerBranch::PreMine.get_branch_key() == branch || + &TransactionKeyManagerBranch::RandomKey.get_branch_key() == branch { - return Err(KeyManagerServiceError::LedgerPrivateKeyInaccessible); + return Err(KeyManagerServiceError::LedgerPrivateKeyInaccessible(key_id.to_string())); } }, WalletType::ProvidedKeys(wallet) => { @@ -353,10 +370,9 @@ where TBackend: KeyManagerBackend + 'static // If we're trying to access any of the private keys, just say no bueno if &TransactionKeyManagerBranch::Spend.get_branch_key() == branch { - return wallet - .private_spend_key - .clone() - .ok_or(KeyManagerServiceError::ImportedPrivateKeyInaccessible); + return wallet.private_spend_key.clone().ok_or( + KeyManagerServiceError::ImportedPrivateKeyInaccessible(key_id.to_string()), + ); } }, } @@ -364,7 +380,7 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(branch) - .ok_or(self.unknown_key_branch_error(branch))? + .ok_or_else(|| self.unknown_key_branch_error("get_private_key", branch))? .read() .await; let key = km.get_private_key(*index)?; @@ -377,13 +393,18 @@ where TBackend: KeyManagerBackend + 'static let commitment_mask = Box::pin(self.get_private_key(&key)).await?; match &self.wallet_type { - WalletType::Ledger(_) => Err(KeyManagerServiceError::LedgerPrivateKeyInaccessible), + WalletType::Ledger(_) => { + Err(KeyManagerServiceError::LedgerPrivateKeyInaccessible(key_id.to_string())) + }, WalletType::DerivedKeys => { let km = self .key_managers .get(&TransactionKeyManagerBranch::Spend.get_branch_key()) .ok_or_else(|| { - self.unknown_key_branch_error(&TransactionKeyManagerBranch::Spend.get_branch_key()) + self.unknown_key_branch_error( + "get_private_key", + &TransactionKeyManagerBranch::Spend.get_branch_key(), + ) })? .read() .await; @@ -400,10 +421,9 @@ where TBackend: KeyManagerBackend + 'static Ok(private_key) }, WalletType::ProvidedKeys(wallet) => { - let private_alpha = wallet - .private_spend_key - .clone() - .ok_or(KeyManagerServiceError::ImportedPrivateKeyInaccessible)?; + let private_alpha = wallet.private_spend_key.clone().ok_or( + KeyManagerServiceError::ImportedPrivateKeyInaccessible(key_id.to_string()), + )?; let hasher = DomainSeparatedHasher::, KeyManagerTransactionsHashDomain>::new_with_label( @@ -498,7 +518,7 @@ where TBackend: KeyManagerBackend + 'static WalletType::Ledger(ledger) => ledger .view_key .clone() - .ok_or(KeyManagerServiceError::LedgerViewKeyInaccessible), + .ok_or(KeyManagerServiceError::LedgerViewKeyInaccessible(format!("{}", ledger))), WalletType::ProvidedKeys(wallet) => Ok(wallet.view_key.clone()), } } @@ -519,7 +539,7 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(&branch) - .ok_or_else(|| self.unknown_key_branch_error(&branch))? + .ok_or_else(|| self.unknown_key_branch_error("get_private_comms_key", &branch))? .read() .await; let key = km.get_private_key(index)?; @@ -554,7 +574,7 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(branch) - .ok_or(self.unknown_key_branch_error(branch))? + .ok_or_else(|| self.unknown_key_branch_error("find_key_index", branch))? .read() .await; @@ -585,7 +605,7 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(branch) - .ok_or(self.unknown_key_branch_error(branch))? + .ok_or_else(|| self.unknown_key_branch_error("find_private_key_index", branch))? .read() .await; @@ -621,7 +641,7 @@ where TBackend: KeyManagerBackend + 'static let mut km = self .key_managers .get(branch) - .ok_or(self.unknown_key_branch_error(branch))? + .ok_or_else(|| self.unknown_key_branch_error("update_current_key_index_if_higher", branch))? .write() .await; let current_index = km.key_index(); @@ -665,11 +685,16 @@ where TBackend: KeyManagerBackend + 'static secret_key_id: &TariKeyId, public_key: &PublicKey, ) -> Result { + debug!( + target: LOG_TARGET, + "get_diffie_hellman_shared_secret: secret_key_id {}, wallet type {}", + secret_key_id, + self.wallet_type + ); if let WalletType::Ledger(ledger) = &self.wallet_type { if let KeyId::Managed { branch, index } = secret_key_id { match TransactionKeyManagerBranch::from_key(branch) { TransactionKeyManagerBranch::OneSidedSenderOffset | TransactionKeyManagerBranch::RandomKey => { - debug!(target: LOG_TARGET, "get_diffie_hellman_shared_secret: {}", self.wallet_type); #[cfg(not(feature = "ledger"))] { return Err(TransactionError::LedgerNotSupported(format!( @@ -704,6 +729,12 @@ where TBackend: KeyManagerBackend + 'static secret_key_id: &TariKeyId, public_key: &PublicKey, ) -> Result>, TransactionError> { + debug!( + target: LOG_TARGET, + "get_diffie_hellman_stealth_domain_hasher: secret_key_id {}, wallet type {}", + secret_key_id, + self.wallet_type + ); match &self.wallet_type { WalletType::Ledger(ledger) => match secret_key_id { KeyId::Managed { branch, index } => match TransactionKeyManagerBranch::from_key(branch) { @@ -729,12 +760,16 @@ where TBackend: KeyManagerBackend + 'static .map(diffie_hellman_stealth_domain_hasher) } }, - _ => Err(TransactionError::from(self.branch_not_supported_error(branch))), + _ => Err(TransactionError::from(self.branch_not_supported_error( + "get_diffie_hellman_stealth_domain_hasher", + branch, + ))), }, - _ => Err(TransactionError::UnsupportedTariKeyId(format!( - "Expected 'KeyId::Managed', got {}", - secret_key_id - ))), + _ => Err(self.key_id_not_supported_error( + "get_diffie_hellman_stealth_domain_hasher", + "KeyId::Managed", + secret_key_id, + )), }, _ => { let secret_key = self.get_private_key(secret_key_id).await?; @@ -787,31 +822,57 @@ where TBackend: KeyManagerBackend + 'static txi_version: &TransactionInputVersion, script_message: &[u8; 32], ) -> Result { + debug!( + target: LOG_TARGET, + "get_script_signature: script_key_id {}, wallet type {}", + script_key_id, + self.wallet_type + ); let commitment = self.get_commitment(commitment_mask_key_id, value).await?; let commitment_private_key = self.get_private_key(commitment_mask_key_id).await?; - match (&self.wallet_type, script_key_id) { - (WalletType::Ledger(ledger), KeyId::Derived { key }) => { - debug!(target: LOG_TARGET, "get_script_signature: {}", self.wallet_type); + match &self.wallet_type { + WalletType::Ledger(ledger) => { #[cfg(not(feature = "ledger"))] { Err(TransactionError::LedgerNotSupported(format!( "{} 'get_script_signature' was called. ({} (has key {}))", - LEDGER_NOT_SUPPORTED, ledger, key + LEDGER_NOT_SUPPORTED, ledger, key_str ))) } #[cfg(feature = "ledger")] { - let key = TariKeyId::from_str(key.to_string().as_str()) - .map_err(|_| KeyManagerServiceError::KeySerializationError)?; - let key = self.get_private_key(&key).await?; + let branch_key = match script_key_id { + TariKeyId::Managed { branch, index } => { + let km = self + .key_managers + .get(branch) + .ok_or_else(|| self.unknown_key_branch_error("get_script_signature", branch))? + .read() + .await; + km.get_private_key(*index) + .map_err(|e| TransactionError::KeyManagerError(e.to_string()))? + }, + TariKeyId::Derived { key: key_str } => { + let key = TariKeyId::from_str(key_str.to_string().as_str()) + .map_err(|_| KeyManagerServiceError::KeySerializationError)?; + self.get_private_key(&key).await? + }, + _ => { + return Err(self.key_id_not_supported_error( + "get_script_signature", + "KeyId::Managed or KeyId::Derived", + script_key_id, + )); + }, + }; let signature = ledger_get_script_signature( ledger.account, ledger.network, txi_version.as_u8(), - &key, + &branch_key, value, &commitment_private_key, &commitment, @@ -821,11 +882,7 @@ where TBackend: KeyManagerBackend + 'static Ok(signature) } }, - (WalletType::Ledger(_ledger), key_id) => Err(TransactionError::UnsupportedTariKeyId(format!( - "Expected 'KeyId::Derived', got {}", - key_id - ))), - (_, _) => { + _ => { let r_a = PrivateKey::random(&mut OsRng); let r_x = PrivateKey::random(&mut OsRng); let r_y = PrivateKey::random(&mut OsRng); @@ -958,31 +1015,42 @@ where TBackend: KeyManagerBackend + 'static script_key_ids: &[TariKeyId], sender_offset_key_ids: &[TariKeyId], ) -> Result { - let mut total_script_private_key = PrivateKey::default(); - let mut derived_key_commitments = vec![]; - for script_key_id in script_key_ids { - match script_key_id { - KeyId::Imported { .. } | KeyId::Managed { .. } | KeyId::Zero => { - total_script_private_key = &total_script_private_key + self.get_private_key(script_key_id).await? - }, - KeyId::Derived { key } => match &self.wallet_type { - WalletType::DerivedKeys | WalletType::ProvidedKeys(_) => { - total_script_private_key = - &total_script_private_key + self.get_private_key(script_key_id).await?; - }, - WalletType::Ledger(_) => { - let key = TariKeyId::from_str(key.to_string().as_str()) - .map_err(|_| KeyManagerServiceError::KeySerializationError)?; - - let key = self.get_private_key(&key).await?; - derived_key_commitments.push(key); - }, - }, - } - } + debug!( + target: LOG_TARGET, + "get_script_offset: script_key_ids {:?}, sender_offset_key_ids {:?}, wallet type {}", + script_key_ids, + sender_offset_key_ids, + self.wallet_type + ); + // let mut total_script_private_key = PrivateKey::default(); + // let mut derived_key_commitments = vec![]; + // for script_key_id in script_key_ids { + // match script_key_id { + // KeyId::Imported { .. } | KeyId::Managed { .. } | KeyId::Zero => { + // total_script_private_key = &total_script_private_key + self.get_private_key(script_key_id).await? + // }, + // KeyId::Derived { key } => match &self.wallet_type { + // WalletType::DerivedKeys | WalletType::ProvidedKeys(_) => { + // total_script_private_key = + // &total_script_private_key + self.get_private_key(script_key_id).await?; + // }, + // WalletType::Ledger(_) => { + // let key = TariKeyId::from_str(key.to_string().as_str()) + // .map_err(|_| KeyManagerServiceError::KeySerializationError)?; + // + // let key = self.get_private_key(&key).await?; + // derived_key_commitments.push(key); + // }, + // }, + // } + // } match &self.wallet_type { WalletType::DerivedKeys | WalletType::ProvidedKeys(_) => { + let mut total_script_private_key = PrivateKey::default(); + for script_key_id in script_key_ids { + total_script_private_key = &total_script_private_key + self.get_private_key(script_key_id).await? + } let mut total_sender_offset_private_key = PrivateKey::default(); for sender_offset_key_id in sender_offset_key_ids { total_sender_offset_private_key = @@ -992,7 +1060,6 @@ where TBackend: KeyManagerBackend + 'static Ok(script_offset) }, WalletType::Ledger(ledger) => { - debug!(target: LOG_TARGET, "get_script_offset: {}", self.wallet_type); #[cfg(not(feature = "ledger"))] { Err(TransactionError::LedgerNotSupported(format!( @@ -1003,26 +1070,92 @@ where TBackend: KeyManagerBackend + 'static #[cfg(feature = "ledger")] { - let mut total_script_private_key = PrivateKey::default(); + let mut partial_script_offset = PrivateKey::default(); + let mut derived_script_keys = vec![]; + let mut script_key_indexes = vec![]; + for script_key_id in script_key_ids { + match script_key_id { + TariKeyId::Managed { branch, index } => { + match TransactionKeyManagerBranch::from_key(branch) { + TransactionKeyManagerBranch::Spend | TransactionKeyManagerBranch::PreMine => { + script_key_indexes + .push((TransactionKeyManagerBranch::from_key(branch), *index)); + }, + _ => { + return Err(TransactionError::from( + self.branch_not_supported_error("get_script_offset", branch), + )); + }, + } + }, + TariKeyId::Derived { key } => { + // TODO: What about if the derived key is a TariKeyId::Managed, but + // TODO: `self.get_private_key(...)` will error? + let key_id = TariKeyId::from_str(key.to_string().as_str()) + .map_err(|_| KeyManagerServiceError::KeySerializationError)?; + let k = self.get_private_key(&key_id).await?; + derived_script_keys.push(k); + }, + TariKeyId::Imported { .. } => { + partial_script_offset = + &partial_script_offset + self.get_private_key(script_key_id).await? + }, + TariKeyId::Zero => { + return Err(self.key_id_not_supported_error( + "get_script_offset", + "KeyId::Managed or TariKeyId::Imported", + script_key_id, + )); + }, + } + } + + let mut derived_offset_keys = vec![]; let mut sender_offset_indexes = vec![]; for sender_offset_key_id in sender_offset_key_ids { match sender_offset_key_id { TariKeyId::Managed { branch, index } => { - if &TransactionKeyManagerBranch::OneSidedSenderOffset.get_branch_key() == branch { - sender_offset_indexes.push(*index); - } else { - total_script_private_key = - total_script_private_key - self.get_private_key(sender_offset_key_id).await?; + match TransactionKeyManagerBranch::from_key(branch) { + TransactionKeyManagerBranch::OneSidedSenderOffset | + TransactionKeyManagerBranch::RandomKey => { + sender_offset_indexes + .push((TransactionKeyManagerBranch::from_key(branch), *index)); + }, + _ => { + return Err(TransactionError::from( + self.branch_not_supported_error("get_script_offset", branch), + )); + }, } }, - TariKeyId::Derived { .. } | TariKeyId::Imported { .. } | TariKeyId::Zero => {}, + TariKeyId::Derived { key } => { + // TODO: What about if the derived key is a TariKeyId::Managed, but + // TODO: `self.get_private_key(...)` will error? + let key_id = TariKeyId::from_str(key.to_string().as_str()) + .map_err(|_| KeyManagerServiceError::KeySerializationError)?; + let k = self.get_private_key(&key_id).await?; + derived_offset_keys.push(k); + }, + TariKeyId::Imported { .. } => { + partial_script_offset = + partial_script_offset - self.get_private_key(sender_offset_key_id).await?; + }, + TariKeyId::Zero => { + return Err(self.key_id_not_supported_error( + "get_script_offset", + "KeyId::Managed or TariKeyId::Imported", + sender_offset_key_id, + )); + }, } } let script_offset = ledger_get_script_offset( ledger.account, - &total_script_private_key, - &derived_key_commitments, + &partial_script_offset, + &derived_script_keys, + &script_key_indexes, + &derived_offset_keys, &sender_offset_indexes, ) .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?; @@ -1079,9 +1212,14 @@ where TBackend: KeyManagerBackend + 'static private_key_id: &TariKeyId, challenge: &[u8], ) -> Result { + debug!( + target: LOG_TARGET, + "sign_script_message: private_key_id {}, wallet type {}", + private_key_id, + self.wallet_type + ); match &self.wallet_type { WalletType::Ledger(ledger) => { - debug!(target: LOG_TARGET, "sign_script_message: {}", self.wallet_type); #[cfg(not(feature = "ledger"))] { Err(TransactionError::LedgerNotSupported(format!( @@ -1102,10 +1240,11 @@ where TBackend: KeyManagerBackend + 'static )?; Ok(signature) }, - _ => Err(TransactionError::UnsupportedTariKeyId(format!( - "Expected 'KeyId::Managed', got {}", - private_key_id - ))), + _ => Err(self.key_id_not_supported_error( + "sign_script_message", + "KeyId::Managed", + private_key_id, + )), } } }, @@ -1124,9 +1263,15 @@ where TBackend: KeyManagerBackend + 'static nonce_key_id: &TariKeyId, challenge: &[u8; 64], ) -> Result { + debug!( + target: LOG_TARGET, + "sign_with_nonce_and_challenge: private_key_id {}, nonce_key_id {}, wallet type {}", + private_key_id, + nonce_key_id, + self.wallet_type + ); match &self.wallet_type { WalletType::Ledger(ledger) => { - debug!(target: LOG_TARGET, "sign_with_nonce_and_challenge: {}", self.wallet_type); #[cfg(not(feature = "ledger"))] { Err(TransactionError::LedgerNotSupported(format!( @@ -1157,15 +1302,17 @@ where TBackend: KeyManagerBackend + 'static .map_err(|e| KeyManagerServiceError::LedgerError(e.to_string()))?; Ok(signature) }, - _ => Err(TransactionError::UnsupportedTariKeyId(format!( - "Expected 'KeyId::Managed', got {}", - nonce_key_id - ))), + _ => Err(self.key_id_not_supported_error( + "sign_with_nonce_and_challenge", + "KeyId::Managed", + nonce_key_id, + )), }, - _ => Err(TransactionError::UnsupportedTariKeyId(format!( - "Expected 'KeyId::Managed', got {}", - private_key_id - ))), + _ => Err(self.key_id_not_supported_error( + "sign_with_nonce_and_challenge", + "KeyId::Managed", + private_key_id, + )), } } }, @@ -1230,6 +1377,13 @@ where TBackend: KeyManagerBackend + 'static metadata_signature_message: &[u8; 32], range_proof_type: RangeProofType, ) -> Result { + debug!( + target: LOG_TARGET, + "get_one_sided_metadata_signature: commitment_mask_key_id {}, sender_offset_key_id {}, wallet type {}", + commitment_mask_key_id, + sender_offset_key_id, + self.wallet_type + ); match &self.wallet_type { WalletType::DerivedKeys | WalletType::ProvidedKeys(_) => { let value = value.into(); @@ -1244,7 +1398,6 @@ where TBackend: KeyManagerBackend + 'static .await }, WalletType::Ledger(ledger) => { - debug!(target: LOG_TARGET, "get_one_sided_metadata_signature: {}", self.wallet_type); #[cfg(not(feature = "ledger"))] { Err(TransactionError::LedgerNotSupported(format!( @@ -1262,6 +1415,11 @@ where TBackend: KeyManagerBackend + 'static let commitment_mask = self.get_private_key(commitment_mask_key_id).await?; + debug!( + target: LOG_TARGET, + "get_one_sided_metadata_signature: (ledger) account {}", + ledger.account, + ); let comm_and_pub_sig = ledger_get_one_sided_metadata_signature( ledger.account, ledger.network, diff --git a/base_layer/key_manager/src/key_manager_service/error.rs b/base_layer/key_manager/src/key_manager_service/error.rs index d6a2bd3703..c61b9e53c9 100644 --- a/base_layer/key_manager/src/key_manager_service/error.rs +++ b/base_layer/key_manager/src/key_manager_service/error.rs @@ -57,14 +57,14 @@ pub enum KeyManagerServiceError { UnknownError(String), #[error("Ledger error: `{0}`")] LedgerError(String), - #[error("The Ledger private key cannot be accessed or read")] - LedgerPrivateKeyInaccessible, - #[error("The Ledger view key cannot be accessed or read")] - LedgerViewKeyInaccessible, + #[error("The Ledger private key cannot be accessed or read: `{0}`")] + LedgerPrivateKeyInaccessible(String), + #[error("The Ledger view key cannot be accessed or read: `{0}`")] + LedgerViewKeyInaccessible(String), #[error("Tari Key Manager storage error: `{0}`")] StorageError(#[from] StorageError), - #[error("The imported private key cannot be accessed or read")] - ImportedPrivateKeyInaccessible, + #[error("The imported private key cannot be accessed or read: `{0}")] + ImportedPrivateKeyInaccessible(String), } impl From for KeyManagerServiceError {