Skip to content

Commit a6a3b82

Browse files
author
Scott Robinson
committed
Extract specialised DescriptorPublicKey functionality into DescriptorExtendedPublicKey
1 parent a21b15f commit a6a3b82

File tree

1 file changed

+100
-56
lines changed

1 file changed

+100
-56
lines changed

src/descriptor/key.rs

+100-56
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,20 @@ impl error::Error for DescriptorKeyParseError {
285285
}
286286
}
287287

288+
impl fmt::Display for DescriptorExtendedPublicKey {
289+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290+
maybe_fmt_master_id(f, &self.origin)?;
291+
self.xkey.fmt(f)?;
292+
fmt_derivation_path(f, &self.derivation_path)?;
293+
match self.wildcard {
294+
Wildcard::None => {}
295+
Wildcard::Unhardened => write!(f, "/*")?,
296+
Wildcard::Hardened => write!(f, "/*h")?,
297+
}
298+
Ok(())
299+
}
300+
}
301+
288302
impl fmt::Display for DescriptorPublicKey {
289303
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
290304
match *self {
@@ -296,17 +310,7 @@ impl fmt::Display for DescriptorPublicKey {
296310
}?;
297311
Ok(())
298312
}
299-
DescriptorPublicKey::XPub(ref xpub) => {
300-
maybe_fmt_master_id(f, &xpub.origin)?;
301-
xpub.xkey.fmt(f)?;
302-
fmt_derivation_path(f, &xpub.derivation_path)?;
303-
match xpub.wildcard {
304-
Wildcard::None => {}
305-
Wildcard::Unhardened => write!(f, "/*")?,
306-
Wildcard::Hardened => write!(f, "/*h")?,
307-
}
308-
Ok(())
309-
}
313+
DescriptorPublicKey::XPub(ref xpub) => xpub.fmt(f),
310314
DescriptorPublicKey::MultiXPub(ref xpub) => {
311315
maybe_fmt_master_id(f, &xpub.origin)?;
312316
xpub.xkey.fmt(f)?;
@@ -527,17 +531,85 @@ impl error::Error for ConversionError {
527531
}
528532
}
529533

534+
impl DescriptorExtendedPublicKey {
535+
/// The fingerprint of the master key associated with this key, `0x00000000` if none.
536+
pub fn master_fingerprint(&self) -> bip32::Fingerprint {
537+
if let Some((fingerprint, _)) = self.origin {
538+
fingerprint
539+
} else {
540+
self.xkey.fingerprint()
541+
}
542+
}
543+
544+
/// Full path, from the master key
545+
///
546+
/// For wildcard keys this will return the path up to the wildcard, so you
547+
/// can get full paths by appending one additional derivation step, according
548+
/// to the wildcard type (hardened or normal).
549+
///
550+
/// For multipath extended keys, this returns `None`.
551+
pub fn full_derivation_path(&self) -> Option<bip32::DerivationPath> {
552+
let origin_path = if let Some((_, ref path)) = self.origin {
553+
path.clone()
554+
} else {
555+
bip32::DerivationPath::from(vec![])
556+
};
557+
Some(origin_path.extend(&self.derivation_path))
558+
}
559+
560+
/// Whether or not the key has a wildcard
561+
pub fn has_wildcard(&self) -> bool {
562+
self.wildcard != Wildcard::None
563+
}
564+
565+
/// Replaces any wildcard (i.e. `/*`) in the key with a particular derivation index, turning it into a
566+
/// *definite* key (i.e. one where all the derivation paths are set).
567+
///
568+
/// # Returns
569+
///
570+
/// - If this key is not an xpub, returns `self`.
571+
/// - If this key is an xpub but does not have a wildcard, returns `self`.
572+
/// - Otherwise, returns the xpub at derivation `index` (removing the wildcard).
573+
///
574+
/// # Errors
575+
///
576+
/// - If `index` is hardened.
577+
pub fn at_derivation_index(self, index: u32) -> Result<DefiniteDescriptorKey, ConversionError> {
578+
let derivation_path = match self.wildcard {
579+
Wildcard::None => self.derivation_path,
580+
Wildcard::Unhardened => self.derivation_path.into_child(
581+
bip32::ChildNumber::from_normal_idx(index)
582+
.ok()
583+
.ok_or(ConversionError::HardenedChild)?,
584+
),
585+
Wildcard::Hardened => self.derivation_path.into_child(
586+
bip32::ChildNumber::from_hardened_idx(index)
587+
.ok()
588+
.ok_or(ConversionError::HardenedChild)?,
589+
),
590+
};
591+
let definite = DescriptorPublicKey::XPub(DescriptorXKey {
592+
origin: self.origin,
593+
xkey: self.xkey,
594+
derivation_path,
595+
wildcard: Wildcard::None,
596+
});
597+
598+
Ok(DefiniteDescriptorKey::new(definite)
599+
.expect("The key should not contain any wildcards at this point"))
600+
}
601+
602+
/// Whether or not this key has multiple derivation paths.
603+
pub fn is_multipath(&self) -> bool {
604+
false
605+
}
606+
}
607+
530608
impl DescriptorPublicKey {
531609
/// The fingerprint of the master key associated with this key, `0x00000000` if none.
532610
pub fn master_fingerprint(&self) -> bip32::Fingerprint {
533611
match *self {
534-
DescriptorPublicKey::XPub(ref xpub) => {
535-
if let Some((fingerprint, _)) = xpub.origin {
536-
fingerprint
537-
} else {
538-
xpub.xkey.fingerprint()
539-
}
540-
}
612+
DescriptorPublicKey::XPub(ref xpub) => xpub.master_fingerprint(),
541613
DescriptorPublicKey::MultiXPub(ref xpub) => {
542614
if let Some((fingerprint, _)) = xpub.origin {
543615
fingerprint
@@ -575,14 +647,7 @@ impl DescriptorPublicKey {
575647
/// For multipath extended keys, this returns `None`.
576648
pub fn full_derivation_path(&self) -> Option<bip32::DerivationPath> {
577649
match *self {
578-
DescriptorPublicKey::XPub(ref xpub) => {
579-
let origin_path = if let Some((_, ref path)) = xpub.origin {
580-
path.clone()
581-
} else {
582-
bip32::DerivationPath::from(vec![])
583-
};
584-
Some(origin_path.extend(&xpub.derivation_path))
585-
}
650+
DescriptorPublicKey::XPub(ref xpub) => xpub.full_derivation_path(),
586651
DescriptorPublicKey::Single(ref single) => {
587652
Some(if let Some((_, ref path)) = single.origin {
588653
path.clone()
@@ -604,7 +669,7 @@ impl DescriptorPublicKey {
604669
pub fn has_wildcard(&self) -> bool {
605670
match *self {
606671
DescriptorPublicKey::Single(..) => false,
607-
DescriptorPublicKey::XPub(ref xpub) => xpub.wildcard != Wildcard::None,
672+
DescriptorPublicKey::XPub(ref xpub) => xpub.has_wildcard(),
608673
DescriptorPublicKey::MultiXPub(ref xpub) => xpub.wildcard != Wildcard::None,
609674
}
610675
}
@@ -628,40 +693,19 @@ impl DescriptorPublicKey {
628693
///
629694
/// - If `index` is hardened.
630695
pub fn at_derivation_index(self, index: u32) -> Result<DefiniteDescriptorKey, ConversionError> {
631-
let definite = match self {
632-
DescriptorPublicKey::Single(_) => self,
633-
DescriptorPublicKey::XPub(xpub) => {
634-
let derivation_path = match xpub.wildcard {
635-
Wildcard::None => xpub.derivation_path,
636-
Wildcard::Unhardened => xpub.derivation_path.into_child(
637-
bip32::ChildNumber::from_normal_idx(index)
638-
.ok()
639-
.ok_or(ConversionError::HardenedChild)?,
640-
),
641-
Wildcard::Hardened => xpub.derivation_path.into_child(
642-
bip32::ChildNumber::from_hardened_idx(index)
643-
.ok()
644-
.ok_or(ConversionError::HardenedChild)?,
645-
),
646-
};
647-
DescriptorPublicKey::XPub(DescriptorXKey {
648-
origin: xpub.origin,
649-
xkey: xpub.xkey,
650-
derivation_path,
651-
wildcard: Wildcard::None,
652-
})
653-
}
654-
DescriptorPublicKey::MultiXPub(_) => return Err(ConversionError::MultiKey),
655-
};
656-
657-
Ok(DefiniteDescriptorKey::new(definite)
658-
.expect("The key should not contain any wildcards at this point"))
696+
match self {
697+
DescriptorPublicKey::Single(_) => Ok(DefiniteDescriptorKey::new(self)
698+
.expect("The key should not contain any wildcards at this point")),
699+
DescriptorPublicKey::XPub(xpub) => xpub.at_derivation_index(index),
700+
DescriptorPublicKey::MultiXPub(_) => Err(ConversionError::MultiKey),
701+
}
659702
}
660703

661704
/// Whether or not this key has multiple derivation paths.
662705
pub fn is_multipath(&self) -> bool {
663706
match *self {
664-
DescriptorPublicKey::Single(..) | DescriptorPublicKey::XPub(..) => false,
707+
DescriptorPublicKey::Single(..) => false,
708+
DescriptorPublicKey::XPub(..) => self.is_multipath(),
665709
DescriptorPublicKey::MultiXPub(_) => true,
666710
}
667711
}

0 commit comments

Comments
 (0)