miniscript_debug/descriptor/
key.rs

1use core::fmt;
2use core::str::FromStr;
3#[cfg(feature = "std")]
4use std::error;
5
6use bitcoin::hashes::hex::FromHex;
7use bitcoin::hashes::{hash160, ripemd160, sha256, Hash, HashEngine};
8use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
9use bitcoin::util::bip32;
10use bitcoin::{self, XOnlyPublicKey, XpubIdentifier};
11
12use crate::prelude::*;
13use crate::{hash256, MiniscriptKey, ToPublicKey};
14
15/// The descriptor pubkey, either a single pubkey or an xpub.
16#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
17pub enum DescriptorPublicKey {
18    /// Single public key.
19    Single(SinglePub),
20    /// Extended public key (xpub).
21    XPub(DescriptorXKey<bip32::ExtendedPubKey>),
22}
23
24/// The descriptor secret key, either a single private key or an xprv.
25#[derive(Debug)]
26pub enum DescriptorSecretKey {
27    /// Single private key.
28    Single(SinglePriv),
29    /// Extended private key (xpriv).
30    XPrv(DescriptorXKey<bip32::ExtendedPrivKey>),
31}
32
33/// A descriptor [`SinglePubKey`] with optional origin information.
34#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
35pub struct SinglePub {
36    /// Origin information (fingerprint and derivation path).
37    pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
38    /// The public key.
39    pub key: SinglePubKey,
40}
41
42/// A descriptor [`bitcoin::PrivateKey`] with optional origin information.
43#[derive(Debug)]
44pub struct SinglePriv {
45    /// Origin information (fingerprint and derivation path).
46    pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
47    /// The private key.
48    pub key: bitcoin::PrivateKey,
49}
50
51/// An extended key with origin, derivation path, and wildcard.
52#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
53pub struct DescriptorXKey<K: InnerXKey> {
54    /// Origin information
55    pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
56    /// The extended key
57    pub xkey: K,
58    /// The derivation path
59    pub derivation_path: bip32::DerivationPath,
60    /// Whether the descriptor is wildcard
61    pub wildcard: Wildcard,
62}
63
64/// Single public key without any origin or range information.
65#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
66pub enum SinglePubKey {
67    /// A bitcoin public key (compressed or uncompressed).
68    FullKey(bitcoin::PublicKey),
69    /// An xonly public key.
70    XOnly(XOnlyPublicKey),
71}
72
73/// A [`DescriptorPublicKey`] without any wildcards.
74#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
75pub struct DefiniteDescriptorKey(DescriptorPublicKey);
76
77impl fmt::Display for DescriptorSecretKey {
78    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79        match self {
80            DescriptorSecretKey::Single(ref sk) => {
81                maybe_fmt_master_id(f, &sk.origin)?;
82                sk.key.fmt(f)?;
83                Ok(())
84            }
85            DescriptorSecretKey::XPrv(ref xprv) => {
86                maybe_fmt_master_id(f, &xprv.origin)?;
87                xprv.xkey.fmt(f)?;
88                fmt_derivation_path(f, &xprv.derivation_path)?;
89                match xprv.wildcard {
90                    Wildcard::None => {}
91                    Wildcard::Unhardened => write!(f, "/*")?,
92                    Wildcard::Hardened => write!(f, "/*h")?,
93                }
94                Ok(())
95            }
96        }
97    }
98}
99
100/// Trait for "extended key" types like `xpub` and `xprv`. Used internally to generalize parsing and
101/// handling of `bip32::ExtendedPubKey` and `bip32::ExtendedPrivKey`.
102pub trait InnerXKey: fmt::Display + FromStr {
103    /// Returns the fingerprint of the key
104    fn xkey_fingerprint<C: Signing>(&self, secp: &Secp256k1<C>) -> bip32::Fingerprint;
105
106    /// Returns whether hardened steps can be derived on the key
107    ///
108    /// `true` for `bip32::ExtendedPrivKey` and `false` for `bip32::ExtendedPubKey`.
109    fn can_derive_hardened() -> bool;
110}
111
112impl InnerXKey for bip32::ExtendedPubKey {
113    fn xkey_fingerprint<C: Signing>(&self, _secp: &Secp256k1<C>) -> bip32::Fingerprint {
114        self.fingerprint()
115    }
116
117    fn can_derive_hardened() -> bool {
118        false
119    }
120}
121
122impl InnerXKey for bip32::ExtendedPrivKey {
123    fn xkey_fingerprint<C: Signing>(&self, secp: &Secp256k1<C>) -> bip32::Fingerprint {
124        self.fingerprint(secp)
125    }
126
127    fn can_derive_hardened() -> bool {
128        true
129    }
130}
131
132/// Whether a descriptor has a wildcard in it
133#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
134pub enum Wildcard {
135    /// No wildcard
136    None,
137    /// Unhardened wildcard, e.g. *
138    Unhardened,
139    /// Unhardened wildcard, e.g. *h
140    Hardened,
141}
142
143impl SinglePriv {
144    /// Returns the public key of this key.
145    fn to_public<C: Signing>(&self, secp: &Secp256k1<C>) -> SinglePub {
146        let pub_key = self.key.public_key(secp);
147
148        SinglePub {
149            origin: self.origin.clone(),
150            key: SinglePubKey::FullKey(pub_key),
151        }
152    }
153}
154
155impl DescriptorXKey<bip32::ExtendedPrivKey> {
156    /// Returns the public version of this key, applying all the hardened derivation steps on the
157    /// private key before turning it into a public key.
158    ///
159    /// If the key already has an origin, the derivation steps applied will be appended to the path
160    /// already present, otherwise this key will be treated as a master key and an origin will be
161    /// added with this key's fingerprint and the derivation steps applied.
162    fn to_public<C: Signing>(
163        &self,
164        secp: &Secp256k1<C>,
165    ) -> Result<DescriptorXKey<bip32::ExtendedPubKey>, DescriptorKeyParseError> {
166        let unhardened = self
167            .derivation_path
168            .into_iter()
169            .rev()
170            .take_while(|c| c.is_normal())
171            .count();
172        let last_hardened_idx = self.derivation_path.len() - unhardened;
173
174        let hardened_path = &self.derivation_path[..last_hardened_idx];
175        let unhardened_path = &self.derivation_path[last_hardened_idx..];
176
177        let xprv = self
178            .xkey
179            .derive_priv(secp, &hardened_path)
180            .map_err(|_| DescriptorKeyParseError("Unable to derive the hardened steps"))?;
181        let xpub = bip32::ExtendedPubKey::from_priv(secp, &xprv);
182
183        let origin = match &self.origin {
184            Some((fingerprint, path)) => Some((
185                *fingerprint,
186                path.into_iter()
187                    .chain(hardened_path.iter())
188                    .cloned()
189                    .collect(),
190            )),
191            None => {
192                if hardened_path.is_empty() {
193                    None
194                } else {
195                    Some((self.xkey.fingerprint(secp), hardened_path.into()))
196                }
197            }
198        };
199
200        Ok(DescriptorXKey {
201            origin,
202            xkey: xpub,
203            derivation_path: unhardened_path.into(),
204            wildcard: self.wildcard,
205        })
206    }
207}
208
209/// Descriptor Key parsing errors
210// FIXME: replace with error enums
211#[derive(Debug, PartialEq, Clone, Copy)]
212pub struct DescriptorKeyParseError(&'static str);
213
214impl fmt::Display for DescriptorKeyParseError {
215    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
216        f.write_str(self.0)
217    }
218}
219
220#[cfg(feature = "std")]
221impl error::Error for DescriptorKeyParseError {
222    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
223        None
224    }
225}
226
227impl fmt::Display for DescriptorPublicKey {
228    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229        match *self {
230            DescriptorPublicKey::Single(ref pk) => {
231                maybe_fmt_master_id(f, &pk.origin)?;
232                match pk.key {
233                    SinglePubKey::FullKey(full_key) => full_key.fmt(f),
234                    SinglePubKey::XOnly(x_only_key) => x_only_key.fmt(f),
235                }?;
236                Ok(())
237            }
238            DescriptorPublicKey::XPub(ref xpub) => {
239                maybe_fmt_master_id(f, &xpub.origin)?;
240                xpub.xkey.fmt(f)?;
241                fmt_derivation_path(f, &xpub.derivation_path)?;
242                match xpub.wildcard {
243                    Wildcard::None => {}
244                    Wildcard::Unhardened => write!(f, "/*")?,
245                    Wildcard::Hardened => write!(f, "/*h")?,
246                }
247                Ok(())
248            }
249        }
250    }
251}
252
253impl DescriptorSecretKey {
254    /// Returns the public version of this key.
255    ///
256    /// If the key is an "XPrv", the hardened derivation steps will be applied
257    /// before converting it to a public key.
258    pub fn to_public<C: Signing>(
259        &self,
260        secp: &Secp256k1<C>,
261    ) -> Result<DescriptorPublicKey, DescriptorKeyParseError> {
262        let pk = match self {
263            DescriptorSecretKey::Single(prv) => DescriptorPublicKey::Single(prv.to_public(secp)),
264            DescriptorSecretKey::XPrv(xprv) => DescriptorPublicKey::XPub(xprv.to_public(secp)?),
265        };
266
267        Ok(pk)
268    }
269}
270
271/// Writes the fingerprint of the origin, if there is one.
272fn maybe_fmt_master_id(
273    f: &mut fmt::Formatter,
274    origin: &Option<(bip32::Fingerprint, bip32::DerivationPath)>,
275) -> fmt::Result {
276    if let Some((ref master_id, ref master_deriv)) = *origin {
277        fmt::Formatter::write_str(f, "[")?;
278        for byte in master_id.into_bytes().iter() {
279            write!(f, "{:02x}", byte)?;
280        }
281        fmt_derivation_path(f, master_deriv)?;
282        fmt::Formatter::write_str(f, "]")?;
283    }
284
285    Ok(())
286}
287
288/// Writes a derivation path to the formatter, no leading 'm'
289fn fmt_derivation_path(f: &mut fmt::Formatter, path: &bip32::DerivationPath) -> fmt::Result {
290    for child in path {
291        write!(f, "/{}", child)?;
292    }
293    Ok(())
294}
295
296impl FromStr for DescriptorPublicKey {
297    type Err = DescriptorKeyParseError;
298
299    fn from_str(s: &str) -> Result<Self, Self::Err> {
300        // A "raw" public key without any origin is the least we accept.
301        if s.len() < 64 {
302            return Err(DescriptorKeyParseError(
303                "Key too short (<66 char), doesn't match any format",
304            ));
305        }
306
307        let (key_part, origin) = DescriptorXKey::<bip32::ExtendedPubKey>::parse_xkey_origin(s)?;
308
309        if key_part.contains("pub") {
310            let (xpub, derivation_path, wildcard) =
311                DescriptorXKey::<bip32::ExtendedPubKey>::parse_xkey_deriv(key_part)?;
312
313            Ok(DescriptorPublicKey::XPub(DescriptorXKey {
314                origin,
315                xkey: xpub,
316                derivation_path,
317                wildcard,
318            }))
319        } else {
320            let key = match key_part.len() {
321                64 => {
322                    let x_only_key = XOnlyPublicKey::from_str(key_part).map_err(|_| {
323                        DescriptorKeyParseError("Error while parsing simple xonly key")
324                    })?;
325                    SinglePubKey::XOnly(x_only_key)
326                }
327                66 | 130 => {
328                    if !(&key_part[0..2] == "02"
329                        || &key_part[0..2] == "03"
330                        || &key_part[0..2] == "04")
331                    {
332                        return Err(DescriptorKeyParseError(
333                            "Only publickeys with prefixes 02/03/04 are allowed",
334                        ));
335                    }
336                    let key = bitcoin::PublicKey::from_str(key_part).map_err(|_| {
337                        DescriptorKeyParseError("Error while parsing simple public key")
338                    })?;
339                    SinglePubKey::FullKey(key)
340                }
341                _ => {
342                    return Err(DescriptorKeyParseError(
343                        "Public keys must be 64/66/130 characters in size",
344                    ))
345                }
346            };
347            Ok(DescriptorPublicKey::Single(SinglePub { key, origin }))
348        }
349    }
350}
351
352/// Descriptor key conversion error
353#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
354pub enum ConversionError {
355    /// Attempted to convert a key with hardened derivations to a bitcoin public key
356    HardenedChild,
357}
358
359impl fmt::Display for ConversionError {
360    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
361        f.write_str(match *self {
362            ConversionError::HardenedChild => "hardened child step in bip32 path",
363        })
364    }
365}
366
367#[cfg(feature = "std")]
368impl error::Error for ConversionError {
369    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
370        use self::ConversionError::*;
371
372        match self {
373            HardenedChild => None,
374        }
375    }
376}
377
378impl DescriptorPublicKey {
379    /// The fingerprint of the master key associated with this key, `0x00000000` if none.
380    pub fn master_fingerprint(&self) -> bip32::Fingerprint {
381        match *self {
382            DescriptorPublicKey::XPub(ref xpub) => {
383                if let Some((fingerprint, _)) = xpub.origin {
384                    fingerprint
385                } else {
386                    xpub.xkey.fingerprint()
387                }
388            }
389            DescriptorPublicKey::Single(ref single) => {
390                if let Some((fingerprint, _)) = single.origin {
391                    fingerprint
392                } else {
393                    let mut engine = XpubIdentifier::engine();
394                    match single.key {
395                        SinglePubKey::FullKey(pk) => {
396                            pk.write_into(&mut engine).expect("engines don't error")
397                        }
398                        SinglePubKey::XOnly(x_only_pk) => engine.input(&x_only_pk.serialize()),
399                    };
400                    bip32::Fingerprint::from(&XpubIdentifier::from_engine(engine)[..4])
401                }
402            }
403        }
404    }
405
406    /// Full path, from the master key
407    ///
408    /// For wildcard keys this will return the path up to the wildcard, so you
409    /// can get full paths by appending one additional derivation step, according
410    /// to the wildcard type (hardened or normal)
411    pub fn full_derivation_path(&self) -> bip32::DerivationPath {
412        match *self {
413            DescriptorPublicKey::XPub(ref xpub) => {
414                let origin_path = if let Some((_, ref path)) = xpub.origin {
415                    path.clone()
416                } else {
417                    bip32::DerivationPath::from(vec![])
418                };
419                origin_path.extend(&xpub.derivation_path)
420            }
421            DescriptorPublicKey::Single(ref single) => {
422                if let Some((_, ref path)) = single.origin {
423                    path.clone()
424                } else {
425                    bip32::DerivationPath::from(vec![])
426                }
427            }
428        }
429    }
430
431    /// Whether or not the key has a wildcard
432    #[deprecated(note = "use has_wildcard instead")]
433    pub fn is_deriveable(&self) -> bool {
434        self.has_wildcard()
435    }
436
437    /// Whether or not the key has a wildcard
438    pub fn has_wildcard(&self) -> bool {
439        match *self {
440            DescriptorPublicKey::Single(..) => false,
441            DescriptorPublicKey::XPub(ref xpub) => xpub.wildcard != Wildcard::None,
442        }
443    }
444
445    #[deprecated(note = "use at_derivation_index instead")]
446    /// Deprecated name of [`at_derivation_index`].
447    pub fn derive(self, index: u32) -> DefiniteDescriptorKey {
448        self.at_derivation_index(index)
449    }
450
451    /// Replaces any wildcard (i.e. `/*`) in the key with a particular derivation index, turning it into a
452    /// *definite* key (i.e. one where all the derivation paths are set).
453    ///
454    /// # Returns
455    ///
456    /// - If this key is not an xpub, returns `self`.
457    /// - If this key is an xpub but does not have a wildcard, returns `self`.
458    /// - Otherwise, returns the xpub at derivation `index` (removing the wildcard).
459    ///
460    /// # Panics
461    ///
462    /// If `index` ≥ 2^31
463    pub fn at_derivation_index(self, index: u32) -> DefiniteDescriptorKey {
464        let definite = match self {
465            DescriptorPublicKey::Single(_) => self,
466            DescriptorPublicKey::XPub(xpub) => {
467                let derivation_path = match xpub.wildcard {
468                    Wildcard::None => xpub.derivation_path,
469                    Wildcard::Unhardened => xpub.derivation_path.into_child(
470                        bip32::ChildNumber::from_normal_idx(index).expect("index must < 2^31"),
471                    ),
472                    Wildcard::Hardened => xpub.derivation_path.into_child(
473                        bip32::ChildNumber::from_hardened_idx(index).expect("index must < 2^31"),
474                    ),
475                };
476                DescriptorPublicKey::XPub(DescriptorXKey {
477                    origin: xpub.origin,
478                    xkey: xpub.xkey,
479                    derivation_path,
480                    wildcard: Wildcard::None,
481                })
482            }
483        };
484
485        DefiniteDescriptorKey::new(definite)
486            .expect("The key should not contain any wildcards at this point")
487    }
488}
489
490impl FromStr for DescriptorSecretKey {
491    type Err = DescriptorKeyParseError;
492
493    fn from_str(s: &str) -> Result<Self, Self::Err> {
494        let (key_part, origin) = DescriptorXKey::<bip32::ExtendedPubKey>::parse_xkey_origin(s)?;
495
496        if key_part.len() <= 52 {
497            let sk = bitcoin::PrivateKey::from_str(key_part)
498                .map_err(|_| DescriptorKeyParseError("Error while parsing a WIF private key"))?;
499            Ok(DescriptorSecretKey::Single(SinglePriv {
500                key: sk,
501                origin: None,
502            }))
503        } else {
504            let (xprv, derivation_path, wildcard) =
505                DescriptorXKey::<bip32::ExtendedPrivKey>::parse_xkey_deriv(key_part)?;
506            Ok(DescriptorSecretKey::XPrv(DescriptorXKey {
507                origin,
508                xkey: xprv,
509                derivation_path,
510                wildcard,
511            }))
512        }
513    }
514}
515
516impl<K: InnerXKey> DescriptorXKey<K> {
517    fn parse_xkey_origin(
518        s: &str,
519    ) -> Result<(&str, Option<bip32::KeySource>), DescriptorKeyParseError> {
520        for ch in s.as_bytes() {
521            if *ch < 20 || *ch > 127 {
522                return Err(DescriptorKeyParseError(
523                    "Encountered an unprintable character",
524                ));
525            }
526        }
527
528        if s.is_empty() {
529            return Err(DescriptorKeyParseError("Empty key"));
530        }
531        let mut parts = s[1..].split(']');
532
533        if let Some('[') = s.chars().next() {
534            let mut raw_origin = parts
535                .next()
536                .ok_or(DescriptorKeyParseError("Unclosed '['"))?
537                .split('/');
538
539            let origin_id_hex = raw_origin.next().ok_or(DescriptorKeyParseError(
540                "No master fingerprint found after '['",
541            ))?;
542
543            if origin_id_hex.len() != 8 {
544                return Err(DescriptorKeyParseError(
545                    "Master fingerprint should be 8 characters long",
546                ));
547            }
548            let parent_fingerprint = bip32::Fingerprint::from_hex(origin_id_hex).map_err(|_| {
549                DescriptorKeyParseError("Malformed master fingerprint, expected 8 hex chars")
550            })?;
551            let origin_path = raw_origin
552                .map(bip32::ChildNumber::from_str)
553                .collect::<Result<bip32::DerivationPath, bip32::Error>>()
554                .map_err(|_| {
555                    DescriptorKeyParseError("Error while parsing master derivation path")
556                })?;
557
558            let key = parts
559                .next()
560                .ok_or(DescriptorKeyParseError("No key after origin."))?;
561
562            if parts.next().is_some() {
563                Err(DescriptorKeyParseError(
564                    "Multiple ']' in Descriptor Public Key",
565                ))
566            } else {
567                Ok((key, Some((parent_fingerprint, origin_path))))
568            }
569        } else {
570            Ok((s, None))
571        }
572    }
573
574    /// Parse an extended key concatenated to a derivation path.
575    fn parse_xkey_deriv(
576        key_deriv: &str,
577    ) -> Result<(K, bip32::DerivationPath, Wildcard), DescriptorKeyParseError> {
578        let mut key_deriv = key_deriv.split('/');
579        let xkey_str = key_deriv.next().ok_or(DescriptorKeyParseError(
580            "No key found after origin description",
581        ))?;
582        let xkey = K::from_str(xkey_str)
583            .map_err(|_| DescriptorKeyParseError("Error while parsing xkey."))?;
584
585        let mut wildcard = Wildcard::None;
586        let derivation_path = key_deriv
587            .filter_map(|p| {
588                if wildcard == Wildcard::None && p == "*" {
589                    wildcard = Wildcard::Unhardened;
590                    None
591                } else if wildcard == Wildcard::None && (p == "*'" || p == "*h") {
592                    wildcard = Wildcard::Hardened;
593                    None
594                } else if wildcard != Wildcard::None {
595                    Some(Err(DescriptorKeyParseError(
596                        "'*' may only appear as last element in a derivation path.",
597                    )))
598                } else {
599                    Some(bip32::ChildNumber::from_str(p).map_err(|_| {
600                        DescriptorKeyParseError("Error while parsing key derivation path")
601                    }))
602                }
603            })
604            .collect::<Result<bip32::DerivationPath, _>>()?;
605
606        Ok((xkey, derivation_path, wildcard))
607    }
608
609    /// Compares this key with a `keysource` and returns the matching derivation path, if any.
610    ///
611    /// For keys that have an origin, the `keysource`'s fingerprint will be compared
612    /// with the origin's fingerprint, and the `keysource`'s path will be compared with the concatenation of the
613    /// origin's and key's paths.
614    ///
615    /// If the key `wildcard`, the last item of the `keysource`'s path will be ignored,
616    ///
617    /// ## Examples
618    ///
619    /// ```
620    /// # use std::str::FromStr;
621    /// # fn body() -> Result<(), ()> {
622    /// use miniscript::bitcoin::util::bip32;
623    /// use miniscript::descriptor::DescriptorPublicKey;
624    ///
625    /// let ctx = miniscript::bitcoin::secp256k1::Secp256k1::signing_only();
626    ///
627    /// let key = DescriptorPublicKey::from_str("[d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*").or(Err(()))?;
628    /// let xpub = match key {
629    ///     DescriptorPublicKey::XPub(xpub) => xpub,
630    ///     _ => panic!("Parsing Error"),
631    /// };
632    ///
633    /// assert_eq!(
634    ///     xpub.matches(&(
635    ///         bip32::Fingerprint::from_str("d34db33f").or(Err(()))?,
636    ///         bip32::DerivationPath::from_str("m/44'/0'/0'/1/42").or(Err(()))?
637    ///     ), &ctx),
638    ///     Some(bip32::DerivationPath::from_str("m/44'/0'/0'/1").or(Err(()))?)
639    /// );
640    /// assert_eq!(
641    ///     xpub.matches(&(
642    ///         bip32::Fingerprint::from_str("ffffffff").or(Err(()))?,
643    ///         bip32::DerivationPath::from_str("m/44'/0'/0'/1/42").or(Err(()))?
644    ///     ), &ctx),
645    ///     None
646    /// );
647    /// assert_eq!(
648    ///     xpub.matches(&(
649    ///         bip32::Fingerprint::from_str("d34db33f").or(Err(()))?,
650    ///         bip32::DerivationPath::from_str("m/44'/0'/0'/100/0").or(Err(()))?
651    ///     ), &ctx),
652    ///     None
653    /// );
654    /// # Ok(())
655    /// # }
656    /// # body().unwrap()
657    /// ```
658    pub fn matches<C: Signing>(
659        &self,
660        keysource: &bip32::KeySource,
661        secp: &Secp256k1<C>,
662    ) -> Option<bip32::DerivationPath> {
663        let (fingerprint, path) = keysource;
664
665        let (compare_fingerprint, compare_path) = match self.origin {
666            Some((fingerprint, ref path)) => (
667                fingerprint,
668                path.into_iter()
669                    .chain(self.derivation_path.into_iter())
670                    .collect(),
671            ),
672            None => (
673                self.xkey.xkey_fingerprint(secp),
674                self.derivation_path.into_iter().collect::<Vec<_>>(),
675            ),
676        };
677
678        let path_excluding_wildcard = if self.wildcard != Wildcard::None && !path.is_empty() {
679            path.into_iter()
680                .take(path.as_ref().len() - 1)
681                .cloned()
682                .collect()
683        } else {
684            path.clone()
685        };
686
687        if &compare_fingerprint == fingerprint
688            && compare_path
689                .into_iter()
690                .eq(path_excluding_wildcard.into_iter())
691        {
692            Some(path_excluding_wildcard)
693        } else {
694            None
695        }
696    }
697}
698
699impl MiniscriptKey for DescriptorPublicKey {
700    type Sha256 = sha256::Hash;
701    type Hash256 = hash256::Hash;
702    type Ripemd160 = ripemd160::Hash;
703    type Hash160 = hash160::Hash;
704
705    fn is_uncompressed(&self) -> bool {
706        match self {
707            DescriptorPublicKey::Single(SinglePub {
708                key: SinglePubKey::FullKey(ref key),
709                ..
710            }) => key.is_uncompressed(),
711            _ => false,
712        }
713    }
714
715    fn is_x_only_key(&self) -> bool {
716        match self {
717            DescriptorPublicKey::Single(SinglePub {
718                key: SinglePubKey::XOnly(ref _key),
719                ..
720            }) => true,
721            _ => false,
722        }
723    }
724}
725
726impl DefiniteDescriptorKey {
727    /// Computes the public key corresponding to this descriptor key.
728    /// When deriving from an XOnlyPublicKey, it adds the default 0x02 y-coordinate
729    /// and returns the obtained full [`bitcoin::PublicKey`]. All BIP32 derivations
730    /// always return a compressed key
731    ///
732    /// Will return an error if the descriptor key has any hardened derivation steps in its path. To
733    /// avoid this error you should replace any such public keys first with [`translate_pk`].
734    ///
735    /// [`translate_pk`]: crate::TranslatePk::translate_pk
736    pub fn derive_public_key<C: Verification>(
737        &self,
738        secp: &Secp256k1<C>,
739    ) -> Result<bitcoin::PublicKey, ConversionError> {
740        match self.0 {
741            DescriptorPublicKey::Single(ref pk) => match pk.key {
742                SinglePubKey::FullKey(pk) => Ok(pk),
743                SinglePubKey::XOnly(xpk) => Ok(xpk.to_public_key()),
744            },
745            DescriptorPublicKey::XPub(ref xpk) => match xpk.wildcard {
746                Wildcard::Unhardened | Wildcard::Hardened => {
747                    unreachable!("we've excluded this error case")
748                }
749                Wildcard::None => match xpk.xkey.derive_pub(secp, &xpk.derivation_path.as_ref()) {
750                    Ok(xpub) => Ok(bitcoin::PublicKey::new(xpub.public_key)),
751                    Err(bip32::Error::CannotDeriveFromHardenedKey) => {
752                        Err(ConversionError::HardenedChild)
753                    }
754                    Err(e) => unreachable!("cryptographically unreachable: {}", e),
755                },
756            },
757        }
758    }
759
760    /// Construct an instance from a descriptor key and a derivation index
761    ///
762    /// Returns `None` if the key contains a wildcard
763    fn new(key: DescriptorPublicKey) -> Option<Self> {
764        if key.has_wildcard() {
765            None
766        } else {
767            Some(Self(key))
768        }
769    }
770
771    /// The fingerprint of the master key associated with this key, `0x00000000` if none.
772    pub fn master_fingerprint(&self) -> bip32::Fingerprint {
773        self.0.master_fingerprint()
774    }
775
776    /// Full path, from the master key
777    pub fn full_derivation_path(&self) -> bip32::DerivationPath {
778        self.0.full_derivation_path()
779    }
780}
781
782impl FromStr for DefiniteDescriptorKey {
783    type Err = DescriptorKeyParseError;
784
785    fn from_str(s: &str) -> Result<Self, Self::Err> {
786        let inner = DescriptorPublicKey::from_str(s)?;
787        Ok(
788            DefiniteDescriptorKey::new(inner).ok_or(DescriptorKeyParseError(
789                "cannot parse key with a wilcard as a DerivedDescriptorKey",
790            ))?,
791        )
792    }
793}
794
795impl fmt::Display for DefiniteDescriptorKey {
796    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
797        self.0.fmt(f)
798    }
799}
800
801impl MiniscriptKey for DefiniteDescriptorKey {
802    type Sha256 = sha256::Hash;
803    type Hash256 = hash256::Hash;
804    type Ripemd160 = ripemd160::Hash;
805    type Hash160 = hash160::Hash;
806
807    fn is_uncompressed(&self) -> bool {
808        self.0.is_uncompressed()
809    }
810
811    fn is_x_only_key(&self) -> bool {
812        self.0.is_x_only_key()
813    }
814}
815
816impl ToPublicKey for DefiniteDescriptorKey {
817    fn to_public_key(&self) -> bitcoin::PublicKey {
818        let secp = Secp256k1::verification_only();
819        self.derive_public_key(&secp).unwrap()
820    }
821
822    fn to_sha256(hash: &sha256::Hash) -> sha256::Hash {
823        *hash
824    }
825
826    fn to_hash256(hash: &hash256::Hash) -> hash256::Hash {
827        *hash
828    }
829
830    fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash {
831        *hash
832    }
833
834    fn to_hash160(hash: &hash160::Hash) -> hash160::Hash {
835        *hash
836    }
837}
838
839impl From<DefiniteDescriptorKey> for DescriptorPublicKey {
840    fn from(d: DefiniteDescriptorKey) -> Self {
841        d.0
842    }
843}
844
845#[cfg(test)]
846mod test {
847    use core::str::FromStr;
848
849    use bitcoin::secp256k1;
850
851    use super::{DescriptorKeyParseError, DescriptorPublicKey, DescriptorSecretKey};
852    use crate::prelude::*;
853
854    #[test]
855    fn parse_descriptor_key_errors() {
856        // And ones with misplaced wildcard
857        let desc = "[78412e3a/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*/44";
858        assert_eq!(
859            DescriptorPublicKey::from_str(desc),
860            Err(DescriptorKeyParseError(
861                "\'*\' may only appear as last element in a derivation path."
862            ))
863        );
864
865        // And ones with invalid fingerprints
866        let desc = "[NonHexor]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*";
867        assert_eq!(
868            DescriptorPublicKey::from_str(desc),
869            Err(DescriptorKeyParseError(
870                "Malformed master fingerprint, expected 8 hex chars"
871            ))
872        );
873
874        // And ones with invalid xpubs..
875        let desc = "[78412e3a]xpub1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaLcgJvLJuZZvRcEL/1/*";
876        assert_eq!(
877            DescriptorPublicKey::from_str(desc),
878            Err(DescriptorKeyParseError("Error while parsing xkey."))
879        );
880
881        // ..or invalid raw keys
882        let desc = "[78412e3a]0208a117f3897c3a13c9384b8695eed98dc31bc2500feb19a1af424cd47a5d83/1/*";
883        assert_eq!(
884            DescriptorPublicKey::from_str(desc),
885            Err(DescriptorKeyParseError(
886                "Public keys must be 64/66/130 characters in size"
887            ))
888        );
889
890        // ..or invalid separators
891        let desc = "[78412e3a]]03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8";
892        assert_eq!(
893            DescriptorPublicKey::from_str(desc),
894            Err(DescriptorKeyParseError(
895                "Multiple \']\' in Descriptor Public Key"
896            ))
897        );
898
899        // fuzzer errors
900        let desc = "[11111f11]033333333333333333333333333333323333333333333333333333333433333333]]333]]3]]101333333333333433333]]]10]333333mmmm";
901        assert_eq!(
902            DescriptorPublicKey::from_str(desc),
903            Err(DescriptorKeyParseError(
904                "Multiple \']\' in Descriptor Public Key"
905            ))
906        );
907
908        // fuzz failure, hybrid keys
909        let desc = "0777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777";
910        assert_eq!(
911            DescriptorPublicKey::from_str(desc),
912            Err(DescriptorKeyParseError(
913                "Only publickeys with prefixes 02/03/04 are allowed"
914            ))
915        );
916    }
917
918    #[test]
919    fn parse_descriptor_secret_key_error() {
920        // Xpubs are invalid
921        let secret_key = "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL";
922        assert_eq!(
923            DescriptorSecretKey::from_str(secret_key),
924            Err(DescriptorKeyParseError("Error while parsing xkey."))
925        );
926
927        // And ones with invalid fingerprints
928        let desc = "[NonHexor]tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/*";
929        assert_eq!(
930            DescriptorSecretKey::from_str(desc),
931            Err(DescriptorKeyParseError(
932                "Malformed master fingerprint, expected 8 hex chars"
933            ))
934        );
935
936        // ..or invalid raw keys
937        let desc = "[78412e3a]L32jTfVLei6BYTPUpwpJSkrHx8iL9GZzeErVS8y4Y/1/*";
938        assert_eq!(
939            DescriptorSecretKey::from_str(desc),
940            Err(DescriptorKeyParseError(
941                "Error while parsing a WIF private key"
942            ))
943        );
944    }
945
946    #[test]
947    fn test_wildcard() {
948        let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2").unwrap();
949        assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
950        assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'/2");
951        assert_eq!(public_key.has_wildcard(), false);
952
953        let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*").unwrap();
954        assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
955        assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'");
956        assert_eq!(public_key.has_wildcard(), true);
957
958        let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*h").unwrap();
959        assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
960        assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'");
961        assert_eq!(public_key.has_wildcard(), true);
962    }
963
964    #[test]
965    fn test_deriv_on_xprv() {
966        let secp = secp256k1::Secp256k1::signing_only();
967
968        let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2").unwrap();
969        let public_key = secret_key.to_public(&secp).unwrap();
970        assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2");
971        assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d");
972        assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'/2");
973        assert_eq!(public_key.has_wildcard(), false);
974
975        let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2'").unwrap();
976        let public_key = secret_key.to_public(&secp).unwrap();
977        assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1'/2']tpubDDPuH46rv4dbFtmF6FrEtJEy1CvLZonyBoVxF6xsesHdYDdTBrq2mHhm8AbsPh39sUwL2nZyxd6vo4uWNTU9v4t893CwxjqPnwMoUACLvMV");
978        assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d");
979        assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'/2'");
980
981        let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0/1/2").unwrap();
982        let public_key = secret_key.to_public(&secp).unwrap();
983        assert_eq!(public_key.to_string(), "tpubD6NzVbkrYhZ4WQdzxL7NmJN7b85ePo4p6RSj9QQHF7te2RR9iUeVSGgnGkoUsB9LBRosgvNbjRv9bcsJgzgBd7QKuxDm23ZewkTRzNSLEDr/0/1/2");
984        assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d");
985        assert_eq!(public_key.full_derivation_path().to_string(), "m/0/1/2");
986
987        let secret_key = DescriptorSecretKey::from_str("[aabbccdd]tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0/1/2").unwrap();
988        let public_key = secret_key.to_public(&secp).unwrap();
989        assert_eq!(public_key.to_string(), "[aabbccdd]tpubD6NzVbkrYhZ4WQdzxL7NmJN7b85ePo4p6RSj9QQHF7te2RR9iUeVSGgnGkoUsB9LBRosgvNbjRv9bcsJgzgBd7QKuxDm23ZewkTRzNSLEDr/0/1/2");
990        assert_eq!(public_key.master_fingerprint().to_string(), "aabbccdd");
991        assert_eq!(public_key.full_derivation_path().to_string(), "m/0/1/2");
992
993        let secret_key = DescriptorSecretKey::from_str("[aabbccdd/90']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2").unwrap();
994        let public_key = secret_key.to_public(&secp).unwrap();
995        assert_eq!(public_key.to_string(), "[aabbccdd/90'/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2");
996        assert_eq!(public_key.master_fingerprint().to_string(), "aabbccdd");
997        assert_eq!(
998            public_key.full_derivation_path().to_string(),
999            "m/90'/0'/1'/2"
1000        );
1001    }
1002
1003    #[test]
1004    fn test_master_fingerprint() {
1005        assert_eq!(
1006            DescriptorPublicKey::from_str(
1007                "02a489e0ea42b56148d212d325b7c67c6460483ff931c303ea311edfef667c8f35",
1008            )
1009            .unwrap()
1010            .master_fingerprint()
1011            .as_bytes(),
1012            b"\xb0\x59\x11\x6a"
1013        );
1014    }
1015}