Skip to content

Commit 8c78a42

Browse files
committed
test(psbt): Fixup test_psbt_multiple_internalkey_signers
to verify the signature of the input and ensure the right internal key is used to sign. This fixes a shortcoming of a previous version of the test that relied on the result of `finalize_psbt` but would have erroneously allowed signing with the wrong key.
1 parent c6b9ed3 commit 8c78a42

File tree

1 file changed

+42
-10
lines changed

1 file changed

+42
-10
lines changed

crates/bdk/tests/psbt.rs

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -161,16 +161,26 @@ fn test_psbt_fee_rate_with_missing_txout() {
161161
fn test_psbt_multiple_internalkey_signers() {
162162
use bdk::signer::{SignerContext, SignerOrdering, SignerWrapper};
163163
use bdk::KeychainKind;
164-
use bitcoin::{secp256k1::Secp256k1, PrivateKey};
165-
use miniscript::psbt::PsbtExt;
164+
use bitcoin::key::TapTweak;
165+
use bitcoin::secp256k1::{schnorr, KeyPair, Message, Secp256k1, XOnlyPublicKey};
166+
use bitcoin::sighash::{Prevouts, SighashCache, TapSighashType};
167+
use bitcoin::{PrivateKey, TxOut};
166168
use std::sync::Arc;
167169

168170
let secp = Secp256k1::new();
169-
let (mut wallet, _) = get_funded_wallet(get_test_tr_single_sig());
171+
let wif = "cNJmN3fH9DDbDt131fQNkVakkpzawJBSeybCUNmP1BovpmGQ45xG";
172+
let desc = format!("tr({})", wif);
173+
let prv = PrivateKey::from_wif(wif).unwrap();
174+
let keypair = KeyPair::from_secret_key(&secp, &prv.inner);
175+
176+
let (mut wallet, _) = get_funded_wallet(&desc);
177+
let to_spend = wallet.get_balance().total();
170178
let send_to = wallet.get_address(AddressIndex::New);
171179
let mut builder = wallet.build_tx();
172-
builder.add_recipient(send_to.script_pubkey(), 10_000);
180+
builder.drain_to(send_to.script_pubkey()).drain_wallet();
173181
let mut psbt = builder.finish().unwrap();
182+
let unsigned_tx = psbt.unsigned_tx.clone();
183+
174184
// Adds a signer for the wrong internal key, bdk should not use this key to sign
175185
wallet.add_signer(
176186
KeychainKind::External,
@@ -183,10 +193,32 @@ fn test_psbt_multiple_internalkey_signers() {
183193
},
184194
)),
185195
);
186-
let _ = wallet.sign(&mut psbt, SignOptions::default()).unwrap();
187-
// Checks that we signed using the right key
188-
assert!(
189-
psbt.finalize_mut(&secp).is_ok(),
190-
"The wrong internal key was used"
191-
);
196+
let finalized = wallet.sign(&mut psbt, SignOptions::default()).unwrap();
197+
assert!(finalized);
198+
199+
// To verify, we need the signature, message, and pubkey
200+
let witness = psbt.inputs[0].final_script_witness.as_ref().unwrap();
201+
assert!(!witness.is_empty());
202+
let signature = schnorr::Signature::from_slice(witness.iter().next().unwrap()).unwrap();
203+
204+
// the prevout we're spending
205+
let prevouts = &[TxOut {
206+
script_pubkey: send_to.script_pubkey(),
207+
value: to_spend,
208+
}];
209+
let prevouts = Prevouts::All(prevouts);
210+
let input_index = 0;
211+
let mut sighash_cache = SighashCache::new(unsigned_tx);
212+
let sighash = sighash_cache
213+
.taproot_key_spend_signature_hash(input_index, &prevouts, TapSighashType::Default)
214+
.unwrap();
215+
let message = Message::from(sighash);
216+
217+
// add tweak. this was taken from `signer::sign_psbt_schnorr`
218+
let keypair = keypair.tap_tweak(&secp, None).to_inner();
219+
let (xonlykey, _parity) = XOnlyPublicKey::from_keypair(&keypair);
220+
221+
// Must verify if we used the correct key to sign
222+
let verify_res = secp.verify_schnorr(&signature, &message, &xonlykey);
223+
assert!(verify_res.is_ok(), "The wrong internal key was used");
192224
}

0 commit comments

Comments
 (0)