From 2e78e153c45d25240b1ca5dd2ad58ae34689a9d1 Mon Sep 17 00:00:00 2001 From: chris-belcher Date: Tue, 29 Jun 2021 23:32:46 +0100 Subject: [PATCH] Add time/hashlock privkey to WalletSwapCoin struct --- src/contracts.rs | 34 ++++++++++++++++++++++++++++++++-- src/maker_protocol.rs | 7 ++++--- src/taker_protocol.rs | 26 +++++++++++++++----------- src/wallet_sync.rs | 39 +++++++++++++++++++++------------------ 4 files changed, 72 insertions(+), 34 deletions(-) diff --git a/src/contracts.rs b/src/contracts.rs index 49bf4393..669c3af5 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -121,6 +121,18 @@ fn read_locktime_from_contract(redeemscript: &Script) -> Option { } } +pub fn read_hashlock_pubkey_from_contract( + redeemscript: &Script, +) -> Result { + PublicKey::from_slice(&redeemscript.to_bytes()[27..60]) +} + +pub fn read_timelock_pubkey_from_contract( + redeemscript: &Script, +) -> Result { + PublicKey::from_slice(&redeemscript.to_bytes()[65..98]) +} + pub fn read_pubkeys_from_multisig_redeemscript( redeemscript: &Script, ) -> Option<(PublicKey, PublicKey)> { @@ -276,7 +288,8 @@ pub fn verify_proof_of_funding( funding_info: &ConfirmedCoinSwapTxInfo, funding_output_index: u32, next_locktime: i64, -) -> Result<(SecretKey, PublicKey), Error> { + //returns my_multisig_privkey, other_multisig_pubkey, my_hashlock_privkey +) -> Result<(SecretKey, PublicKey, SecretKey), Error> { //check the funding_tx exists and was really confirmed if let Some(txout) = rpc.get_tx_out(&funding_info.funding_tx.txid(), funding_output_index, None)? @@ -329,6 +342,19 @@ pub fn verify_proof_of_funding( return Err(Error::Protocol("locktime too short")); } + //check that provided hashlock_key_nonce really corresponds to the hashlock_pubkey in contract + let contract_hashlock_pubkey = + read_hashlock_pubkey_from_contract(&funding_info.contract_redeemscript) + .map_err(|_| Error::Protocol("unable to read hashlock pubkey from contract"))?; + let derived_hashlock_pubkey = + calculate_maker_pubkey_from_nonce(tweakable_point, funding_info.hashlock_key_nonce) + .map_err(|_| Error::Protocol("unable to calculate maker pubkey from nonce"))?; + if contract_hashlock_pubkey != derived_hashlock_pubkey { + return Err(Error::Protocol( + "contract hashlock pubkey doesnt match key derived from nonce", + )); + } + //check that the provided contract matches the scriptpubkey from the //cache which was populated when the signsendercontracttx message arrived let contract_spk = Address::p2wsh(&funding_info.contract_redeemscript, NETWORK).script_pubkey(); @@ -349,13 +375,17 @@ pub fn verify_proof_of_funding( my_privkey .add_assign(funding_info.multisig_key_nonce.as_ref()) .map_err(|_| Error::Protocol("error with wallet tweakable privkey + nonce"))?; + let mut hashlock_privkey = tweakable_privkey; + hashlock_privkey + .add_assign(funding_info.hashlock_key_nonce.as_ref()) + .map_err(|_| Error::Protocol("error with wallet tweakable privkey + nonce"))?; let other_pubkey = if pubkey1 == my_pubkey { pubkey2 } else { pubkey1 }; - Ok((my_privkey, other_pubkey)) + Ok((my_privkey, other_pubkey, hashlock_privkey)) } pub fn validate_contract_tx( diff --git a/src/maker_protocol.rs b/src/maker_protocol.rs index 3f338130..ba78adc1 100644 --- a/src/maker_protocol.rs +++ b/src/maker_protocol.rs @@ -314,7 +314,7 @@ fn handle_proof_of_funding( ) -> Result, Error> { let mut funding_output_indexes = Vec::::new(); let mut funding_outputs = Vec::<&TxOut>::new(); - let mut incoming_swapcoin_keys = Vec::<(SecretKey, PublicKey)>::new(); + let mut incoming_swapcoin_keys = Vec::<(SecretKey, PublicKey, SecretKey)>::new(); if proof.confirmed_funding_txes.len() == 0 { return Err(Error::Protocol("zero funding txes provided")); } @@ -391,7 +391,7 @@ fn handle_proof_of_funding( funding_output.value, &funding_info.contract_redeemscript, ); - let (coin_privkey, coin_other_pubkey) = incoming_swapcoin_keys; + let (coin_privkey, coin_other_pubkey, hashlock_privkey) = incoming_swapcoin_keys; println!( "adding incoming_swapcoin contract_tx = {:?} fo = {:?}", my_receivers_contract_tx.clone(), @@ -406,6 +406,7 @@ fn handle_proof_of_funding( coin_other_pubkey, my_receivers_contract_tx.clone(), funding_info.contract_redeemscript.clone(), + hashlock_privkey, funding_output.value, )); } @@ -416,7 +417,7 @@ fn handle_proof_of_funding( println!("incoming amount = {}", incoming_amount); let amount = incoming_amount - coinswap_fees; - let (my_funding_txes, outgoing_swapcoins, timelock_pubkeys, _timelock_privkeys) = + let (my_funding_txes, outgoing_swapcoins, timelock_pubkeys) = wallet.write().unwrap().initalize_coinswap( &rpc, amount, diff --git a/src/taker_protocol.rs b/src/taker_protocol.rs index 2dc77d6b..3325ff2b 100644 --- a/src/taker_protocol.rs +++ b/src/taker_protocol.rs @@ -85,17 +85,16 @@ async fn send_coinswap( mut this_maker_hashlock_privkeys, ) = generate_maker_multisig_and_hashlock_keys(&first_maker.offer.tweakable_point, my_tx_count); - let (my_funding_txes, mut outgoing_swapcoins, my_timelock_pubkeys, _my_timelock_privkeys) = - wallet - .initalize_coinswap( - rpc, - amount, - &first_maker_multisig_pubkeys, - &first_maker_hashlock_pubkeys, - hashvalue, - first_swap_locktime, - ) - .unwrap(); + let (my_funding_txes, mut outgoing_swapcoins, my_timelock_pubkeys) = wallet + .initalize_coinswap( + rpc, + amount, + &first_maker_multisig_pubkeys, + &first_maker_hashlock_pubkeys, + hashvalue, + first_swap_locktime, + ) + .unwrap(); let first_maker_senders_contract_sigs = request_senders_contract_tx_signatures( &first_maker.address, @@ -258,6 +257,7 @@ async fn send_coinswap( &maker_sign_sender_and_receiver_contracts, &funding_txes, &next_swap_contract_redeemscripts, + &next_peer_hashlock_keys_or_nonces, &next_peer_multisig_pubkeys, &next_peer_multisig_keys_or_nonces, preimage, @@ -890,6 +890,7 @@ fn create_incoming_swapcoins( maker_sign_sender_and_receiver_contracts: &SignSendersAndReceiversContractTxes, funding_txes: &[Transaction], next_swap_contract_redeemscripts: &[Script], + next_peer_hashlock_keys_or_nonces: &[SecretKey], next_peer_multisig_pubkeys: &[PublicKey], next_peer_multisig_keys_or_nonces: &[SecretKey], preimage: [u8; 32], @@ -941,6 +942,7 @@ fn create_incoming_swapcoins( &maker_funded_multisig_privkey, my_receivers_contract_tx, next_contract_redeemscript, + &hashlock_privkey, &maker_funding_tx_value, ) in izip!( next_swap_multisig_redeemscripts.iter(), @@ -948,6 +950,7 @@ fn create_incoming_swapcoins( next_peer_multisig_keys_or_nonces.iter(), my_receivers_contract_txes.iter(), next_swap_contract_redeemscripts.iter(), + next_peer_hashlock_keys_or_nonces.iter(), last_makers_funding_tx_values.iter(), ) { let (o_ms_pubkey1, o_ms_pubkey2) = @@ -967,6 +970,7 @@ fn create_incoming_swapcoins( maker_funded_other_multisig_pubkey, my_receivers_contract_tx.clone(), next_contract_redeemscript.clone(), + hashlock_privkey, maker_funding_tx_value, ); incoming_swapcoin.hash_preimage = Some(preimage); diff --git a/src/wallet_sync.rs b/src/wallet_sync.rs index f9c6860a..98e29c67 100644 --- a/src/wallet_sync.rs +++ b/src/wallet_sync.rs @@ -93,10 +93,15 @@ pub struct WalletSwapCoin { pub other_privkey: Option, pub contract_tx: Transaction, pub contract_redeemscript: Script, + //either timelock_privkey for outgoing swapcoins or hashlock_privkey for incoming swapcoins + pub contract_privkey: SecretKey, pub funding_amount: u64, pub others_contract_sig: Option, pub hash_preimage: Option<[u8; 32]>, } +//TODO split WalletSwapCoin into two structs, IncomingSwapCoin and OutgoingSwapCoin +//where Incoming has hashlock_privkey and Outgoing has timelock_privkey +//that is a much more rustic way of doing things, which uses the compiler to check for some bugs impl WalletSwapCoin { pub fn new( @@ -104,14 +109,26 @@ impl WalletSwapCoin { other_pubkey: PublicKey, contract_tx: Transaction, contract_redeemscript: Script, + contract_privkey: SecretKey, funding_amount: u64, ) -> WalletSwapCoin { + let secp = Secp256k1::new(); + let contract_pubkey = PublicKey { + compressed: true, + key: secp256k1::PublicKey::from_secret_key(&secp, &contract_privkey), + }; + assert!(contract_pubkey == + contracts::read_hashlock_pubkey_from_contract(&contract_redeemscript).unwrap() || + contract_pubkey == + contracts::read_timelock_pubkey_from_contract(&contract_redeemscript).unwrap() + ); WalletSwapCoin { my_privkey, other_pubkey, other_privkey: None, contract_tx, contract_redeemscript, + contract_privkey, funding_amount, others_contract_sig: None, hash_preimage: None, @@ -984,16 +1001,8 @@ impl Wallet { other_multisig_pubkeys: &[PublicKey], hashlock_pubkeys: &[PublicKey], hashvalue: [u8; 20], - locktime: i64, //returns: funding_tx, swapcoin, timelock_pubkey, timelock_privkey - ) -> Result< - ( - Vec, - Vec, - Vec, - Vec, - ), - Error, - > { + locktime: i64, //returns: funding_txes, swapcoins, timelock_pubkeys + ) -> Result<(Vec, Vec, Vec), Error> { let (coinswap_addresses, my_multisig_privkeys): (Vec<_>, Vec<_>) = other_multisig_pubkeys .iter() .map(|other_key| self.create_and_import_coinswap_address(rpc, other_key)) @@ -1007,7 +1016,6 @@ impl Wallet { // an integer but also can be Sweep let mut timelock_pubkeys = Vec::::new(); - let mut timelock_privkeys = Vec::::new(); let mut outgoing_swapcoins = Vec::::new(); for ( @@ -1042,22 +1050,17 @@ impl Wallet { ); timelock_pubkeys.push(timelock_pubkey); - timelock_privkeys.push(timelock_privkey); outgoing_swapcoins.push(WalletSwapCoin::new( my_multisig_privkey, other_multisig_pubkey, my_senders_contract_tx, contract_redeemscript, + timelock_privkey, funding_amount, )); } - Ok(( - my_funding_txes, - outgoing_swapcoins, - timelock_pubkeys, - timelock_privkeys, - )) + Ok((my_funding_txes, outgoing_swapcoins, timelock_pubkeys)) } }