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::{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#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
21pub enum DescriptorPublicKey {
22 Single(SinglePub),
24 XPub(DescriptorXKey<bip32::Xpub>),
26 MultiXPub(DescriptorMultiXKey<bip32::Xpub>),
28}
29
30#[derive(Debug, Eq, PartialEq, Clone)]
32pub enum DescriptorSecretKey {
33 Single(SinglePriv),
35 XPrv(DescriptorXKey<bip32::Xpriv>),
37 MultiXPrv(DescriptorMultiXKey<bip32::Xpriv>),
39}
40
41#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
43pub struct SinglePub {
44 pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
46 pub key: SinglePubKey,
48}
49
50#[derive(Debug, Eq, PartialEq, Clone)]
52pub struct SinglePriv {
53 pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
55 pub key: bitcoin::PrivateKey,
57}
58
59#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
61pub struct DescriptorXKey<K: InnerXKey> {
62 pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
64 pub xkey: K,
66 pub derivation_path: bip32::DerivationPath,
68 pub wildcard: Wildcard,
70}
71
72#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
74pub struct DerivPaths(Vec<bip32::DerivationPath>);
75
76impl DerivPaths {
77 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 pub fn paths(&self) -> &Vec<bip32::DerivationPath> { &self.0 }
88
89 pub fn into_paths(self) -> Vec<bip32::DerivationPath> { self.0 }
91}
92
93#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
95pub struct DescriptorMultiXKey<K: InnerXKey> {
96 pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
98 pub xkey: K,
100 pub derivation_paths: DerivPaths,
102 pub wildcard: Wildcard,
104}
105
106#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
108pub enum SinglePubKey {
109 FullKey(bitcoin::PublicKey),
111 XOnly(XOnlyPublicKey),
113}
114
115#[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
153pub trait InnerXKey: fmt::Display + FromStr {
156 fn xkey_fingerprint<C: Signing>(&self, secp: &Secp256k1<C>) -> bip32::Fingerprint;
158
159 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#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
183pub enum Wildcard {
184 None,
186 Unhardened,
188 Hardened,
190}
191
192impl SinglePriv {
193 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 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#[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 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 pub fn is_multipath(&self) -> bool {
334 match *self {
335 DescriptorSecretKey::Single(..) | DescriptorSecretKey::XPrv(..) => false,
336 DescriptorSecretKey::MultiXPrv(_) => true,
337 }
338 }
339
340 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
367fn 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
384fn 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
392fn 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 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#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
490pub enum ConversionError {
491 HardenedChild,
493 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 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 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 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 #[deprecated(note = "use has_wildcard instead")]
613 pub fn is_deriveable(&self) -> bool { self.has_wildcard() }
614
615 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 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 pub fn derive(self, index: u32) -> Result<DefiniteDescriptorKey, ConversionError> {
644 self.at_derivation_index(index)
645 }
646
647 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 pub fn is_multipath(&self) -> bool {
692 match *self {
693 DescriptorPublicKey::Single(..) | DescriptorPublicKey::XPub(..) => false,
694 DescriptorPublicKey::MultiXPub(_) => true,
695 }
696 }
697
698 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
756fn 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
804fn 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 if p.starts_with('<') && p.ends_with('>') {
833 if multipath {
835 return Some(Err(DescriptorKeyParseError(
836 "'<' may only appear once in a derivation path.",
837 )));
838 }
839 multipath = true;
840
841 if p.len() < 5 || !p.contains(';') {
844 return Some(Err(DescriptorKeyParseError(
845 "Invalid multi index step in multipath descriptor.",
846 )));
847 }
848
849 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 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 .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 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 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 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 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 pub fn master_fingerprint(&self) -> bip32::Fingerprint { self.0.master_fingerprint() }
1078
1079 pub fn full_derivation_path(&self) -> Option<bip32::DerivationPath> {
1081 self.0.full_derivation_path()
1082 }
1083
1084 pub fn full_derivation_paths(&self) -> Vec<bip32::DerivationPath> {
1087 self.0.full_derivation_paths()
1088 }
1089
1090 pub fn as_descriptor_public_key(&self) -> &DescriptorPublicKey { &self.0 }
1092
1093 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 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 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 let desc = "[78412e3a]xpub1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaLcgJvLJuZZvRcEL/1/*";
1204 assert_eq!(
1205 DescriptorPublicKey::from_str(desc),
1206 Err(DescriptorKeyParseError("Error while parsing xkey."))
1207 );
1208
1209 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 let desc = "[78412e3a]]03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8";
1218 assert_eq!(
1219 DescriptorPublicKey::from_str(desc),
1220 Err(DescriptorKeyParseError("Multiple \']\' in Descriptor Public Key"))
1221 );
1222
1223 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 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 let secret_key = "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL";
1242 assert_eq!(
1243 DescriptorSecretKey::from_str(secret_key),
1244 Err(DescriptorKeyParseError("Error while parsing xkey."))
1245 );
1246
1247 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 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 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 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 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 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 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 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 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 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 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 let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
1535 .parse::<DescriptorPublicKey>()
1536 .unwrap();
1537 assert!(DefiniteDescriptorKey::new(desc).is_some());
1538 let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/*"
1540 .parse::<DescriptorPublicKey>()
1541 .unwrap();
1542 assert!(DefiniteDescriptorKey::new(desc).is_none());
1543 let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/<0;1>"
1545 .parse::<DescriptorPublicKey>()
1546 .unwrap();
1547 assert!(DefiniteDescriptorKey::new(desc).is_none());
1548 let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/1'/2"
1550 .parse::<DescriptorPublicKey>()
1551 .unwrap();
1552 assert!(DefiniteDescriptorKey::new(desc).is_none());
1553 }
1554}