miniscript/descriptor/
key.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use core::convert::TryInto;
4use core::fmt;
5use core::str::FromStr;
6#[cfg(feature = "std")]
7use std::error;
8
9use bitcoin::bip32::{self, XKeyIdentifier};
10use bitcoin::hashes::{hash160, ripemd160, sha256, Hash, HashEngine};
11use bitcoin::key::{PublicKey, XOnlyPublicKey};
12use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
13
14use crate::prelude::*;
15#[cfg(feature = "serde")]
16use crate::serde::{Deserialize, Deserializer, Serialize, Serializer};
17use crate::{hash256, MiniscriptKey, ToPublicKey};
18
19/// The descriptor pubkey, either a single pubkey or an xpub.
20#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
21pub enum DescriptorPublicKey {
22    /// Single public key.
23    Single(SinglePub),
24    /// Extended public key (xpub).
25    XPub(DescriptorXKey<bip32::Xpub>),
26    /// Multiple extended public keys.
27    MultiXPub(DescriptorMultiXKey<bip32::Xpub>),
28}
29
30/// The descriptor secret key, either a single private key or an xprv.
31#[derive(Debug, Eq, PartialEq, Clone)]
32pub enum DescriptorSecretKey {
33    /// Single private key.
34    Single(SinglePriv),
35    /// Extended private key (xpriv).
36    XPrv(DescriptorXKey<bip32::Xpriv>),
37    /// Multiple extended private keys.
38    MultiXPrv(DescriptorMultiXKey<bip32::Xpriv>),
39}
40
41/// A descriptor [`SinglePubKey`] with optional origin information.
42#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
43pub struct SinglePub {
44    /// Origin information (fingerprint and derivation path).
45    pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
46    /// The public key.
47    pub key: SinglePubKey,
48}
49
50/// A descriptor [`bitcoin::PrivateKey`] with optional origin information.
51#[derive(Debug, Eq, PartialEq, Clone)]
52pub struct SinglePriv {
53    /// Origin information (fingerprint and derivation path).
54    pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
55    /// The private key.
56    pub key: bitcoin::PrivateKey,
57}
58
59/// An extended key with origin, derivation path, and wildcard.
60#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
61pub struct DescriptorXKey<K: InnerXKey> {
62    /// Origin information
63    pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
64    /// The extended key
65    pub xkey: K,
66    /// The derivation path
67    pub derivation_path: bip32::DerivationPath,
68    /// Whether the descriptor is wildcard
69    pub wildcard: Wildcard,
70}
71
72/// The derivation paths in a multipath key expression.
73#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
74pub struct DerivPaths(Vec<bip32::DerivationPath>);
75
76impl DerivPaths {
77    /// Create a non empty derivation paths list.
78    pub fn new(paths: Vec<bip32::DerivationPath>) -> Option<DerivPaths> {
79        if paths.is_empty() {
80            None
81        } else {
82            Some(DerivPaths(paths))
83        }
84    }
85
86    /// Get the list of derivation paths.
87    pub fn paths(&self) -> &Vec<bip32::DerivationPath> { &self.0 }
88
89    /// Get the list of derivation paths.
90    pub fn into_paths(self) -> Vec<bip32::DerivationPath> { self.0 }
91}
92
93/// Instance of one or more extended keys, as specified in BIP 389.
94#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
95pub struct DescriptorMultiXKey<K: InnerXKey> {
96    /// Origin information
97    pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
98    /// The extended key
99    pub xkey: K,
100    /// The derivation paths. Never empty.
101    pub derivation_paths: DerivPaths,
102    /// Whether the descriptor is wildcard
103    pub wildcard: Wildcard,
104}
105
106/// Single public key without any origin or range information.
107#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
108pub enum SinglePubKey {
109    /// A bitcoin public key (compressed or uncompressed).
110    FullKey(bitcoin::PublicKey),
111    /// An xonly public key.
112    XOnly(XOnlyPublicKey),
113}
114
115/// A [`DescriptorPublicKey`] without any wildcards.
116#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
117pub struct DefiniteDescriptorKey(DescriptorPublicKey);
118
119impl fmt::Display for DescriptorSecretKey {
120    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121        match self {
122            DescriptorSecretKey::Single(ref sk) => {
123                maybe_fmt_master_id(f, &sk.origin)?;
124                sk.key.fmt(f)?;
125                Ok(())
126            }
127            DescriptorSecretKey::XPrv(ref xprv) => {
128                maybe_fmt_master_id(f, &xprv.origin)?;
129                xprv.xkey.fmt(f)?;
130                fmt_derivation_path(f, &xprv.derivation_path)?;
131                match xprv.wildcard {
132                    Wildcard::None => {}
133                    Wildcard::Unhardened => write!(f, "/*")?,
134                    Wildcard::Hardened => write!(f, "/*h")?,
135                }
136                Ok(())
137            }
138            DescriptorSecretKey::MultiXPrv(ref xprv) => {
139                maybe_fmt_master_id(f, &xprv.origin)?;
140                xprv.xkey.fmt(f)?;
141                fmt_derivation_paths(f, xprv.derivation_paths.paths())?;
142                match xprv.wildcard {
143                    Wildcard::None => {}
144                    Wildcard::Unhardened => write!(f, "/*")?,
145                    Wildcard::Hardened => write!(f, "/*h")?,
146                }
147                Ok(())
148            }
149        }
150    }
151}
152
153/// Trait for "extended key" types like `xpub` and `xprv`. Used internally to generalize parsing and
154/// handling of `bip32::Xpub` and `bip32::Xpriv`.
155pub trait InnerXKey: fmt::Display + FromStr {
156    /// Returns the fingerprint of the key
157    fn xkey_fingerprint<C: Signing>(&self, secp: &Secp256k1<C>) -> bip32::Fingerprint;
158
159    /// Returns whether hardened steps can be derived on the key
160    ///
161    /// `true` for `bip32::Xpriv` and `false` for `bip32::Xpub`.
162    fn can_derive_hardened() -> bool;
163}
164
165impl InnerXKey for bip32::Xpub {
166    fn xkey_fingerprint<C: Signing>(&self, _secp: &Secp256k1<C>) -> bip32::Fingerprint {
167        self.fingerprint()
168    }
169
170    fn can_derive_hardened() -> bool { false }
171}
172
173impl InnerXKey for bip32::Xpriv {
174    fn xkey_fingerprint<C: Signing>(&self, secp: &Secp256k1<C>) -> bip32::Fingerprint {
175        self.fingerprint(secp)
176    }
177
178    fn can_derive_hardened() -> bool { true }
179}
180
181/// Whether a descriptor has a wildcard in it
182#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
183pub enum Wildcard {
184    /// No wildcard
185    None,
186    /// Unhardened wildcard, e.g. *
187    Unhardened,
188    /// Unhardened wildcard, e.g. *h
189    Hardened,
190}
191
192impl SinglePriv {
193    /// Returns the public key of this key.
194    fn to_public<C: Signing>(&self, secp: &Secp256k1<C>) -> SinglePub {
195        let pub_key = self.key.public_key(secp);
196
197        SinglePub { origin: self.origin.clone(), key: SinglePubKey::FullKey(pub_key) }
198    }
199}
200
201impl DescriptorXKey<bip32::Xpriv> {
202    /// Returns the public version of this key, applying all the hardened derivation steps on the
203    /// private key before turning it into a public key.
204    ///
205    /// If the key already has an origin, the derivation steps applied will be appended to the path
206    /// already present, otherwise this key will be treated as a master key and an origin will be
207    /// added with this key's fingerprint and the derivation steps applied.
208    fn to_public<C: Signing>(
209        &self,
210        secp: &Secp256k1<C>,
211    ) -> Result<DescriptorXKey<bip32::Xpub>, DescriptorKeyParseError> {
212        let unhardened = self
213            .derivation_path
214            .into_iter()
215            .rev()
216            .take_while(|c| c.is_normal())
217            .count();
218        let last_hardened_idx = self.derivation_path.len() - unhardened;
219
220        let hardened_path = &self.derivation_path[..last_hardened_idx];
221        let unhardened_path = &self.derivation_path[last_hardened_idx..];
222
223        let xprv = self
224            .xkey
225            .derive_priv(secp, &hardened_path)
226            .map_err(|_| DescriptorKeyParseError("Unable to derive the hardened steps"))?;
227        let xpub = bip32::Xpub::from_priv(secp, &xprv);
228
229        let origin = match &self.origin {
230            Some((fingerprint, path)) => Some((
231                *fingerprint,
232                path.into_iter()
233                    .chain(hardened_path.iter())
234                    .cloned()
235                    .collect(),
236            )),
237            None => {
238                if hardened_path.is_empty() {
239                    None
240                } else {
241                    Some((self.xkey.fingerprint(secp), hardened_path.into()))
242                }
243            }
244        };
245
246        Ok(DescriptorXKey {
247            origin,
248            xkey: xpub,
249            derivation_path: unhardened_path.into(),
250            wildcard: self.wildcard,
251        })
252    }
253}
254
255/// Descriptor Key parsing errors
256// FIXME: replace with error enums
257#[derive(Debug, PartialEq, Clone, Copy)]
258pub struct DescriptorKeyParseError(&'static str);
259
260impl fmt::Display for DescriptorKeyParseError {
261    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.0) }
262}
263
264#[cfg(feature = "std")]
265impl error::Error for DescriptorKeyParseError {
266    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
267}
268
269impl fmt::Display for DescriptorPublicKey {
270    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
271        match *self {
272            DescriptorPublicKey::Single(ref pk) => {
273                maybe_fmt_master_id(f, &pk.origin)?;
274                match pk.key {
275                    SinglePubKey::FullKey(full_key) => full_key.fmt(f),
276                    SinglePubKey::XOnly(x_only_key) => x_only_key.fmt(f),
277                }?;
278                Ok(())
279            }
280            DescriptorPublicKey::XPub(ref xpub) => {
281                maybe_fmt_master_id(f, &xpub.origin)?;
282                xpub.xkey.fmt(f)?;
283                fmt_derivation_path(f, &xpub.derivation_path)?;
284                match xpub.wildcard {
285                    Wildcard::None => {}
286                    Wildcard::Unhardened => write!(f, "/*")?,
287                    Wildcard::Hardened => write!(f, "/*h")?,
288                }
289                Ok(())
290            }
291            DescriptorPublicKey::MultiXPub(ref xpub) => {
292                maybe_fmt_master_id(f, &xpub.origin)?;
293                xpub.xkey.fmt(f)?;
294                fmt_derivation_paths(f, xpub.derivation_paths.paths())?;
295                match xpub.wildcard {
296                    Wildcard::None => {}
297                    Wildcard::Unhardened => write!(f, "/*")?,
298                    Wildcard::Hardened => write!(f, "/*h")?,
299                }
300                Ok(())
301            }
302        }
303    }
304}
305
306impl DescriptorSecretKey {
307    /// Returns the public version of this key.
308    ///
309    /// If the key is an "XPrv", the hardened derivation steps will be applied
310    /// before converting it to a public key.
311    ///
312    /// It will return an error if the key is a "multi-xpriv", as we wouldn't
313    /// always be able to apply hardened derivation steps if there are multiple
314    /// paths.
315    pub fn to_public<C: Signing>(
316        &self,
317        secp: &Secp256k1<C>,
318    ) -> Result<DescriptorPublicKey, DescriptorKeyParseError> {
319        let pk = match self {
320            DescriptorSecretKey::Single(prv) => DescriptorPublicKey::Single(prv.to_public(secp)),
321            DescriptorSecretKey::XPrv(xprv) => DescriptorPublicKey::XPub(xprv.to_public(secp)?),
322            DescriptorSecretKey::MultiXPrv(_) => {
323                return Err(DescriptorKeyParseError(
324                    "Can't make an extended private key with multiple paths into a public key.",
325                ))
326            }
327        };
328
329        Ok(pk)
330    }
331
332    /// Whether or not this key has multiple derivation paths.
333    pub fn is_multipath(&self) -> bool {
334        match *self {
335            DescriptorSecretKey::Single(..) | DescriptorSecretKey::XPrv(..) => false,
336            DescriptorSecretKey::MultiXPrv(_) => true,
337        }
338    }
339
340    /// Get as many keys as derivation paths in this key.
341    ///
342    /// For raw keys and single-path extended keys it will return the key itself.
343    /// For multipath extended keys it will return a single-path extended key per derivation
344    /// path.
345    pub fn into_single_keys(self) -> Vec<DescriptorSecretKey> {
346        match self {
347            DescriptorSecretKey::Single(..) | DescriptorSecretKey::XPrv(..) => vec![self],
348            DescriptorSecretKey::MultiXPrv(xpub) => {
349                let DescriptorMultiXKey { origin, xkey, derivation_paths, wildcard } = xpub;
350                derivation_paths
351                    .into_paths()
352                    .into_iter()
353                    .map(|derivation_path| {
354                        DescriptorSecretKey::XPrv(DescriptorXKey {
355                            origin: origin.clone(),
356                            xkey,
357                            derivation_path,
358                            wildcard,
359                        })
360                    })
361                    .collect()
362            }
363        }
364    }
365}
366
367/// Writes the fingerprint of the origin, if there is one.
368fn maybe_fmt_master_id(
369    f: &mut fmt::Formatter,
370    origin: &Option<(bip32::Fingerprint, bip32::DerivationPath)>,
371) -> fmt::Result {
372    if let Some((ref master_id, ref master_deriv)) = *origin {
373        fmt::Formatter::write_str(f, "[")?;
374        for byte in master_id.as_bytes().iter() {
375            write!(f, "{:02x}", byte)?;
376        }
377        fmt_derivation_path(f, master_deriv)?;
378        fmt::Formatter::write_str(f, "]")?;
379    }
380
381    Ok(())
382}
383
384/// Writes a derivation path to the formatter, no leading 'm'
385fn fmt_derivation_path(f: &mut fmt::Formatter, path: &bip32::DerivationPath) -> fmt::Result {
386    for child in path {
387        write!(f, "/{}", child)?;
388    }
389    Ok(())
390}
391
392/// Writes multiple derivation paths to the formatter, no leading 'm'.
393/// NOTE: we assume paths only differ at a single index, as prescribed by BIP389.
394/// Will panic if the list of paths is empty.
395fn fmt_derivation_paths(f: &mut fmt::Formatter, paths: &[bip32::DerivationPath]) -> fmt::Result {
396    for (i, child) in paths[0].into_iter().enumerate() {
397        if paths.len() > 1 && child != &paths[1][i] {
398            write!(f, "/<")?;
399            for (j, p) in paths.iter().enumerate() {
400                write!(f, "{}", p[i])?;
401                if j != paths.len() - 1 {
402                    write!(f, ";")?;
403                }
404            }
405            write!(f, ">")?;
406        } else {
407            write!(f, "/{}", child)?;
408        }
409    }
410    Ok(())
411}
412
413impl FromStr for DescriptorPublicKey {
414    type Err = DescriptorKeyParseError;
415
416    fn from_str(s: &str) -> Result<Self, Self::Err> {
417        // A "raw" public key without any origin is the least we accept.
418        if s.len() < 64 {
419            return Err(DescriptorKeyParseError(
420                "Key too short (<66 char), doesn't match any format",
421            ));
422        }
423
424        let (key_part, origin) = parse_key_origin(s)?;
425
426        if key_part.contains("pub") {
427            let (xpub, derivation_paths, wildcard) = parse_xkey_deriv::<bip32::Xpub>(key_part)?;
428            if derivation_paths.len() > 1 {
429                Ok(DescriptorPublicKey::MultiXPub(DescriptorMultiXKey {
430                    origin,
431                    xkey: xpub,
432                    derivation_paths: DerivPaths::new(derivation_paths).expect("Not empty"),
433                    wildcard,
434                }))
435            } else {
436                Ok(DescriptorPublicKey::XPub(DescriptorXKey {
437                    origin,
438                    xkey: xpub,
439                    derivation_path: derivation_paths.into_iter().next().unwrap_or_default(),
440                    wildcard,
441                }))
442            }
443        } else {
444            let key = match key_part.len() {
445                64 => {
446                    let x_only_key = XOnlyPublicKey::from_str(key_part).map_err(|_| {
447                        DescriptorKeyParseError("Error while parsing simple xonly key")
448                    })?;
449                    SinglePubKey::XOnly(x_only_key)
450                }
451                66 | 130 => {
452                    if !(&key_part[0..2] == "02"
453                        || &key_part[0..2] == "03"
454                        || &key_part[0..2] == "04")
455                    {
456                        return Err(DescriptorKeyParseError(
457                            "Only publickeys with prefixes 02/03/04 are allowed",
458                        ));
459                    }
460                    let key = bitcoin::PublicKey::from_str(key_part).map_err(|_| {
461                        DescriptorKeyParseError("Error while parsing simple public key")
462                    })?;
463                    SinglePubKey::FullKey(key)
464                }
465                _ => {
466                    return Err(DescriptorKeyParseError(
467                        "Public keys must be 64/66/130 characters in size",
468                    ))
469                }
470            };
471            Ok(DescriptorPublicKey::Single(SinglePub { key, origin }))
472        }
473    }
474}
475
476impl From<XOnlyPublicKey> for DescriptorPublicKey {
477    fn from(key: XOnlyPublicKey) -> Self {
478        DescriptorPublicKey::Single(SinglePub { origin: None, key: SinglePubKey::XOnly(key) })
479    }
480}
481
482impl From<PublicKey> for DescriptorPublicKey {
483    fn from(key: PublicKey) -> Self {
484        DescriptorPublicKey::Single(SinglePub { origin: None, key: SinglePubKey::FullKey(key) })
485    }
486}
487
488/// Descriptor key conversion error
489#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
490pub enum ConversionError {
491    /// Attempted to convert a key with hardened derivations to a bitcoin public key
492    HardenedChild,
493    /// Attempted to convert a key with multiple derivation paths to a bitcoin public key
494    MultiKey,
495}
496
497impl fmt::Display for ConversionError {
498    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
499        f.write_str(match *self {
500            ConversionError::HardenedChild => "hardened child step in bip32 path",
501            ConversionError::MultiKey => "multiple existing keys",
502        })
503    }
504}
505
506#[cfg(feature = "std")]
507impl error::Error for ConversionError {
508    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
509        use self::ConversionError::*;
510
511        match self {
512            HardenedChild | MultiKey => None,
513        }
514    }
515}
516
517impl DescriptorPublicKey {
518    /// The fingerprint of the master key associated with this key, `0x00000000` if none.
519    pub fn master_fingerprint(&self) -> bip32::Fingerprint {
520        match *self {
521            DescriptorPublicKey::XPub(ref xpub) => {
522                if let Some((fingerprint, _)) = xpub.origin {
523                    fingerprint
524                } else {
525                    xpub.xkey.fingerprint()
526                }
527            }
528            DescriptorPublicKey::MultiXPub(ref xpub) => {
529                if let Some((fingerprint, _)) = xpub.origin {
530                    fingerprint
531                } else {
532                    xpub.xkey.fingerprint()
533                }
534            }
535            DescriptorPublicKey::Single(ref single) => {
536                if let Some((fingerprint, _)) = single.origin {
537                    fingerprint
538                } else {
539                    let mut engine = XKeyIdentifier::engine();
540                    match single.key {
541                        SinglePubKey::FullKey(pk) => {
542                            pk.write_into(&mut engine).expect("engines don't error")
543                        }
544                        SinglePubKey::XOnly(x_only_pk) => engine.input(&x_only_pk.serialize()),
545                    };
546                    bip32::Fingerprint::from(
547                        &XKeyIdentifier::from_engine(engine)[..4]
548                            .try_into()
549                            .expect("4 byte slice"),
550                    )
551                }
552            }
553        }
554    }
555
556    /// Full path, from the master key
557    ///
558    /// For wildcard keys this will return the path up to the wildcard, so you
559    /// can get full paths by appending one additional derivation step, according
560    /// to the wildcard type (hardened or normal).
561    ///
562    /// For multipath extended keys, this returns `None`.
563    pub fn full_derivation_path(&self) -> Option<bip32::DerivationPath> {
564        match *self {
565            DescriptorPublicKey::XPub(ref xpub) => {
566                let origin_path = if let Some((_, ref path)) = xpub.origin {
567                    path.clone()
568                } else {
569                    bip32::DerivationPath::from(vec![])
570                };
571                Some(origin_path.extend(&xpub.derivation_path))
572            }
573            DescriptorPublicKey::Single(ref single) => {
574                Some(if let Some((_, ref path)) = single.origin {
575                    path.clone()
576                } else {
577                    bip32::DerivationPath::from(vec![])
578                })
579            }
580            DescriptorPublicKey::MultiXPub(_) => None,
581        }
582    }
583
584    /// Returns a vector containing the full derivation paths from the master key.
585    /// The vector will contain just one element for single keys, and multiple elements
586    /// for multipath extended keys.
587    ///
588    /// For wildcard keys this will return the path up to the wildcard, so you
589    /// can get full paths by appending one additional derivation step, according
590    /// to the wildcard type (hardened or normal).
591    pub fn full_derivation_paths(&self) -> Vec<bip32::DerivationPath> {
592        match self {
593            DescriptorPublicKey::MultiXPub(xpub) => {
594                let origin_path = if let Some((_, ref path)) = xpub.origin {
595                    path.clone()
596                } else {
597                    bip32::DerivationPath::from(vec![])
598                };
599                xpub.derivation_paths
600                    .paths()
601                    .iter()
602                    .map(|p| origin_path.extend(p))
603                    .collect()
604            }
605            _ => vec![self
606                .full_derivation_path()
607                .expect("Must be Some for non-multipath keys")],
608        }
609    }
610
611    /// Whether or not the key has a wildcard
612    #[deprecated(note = "use has_wildcard instead")]
613    pub fn is_deriveable(&self) -> bool { self.has_wildcard() }
614
615    /// Whether or not the key has a wildcard
616    pub fn has_wildcard(&self) -> bool {
617        match *self {
618            DescriptorPublicKey::Single(..) => false,
619            DescriptorPublicKey::XPub(ref xpub) => xpub.wildcard != Wildcard::None,
620            DescriptorPublicKey::MultiXPub(ref xpub) => xpub.wildcard != Wildcard::None,
621        }
622    }
623
624    /// Whether or not the key has a wildcard
625    pub fn has_hardened_step(&self) -> bool {
626        let paths = match self {
627            DescriptorPublicKey::Single(..) => &[],
628            DescriptorPublicKey::XPub(xpub) => core::slice::from_ref(&xpub.derivation_path),
629            DescriptorPublicKey::MultiXPub(xpub) => &xpub.derivation_paths.paths()[..],
630        };
631        for p in paths {
632            for step in p.into_iter() {
633                if step.is_hardened() {
634                    return true;
635                }
636            }
637        }
638        false
639    }
640
641    #[deprecated(note = "use at_derivation_index instead")]
642    /// Deprecated name for [`Self::at_derivation_index`].
643    pub fn derive(self, index: u32) -> Result<DefiniteDescriptorKey, ConversionError> {
644        self.at_derivation_index(index)
645    }
646
647    /// Replaces any wildcard (i.e. `/*`) in the key with a particular derivation index, turning it into a
648    /// *definite* key (i.e. one where all the derivation paths are set).
649    ///
650    /// # Returns
651    ///
652    /// - If this key is not an xpub, returns `self`.
653    /// - If this key is an xpub but does not have a wildcard, returns `self`.
654    /// - Otherwise, returns the xpub at derivation `index` (removing the wildcard).
655    ///
656    /// # Errors
657    ///
658    /// - If `index` is hardened.
659    pub fn at_derivation_index(self, index: u32) -> Result<DefiniteDescriptorKey, ConversionError> {
660        let definite = match self {
661            DescriptorPublicKey::Single(_) => self,
662            DescriptorPublicKey::XPub(xpub) => {
663                let derivation_path = match xpub.wildcard {
664                    Wildcard::None => xpub.derivation_path,
665                    Wildcard::Unhardened => xpub.derivation_path.into_child(
666                        bip32::ChildNumber::from_normal_idx(index)
667                            .ok()
668                            .ok_or(ConversionError::HardenedChild)?,
669                    ),
670                    Wildcard::Hardened => xpub.derivation_path.into_child(
671                        bip32::ChildNumber::from_hardened_idx(index)
672                            .ok()
673                            .ok_or(ConversionError::HardenedChild)?,
674                    ),
675                };
676                DescriptorPublicKey::XPub(DescriptorXKey {
677                    origin: xpub.origin,
678                    xkey: xpub.xkey,
679                    derivation_path,
680                    wildcard: Wildcard::None,
681                })
682            }
683            DescriptorPublicKey::MultiXPub(_) => return Err(ConversionError::MultiKey),
684        };
685
686        Ok(DefiniteDescriptorKey::new(definite)
687            .expect("The key should not contain any wildcards at this point"))
688    }
689
690    /// Whether or not this key has multiple derivation paths.
691    pub fn is_multipath(&self) -> bool {
692        match *self {
693            DescriptorPublicKey::Single(..) | DescriptorPublicKey::XPub(..) => false,
694            DescriptorPublicKey::MultiXPub(_) => true,
695        }
696    }
697
698    /// Get as many keys as derivation paths in this key.
699    ///
700    /// For raw public key and single-path extended keys it will return the key itself.
701    /// For multipath extended keys it will return a single-path extended key per derivation
702    /// path.
703    pub fn into_single_keys(self) -> Vec<DescriptorPublicKey> {
704        match self {
705            DescriptorPublicKey::Single(..) | DescriptorPublicKey::XPub(..) => vec![self],
706            DescriptorPublicKey::MultiXPub(xpub) => {
707                let DescriptorMultiXKey { origin, xkey, derivation_paths, wildcard } = xpub;
708                derivation_paths
709                    .into_paths()
710                    .into_iter()
711                    .map(|derivation_path| {
712                        DescriptorPublicKey::XPub(DescriptorXKey {
713                            origin: origin.clone(),
714                            xkey,
715                            derivation_path,
716                            wildcard,
717                        })
718                    })
719                    .collect()
720            }
721        }
722    }
723}
724
725impl FromStr for DescriptorSecretKey {
726    type Err = DescriptorKeyParseError;
727
728    fn from_str(s: &str) -> Result<Self, Self::Err> {
729        let (key_part, origin) = parse_key_origin(s)?;
730
731        if key_part.len() <= 52 {
732            let sk = bitcoin::PrivateKey::from_str(key_part)
733                .map_err(|_| DescriptorKeyParseError("Error while parsing a WIF private key"))?;
734            Ok(DescriptorSecretKey::Single(SinglePriv { key: sk, origin: None }))
735        } else {
736            let (xpriv, derivation_paths, wildcard) = parse_xkey_deriv::<bip32::Xpriv>(key_part)?;
737            if derivation_paths.len() > 1 {
738                Ok(DescriptorSecretKey::MultiXPrv(DescriptorMultiXKey {
739                    origin,
740                    xkey: xpriv,
741                    derivation_paths: DerivPaths::new(derivation_paths).expect("Not empty"),
742                    wildcard,
743                }))
744            } else {
745                Ok(DescriptorSecretKey::XPrv(DescriptorXKey {
746                    origin,
747                    xkey: xpriv,
748                    derivation_path: derivation_paths.into_iter().next().unwrap_or_default(),
749                    wildcard,
750                }))
751            }
752        }
753    }
754}
755
756// Parse the origin information part of a descriptor key.
757fn parse_key_origin(s: &str) -> Result<(&str, Option<bip32::KeySource>), DescriptorKeyParseError> {
758    for ch in s.as_bytes() {
759        if *ch < 20 || *ch > 127 {
760            return Err(DescriptorKeyParseError("Encountered an unprintable character"));
761        }
762    }
763
764    if s.is_empty() {
765        return Err(DescriptorKeyParseError("Empty key"));
766    }
767    let mut parts = s[1..].split(']');
768
769    if let Some('[') = s.chars().next() {
770        let mut raw_origin = parts
771            .next()
772            .ok_or(DescriptorKeyParseError("Unclosed '['"))?
773            .split('/');
774
775        let origin_id_hex = raw_origin
776            .next()
777            .ok_or(DescriptorKeyParseError("No master fingerprint found after '['"))?;
778
779        if origin_id_hex.len() != 8 {
780            return Err(DescriptorKeyParseError("Master fingerprint should be 8 characters long"));
781        }
782        let parent_fingerprint = bip32::Fingerprint::from_hex(origin_id_hex).map_err(|_| {
783            DescriptorKeyParseError("Malformed master fingerprint, expected 8 hex chars")
784        })?;
785        let origin_path = raw_origin
786            .map(bip32::ChildNumber::from_str)
787            .collect::<Result<bip32::DerivationPath, bip32::Error>>()
788            .map_err(|_| DescriptorKeyParseError("Error while parsing master derivation path"))?;
789
790        let key = parts
791            .next()
792            .ok_or(DescriptorKeyParseError("No key after origin."))?;
793
794        if parts.next().is_some() {
795            Err(DescriptorKeyParseError("Multiple ']' in Descriptor Public Key"))
796        } else {
797            Ok((key, Some((parent_fingerprint, origin_path))))
798        }
799    } else {
800        Ok((s, None))
801    }
802}
803
804/// Parse an extended key concatenated to a derivation path.
805fn parse_xkey_deriv<K: InnerXKey>(
806    key_deriv: &str,
807) -> Result<(K, Vec<bip32::DerivationPath>, Wildcard), DescriptorKeyParseError> {
808    let mut key_deriv = key_deriv.split('/');
809    let xkey_str = key_deriv
810        .next()
811        .ok_or(DescriptorKeyParseError("No key found after origin description"))?;
812    let xkey =
813        K::from_str(xkey_str).map_err(|_| DescriptorKeyParseError("Error while parsing xkey."))?;
814
815    let mut wildcard = Wildcard::None;
816    let mut multipath = false;
817    let derivation_paths = key_deriv
818        .filter_map(|p| {
819            if wildcard == Wildcard::None && p == "*" {
820                wildcard = Wildcard::Unhardened;
821                None
822            } else if wildcard == Wildcard::None && (p == "*'" || p == "*h") {
823                wildcard = Wildcard::Hardened;
824                None
825            } else if wildcard != Wildcard::None {
826                Some(Err(DescriptorKeyParseError(
827                    "'*' may only appear as last element in a derivation path.",
828                )))
829            } else {
830                // BIP389 defines a new step in the derivation path. This step contains two or more
831                // derivation indexes in the form '<1;2;3';4h;5H;6>'.
832                if p.starts_with('<') && p.ends_with('>') {
833                    // There may only be one occurence of this step.
834                    if multipath {
835                        return Some(Err(DescriptorKeyParseError(
836                            "'<' may only appear once in a derivation path.",
837                        )));
838                    }
839                    multipath = true;
840
841                    // The step must contain at least two derivation indexes.
842                    // So it's at least '<' + a number + ';' + a number + '>'.
843                    if p.len() < 5 || !p.contains(';') {
844                        return Some(Err(DescriptorKeyParseError(
845                            "Invalid multi index step in multipath descriptor.",
846                        )));
847                    }
848
849                    // Collect all derivation indexes at this step.
850                    let indexes = p[1..p.len() - 1].split(';');
851                    Some(
852                        indexes
853                            .into_iter()
854                            .map(|s| {
855                                bip32::ChildNumber::from_str(s).map_err(|_| {
856                                    DescriptorKeyParseError(
857                                        "Error while parsing index in key derivation path.",
858                                    )
859                                })
860                            })
861                            .collect::<Result<Vec<bip32::ChildNumber>, _>>(),
862                    )
863                } else {
864                    // Not a BIP389 step, just a regular derivation index.
865                    Some(
866                        bip32::ChildNumber::from_str(p)
867                            .map(|i| vec![i])
868                            .map_err(|_| {
869                                DescriptorKeyParseError("Error while parsing key derivation path")
870                            }),
871                    )
872                }
873            }
874        })
875        // Now we've got all derivation indexes in a list of vectors of indexes. If the derivation
876        // path was empty then this list is empty. If the derivation path didn't contain any BIP389
877        // step all the vectors of indexes contain a single element. If it did though, one of the
878        // vectors contains more than one element.
879        // Now transform this list of vectors of steps into distinct derivation paths.
880        .try_fold(Vec::new(), |mut paths, index_list| {
881            let mut index_list = index_list?.into_iter();
882            let first_index = index_list
883                .next()
884                .expect("There is always at least one element");
885
886            if paths.is_empty() {
887                paths.push(vec![first_index]);
888            } else {
889                for path in paths.iter_mut() {
890                    path.push(first_index);
891                }
892            }
893
894            // If the step is a BIP389 one, create as many paths as there is indexes.
895            for (i, index) in index_list.enumerate() {
896                paths.push(paths[0].clone());
897                *paths[i + 1].last_mut().expect("Never empty") = index;
898            }
899
900            Ok(paths)
901        })?
902        .into_iter()
903        .map(|index_list| index_list.into_iter().collect::<bip32::DerivationPath>())
904        .collect::<Vec<bip32::DerivationPath>>();
905
906    Ok((xkey, derivation_paths, wildcard))
907}
908
909impl<K: InnerXKey> DescriptorXKey<K> {
910    /// Compares this key with a `keysource` and returns the matching derivation path, if any.
911    ///
912    /// For keys that have an origin, the `keysource`'s fingerprint will be compared
913    /// with the origin's fingerprint, and the `keysource`'s path will be compared with the concatenation of the
914    /// origin's and key's paths.
915    ///
916    /// If the key `wildcard`, the last item of the `keysource`'s path will be ignored,
917    ///
918    /// ## Examples
919    ///
920    /// ```
921    /// # use std::str::FromStr;
922    /// # fn body() -> Result<(), ()> {
923    /// use miniscript::bitcoin::bip32;
924    /// use miniscript::descriptor::DescriptorPublicKey;
925    ///
926    /// let ctx = miniscript::bitcoin::secp256k1::Secp256k1::signing_only();
927    ///
928    /// let key = DescriptorPublicKey::from_str("[d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*").or(Err(()))?;
929    /// let xpub = match key {
930    ///     DescriptorPublicKey::XPub(xpub) => xpub,
931    ///     _ => panic!("Parsing Error"),
932    /// };
933    ///
934    /// assert_eq!(
935    ///     xpub.matches(&(
936    ///         bip32::Fingerprint::from_str("d34db33f").or(Err(()))?,
937    ///         bip32::DerivationPath::from_str("m/44'/0'/0'/1/42").or(Err(()))?
938    ///     ), &ctx),
939    ///     Some(bip32::DerivationPath::from_str("m/44'/0'/0'/1").or(Err(()))?)
940    /// );
941    /// assert_eq!(
942    ///     xpub.matches(&(
943    ///         bip32::Fingerprint::from_str("ffffffff").or(Err(()))?,
944    ///         bip32::DerivationPath::from_str("m/44'/0'/0'/1/42").or(Err(()))?
945    ///     ), &ctx),
946    ///     None
947    /// );
948    /// assert_eq!(
949    ///     xpub.matches(&(
950    ///         bip32::Fingerprint::from_str("d34db33f").or(Err(()))?,
951    ///         bip32::DerivationPath::from_str("m/44'/0'/0'/100/0").or(Err(()))?
952    ///     ), &ctx),
953    ///     None
954    /// );
955    /// # Ok(())
956    /// # }
957    /// # body().unwrap()
958    /// ```
959    pub fn matches<C: Signing>(
960        &self,
961        keysource: &bip32::KeySource,
962        secp: &Secp256k1<C>,
963    ) -> Option<bip32::DerivationPath> {
964        let (fingerprint, path) = keysource;
965
966        let (compare_fingerprint, compare_path) = match self.origin {
967            Some((fingerprint, ref path)) => {
968                (fingerprint, path.into_iter().chain(&self.derivation_path).collect())
969            }
970            None => (
971                self.xkey.xkey_fingerprint(secp),
972                self.derivation_path.into_iter().collect::<Vec<_>>(),
973            ),
974        };
975
976        let path_excluding_wildcard = if self.wildcard != Wildcard::None && !path.is_empty() {
977            path.into_iter()
978                .take(path.as_ref().len() - 1)
979                .cloned()
980                .collect()
981        } else {
982            path.clone()
983        };
984
985        if &compare_fingerprint == fingerprint
986            && compare_path
987                .into_iter()
988                .eq(path_excluding_wildcard.into_iter())
989        {
990            Some(path_excluding_wildcard)
991        } else {
992            None
993        }
994    }
995}
996
997impl MiniscriptKey for DescriptorPublicKey {
998    type Sha256 = sha256::Hash;
999    type Hash256 = hash256::Hash;
1000    type Ripemd160 = ripemd160::Hash;
1001    type Hash160 = hash160::Hash;
1002
1003    fn is_uncompressed(&self) -> bool {
1004        match self {
1005            DescriptorPublicKey::Single(SinglePub {
1006                key: SinglePubKey::FullKey(ref key), ..
1007            }) => key.is_uncompressed(),
1008            _ => false,
1009        }
1010    }
1011
1012    fn is_x_only_key(&self) -> bool {
1013        matches!(
1014            self,
1015            DescriptorPublicKey::Single(SinglePub { key: SinglePubKey::XOnly(ref _key), .. })
1016        )
1017    }
1018
1019    fn num_der_paths(&self) -> usize {
1020        match self {
1021            DescriptorPublicKey::Single(_) => 0,
1022            DescriptorPublicKey::XPub(_) => 1,
1023            DescriptorPublicKey::MultiXPub(xpub) => xpub.derivation_paths.paths().len(),
1024        }
1025    }
1026}
1027
1028impl DefiniteDescriptorKey {
1029    /// Computes the public key corresponding to this descriptor key.
1030    /// When deriving from an XOnlyPublicKey, it adds the default 0x02 y-coordinate
1031    /// and returns the obtained full [`bitcoin::PublicKey`]. All BIP32 derivations
1032    /// always return a compressed key
1033    ///
1034    /// Will return an error if the descriptor key has any hardened derivation steps in its path. To
1035    /// avoid this error you should replace any such public keys first with [`translate_pk`].
1036    ///
1037    /// [`translate_pk`]: crate::TranslatePk::translate_pk
1038    pub fn derive_public_key<C: Verification>(
1039        &self,
1040        secp: &Secp256k1<C>,
1041    ) -> Result<bitcoin::PublicKey, ConversionError> {
1042        match self.0 {
1043            DescriptorPublicKey::Single(ref pk) => match pk.key {
1044                SinglePubKey::FullKey(pk) => Ok(pk),
1045                SinglePubKey::XOnly(xpk) => Ok(xpk.to_public_key()),
1046            },
1047            DescriptorPublicKey::XPub(ref xpk) => match xpk.wildcard {
1048                Wildcard::Unhardened | Wildcard::Hardened => {
1049                    unreachable!("we've excluded this error case")
1050                }
1051                Wildcard::None => match xpk.xkey.derive_pub(secp, &xpk.derivation_path.as_ref()) {
1052                    Ok(xpub) => Ok(bitcoin::PublicKey::new(xpub.public_key)),
1053                    Err(bip32::Error::CannotDeriveFromHardenedKey) => {
1054                        Err(ConversionError::HardenedChild)
1055                    }
1056                    Err(e) => unreachable!("cryptographically unreachable: {}", e),
1057                },
1058            },
1059            DescriptorPublicKey::MultiXPub(_) => {
1060                unreachable!("A definite key cannot contain a multipath key.")
1061            }
1062        }
1063    }
1064
1065    /// Construct an instance from a descriptor key and a derivation index
1066    ///
1067    /// Returns `None` if the key contains a wildcard
1068    pub fn new(key: DescriptorPublicKey) -> Option<Self> {
1069        if key.has_wildcard() || key.is_multipath() || key.has_hardened_step() {
1070            None
1071        } else {
1072            Some(Self(key))
1073        }
1074    }
1075
1076    /// The fingerprint of the master key associated with this key, `0x00000000` if none.
1077    pub fn master_fingerprint(&self) -> bip32::Fingerprint { self.0.master_fingerprint() }
1078
1079    /// Full path from the master key if not a multipath extended key.
1080    pub fn full_derivation_path(&self) -> Option<bip32::DerivationPath> {
1081        self.0.full_derivation_path()
1082    }
1083
1084    /// Full paths from the master key. The vector will contain just one path for single
1085    /// keys, and multiple ones for multipath extended keys
1086    pub fn full_derivation_paths(&self) -> Vec<bip32::DerivationPath> {
1087        self.0.full_derivation_paths()
1088    }
1089
1090    /// Reference to the underlying `DescriptorPublicKey`
1091    pub fn as_descriptor_public_key(&self) -> &DescriptorPublicKey { &self.0 }
1092
1093    /// Converts the definite key into a generic one
1094    pub fn into_descriptor_public_key(self) -> DescriptorPublicKey { self.0 }
1095}
1096
1097impl FromStr for DefiniteDescriptorKey {
1098    type Err = DescriptorKeyParseError;
1099
1100    fn from_str(s: &str) -> Result<Self, Self::Err> {
1101        let inner = DescriptorPublicKey::from_str(s)?;
1102        DefiniteDescriptorKey::new(inner).ok_or(DescriptorKeyParseError(
1103            "cannot parse multi-path keys, keys with a wildcard or keys with hardened derivation steps as a DerivedDescriptorKey",
1104        ))
1105    }
1106}
1107
1108impl fmt::Display for DefiniteDescriptorKey {
1109    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) }
1110}
1111
1112impl MiniscriptKey for DefiniteDescriptorKey {
1113    type Sha256 = sha256::Hash;
1114    type Hash256 = hash256::Hash;
1115    type Ripemd160 = ripemd160::Hash;
1116    type Hash160 = hash160::Hash;
1117
1118    fn is_uncompressed(&self) -> bool { self.0.is_uncompressed() }
1119
1120    fn is_x_only_key(&self) -> bool { self.0.is_x_only_key() }
1121
1122    fn num_der_paths(&self) -> usize { self.0.num_der_paths() }
1123}
1124
1125impl ToPublicKey for DefiniteDescriptorKey {
1126    fn to_public_key(&self) -> bitcoin::PublicKey {
1127        let secp = Secp256k1::verification_only();
1128        self.derive_public_key(&secp).unwrap()
1129    }
1130
1131    fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash }
1132
1133    fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { *hash }
1134
1135    fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash { *hash }
1136
1137    fn to_hash160(hash: &hash160::Hash) -> hash160::Hash { *hash }
1138}
1139
1140impl From<DefiniteDescriptorKey> for DescriptorPublicKey {
1141    fn from(d: DefiniteDescriptorKey) -> Self { d.0 }
1142}
1143
1144impl Borrow<DescriptorPublicKey> for DefiniteDescriptorKey {
1145    fn borrow(&self) -> &DescriptorPublicKey { &self.0 }
1146}
1147
1148#[cfg(feature = "serde")]
1149impl<'de> Deserialize<'de> for DescriptorPublicKey {
1150    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1151    where
1152        D: Deserializer<'de>,
1153    {
1154        let s = String::deserialize(deserializer)?;
1155        DescriptorPublicKey::from_str(&s).map_err(crate::serde::de::Error::custom)
1156    }
1157}
1158
1159#[cfg(feature = "serde")]
1160impl Serialize for DescriptorPublicKey {
1161    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1162    where
1163        S: Serializer,
1164    {
1165        serializer.serialize_str(&self.to_string())
1166    }
1167}
1168
1169#[cfg(test)]
1170mod test {
1171    use core::str::FromStr;
1172
1173    use bitcoin::bip32;
1174    #[cfg(feature = "serde")]
1175    use serde_test::{assert_tokens, Token};
1176
1177    use super::{
1178        DescriptorKeyParseError, DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey,
1179        MiniscriptKey, Wildcard,
1180    };
1181    use crate::prelude::*;
1182    use crate::DefiniteDescriptorKey;
1183
1184    #[test]
1185    fn parse_descriptor_key_errors() {
1186        // And ones with misplaced wildcard
1187        let desc = "[78412e3a/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*/44";
1188        assert_eq!(
1189            DescriptorPublicKey::from_str(desc),
1190            Err(DescriptorKeyParseError(
1191                "\'*\' may only appear as last element in a derivation path."
1192            ))
1193        );
1194
1195        // And ones with invalid fingerprints
1196        let desc = "[NonHexor]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*";
1197        assert_eq!(
1198            DescriptorPublicKey::from_str(desc),
1199            Err(DescriptorKeyParseError("Malformed master fingerprint, expected 8 hex chars"))
1200        );
1201
1202        // And ones with invalid xpubs..
1203        let desc = "[78412e3a]xpub1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaLcgJvLJuZZvRcEL/1/*";
1204        assert_eq!(
1205            DescriptorPublicKey::from_str(desc),
1206            Err(DescriptorKeyParseError("Error while parsing xkey."))
1207        );
1208
1209        // ..or invalid raw keys
1210        let desc = "[78412e3a]0208a117f3897c3a13c9384b8695eed98dc31bc2500feb19a1af424cd47a5d83/1/*";
1211        assert_eq!(
1212            DescriptorPublicKey::from_str(desc),
1213            Err(DescriptorKeyParseError("Public keys must be 64/66/130 characters in size"))
1214        );
1215
1216        // ..or invalid separators
1217        let desc = "[78412e3a]]03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8";
1218        assert_eq!(
1219            DescriptorPublicKey::from_str(desc),
1220            Err(DescriptorKeyParseError("Multiple \']\' in Descriptor Public Key"))
1221        );
1222
1223        // fuzzer errors
1224        let desc = "[11111f11]033333333333333333333333333333323333333333333333333333333433333333]]333]]3]]101333333333333433333]]]10]333333mmmm";
1225        assert_eq!(
1226            DescriptorPublicKey::from_str(desc),
1227            Err(DescriptorKeyParseError("Multiple \']\' in Descriptor Public Key"))
1228        );
1229
1230        // fuzz failure, hybrid keys
1231        let desc = "0777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777";
1232        assert_eq!(
1233            DescriptorPublicKey::from_str(desc),
1234            Err(DescriptorKeyParseError("Only publickeys with prefixes 02/03/04 are allowed"))
1235        );
1236    }
1237
1238    #[test]
1239    fn parse_descriptor_secret_key_error() {
1240        // Xpubs are invalid
1241        let secret_key = "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL";
1242        assert_eq!(
1243            DescriptorSecretKey::from_str(secret_key),
1244            Err(DescriptorKeyParseError("Error while parsing xkey."))
1245        );
1246
1247        // And ones with invalid fingerprints
1248        let desc = "[NonHexor]tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/*";
1249        assert_eq!(
1250            DescriptorSecretKey::from_str(desc),
1251            Err(DescriptorKeyParseError("Malformed master fingerprint, expected 8 hex chars"))
1252        );
1253
1254        // ..or invalid raw keys
1255        let desc = "[78412e3a]L32jTfVLei6BYTPUpwpJSkrHx8iL9GZzeErVS8y4Y/1/*";
1256        assert_eq!(
1257            DescriptorSecretKey::from_str(desc),
1258            Err(DescriptorKeyParseError("Error while parsing a WIF private key"))
1259        );
1260    }
1261
1262    #[test]
1263    fn test_wildcard() {
1264        let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2").unwrap();
1265        assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
1266        assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'/2");
1267        assert!(!public_key.has_wildcard());
1268
1269        let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*").unwrap();
1270        assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
1271        assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'");
1272        assert!(public_key.has_wildcard());
1273
1274        let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*h").unwrap();
1275        assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
1276        assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'");
1277        assert!(public_key.has_wildcard());
1278    }
1279
1280    #[test]
1281    fn test_deriv_on_xprv() {
1282        let secp = secp256k1::Secp256k1::signing_only();
1283
1284        let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2").unwrap();
1285        let public_key = secret_key.to_public(&secp).unwrap();
1286        assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2");
1287        assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d");
1288        assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'/2");
1289        assert!(!public_key.has_wildcard());
1290
1291        let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2'").unwrap();
1292        let public_key = secret_key.to_public(&secp).unwrap();
1293        assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1'/2']tpubDDPuH46rv4dbFtmF6FrEtJEy1CvLZonyBoVxF6xsesHdYDdTBrq2mHhm8AbsPh39sUwL2nZyxd6vo4uWNTU9v4t893CwxjqPnwMoUACLvMV");
1294        assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d");
1295        assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'/2'");
1296
1297        let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0/1/2").unwrap();
1298        let public_key = secret_key.to_public(&secp).unwrap();
1299        assert_eq!(public_key.to_string(), "tpubD6NzVbkrYhZ4WQdzxL7NmJN7b85ePo4p6RSj9QQHF7te2RR9iUeVSGgnGkoUsB9LBRosgvNbjRv9bcsJgzgBd7QKuxDm23ZewkTRzNSLEDr/0/1/2");
1300        assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d");
1301        assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0/1/2");
1302
1303        let secret_key = DescriptorSecretKey::from_str("[aabbccdd]tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0/1/2").unwrap();
1304        let public_key = secret_key.to_public(&secp).unwrap();
1305        assert_eq!(public_key.to_string(), "[aabbccdd]tpubD6NzVbkrYhZ4WQdzxL7NmJN7b85ePo4p6RSj9QQHF7te2RR9iUeVSGgnGkoUsB9LBRosgvNbjRv9bcsJgzgBd7QKuxDm23ZewkTRzNSLEDr/0/1/2");
1306        assert_eq!(public_key.master_fingerprint().to_string(), "aabbccdd");
1307        assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0/1/2");
1308
1309        let secret_key = DescriptorSecretKey::from_str("[aabbccdd/90']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2").unwrap();
1310        let public_key = secret_key.to_public(&secp).unwrap();
1311        assert_eq!(public_key.to_string(), "[aabbccdd/90'/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2");
1312        assert_eq!(public_key.master_fingerprint().to_string(), "aabbccdd");
1313        assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "90'/0'/1'/2");
1314    }
1315
1316    #[test]
1317    fn test_master_fingerprint() {
1318        assert_eq!(
1319            DescriptorPublicKey::from_str(
1320                "02a489e0ea42b56148d212d325b7c67c6460483ff931c303ea311edfef667c8f35",
1321            )
1322            .unwrap()
1323            .master_fingerprint()
1324            .as_bytes(),
1325            b"\xb0\x59\x11\x6a"
1326        );
1327    }
1328
1329    fn get_multipath_xpub(key_str: &str, num_paths: usize) -> DescriptorMultiXKey<bip32::Xpub> {
1330        let desc_key = DescriptorPublicKey::from_str(key_str).unwrap();
1331        assert_eq!(desc_key.num_der_paths(), num_paths);
1332        match desc_key {
1333            DescriptorPublicKey::MultiXPub(xpub) => xpub,
1334            _ => unreachable!(),
1335        }
1336    }
1337
1338    fn get_multipath_xprv(key_str: &str) -> DescriptorMultiXKey<bip32::Xpriv> {
1339        let desc_key = DescriptorSecretKey::from_str(key_str).unwrap();
1340        match desc_key {
1341            DescriptorSecretKey::MultiXPrv(xprv) => xprv,
1342            _ => unreachable!(),
1343        }
1344    }
1345
1346    #[test]
1347    fn multipath_extended_keys() {
1348        let secp = secp256k1::Secp256k1::signing_only();
1349
1350        // We can have a key in a descriptor that has multiple paths
1351        let xpub = get_multipath_xpub("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/<0;1;42;9854>", 4);
1352        assert_eq!(
1353            xpub.derivation_paths.paths(),
1354            &vec![
1355                bip32::DerivationPath::from_str("m/2/0").unwrap(),
1356                bip32::DerivationPath::from_str("m/2/1").unwrap(),
1357                bip32::DerivationPath::from_str("m/2/42").unwrap(),
1358                bip32::DerivationPath::from_str("m/2/9854").unwrap()
1359            ],
1360        );
1361        assert_eq!(
1362            xpub,
1363            get_multipath_xpub(&DescriptorPublicKey::MultiXPub(xpub.clone()).to_string(), 4)
1364        );
1365        // Even if it's in the middle of the derivation path.
1366        let xpub = get_multipath_xpub("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/<0;1;9854>/0/5/10", 3);
1367        assert_eq!(
1368            xpub.derivation_paths.paths(),
1369            &vec![
1370                bip32::DerivationPath::from_str("m/2/0/0/5/10").unwrap(),
1371                bip32::DerivationPath::from_str("m/2/1/0/5/10").unwrap(),
1372                bip32::DerivationPath::from_str("m/2/9854/0/5/10").unwrap()
1373            ],
1374        );
1375        assert_eq!(
1376            xpub,
1377            get_multipath_xpub(&DescriptorPublicKey::MultiXPub(xpub.clone()).to_string(), 3)
1378        );
1379        // Even if it is a wildcard extended key.
1380        let xpub = get_multipath_xpub("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/<0;1;9854>/3456/9876/*", 3);
1381        assert_eq!(xpub.wildcard, Wildcard::Unhardened);
1382        assert_eq!(
1383            xpub.derivation_paths.paths(),
1384            &vec![
1385                bip32::DerivationPath::from_str("m/2/0/3456/9876").unwrap(),
1386                bip32::DerivationPath::from_str("m/2/1/3456/9876").unwrap(),
1387                bip32::DerivationPath::from_str("m/2/9854/3456/9876").unwrap()
1388            ],
1389        );
1390        assert_eq!(
1391            xpub,
1392            get_multipath_xpub(&DescriptorPublicKey::MultiXPub(xpub.clone()).to_string(), 3)
1393        );
1394        // Also even if it has an origin.
1395        let xpub = get_multipath_xpub("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/<0;1>/*", 2);
1396        assert_eq!(xpub.wildcard, Wildcard::Unhardened);
1397        assert_eq!(
1398            xpub.derivation_paths.paths(),
1399            &vec![
1400                bip32::DerivationPath::from_str("m/0").unwrap(),
1401                bip32::DerivationPath::from_str("m/1").unwrap(),
1402            ],
1403        );
1404        assert_eq!(
1405            xpub,
1406            get_multipath_xpub(&DescriptorPublicKey::MultiXPub(xpub.clone()).to_string(), 2)
1407        );
1408        // Also if it has hardened steps in the derivation path. In fact, it can also have hardened
1409        // indexes even at the step with multiple indexes!
1410        let xpub = get_multipath_xpub("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/9478'/<0';1h>/8h/*'", 2);
1411        assert_eq!(xpub.wildcard, Wildcard::Hardened);
1412        assert_eq!(
1413            xpub.derivation_paths.paths(),
1414            &vec![
1415                bip32::DerivationPath::from_str("m/9478'/0'/8'").unwrap(),
1416                bip32::DerivationPath::from_str("m/9478h/1h/8h").unwrap(),
1417            ],
1418        );
1419        assert_eq!(
1420            xpub,
1421            get_multipath_xpub(&DescriptorPublicKey::MultiXPub(xpub.clone()).to_string(), 2)
1422        );
1423        // You can't get the "full derivation path" for a multipath extended public key.
1424        let desc_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/9478'/<0';1>/8h/*'").unwrap();
1425        assert!(desc_key.full_derivation_path().is_none());
1426        assert!(desc_key.is_multipath());
1427        // But you can get all the derivation paths
1428        assert_eq!(
1429            desc_key.full_derivation_paths(),
1430            vec![
1431                bip32::DerivationPath::from_str("m/0'/1'/9478'/0'/8'").unwrap(),
1432                bip32::DerivationPath::from_str("m/0'/1'/9478'/1/8'").unwrap(),
1433            ],
1434        );
1435        assert_eq!(desc_key.into_single_keys(), vec![DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/9478'/0'/8h/*'").unwrap(), DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/9478'/1/8h/*'").unwrap()]);
1436
1437        // All the same but with extended private keys instead of xpubs.
1438        let xprv = get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/2/<0;1;42;9854>");
1439        assert_eq!(
1440            xprv.derivation_paths.paths(),
1441            &vec![
1442                bip32::DerivationPath::from_str("m/2/0").unwrap(),
1443                bip32::DerivationPath::from_str("m/2/1").unwrap(),
1444                bip32::DerivationPath::from_str("m/2/42").unwrap(),
1445                bip32::DerivationPath::from_str("m/2/9854").unwrap()
1446            ],
1447        );
1448        assert_eq!(
1449            xprv,
1450            get_multipath_xprv(&DescriptorSecretKey::MultiXPrv(xprv.clone()).to_string())
1451        );
1452        let xprv = get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/2/<0;1;9854>/0/5/10");
1453        assert_eq!(
1454            xprv.derivation_paths.paths(),
1455            &vec![
1456                bip32::DerivationPath::from_str("m/2/0/0/5/10").unwrap(),
1457                bip32::DerivationPath::from_str("m/2/1/0/5/10").unwrap(),
1458                bip32::DerivationPath::from_str("m/2/9854/0/5/10").unwrap()
1459            ],
1460        );
1461        assert_eq!(
1462            xprv,
1463            get_multipath_xprv(&DescriptorSecretKey::MultiXPrv(xprv.clone()).to_string())
1464        );
1465        let xprv = get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/2/<0;1;9854>/3456/9876/*");
1466        assert_eq!(xprv.wildcard, Wildcard::Unhardened);
1467        assert_eq!(
1468            xprv.derivation_paths.paths(),
1469            &vec![
1470                bip32::DerivationPath::from_str("m/2/0/3456/9876").unwrap(),
1471                bip32::DerivationPath::from_str("m/2/1/3456/9876").unwrap(),
1472                bip32::DerivationPath::from_str("m/2/9854/3456/9876").unwrap()
1473            ],
1474        );
1475        assert_eq!(
1476            xprv,
1477            get_multipath_xprv(&DescriptorSecretKey::MultiXPrv(xprv.clone()).to_string())
1478        );
1479        let xprv = get_multipath_xprv("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/<0;1>/*");
1480        assert_eq!(xprv.wildcard, Wildcard::Unhardened);
1481        assert_eq!(
1482            xprv.derivation_paths.paths(),
1483            &vec![
1484                bip32::DerivationPath::from_str("m/0").unwrap(),
1485                bip32::DerivationPath::from_str("m/1").unwrap(),
1486            ],
1487        );
1488        assert_eq!(
1489            xprv,
1490            get_multipath_xprv(&DescriptorSecretKey::MultiXPrv(xprv.clone()).to_string())
1491        );
1492        let xprv = get_multipath_xprv("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/<0';1h>/8h/*'");
1493        assert_eq!(xprv.wildcard, Wildcard::Hardened);
1494        assert_eq!(
1495            xprv.derivation_paths.paths(),
1496            &vec![
1497                bip32::DerivationPath::from_str("m/9478'/0'/8'").unwrap(),
1498                bip32::DerivationPath::from_str("m/9478h/1h/8h").unwrap(),
1499            ],
1500        );
1501        assert_eq!(
1502            xprv,
1503            get_multipath_xprv(&DescriptorSecretKey::MultiXPrv(xprv.clone()).to_string())
1504        );
1505        let desc_key = DescriptorSecretKey::from_str("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/<0';1>/8h/*'").unwrap();
1506        assert!(desc_key.to_public(&secp).is_err());
1507        assert!(desc_key.is_multipath());
1508        assert_eq!(desc_key.into_single_keys(), vec![DescriptorSecretKey::from_str("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/0'/8h/*'").unwrap(), DescriptorSecretKey::from_str("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/1/8h/*'").unwrap()]);
1509
1510        // It's invalid to:
1511        // - Not have opening or closing brackets
1512        // - Have multiple steps with different indexes
1513        // - Only have one index within the brackets
1514        DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/<0;1;42;9854").unwrap_err();
1515        DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/0;1;42;9854>").unwrap_err();
1516        DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/4/<0;1>/96/<0;1>").unwrap_err();
1517        DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/4/<0>").unwrap_err();
1518        DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/4/<0;>").unwrap_err();
1519        DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/4/<;1>").unwrap_err();
1520        DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/4/<0;1;>").unwrap_err();
1521    }
1522
1523    #[test]
1524    #[cfg(feature = "serde")]
1525    fn test_descriptor_public_key_serde() {
1526        let desc = "[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2";
1527        let public_key = DescriptorPublicKey::from_str(desc).unwrap();
1528        assert_tokens(&public_key, &[Token::String(desc)]);
1529    }
1530
1531    #[test]
1532    fn definite_keys() {
1533        // basic xpub
1534        let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
1535            .parse::<DescriptorPublicKey>()
1536            .unwrap();
1537        assert!(DefiniteDescriptorKey::new(desc).is_some());
1538        // xpub with wildcard
1539        let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/*"
1540            .parse::<DescriptorPublicKey>()
1541            .unwrap();
1542        assert!(DefiniteDescriptorKey::new(desc).is_none());
1543        // multipath xpub
1544        let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/<0;1>"
1545            .parse::<DescriptorPublicKey>()
1546            .unwrap();
1547        assert!(DefiniteDescriptorKey::new(desc).is_none());
1548        // xpub with hardened path
1549        let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/1'/2"
1550            .parse::<DescriptorPublicKey>()
1551            .unwrap();
1552        assert!(DefiniteDescriptorKey::new(desc).is_none());
1553    }
1554}