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