@@ -70,14 +70,9 @@ pub enum SinglePubKey {
7070 XOnly(XOnlyPublicKey),
7171}
7272
73- /// A derived [`DescriptorPublicKey`]
74- ///
75- /// Derived keys are guaranteed to never contain wildcards
73+ /// A [`DescriptorPublicKey`] without any wildcards.
7674#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
77- pub struct DerivedDescriptorKey {
78- key: DescriptorPublicKey,
79- index: u32,
80- }
75+ pub struct DefiniteDescriptorKey(DescriptorPublicKey);
8176
8277impl fmt::Display for DescriptorSecretKey {
8378 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -357,22 +352,14 @@ impl FromStr for DescriptorPublicKey {
357352/// Descriptor key conversion error
358353#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
359354pub enum ConversionError {
360- /// Attempted to convert a key with a wildcard to a bitcoin public key
361- Wildcard,
362355 /// Attempted to convert a key with hardened derivations to a bitcoin public key
363356 HardenedChild,
364- /// Attempted to convert a key with a hardened wildcard to a bitcoin public key
365- HardenedWildcard,
366357}
367358
368359impl fmt::Display for ConversionError {
369360 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
370361 f.write_str(match *self {
371- ConversionError::Wildcard => "uninstantiated wildcard in bip32 path",
372362 ConversionError::HardenedChild => "hardened child step in bip32 path",
373- ConversionError::HardenedWildcard => {
374- "hardened and uninstantiated wildcard in bip32 path"
375- }
376363 })
377364 }
378365}
@@ -383,7 +370,7 @@ impl error::Error for ConversionError {
383370 use self::ConversionError::*;
384371
385372 match self {
386- Wildcard | HardenedChild | HardenedWildcard => None,
373+ HardenedChild => None,
387374 }
388375 }
389376}
@@ -441,40 +428,50 @@ impl DescriptorPublicKey {
441428 }
442429 }
443430
444- /// Whether or not the key has a wildcards
431+ /// Whether or not the key has a wildcard
432+ #[deprecated(note = "use has_wildcard instead")]
445433 pub fn is_deriveable(&self) -> bool {
434+ self.has_wildcard()
435+ }
436+
437+ /// Whether or not the key has a wildcard
438+ pub fn has_wildcard(&self) -> bool {
446439 match *self {
447440 DescriptorPublicKey::Single(..) => false,
448441 DescriptorPublicKey::XPub(ref xpub) => xpub.wildcard != Wildcard::None,
449442 }
450443 }
451444
452- /// Derives the [`DescriptorPublicKey`] at `index` if this key is an xpub and has a wildcard.
445+ #[deprecated(note = "use at_derivation_index instead")]
446+ /// Deprecated name of [`at_derivation_index`].
447+ pub fn derive(self, index: u32) -> DefiniteDescriptorKey {
448+ self.at_derivation_index(index)
449+ }
450+
451+ /// Replaces any wildcard (i.e. `/*`) in the key with a particular derivation index, turning it into a
452+ /// *definite* key (i.e. one where all the derivation paths are set).
453453 ///
454454 /// # Returns
455455 ///
456456 /// - If this key is not an xpub, returns `self`.
457457 /// - If this key is an xpub but does not have a wildcard, returns `self`.
458- /// - Otherwise, returns the derived xpub at `index` (removing the wildcard).
459- ///
460- /// Since it's guaranteed that extended keys won't have wildcards, the key is returned as
461- /// [`DerivedDescriptorKey`].
458+ /// - Otherwise, returns the xpub at derivation `index` (removing the wildcard).
462459 ///
463460 /// # Panics
464461 ///
465462 /// If `index` ≥ 2^31
466- pub fn derive (self, index: u32) -> DerivedDescriptorKey {
467- let derived = match self {
463+ pub fn at_derivation_index (self, index: u32) -> DefiniteDescriptorKey {
464+ let definite = match self {
468465 DescriptorPublicKey::Single(_) => self,
469466 DescriptorPublicKey::XPub(xpub) => {
470467 let derivation_path = match xpub.wildcard {
471468 Wildcard::None => xpub.derivation_path,
472- Wildcard::Unhardened => xpub
473- .derivation_path
474- .into_child(bip32::ChildNumber::from_normal_idx(index).unwrap() ),
475- Wildcard::Hardened => xpub
476- .derivation_path
477- .into_child(bip32::ChildNumber::from_hardened_idx(index).unwrap() ),
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+ ),
478475 };
479476 DescriptorPublicKey::XPub(DescriptorXKey {
480477 origin: xpub.origin,
@@ -485,7 +482,7 @@ impl DescriptorPublicKey {
485482 }
486483 };
487484
488- DerivedDescriptorKey ::new(derived, index )
485+ DefiniteDescriptorKey ::new(definite )
489486 .expect("The key should not contain any wildcards at this point")
490487 }
491488
@@ -494,13 +491,10 @@ impl DescriptorPublicKey {
494491 /// and returns the obtained full [`bitcoin::PublicKey`]. All BIP32 derivations
495492 /// always return a compressed key
496493 ///
497- /// Will return an error if the descriptor key has any hardened
498- /// derivation steps in its path, or if the key has any wildcards .
494+ /// Will return an error if the descriptor key has any hardened derivation steps in its path. To
495+ /// avoid this error you should replace any such public keys first with [`translate_pk`] .
499496 ///
500- /// To ensure there are no wildcards, call `.derive(0)` or similar;
501- /// to avoid hardened derivation steps, start from a `DescriptorSecretKey`
502- /// and call `to_public`, or call `TranslatePk2::translate_pk2` with
503- /// some function which has access to secret key data.
497+ /// [`translate_pk`]: crate::TranslatePk::translate_pk
504498 pub fn derive_public_key<C: Verification>(
505499 &self,
506500 secp: &Secp256k1<C>,
@@ -511,8 +505,9 @@ impl DescriptorPublicKey {
511505 SinglePubKey::XOnly(xpk) => Ok(xpk.to_public_key()),
512506 },
513507 DescriptorPublicKey::XPub(ref xpk) => match xpk.wildcard {
514- Wildcard::Unhardened => Err(ConversionError::Wildcard),
515- Wildcard::Hardened => Err(ConversionError::HardenedWildcard),
508+ Wildcard::Unhardened | Wildcard::Hardened => {
509+ unreachable!("we've excluded this error case")
510+ }
516511 Wildcard::None => match xpk.xkey.derive_pub(secp, &xpk.derivation_path.as_ref()) {
517512 Ok(xpub) => Ok(bitcoin::PublicKey::new(xpub.public_key)),
518513 Err(bip32::Error::CannotDeriveFromHardenedKey) => {
@@ -767,7 +762,7 @@ impl MiniscriptKey for DescriptorPublicKey {
767762 }
768763}
769764
770- impl DerivedDescriptorKey {
765+ impl DefiniteDescriptorKey {
771766 /// Computes the raw [`bitcoin::PublicKey`] for this descriptor key.
772767 ///
773768 /// Will return an error if the key has any hardened derivation steps
@@ -778,32 +773,51 @@ impl DerivedDescriptorKey {
778773 &self,
779774 secp: &Secp256k1<C>,
780775 ) -> Result<bitcoin::PublicKey, ConversionError> {
781- self.key.derive_public_key(secp)
782- }
783-
784- /// Return the derivation index of this key
785- pub fn index(&self) -> u32 {
786- self.index
776+ self.0.derive_public_key(secp)
787777 }
788778
789779 /// Construct an instance from a descriptor key and a derivation index
790780 ///
791781 /// Returns `None` if the key contains a wildcard
792- fn new(key: DescriptorPublicKey, index: u32) -> Option<Self> {
793- match key {
794- DescriptorPublicKey::XPub(ref xpk) if xpk.wildcard != Wildcard::None => None,
795- k => Some(DerivedDescriptorKey { key: k, index }),
782+ fn new(key: DescriptorPublicKey) -> Option<Self> {
783+ if key.has_wildcard() {
784+ None
785+ } else {
786+ Some(Self(key))
796787 }
797788 }
789+
790+ /// The fingerprint of the master key associated with this key, `0x00000000` if none.
791+ pub fn master_fingerprint(&self) -> bip32::Fingerprint {
792+ self.0.master_fingerprint()
793+ }
794+
795+ /// Full path, from the master key
796+ pub fn full_derivation_path(&self) -> bip32::DerivationPath {
797+ self.0.full_derivation_path()
798+ }
799+ }
800+
801+ impl FromStr for DefiniteDescriptorKey {
802+ type Err = DescriptorKeyParseError;
803+
804+ fn from_str(s: &str) -> Result<Self, Self::Err> {
805+ let inner = DescriptorPublicKey::from_str(s)?;
806+ Ok(
807+ DefiniteDescriptorKey::new(inner).ok_or(DescriptorKeyParseError(
808+ "cannot parse key with a wilcard as a DerivedDescriptorKey",
809+ ))?,
810+ )
811+ }
798812}
799813
800- impl fmt::Display for DerivedDescriptorKey {
814+ impl fmt::Display for DefiniteDescriptorKey {
801815 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
802- self.key .fmt(f)
816+ self.0 .fmt(f)
803817 }
804818}
805819
806- impl MiniscriptKey for DerivedDescriptorKey {
820+ impl MiniscriptKey for DefiniteDescriptorKey {
807821 // This allows us to be able to derive public keys even for PkH s
808822 type RawPkHash = Self;
809823 type Sha256 = sha256::Hash;
@@ -812,22 +826,22 @@ impl MiniscriptKey for DerivedDescriptorKey {
812826 type Hash160 = hash160::Hash;
813827
814828 fn is_uncompressed(&self) -> bool {
815- self.key .is_uncompressed()
829+ self.0 .is_uncompressed()
816830 }
817831
818832 fn is_x_only_key(&self) -> bool {
819- self.key .is_x_only_key()
833+ self.0 .is_x_only_key()
820834 }
821835
822836 fn to_pubkeyhash(&self) -> Self {
823837 self.clone()
824838 }
825839}
826840
827- impl ToPublicKey for DerivedDescriptorKey {
841+ impl ToPublicKey for DefiniteDescriptorKey {
828842 fn to_public_key(&self) -> bitcoin::PublicKey {
829843 let secp = Secp256k1::verification_only();
830- self.key .derive_public_key(&secp).unwrap()
844+ self.0 .derive_public_key(&secp).unwrap()
831845 }
832846
833847 fn hash_to_hash160(hash: &Self) -> hash160::Hash {
@@ -851,6 +865,12 @@ impl ToPublicKey for DerivedDescriptorKey {
851865 }
852866}
853867
868+ impl From<DefiniteDescriptorKey> for DescriptorPublicKey {
869+ fn from(d: DefiniteDescriptorKey) -> Self {
870+ d.0
871+ }
872+ }
873+
854874#[cfg(test)]
855875mod test {
856876 use core::str::FromStr;
@@ -957,17 +977,17 @@ mod test {
957977 let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2").unwrap();
958978 assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
959979 assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'/2");
960- assert_eq!(public_key.is_deriveable (), false);
980+ assert_eq!(public_key.has_wildcard (), false);
961981
962982 let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*").unwrap();
963983 assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
964984 assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'");
965- assert_eq!(public_key.is_deriveable (), true);
985+ assert_eq!(public_key.has_wildcard (), true);
966986
967987 let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*h").unwrap();
968988 assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
969989 assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'");
970- assert_eq!(public_key.is_deriveable (), true);
990+ assert_eq!(public_key.has_wildcard (), true);
971991 }
972992
973993 #[test]
@@ -979,7 +999,7 @@ mod test {
979999 assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2");
9801000 assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d");
9811001 assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'/2");
982- assert_eq!(public_key.is_deriveable (), false);
1002+ assert_eq!(public_key.has_wildcard (), false);
9831003
9841004 let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2'").unwrap();
9851005 let public_key = secret_key.to_public(&secp).unwrap();
0 commit comments