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