diff --git a/Cargo.lock b/Cargo.lock index 577db90300..6b6b82b193 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4909,6 +4909,7 @@ dependencies = [ "tui", "unicode-segmentation", "unicode-width", + "zeroize", ] [[package]] diff --git a/applications/tari_console_wallet/Cargo.toml b/applications/tari_console_wallet/Cargo.toml index 906ffa9f28..3a6c948589 100644 --- a/applications/tari_console_wallet/Cargo.toml +++ b/applications/tari_console_wallet/Cargo.toml @@ -19,6 +19,7 @@ tari_app_grpc = { path = "../tari_app_grpc" } tari_shutdown = { path = "../../infrastructure/shutdown" } tari_key_manager = { path = "../../base_layer/key_manager" } tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +zeroize = "1.5" # Uncomment for tokio tracing via tokio-console (needs "tracing" featurs) #console-subscriber = "0.1.3" diff --git a/applications/tari_console_wallet/src/automation/commands.rs b/applications/tari_console_wallet/src/automation/commands.rs index e3461968a6..8eda5cb36e 100644 --- a/applications/tari_console_wallet/src/automation/commands.rs +++ b/applications/tari_console_wallet/src/automation/commands.rs @@ -57,7 +57,7 @@ use tari_utilities::{hex::Hex, ByteArray}; use tari_wallet::{ connectivity_service::WalletConnectivityInterface, error::WalletError, - key_manager_service::NextKeyResult, + key_manager_service::{KeyManagerInterface, NextKeyResult}, output_manager_service::{handle::OutputManagerHandle, UtxoSelectionCriteria}, transaction_service::handle::{TransactionEvent, TransactionServiceHandle}, TransactionStage, @@ -68,6 +68,7 @@ use tokio::{ sync::{broadcast, mpsc}, time::{sleep, timeout}, }; +use zeroize::Zeroizing; use super::error::CommandError; use crate::{ @@ -84,6 +85,7 @@ pub enum WalletCommand { GetBalance, SendTari, SendOneSided, + CreateKeyPair, MakeItRain, CoinSplit, DiscoverPeer, @@ -583,6 +585,7 @@ pub async fn command_runner( let mut transaction_service = wallet.transaction_service.clone(); let mut output_service = wallet.output_manager_service.clone(); + let key_manager_service = wallet.key_manager_service.clone(); let dht_service = wallet.dht_service.discovery_service_requester().clone(); let connectivity_requester = wallet.comms.connectivity(); let mut online = false; @@ -637,6 +640,18 @@ pub async fn command_runner( Err(e) => eprintln!("BurnTari error! {}", e), } }, + CreateKeyPair(args) => match key_manager_service.create_key_pair(args.key_branch).await { + Ok((sk, pk)) => { + println!( + "New key pair: + 1. secret key: {}, + 2. public key: {}", + *Zeroizing::new(sk.to_hex()), + pk.to_hex() + ) + }, + Err(e) => eprintln!("CreateKeyPair error! {}", e), + }, SendTari(args) => { match send_tari( transaction_service.clone(), diff --git a/applications/tari_console_wallet/src/cli.rs b/applications/tari_console_wallet/src/cli.rs index 96b3faf5af..6cc735be6b 100644 --- a/applications/tari_console_wallet/src/cli.rs +++ b/applications/tari_console_wallet/src/cli.rs @@ -116,6 +116,7 @@ pub enum CliCommands { GetBalance, SendTari(SendTariArgs), BurnTari(BurnTariArgs), + CreateKeyPair(CreateKeyPairArgs), SendOneSided(SendTariArgs), SendOneSidedToStealthAddress(SendTariArgs), MakeItRain(MakeItRainArgs), @@ -155,6 +156,11 @@ pub struct BurnTariArgs { pub message: String, } +#[derive(Debug, Args, Clone)] +pub struct CreateKeyPairArgs { + pub key_branch: String, +} + #[derive(Debug, Args, Clone)] pub struct MakeItRainArgs { pub destination: UniPublicKey, diff --git a/applications/tari_console_wallet/src/wallet_modes.rs b/applications/tari_console_wallet/src/wallet_modes.rs index 9bf3e65b38..c06c635fb6 100644 --- a/applications/tari_console_wallet/src/wallet_modes.rs +++ b/applications/tari_console_wallet/src/wallet_modes.rs @@ -429,6 +429,8 @@ mod test { burn-tari --message Ups_these_funds_will_be_burned! 100T + create-key-pair pie + coin-split --message Make_many_dust_UTXOs! --fee-per-gram 2 0.001T 499 make-it-rain --duration 100 --transactions-per-second 10 --start-amount 0.009200T --increase-amount 0T \ @@ -444,6 +446,7 @@ mod test { let mut get_balance = false; let mut send_tari = false; let mut burn_tari = false; + let mut create_key_pair = false; let mut make_it_rain = false; let mut coin_split = false; let mut discover_peer = false; @@ -453,6 +456,7 @@ mod test { CliCommands::GetBalance => get_balance = true, CliCommands::SendTari(_) => send_tari = true, CliCommands::BurnTari(_) => burn_tari = true, + CliCommands::CreateKeyPair(_) => create_key_pair = true, CliCommands::SendOneSided(_) => {}, CliCommands::SendOneSidedToStealthAddress(_) => {}, CliCommands::MakeItRain(_) => make_it_rain = true, @@ -472,6 +476,15 @@ mod test { CliCommands::HashGrpcPassword(_) => {}, } } - assert!(get_balance && send_tari && burn_tari && make_it_rain && coin_split && discover_peer && whois); + assert!( + get_balance && + send_tari && + burn_tari && + create_key_pair && + make_it_rain && + coin_split && + discover_peer && + whois + ); } } diff --git a/base_layer/wallet/src/key_manager_service/handle.rs b/base_layer/wallet/src/key_manager_service/handle.rs index 78b1454e06..d53be0e37b 100644 --- a/base_layer/wallet/src/key_manager_service/handle.rs +++ b/base_layer/wallet/src/key_manager_service/handle.rs @@ -23,7 +23,7 @@ use std::sync::Arc; use chacha20poly1305::XChaCha20Poly1305; -use tari_common_types::types::PrivateKey; +use tari_common_types::types::{PrivateKey, PublicKey}; use tari_key_manager::cipher_seed::CipherSeed; use tokio::sync::RwLock; @@ -73,6 +73,24 @@ where TBackend: KeyManagerBackend + 'static (*self.key_manager_inner).write().await.apply_encryption(cipher) } + async fn create_key_pair + Send>( + &self, + branch: T, + ) -> Result<(PrivateKey, PublicKey), KeyManagerServiceError> { + let branch: String = branch.into(); + + self.key_manager_inner + .write() + .await + .add_key_manager_branch(branch.clone())?; + + let next_key = self.get_next_key(branch).await?; + let sk = next_key.key.clone(); + let pk = next_key.to_public_key(); + + Ok((sk, pk)) + } + async fn remove_encryption(&self) -> Result<(), KeyManagerServiceError> { (*self.key_manager_inner).write().await.remove_encryption() } diff --git a/base_layer/wallet/src/key_manager_service/interface.rs b/base_layer/wallet/src/key_manager_service/interface.rs index a03266e03c..fed1c2d680 100644 --- a/base_layer/wallet/src/key_manager_service/interface.rs +++ b/base_layer/wallet/src/key_manager_service/interface.rs @@ -72,6 +72,12 @@ pub trait KeyManagerInterface: Clone + Send + Sync + 'static { index: u64, ) -> Result; + /// Gets new key combo pair out of a key seed + async fn create_key_pair + Send>( + &self, + branch: T, + ) -> Result<(PrivateKey, PublicKey), KeyManagerServiceError>; + /// Searches the branch to find the index used to generated the key, O(N) where N = index used. async fn find_key_index + Send>( &self, diff --git a/base_layer/wallet/src/key_manager_service/mock.rs b/base_layer/wallet/src/key_manager_service/mock.rs index 3a9ba2a3da..c1f737126d 100644 --- a/base_layer/wallet/src/key_manager_service/mock.rs +++ b/base_layer/wallet/src/key_manager_service/mock.rs @@ -22,7 +22,7 @@ use chacha20poly1305::XChaCha20Poly1305; use log::*; -use tari_common_types::types::PrivateKey; +use tari_common_types::types::{PrivateKey, PublicKey}; use tari_key_manager::{cipher_seed::CipherSeed, key_manager::KeyManager}; use tokio::sync::RwLock; @@ -162,6 +162,13 @@ impl KeyManagerInterface for KeyManagerMock { unimplemented!("Not supported"); } + async fn create_key_pair + Send>( + &self, + _branch: T, + ) -> Result<(PrivateKey, PublicKey), KeyManagerServiceError> { + unimplemented!("Not supported"); + } + async fn find_key_index + Send>( &self, branch: T,