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};
13use bitcoin::NetworkKind;
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
120#[derive(Debug, Eq, PartialEq, Clone)]
122pub enum XKeyNetwork {
123 NoXKeys,
125 Mixed,
127 Single(NetworkKind),
129}
130
131impl fmt::Display for DescriptorSecretKey {
132 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133 match self {
134 DescriptorSecretKey::Single(ref sk) => {
135 maybe_fmt_master_id(f, &sk.origin)?;
136 sk.key.fmt(f)?;
137 Ok(())
138 }
139 DescriptorSecretKey::XPrv(ref xprv) => {
140 maybe_fmt_master_id(f, &xprv.origin)?;
141 xprv.xkey.fmt(f)?;
142 fmt_derivation_path(f, &xprv.derivation_path)?;
143 match xprv.wildcard {
144 Wildcard::None => {}
145 Wildcard::Unhardened => write!(f, "/*")?,
146 Wildcard::Hardened => write!(f, "/*h")?,
147 }
148 Ok(())
149 }
150 DescriptorSecretKey::MultiXPrv(ref xprv) => {
151 maybe_fmt_master_id(f, &xprv.origin)?;
152 xprv.xkey.fmt(f)?;
153 fmt_derivation_paths(f, xprv.derivation_paths.paths())?;
154 match xprv.wildcard {
155 Wildcard::None => {}
156 Wildcard::Unhardened => write!(f, "/*")?,
157 Wildcard::Hardened => write!(f, "/*h")?,
158 }
159 Ok(())
160 }
161 }
162 }
163}
164
165pub trait InnerXKey: fmt::Display + FromStr {
168 fn xkey_fingerprint<C: Signing>(&self, secp: &Secp256k1<C>) -> bip32::Fingerprint;
170
171 fn can_derive_hardened() -> bool;
175}
176
177impl InnerXKey for bip32::Xpub {
178 fn xkey_fingerprint<C: Signing>(&self, _secp: &Secp256k1<C>) -> bip32::Fingerprint {
179 self.fingerprint()
180 }
181
182 fn can_derive_hardened() -> bool { false }
183}
184
185impl InnerXKey for bip32::Xpriv {
186 fn xkey_fingerprint<C: Signing>(&self, secp: &Secp256k1<C>) -> bip32::Fingerprint {
187 self.fingerprint(secp)
188 }
189
190 fn can_derive_hardened() -> bool { true }
191}
192
193#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
195pub enum Wildcard {
196 None,
198 Unhardened,
200 Hardened,
202}
203
204impl SinglePriv {
205 fn to_public<C: Signing>(&self, secp: &Secp256k1<C>) -> SinglePub {
207 let pub_key = self.key.public_key(secp);
208
209 SinglePub { origin: self.origin.clone(), key: SinglePubKey::FullKey(pub_key) }
210 }
211}
212
213impl DescriptorXKey<bip32::Xpriv> {
214 fn to_public<C: Signing>(
221 &self,
222 secp: &Secp256k1<C>,
223 ) -> Result<DescriptorXKey<bip32::Xpub>, DescriptorKeyParseError> {
224 let unhardened = self
225 .derivation_path
226 .into_iter()
227 .rev()
228 .take_while(|c| c.is_normal())
229 .count();
230 let last_hardened_idx = self.derivation_path.len() - unhardened;
231
232 let hardened_path = &self.derivation_path[..last_hardened_idx];
233 let unhardened_path = &self.derivation_path[last_hardened_idx..];
234
235 let xprv = self
236 .xkey
237 .derive_priv(secp, &hardened_path)
238 .map_err(DescriptorKeyParseError::DeriveHardenedKey)?;
239
240 let xpub = bip32::Xpub::from_priv(secp, &xprv);
241
242 let origin = match &self.origin {
243 Some((fingerprint, path)) => {
244 Some((*fingerprint, path.into_iter().chain(hardened_path).copied().collect()))
245 }
246 None if !hardened_path.is_empty() => {
247 Some((self.xkey.fingerprint(secp), hardened_path.into()))
248 }
249 None => None,
250 };
251
252 Ok(DescriptorXKey {
253 origin,
254 xkey: xpub,
255 derivation_path: unhardened_path.into(),
256 wildcard: self.wildcard,
257 })
258 }
259}
260
261impl DescriptorMultiXKey<bip32::Xpriv> {
262 fn to_public<C: Signing>(
267 &self,
268 secp: &Secp256k1<C>,
269 ) -> Result<DescriptorMultiXKey<bip32::Xpub>, DescriptorKeyParseError> {
270 let deriv_paths = self.derivation_paths.paths();
271
272 let shared_prefix: Vec<_> = deriv_paths[0]
273 .into_iter()
274 .enumerate()
275 .take_while(|(index, child_num)| {
276 deriv_paths[1..].iter().all(|other_path| {
277 other_path.len() > *index && other_path[*index] == **child_num
278 })
279 })
280 .map(|(_, child_num)| *child_num)
281 .collect();
282
283 let suffixes: Vec<Vec<_>> = deriv_paths
284 .iter()
285 .map(|path| {
286 path.into_iter()
287 .skip(shared_prefix.len())
288 .map(|child_num| {
289 if child_num.is_normal() {
290 Ok(*child_num)
291 } else {
292 Err(DescriptorKeyParseError::MalformedKeyData(
293 MalformedKeyDataKind::InvalidMultiXKeyDerivation,
294 ))
295 }
296 })
297 .collect()
298 })
299 .collect::<Result<_, _>>()?;
300
301 let unhardened = shared_prefix
302 .iter()
303 .rev()
304 .take_while(|c| c.is_normal())
305 .count();
306 let last_hardened_idx = shared_prefix.len() - unhardened;
307 let hardened_path = &shared_prefix[..last_hardened_idx];
308 let unhardened_path = &shared_prefix[last_hardened_idx..];
309
310 let xprv = self
311 .xkey
312 .derive_priv(secp, &hardened_path)
313 .map_err(DescriptorKeyParseError::DeriveHardenedKey)?;
314 let xpub = bip32::Xpub::from_priv(secp, &xprv);
315
316 let origin = match &self.origin {
317 Some((fingerprint, path)) => {
318 Some((*fingerprint, path.into_iter().chain(hardened_path).copied().collect()))
319 }
320 None if !hardened_path.is_empty() => {
321 Some((self.xkey.fingerprint(secp), hardened_path.into()))
322 }
323 None => None,
324 };
325 let new_deriv_paths = suffixes
326 .into_iter()
327 .map(|suffix| {
328 let path = unhardened_path.iter().copied().chain(suffix);
329 path.collect::<Vec<_>>().into()
330 })
331 .collect();
332
333 Ok(DescriptorMultiXKey {
334 origin,
335 xkey: xpub,
336 derivation_paths: DerivPaths::new(new_deriv_paths).expect("not empty"),
337 wildcard: self.wildcard,
338 })
339 }
340}
341
342#[derive(Debug, PartialEq, Eq, Clone)]
344#[non_exhaustive]
345#[allow(missing_docs)]
346pub enum NonDefiniteKeyError {
347 Wildcard,
348 Multipath,
349 HardenedStep,
350}
351
352impl fmt::Display for NonDefiniteKeyError {
353 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354 match *self {
355 Self::Wildcard => f.write_str("key with a wildcard cannot be a DerivedDescriptorKey"),
356 Self::Multipath => f.write_str("multipath key cannot be a DerivedDescriptorKey"),
357 Self::HardenedStep => {
358 f.write_str("key with hardened derivation steps cannot be a DerivedDescriptorKey")
359 }
360 }
361 }
362}
363
364#[cfg(feature = "std")]
365impl error::Error for NonDefiniteKeyError {}
366
367#[derive(Debug, PartialEq, Eq, Clone)]
369#[non_exhaustive]
370#[allow(missing_docs)]
371pub enum MalformedKeyDataKind {
372 EmptyKey,
373 EncounteredUnprintableCharacter,
374 InvalidFullPublicKeyPrefix,
375 InvalidMasterFingerprintLength,
376 InvalidMultiIndexStep,
377 InvalidMultiXKeyDerivation,
378 InvalidPublicKeyLength,
379 InvalidWildcardInDerivationPath,
380 KeyTooShort,
381 MultipleFingerprintsInPublicKey,
382 MultipleDerivationPathIndexSteps,
383 NoKeyAfterOrigin,
384 NoMasterFingerprintFound,
385 UnclosedSquareBracket,
386}
387
388impl fmt::Display for MalformedKeyDataKind {
389 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
390 let err = match self {
391 Self::EmptyKey => "empty key",
392 Self::EncounteredUnprintableCharacter => "encountered an unprintable character",
393 Self::InvalidFullPublicKeyPrefix => "only full public keys with prefixes '02', '03' or '04' are allowed",
394 Self::InvalidMasterFingerprintLength => "master fingerprint should be 8 characters long",
395 Self::InvalidMultiIndexStep => "invalid multi index step in multipath descriptor",
396 Self::InvalidMultiXKeyDerivation => "can't make a multi-xpriv with hardened derivation steps that are not shared among all paths into a public key",
397 Self::InvalidPublicKeyLength => "public keys must be 64, 66 or 130 characters in size",
398 Self::InvalidWildcardInDerivationPath => "'*' may only appear as last element in a derivation path",
399 Self::KeyTooShort => "key too short",
400 Self::MultipleFingerprintsInPublicKey => "multiple ']' in Descriptor Public Key",
401 Self::MultipleDerivationPathIndexSteps => "'<' may only appear once in a derivation path",
402 Self::NoKeyAfterOrigin => "no key after origin",
403 Self::NoMasterFingerprintFound => "no master fingerprint found after '['",
404 Self::UnclosedSquareBracket => "unclosed '['",
405 };
406
407 f.write_str(err)
408 }
409}
410
411#[derive(Debug, PartialEq, Eq, Clone)]
413#[non_exhaustive]
414pub enum DescriptorKeyParseError {
415 Bip32Xpriv(bip32::Error),
417 Bip32Xpub(bip32::Error),
419 DerivationIndexError {
421 index: String,
423 err: bitcoin::bip32::Error,
425 },
426 DeriveHardenedKey(bip32::Error),
428 MalformedKeyData(MalformedKeyDataKind),
430 MasterDerivationPath(bip32::Error),
432 MasterFingerprint {
434 fingerprint: String,
436 err: bitcoin::hex::HexToArrayError,
438 },
439 NonDefiniteKey(NonDefiniteKeyError),
441 FullPublicKey(bitcoin::key::ParsePublicKeyError),
443 WifPrivateKey(bitcoin::key::FromWifError),
445 XonlyPublicKey(bitcoin::secp256k1::Error),
447}
448
449impl fmt::Display for DescriptorKeyParseError {
450 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
451 match self {
452 Self::Bip32Xpriv(err) => err.fmt(f),
453 Self::Bip32Xpub(err) => err.fmt(f),
454 Self::DerivationIndexError { index, err } => {
455 write!(f, "at derivation index '{index}': {err}")
456 }
457 Self::DeriveHardenedKey(err) => err.fmt(f),
458 Self::MalformedKeyData(err) => err.fmt(f),
459 Self::MasterDerivationPath(err) => err.fmt(f),
460 Self::MasterFingerprint { fingerprint, err } => {
461 write!(f, "on master fingerprint '{fingerprint}': {err}")
462 }
463 Self::NonDefiniteKey(err) => err.fmt(f),
464 Self::FullPublicKey(err) => err.fmt(f),
465 Self::WifPrivateKey(err) => err.fmt(f),
466 Self::XonlyPublicKey(err) => err.fmt(f),
467 }
468 }
469}
470
471#[cfg(feature = "std")]
472impl error::Error for DescriptorKeyParseError {
473 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
474 match self {
475 Self::Bip32Xpriv(err)
476 | Self::Bip32Xpub(err)
477 | Self::DerivationIndexError { err, .. }
478 | Self::DeriveHardenedKey(err)
479 | Self::MasterDerivationPath(err) => Some(err),
480 Self::MasterFingerprint { err, .. } => Some(err),
481 Self::NonDefiniteKey(err) => Some(err),
482 Self::FullPublicKey(err) => Some(err),
483 Self::WifPrivateKey(err) => Some(err),
484 Self::XonlyPublicKey(err) => Some(err),
485 Self::MalformedKeyData(_) => None,
486 }
487 }
488}
489
490impl fmt::Display for DescriptorPublicKey {
491 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
492 match *self {
493 Self::Single(ref pk) => {
494 maybe_fmt_master_id(f, &pk.origin)?;
495 match pk.key {
496 SinglePubKey::FullKey(full_key) => full_key.fmt(f),
497 SinglePubKey::XOnly(x_only_key) => x_only_key.fmt(f),
498 }?;
499 Ok(())
500 }
501 Self::XPub(ref xpub) => {
502 maybe_fmt_master_id(f, &xpub.origin)?;
503 xpub.xkey.fmt(f)?;
504 fmt_derivation_path(f, &xpub.derivation_path)?;
505 match xpub.wildcard {
506 Wildcard::None => {}
507 Wildcard::Unhardened => write!(f, "/*")?,
508 Wildcard::Hardened => write!(f, "/*h")?,
509 }
510 Ok(())
511 }
512 Self::MultiXPub(ref xpub) => {
513 maybe_fmt_master_id(f, &xpub.origin)?;
514 xpub.xkey.fmt(f)?;
515 fmt_derivation_paths(f, xpub.derivation_paths.paths())?;
516 match xpub.wildcard {
517 Wildcard::None => {}
518 Wildcard::Unhardened => write!(f, "/*")?,
519 Wildcard::Hardened => write!(f, "/*h")?,
520 }
521 Ok(())
522 }
523 }
524 }
525}
526
527impl DescriptorSecretKey {
528 pub fn to_public<C: Signing>(
536 &self,
537 secp: &Secp256k1<C>,
538 ) -> Result<DescriptorPublicKey, DescriptorKeyParseError> {
539 let pk = match self {
540 DescriptorSecretKey::Single(prv) => DescriptorPublicKey::Single(prv.to_public(secp)),
541 DescriptorSecretKey::XPrv(xprv) => DescriptorPublicKey::XPub(xprv.to_public(secp)?),
542 DescriptorSecretKey::MultiXPrv(xprv) => {
543 DescriptorPublicKey::MultiXPub(xprv.to_public(secp)?)
544 }
545 };
546
547 Ok(pk)
548 }
549
550 pub fn is_multipath(&self) -> bool {
552 match *self {
553 DescriptorSecretKey::Single(..) | DescriptorSecretKey::XPrv(..) => false,
554 DescriptorSecretKey::MultiXPrv(_) => true,
555 }
556 }
557
558 pub fn into_single_keys(self) -> Vec<DescriptorSecretKey> {
564 match self {
565 DescriptorSecretKey::Single(..) | DescriptorSecretKey::XPrv(..) => vec![self],
566 DescriptorSecretKey::MultiXPrv(xpub) => {
567 let DescriptorMultiXKey { origin, xkey, derivation_paths, wildcard } = xpub;
568 derivation_paths
569 .into_paths()
570 .into_iter()
571 .map(|derivation_path| {
572 DescriptorSecretKey::XPrv(DescriptorXKey {
573 origin: origin.clone(),
574 xkey,
575 derivation_path,
576 wildcard,
577 })
578 })
579 .collect()
580 }
581 }
582 }
583}
584
585fn maybe_fmt_master_id(
587 f: &mut fmt::Formatter,
588 origin: &Option<(bip32::Fingerprint, bip32::DerivationPath)>,
589) -> fmt::Result {
590 if let Some((ref master_id, ref master_deriv)) = *origin {
591 fmt::Formatter::write_str(f, "[")?;
592 for byte in master_id.as_bytes().iter() {
593 write!(f, "{:02x}", byte)?;
594 }
595 fmt_derivation_path(f, master_deriv)?;
596 fmt::Formatter::write_str(f, "]")?;
597 }
598
599 Ok(())
600}
601
602fn fmt_derivation_path(f: &mut fmt::Formatter, path: &bip32::DerivationPath) -> fmt::Result {
604 for child in path {
605 write!(f, "/{}", child)?;
606 }
607 Ok(())
608}
609
610fn fmt_derivation_paths(f: &mut fmt::Formatter, paths: &[bip32::DerivationPath]) -> fmt::Result {
614 for (i, child) in paths[0].into_iter().enumerate() {
615 if paths.len() > 1 && child != &paths[1][i] {
616 write!(f, "/<")?;
617 for (j, p) in paths.iter().enumerate() {
618 write!(f, "{}", p[i])?;
619 if j != paths.len() - 1 {
620 write!(f, ";")?;
621 }
622 }
623 write!(f, ">")?;
624 } else {
625 write!(f, "/{}", child)?;
626 }
627 }
628 Ok(())
629}
630
631impl FromStr for DescriptorPublicKey {
632 type Err = DescriptorKeyParseError;
633
634 fn from_str(s: &str) -> Result<Self, Self::Err> {
635 if s.len() < 64 {
637 return Err(DescriptorKeyParseError::MalformedKeyData(
638 MalformedKeyDataKind::KeyTooShort,
639 ));
640 }
641
642 let (key_part, origin) = parse_key_origin(s)?;
643
644 if key_part.contains("pub") {
645 let (xpub, derivation_paths, wildcard) = parse_xkey_deriv(parse_bip32_xpub, key_part)?;
646 if derivation_paths.len() > 1 {
647 Ok(DescriptorPublicKey::MultiXPub(DescriptorMultiXKey {
648 origin,
649 xkey: xpub,
650 derivation_paths: DerivPaths::new(derivation_paths).expect("Not empty"),
651 wildcard,
652 }))
653 } else {
654 Ok(DescriptorPublicKey::XPub(DescriptorXKey {
655 origin,
656 xkey: xpub,
657 derivation_path: derivation_paths.into_iter().next().unwrap_or_default(),
658 wildcard,
659 }))
660 }
661 } else {
662 let key = match key_part.len() {
663 64 => {
664 let x_only_key = XOnlyPublicKey::from_str(key_part)
665 .map_err(DescriptorKeyParseError::XonlyPublicKey)?;
666 SinglePubKey::XOnly(x_only_key)
667 }
668 66 | 130 => {
669 if !(&key_part[0..2] == "02"
670 || &key_part[0..2] == "03"
671 || &key_part[0..2] == "04")
672 {
673 return Err(DescriptorKeyParseError::MalformedKeyData(
674 MalformedKeyDataKind::InvalidFullPublicKeyPrefix,
675 ));
676 }
677 let key = bitcoin::PublicKey::from_str(key_part)
678 .map_err(DescriptorKeyParseError::FullPublicKey)?;
679 SinglePubKey::FullKey(key)
680 }
681 _ => {
682 return Err(DescriptorKeyParseError::MalformedKeyData(
683 MalformedKeyDataKind::InvalidPublicKeyLength,
684 ))
685 }
686 };
687 Ok(DescriptorPublicKey::Single(SinglePub { key, origin }))
688 }
689 }
690}
691
692impl From<XOnlyPublicKey> for DescriptorPublicKey {
693 fn from(key: XOnlyPublicKey) -> Self {
694 DescriptorPublicKey::Single(SinglePub { origin: None, key: SinglePubKey::XOnly(key) })
695 }
696}
697
698impl From<PublicKey> for DescriptorPublicKey {
699 fn from(key: PublicKey) -> Self {
700 DescriptorPublicKey::Single(SinglePub { origin: None, key: SinglePubKey::FullKey(key) })
701 }
702}
703
704impl DescriptorPublicKey {
705 pub fn master_fingerprint(&self) -> bip32::Fingerprint {
707 match *self {
708 DescriptorPublicKey::XPub(ref xpub) => {
709 if let Some((fingerprint, _)) = xpub.origin {
710 fingerprint
711 } else {
712 xpub.xkey.fingerprint()
713 }
714 }
715 DescriptorPublicKey::MultiXPub(ref xpub) => {
716 if let Some((fingerprint, _)) = xpub.origin {
717 fingerprint
718 } else {
719 xpub.xkey.fingerprint()
720 }
721 }
722 DescriptorPublicKey::Single(ref single) => {
723 if let Some((fingerprint, _)) = single.origin {
724 fingerprint
725 } else {
726 let mut engine = XKeyIdentifier::engine();
727 match single.key {
728 SinglePubKey::FullKey(pk) => {
729 pk.write_into(&mut engine).expect("engines don't error")
730 }
731 SinglePubKey::XOnly(x_only_pk) => engine.input(&x_only_pk.serialize()),
732 };
733 bip32::Fingerprint::from(
734 &XKeyIdentifier::from_engine(engine)[..4]
735 .try_into()
736 .expect("4 byte slice"),
737 )
738 }
739 }
740 }
741 }
742
743 pub fn full_derivation_path(&self) -> Option<bip32::DerivationPath> {
751 match *self {
752 DescriptorPublicKey::XPub(ref xpub) => {
753 let origin_path = if let Some((_, ref path)) = xpub.origin {
754 path.clone()
755 } else {
756 bip32::DerivationPath::from(vec![])
757 };
758 Some(origin_path.extend(&xpub.derivation_path))
759 }
760 DescriptorPublicKey::Single(ref single) => {
761 Some(if let Some((_, ref path)) = single.origin {
762 path.clone()
763 } else {
764 bip32::DerivationPath::from(vec![])
765 })
766 }
767 DescriptorPublicKey::MultiXPub(_) => None,
768 }
769 }
770
771 pub fn full_derivation_paths(&self) -> Vec<bip32::DerivationPath> {
779 match self {
780 DescriptorPublicKey::MultiXPub(xpub) => {
781 let origin_path = if let Some((_, ref path)) = xpub.origin {
782 path.clone()
783 } else {
784 bip32::DerivationPath::from(vec![])
785 };
786 xpub.derivation_paths
787 .paths()
788 .iter()
789 .map(|p| origin_path.extend(p))
790 .collect()
791 }
792 _ => vec![self
793 .full_derivation_path()
794 .expect("Must be Some for non-multipath keys")],
795 }
796 }
797
798 pub fn has_wildcard(&self) -> bool {
800 match *self {
801 DescriptorPublicKey::Single(..) => false,
802 DescriptorPublicKey::XPub(ref xpub) => xpub.wildcard != Wildcard::None,
803 DescriptorPublicKey::MultiXPub(ref xpub) => xpub.wildcard != Wildcard::None,
804 }
805 }
806
807 pub fn has_hardened_step(&self) -> bool {
809 let paths = match self {
810 DescriptorPublicKey::Single(..) => &[],
811 DescriptorPublicKey::XPub(xpub) => core::slice::from_ref(&xpub.derivation_path),
812 DescriptorPublicKey::MultiXPub(xpub) => &xpub.derivation_paths.paths()[..],
813 };
814 for p in paths {
815 for step in p.into_iter() {
816 if step.is_hardened() {
817 return true;
818 }
819 }
820 }
821 false
822 }
823
824 pub fn at_derivation_index(
838 self,
839 index: u32,
840 ) -> Result<DefiniteDescriptorKey, NonDefiniteKeyError> {
841 let definite = match self {
842 DescriptorPublicKey::Single(_) => self,
843 DescriptorPublicKey::XPub(xpub) => {
844 let derivation_path = match xpub.wildcard {
845 Wildcard::None => xpub.derivation_path,
846 Wildcard::Unhardened => xpub.derivation_path.into_child(
847 bip32::ChildNumber::from_normal_idx(index)
848 .ok()
849 .ok_or(NonDefiniteKeyError::HardenedStep)?,
850 ),
851 Wildcard::Hardened => xpub.derivation_path.into_child(
852 bip32::ChildNumber::from_hardened_idx(index)
853 .ok()
854 .ok_or(NonDefiniteKeyError::HardenedStep)?,
855 ),
856 };
857 DescriptorPublicKey::XPub(DescriptorXKey {
858 origin: xpub.origin,
859 xkey: xpub.xkey,
860 derivation_path,
861 wildcard: Wildcard::None,
862 })
863 }
864 DescriptorPublicKey::MultiXPub(_) => return Err(NonDefiniteKeyError::Multipath),
865 };
866
867 Ok(DefiniteDescriptorKey::new(definite)
868 .expect("The key should not contain any wildcards at this point"))
869 }
870
871 pub fn is_multipath(&self) -> bool {
873 match *self {
874 DescriptorPublicKey::Single(..) | DescriptorPublicKey::XPub(..) => false,
875 DescriptorPublicKey::MultiXPub(_) => true,
876 }
877 }
878
879 pub fn into_single_keys(self) -> Vec<DescriptorPublicKey> {
885 match self {
886 DescriptorPublicKey::Single(..) | DescriptorPublicKey::XPub(..) => vec![self],
887 DescriptorPublicKey::MultiXPub(xpub) => {
888 let DescriptorMultiXKey { origin, xkey, derivation_paths, wildcard } = xpub;
889 derivation_paths
890 .into_paths()
891 .into_iter()
892 .map(|derivation_path| {
893 DescriptorPublicKey::XPub(DescriptorXKey {
894 origin: origin.clone(),
895 xkey,
896 derivation_path,
897 wildcard,
898 })
899 })
900 .collect()
901 }
902 }
903 }
904
905 pub fn xkey_network(&self) -> Option<NetworkKind> {
909 match self {
910 DescriptorPublicKey::Single(_) => None,
911 DescriptorPublicKey::XPub(xpub) => Some(xpub.xkey.network),
912 DescriptorPublicKey::MultiXPub(multi_xpub) => Some(multi_xpub.xkey.network),
913 }
914 }
915}
916
917impl FromStr for DescriptorSecretKey {
918 type Err = DescriptorKeyParseError;
919
920 fn from_str(s: &str) -> Result<Self, Self::Err> {
921 let (key_part, origin) = parse_key_origin(s)?;
922
923 if key_part.len() <= 52 {
924 let sk = bitcoin::PrivateKey::from_str(key_part)
925 .map_err(DescriptorKeyParseError::WifPrivateKey)?;
926 Ok(DescriptorSecretKey::Single(SinglePriv { key: sk, origin }))
927 } else {
928 let (xpriv, derivation_paths, wildcard) =
929 parse_xkey_deriv(parse_bip32_xpriv, key_part)?;
930 if derivation_paths.len() > 1 {
931 Ok(DescriptorSecretKey::MultiXPrv(DescriptorMultiXKey {
932 origin,
933 xkey: xpriv,
934 derivation_paths: DerivPaths::new(derivation_paths).expect("Not empty"),
935 wildcard,
936 }))
937 } else {
938 Ok(DescriptorSecretKey::XPrv(DescriptorXKey {
939 origin,
940 xkey: xpriv,
941 derivation_path: derivation_paths.into_iter().next().unwrap_or_default(),
942 wildcard,
943 }))
944 }
945 }
946 }
947}
948
949fn parse_key_origin(s: &str) -> Result<(&str, Option<bip32::KeySource>), DescriptorKeyParseError> {
951 for ch in s.as_bytes() {
952 if *ch < 20 || *ch > 127 {
953 return Err(DescriptorKeyParseError::MalformedKeyData(
954 MalformedKeyDataKind::EncounteredUnprintableCharacter,
955 ));
956 }
957 }
958
959 if s.is_empty() {
960 return Err(DescriptorKeyParseError::MalformedKeyData(MalformedKeyDataKind::EmptyKey));
961 }
962 let mut parts = s[1..].split(']');
963
964 if let Some('[') = s.chars().next() {
965 let mut raw_origin = parts
966 .next()
967 .ok_or(DescriptorKeyParseError::MalformedKeyData(
968 MalformedKeyDataKind::UnclosedSquareBracket,
969 ))?
970 .split('/');
971
972 let origin_id_hex = raw_origin
973 .next()
974 .ok_or(DescriptorKeyParseError::MalformedKeyData(
975 MalformedKeyDataKind::NoMasterFingerprintFound,
976 ))?;
977
978 if origin_id_hex.len() != 8 {
979 return Err(DescriptorKeyParseError::MalformedKeyData(
980 MalformedKeyDataKind::InvalidMasterFingerprintLength,
981 ));
982 }
983 let parent_fingerprint = bip32::Fingerprint::from_hex(origin_id_hex).map_err(|err| {
984 DescriptorKeyParseError::MasterFingerprint {
985 fingerprint: origin_id_hex.to_owned(),
986 err,
987 }
988 })?;
989 let origin_path = raw_origin
990 .map(bip32::ChildNumber::from_str)
991 .collect::<Result<bip32::DerivationPath, bip32::Error>>()
992 .map_err(DescriptorKeyParseError::MasterDerivationPath)?;
993
994 let key = parts
995 .next()
996 .ok_or(DescriptorKeyParseError::MalformedKeyData(
997 MalformedKeyDataKind::NoKeyAfterOrigin,
998 ))?;
999
1000 if parts.next().is_some() {
1001 Err(DescriptorKeyParseError::MalformedKeyData(
1002 MalformedKeyDataKind::MultipleFingerprintsInPublicKey,
1003 ))
1004 } else {
1005 Ok((key, Some((parent_fingerprint, origin_path))))
1006 }
1007 } else {
1008 Ok((s, None))
1009 }
1010}
1011
1012fn parse_bip32_xpub(xkey_str: &str) -> Result<bip32::Xpub, DescriptorKeyParseError> {
1013 bip32::Xpub::from_str(xkey_str).map_err(DescriptorKeyParseError::Bip32Xpub)
1014}
1015
1016fn parse_bip32_xpriv(xkey_str: &str) -> Result<bip32::Xpriv, DescriptorKeyParseError> {
1017 bip32::Xpriv::from_str(xkey_str).map_err(DescriptorKeyParseError::Bip32Xpriv)
1018}
1019
1020fn parse_xkey_deriv<Key>(
1021 parse_xkey_fn: impl Fn(&str) -> Result<Key, DescriptorKeyParseError>,
1022 key_deriv: &str,
1023) -> Result<(Key, Vec<bip32::DerivationPath>, Wildcard), DescriptorKeyParseError> {
1024 let mut key_deriv = key_deriv.split('/');
1025 let xkey_str = key_deriv
1026 .next()
1027 .ok_or(DescriptorKeyParseError::MalformedKeyData(
1028 MalformedKeyDataKind::NoKeyAfterOrigin,
1029 ))?;
1030
1031 let xkey = parse_xkey_fn(xkey_str)?;
1032
1033 let mut wildcard = Wildcard::None;
1034 let mut multipath = false;
1035 let derivation_paths = key_deriv
1036 .filter_map(|p| {
1037 if wildcard == Wildcard::None && p == "*" {
1038 wildcard = Wildcard::Unhardened;
1039 None
1040 } else if wildcard == Wildcard::None && (p == "*'" || p == "*h") {
1041 wildcard = Wildcard::Hardened;
1042 None
1043 } else if wildcard != Wildcard::None {
1044 Some(Err(DescriptorKeyParseError::MalformedKeyData(
1045 MalformedKeyDataKind::InvalidWildcardInDerivationPath,
1046 )))
1047 } else {
1048 if p.starts_with('<') && p.ends_with('>') {
1051 if multipath {
1053 return Some(Err(DescriptorKeyParseError::MalformedKeyData(
1054 MalformedKeyDataKind::MultipleDerivationPathIndexSteps,
1055 )));
1056 }
1057 multipath = true;
1058
1059 if p.len() < 5 || !p.contains(';') {
1062 return Some(Err(DescriptorKeyParseError::MalformedKeyData(
1063 MalformedKeyDataKind::InvalidMultiIndexStep,
1064 )));
1065 }
1066
1067 let indexes = p[1..p.len() - 1].split(';');
1069 Some(
1070 indexes
1071 .into_iter()
1072 .map(|s| {
1073 bip32::ChildNumber::from_str(s).map_err(|err| {
1074 DescriptorKeyParseError::DerivationIndexError {
1075 index: s.to_owned(),
1076 err,
1077 }
1078 })
1079 })
1080 .collect::<Result<Vec<bip32::ChildNumber>, _>>(),
1081 )
1082 } else {
1083 Some(
1085 bip32::ChildNumber::from_str(p)
1086 .map(|i| vec![i])
1087 .map_err(|err| DescriptorKeyParseError::DerivationIndexError {
1088 index: p.to_owned(),
1089 err,
1090 }),
1091 )
1092 }
1093 }
1094 })
1095 .try_fold(Vec::new(), |mut paths, index_list| {
1101 let mut index_list = index_list?.into_iter();
1102 let first_index = index_list
1103 .next()
1104 .expect("There is always at least one element");
1105
1106 if paths.is_empty() {
1107 paths.push(vec![first_index]);
1108 } else {
1109 for path in paths.iter_mut() {
1110 path.push(first_index);
1111 }
1112 }
1113
1114 for (i, index) in index_list.enumerate() {
1116 paths.push(paths[0].clone());
1117 *paths[i + 1].last_mut().expect("Never empty") = index;
1118 }
1119
1120 Ok(paths)
1121 })?
1122 .into_iter()
1123 .map(|index_list| index_list.into_iter().collect::<bip32::DerivationPath>())
1124 .collect::<Vec<bip32::DerivationPath>>();
1125
1126 Ok((xkey, derivation_paths, wildcard))
1127}
1128
1129impl<K: InnerXKey> DescriptorXKey<K> {
1130 pub fn matches<C: Signing>(
1180 &self,
1181 keysource: &bip32::KeySource,
1182 secp: &Secp256k1<C>,
1183 ) -> Option<bip32::DerivationPath> {
1184 let (fingerprint, path) = keysource;
1185
1186 let (compare_fingerprint, compare_path) = match self.origin {
1187 Some((fingerprint, ref path)) => {
1188 (fingerprint, path.into_iter().chain(&self.derivation_path).collect())
1189 }
1190 None => (
1191 self.xkey.xkey_fingerprint(secp),
1192 self.derivation_path.into_iter().collect::<Vec<_>>(),
1193 ),
1194 };
1195
1196 let path_excluding_wildcard = if self.wildcard != Wildcard::None && !path.is_empty() {
1197 path.into_iter()
1198 .take(path.as_ref().len() - 1)
1199 .cloned()
1200 .collect()
1201 } else {
1202 path.clone()
1203 };
1204
1205 if &compare_fingerprint == fingerprint
1206 && compare_path.into_iter().eq(&path_excluding_wildcard)
1207 {
1208 Some(path_excluding_wildcard)
1209 } else {
1210 None
1211 }
1212 }
1213}
1214
1215impl MiniscriptKey for DescriptorPublicKey {
1216 type Sha256 = sha256::Hash;
1217 type Hash256 = hash256::Hash;
1218 type Ripemd160 = ripemd160::Hash;
1219 type Hash160 = hash160::Hash;
1220
1221 fn is_uncompressed(&self) -> bool {
1222 match self {
1223 DescriptorPublicKey::Single(SinglePub {
1224 key: SinglePubKey::FullKey(ref key), ..
1225 }) => key.is_uncompressed(),
1226 _ => false,
1227 }
1228 }
1229
1230 fn is_x_only_key(&self) -> bool {
1231 matches!(
1232 self,
1233 DescriptorPublicKey::Single(SinglePub { key: SinglePubKey::XOnly(ref _key), .. })
1234 )
1235 }
1236
1237 fn num_der_paths(&self) -> usize {
1238 match self {
1239 DescriptorPublicKey::Single(_) => 0,
1240 DescriptorPublicKey::XPub(_) => 1,
1241 DescriptorPublicKey::MultiXPub(xpub) => xpub.derivation_paths.paths().len(),
1242 }
1243 }
1244}
1245
1246impl DefiniteDescriptorKey {
1247 pub fn derive_public_key<C: Verification>(&self, secp: &Secp256k1<C>) -> bitcoin::PublicKey {
1255 match self.0 {
1256 DescriptorPublicKey::Single(ref pk) => match pk.key {
1257 SinglePubKey::FullKey(pk) => pk,
1258 SinglePubKey::XOnly(xpk) => xpk.to_public_key(),
1259 },
1260 DescriptorPublicKey::XPub(ref xpk) => match xpk.wildcard {
1261 Wildcard::Unhardened | Wildcard::Hardened => {
1262 unreachable!("impossible by construction of DefiniteDescriptorKey")
1263 }
1264 Wildcard::None => match xpk.xkey.derive_pub(secp, &xpk.derivation_path.as_ref()) {
1265 Ok(xpub) => bitcoin::PublicKey::new(xpub.public_key),
1266 Err(bip32::Error::CannotDeriveFromHardenedKey) => {
1267 unreachable!("impossible by construction of DefiniteDescriptorKey")
1268 }
1269 Err(e) => unreachable!("cryptographically unreachable: {}", e),
1270 },
1271 },
1272 DescriptorPublicKey::MultiXPub(_) => {
1273 unreachable!("impossible by construction of DefiniteDescriptorKey")
1274 }
1275 }
1276 }
1277
1278 pub fn new(key: DescriptorPublicKey) -> Result<Self, NonDefiniteKeyError> {
1282 if key.has_wildcard() {
1283 Err(NonDefiniteKeyError::Wildcard)
1284 } else if key.has_hardened_step() {
1285 Err(NonDefiniteKeyError::HardenedStep)
1286 } else if key.is_multipath() {
1287 Err(NonDefiniteKeyError::Multipath)
1288 } else {
1289 Ok(Self(key))
1290 }
1291 }
1292
1293 pub fn master_fingerprint(&self) -> bip32::Fingerprint { self.0.master_fingerprint() }
1295
1296 pub fn full_derivation_path(&self) -> Option<bip32::DerivationPath> {
1298 self.0.full_derivation_path()
1299 }
1300
1301 pub fn full_derivation_paths(&self) -> Vec<bip32::DerivationPath> {
1304 self.0.full_derivation_paths()
1305 }
1306
1307 pub fn as_descriptor_public_key(&self) -> &DescriptorPublicKey { &self.0 }
1309
1310 pub fn into_descriptor_public_key(self) -> DescriptorPublicKey { self.0 }
1312}
1313
1314impl FromStr for DefiniteDescriptorKey {
1315 type Err = DescriptorKeyParseError;
1316
1317 fn from_str(s: &str) -> Result<Self, Self::Err> {
1318 let d = DescriptorPublicKey::from_str(s)?;
1319 DefiniteDescriptorKey::new(d).map_err(DescriptorKeyParseError::NonDefiniteKey)
1320 }
1321}
1322
1323impl fmt::Display for DefiniteDescriptorKey {
1324 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) }
1325}
1326
1327impl MiniscriptKey for DefiniteDescriptorKey {
1328 type Sha256 = sha256::Hash;
1329 type Hash256 = hash256::Hash;
1330 type Ripemd160 = ripemd160::Hash;
1331 type Hash160 = hash160::Hash;
1332
1333 fn is_uncompressed(&self) -> bool { self.0.is_uncompressed() }
1334
1335 fn is_x_only_key(&self) -> bool { self.0.is_x_only_key() }
1336
1337 fn num_der_paths(&self) -> usize { self.0.num_der_paths() }
1338}
1339
1340impl ToPublicKey for DefiniteDescriptorKey {
1341 fn to_public_key(&self) -> bitcoin::PublicKey {
1342 let secp = Secp256k1::verification_only();
1343 self.derive_public_key(&secp)
1344 }
1345
1346 fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash }
1347
1348 fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { *hash }
1349
1350 fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash { *hash }
1351
1352 fn to_hash160(hash: &hash160::Hash) -> hash160::Hash { *hash }
1353}
1354
1355impl From<DefiniteDescriptorKey> for DescriptorPublicKey {
1356 fn from(d: DefiniteDescriptorKey) -> Self { d.0 }
1357}
1358
1359impl Borrow<DescriptorPublicKey> for DefiniteDescriptorKey {
1360 fn borrow(&self) -> &DescriptorPublicKey { &self.0 }
1361}
1362
1363#[cfg(feature = "serde")]
1364impl<'de> Deserialize<'de> for DescriptorPublicKey {
1365 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1366 where
1367 D: Deserializer<'de>,
1368 {
1369 let s = String::deserialize(deserializer)?;
1370 DescriptorPublicKey::from_str(&s).map_err(crate::serde::de::Error::custom)
1371 }
1372}
1373
1374#[cfg(feature = "serde")]
1375impl Serialize for DescriptorPublicKey {
1376 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1377 where
1378 S: Serializer,
1379 {
1380 serializer.serialize_str(&self.to_string())
1381 }
1382}
1383
1384#[cfg(test)]
1385mod test {
1386 use core::str::FromStr;
1387
1388 use bitcoin::bip32;
1389 #[cfg(feature = "serde")]
1390 use serde_test::{assert_tokens, Token};
1391
1392 use super::{
1393 DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey, MiniscriptKey, Wildcard,
1394 };
1395 use crate::descriptor::key::NonDefiniteKeyError;
1396 use crate::prelude::*;
1397 use crate::DefiniteDescriptorKey;
1398
1399 #[test]
1400 fn parse_descriptor_key_errors() {
1401 let desc = "[78412e3a/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*/44";
1403 assert_eq!(
1404 DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1405 "\'*\' may only appear as last element in a derivation path"
1406 );
1407
1408 let desc = "[NonHexor]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*";
1410 assert_eq!(
1411 DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1412 "on master fingerprint 'NonHexor': failed to parse hex digit"
1413 );
1414
1415 let desc = "[78412e3a]xpub1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaLcgJvLJuZZvRcEL/1/*";
1417 assert_eq!(
1418 DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1419 "base58 encoding error"
1420 );
1421
1422 let desc = "[78412e3a]0208a117f3897c3a13c9384b8695eed98dc31bc2500feb19a1af424cd47a5d83/1/*";
1424 assert_eq!(
1425 DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1426 "public keys must be 64, 66 or 130 characters in size",
1427 );
1428
1429 let desc = "[78412e3a]]03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8";
1431 assert_eq!(
1432 DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1433 "multiple \']\' in Descriptor Public Key"
1434 );
1435
1436 let desc = "[11111f11]033333333333333333333333333333323333333333333333333333333433333333]]333]]3]]101333333333333433333]]]10]333333mmmm";
1438 assert_eq!(
1439 DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1440 "multiple \']\' in Descriptor Public Key"
1441 );
1442
1443 let desc = "0777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777";
1445 assert_eq!(
1446 DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1447 "only full public keys with prefixes '02', '03' or '04' are allowed"
1448 );
1449 }
1450
1451 #[test]
1452 fn parse_descriptor_secret_key_error() {
1453 let secret_key = "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL";
1455 assert_eq!(
1456 DescriptorSecretKey::from_str(secret_key)
1457 .unwrap_err()
1458 .to_string(),
1459 "unknown version magic bytes: [4, 136, 178, 30]"
1460 );
1461
1462 let desc = "[NonHexor]tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/*";
1464 assert_eq!(
1465 DescriptorSecretKey::from_str(desc).unwrap_err().to_string(),
1466 "on master fingerprint 'NonHexor': failed to parse hex digit"
1467 );
1468
1469 let desc = "[78412e3a]L32jTfVLei6BYTPUpwpJSkrHx8iL9GZzeErVS8y4Y/1/*";
1471 assert_eq!(DescriptorSecretKey::from_str(desc).unwrap_err().to_string(), "invalid base58");
1472 }
1473
1474 #[test]
1475 fn test_wildcard() {
1476 let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2").unwrap();
1477 assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
1478 assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'/2");
1479 assert!(!public_key.has_wildcard());
1480
1481 let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*").unwrap();
1482 assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
1483 assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'");
1484 assert!(public_key.has_wildcard());
1485
1486 let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*h").unwrap();
1487 assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
1488 assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'");
1489 assert!(public_key.has_wildcard());
1490 }
1491
1492 #[test]
1493 fn test_deriv_on_xprv() {
1494 let secp = secp256k1::Secp256k1::signing_only();
1495
1496 let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2").unwrap();
1497 let public_key = secret_key.to_public(&secp).unwrap();
1498 assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2");
1499 assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d");
1500 assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'/2");
1501 assert!(!public_key.has_wildcard());
1502
1503 let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2'").unwrap();
1504 let public_key = secret_key.to_public(&secp).unwrap();
1505 assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1'/2']tpubDDPuH46rv4dbFtmF6FrEtJEy1CvLZonyBoVxF6xsesHdYDdTBrq2mHhm8AbsPh39sUwL2nZyxd6vo4uWNTU9v4t893CwxjqPnwMoUACLvMV");
1506 assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d");
1507 assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'/2'");
1508
1509 let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0/1/2").unwrap();
1510 let public_key = secret_key.to_public(&secp).unwrap();
1511 assert_eq!(public_key.to_string(), "tpubD6NzVbkrYhZ4WQdzxL7NmJN7b85ePo4p6RSj9QQHF7te2RR9iUeVSGgnGkoUsB9LBRosgvNbjRv9bcsJgzgBd7QKuxDm23ZewkTRzNSLEDr/0/1/2");
1512 assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d");
1513 assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0/1/2");
1514
1515 let secret_key = DescriptorSecretKey::from_str("[aabbccdd]tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0/1/2").unwrap();
1516 let public_key = secret_key.to_public(&secp).unwrap();
1517 assert_eq!(public_key.to_string(), "[aabbccdd]tpubD6NzVbkrYhZ4WQdzxL7NmJN7b85ePo4p6RSj9QQHF7te2RR9iUeVSGgnGkoUsB9LBRosgvNbjRv9bcsJgzgBd7QKuxDm23ZewkTRzNSLEDr/0/1/2");
1518 assert_eq!(public_key.master_fingerprint().to_string(), "aabbccdd");
1519 assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0/1/2");
1520
1521 let secret_key = DescriptorSecretKey::from_str("[aabbccdd/90']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2").unwrap();
1522 let public_key = secret_key.to_public(&secp).unwrap();
1523 assert_eq!(public_key.to_string(), "[aabbccdd/90'/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2");
1524 assert_eq!(public_key.master_fingerprint().to_string(), "aabbccdd");
1525 assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "90'/0'/1'/2");
1526 }
1527
1528 #[test]
1529 fn test_master_fingerprint() {
1530 assert_eq!(
1531 DescriptorPublicKey::from_str(
1532 "02a489e0ea42b56148d212d325b7c67c6460483ff931c303ea311edfef667c8f35",
1533 )
1534 .unwrap()
1535 .master_fingerprint()
1536 .as_bytes(),
1537 b"\xb0\x59\x11\x6a"
1538 );
1539 }
1540
1541 fn get_multipath_xpub(key_str: &str, num_paths: usize) -> DescriptorMultiXKey<bip32::Xpub> {
1542 let desc_key = DescriptorPublicKey::from_str(key_str).unwrap();
1543 assert_eq!(desc_key.num_der_paths(), num_paths);
1544 match desc_key {
1545 DescriptorPublicKey::MultiXPub(xpub) => xpub,
1546 _ => unreachable!(),
1547 }
1548 }
1549
1550 fn get_multipath_xprv(key_str: &str) -> DescriptorMultiXKey<bip32::Xpriv> {
1551 let desc_key = DescriptorSecretKey::from_str(key_str).unwrap();
1552 match desc_key {
1553 DescriptorSecretKey::MultiXPrv(xprv) => xprv,
1554 _ => unreachable!(),
1555 }
1556 }
1557
1558 #[test]
1559 fn multipath_extended_keys() {
1560 let secp = secp256k1::Secp256k1::signing_only();
1561
1562 let xpub = get_multipath_xpub("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/<0;1;42;9854>", 4);
1564 assert_eq!(
1565 xpub.derivation_paths.paths(),
1566 &vec![
1567 bip32::DerivationPath::from_str("m/2/0").unwrap(),
1568 bip32::DerivationPath::from_str("m/2/1").unwrap(),
1569 bip32::DerivationPath::from_str("m/2/42").unwrap(),
1570 bip32::DerivationPath::from_str("m/2/9854").unwrap()
1571 ],
1572 );
1573 assert_eq!(
1574 xpub,
1575 get_multipath_xpub(&DescriptorPublicKey::MultiXPub(xpub.clone()).to_string(), 4)
1576 );
1577 let xpub = get_multipath_xpub("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/<0;1;9854>/0/5/10", 3);
1579 assert_eq!(
1580 xpub.derivation_paths.paths(),
1581 &vec![
1582 bip32::DerivationPath::from_str("m/2/0/0/5/10").unwrap(),
1583 bip32::DerivationPath::from_str("m/2/1/0/5/10").unwrap(),
1584 bip32::DerivationPath::from_str("m/2/9854/0/5/10").unwrap()
1585 ],
1586 );
1587 assert_eq!(
1588 xpub,
1589 get_multipath_xpub(&DescriptorPublicKey::MultiXPub(xpub.clone()).to_string(), 3)
1590 );
1591 let xpub = get_multipath_xpub("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/<0;1;9854>/3456/9876/*", 3);
1593 assert_eq!(xpub.wildcard, Wildcard::Unhardened);
1594 assert_eq!(
1595 xpub.derivation_paths.paths(),
1596 &vec![
1597 bip32::DerivationPath::from_str("m/2/0/3456/9876").unwrap(),
1598 bip32::DerivationPath::from_str("m/2/1/3456/9876").unwrap(),
1599 bip32::DerivationPath::from_str("m/2/9854/3456/9876").unwrap()
1600 ],
1601 );
1602 assert_eq!(
1603 xpub,
1604 get_multipath_xpub(&DescriptorPublicKey::MultiXPub(xpub.clone()).to_string(), 3)
1605 );
1606 let xpub = get_multipath_xpub("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/<0;1>/*", 2);
1608 assert_eq!(xpub.wildcard, Wildcard::Unhardened);
1609 assert_eq!(
1610 xpub.derivation_paths.paths(),
1611 &vec![
1612 bip32::DerivationPath::from_str("m/0").unwrap(),
1613 bip32::DerivationPath::from_str("m/1").unwrap(),
1614 ],
1615 );
1616 assert_eq!(
1617 xpub,
1618 get_multipath_xpub(&DescriptorPublicKey::MultiXPub(xpub.clone()).to_string(), 2)
1619 );
1620 let xpub = get_multipath_xpub("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/9478'/<0';1h>/8h/*'", 2);
1623 assert_eq!(xpub.wildcard, Wildcard::Hardened);
1624 assert_eq!(
1625 xpub.derivation_paths.paths(),
1626 &vec![
1627 bip32::DerivationPath::from_str("m/9478'/0'/8'").unwrap(),
1628 bip32::DerivationPath::from_str("m/9478h/1h/8h").unwrap(),
1629 ],
1630 );
1631 assert_eq!(
1632 xpub,
1633 get_multipath_xpub(&DescriptorPublicKey::MultiXPub(xpub.clone()).to_string(), 2)
1634 );
1635 let desc_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/9478'/<0';1>/8h/*'").unwrap();
1637 assert!(desc_key.full_derivation_path().is_none());
1638 assert!(desc_key.is_multipath());
1639 assert_eq!(
1641 desc_key.full_derivation_paths(),
1642 vec![
1643 bip32::DerivationPath::from_str("m/0'/1'/9478'/0'/8'").unwrap(),
1644 bip32::DerivationPath::from_str("m/0'/1'/9478'/1/8'").unwrap(),
1645 ],
1646 );
1647 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()]);
1648
1649 let xprv = get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/2/<0;1;42;9854>");
1651 assert_eq!(
1652 xprv.derivation_paths.paths(),
1653 &vec![
1654 bip32::DerivationPath::from_str("m/2/0").unwrap(),
1655 bip32::DerivationPath::from_str("m/2/1").unwrap(),
1656 bip32::DerivationPath::from_str("m/2/42").unwrap(),
1657 bip32::DerivationPath::from_str("m/2/9854").unwrap()
1658 ],
1659 );
1660 assert_eq!(
1661 xprv,
1662 get_multipath_xprv(&DescriptorSecretKey::MultiXPrv(xprv.clone()).to_string())
1663 );
1664 let xprv = get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/2/<0;1;9854>/0/5/10");
1665 assert_eq!(
1666 xprv.derivation_paths.paths(),
1667 &vec![
1668 bip32::DerivationPath::from_str("m/2/0/0/5/10").unwrap(),
1669 bip32::DerivationPath::from_str("m/2/1/0/5/10").unwrap(),
1670 bip32::DerivationPath::from_str("m/2/9854/0/5/10").unwrap()
1671 ],
1672 );
1673 assert_eq!(
1674 xprv,
1675 get_multipath_xprv(&DescriptorSecretKey::MultiXPrv(xprv.clone()).to_string())
1676 );
1677 let xprv = get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/2/<0;1;9854>/3456/9876/*");
1678 assert_eq!(xprv.wildcard, Wildcard::Unhardened);
1679 assert_eq!(
1680 xprv.derivation_paths.paths(),
1681 &vec![
1682 bip32::DerivationPath::from_str("m/2/0/3456/9876").unwrap(),
1683 bip32::DerivationPath::from_str("m/2/1/3456/9876").unwrap(),
1684 bip32::DerivationPath::from_str("m/2/9854/3456/9876").unwrap()
1685 ],
1686 );
1687 assert_eq!(
1688 xprv,
1689 get_multipath_xprv(&DescriptorSecretKey::MultiXPrv(xprv.clone()).to_string())
1690 );
1691 let xprv = get_multipath_xprv("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/<0;1>/*");
1692 assert_eq!(xprv.wildcard, Wildcard::Unhardened);
1693 assert_eq!(
1694 xprv.derivation_paths.paths(),
1695 &vec![
1696 bip32::DerivationPath::from_str("m/0").unwrap(),
1697 bip32::DerivationPath::from_str("m/1").unwrap(),
1698 ],
1699 );
1700 assert_eq!(
1701 xprv,
1702 get_multipath_xprv(&DescriptorSecretKey::MultiXPrv(xprv.clone()).to_string())
1703 );
1704 let xprv = get_multipath_xprv("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/<0';1h>/8h/*'");
1705 assert_eq!(xprv.wildcard, Wildcard::Hardened);
1706 assert_eq!(
1707 xprv.derivation_paths.paths(),
1708 &vec![
1709 bip32::DerivationPath::from_str("m/9478'/0'/8'").unwrap(),
1710 bip32::DerivationPath::from_str("m/9478h/1h/8h").unwrap(),
1711 ],
1712 );
1713 assert_eq!(
1714 xprv,
1715 get_multipath_xprv(&DescriptorSecretKey::MultiXPrv(xprv.clone()).to_string())
1716 );
1717 let desc_key = DescriptorSecretKey::from_str("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/<0';1>/8h/*'").unwrap();
1718 assert!(desc_key.to_public(&secp).is_err());
1719 assert!(desc_key.is_multipath());
1720 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()]);
1721
1722 DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/<0;1;42;9854").unwrap_err();
1727 DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/0;1;42;9854>").unwrap_err();
1728 DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/4/<0;1>/96/<0;1>").unwrap_err();
1729 DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/4/<0>").unwrap_err();
1730 DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/4/<0;>").unwrap_err();
1731 DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/4/<;1>").unwrap_err();
1732 DescriptorPublicKey::from_str("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/4/<0;1;>").unwrap_err();
1733 }
1734
1735 #[test]
1736 fn test_multixprv_to_public() {
1737 let secp = secp256k1::Secp256k1::signing_only();
1738
1739 let xprv = get_multipath_xprv("[01020304/5]tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1'/2'/3/<4;5>/6");
1741 let xpub = DescriptorPublicKey::MultiXPub(xprv.to_public(&secp).unwrap()); assert_eq!(xpub.to_string(), "[01020304/5/1'/2']tpubDBTRkEMEFkUbk3WTz6CFSULyswkTPpPr38AWibf5TVkB5GxuBxbSbmdFGr3jmswwemknyYxAGoX7BJnKfyPy4WXaHmcrxZhfzFwoUFvFtm5/3/<4;5>/6");
1743
1744 get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/2/<3';4'>/5").to_public(&secp).unwrap_err();
1746 get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/2/<3;4>/5/6'").to_public(&secp).unwrap_err();
1747 }
1748
1749 #[test]
1750 fn test_parse_wif() {
1751 let secret_key = "[0dd03d09/0'/1/2']5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ"
1752 .parse()
1753 .unwrap();
1754 if let DescriptorSecretKey::Single(single) = secret_key {
1755 assert_eq!(
1756 single.key.inner,
1757 "0C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D"
1758 .parse()
1759 .unwrap()
1760 );
1761 assert_eq!(
1762 single.origin,
1763 Some(("0dd03d09".parse().unwrap(), "m/0'/1/2'".parse().unwrap()))
1764 );
1765 } else {
1766 panic!("expected a DescriptorSecretKey::Single");
1767 }
1768 }
1769
1770 #[test]
1771 #[cfg(feature = "serde")]
1772 fn test_descriptor_public_key_serde() {
1773 let desc = "[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2";
1774 let public_key = DescriptorPublicKey::from_str(desc).unwrap();
1775 assert_tokens(&public_key, &[Token::String(desc)]);
1776 }
1777
1778 #[test]
1779 fn definite_keys() {
1780 let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
1782 .parse::<DescriptorPublicKey>()
1783 .unwrap();
1784 assert!(matches!(DefiniteDescriptorKey::new(desc), Ok(..)));
1785 let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/*"
1787 .parse::<DescriptorPublicKey>()
1788 .unwrap();
1789 assert!(matches!(DefiniteDescriptorKey::new(desc), Err(NonDefiniteKeyError::Wildcard)));
1790 let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/<0;1>"
1792 .parse::<DescriptorPublicKey>()
1793 .unwrap();
1794 assert!(matches!(DefiniteDescriptorKey::new(desc), Err(NonDefiniteKeyError::Multipath)));
1795 let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/1'/2"
1797 .parse::<DescriptorPublicKey>()
1798 .unwrap();
1799 assert!(matches!(
1800 DefiniteDescriptorKey::new(desc),
1801 Err(NonDefiniteKeyError::HardenedStep)
1802 ));
1803 }
1804
1805 #[test]
1806 fn test_xkey_network() {
1807 use bitcoin::NetworkKind;
1808
1809 let mainnet_xpub = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
1811 .parse::<DescriptorPublicKey>()
1812 .unwrap();
1813 assert_eq!(mainnet_xpub.xkey_network(), Some(NetworkKind::Main));
1814
1815 let testnet_xpub = "tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi"
1817 .parse::<DescriptorPublicKey>()
1818 .unwrap();
1819 assert_eq!(testnet_xpub.xkey_network(), Some(NetworkKind::Test));
1820
1821 let single_key = "021d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b"
1823 .parse::<DescriptorPublicKey>()
1824 .unwrap();
1825 assert_eq!(single_key.xkey_network(), None);
1826 }
1827}