diff --git a/applications/minotari_console_wallet/src/automation/commands.rs b/applications/minotari_console_wallet/src/automation/commands.rs index 2454c1f8a6..4d137e504f 100644 --- a/applications/minotari_console_wallet/src/automation/commands.rs +++ b/applications/minotari_console_wallet/src/automation/commands.rs @@ -1387,7 +1387,7 @@ pub async fn command_runner( #[allow(clippy::mutable_key_type)] let mut input_shares = HashMap::new(); - let mut script_signature_public_nonces = Vec::with_capacity(args.input_file_names.len()); + let mut script_signature_public_nonce_shares = Vec::with_capacity(args.input_file_names.len()); let mut sender_offset_public_key_shares = Vec::with_capacity(args.input_file_names.len()); let mut metadata_ephemeral_public_key_shares = Vec::with_capacity(args.input_file_names.len()); let mut dh_shared_secret_shares = Vec::with_capacity(args.input_file_names.len()); @@ -1399,7 +1399,7 @@ pub async fn command_runner( &session_info, )?; input_shares.insert(party_info.pre_mine_public_script_key, party_info.script_input_signature); - script_signature_public_nonces.push(party_info.public_script_nonce_key); + script_signature_public_nonce_shares.push(party_info.public_script_nonce_key); sender_offset_public_key_shares.push(party_info.public_sender_offset_key); metadata_ephemeral_public_key_shares.push(party_info.public_sender_offset_nonce_key); dh_shared_secret_shares.push(party_info.dh_shared_secret_public_key); @@ -1412,7 +1412,7 @@ pub async fn command_runner( .map_err(|e| CommandError::InvalidArgument(e.to_string()))?, Commitment::from_hex(&session_info.commitment_to_spend)?, input_shares, - script_signature_public_nonces, + script_signature_public_nonce_shares, sender_offset_public_key_shares, metadata_ephemeral_public_key_shares, dh_shared_secret_shares, diff --git a/base_layer/core/src/transactions/transaction_components/wallet_output.rs b/base_layer/core/src/transactions/transaction_components/wallet_output.rs index 7ca6de7201..d458c3ab9f 100644 --- a/base_layer/core/src/transactions/transaction_components/wallet_output.rs +++ b/base_layer/core/src/transactions/transaction_components/wallet_output.rs @@ -30,6 +30,7 @@ use std::{ use serde::{Deserialize, Serialize}; use tari_common_types::types::{ComAndPubSignature, Commitment, FixedHash, PublicKey, RangeProof}; +use tari_key_manager::key_manager_service::KeyAndId; use tari_script::{ExecutionStack, TariScript}; use super::TransactionOutputVersion; @@ -303,6 +304,81 @@ impl WalletOutput { Ok((input, script_public_key)) } + // /// It creates a transaction input given an updated multi-party script public keys and nonces. The inputs + // /// `script_signature_public_nonces` and `script_public_key_shares` exclude the caller's data. + // pub async fn to_transaction_input_with_multi_party_script_signature_2( + // &self, + // script_signature_public_nonce_shares: &[PublicKey], + // script_input_public_key_shares: &[PublicKey], + // key_manager: &KM, + // script_key: &KeyAndId, + // ) -> Result<(TransactionInput, PublicKey, PublicKey), TransactionError> { + // if script_key.key_id != self.script_key_id { + // return Err(TransactionError::KeyManagerError(format!( + // "Cached script key does not match self - cached: {}, expected {}", + // script_key.key_id, self.script_key_id + // ))); + // } + // let value = self.value.into(); + // let version = TransactionInputVersion::get_current_version(); + // let commitment = key_manager.get_commitment(&self.commitment_mask_key_id, &value).await?; + // let message = TransactionInput::build_script_signature_message(&version, &self.script, &self.input_data); + // + // let aggregated_script_public_key = script_input_public_key_shares + // .iter() + // .fold(script_key.pub_key.clone(), |acc, x| acc + x); + // + // let ephemeral_public_key_self = key_manager.get_random_key().await?; + // let aggregated_ephemeral_public_key = script_signature_public_nonce_shares + // .iter() + // .fold(ephemeral_public_key_self.pub_key.clone(), |acc, x| acc + x); + // + // let commitment_partial_script_signature = key_manager + // .get_partial_script_signature( + // &self.commitment_mask_key_id, + // &value, + // &version, + // &aggregated_ephemeral_public_key, + // &aggregated_script_public_key, + // &message, + // ) + // .await?; + // let challenge = TransactionInput::finalize_script_signature_challenge( + // &version, + // commitment_partial_script_signature.ephemeral_commitment(), + // &aggregated_ephemeral_public_key, + // &aggregated_script_public_key, + // &commitment, + // &message, + // ); + // let script_key_partial_script_signature = key_manager + // .sign_with_nonce_and_challenge(&script_key.key_id, &ephemeral_public_key_self.key_id, &challenge) + // .await?; + // let script_signature = &commitment_partial_script_signature + &script_key_partial_script_signature; + // + // let input = TransactionInput::new_current_version( + // SpentOutput::OutputData { + // features: self.features.clone(), + // commitment, + // script: self.script.clone(), + // sender_offset_public_key: self.sender_offset_public_key.clone(), + // covenant: self.covenant.clone(), + // encrypted_data: self.encrypted_data.clone(), + // metadata_signature: self.metadata_signature.clone(), + // version: self.version, + // minimum_value_promise: self.minimum_value_promise, + // rangeproof_hash: match &self.range_proof { + // Some(rp) => rp.hash(), + // None => FixedHash::zero(), + // }, + // }, + // self.input_data.clone(), + // script_signature, + // ); + // + // Ok((input, aggregated_script_public_key, aggregated_ephemeral_public_key)) + // } + /// Commits an WalletOutput into a TransactionInput that only contains the hash of the spent output data pub async fn to_compact_transaction_input( &self, diff --git a/base_layer/wallet/src/output_manager_service/service.rs b/base_layer/wallet/src/output_manager_service/service.rs index b1ba319885..2fd278430a 100644 --- a/base_layer/wallet/src/output_manager_service/service.rs +++ b/base_layer/wallet/src/output_manager_service/service.rs @@ -1178,7 +1178,7 @@ where output_hash: HashOutput, expected_commitment: PedersenCommitment, mut script_input_shares: HashMap, - script_signature_public_nonces: Vec, + script_signature_public_nonce_shares: Vec, sender_offset_public_key_shares: Vec, metadata_ephemeral_public_key_shares: Vec, dh_shared_secret_shares: Vec, @@ -1247,12 +1247,16 @@ where .iter() .fold(tari_common_types::types::PublicKey::default(), |acc, x| acc + x); let encryption_private_key = public_key_to_output_encryption_key(&sum_public_keys)?; - let mut aggregated_script_public_key_shares = PublicKey::default(); trace!(target: LOG_TARGET, "encumber_aggregate_utxo: created deterministic encryption key"); // Decrypt the output secrets and create a new input as WalletOutput (unblinded) let input = if let Ok((amount, commitment_mask, payment_id)) = EncryptedData::decrypt_data(&encryption_private_key, &output.commitment, &output.encrypted_data) { + // let index if let PaymentId::U64(val) = payment_id { + // val + // } else { + // + // } if output.verify_mask(&self.resources.factories.range_proof, &commitment_mask, amount.as_u64())? { let mut script_signatures = Vec::new(); // lets add our own signature to the list @@ -1268,10 +1272,6 @@ where for key in multi_sig_public_keys { if let Some(signature) = script_input_shares.get(&key) { script_signatures.push(StackItem::Signature(signature.clone())); - // our own key should not be aggregated yet, it will be added with the script signing - if key != script_key.pub_key { - aggregated_script_public_key_shares = aggregated_script_public_key_shares + key; - } } } if script_signatures.len() != usize::from(*threshold) { @@ -1290,7 +1290,7 @@ where output.features, output.script, ExecutionStack::new(script_signatures), - script_key.key_id, // Only of the master wallet + script_key.key_id.clone(), // Only of the master wallet output.sender_offset_public_key, output.metadata_signature, 0, @@ -1462,7 +1462,7 @@ where .await? .with_input_data(ExecutionStack::default()) // Just a placeholder in the wallet .with_sender_offset_public_key(sender_offset_public_key) - .with_script_key(self.resources.key_manager.get_spend_key().await?.key_id) + .with_script_key(TariKeyId::default()) // One-sided receiver will control this .with_minimum_value_promise(minimum_value_promise) .sign_partial_as_sender_and_receiver( &self.resources.key_manager, @@ -1496,11 +1496,16 @@ where info!(target: LOG_TARGET, "Finalized partial one-side transaction TxId: {}", tx_id); trace!(target: LOG_TARGET, "encumber_aggregate_utxo: finalized partial transaction"); - let aggregated_script_signature_public_nonces = script_signature_public_nonces + // Update the input's script signature + let script_input_public_key_shares = script_input_shares.keys().cloned().collect::>(); + let aggregated_script_public_key_shares = script_input_public_key_shares + .iter() + .fold(PublicKey::default(), |acc, x| acc + x); + + let aggregated_script_signature_public_nonces = script_signature_public_nonce_shares .iter() .fold(PublicKey::default(), |acc, x| acc + x); - // Update the input's script signature let (updated_input, total_script_public_key) = input .to_transaction_input_with_multi_party_script_signature( &aggregated_script_signature_public_nonces, @@ -1508,10 +1513,21 @@ where &self.resources.key_manager, ) .await?; - trace!(target: LOG_TARGET, "encumber_aggregate_utxo: updated script input signature"); - let total_script_nonce = aggregated_script_signature_public_nonces + updated_input.script_signature.ephemeral_pubkey(); + + // // Update the input's script signature + // let (updated_input, total_script_public_key, total_script_nonce) = input + // .to_transaction_input_with_multi_party_script_signature_2( + // &script_signature_public_nonce_shares, + // &script_input_public_key_shares, + // &self.resources.key_manager, + // &script_key, + // ) + // .await?; + + trace!(target: LOG_TARGET, "encumber_aggregate_utxo: updated script input signature"); + let mut tx = stp.get_transaction()?.clone(); let mut tx_body = tx.body; tx_body.update_script_signature(updated_input.commitment()?, updated_input.script_signature.clone())?;