Skip to content

Commit 63ebd13

Browse files
committed
fix: allow parsing Descriptor<DescriptorPublicKey> from pk with xprv
Refactor and fix FromStr for DescriptorPublicKey so that it can parse a xprv/tprv by doing the conversion into the DescriptorPublicKey. Added test that reflects what was reported in the issues: bitcoinfuzz/bitcoinfuzz#70 #785
1 parent a19d92c commit 63ebd13

1 file changed

Lines changed: 56 additions & 40 deletions

File tree

src/descriptor/key.rs

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -735,50 +735,57 @@ impl FromStr for DescriptorPublicKey {
735735

736736
let (key_part, origin) = parse_key_origin(s)?;
737737

738-
if key_part.contains("pub") {
739-
let (xpub, derivation_paths, wildcard) = parse_xkey_deriv(key_part)?;
740-
if derivation_paths.len() > 1 {
741-
Ok(DescriptorPublicKey::MultiXPub(DescriptorMultiXKey {
742-
origin,
743-
xkey: xpub,
744-
derivation_paths: DerivPaths::new(derivation_paths).expect("Not empty"),
745-
wildcard,
746-
}))
747-
} else {
748-
Ok(DescriptorPublicKey::XPub(DescriptorXKey {
749-
origin,
750-
xkey: xpub,
751-
derivation_path: derivation_paths.into_iter().next().unwrap_or_default(),
752-
wildcard,
753-
}))
738+
match key_part.get(..4) {
739+
Some("xprv" | "tprv") => {
740+
let prv = DescriptorSecretKey::from_str(s)?;
741+
prv.to_public(&Secp256k1::signing_only())
754742
}
755-
} else {
756-
let key = match key_part.len() {
757-
64 => {
758-
let x_only_key = XOnlyPublicKey::from_str(key_part)
759-
.map_err(DescriptorKeyParseError::XonlyPublicKey)?;
760-
SinglePubKey::XOnly(x_only_key)
743+
Some("xpub" | "tpub") => {
744+
let (xpub, derivation_paths, wildcard) = parse_xkey_deriv(key_part)?;
745+
if derivation_paths.len() > 1 {
746+
Ok(DescriptorPublicKey::MultiXPub(DescriptorMultiXKey {
747+
origin,
748+
xkey: xpub,
749+
derivation_paths: DerivPaths::new(derivation_paths).expect("Not empty"),
750+
wildcard,
751+
}))
752+
} else {
753+
Ok(DescriptorPublicKey::XPub(DescriptorXKey {
754+
origin,
755+
xkey: xpub,
756+
derivation_path: derivation_paths.into_iter().next().unwrap_or_default(),
757+
wildcard,
758+
}))
761759
}
762-
66 | 130 => {
763-
if !(&key_part[0..2] == "02"
764-
|| &key_part[0..2] == "03"
765-
|| &key_part[0..2] == "04")
766-
{
760+
}
761+
_ => {
762+
let key = match key_part.len() {
763+
64 => {
764+
let x_only_key = XOnlyPublicKey::from_str(key_part)
765+
.map_err(DescriptorKeyParseError::XonlyPublicKey)?;
766+
SinglePubKey::XOnly(x_only_key)
767+
}
768+
66 | 130 => {
769+
if !(&key_part[0..2] == "02"
770+
|| &key_part[0..2] == "03"
771+
|| &key_part[0..2] == "04")
772+
{
773+
return Err(DescriptorKeyParseError::MalformedKeyData(
774+
MalformedKeyDataKind::InvalidFullPublicKeyPrefix,
775+
));
776+
}
777+
let key = bitcoin::PublicKey::from_str(key_part)
778+
.map_err(DescriptorKeyParseError::FullPublicKey)?;
779+
SinglePubKey::FullKey(key)
780+
}
781+
_ => {
767782
return Err(DescriptorKeyParseError::MalformedKeyData(
768-
MalformedKeyDataKind::InvalidFullPublicKeyPrefix,
769-
));
783+
MalformedKeyDataKind::InvalidPublicKeyLength,
784+
))
770785
}
771-
let key = bitcoin::PublicKey::from_str(key_part)
772-
.map_err(DescriptorKeyParseError::FullPublicKey)?;
773-
SinglePubKey::FullKey(key)
774-
}
775-
_ => {
776-
return Err(DescriptorKeyParseError::MalformedKeyData(
777-
MalformedKeyDataKind::InvalidPublicKeyLength,
778-
))
779-
}
780-
};
781-
Ok(DescriptorPublicKey::Single(SinglePub { key, origin }))
786+
};
787+
Ok(DescriptorPublicKey::Single(SinglePub { key, origin }))
788+
}
782789
}
783790
}
784791
}
@@ -1952,4 +1959,13 @@ mod test {
19521959
.unwrap();
19531960
assert_eq!(single_key.xkey_network(), None);
19541961
}
1962+
1963+
// https://github.com/bitcoinfuzz/bitcoinfuzz/issues/70
1964+
// https://github.com/rust-bitcoin/rust-miniscript/issues/785
1965+
#[test]
1966+
fn can_parse_pk_from_xprv() {
1967+
assert!("pk(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/*)".parse::<crate::Descriptor::<DescriptorPublicKey>>().is_ok());
1968+
// xprv containing "pub"
1969+
assert!("pk(xprv9s21ZrQH143K3MByafknWupz9D5c3Wz3MrAZpC5KFxUuwwbefg6BVSWFwyUbEcqxGTpubCGtQyC3m3vm8rZkmN1TNoc7n6VdZBt5NeXdxwV/*)".parse::<crate::Descriptor::<DescriptorPublicKey>>().is_ok());
1970+
}
19551971
}

0 commit comments

Comments
 (0)