Skip to content

Commit 3fdab87

Browse files
Merge #1200: fix(bdk): Check if we're using the correct internal key before signing
e553231 fix(bdk): Check if we're using the correct... ...internal key before signing (Daniela Brozzoni) Pull request description: ### Description 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. ### Changelog notice - Fix a bug related to taproot signing with internal keys. We would previously sign with the first private key we had, without checking if it was the correct internal key or not. ### Checklists #### All Submissions: * [x] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) * [x] I ran `cargo fmt` and `cargo clippy` before committing #### Bugfixes: * [ ] This pull request breaks the existing API * [x] I've added tests to reproduce the issue which are now passing * [x] I'm linking the issue being fixed by this PR ACKs for top commit: evanlinjin: ACK e553231 Tree-SHA512: c4abbcd27935b8ce80a70b6e0843507866e3d075939f0b01504c090929ed96b4b9c6fee599f701e69960a6c86175682cc6d7f8cc4c3fb1d08a74b7563f8ca145
2 parents 855c61a + e553231 commit 3fdab87

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)