diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs deleted file mode 100644 index 3361ec7a77..0000000000 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2024 The Tari Project -// SPDX-License-Identifier: BSD-3-Clause - -use alloc::format; - -use blake2::Blake2b; -use digest::consts::U64; -use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; -use tari_crypto::{ - keys::PublicKey, - ristretto::{ - pedersen::{extended_commitment_factory::ExtendedPedersenCommitmentFactory, PedersenCommitment}, - RistrettoComAndPubSig, - RistrettoPublicKey, - RistrettoSecretKey, - }, -}; -use tari_hashing::TransactionHashDomain; - -use crate::{ - alloc::string::ToString, - hashing::DomainSeparatedConsensusHasher, - utils::{derive_from_bip32_key, get_key_from_canonical_bytes}, - AppSW, - KeyType, - RESPONSE_VERSION, -}; - -pub fn handler_get_metadata_signature(comm: &mut Comm) -> Result<(), AppSW> { - let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; - - let mut account_bytes = [0u8; 8]; - account_bytes.clone_from_slice(&data[0..8]); - let account = u64::from_le_bytes(account_bytes); - - let mut network_bytes = [0u8; 8]; - network_bytes.clone_from_slice(&data[8..16]); - let network = u64::from_le_bytes(network_bytes); - - let mut txo_version_bytes = [0u8; 8]; - txo_version_bytes.clone_from_slice(&data[16..24]); - let txo_version = u64::from_le_bytes(txo_version_bytes); - - let mut ephemeral_private_nonce_index_bytes = [0u8; 8]; - ephemeral_private_nonce_index_bytes.clone_from_slice(&data[24..32]); - let ephemeral_private_nonce_index = u64::from_le_bytes(ephemeral_private_nonce_index_bytes); - - let mut sender_offset_key_index_bytes = [0u8; 8]; - sender_offset_key_index_bytes.clone_from_slice(&data[32..40]); - let sender_offset_key_index = u64::from_le_bytes(sender_offset_key_index_bytes); - - let commitment: PedersenCommitment = get_key_from_canonical_bytes(&data[40..72])?; - let ephemeral_commitment: PedersenCommitment = get_key_from_canonical_bytes(&data[72..104])?; - - let mut metadata_signature_message = [0u8; 32]; - metadata_signature_message.clone_from_slice(&data[104..136]); - - let ephemeral_private_key = derive_from_bip32_key(account, ephemeral_private_nonce_index, KeyType::Nonce)?; - let ephemeral_pubkey = RistrettoPublicKey::from_secret_key(&ephemeral_private_key); - - let sender_offset_private_key = derive_from_bip32_key(account, sender_offset_key_index, KeyType::SenderOffset)?; - let sender_offset_public_key = RistrettoPublicKey::from_secret_key(&sender_offset_private_key); - - let challenge = finalize_metadata_signature_challenge( - txo_version, - network, - &sender_offset_public_key, - &ephemeral_commitment, - &ephemeral_pubkey, - &commitment, - &metadata_signature_message, - ); - - let factory = ExtendedPedersenCommitmentFactory::default(); - - let metadata_signature = match RistrettoComAndPubSig::sign( - &RistrettoSecretKey::default(), - &RistrettoSecretKey::default(), - &sender_offset_private_key, - &RistrettoSecretKey::default(), - &RistrettoSecretKey::default(), - &ephemeral_private_key, - &challenge, - &factory, - ) { - Ok(sig) => sig, - Err(e) => { - SingleMessage::new(&format!("Signing error: {:?}", e.to_string())).show_and_wait(); - return Err(AppSW::MetadataSignatureFail); - }, - }; - - comm.append(&[RESPONSE_VERSION]); // version - comm.append(&metadata_signature.to_vec()); - comm.reply_ok(); - - Ok(()) -} - -fn finalize_metadata_signature_challenge( - _version: u64, - network: u64, - sender_offset_public_key: &RistrettoPublicKey, - ephemeral_commitment: &PedersenCommitment, - ephemeral_pubkey: &RistrettoPublicKey, - commitment: &PedersenCommitment, - message: &[u8; 32], -) -> [u8; 64] { - let challenge = - DomainSeparatedConsensusHasher::>::new("metadata_signature", network) - .chain(ephemeral_pubkey) - .chain(ephemeral_commitment) - .chain(sender_offset_public_key) - .chain(commitment) - .chain(&message) - .finalize(); - - challenge.into() -} diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index 4eda1cdd54..e27c78b93c 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -15,7 +15,6 @@ mod app_ui { } mod handlers { pub mod get_dh_shared_secret; - pub mod get_metadata_signature; pub mod get_public_alpha; pub mod get_public_key; pub mod get_script_offset; @@ -30,7 +29,6 @@ use app_ui::menu::ui_menu_main; use critical_section::RawRestoreState; use handlers::{ get_dh_shared_secret::handler_get_dh_shared_secret, - get_metadata_signature::handler_get_metadata_signature, get_public_alpha::handler_get_public_alpha, get_public_key::handler_get_public_key, get_script_offset::{handler_get_script_offset, ScriptOffsetCtx}, @@ -117,7 +115,7 @@ pub enum Instruction { GetPublicAlpha, GetScriptSignature, GetScriptOffset { chunk: u8, more: bool }, - GetMetadataSignature, + GetScriptSignatureFromChallenge, GetViewKey, GetDHSharedSecret, } @@ -144,7 +142,7 @@ impl KeyType { fn from_branch_key(n: u64) -> Self { match n { 1 => Self::Alpha, - 6 => Self::SenderOffset, + 7 => Self::SenderOffset, 5 | 2 | _ => Self::Nonce, } } @@ -175,7 +173,7 @@ impl TryFrom for Instruction { chunk: value.p1, more: value.p2 == P2_MORE, }), - (0x07, 0, 0) => Ok(Instruction::GetMetadataSignature), + (0x08, 0, 0) => Ok(Instruction::GetScriptSignatureFromChallenge), (0x09, 0, 0) => Ok(Instruction::GetViewKey), (0x10, 0, 0) => Ok(Instruction::GetDHSharedSecret), (0x06, _, _) => Err(AppSW::WrongP1P2), @@ -223,7 +221,7 @@ fn handle_apdu(comm: &mut Comm, ins: Instruction, offset_ctx: &mut ScriptOffsetC Instruction::GetPublicAlpha => handler_get_public_alpha(comm), Instruction::GetScriptSignature => handler_get_script_signature(comm), Instruction::GetScriptOffset { chunk, more } => handler_get_script_offset(comm, chunk, more, offset_ctx), - Instruction::GetMetadataSignature => handler_get_metadata_signature(comm), + Instruction::GetScriptSignatureFromChallenge => handler_get_script_signature_from_challenge(comm), Instruction::GetViewKey => handler_get_view_key(comm), Instruction::GetDHSharedSecret => handler_get_dh_shared_secret(comm), } diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 9dfed11033..a8d48a37ea 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -50,8 +50,6 @@ use tari_crypto::{ }, }; use tari_hashing::KeyManagerTransactionsHashDomain; -#[cfg(feature = "ledger")] -use tari_key_manager::error::KeyManagerError; use tari_key_manager::{ cipher_seed::CipherSeed, key_manager::KeyManager, @@ -212,9 +210,7 @@ where TBackend: KeyManagerBackend + 'static // SenderOffset than we fetch from the ledger, all other keys are fetched below. #[allow(unused_variables)] if let WalletType::Ledger(ledger) = &self.wallet_type { - if branch == &TransactionKeyManagerBranch::MetadataEphemeralNonce.get_branch_key() || - branch == &TransactionKeyManagerBranch::SenderOffset.get_branch_key() - { + if branch == &TransactionKeyManagerBranch::SenderOffsetLedger.get_branch_key() { #[cfg(not(feature = "ledger"))] { return Err(KeyManagerServiceError::LedgerError( @@ -472,9 +468,9 @@ where TBackend: KeyManagerBackend + 'static // If we're trying to access any of the private keys, just say no bueno if &TransactionKeyManagerBranch::Alpha.get_branch_key() == branch || - &TransactionKeyManagerBranch::SenderOffset.get_branch_key() == branch || - &TransactionKeyManagerBranch::MetadataEphemeralNonce.get_branch_key() == branch + &TransactionKeyManagerBranch::SenderOffsetLedger.get_branch_key() == branch { + debug!(target: LOG_TARGET, "Attempted to access private key for branch {branch:?}"); return Err(KeyManagerServiceError::LedgerPrivateKeyInaccessible); } }; @@ -559,7 +555,7 @@ where TBackend: KeyManagerBackend + 'static #[allow(unused_variables)] if let WalletType::Ledger(ledger) = &self.wallet_type { if let KeyId::Managed { branch, index } = secret_key_id { - if branch == &TransactionKeyManagerBranch::SenderOffset.get_branch_key() { + if branch == &TransactionKeyManagerBranch::SenderOffsetLedger.get_branch_key() { #[cfg(not(feature = "ledger"))] { return Err(TransactionError::LedgerNotSupported); @@ -586,7 +582,7 @@ where TBackend: KeyManagerBackend + 'static #[allow(unused_variables)] if let WalletType::Ledger(ledger) = &self.wallet_type { if let KeyId::Managed { branch, index } = secret_key_id { - if branch == &TransactionKeyManagerBranch::SenderOffset.get_branch_key() { + if branch == &TransactionKeyManagerBranch::SenderOffsetLedger.get_branch_key() { #[cfg(not(feature = "ledger"))] { return Err(TransactionError::LedgerNotSupported); @@ -1176,99 +1172,31 @@ where TBackend: KeyManagerBackend + 'static txo_version: &TransactionOutputVersion, metadata_signature_message: &[u8; 32], ) -> Result { - match &self.wallet_type { - WalletType::Software => { - let ephemeral_private_key = self.get_private_key(ephemeral_private_nonce_id).await?; - let ephemeral_pubkey = PublicKey::from_secret_key(&ephemeral_private_key); - PublicKey::from_secret_key(&ephemeral_private_key); - let sender_offset_private_key = self.get_private_key(sender_offset_key_id).await?; // Take the index and use it to find the key from ledger - let sender_offset_public_key = PublicKey::from_secret_key(&sender_offset_private_key); - - let challenge = TransactionOutput::finalize_metadata_signature_challenge( - txo_version, - &sender_offset_public_key, - ephemeral_commitment, - &ephemeral_pubkey, - commitment, - metadata_signature_message, - ); - - let metadata_signature = ComAndPubSignature::sign( - &PrivateKey::default(), - &PrivateKey::default(), - &sender_offset_private_key, - &PrivateKey::default(), - &PrivateKey::default(), - &ephemeral_private_key, - &challenge, - &*self.crypto_factories.commitment, - )?; - Ok(metadata_signature) - }, - #[allow(unused_variables)] - WalletType::Ledger(ledger) => { - #[cfg(not(feature = "ledger"))] - { - Err(TransactionError::LedgerNotSupported) - } - - #[cfg(feature = "ledger")] - { - let ephemeral_private_nonce_index = - ephemeral_private_nonce_id - .managed_index() - .ok_or(TransactionError::KeyManagerError( - KeyManagerError::InvalidKeyID.to_string(), - ))?; - let sender_offset_key_index = - sender_offset_key_id - .managed_index() - .ok_or(TransactionError::KeyManagerError( - KeyManagerError::InvalidKeyID.to_string(), - ))?; + let ephemeral_private_key = self.get_private_key(ephemeral_private_nonce_id).await?; + let ephemeral_pubkey = PublicKey::from_secret_key(&ephemeral_private_key); + let sender_offset_private_key = self.get_private_key(sender_offset_key_id).await?; // Take the index and use it to find the key from ledger + let sender_offset_public_key = PublicKey::from_secret_key(&sender_offset_private_key); - let mut data = u64::from(ledger.network.as_byte()).to_le_bytes().to_vec(); - data.extend_from_slice(&u64::from(txo_version.as_u8()).to_le_bytes()); - data.extend_from_slice(&ephemeral_private_nonce_index.to_le_bytes()); - data.extend_from_slice(&sender_offset_key_index.to_le_bytes()); - data.extend_from_slice(&commitment.to_vec()); - data.extend_from_slice(&ephemeral_commitment.to_vec()); - data.extend_from_slice(&metadata_signature_message.to_vec()); - - let command = ledger.build_command(Instruction::GetMetadataSignature, data); - let transport = get_transport()?; + let challenge = TransactionOutput::finalize_metadata_signature_challenge( + txo_version, + &sender_offset_public_key, + ephemeral_commitment, + &ephemeral_pubkey, + commitment, + metadata_signature_message, + ); - match command.execute_with_transport(&transport) { - Ok(result) => { - if result.data().len() < 161 { - debug!(target: LOG_TARGET, "result less than 161"); - return Err(LedgerDeviceError::Processing(format!( - "'get_metadata_signature' insufficient data - expected 161 got {} bytes ({:?})", - result.data().len(), - result - )) - .into()); - } - let data = result.data(); - debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); - Ok(ComAndPubSignature::new( - Commitment::from_canonical_bytes(&data[1..33]) - .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, - PublicKey::from_canonical_bytes(&data[33..65]) - .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, - PrivateKey::from_canonical_bytes(&data[65..97]) - .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, - PrivateKey::from_canonical_bytes(&data[97..129]) - .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, - PrivateKey::from_canonical_bytes(&data[129..161]) - .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, - )) - }, - Err(e) => Err(LedgerDeviceError::Instruction(format!("GetMetadataSignature: {}", e)).into()), - } - } - }, - } + let metadata_signature = ComAndPubSignature::sign( + &PrivateKey::default(), + &PrivateKey::default(), + &sender_offset_private_key, + &PrivateKey::default(), + &PrivateKey::default(), + &ephemeral_private_key, + &challenge, + &*self.crypto_factories.commitment, + )?; + Ok(metadata_signature) } // ----------------------------------------------------------------------------------------------------------------- diff --git a/base_layer/core/src/transactions/key_manager/interface.rs b/base_layer/core/src/transactions/key_manager/interface.rs index c7b1eeed8a..0d9ca012c5 100644 --- a/base_layer/core/src/transactions/key_manager/interface.rs +++ b/base_layer/core/src/transactions/key_manager/interface.rs @@ -64,6 +64,7 @@ pub enum TransactionKeyManagerBranch { Nonce = 0x04, KernelNonce = 0x05, SenderOffset = 0x06, + SenderOffsetLedger = 0x07, } impl TransactionKeyManagerBranch { @@ -78,6 +79,7 @@ impl TransactionKeyManagerBranch { TransactionKeyManagerBranch::MetadataEphemeralNonce => "metadata ephemeral nonce".to_string(), TransactionKeyManagerBranch::KernelNonce => "kernel nonce".to_string(), TransactionKeyManagerBranch::SenderOffset => "sender offset".to_string(), + TransactionKeyManagerBranch::SenderOffsetLedger => "sender offset ledger".to_string(), } } @@ -89,6 +91,7 @@ impl TransactionKeyManagerBranch { "metadata ephemeral nonce" => TransactionKeyManagerBranch::MetadataEphemeralNonce, "kernel nonce" => TransactionKeyManagerBranch::KernelNonce, "sender offset" => TransactionKeyManagerBranch::SenderOffset, + "sender offset ledger" => TransactionKeyManagerBranch::SenderOffsetLedger, "nonce" => TransactionKeyManagerBranch::Nonce, _ => TransactionKeyManagerBranch::Nonce, } diff --git a/base_layer/core/src/transactions/transaction_protocol/sender.rs b/base_layer/core/src/transactions/transaction_protocol/sender.rs index 04b58100ee..5d602620b0 100644 --- a/base_layer/core/src/transactions/transaction_protocol/sender.rs +++ b/base_layer/core/src/transactions/transaction_protocol/sender.rs @@ -342,6 +342,22 @@ impl SenderTransactionProtocol { } } + pub fn change_recipient_sender_offset_private_key(&mut self, key_id: TariKeyId) -> Result<(), TPE> { + match &mut self.state { + SenderState::Initializing(ref mut info) | + SenderState::Finalizing(ref mut info) | + SenderState::SingleRoundMessageReady(ref mut info) | + SenderState::CollectingSingleSignature(ref mut info) => { + if let Some(ref mut v) = info.recipient_data { + v.recipient_sender_offset_key_id = key_id; + } + }, + SenderState::FinalizedTransaction(_) | SenderState::Failed(_) => return Err(TPE::InvalidStateError), + } + + Ok(()) + } + /// This function will return the value of the fee of this transaction pub fn get_fee_amount(&self) -> Result { match &self.state { diff --git a/base_layer/wallet/src/transaction_service/service.rs b/base_layer/wallet/src/transaction_service/service.rs index b202632fa1..2e640b6dc0 100644 --- a/base_layer/wallet/src/transaction_service/service.rs +++ b/base_layer/wallet/src/transaction_service/service.rs @@ -54,7 +54,7 @@ use tari_core::{ }, proto::{base_node as base_node_proto, base_node::FetchMatchingUtxos}, transactions::{ - key_manager::{TariKeyId, TransactionKeyManagerInterface}, + key_manager::{TariKeyId, TransactionKeyManagerBranch, TransactionKeyManagerInterface}, tari_amount::MicroMinotari, transaction_components::{ encrypted_data::PaymentId, @@ -1840,6 +1840,13 @@ where // This call is needed to advance the state from `SingleRoundMessageReady` to `SingleRoundMessageReady`, // but the returned value is not used. We have to wait until the sender transaction protocol creates a // sender_offset_private_key for us, so we can use it to create the shared secret + let (key, _) = self + .resources + .transaction_key_manager_service + .get_next_key(TransactionKeyManagerBranch::SenderOffsetLedger.get_branch_key()) + .await?; + + stp.change_recipient_sender_offset_private_key(key)?; let _single_round_sender_data = stp .build_single_round_message(&self.resources.transaction_key_manager_service) .await