Skip to content

Commit e553231

Browse files
fix(bdk): Check if we're using the correct...
...internal key before signing Fixes #1142 We would previously sign with whatever x_only_pubkey we had in hand, without first checking if it was the right key or not. This effectively meant that adding multiple taproot PrivateKey signers would produce unbroadcastable transactions.
1 parent 2f2f138 commit e553231

File tree

2 files changed

+51
-14
lines changed

2 files changed

+51
-14
lines changed

crates/bdk/src/wallet/signer.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -459,20 +459,23 @@ impl InputSigner for SignerWrapper<PrivateKey> {
459459
let x_only_pubkey = XOnlyPublicKey::from(pubkey.inner);
460460

461461
if let SignerContext::Tap { is_internal_key } = self.ctx {
462-
if is_internal_key
463-
&& psbt.inputs[input_index].tap_key_sig.is_none()
464-
&& sign_options.sign_with_tap_internal_key
465-
{
466-
let (hash, hash_ty) = Tap::sighash(psbt, input_index, None)?;
467-
sign_psbt_schnorr(
468-
&self.inner,
469-
x_only_pubkey,
470-
None,
471-
&mut psbt.inputs[input_index],
472-
hash,
473-
hash_ty,
474-
secp,
475-
);
462+
if let Some(psbt_internal_key) = psbt.inputs[input_index].tap_internal_key {
463+
if is_internal_key
464+
&& psbt.inputs[input_index].tap_key_sig.is_none()
465+
&& sign_options.sign_with_tap_internal_key
466+
&& x_only_pubkey == psbt_internal_key
467+
{
468+
let (hash, hash_ty) = Tap::sighash(psbt, input_index, None)?;
469+
sign_psbt_schnorr(
470+
&self.inner,
471+
x_only_pubkey,
472+
None,
473+
&mut psbt.inputs[input_index],
474+
hash,
475+
hash_ty,
476+
secp,
477+
);
478+
}
476479
}
477480

478481
if let Some((leaf_hashes, _)) =

crates/bdk/tests/psbt.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,37 @@ fn test_psbt_fee_rate_with_missing_txout() {
156156
assert!(pkh_psbt.fee_amount().is_none());
157157
assert!(pkh_psbt.fee_rate().is_none());
158158
}
159+
160+
#[test]
161+
fn test_psbt_multiple_internalkey_signers() {
162+
use bdk::signer::{SignerContext, SignerOrdering, SignerWrapper};
163+
use bdk::KeychainKind;
164+
use bitcoin::{secp256k1::Secp256k1, PrivateKey};
165+
use miniscript::psbt::PsbtExt;
166+
use std::sync::Arc;
167+
168+
let secp = Secp256k1::new();
169+
let (mut wallet, _) = get_funded_wallet(get_test_tr_single_sig());
170+
let send_to = wallet.get_address(AddressIndex::New);
171+
let mut builder = wallet.build_tx();
172+
builder.add_recipient(send_to.script_pubkey(), 10_000);
173+
let mut psbt = builder.finish().unwrap();
174+
// Adds a signer for the wrong internal key, bdk should not use this key to sign
175+
wallet.add_signer(
176+
KeychainKind::External,
177+
// A signerordering lower than 100, bdk will use this signer first
178+
SignerOrdering(0),
179+
Arc::new(SignerWrapper::new(
180+
PrivateKey::from_wif("5J5PZqvCe1uThJ3FZeUUFLCh2FuK9pZhtEK4MzhNmugqTmxCdwE").unwrap(),
181+
SignerContext::Tap {
182+
is_internal_key: true,
183+
},
184+
)),
185+
);
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+
);
192+
}

0 commit comments

Comments
 (0)