diff --git a/swap/src/bitcoin/redeem.rs b/swap/src/bitcoin/redeem.rs index bc670da4..0a7888c5 100644 --- a/swap/src/bitcoin/redeem.rs +++ b/swap/src/bitcoin/redeem.rs @@ -1,12 +1,16 @@ use crate::bitcoin::{ - verify_sig, Address, EmptyWitnessStack, NoInputs, NotThreeWitnesses, PublicKey, TooManyInputs, - Transaction, TxLock, + verify_encsig, verify_sig, Address, EmptyWitnessStack, EncryptedSignature, NoInputs, + NotThreeWitnesses, PublicKey, SecretKey, TooManyInputs, Transaction, TxLock, }; use ::bitcoin::util::bip143::SigHashCache; use ::bitcoin::{SigHash, SigHashType, Txid}; use anyhow::{bail, Context, Result}; +use ecdsa_fun::adaptor::{Adaptor, HashTranscript}; +use ecdsa_fun::fun::Scalar; +use ecdsa_fun::nonce::Deterministic; use ecdsa_fun::Signature; use miniscript::{Descriptor, DescriptorTrait}; +use sha2::Sha256; use std::collections::HashMap; #[derive(Debug, Clone)] @@ -44,17 +48,31 @@ impl TxRedeem { self.digest } - pub fn add_signatures( - self, - (A, sig_a): (PublicKey, Signature), - (B, sig_b): (PublicKey, Signature), + pub fn complete( + mut self, + encrypted_signature: EncryptedSignature, + a: SecretKey, + s_a: Scalar, + B: PublicKey, ) -> Result { + verify_encsig( + B, + PublicKey::from(s_a.clone()), + &self.digest(), + &encrypted_signature, + ) + .context("Invalid encrypted signature received")?; + + let sig_a = a.sign(self.digest()); + let adaptor = Adaptor::, Deterministic>::default(); + let sig_b = adaptor.decrypt_signature(&s_a, encrypted_signature); + let satisfier = { let mut satisfier = HashMap::with_capacity(2); let A = ::bitcoin::PublicKey { compressed: true, - key: A.0.into(), + key: a.public.into(), }; let B = ::bitcoin::PublicKey { compressed: true, @@ -68,11 +86,11 @@ impl TxRedeem { satisfier }; - let mut tx_redeem = self.inner; self.lock_output_descriptor - .satisfy(&mut tx_redeem.input[0], satisfier)?; + .satisfy(&mut self.inner.input[0], satisfier) + .context("Failed to sign Bitcoin redeem transaction")?; - Ok(tx_redeem) + Ok(self.inner) } pub fn extract_signature_by_key( diff --git a/swap/src/protocol/alice/steps.rs b/swap/src/protocol/alice/steps.rs index ec959ac7..b44f1e61 100644 --- a/swap/src/protocol/alice/steps.rs +++ b/swap/src/protocol/alice/steps.rs @@ -7,12 +7,9 @@ use crate::protocol::alice::event_loop::EventLoopHandle; use crate::protocol::alice::TransferProof; use crate::{bitcoin, monero}; use anyhow::{Context, Result}; -use ecdsa_fun::adaptor::{Adaptor, HashTranscript}; -use ecdsa_fun::nonce::Deterministic; use futures::future::{select, Either}; use futures::pin_mut; use libp2p::PeerId; -use sha2::Sha256; pub async fn lock_xmr( bob_peer_id: PeerId, @@ -56,36 +53,6 @@ pub async fn wait_for_bitcoin_encrypted_signature( Ok(msg3.tx_redeem_encsig) } -pub fn build_bitcoin_redeem_transaction( - encrypted_signature: EncryptedSignature, - tx_lock: &TxLock, - a: bitcoin::SecretKey, - s_a: ecdsa_fun::fun::Scalar, - B: bitcoin::PublicKey, - redeem_address: &bitcoin::Address, -) -> Result { - let adaptor = Adaptor::, Deterministic>::default(); - - let tx_redeem = bitcoin::TxRedeem::new(tx_lock, redeem_address); - - bitcoin::verify_encsig( - B, - bitcoin::PublicKey::from(s_a.clone()), - &tx_redeem.digest(), - &encrypted_signature, - ) - .context("Invalid encrypted signature received")?; - - let sig_a = a.sign(tx_redeem.digest()); - let sig_b = adaptor.decrypt_signature(&s_a, encrypted_signature); - - let tx = tx_redeem - .add_signatures((a.public(), sig_a), (B, sig_b)) - .context("Failed to sign Bitcoin redeem transaction")?; - - Ok(tx) -} - pub async fn publish_cancel_transaction( tx_lock: TxLock, a: bitcoin::SecretKey, diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 93064260..12a72fbc 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -1,15 +1,14 @@ //! Run an XMR/BTC swap in the role of Alice. //! Alice holds XMR and wishes receive BTC. -use crate::bitcoin::ExpiredTimelocks; +use crate::bitcoin::{ExpiredTimelocks, TxRedeem}; use crate::database::Database; use crate::execution_params::ExecutionParams; use crate::monero_ext::ScalarExt; use crate::protocol::alice; use crate::protocol::alice::event_loop::EventLoopHandle; use crate::protocol::alice::steps::{ - build_bitcoin_punish_transaction, build_bitcoin_redeem_transaction, extract_monero_private_key, - lock_xmr, publish_cancel_transaction, wait_for_bitcoin_encrypted_signature, - wait_for_bitcoin_refund, + build_bitcoin_punish_transaction, extract_monero_private_key, lock_xmr, + publish_cancel_transaction, wait_for_bitcoin_encrypted_signature, wait_for_bitcoin_refund, }; use crate::protocol::alice::AliceState; use crate::{bitcoin, database, monero}; @@ -203,13 +202,13 @@ async fn run_until_internal( } => { let state = match state3.expired_timelocks(bitcoin_wallet.as_ref()).await? { ExpiredTimelocks::None => { - match build_bitcoin_redeem_transaction( + let tx_redeem = TxRedeem::new(&state3.tx_lock, &state3.redeem_address); + + match tx_redeem.complete( *encrypted_signature, - &state3.tx_lock, state3.a.clone(), state3.s_a.to_secpfun_scalar(), state3.B, - &state3.redeem_address, ) { Ok(tx) => match bitcoin_wallet.broadcast(tx, "redeem").await { Ok(txid) => {