bdk_wallet/descriptor/
mod.rs

1// Bitcoin Dev Kit
2// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
3//
4// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
5//
6// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
7// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
9// You may not use this file except in accordance with one or both of these
10// licenses.
11
12//! Descriptors
13//!
14//! This module contains generic utilities to work with descriptors, plus some re-exported types
15//! from [`miniscript`].
16
17use crate::alloc::string::ToString;
18use crate::collections::BTreeMap;
19use alloc::string::String;
20use alloc::vec::Vec;
21
22use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, KeySource, Xpub};
23use bitcoin::{key::XOnlyPublicKey, secp256k1, PublicKey};
24use bitcoin::{psbt, taproot};
25use bitcoin::{Network, TxOut};
26
27use miniscript::descriptor::{
28    DefiniteDescriptorKey, DescriptorMultiXKey, DescriptorSecretKey, DescriptorType,
29    DescriptorXKey, InnerXKey, KeyMap, SinglePubKey, Wildcard,
30};
31pub use miniscript::{
32    Descriptor, DescriptorPublicKey, Legacy, Miniscript, ScriptContext, Segwitv0,
33};
34use miniscript::{ForEachKey, MiniscriptKey, TranslatePk};
35
36use crate::descriptor::policy::BuildSatisfaction;
37
38pub mod checksum;
39#[doc(hidden)]
40pub mod dsl;
41pub mod error;
42pub mod policy;
43pub mod template;
44
45pub use self::checksum::calc_checksum;
46pub use self::error::Error as DescriptorError;
47pub use self::policy::Policy;
48use self::template::DescriptorTemplateOut;
49use crate::keys::{IntoDescriptorKey, KeyError};
50use crate::wallet::signer::SignersContainer;
51use crate::wallet::utils::SecpCtx;
52
53/// Alias for a [`Descriptor`] that can contain extended keys using [`DescriptorPublicKey`]
54pub type ExtendedDescriptor = Descriptor<DescriptorPublicKey>;
55
56/// Alias for a [`Descriptor`] that contains extended **derived** keys
57pub type DerivedDescriptor = Descriptor<DefiniteDescriptorKey>;
58
59/// Alias for the type of maps that represent derivation paths in a [`psbt::Input`] or
60/// [`psbt::Output`]
61///
62/// [`psbt::Input`]: bitcoin::psbt::Input
63/// [`psbt::Output`]: bitcoin::psbt::Output
64pub type HdKeyPaths = BTreeMap<secp256k1::PublicKey, KeySource>;
65
66/// Alias for the type of maps that represent taproot key origins in a [`psbt::Input`] or
67/// [`psbt::Output`]
68///
69/// [`psbt::Input`]: bitcoin::psbt::Input
70/// [`psbt::Output`]: bitcoin::psbt::Output
71pub type TapKeyOrigins = BTreeMap<XOnlyPublicKey, (Vec<taproot::TapLeafHash>, KeySource)>;
72
73/// Trait for types which can be converted into an [`ExtendedDescriptor`] and a [`KeyMap`] usable by
74/// a wallet in a specific [`Network`]
75pub trait IntoWalletDescriptor {
76    /// Convert to wallet descriptor
77    fn into_wallet_descriptor(
78        self,
79        secp: &SecpCtx,
80        network: Network,
81    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError>;
82}
83
84impl IntoWalletDescriptor for &str {
85    fn into_wallet_descriptor(
86        self,
87        secp: &SecpCtx,
88        network: Network,
89    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
90        let descriptor = match self.split_once('#') {
91            Some((desc, original_checksum)) => {
92                let checksum = calc_checksum(desc)?;
93                if original_checksum != checksum {
94                    return Err(DescriptorError::InvalidDescriptorChecksum);
95                }
96                desc
97            }
98            None => self,
99        };
100
101        ExtendedDescriptor::parse_descriptor(secp, descriptor)?
102            .into_wallet_descriptor(secp, network)
103    }
104}
105
106impl IntoWalletDescriptor for &String {
107    fn into_wallet_descriptor(
108        self,
109        secp: &SecpCtx,
110        network: Network,
111    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
112        self.as_str().into_wallet_descriptor(secp, network)
113    }
114}
115
116impl IntoWalletDescriptor for String {
117    fn into_wallet_descriptor(
118        self,
119        secp: &SecpCtx,
120        network: Network,
121    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
122        self.as_str().into_wallet_descriptor(secp, network)
123    }
124}
125
126impl IntoWalletDescriptor for ExtendedDescriptor {
127    fn into_wallet_descriptor(
128        self,
129        secp: &SecpCtx,
130        network: Network,
131    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
132        (self, KeyMap::default()).into_wallet_descriptor(secp, network)
133    }
134}
135
136impl IntoWalletDescriptor for (ExtendedDescriptor, KeyMap) {
137    fn into_wallet_descriptor(
138        self,
139        secp: &SecpCtx,
140        network: Network,
141    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
142        use crate::keys::DescriptorKey;
143
144        struct Translator<'s, 'd> {
145            secp: &'s SecpCtx,
146            descriptor: &'d ExtendedDescriptor,
147            network: Network,
148        }
149
150        impl miniscript::Translator<DescriptorPublicKey, String, DescriptorError> for Translator<'_, '_> {
151            fn pk(&mut self, pk: &DescriptorPublicKey) -> Result<String, DescriptorError> {
152                let secp = &self.secp;
153
154                let (_, _, networks) = if self.descriptor.is_taproot() {
155                    let descriptor_key: DescriptorKey<miniscript::Tap> =
156                        pk.clone().into_descriptor_key()?;
157                    descriptor_key.extract(secp)?
158                } else if self.descriptor.is_witness() {
159                    let descriptor_key: DescriptorKey<miniscript::Segwitv0> =
160                        pk.clone().into_descriptor_key()?;
161                    descriptor_key.extract(secp)?
162                } else {
163                    let descriptor_key: DescriptorKey<miniscript::Legacy> =
164                        pk.clone().into_descriptor_key()?;
165                    descriptor_key.extract(secp)?
166                };
167
168                if networks.contains(&self.network) {
169                    Ok(Default::default())
170                } else {
171                    Err(DescriptorError::Key(KeyError::InvalidNetwork))
172                }
173            }
174            fn sha256(
175                &mut self,
176                _sha256: &<DescriptorPublicKey as MiniscriptKey>::Sha256,
177            ) -> Result<String, DescriptorError> {
178                Ok(Default::default())
179            }
180            fn hash256(
181                &mut self,
182                _hash256: &<DescriptorPublicKey as MiniscriptKey>::Hash256,
183            ) -> Result<String, DescriptorError> {
184                Ok(Default::default())
185            }
186            fn ripemd160(
187                &mut self,
188                _ripemd160: &<DescriptorPublicKey as MiniscriptKey>::Ripemd160,
189            ) -> Result<String, DescriptorError> {
190                Ok(Default::default())
191            }
192            fn hash160(
193                &mut self,
194                _hash160: &<DescriptorPublicKey as MiniscriptKey>::Hash160,
195            ) -> Result<String, DescriptorError> {
196                Ok(Default::default())
197            }
198        }
199
200        // check the network for the keys
201        use miniscript::TranslateErr;
202        match self.0.translate_pk(&mut Translator {
203            secp,
204            network,
205            descriptor: &self.0,
206        }) {
207            Ok(_) => {}
208            Err(TranslateErr::TranslatorErr(e)) => return Err(e),
209            Err(TranslateErr::OuterError(e)) => return Err(e.into()),
210        }
211
212        Ok(self)
213    }
214}
215
216impl IntoWalletDescriptor for DescriptorTemplateOut {
217    fn into_wallet_descriptor(
218        self,
219        _secp: &SecpCtx,
220        network: Network,
221    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
222        struct Translator {
223            network: Network,
224        }
225
226        impl miniscript::Translator<DescriptorPublicKey, DescriptorPublicKey, DescriptorError>
227            for Translator
228        {
229            fn pk(
230                &mut self,
231                pk: &DescriptorPublicKey,
232            ) -> Result<DescriptorPublicKey, DescriptorError> {
233                // workaround for xpubs generated by other key types, like bip39: since when the
234                // conversion is made one network has to be chosen, what we generally choose
235                // "mainnet", but then override the set of valid networks to specify that all of
236                // them are valid. here we reset the network to make sure the wallet struct gets a
237                // descriptor with the right network everywhere.
238                let pk = match pk {
239                    DescriptorPublicKey::XPub(ref xpub) => {
240                        let mut xpub = xpub.clone();
241                        xpub.xkey.network = self.network.into();
242
243                        DescriptorPublicKey::XPub(xpub)
244                    }
245                    other => other.clone(),
246                };
247
248                Ok(pk)
249            }
250            miniscript::translate_hash_clone!(
251                DescriptorPublicKey,
252                DescriptorPublicKey,
253                DescriptorError
254            );
255        }
256
257        let (desc, keymap, networks) = self;
258
259        if !networks.contains(&network) {
260            return Err(DescriptorError::Key(KeyError::InvalidNetwork));
261        }
262
263        // fixup the network for keys that need it in the descriptor
264        use miniscript::TranslateErr;
265        let translated = match desc.translate_pk(&mut Translator { network }) {
266            Ok(descriptor) => descriptor,
267            Err(TranslateErr::TranslatorErr(e)) => return Err(e),
268            Err(TranslateErr::OuterError(e)) => return Err(e.into()),
269        };
270        // ...and in the key map
271        let fixed_keymap = keymap
272            .into_iter()
273            .map(|(mut k, mut v)| {
274                match (&mut k, &mut v) {
275                    (DescriptorPublicKey::XPub(xpub), DescriptorSecretKey::XPrv(xprv)) => {
276                        xpub.xkey.network = network.into();
277                        xprv.xkey.network = network.into();
278                    }
279                    (_, DescriptorSecretKey::Single(key)) => {
280                        key.key.network = network.into();
281                    }
282                    _ => {}
283                }
284
285                (k, v)
286            })
287            .collect();
288
289        Ok((translated, fixed_keymap))
290    }
291}
292
293/// Extra checks for [`ExtendedDescriptor`].
294pub(crate) fn check_wallet_descriptor(
295    descriptor: &Descriptor<DescriptorPublicKey>,
296) -> Result<(), DescriptorError> {
297    // Ensure the keys don't contain any hardened derivation steps or hardened wildcards
298    let descriptor_contains_hardened_steps = descriptor.for_any_key(|k| {
299        if let DescriptorPublicKey::XPub(DescriptorXKey {
300            derivation_path,
301            wildcard,
302            ..
303        }) = k
304        {
305            return *wildcard == Wildcard::Hardened
306                || derivation_path.into_iter().any(ChildNumber::is_hardened);
307        }
308
309        false
310    });
311    if descriptor_contains_hardened_steps {
312        return Err(DescriptorError::HardenedDerivationXpub);
313    }
314
315    if descriptor.is_multipath() {
316        return Err(DescriptorError::Miniscript(
317            miniscript::Error::BadDescriptor(
318                "`check_wallet_descriptor` must not contain multipath keys".to_string(),
319            ),
320        ));
321    }
322
323    // Run miniscript's sanity check, which will look for duplicated keys and other potential
324    // issues
325    descriptor.sanity_check()?;
326
327    Ok(())
328}
329
330#[doc(hidden)]
331/// Used internally mainly by the `descriptor!()` and `fragment!()` macros
332pub trait CheckMiniscript<Ctx: miniscript::ScriptContext> {
333    fn check_miniscript(&self) -> Result<(), miniscript::Error>;
334}
335
336impl<Ctx: miniscript::ScriptContext, Pk: miniscript::MiniscriptKey> CheckMiniscript<Ctx>
337    for miniscript::Miniscript<Pk, Ctx>
338{
339    fn check_miniscript(&self) -> Result<(), miniscript::Error> {
340        Ctx::check_global_validity(self)?;
341
342        Ok(())
343    }
344}
345
346/// Trait implemented on [`Descriptor`]s to add a method to extract the spending [`policy`]
347pub trait ExtractPolicy {
348    /// Extract the spending [`policy`]
349    fn extract_policy(
350        &self,
351        signers: &SignersContainer,
352        psbt: BuildSatisfaction,
353        secp: &SecpCtx,
354    ) -> Result<Option<Policy>, DescriptorError>;
355}
356
357pub(crate) trait XKeyUtils {
358    fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint;
359}
360
361impl<T> XKeyUtils for DescriptorMultiXKey<T>
362where
363    T: InnerXKey,
364{
365    fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint {
366        match self.origin {
367            Some((fingerprint, _)) => fingerprint,
368            None => self.xkey.xkey_fingerprint(secp),
369        }
370    }
371}
372
373impl<T> XKeyUtils for DescriptorXKey<T>
374where
375    T: InnerXKey,
376{
377    fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint {
378        match self.origin {
379            Some((fingerprint, _)) => fingerprint,
380            None => self.xkey.xkey_fingerprint(secp),
381        }
382    }
383}
384
385pub(crate) trait DescriptorMeta {
386    fn is_witness(&self) -> bool;
387    fn is_taproot(&self) -> bool;
388    fn get_extended_keys(&self) -> Vec<DescriptorXKey<Xpub>>;
389    fn derive_from_hd_keypaths(
390        &self,
391        hd_keypaths: &HdKeyPaths,
392        secp: &SecpCtx,
393    ) -> Option<DerivedDescriptor>;
394    fn derive_from_tap_key_origins(
395        &self,
396        tap_key_origins: &TapKeyOrigins,
397        secp: &SecpCtx,
398    ) -> Option<DerivedDescriptor>;
399    fn derive_from_psbt_key_origins(
400        &self,
401        key_origins: BTreeMap<Fingerprint, (&DerivationPath, SinglePubKey)>,
402        secp: &SecpCtx,
403    ) -> Option<DerivedDescriptor>;
404    fn derive_from_psbt_input(
405        &self,
406        psbt_input: &psbt::Input,
407        utxo: Option<TxOut>,
408        secp: &SecpCtx,
409    ) -> Option<DerivedDescriptor>;
410}
411
412impl DescriptorMeta for ExtendedDescriptor {
413    fn is_witness(&self) -> bool {
414        matches!(
415            self.desc_type(),
416            DescriptorType::Wpkh
417                | DescriptorType::ShWpkh
418                | DescriptorType::Wsh
419                | DescriptorType::ShWsh
420                | DescriptorType::ShWshSortedMulti
421                | DescriptorType::WshSortedMulti
422        )
423    }
424
425    fn is_taproot(&self) -> bool {
426        self.desc_type() == DescriptorType::Tr
427    }
428
429    fn get_extended_keys(&self) -> Vec<DescriptorXKey<Xpub>> {
430        let mut answer = Vec::new();
431
432        self.for_each_key(|pk| {
433            if let DescriptorPublicKey::XPub(xpub) = pk {
434                answer.push(xpub.clone());
435            }
436
437            true
438        });
439
440        answer
441    }
442
443    fn derive_from_psbt_key_origins(
444        &self,
445        key_origins: BTreeMap<Fingerprint, (&DerivationPath, SinglePubKey)>,
446        secp: &SecpCtx,
447    ) -> Option<DerivedDescriptor> {
448        // Ensure that deriving `xpub` with `path` yields `expected`
449        let verify_key =
450            |xpub: &DescriptorXKey<Xpub>, path: &DerivationPath, expected: &SinglePubKey| {
451                let derived = xpub
452                    .xkey
453                    .derive_pub(secp, path)
454                    .expect("The path should never contain hardened derivation steps")
455                    .public_key;
456
457                match expected {
458                    SinglePubKey::FullKey(pk) if &PublicKey::new(derived) == pk => true,
459                    SinglePubKey::XOnly(pk) if &XOnlyPublicKey::from(derived) == pk => true,
460                    _ => false,
461                }
462            };
463
464        let mut path_found = None;
465
466        // using `for_any_key` should make this stop as soon as we return `true`
467        self.for_any_key(|key| {
468            if let DescriptorPublicKey::XPub(xpub) = key {
469                // Check if the key matches one entry in our `key_origins`. If it does, `matches()`
470                // will return the "prefix" that matched, so we remove that prefix
471                // from the full path found in `key_origins` and save it in
472                // `derive_path`. We expect this to be a derivation path of length 1
473                // if the key is `wildcard` and an empty path otherwise.
474                let root_fingerprint = xpub.root_fingerprint(secp);
475                let derive_path = key_origins
476                    .get_key_value(&root_fingerprint)
477                    .and_then(|(fingerprint, (path, expected))| {
478                        xpub.matches(&(*fingerprint, (*path).clone()), secp)
479                            .zip(Some((path, expected)))
480                    })
481                    .and_then(|(prefix, (full_path, expected))| {
482                        let derive_path = full_path
483                            .into_iter()
484                            .skip(prefix.into_iter().count())
485                            .cloned()
486                            .collect::<DerivationPath>();
487
488                        // `derive_path` only contains the replacement index for the wildcard, if
489                        // present, or an empty path for fixed descriptors.
490                        // To verify the key we also need the normal steps
491                        // that come before the wildcard, so we take them directly from `xpub` and
492                        // then append the final index
493                        if verify_key(
494                            xpub,
495                            &xpub.derivation_path.extend(derive_path.clone()),
496                            expected,
497                        ) {
498                            Some(derive_path)
499                        } else {
500                            None
501                        }
502                    });
503
504                match derive_path {
505                    Some(path) if xpub.wildcard != Wildcard::None && path.len() == 1 => {
506                        // Ignore hardened wildcards
507                        if let ChildNumber::Normal { index } = path[0] {
508                            path_found = Some(index);
509                            return true;
510                        }
511                    }
512                    Some(path) if xpub.wildcard == Wildcard::None && path.is_empty() => {
513                        path_found = Some(0);
514                        return true;
515                    }
516                    _ => {}
517                }
518            }
519
520            false
521        });
522
523        path_found.map(|path| {
524            self.at_derivation_index(path)
525                .expect("We ignore hardened wildcards")
526        })
527    }
528
529    fn derive_from_hd_keypaths(
530        &self,
531        hd_keypaths: &HdKeyPaths,
532        secp: &SecpCtx,
533    ) -> Option<DerivedDescriptor> {
534        // "Convert" an hd_keypaths map to the format required by `derive_from_psbt_key_origins`
535        let key_origins = hd_keypaths
536            .iter()
537            .map(|(pk, (fingerprint, path))| {
538                (
539                    *fingerprint,
540                    (path, SinglePubKey::FullKey(PublicKey::new(*pk))),
541                )
542            })
543            .collect();
544        self.derive_from_psbt_key_origins(key_origins, secp)
545    }
546
547    fn derive_from_tap_key_origins(
548        &self,
549        tap_key_origins: &TapKeyOrigins,
550        secp: &SecpCtx,
551    ) -> Option<DerivedDescriptor> {
552        // "Convert" a tap_key_origins map to the format required by `derive_from_psbt_key_origins`
553        let key_origins = tap_key_origins
554            .iter()
555            .map(|(pk, (_, (fingerprint, path)))| (*fingerprint, (path, SinglePubKey::XOnly(*pk))))
556            .collect();
557        self.derive_from_psbt_key_origins(key_origins, secp)
558    }
559
560    fn derive_from_psbt_input(
561        &self,
562        psbt_input: &psbt::Input,
563        utxo: Option<TxOut>,
564        secp: &SecpCtx,
565    ) -> Option<DerivedDescriptor> {
566        if let Some(derived) = self.derive_from_hd_keypaths(&psbt_input.bip32_derivation, secp) {
567            return Some(derived);
568        }
569        if let Some(derived) = self.derive_from_tap_key_origins(&psbt_input.tap_key_origins, secp) {
570            return Some(derived);
571        }
572        if self.has_wildcard() {
573            // We can't try to bruteforce the derivation index, exit here
574            return None;
575        }
576
577        let descriptor = self.at_derivation_index(0).expect("0 is not hardened");
578        match descriptor.desc_type() {
579            // TODO: add pk() here
580            DescriptorType::Pkh
581            | DescriptorType::Wpkh
582            | DescriptorType::ShWpkh
583            | DescriptorType::Tr
584                if utxo.is_some()
585                    && descriptor.script_pubkey() == utxo.as_ref().unwrap().script_pubkey =>
586            {
587                Some(descriptor)
588            }
589            DescriptorType::Bare | DescriptorType::Sh | DescriptorType::ShSortedMulti
590                if psbt_input.redeem_script.is_some()
591                    && &descriptor.explicit_script().unwrap()
592                        == psbt_input.redeem_script.as_ref().unwrap() =>
593            {
594                Some(descriptor)
595            }
596            DescriptorType::Wsh
597            | DescriptorType::ShWsh
598            | DescriptorType::ShWshSortedMulti
599            | DescriptorType::WshSortedMulti
600                if psbt_input.witness_script.is_some()
601                    && &descriptor.explicit_script().unwrap()
602                        == psbt_input.witness_script.as_ref().unwrap() =>
603            {
604                Some(descriptor)
605            }
606            _ => None,
607        }
608    }
609}
610
611#[cfg(test)]
612mod test {
613    use alloc::string::ToString;
614    use core::str::FromStr;
615
616    use assert_matches::assert_matches;
617    use bitcoin::hex::FromHex;
618    use bitcoin::secp256k1::Secp256k1;
619    use bitcoin::{bip32, Psbt};
620    use bitcoin::{NetworkKind, ScriptBuf};
621
622    use super::*;
623    use crate::psbt::PsbtUtils;
624
625    #[test]
626    fn test_derive_from_psbt_input_wpkh_wif() {
627        let descriptor = Descriptor::<DescriptorPublicKey>::from_str(
628            "wpkh(02b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737)",
629        )
630        .unwrap();
631        let psbt = Psbt::deserialize(
632            &Vec::<u8>::from_hex(
633                "70736274ff010052010000000162307be8e431fbaff807cdf9cdc3fde44d7402\
634                 11bc8342c31ffd6ec11fe35bcc0100000000ffffffff01328601000000000016\
635                 001493ce48570b55c42c2af816aeaba06cfee1224fae000000000001011fa086\
636                 01000000000016001493ce48570b55c42c2af816aeaba06cfee1224fae010304\
637                 010000000000",
638            )
639            .unwrap(),
640        )
641        .unwrap();
642
643        assert!(descriptor
644            .derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0), &Secp256k1::new())
645            .is_some());
646    }
647
648    #[test]
649    fn test_derive_from_psbt_input_pkh_tpub() {
650        let descriptor = Descriptor::<DescriptorPublicKey>::from_str(
651            "pkh([0f056943/44h/0h/0h]tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd/10/*)",
652        )
653        .unwrap();
654        let psbt = Psbt::deserialize(
655            &Vec::<u8>::from_hex(
656                "70736274ff010053010000000145843b86be54a3cd8c9e38444e1162676c00df\
657                 e7964122a70df491ea12fd67090100000000ffffffff01c19598000000000017\
658                 a91432bb94283282f72b2e034709e348c44d5a4db0ef8700000000000100f902\
659                 0000000001010167e99c0eb67640f3a1b6805f2d8be8238c947f8aaf49eb0a9c\
660                 bee6a42c984200000000171600142b29a22019cca05b9c2b2d283a4c4489e1cf\
661                 9f8ffeffffff02a01dced06100000017a914e2abf033cadbd74f0f4c74946201\
662                 decd20d5c43c8780969800000000001976a9148b0fce5fb1264e599a65387313\
663                 3c95478b902eb288ac02473044022015d9211576163fa5b001e84dfa3d44efd9\
664                 86b8f3a0d3d2174369288b2b750906022048dacc0e5d73ae42512fd2b97e2071\
665                 a8d0bce443b390b1fe0b8128fe70ec919e01210232dad1c5a67dcb0116d407e2\
666                 52584228ab7ec00e8b9779d0c3ffe8114fc1a7d2c80600000103040100000022\
667                 0603433b83583f8c4879b329dd08bbc7da935e4cc02f637ff746e05f0466ffb2\
668                 a6a2180f0569432c00008000000080000000800a000000000000000000",
669            )
670            .unwrap(),
671        )
672        .unwrap();
673
674        assert!(descriptor
675            .derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0), &Secp256k1::new())
676            .is_some());
677    }
678
679    #[test]
680    fn test_derive_from_psbt_input_wsh() {
681        let descriptor = Descriptor::<DescriptorPublicKey>::from_str(
682            "wsh(and_v(v:pk(03b6633fef2397a0a9de9d7b6f23aef8368a6e362b0581f0f0af70d5ecfd254b14),older(6)))",
683        )
684        .unwrap();
685        let psbt = Psbt::deserialize(
686            &Vec::<u8>::from_hex(
687                "70736274ff01005302000000011c8116eea34408ab6529223c9a176606742207\
688                 67a1ff1d46a6e3c4a88243ea6e01000000000600000001109698000000000017\
689                 a914ad105f61102e0d01d7af40d06d6a5c3ae2f7fde387000000000001012b80\
690                 969800000000002200203ca72f106a72234754890ca7640c43f65d2174e44d33\
691                 336030f9059345091044010304010000000105252103b6633fef2397a0a9de9d\
692                 7b6f23aef8368a6e362b0581f0f0af70d5ecfd254b14ad56b20000",
693            )
694            .unwrap(),
695        )
696        .unwrap();
697
698        assert!(descriptor
699            .derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0), &Secp256k1::new())
700            .is_some());
701    }
702
703    #[test]
704    fn test_derive_from_psbt_input_sh() {
705        let descriptor = Descriptor::<DescriptorPublicKey>::from_str(
706            "sh(and_v(v:pk(021403881a5587297818fcaf17d239cefca22fce84a45b3b1d23e836c4af671dbb),after(630000)))",
707        )
708        .unwrap();
709        let psbt = Psbt::deserialize(
710            &Vec::<u8>::from_hex(
711                "70736274ff0100530100000001bc8c13df445dfadcc42afa6dc841f85d22b01d\
712                 a6270ebf981740f4b7b1d800390000000000feffffff01ba9598000000000017\
713                 a91457b148ba4d3e5fa8608a8657875124e3d1c9390887f09c0900000100e002\
714                 0000000001016ba1bbe05cc93574a0d611ec7d93ad0ab6685b28d0cd80e8a82d\
715                 debb326643c90100000000feffffff02809698000000000017a914d9a6e8c455\
716                 8e16c8253afe53ce37ad61cf4c38c487403504cf6100000017a9144044fb6e0b\
717                 757dfc1b34886b6a95aef4d3db137e870247304402202a9b72d939bcde8ba2a1\
718                 e0980597e47af4f5c152a78499143c3d0a78ac2286a602207a45b1df9e93b8c9\
719                 6f09f5c025fe3e413ca4b905fe65ee55d32a3276439a9b8f012102dc1fcc2636\
720                 4da1aa718f03d8d9bd6f2ff410ed2cf1245a168aa3bcc995ac18e0a806000001\
721                 03040100000001042821021403881a5587297818fcaf17d239cefca22fce84a4\
722                 5b3b1d23e836c4af671dbbad03f09c09b10000",
723            )
724            .unwrap(),
725        )
726        .unwrap();
727
728        assert!(descriptor
729            .derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0), &Secp256k1::new())
730            .is_some());
731    }
732
733    #[test]
734    fn test_to_wallet_descriptor_fixup_networks() {
735        use crate::keys::{any_network, IntoDescriptorKey};
736
737        let secp = Secp256k1::new();
738
739        let xprv = bip32::Xpriv::from_str("xprv9s21ZrQH143K3c3gF1DUWpWNr2SG2XrG8oYPpqYh7hoWsJy9NjabErnzriJPpnGHyKz5NgdXmq1KVbqS1r4NXdCoKitWg5e86zqXHa8kxyB").unwrap();
740        let path = bip32::DerivationPath::from_str("m/0").unwrap();
741
742        // here `to_descriptor_key` will set the valid networks for the key to only mainnet, since
743        // we are using an "xpub"
744        let key = (xprv, path.clone()).into_descriptor_key().unwrap();
745        // override it with any. this happens in some key conversions, like bip39
746        let key = key.override_valid_networks(any_network());
747
748        // make a descriptor out of it
749        let desc = crate::descriptor!(wpkh(key)).unwrap();
750        // this should convert the key that supports "any_network" to the right network (testnet)
751        let (wallet_desc, keymap) = desc
752            .into_wallet_descriptor(&secp, Network::Testnet)
753            .unwrap();
754
755        let mut xprv_testnet = xprv;
756        xprv_testnet.network = NetworkKind::Test;
757
758        let xpub_testnet = bip32::Xpub::from_priv(&secp, &xprv_testnet);
759        let desc_pubkey = DescriptorPublicKey::XPub(DescriptorXKey {
760            xkey: xpub_testnet,
761            origin: None,
762            derivation_path: path,
763            wildcard: Wildcard::Unhardened,
764        });
765
766        assert_eq!(wallet_desc.to_string(), "wpkh(tpubD6NzVbkrYhZ4XtJzoDja5snUjBNQRP5B3f4Hyn1T1x6PVPxzzVjvw6nJx2D8RBCxog9GEVjZoyStfepTz7TtKoBVdkCtnc7VCJh9dD4RAU9/0/*)#a3svx0ha");
767        assert_eq!(
768            keymap
769                .get(&desc_pubkey)
770                .map(|key| key.to_public(&secp).unwrap()),
771            Some(desc_pubkey)
772        );
773    }
774
775    // test IntoWalletDescriptor trait from &str with and without checksum appended
776    #[test]
777    fn test_descriptor_from_str_with_checksum() {
778        let secp = Secp256k1::new();
779
780        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#tqz0nc62"
781            .into_wallet_descriptor(&secp, Network::Testnet);
782        assert!(desc.is_ok());
783
784        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
785            .into_wallet_descriptor(&secp, Network::Testnet);
786        assert!(desc.is_ok());
787
788        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)#67ju93jw"
789            .into_wallet_descriptor(&secp, Network::Testnet);
790        assert!(desc.is_ok());
791
792        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)"
793            .into_wallet_descriptor(&secp, Network::Testnet);
794        assert!(desc.is_ok());
795
796        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#67ju93jw"
797            .into_wallet_descriptor(&secp, Network::Testnet);
798        assert_matches!(desc, Err(DescriptorError::InvalidDescriptorChecksum));
799
800        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#67ju93jw"
801            .into_wallet_descriptor(&secp, Network::Testnet);
802        assert_matches!(desc, Err(DescriptorError::InvalidDescriptorChecksum));
803    }
804
805    // test IntoWalletDescriptor trait from &str with keys from right and wrong network
806    #[test]
807    fn test_descriptor_from_str_with_keys_network() {
808        let secp = Secp256k1::new();
809
810        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
811            .into_wallet_descriptor(&secp, Network::Testnet);
812        assert!(desc.is_ok());
813
814        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
815            .into_wallet_descriptor(&secp, Network::Testnet4);
816        assert!(desc.is_ok());
817
818        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
819            .into_wallet_descriptor(&secp, Network::Regtest);
820        assert!(desc.is_ok());
821
822        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)"
823            .into_wallet_descriptor(&secp, Network::Testnet);
824        assert!(desc.is_ok());
825
826        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)"
827            .into_wallet_descriptor(&secp, Network::Regtest);
828        assert!(desc.is_ok());
829
830        let desc = "sh(wpkh(02864bb4ad00cefa806098a69e192bbda937494e69eb452b87bb3f20f6283baedb))"
831            .into_wallet_descriptor(&secp, Network::Testnet);
832        assert!(desc.is_ok());
833
834        let desc = "sh(wpkh(02864bb4ad00cefa806098a69e192bbda937494e69eb452b87bb3f20f6283baedb))"
835            .into_wallet_descriptor(&secp, Network::Bitcoin);
836        assert!(desc.is_ok());
837
838        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
839            .into_wallet_descriptor(&secp, Network::Bitcoin);
840        assert_matches!(desc, Err(DescriptorError::Key(KeyError::InvalidNetwork)));
841
842        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)"
843            .into_wallet_descriptor(&secp, Network::Bitcoin);
844        assert_matches!(desc, Err(DescriptorError::Key(KeyError::InvalidNetwork)));
845    }
846
847    // test IntoWalletDescriptor trait from the output of the descriptor!() macro
848    #[test]
849    fn test_descriptor_from_str_from_output_of_macro() {
850        let secp = Secp256k1::new();
851
852        let tpub = bip32::Xpub::from_str("tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK").unwrap();
853        let path = bip32::DerivationPath::from_str("m/1/2").unwrap();
854        let key = (tpub, path).into_descriptor_key().unwrap();
855
856        // make a descriptor out of it
857        let desc = crate::descriptor!(wpkh(key)).unwrap();
858
859        let (wallet_desc, _) = desc
860            .into_wallet_descriptor(&secp, Network::Testnet)
861            .unwrap();
862        let wallet_desc_str = wallet_desc.to_string();
863        assert_eq!(wallet_desc_str, "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)#67ju93jw");
864
865        let (wallet_desc2, _) = wallet_desc_str
866            .into_wallet_descriptor(&secp, Network::Testnet)
867            .unwrap();
868        assert_eq!(wallet_desc, wallet_desc2)
869    }
870
871    #[test]
872    fn test_check_wallet_descriptor() {
873        let secp = Secp256k1::new();
874
875        let descriptor = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/0'/1/2/*)";
876        let (descriptor, _) = descriptor
877            .into_wallet_descriptor(&secp, Network::Testnet)
878            .expect("must parse");
879        let result = check_wallet_descriptor(&descriptor);
880
881        assert_matches!(result, Err(DescriptorError::HardenedDerivationXpub));
882
883        // Any multipath descriptor should fail
884        let descriptor = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/<0;1>/*)";
885        let (descriptor, _) = descriptor
886            .into_wallet_descriptor(&secp, Network::Testnet)
887            .expect("must parse");
888        let result = check_wallet_descriptor(&descriptor);
889
890        assert_matches!(
891            result,
892            Err(DescriptorError::Miniscript(
893                miniscript::Error::BadDescriptor(_)
894            ))
895        );
896
897        // repeated pubkeys
898        let descriptor = "wsh(multi(2,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/0/*,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/0/*))";
899        let (descriptor, _) = descriptor
900            .into_wallet_descriptor(&secp, Network::Testnet)
901            .expect("must parse");
902        let result = check_wallet_descriptor(&descriptor);
903
904        assert!(result.is_err());
905    }
906
907    #[test]
908    fn test_sh_wsh_sortedmulti_redeemscript() {
909        use miniscript::psbt::PsbtInputExt;
910
911        let secp = Secp256k1::new();
912
913        let descriptor = "sh(wsh(sortedmulti(3,tpubDEsqS36T4DVsKJd9UH8pAKzrkGBYPLEt9jZMwpKtzh1G6mgYehfHt9WCgk7MJG5QGSFWf176KaBNoXbcuFcuadAFKxDpUdMDKGBha7bY3QM/0/*,tpubDF3cpwfs7fMvXXuoQbohXtLjNM6ehwYT287LWtmLsd4r77YLg6MZg4vTETx5MSJ2zkfigbYWu31VA2Z2Vc1cZugCYXgS7FQu6pE8V6TriEH/0/*,tpubDE1SKfcW76Tb2AASv5bQWMuScYNAdoqLHoexw13sNDXwmUhQDBbCD3QAedKGLhxMrWQdMDKENzYtnXPDRvexQPNuDrLj52wAjHhNEm8sJ4p/0/*,tpubDFLc6oXwJmhm3FGGzXkfJNTh2KitoY3WhmmQvuAjMhD8YbyWn5mAqckbxXfm2etM3p5J6JoTpSrMqRSTfMLtNW46poDaEZJ1kjd3csRSjwH/0/*,tpubDEWD9NBeWP59xXmdqSNt4VYdtTGwbpyP8WS962BuqpQeMZmX9Pur14dhXdZT5a7wR1pK6dPtZ9fP5WR493hPzemnBvkfLLYxnUjAKj1JCQV/0/*,tpubDEHyZkkwd7gZWCTgQuYQ9C4myF2hMEmyHsBCCmLssGqoqUxeT3gzohF5uEVURkf9TtmeepJgkSUmteac38FwZqirjApzNX59XSHLcwaTZCH/0/*,tpubDEqLouCekwnMUWN486kxGzD44qVgeyuqHyxUypNEiQt5RnUZNJe386TKPK99fqRV1vRkZjYAjtXGTECz98MCsdLcnkM67U6KdYRzVubeCgZ/0/*)))";
914        let (descriptor, _) = descriptor
915            .into_wallet_descriptor(&secp, Network::Testnet)
916            .unwrap();
917        check_wallet_descriptor(&descriptor).expect("descriptor");
918
919        let descriptor = descriptor.at_derivation_index(0).unwrap();
920
921        let script = ScriptBuf::from_hex("5321022f533b667e2ea3b36e21961c9fe9dca340fbe0af5210173a83ae0337ab20a57621026bb53a98e810bd0ee61a0ed1164ba6c024786d76554e793e202dc6ce9c78c4ea2102d5b8a7d66a41ffdb6f4c53d61994022e886b4f45001fb158b95c9164d45f8ca3210324b75eead2c1f9c60e8adeb5e7009fec7a29afcdb30d829d82d09562fe8bae8521032d34f8932200833487bd294aa219dcbe000b9f9b3d824799541430009f0fa55121037468f8ea99b6c64788398b5ad25480cad08f4b0d65be54ce3a55fd206b5ae4722103f72d3d96663b0ea99b0aeb0d7f273cab11a8de37885f1dddc8d9112adb87169357ae").unwrap();
922
923        let mut psbt_input = psbt::Input::default();
924        psbt_input
925            .update_with_descriptor_unchecked(&descriptor)
926            .unwrap();
927
928        assert_eq!(psbt_input.redeem_script, Some(script.to_p2wsh()));
929        assert_eq!(psbt_input.witness_script, Some(script));
930    }
931
932    #[test]
933    fn test_into_wallet_descriptor_multi() -> anyhow::Result<()> {
934        // See <https://github.com/bitcoindevkit/bdk_wallet/issues/10>
935        let secp = Secp256k1::new();
936
937        // multipath tpub
938        let descriptor_str = "wpkh([9a6a2580/84'/1'/0']tpubDDnGNapGEY6AZAdQbfRJgMg9fvz8pUBrLwvyvUqEgcUfgzM6zc2eVK4vY9x9L5FJWdX8WumXuLEDV5zDZnTfbn87vLe9XceCFwTu9so9Kks/<0;1>/*)";
939        let (descriptor, _key_map) = descriptor_str
940            .into_wallet_descriptor(&secp, Network::Testnet)
941            .expect("should parse multipath tpub");
942
943        assert!(descriptor.is_multipath());
944
945        // invalid network for descriptor
946        let descriptor_str = "wpkh([9a6a2580/84'/0'/0']xpub6DEzNop46vmxR49zYWFnMwmEfawSNmAMf6dLH5YKDY463twtvw1XD7ihwJRLPRGZJz799VPFzXHpZu6WdhT29WnaeuChS6aZHZPFmqczR5K/<0;1>/*)";
947        let res = descriptor_str.into_wallet_descriptor(&secp, Network::Testnet);
948
949        assert!(matches!(
950            res,
951            Err(DescriptorError::Key(KeyError::InvalidNetwork))
952        ));
953
954        // multipath xpub
955        let descriptor_str = "wpkh([9a6a2580/84'/0'/0']xpub6DEzNop46vmxR49zYWFnMwmEfawSNmAMf6dLH5YKDY463twtvw1XD7ihwJRLPRGZJz799VPFzXHpZu6WdhT29WnaeuChS6aZHZPFmqczR5K/<0;1>/*)";
956        let (descriptor, _key_map) = descriptor_str
957            .into_wallet_descriptor(&secp, Network::Bitcoin)
958            .expect("should parse multipath xpub");
959
960        assert!(descriptor.is_multipath());
961
962        // Miniscript can't make an extended private key with multiple paths into a public key.
963        // ref: <https://docs.rs/miniscript/12.3.2/miniscript/descriptor/enum.DescriptorSecretKey.html#method.to_public>
964        let descriptor_str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/<0;1>/*)";
965        assert!(matches!(
966            Descriptor::parse_descriptor(&secp, descriptor_str),
967            Err(miniscript::Error::Unexpected(..)),
968        ));
969        let _ = descriptor_str
970            .into_wallet_descriptor(&secp, Network::Testnet)
971            .unwrap_err();
972
973        Ok(())
974    }
975}