Skip to content

Commit

Permalink
Extract FromStr functionality for DescriptorInnerKeys
Browse files Browse the repository at this point in the history
  • Loading branch information
quad committed Jul 23, 2023
1 parent 100b7d6 commit 14799e2
Showing 1 changed file with 83 additions and 48 deletions.
131 changes: 83 additions & 48 deletions src/descriptor/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,66 +447,101 @@ fn fmt_derivation_paths(f: &mut fmt::Formatter, paths: &[bip32::DerivationPath])
Ok(())
}

impl FromStr for DescriptorPublicKey {
impl FromStr for DescriptorSinglePublicKey {
type Err = DescriptorKeyParseError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let (key_part, origin) = parse_key_origin(s)?;

let key = match key_part.len() {
64 => {
let x_only_key = XOnlyPublicKey::from_str(key_part)
.map_err(|_| DescriptorKeyParseError("Error while parsing simple xonly key"))?;
SinglePubKey::XOnly(x_only_key)
}
66 | 130 => {
if !(&key_part[0..2] == "02" || &key_part[0..2] == "03" || &key_part[0..2] == "04")
{
return Err(DescriptorKeyParseError(
"Only publickeys with prefixes 02/03/04 are allowed",
));
}
let key = bitcoin::PublicKey::from_str(key_part).map_err(|_| {
DescriptorKeyParseError("Error while parsing simple public key")
})?;
SinglePubKey::FullKey(key)
}
_ => {
return Err(DescriptorKeyParseError(
"Public keys must be 64/66/130 characters in size",
))
}
};

Ok(Self { key, origin })
}
}

impl FromStr for DescriptorExtendedPublicKey {
type Err = DescriptorKeyParseError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
// A "raw" public key without any origin is the least we accept.
if s.len() < 64 {
let (key_part, origin) = parse_key_origin(s)?;

let (xpub, derivation_paths, wildcard) =
parse_xkey_deriv::<bip32::ExtendedPubKey>(key_part)?;

if derivation_paths.len() > 1 {
return Err(DescriptorKeyParseError(
"Key too short (<66 char), doesn't match any format",
"Multiple derivation paths are not allowed for single extended keys",
));
}

Ok(Self {
origin,
xkey: xpub,
derivation_path: derivation_paths.into_iter().next().unwrap_or_default(),
wildcard,
})
}
}

impl FromStr for DescriptorMultiExtendedPublicKey {
type Err = DescriptorKeyParseError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let (key_part, origin) = parse_key_origin(s)?;

if key_part.contains("pub") {
let (xpub, derivation_paths, wildcard) =
parse_xkey_deriv::<bip32::ExtendedPubKey>(key_part)?;
if derivation_paths.len() > 1 {
Ok(DescriptorPublicKey::MultiXPub(DescriptorMultiXKey {
origin,
xkey: xpub,
derivation_paths: DerivPaths::new(derivation_paths).expect("Not empty"),
wildcard,
}))
let (xpub, derivation_paths, wildcard) =
parse_xkey_deriv::<bip32::ExtendedPubKey>(key_part)?;

if derivation_paths.len() < 2 {
return Err(DescriptorKeyParseError(
"Multiple derivation paths are required for multi extended keys",
));
}

Ok(Self {
origin,
xkey: xpub,
derivation_paths: DerivPaths::new(derivation_paths).expect("Not empty"),
wildcard,
})
}
}

impl FromStr for DescriptorPublicKey {
type Err = DescriptorKeyParseError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.contains("pub") {
if s.contains("<") {
DescriptorMultiExtendedPublicKey::from_str(s).map(Self::MultiXPub)
} else {
Ok(DescriptorPublicKey::XPub(DescriptorXKey {
origin,
xkey: xpub,
derivation_path: derivation_paths.into_iter().next().unwrap_or_default(),
wildcard,
}))
DescriptorExtendedPublicKey::from_str(s).map(Self::XPub)
}
} else {
let key = match key_part.len() {
64 => {
let x_only_key = XOnlyPublicKey::from_str(key_part).map_err(|_| {
DescriptorKeyParseError("Error while parsing simple xonly key")
})?;
SinglePubKey::XOnly(x_only_key)
}
66 | 130 => {
if !(&key_part[0..2] == "02"
|| &key_part[0..2] == "03"
|| &key_part[0..2] == "04")
{
return Err(DescriptorKeyParseError(
"Only publickeys with prefixes 02/03/04 are allowed",
));
}
let key = bitcoin::PublicKey::from_str(key_part).map_err(|_| {
DescriptorKeyParseError("Error while parsing simple public key")
})?;
SinglePubKey::FullKey(key)
}
_ => {
return Err(DescriptorKeyParseError(
"Public keys must be 64/66/130 characters in size",
))
}
};
Ok(DescriptorPublicKey::Single(SinglePub { key, origin }))
DescriptorSinglePublicKey::from_str(s).map(Self::Single)
}
}
}
Expand Down

0 comments on commit 14799e2

Please sign in to comment.