]> Untitled Git - bdk/commitdiff
fix(bdk): Check if we're using the correct...
authorDaniela Brozzoni <danielabrozzoni@protonmail.com>
Wed, 8 Nov 2023 17:16:21 +0000 (18:16 +0100)
committerDaniela Brozzoni <danielabrozzoni@protonmail.com>
Fri, 10 Nov 2023 17:25:46 +0000 (18:25 +0100)
...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.

crates/bdk/src/wallet/signer.rs
crates/bdk/tests/psbt.rs

index 68b2ecb154a08d017fca2cbfd1145d9b8e08f8cc..d71ba0e638e0d88aeef6f6b4efa3c0562aa3c466 100644 (file)
@@ -459,20 +459,23 @@ impl InputSigner for SignerWrapper<PrivateKey> {
         let x_only_pubkey = XOnlyPublicKey::from(pubkey.inner);
 
         if let SignerContext::Tap { is_internal_key } = self.ctx {
-            if is_internal_key
-                && psbt.inputs[input_index].tap_key_sig.is_none()
-                && sign_options.sign_with_tap_internal_key
-            {
-                let (hash, hash_ty) = Tap::sighash(psbt, input_index, None)?;
-                sign_psbt_schnorr(
-                    &self.inner,
-                    x_only_pubkey,
-                    None,
-                    &mut psbt.inputs[input_index],
-                    hash,
-                    hash_ty,
-                    secp,
-                );
+            if let Some(psbt_internal_key) = psbt.inputs[input_index].tap_internal_key {
+                if is_internal_key
+                    && psbt.inputs[input_index].tap_key_sig.is_none()
+                    && sign_options.sign_with_tap_internal_key
+                    && x_only_pubkey == psbt_internal_key
+                {
+                    let (hash, hash_ty) = Tap::sighash(psbt, input_index, None)?;
+                    sign_psbt_schnorr(
+                        &self.inner,
+                        x_only_pubkey,
+                        None,
+                        &mut psbt.inputs[input_index],
+                        hash,
+                        hash_ty,
+                        secp,
+                    );
+                }
             }
 
             if let Some((leaf_hashes, _)) =
index 602c37dbd5628904af86477d1060957d81b49477..3c4968bfebf72647bece380d8a407bb2125892a3 100644 (file)
@@ -156,3 +156,37 @@ fn test_psbt_fee_rate_with_missing_txout() {
     assert!(pkh_psbt.fee_amount().is_none());
     assert!(pkh_psbt.fee_rate().is_none());
 }
+
+#[test]
+fn test_psbt_multiple_internalkey_signers() {
+    use bdk::signer::{SignerContext, SignerOrdering, SignerWrapper};
+    use bdk::KeychainKind;
+    use bitcoin::{secp256k1::Secp256k1, PrivateKey};
+    use miniscript::psbt::PsbtExt;
+    use std::sync::Arc;
+
+    let secp = Secp256k1::new();
+    let (mut wallet, _) = get_funded_wallet(get_test_tr_single_sig());
+    let send_to = wallet.get_address(AddressIndex::New);
+    let mut builder = wallet.build_tx();
+    builder.add_recipient(send_to.script_pubkey(), 10_000);
+    let mut psbt = builder.finish().unwrap();
+    // Adds a signer for the wrong internal key, bdk should not use this key to sign
+    wallet.add_signer(
+        KeychainKind::External,
+        // A signerordering lower than 100, bdk will use this signer first
+        SignerOrdering(0),
+        Arc::new(SignerWrapper::new(
+            PrivateKey::from_wif("5J5PZqvCe1uThJ3FZeUUFLCh2FuK9pZhtEK4MzhNmugqTmxCdwE").unwrap(),
+            SignerContext::Tap {
+                is_internal_key: true,
+            },
+        )),
+    );
+    let _ = wallet.sign(&mut psbt, SignOptions::default()).unwrap();
+    // Checks that we signed using the right key
+    assert!(
+        psbt.finalize_mut(&secp).is_ok(),
+        "The wrong internal key was used"
+    );
+}