Skip to main content

miniscript/
plan.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! A spending plan (or *plan*) is a representation of a particular spending path on a
4//! descriptor.
5//!
6//! This allows us to analayze a choice of spending path without producing any
7//! signatures or other witness data for it.
8//!
9//! To make a plan you provide the descriptor with "assets" like which keys you are able to use, hash
10//! pre-images you have access to, absolute/relative timelock constraints etc.
11//!
12//! Once you've got a plan it can tell you its expected satisfaction weight which can be useful for
13//! doing coin selection. Furthermore it provides which subset of those keys and hash pre-images you
14//! will actually need as well as what locktime or sequence number you need to set.
15//!
16//! Once you've obtained signatures, hash pre-images etc required by the plan, it can create a
17//! witness/script_sig for the input.
18
19use core::iter::FromIterator;
20
21use bitcoin::hashes::{hash160, ripemd160, sha256};
22use bitcoin::key::XOnlyPublicKey;
23use bitcoin::script::PushBytesBuf;
24use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash};
25use bitcoin::{absolute, bip32, psbt, relative, ScriptBuf, WitnessVersion};
26
27use crate::descriptor::{self, Descriptor, DescriptorType, KeyMap};
28use crate::miniscript::hash256;
29use crate::miniscript::satisfy::{Placeholder, Satisfier, SchnorrSigType};
30use crate::prelude::*;
31use crate::util::witness_size;
32use crate::{DefiniteDescriptorKey, DescriptorPublicKey, Error, MiniscriptKey, ToPublicKey};
33
34/// Trait describing a present/missing lookup table for constructing witness templates
35///
36/// This trait mirrors the [`Satisfier`] trait, with the difference that most methods just return a
37/// boolean indicating the item presence. The methods looking up keys return the key
38/// length, the methods looking up public key hashes return the public key, and a few other methods
39/// need to return the item itself.
40///
41/// This trait is automatically implemented for every type that is also a satisfier, and simply
42/// proxies the queries to the satisfier and returns whether an item is available or not.
43///
44/// All the methods have a default implementation that returns `false` or `None`.
45pub trait AssetProvider<Pk: MiniscriptKey> {
46    /// Given a public key, look up an ECDSA signature with that key, return whether we found it
47    fn provider_lookup_ecdsa_sig(&self, _: &Pk) -> bool { false }
48
49    /// Lookup the tap key spend sig and return its size
50    fn provider_lookup_tap_key_spend_sig(&self, _: &Pk) -> Option<usize> { None }
51
52    /// Given a public key and a associated leaf hash, look up a schnorr signature with that key
53    /// and return its size
54    fn provider_lookup_tap_leaf_script_sig(&self, _: &Pk, _: &TapLeafHash) -> Option<usize> { None }
55
56    /// Given a raw `Pkh`, lookup corresponding [`bitcoin::PublicKey`]
57    fn provider_lookup_raw_pkh_pk(&self, _: &hash160::Hash) -> Option<bitcoin::PublicKey> { None }
58
59    /// Given a raw `Pkh`, lookup corresponding [`bitcoin::secp256k1::XOnlyPublicKey`]
60    fn provider_lookup_raw_pkh_x_only_pk(&self, _: &hash160::Hash) -> Option<XOnlyPublicKey> {
61        None
62    }
63
64    /// Given a keyhash, look up the EC signature and the associated key.
65    ///
66    /// Returns the key if a signature is found.
67    ///
68    /// Even if signatures for public key Hashes are not available, the users
69    /// can use this map to provide pkh -> pk mapping which can be useful
70    /// for dissatisfying pkh.
71    fn provider_lookup_raw_pkh_ecdsa_sig(&self, _: &hash160::Hash) -> Option<bitcoin::PublicKey> {
72        None
73    }
74
75    /// Given a keyhash, look up the schnorr signature and the associated key.
76    ///
77    /// Returns the key and sig len if a signature is found.
78    ///
79    /// Even if signatures for public key Hashes are not available, the users
80    /// can use this map to provide pkh -> pk mapping which can be useful
81    /// for dissatisfying pkh.
82    fn provider_lookup_raw_pkh_tap_leaf_script_sig(
83        &self,
84        _: &(hash160::Hash, TapLeafHash),
85    ) -> Option<(XOnlyPublicKey, usize)> {
86        None
87    }
88
89    /// Given a SHA256 hash, look up its preimage, return whether we found it
90    fn provider_lookup_sha256(&self, _: &Pk::Sha256) -> bool { false }
91
92    /// Given a HASH256 hash, look up its preimage, return whether we found it
93    fn provider_lookup_hash256(&self, _: &Pk::Hash256) -> bool { false }
94
95    /// Given a RIPEMD160 hash, look up its preimage, return whether we found it
96    fn provider_lookup_ripemd160(&self, _: &Pk::Ripemd160) -> bool { false }
97
98    /// Given a HASH160 hash, look up its preimage, return whether we found it
99    fn provider_lookup_hash160(&self, _: &Pk::Hash160) -> bool { false }
100
101    /// Assert whether a relative locktime is satisfied
102    fn check_older(&self, _: relative::LockTime) -> bool { false }
103
104    /// Assert whether an absolute locktime is satisfied
105    fn check_after(&self, _: absolute::LockTime) -> bool { false }
106}
107
108/// Wrapper around [`Assets`] that logs every query and value returned
109#[cfg(feature = "std")]
110pub struct LoggerAssetProvider<'a>(pub &'a Assets);
111
112#[cfg(feature = "std")]
113macro_rules! impl_log_method {
114    ( $name:ident, $( <$ctx:ident: ScriptContext > )? $( $arg:ident : $ty:ty, )* -> $ret_ty:ty ) => {
115        fn $name $( <$ctx: ScriptContext> )? ( &self, $( $arg:$ty ),* ) -> $ret_ty {
116            let ret = (self.0).$name $( ::<$ctx> )*( $( $arg ),* );
117            dbg!(stringify!( $name ), ( $( $arg ),* ), &ret);
118
119            ret
120        }
121    }
122}
123
124#[cfg(feature = "std")]
125impl AssetProvider<DefiniteDescriptorKey> for LoggerAssetProvider<'_> {
126    impl_log_method!(provider_lookup_ecdsa_sig, pk: &DefiniteDescriptorKey, -> bool);
127    impl_log_method!(provider_lookup_tap_key_spend_sig, pk: &DefiniteDescriptorKey, -> Option<usize>);
128    impl_log_method!(provider_lookup_tap_leaf_script_sig, pk: &DefiniteDescriptorKey, leaf_hash: &TapLeafHash, -> Option<usize>);
129    impl_log_method!(provider_lookup_raw_pkh_pk, hash: &hash160::Hash, -> Option<bitcoin::PublicKey>);
130    impl_log_method!(provider_lookup_raw_pkh_x_only_pk, hash: &hash160::Hash, -> Option<XOnlyPublicKey>);
131    impl_log_method!(provider_lookup_raw_pkh_ecdsa_sig, hash: &hash160::Hash, -> Option<bitcoin::PublicKey>);
132    impl_log_method!(provider_lookup_raw_pkh_tap_leaf_script_sig, hash: &(hash160::Hash, TapLeafHash), -> Option<(XOnlyPublicKey, usize)>);
133    impl_log_method!(provider_lookup_sha256, hash: &sha256::Hash, -> bool);
134    impl_log_method!(provider_lookup_hash256, hash: &hash256::Hash, -> bool);
135    impl_log_method!(provider_lookup_ripemd160, hash: &ripemd160::Hash, -> bool);
136    impl_log_method!(provider_lookup_hash160, hash: &hash160::Hash, -> bool);
137    impl_log_method!(check_older, s: relative::LockTime, -> bool);
138    impl_log_method!(check_after, t: absolute::LockTime, -> bool);
139}
140
141impl<T, Pk> AssetProvider<Pk> for T
142where
143    T: Satisfier<Pk>,
144    Pk: MiniscriptKey + ToPublicKey,
145{
146    fn provider_lookup_ecdsa_sig(&self, pk: &Pk) -> bool {
147        Satisfier::lookup_ecdsa_sig(self, pk).is_some()
148    }
149
150    fn provider_lookup_tap_key_spend_sig(&self, pk: &Pk) -> Option<usize> {
151        Satisfier::lookup_tap_key_spend_sig(self, pk).map(|s| s.to_vec().len())
152    }
153
154    fn provider_lookup_tap_leaf_script_sig(
155        &self,
156        pk: &Pk,
157        leaf_hash: &TapLeafHash,
158    ) -> Option<usize> {
159        Satisfier::lookup_tap_leaf_script_sig(self, pk, leaf_hash).map(|s| s.to_vec().len())
160    }
161
162    fn provider_lookup_raw_pkh_pk(&self, hash: &hash160::Hash) -> Option<bitcoin::PublicKey> {
163        Satisfier::lookup_raw_pkh_pk(self, hash)
164    }
165
166    fn provider_lookup_raw_pkh_x_only_pk(&self, hash: &hash160::Hash) -> Option<XOnlyPublicKey> {
167        Satisfier::lookup_raw_pkh_x_only_pk(self, hash)
168    }
169
170    fn provider_lookup_raw_pkh_ecdsa_sig(
171        &self,
172        hash: &hash160::Hash,
173    ) -> Option<bitcoin::PublicKey> {
174        Satisfier::lookup_raw_pkh_ecdsa_sig(self, hash).map(|(pk, _)| pk)
175    }
176
177    fn provider_lookup_raw_pkh_tap_leaf_script_sig(
178        &self,
179        hash: &(hash160::Hash, TapLeafHash),
180    ) -> Option<(XOnlyPublicKey, usize)> {
181        Satisfier::lookup_raw_pkh_tap_leaf_script_sig(self, hash)
182            .map(|(pk, sig)| (pk, sig.to_vec().len()))
183    }
184
185    fn provider_lookup_sha256(&self, hash: &Pk::Sha256) -> bool {
186        Satisfier::lookup_sha256(self, hash).is_some()
187    }
188
189    fn provider_lookup_hash256(&self, hash: &Pk::Hash256) -> bool {
190        Satisfier::lookup_hash256(self, hash).is_some()
191    }
192
193    fn provider_lookup_ripemd160(&self, hash: &Pk::Ripemd160) -> bool {
194        Satisfier::lookup_ripemd160(self, hash).is_some()
195    }
196
197    fn provider_lookup_hash160(&self, hash: &Pk::Hash160) -> bool {
198        Satisfier::lookup_hash160(self, hash).is_some()
199    }
200
201    fn check_older(&self, s: relative::LockTime) -> bool { Satisfier::check_older(self, s) }
202
203    fn check_after(&self, l: absolute::LockTime) -> bool { Satisfier::check_after(self, l) }
204}
205
206/// Representation of a particular spending path on a descriptor.
207///
208/// Contains the witness template
209/// and the timelocks needed for satisfying the plan.
210/// Calling `plan` on a Descriptor will return this structure,
211/// containing the cheapest spending path possible (considering the `Assets` given)
212#[derive(Debug, Clone)]
213pub struct Plan {
214    /// This plan's witness template
215    pub(crate) template: Vec<Placeholder<DefiniteDescriptorKey>>,
216    /// The absolute timelock this plan uses
217    pub absolute_timelock: Option<absolute::LockTime>,
218    /// The relative timelock this plan uses
219    pub relative_timelock: Option<relative::LockTime>,
220    /// The target descriptor for this plan
221    pub descriptor: Descriptor<DefiniteDescriptorKey>,
222}
223
224impl Plan {
225    /// Returns the witness template
226    pub fn witness_template(&self) -> &Vec<Placeholder<DefiniteDescriptorKey>> { &self.template }
227
228    /// Returns the witness version
229    pub fn witness_version(&self) -> Option<WitnessVersion> {
230        self.descriptor.desc_type().segwit_version()
231    }
232
233    /// The weight, in witness units, needed for satisfying this plan (includes both
234    /// the script sig weight and the witness weight)
235    pub fn satisfaction_weight(&self) -> usize { self.witness_size() + self.scriptsig_size() * 4 }
236
237    /// The size in bytes of the script sig that satisfies this plan, including the size of the
238    /// var-int prefix.
239    pub fn scriptsig_size(&self) -> usize {
240        match (self.descriptor.desc_type().segwit_version(), self.descriptor.desc_type()) {
241            // Entire witness goes in the script_sig
242            (None, _) => witness_size(self.template.as_ref()),
243            // Taproot doesn't have a "wrapped" version (scriptSig len (1))
244            (Some(WitnessVersion::V1), _) => 1,
245            // scriptSig len (1) + OP_0 (1) + OP_PUSHBYTES_20 (1) + <pk hash> (20)
246            (_, DescriptorType::ShWpkh) => 1 + 1 + 1 + 20,
247            // scriptSig len (1) + OP_0 (1) + OP_PUSHBYTES_32 (1) + <script hash> (32)
248            (_, DescriptorType::ShWsh) | (_, DescriptorType::ShWshSortedMulti) => 1 + 1 + 1 + 32,
249            // Native Segwit v0 (scriptSig len (1))
250            _ => 1,
251        }
252    }
253
254    /// The size in bytes of the witness that satisfies this plan.
255    ///
256    /// NOTE: Returns 0 if there is no witness. You need to manually take care to count it as 1 byte
257    /// if there's at least one segwit input in the tx. See ["Empty script witnesses are encoded as a zero byte"](https://github.com/bitcoin/bips/blob/d8a56c9f2b521bf4af5d588f217e7618cc44952c/bip-0144.mediawiki#serialization).
258    pub fn witness_size(&self) -> usize {
259        if self.descriptor.desc_type().segwit_version().is_some() {
260            witness_size(self.template.as_ref())
261        } else {
262            0
263        }
264    }
265
266    /// Try creating the final script_sig and witness using a [`Satisfier`]
267    pub fn satisfy<Sat: Satisfier<DefiniteDescriptorKey>>(
268        &self,
269        stfr: &Sat,
270    ) -> Result<(Vec<Vec<u8>>, ScriptBuf), Error> {
271        use bitcoin::blockdata::script::Builder;
272
273        let stack = self
274            .template
275            .iter()
276            .map(|placeholder| placeholder.satisfy_self(stfr))
277            .collect::<Option<Vec<Vec<u8>>>>()
278            .ok_or(Error::CouldNotSatisfy)?;
279
280        Ok(match self.descriptor.desc_type() {
281            DescriptorType::Bare
282            | DescriptorType::Sh
283            | DescriptorType::Pkh
284            | DescriptorType::ShSortedMulti => (
285                vec![],
286                stack
287                    .into_iter()
288                    .fold(Builder::new(), |builder, item| {
289                        let bytes = PushBytesBuf::try_from(item)
290                            .expect("All the possible placeholders can be made into PushBytesBuf");
291                        builder.push_slice(bytes)
292                    })
293                    .into_script(),
294            ),
295            DescriptorType::Wpkh
296            | DescriptorType::Wsh
297            | DescriptorType::WshSortedMulti
298            | DescriptorType::Tr => (stack, ScriptBuf::new()),
299            DescriptorType::ShWsh | DescriptorType::ShWshSortedMulti | DescriptorType::ShWpkh => {
300                (stack, self.descriptor.unsigned_script_sig())
301            }
302        })
303    }
304
305    /// Update a PSBT input with the metadata required to complete this plan
306    ///
307    /// This will only add the metadata for items required to complete this plan. For example, if
308    /// there are multiple keys present in the descriptor, only the few used by this plan will be
309    /// added to the PSBT.
310    pub fn update_psbt_input(&self, input: &mut psbt::Input) {
311        if let Descriptor::Tr(tr) = &self.descriptor {
312            enum SpendType {
313                KeySpend { internal_key: XOnlyPublicKey },
314                ScriptSpend { leaf_hash: TapLeafHash },
315            }
316
317            #[derive(Default)]
318            struct TrDescriptorData {
319                tap_script: Option<ScriptBuf>,
320                control_block: Option<ControlBlock>,
321                spend_type: Option<SpendType>,
322                key_origins: BTreeMap<XOnlyPublicKey, bip32::KeySource>,
323            }
324
325            let spend_info = tr.spend_info();
326            input.tap_merkle_root = spend_info.merkle_root();
327
328            let data = self
329                .template
330                .iter()
331                .fold(TrDescriptorData::default(), |mut data, item| {
332                    match item {
333                        Placeholder::TapScript(script) => data.tap_script = Some(script.clone()),
334                        Placeholder::TapControlBlock(cb) => data.control_block = Some(cb.clone()),
335                        Placeholder::SchnorrSigPk(pk, sig_type, _) => {
336                            let raw_pk = pk.to_x_only_pubkey();
337
338                            match (&data.spend_type, sig_type) {
339                                // First encountered schnorr sig, update the `TrDescriptorData` accordingly
340                                (None, SchnorrSigType::KeySpend { .. }) => data.spend_type = Some(SpendType::KeySpend { internal_key: raw_pk }),
341                                (None, SchnorrSigType::ScriptSpend { leaf_hash }) => data.spend_type = Some(SpendType::ScriptSpend { leaf_hash: *leaf_hash }),
342
343                                // Inconsistent placeholders (should be unreachable with the
344                                // current implementation)
345                                (Some(SpendType::KeySpend {..}), SchnorrSigType::ScriptSpend { .. }) | (Some(SpendType::ScriptSpend {..}), SchnorrSigType::KeySpend{..}) => unreachable!("Mixed taproot key-spend and script-spend placeholders in the same plan"),
346
347                                _ => {},
348                            }
349
350                            for path in pk.full_derivation_paths() {
351                                data.key_origins.insert(raw_pk, (pk.master_fingerprint(), path));
352                            }
353                        }
354                        Placeholder::SchnorrSigPkHash(_, tap_leaf_hash, _) => {
355                            data.spend_type = Some(SpendType::ScriptSpend { leaf_hash: *tap_leaf_hash });
356                        }
357                        _ => {}
358                    }
359
360                    data
361                });
362
363            let leaf_hash = match data.spend_type {
364                Some(SpendType::KeySpend { internal_key }) => {
365                    input.tap_internal_key = Some(internal_key);
366                    None
367                }
368                Some(SpendType::ScriptSpend { leaf_hash }) => Some(leaf_hash),
369                _ => None,
370            };
371            for (pk, key_source) in data.key_origins {
372                input
373                    .tap_key_origins
374                    .entry(pk)
375                    .and_modify(|(leaf_hashes, _)| {
376                        if let Some(lh) = leaf_hash {
377                            if leaf_hashes.iter().all(|&i| i != lh) {
378                                leaf_hashes.push(lh);
379                            }
380                        }
381                    })
382                    .or_insert_with(|| (vec![], key_source));
383            }
384            if let (Some(tap_script), Some(control_block)) = (data.tap_script, data.control_block) {
385                input
386                    .tap_scripts
387                    .insert(control_block, (tap_script, LeafVersion::TapScript));
388            }
389        } else {
390            for item in &self.template {
391                if let Placeholder::EcdsaSigPk(pk) = item {
392                    let public_key = pk.to_public_key().inner;
393                    let master_fingerprint = pk.master_fingerprint();
394                    for derivation_path in pk.full_derivation_paths() {
395                        input
396                            .bip32_derivation
397                            .insert(public_key, (master_fingerprint, derivation_path));
398                    }
399                }
400            }
401
402            match &self.descriptor {
403                Descriptor::Bare(_) | Descriptor::Pkh(_) | Descriptor::Wpkh(_) => {}
404                Descriptor::Sh(sh) => match sh.as_inner() {
405                    descriptor::ShInner::Wsh(wsh) => {
406                        input.witness_script = Some(wsh.inner_script());
407                        input.redeem_script = Some(wsh.inner_script().to_p2wsh());
408                    }
409                    descriptor::ShInner::Wpkh(..) => input.redeem_script = Some(sh.inner_script()),
410                    descriptor::ShInner::SortedMulti(_) | descriptor::ShInner::Ms(_) => {
411                        input.redeem_script = Some(sh.inner_script())
412                    }
413                },
414                Descriptor::Wsh(wsh) => input.witness_script = Some(wsh.inner_script()),
415                Descriptor::Tr(_) => unreachable!("Tr is dealt with separately"),
416            }
417        }
418    }
419}
420
421#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
422/// Signatures which a key can produce
423///
424/// Defaults to `ecdsa=true` and `taproot=TaprootCanSign::default()`
425pub struct CanSign {
426    /// Whether the key can produce ECDSA signatures
427    pub ecdsa: bool,
428    /// Whether the key can produce taproot (Schnorr) signatures
429    pub taproot: TaprootCanSign,
430}
431
432impl Default for CanSign {
433    fn default() -> Self { CanSign { ecdsa: true, taproot: TaprootCanSign::default() } }
434}
435
436#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
437/// Signatures which a taproot key can produce
438///
439/// Defaults to `key_spend=true`, `script_spend=Any` and `sighash_default=true`
440pub struct TaprootCanSign {
441    /// Can produce key spend signatures
442    pub key_spend: bool,
443    /// Can produce script spend signatures
444    pub script_spend: TaprootAvailableLeaves,
445    /// Whether `SIGHASH_DEFAULT` will be used to sign
446    pub sighash_default: bool,
447}
448
449impl TaprootCanSign {
450    fn sig_len(&self) -> usize {
451        match self.sighash_default {
452            true => 64,
453            false => 65,
454        }
455    }
456}
457
458impl Default for TaprootCanSign {
459    fn default() -> Self {
460        TaprootCanSign {
461            key_spend: true,
462            script_spend: TaprootAvailableLeaves::Any,
463            sighash_default: true,
464        }
465    }
466}
467
468#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
469/// Which taproot leaves the key can sign for
470pub enum TaprootAvailableLeaves {
471    /// Cannot sign for any leaf
472    None,
473    /// Can sign for any leaf
474    Any,
475    /// Can sign only for a specific leaf
476    Single(TapLeafHash),
477    /// Can sign for multiple leaves
478    Many(Vec<TapLeafHash>),
479}
480
481impl TaprootAvailableLeaves {
482    fn is_available(&self, lh: &TapLeafHash) -> bool {
483        use TaprootAvailableLeaves::*;
484
485        match self {
486            None => false,
487            Any => true,
488            Single(v) => v == lh,
489            Many(list) => list.contains(lh),
490        }
491    }
492}
493
494/// The Assets we can use to satisfy a particular spending path
495#[derive(Debug, Default)]
496pub struct Assets {
497    /// Keys the user can sign for, and how.
498    ///
499    /// A pair `(fingerprint, derivation_path)` is
500    /// provided, meaning that the user can sign using the key with `fingerprint`,
501    /// derived with either `derivation_path` or a derivation path that extends `derivation_path`
502    /// by exactly one child number. For example, if the derivation path `m/0/1` is provided, the
503    /// user can sign with either `m/0/1` or `m/0/1/*`.
504    pub keys: BTreeSet<(bip32::KeySource, CanSign)>,
505    /// Set of available sha256 preimages
506    pub sha256_preimages: BTreeSet<sha256::Hash>,
507    /// Set of available hash256 preimages
508    pub hash256_preimages: BTreeSet<hash256::Hash>,
509    /// Set of available ripemd160 preimages
510    pub ripemd160_preimages: BTreeSet<ripemd160::Hash>,
511    /// Set of available hash160 preimages
512    pub hash160_preimages: BTreeSet<hash160::Hash>,
513    /// Maximum absolute timelock allowed
514    pub absolute_timelock: Option<absolute::LockTime>,
515    /// Maximum relative timelock allowed
516    pub relative_timelock: Option<relative::LockTime>,
517}
518
519// Checks if the `pk` is a "direct child" of the `derivation_path` provided.
520// Direct child means that the key derivation path is either the same as the
521// `derivation_path`, or the same extended by exactly one child number.
522// For example, `pk/0/1/2` is a direct child of `m/0/1` and of `m/0/1/2`,
523// but not of `m/0`.
524fn is_key_direct_child_of(
525    pk: &DefiniteDescriptorKey,
526    derivation_path: &bip32::DerivationPath,
527) -> bool {
528    for pk_derivation_path in pk.full_derivation_paths() {
529        if &pk_derivation_path == derivation_path {
530            return true;
531        }
532
533        let definite_path_len = pk_derivation_path.len();
534        if derivation_path.as_ref() == &pk_derivation_path[..(definite_path_len - 1)] {
535            return true;
536        }
537    }
538
539    false
540}
541
542impl Assets {
543    pub(crate) fn has_ecdsa_key(&self, pk: &DefiniteDescriptorKey) -> bool {
544        self.keys.iter().any(|(keysource, can_sign)| {
545            can_sign.ecdsa
546                && pk.master_fingerprint() == keysource.0
547                && is_key_direct_child_of(pk, &keysource.1)
548        })
549    }
550
551    pub(crate) fn has_taproot_internal_key(&self, pk: &DefiniteDescriptorKey) -> Option<usize> {
552        self.keys.iter().find_map(|(keysource, can_sign)| {
553            if !can_sign.taproot.key_spend
554                || pk.master_fingerprint() != keysource.0
555                || !is_key_direct_child_of(pk, &keysource.1)
556            {
557                None
558            } else {
559                Some(can_sign.taproot.sig_len())
560            }
561        })
562    }
563
564    pub(crate) fn has_taproot_script_key(
565        &self,
566        pk: &DefiniteDescriptorKey,
567        tap_leaf_hash: &TapLeafHash,
568    ) -> Option<usize> {
569        self.keys.iter().find_map(|(keysource, can_sign)| {
570            if !can_sign.taproot.script_spend.is_available(tap_leaf_hash)
571                || pk.master_fingerprint() != keysource.0
572                || !is_key_direct_child_of(pk, &keysource.1)
573            {
574                None
575            } else {
576                Some(can_sign.taproot.sig_len())
577            }
578        })
579    }
580}
581
582impl AssetProvider<DefiniteDescriptorKey> for Assets {
583    fn provider_lookup_ecdsa_sig(&self, pk: &DefiniteDescriptorKey) -> bool {
584        self.has_ecdsa_key(pk)
585    }
586
587    fn provider_lookup_tap_key_spend_sig(&self, pk: &DefiniteDescriptorKey) -> Option<usize> {
588        self.has_taproot_internal_key(pk)
589    }
590
591    fn provider_lookup_tap_leaf_script_sig(
592        &self,
593        pk: &DefiniteDescriptorKey,
594        tap_leaf_hash: &TapLeafHash,
595    ) -> Option<usize> {
596        self.has_taproot_script_key(pk, tap_leaf_hash)
597    }
598
599    fn provider_lookup_sha256(&self, hash: &sha256::Hash) -> bool {
600        self.sha256_preimages.contains(hash)
601    }
602
603    fn provider_lookup_hash256(&self, hash: &hash256::Hash) -> bool {
604        self.hash256_preimages.contains(hash)
605    }
606
607    fn provider_lookup_ripemd160(&self, hash: &ripemd160::Hash) -> bool {
608        self.ripemd160_preimages.contains(hash)
609    }
610
611    fn provider_lookup_hash160(&self, hash: &hash160::Hash) -> bool {
612        self.hash160_preimages.contains(hash)
613    }
614
615    fn check_older(&self, s: relative::LockTime) -> bool {
616        if let Some(timelock) = self.relative_timelock {
617            s.is_implied_by(timelock)
618        } else {
619            false
620        }
621    }
622
623    fn check_after(&self, l: absolute::LockTime) -> bool {
624        if let Some(timelock) = self.absolute_timelock {
625            l.is_implied_by(timelock)
626        } else {
627            false
628        }
629    }
630}
631
632impl FromIterator<DescriptorPublicKey> for Assets {
633    fn from_iter<I: IntoIterator<Item = DescriptorPublicKey>>(iter: I) -> Self {
634        let mut keys = BTreeSet::new();
635        for pk in iter {
636            for deriv_path in pk.full_derivation_paths() {
637                keys.insert(((pk.master_fingerprint(), deriv_path), CanSign::default()));
638            }
639        }
640        Assets { keys, ..Default::default() }
641    }
642}
643
644/// Conversion into a `Assets`
645pub trait IntoAssets {
646    /// Convert `self` into a `Assets` struct
647    fn into_assets(self) -> Assets;
648}
649
650impl IntoAssets for KeyMap {
651    fn into_assets(self) -> Assets { Assets::from_iter(self.into_iter().map(|(k, _)| k)) }
652}
653
654impl IntoAssets for DescriptorPublicKey {
655    fn into_assets(self) -> Assets { vec![self].into_assets() }
656}
657
658impl IntoAssets for Vec<DescriptorPublicKey> {
659    fn into_assets(self) -> Assets { Assets::from_iter(self) }
660}
661
662impl IntoAssets for sha256::Hash {
663    fn into_assets(self) -> Assets {
664        Assets { sha256_preimages: vec![self].into_iter().collect(), ..Default::default() }
665    }
666}
667
668impl IntoAssets for hash256::Hash {
669    fn into_assets(self) -> Assets {
670        Assets { hash256_preimages: vec![self].into_iter().collect(), ..Default::default() }
671    }
672}
673
674impl IntoAssets for ripemd160::Hash {
675    fn into_assets(self) -> Assets {
676        Assets { ripemd160_preimages: vec![self].into_iter().collect(), ..Default::default() }
677    }
678}
679
680impl IntoAssets for hash160::Hash {
681    fn into_assets(self) -> Assets {
682        Assets { hash160_preimages: vec![self].into_iter().collect(), ..Default::default() }
683    }
684}
685
686impl IntoAssets for Assets {
687    fn into_assets(self) -> Assets { self }
688}
689
690impl Assets {
691    /// Construct an empty instance
692    pub fn new() -> Self { Self::default() }
693
694    /// Add some assets
695    #[allow(clippy::should_implement_trait)] // looks like the `ops::Add` trait
696    pub fn add<A: IntoAssets>(mut self, asset: A) -> Self {
697        self.append(asset.into_assets());
698        self
699    }
700
701    /// Set the maximum relative timelock allowed
702    pub fn older(mut self, seq: relative::LockTime) -> Self {
703        self.relative_timelock = Some(seq);
704        self
705    }
706
707    /// Set the maximum absolute timelock allowed
708    pub fn after(mut self, lt: absolute::LockTime) -> Self {
709        self.absolute_timelock = Some(lt);
710        self
711    }
712
713    fn append(&mut self, b: Self) {
714        self.keys.extend(b.keys);
715        self.sha256_preimages.extend(b.sha256_preimages);
716        self.hash256_preimages.extend(b.hash256_preimages);
717        self.ripemd160_preimages.extend(b.ripemd160_preimages);
718        self.hash160_preimages.extend(b.hash160_preimages);
719
720        self.relative_timelock = b.relative_timelock.or(self.relative_timelock);
721        self.absolute_timelock = b.absolute_timelock.or(self.absolute_timelock);
722    }
723}
724
725#[cfg(test)]
726mod test {
727    use std::str::FromStr;
728
729    use bitcoin::bip32::Xpub;
730
731    use super::*;
732    use crate::*;
733
734    #[allow(clippy::type_complexity)]
735    fn test_inner(
736        desc: &str,
737        keys: Vec<DescriptorPublicKey>,
738        hashes: Vec<hash160::Hash>,
739        // [ (key_indexes, hash_indexes, older, after, expected) ]
740        tests: Vec<(
741            Vec<usize>,
742            Vec<usize>,
743            Option<relative::LockTime>,
744            Option<absolute::LockTime>,
745            Option<usize>,
746        )>,
747    ) {
748        let desc = Descriptor::<DefiniteDescriptorKey>::from_str(desc).unwrap();
749
750        for (key_indexes, hash_indexes, older, after, expected) in tests {
751            let mut assets = Assets::new();
752            if let Some(seq) = older {
753                assets = assets.older(seq);
754            }
755            if let Some(locktime) = after {
756                assets = assets.after(locktime);
757            }
758            for ki in key_indexes {
759                assets = assets.add(keys[ki].clone());
760            }
761            for hi in hash_indexes {
762                assets = assets.add(hashes[hi]);
763            }
764
765            let result = desc.clone().plan(&assets);
766            assert_eq!(
767                result.as_ref().ok().map(|plan| plan.satisfaction_weight()),
768                expected,
769                "{:#?}",
770                result
771            );
772        }
773    }
774
775    #[test]
776    fn test_or() {
777        let keys = vec![
778            DescriptorPublicKey::from_str(
779                "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
780            )
781            .unwrap(),
782            DescriptorPublicKey::from_str(
783                "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
784            )
785            .unwrap(),
786        ];
787        let hashes = vec![];
788        let desc = format!("wsh(t:or_c(pk({}),v:pkh({})))", keys[0], keys[1]);
789
790        // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig)
791        let tests = vec![
792            (vec![], vec![], None, None, None),
793            (vec![0], vec![], None, None, Some(4 + 1 + 73)),
794            (vec![0, 1], vec![], None, None, Some(4 + 1 + 73)),
795        ];
796
797        test_inner(&desc, keys, hashes, tests);
798    }
799
800    #[test]
801    fn test_and() {
802        let keys = vec![
803            DescriptorPublicKey::from_str(
804                "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
805            )
806            .unwrap(),
807            DescriptorPublicKey::from_str(
808                "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
809            )
810            .unwrap(),
811        ];
812        let hashes = vec![];
813        let desc = format!("wsh(and_v(v:pk({}),pk({})))", keys[0], keys[1]);
814
815        // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 2
816        let tests = vec![
817            (vec![], vec![], None, None, None),
818            (vec![0], vec![], None, None, None),
819            (vec![0, 1], vec![], None, None, Some(4 + 1 + 73 * 2)),
820        ];
821
822        test_inner(&desc, keys, hashes, tests);
823    }
824
825    #[test]
826    fn test_multi() {
827        let keys = vec![
828            DescriptorPublicKey::from_str(
829                "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
830            )
831            .unwrap(),
832            DescriptorPublicKey::from_str(
833                "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
834            )
835            .unwrap(),
836            DescriptorPublicKey::from_str(
837                "03500a2b48b0f66c8183cc0d6645ab21cc19c7fad8a33ff04d41c3ece54b0bc1c5",
838            )
839            .unwrap(),
840            DescriptorPublicKey::from_str(
841                "033ad2d191da4f39512adbaac320cae1f12f298386a4e9d43fd98dec7cf5db2ac9",
842            )
843            .unwrap(),
844        ];
845        let hashes = vec![];
846        let desc = format!("wsh(multi(3,{},{},{},{}))", keys[0], keys[1], keys[2], keys[3]);
847
848        let tests = vec![
849            (vec![], vec![], None, None, None),
850            (vec![0, 1], vec![], None, None, None),
851            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 3 + 1 (dummy push)
852            (vec![0, 1, 3], vec![], None, None, Some(4 + 1 + 73 * 3 + 1)),
853        ];
854
855        test_inner(&desc, keys, hashes, tests);
856    }
857
858    #[test]
859    fn test_thresh() {
860        // relative::LockTime has no constructors except by going through Sequence
861        use bitcoin::Sequence;
862        let keys = vec![
863            DescriptorPublicKey::from_str(
864                "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
865            )
866            .unwrap(),
867            DescriptorPublicKey::from_str(
868                "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
869            )
870            .unwrap(),
871        ];
872        let hashes = vec![];
873        let desc = format!("wsh(thresh(2,pk({}),s:pk({}),snl:older(144)))", keys[0], keys[1]);
874
875        let tests = vec![
876            (vec![], vec![], None, None, None),
877            (
878                vec![],
879                vec![],
880                Some(Sequence(1000).to_relative_lock_time().unwrap()),
881                None,
882                None,
883            ),
884            (vec![0], vec![], None, None, None),
885            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) + 1 (OP_0) + 1 (OP_ZERO)
886            (
887                vec![0],
888                vec![],
889                Some(Sequence(1000).to_relative_lock_time().unwrap()),
890                None,
891                Some(80),
892            ),
893            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 2 + 2 (OP_PUSHBYTE_1 0x01)
894            (vec![0, 1], vec![], None, None, Some(153)),
895            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) + 1 (OP_0) + 1 (OP_ZERO)
896            (
897                vec![0, 1],
898                vec![],
899                Some(Sequence(1000).to_relative_lock_time().unwrap()),
900                None,
901                Some(80),
902            ),
903            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 2 + 2 (OP_PUSHBYTE_1 0x01)
904            (
905                vec![0, 1],
906                vec![],
907                Some(
908                    Sequence::from_512_second_intervals(10)
909                        .to_relative_lock_time()
910                        .unwrap(),
911                ),
912                None,
913                Some(153),
914            ), // incompatible timelock
915        ];
916
917        test_inner(&desc, keys.clone(), hashes.clone(), tests);
918
919        let desc = format!("wsh(thresh(2,pk({}),s:pk({}),snl:after(144)))", keys[0], keys[1]);
920
921        let tests = vec![
922            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) + 1 (OP_0) + 1 (OP_ZERO)
923            (
924                vec![0],
925                vec![],
926                None,
927                Some(absolute::LockTime::from_height(1000).unwrap()),
928                Some(80),
929            ),
930            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 2 + 2 (OP_PUSHBYTE_1 0x01)
931            (
932                vec![0, 1],
933                vec![],
934                None,
935                Some(absolute::LockTime::from_time(500_001_000).unwrap()),
936                Some(153),
937            ), // incompatible timelock
938        ];
939
940        test_inner(&desc, keys, hashes, tests);
941    }
942
943    #[test]
944    fn test_taproot() {
945        let keys = vec![
946            DescriptorPublicKey::from_str(
947                "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
948            )
949            .unwrap(),
950            DescriptorPublicKey::from_str(
951                "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a",
952            )
953            .unwrap(),
954            DescriptorPublicKey::from_str(
955                "03500a2b48b0f66c8183cc0d6645ab21cc19c7fad8a33ff04d41c3ece54b0bc1c5",
956            )
957            .unwrap(),
958            DescriptorPublicKey::from_str(
959                "033ad2d191da4f39512adbaac320cae1f12f298386a4e9d43fd98dec7cf5db2ac9",
960            )
961            .unwrap(),
962            DescriptorPublicKey::from_str(
963                "023fc33527afab09fa97135f2180bcd22ce637b1d2fbcb2db748b1f2c33f45b2b4",
964            )
965            .unwrap(),
966        ];
967        let hashes = vec![];
968        //    .
969        //   / \
970        //  .   .
971        //  A  / \
972        //    .   .
973        //    B   C
974        //  where A = pk(key1)
975        //        B = multi(1, key2, key3)
976        //        C = and(key4, after(10))
977        let desc = format!(
978            "tr({},{{pk({}),{{multi_a(1,{},{}),and_v(v:pk({}),after(10))}}}})",
979            keys[0], keys[1], keys[2], keys[3], keys[4]
980        );
981
982        // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 64 (sig)
983        let internal_key_sat_weight = Some(70);
984        // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 64 (sig)
985        // + 1 (script len)
986        // + 34 [script: 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIG)]
987        // + 1 (control block len)
988        // + 65 [control block: 1 (control byte) + 32 (internal key) + 32 (hash BC)]
989        let first_leaf_sat_weight = Some(171);
990        // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 64 (sig)
991        // + 1 (OP_ZERO)
992        // + 1 (script len)
993        // + 70 [script: 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIG)
994        //       + 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIGADD)
995        //       + 1 (OP_PUSHNUM1) + 1 (OP_NUMEQUAL)]
996        // + 1 (control block len)
997        // + 97 [control block: 1 (control byte) + 32 (internal key) + 32 (hash C) + 32 (hash
998        //       A)]
999        let second_leaf_sat_weight = Some(240);
1000        // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 64 (sig)
1001        // + 1 (script len)
1002        // + 36 [script: 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIGVERIFY)
1003        //       + 1 (OP_PUSHNUM_10) + 1 (OP_CLTV)]
1004        // + 1 (control block len)
1005        // + 97 [control block: 1 (control byte) + 32 (internal key) + 32 (hash B) + 32 (hash
1006        //       A)]
1007        let third_leaf_sat_weight = Some(205);
1008
1009        let tests = vec![
1010            // Don't give assets
1011            (vec![], vec![], None, None, None),
1012            // Spend with internal key
1013            (vec![0], vec![], None, None, internal_key_sat_weight),
1014            // Spend with first leaf (single pk)
1015            (vec![1], vec![], None, None, first_leaf_sat_weight),
1016            // Spend with second leaf (1of2)
1017            (vec![2], vec![], None, None, second_leaf_sat_weight),
1018            // Spend with second leaf (1of2)
1019            (vec![2, 3], vec![], None, None, second_leaf_sat_weight),
1020            // Spend with third leaf (key + timelock)
1021            (
1022                vec![4],
1023                vec![],
1024                None,
1025                Some(absolute::LockTime::from_height(10).unwrap()),
1026                third_leaf_sat_weight,
1027            ),
1028            // Spend with third leaf (key + timelock),
1029            // but timelock is too low (=impossible)
1030            (vec![4], vec![], None, Some(absolute::LockTime::from_height(9).unwrap()), None),
1031            // Spend with third leaf (key + timelock),
1032            // but timelock is in the wrong unit (=impossible)
1033            (
1034                vec![4],
1035                vec![],
1036                None,
1037                Some(absolute::LockTime::from_time(1296000000).unwrap()),
1038                None,
1039            ),
1040            // Spend with third leaf (key + timelock),
1041            // but don't give the timelock (=impossible)
1042            (vec![4], vec![], None, None, None),
1043            // Give all the keys (internal key will be used, as it's cheaper)
1044            (vec![0, 1, 2, 3, 4], vec![], None, None, internal_key_sat_weight),
1045            // Give all the leaf keys (uses 1st leaf)
1046            (vec![1, 2, 3, 4], vec![], None, None, first_leaf_sat_weight),
1047            // Give 2nd+3rd leaf without timelock (uses 2nd leaf)
1048            (vec![2, 3, 4], vec![], None, None, second_leaf_sat_weight),
1049            // Give 2nd+3rd leaf with timelock (uses 3rd leaf)
1050            (
1051                vec![2, 3, 4],
1052                vec![],
1053                None,
1054                Some(absolute::LockTime::from_consensus(11)),
1055                third_leaf_sat_weight,
1056            ),
1057        ];
1058
1059        test_inner(&desc, keys, hashes, tests);
1060    }
1061
1062    #[test]
1063    fn test_hash() {
1064        let keys = vec![DescriptorPublicKey::from_str(
1065            "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c",
1066        )
1067        .unwrap()];
1068        let hashes = vec![hash160::Hash::from_slice(&[0; 20]).unwrap()];
1069        let desc = format!("wsh(and_v(v:pk({}),hash160({})))", keys[0], hashes[0]);
1070
1071        let tests = vec![
1072            // No assets, impossible
1073            (vec![], vec![], None, None, None),
1074            // Only key, impossible
1075            (vec![0], vec![], None, None, None),
1076            // Only hash, impossible
1077            (vec![], vec![0], None, None, None),
1078            // Key + hash
1079            // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) + 1 (OP_PUSH) + 32 (preimage)
1080            (vec![0], vec![0], None, None, Some(111)),
1081        ];
1082
1083        test_inner(&desc, keys, hashes, tests);
1084    }
1085
1086    #[test]
1087    fn test_plan_update_psbt_tr() {
1088        // keys taken from: https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki#Specifications
1089        let root_xpub = Xpub::from_str("xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8").unwrap();
1090        let fingerprint = root_xpub.fingerprint();
1091        let xpub = format!("[{}/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ", fingerprint);
1092        let desc =
1093            format!("tr({}/0/0,{{pkh({}/0/1),multi_a(2,{}/1/0,{}/1/1)}})", xpub, xpub, xpub, xpub);
1094
1095        let desc = Descriptor::from_str(&desc).unwrap();
1096
1097        let internal_key = DescriptorPublicKey::from_str(&format!("{}/0/0", xpub)).unwrap();
1098        let first_branch = DescriptorPublicKey::from_str(&format!("{}/0/1", xpub)).unwrap();
1099        let second_branch = DescriptorPublicKey::from_str(&format!("{}/1/*", xpub)).unwrap(); // Note this is a wildcard key, so it can sign for the whole multi_a
1100
1101        let mut psbt_input = bitcoin::psbt::Input::default();
1102        let assets = Assets::new().add(internal_key);
1103        desc.clone()
1104            .plan(&assets)
1105            .unwrap()
1106            .update_psbt_input(&mut psbt_input);
1107        assert!(psbt_input.tap_internal_key.is_some(), "Internal key is missing");
1108        assert!(psbt_input.tap_merkle_root.is_some(), "Merkle root is missing");
1109        assert_eq!(psbt_input.tap_key_origins.len(), 1, "Unexpected number of tap_key_origins");
1110        assert_eq!(psbt_input.tap_scripts.len(), 0, "Unexpected number of tap_scripts");
1111
1112        let mut psbt_input = bitcoin::psbt::Input::default();
1113        let assets = Assets::new().add(first_branch);
1114        desc.clone()
1115            .plan(&assets)
1116            .unwrap()
1117            .update_psbt_input(&mut psbt_input);
1118        assert!(psbt_input.tap_internal_key.is_none(), "Internal key is present");
1119        assert!(psbt_input.tap_merkle_root.is_some(), "Merkle root is missing");
1120        assert_eq!(psbt_input.tap_key_origins.len(), 1, "Unexpected number of tap_key_origins");
1121        assert_eq!(psbt_input.tap_scripts.len(), 1, "Unexpected number of tap_scripts");
1122
1123        let mut psbt_input = bitcoin::psbt::Input::default();
1124        let assets = Assets::new().add(second_branch);
1125        desc.plan(&assets)
1126            .unwrap()
1127            .update_psbt_input(&mut psbt_input);
1128        assert!(psbt_input.tap_internal_key.is_none(), "Internal key is present");
1129        assert!(psbt_input.tap_merkle_root.is_some(), "Merkle root is missing");
1130        assert_eq!(psbt_input.tap_key_origins.len(), 2, "Unexpected number of tap_key_origins");
1131        assert_eq!(psbt_input.tap_scripts.len(), 1, "Unexpected number of tap_scripts");
1132    }
1133
1134    #[test]
1135    fn test_plan_update_psbt_segwit() {
1136        // keys taken from: https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki#Specifications
1137        let root_xpub = Xpub::from_str("xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8").unwrap();
1138        let fingerprint = root_xpub.fingerprint();
1139        let xpub = format!("[{}/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ", fingerprint);
1140        let desc = format!("wsh(multi(2,{}/1/0,{}/1/1))", xpub, xpub);
1141
1142        let desc = Descriptor::from_str(&desc).unwrap();
1143
1144        let asset_key = DescriptorPublicKey::from_str(&format!("{}/1/*", xpub)).unwrap(); // Note this is a wildcard key, so it can sign for the whole multi
1145
1146        let mut psbt_input = bitcoin::psbt::Input::default();
1147        let assets = Assets::new().add(asset_key);
1148        desc.plan(&assets)
1149            .unwrap()
1150            .update_psbt_input(&mut psbt_input);
1151        assert!(psbt_input.witness_script.is_some(), "Witness script missing");
1152        assert!(psbt_input.redeem_script.is_none(), "Redeem script present");
1153        assert_eq!(psbt_input.bip32_derivation.len(), 2, "Unexpected number of bip32_derivation");
1154    }
1155}