Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increase terseness in descriptor module #376

Merged
merged 4 commits into from
Apr 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 16 additions & 18 deletions integration_test/src/test_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@ extern crate rand;

use self::rand::RngCore;
use bitcoin::hashes::{hex::ToHex, Hash};
use miniscript::{
descriptor::{DescriptorSinglePub, SinglePubKey},
Descriptor, DescriptorPublicKey, Miniscript, ScriptContext, TranslatePk,
};
use miniscript::descriptor::{SinglePub, SinglePubKey};
use miniscript::{Descriptor, DescriptorPublicKey, Miniscript, ScriptContext, TranslatePk};
use std::str::FromStr;

use bitcoin;
Expand Down Expand Up @@ -163,24 +161,24 @@ pub fn parse_insane_ms<Ctx: ScriptContext>(
if avail {
i = i + 1;
if pk_str.starts_with("K") {
DescriptorPublicKey::SinglePub(DescriptorSinglePub {
DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(pubdata.pks[i]),
})
} else if pk_str.starts_with("X") {
DescriptorPublicKey::SinglePub(DescriptorSinglePub {
DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::XOnly(pubdata.x_only_pks[i]),
})
} else {
// Parse any other keys as known to allow compatibility with existing tests
DescriptorPublicKey::SinglePub(DescriptorSinglePub {
DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(pubdata.pks[i]),
})
}
} else {
DescriptorPublicKey::SinglePub(DescriptorSinglePub {
DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(random_pk(59)),
})
Expand All @@ -191,24 +189,24 @@ pub fn parse_insane_ms<Ctx: ScriptContext>(
if avail {
j = j - 1;
if pk_str.starts_with("K") {
DescriptorPublicKey::SinglePub(DescriptorSinglePub {
DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(pubdata.pks[j]),
})
} else if pk_str.starts_with("X") {
DescriptorPublicKey::SinglePub(DescriptorSinglePub {
DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::XOnly(pubdata.x_only_pks[j]),
})
} else {
// Parse any other keys as known to allow compatibility with existing tests
DescriptorPublicKey::SinglePub(DescriptorSinglePub {
DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(pubdata.pks[j]),
})
}
} else {
DescriptorPublicKey::SinglePub(DescriptorSinglePub {
DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(random_pk(59)),
})
Expand All @@ -230,20 +228,20 @@ pub fn parse_test_desc(desc: &str, pubdata: &PubData) -> Descriptor<DescriptorPu
if avail {
i = i + 1;
if pk_str.starts_with("K") {
Ok(DescriptorPublicKey::SinglePub(DescriptorSinglePub {
Ok(DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(pubdata.pks[i]),
}))
} else if pk_str.starts_with("X") {
Ok(DescriptorPublicKey::SinglePub(DescriptorSinglePub {
Ok(DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::XOnly(pubdata.x_only_pks[i]),
}))
} else {
panic!("Key must start with either K or X")
}
} else {
Ok(DescriptorPublicKey::SinglePub(DescriptorSinglePub {
Ok(DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(random_pk(59)),
}))
Expand All @@ -254,20 +252,20 @@ pub fn parse_test_desc(desc: &str, pubdata: &PubData) -> Descriptor<DescriptorPu
if avail {
j = j - 1;
if pkh_str.starts_with("K") {
Ok(DescriptorPublicKey::SinglePub(DescriptorSinglePub {
Ok(DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(pubdata.pks[j]),
}))
} else if pkh_str.starts_with("X") {
Ok(DescriptorPublicKey::SinglePub(DescriptorSinglePub {
Ok(DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::XOnly(pubdata.x_only_pks[j]),
}))
} else {
panic!("Key must start with either K or X")
}
} else {
Ok(DescriptorPublicKey::SinglePub(DescriptorSinglePub {
Ok(DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(random_pk(61)),
}))
Expand Down
120 changes: 58 additions & 62 deletions src/descriptor/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,56 +12,68 @@ use bitcoin::{

use {MiniscriptKey, ToPublicKey};

/// Single public key without any origin or range information
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
pub enum SinglePubKey {
/// FullKey (compressed or uncompressed)
FullKey(bitcoin::PublicKey),
/// XOnlyPublicKey
XOnly(XOnlyPublicKey),
}

/// The MiniscriptKey corresponding to Descriptors. This can
/// either be Single public key or a Xpub
/// The descriptor pubkey, either a single pubkey or an xpub.
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
pub enum DescriptorPublicKey {
/// Single Public Key
SinglePub(DescriptorSinglePub),
/// Xpub
/// Single public key.
Single(SinglePub),
/// Extended public key (xpub).
XPub(DescriptorXKey<bip32::ExtendedPubKey>),
}

/// A Single Descriptor Key with optional origin information
/// The descriptor secret key, either a single private key or an xprv.
#[derive(Debug)]
pub enum DescriptorSecretKey {
/// Single private key.
Single(SinglePriv),
/// Extended private key (xpriv).
XPrv(DescriptorXKey<bip32::ExtendedPrivKey>),
}

/// A descriptor [`SinglePubKey`] with optional origin information.
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
pub struct DescriptorSinglePub {
/// Origin information
pub struct SinglePub {
/// Origin information (fingerprint and derivation path).
pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
/// The key
/// The public key.
pub key: SinglePubKey,
}

/// A Single Descriptor Secret Key with optional origin information
/// A descriptor [`bitcoin::PrivateKey`] with optional origin information.
#[derive(Debug)]
pub struct DescriptorSinglePriv {
/// Origin information
pub origin: Option<bip32::KeySource>,
/// The key
pub struct SinglePriv {
/// Origin information (fingerprint and derivation path).
pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
/// The private key.
pub key: bitcoin::PrivateKey,
}

/// A Secret Key that can be either a single key or an Xprv
#[derive(Debug)]
pub enum DescriptorSecretKey {
/// Single Secret Key
SinglePriv(DescriptorSinglePriv),
/// Xprv
XPrv(DescriptorXKey<bip32::ExtendedPrivKey>),
/// An extended key with origin, derivation path, and wildcard.
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
pub struct DescriptorXKey<K: InnerXKey> {
/// Origin information
pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
/// The extended key
pub xkey: K,
/// The derivation path
pub derivation_path: bip32::DerivationPath,
/// Whether the descriptor is wildcard
pub wildcard: Wildcard,
}

/// Single public key without any origin or range information.
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
pub enum SinglePubKey {
/// A bitcoin public key (compressed or uncompressed).
FullKey(bitcoin::PublicKey),
/// An xonly public key.
XOnly(XOnlyPublicKey),
}

impl fmt::Display for DescriptorSecretKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&DescriptorSecretKey::SinglePriv(ref sk) => {
&DescriptorSecretKey::Single(ref sk) => {
maybe_fmt_master_id(f, &sk.origin)?;
sk.key.fmt(f)?;
Ok(())
Expand Down Expand Up @@ -124,28 +136,15 @@ pub enum Wildcard {
Hardened,
}

/// Instance of an extended key with origin and derivation path
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
pub struct DescriptorXKey<K: InnerXKey> {
/// Origin information
pub origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
/// The extended key
pub xkey: K,
/// The derivation path
pub derivation_path: bip32::DerivationPath,
/// Whether the descriptor is wildcard
pub wildcard: Wildcard,
}

impl DescriptorSinglePriv {
impl SinglePriv {
/// Returns the public key of this key
fn as_public<C: Signing>(
&self,
secp: &Secp256k1<C>,
) -> Result<DescriptorSinglePub, DescriptorKeyParseError> {
) -> Result<SinglePub, DescriptorKeyParseError> {
let pub_key = self.key.public_key(secp);

Ok(DescriptorSinglePub {
Ok(SinglePub {
origin: self.origin.clone(),
key: SinglePubKey::FullKey(pub_key),
})
Expand Down Expand Up @@ -219,7 +218,7 @@ impl error::Error for DescriptorKeyParseError {}
impl fmt::Display for DescriptorPublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
DescriptorPublicKey::SinglePub(ref pk) => {
DescriptorPublicKey::Single(ref pk) => {
maybe_fmt_master_id(f, &pk.origin)?;
match pk.key {
SinglePubKey::FullKey(full_key) => full_key.fmt(f),
Expand All @@ -244,7 +243,7 @@ impl fmt::Display for DescriptorPublicKey {

impl DescriptorSecretKey {
/// Return the public version of this key, by applying either
/// [`DescriptorSinglePriv::as_public`] or [`DescriptorXKey<bip32::ExtendedPrivKey>::as_public`]
/// [`SinglePriv::as_public`] or [`DescriptorXKey<bip32::ExtendedPrivKey>::as_public`]
/// depending on the type of key.
///
/// If the key is an "XPrv", the hardened derivation steps will be applied before converting it
Expand All @@ -255,8 +254,8 @@ impl DescriptorSecretKey {
secp: &Secp256k1<C>,
) -> Result<DescriptorPublicKey, DescriptorKeyParseError> {
Ok(match self {
&DescriptorSecretKey::SinglePriv(ref sk) => {
DescriptorPublicKey::SinglePub(sk.as_public(secp)?)
&DescriptorSecretKey::Single(ref sk) => {
DescriptorPublicKey::Single(sk.as_public(secp)?)
}
&DescriptorSecretKey::XPrv(ref xprv) => {
DescriptorPublicKey::XPub(xprv.as_public(secp)?)
Expand Down Expand Up @@ -341,10 +340,7 @@ impl FromStr for DescriptorPublicKey {
))
}
};
Ok(DescriptorPublicKey::SinglePub(DescriptorSinglePub {
key,
origin,
}))
Ok(DescriptorPublicKey::Single(SinglePub { key, origin }))
}
}
}
Expand Down Expand Up @@ -385,7 +381,7 @@ impl DescriptorPublicKey {
xpub.xkey.fingerprint()
}
}
DescriptorPublicKey::SinglePub(ref single) => {
DescriptorPublicKey::Single(ref single) => {
if let Some((fingerprint, _)) = single.origin {
fingerprint
} else {
Expand Down Expand Up @@ -417,7 +413,7 @@ impl DescriptorPublicKey {
};
origin_path.extend(&xpub.derivation_path)
}
DescriptorPublicKey::SinglePub(ref single) => {
DescriptorPublicKey::Single(ref single) => {
if let Some((_, ref path)) = single.origin {
path.clone()
} else {
Expand All @@ -430,7 +426,7 @@ impl DescriptorPublicKey {
/// Whether or not the key has a wildcards
pub fn is_deriveable(&self) -> bool {
match *self {
DescriptorPublicKey::SinglePub(..) => false,
DescriptorPublicKey::Single(..) => false,
DescriptorPublicKey::XPub(ref xpub) => xpub.wildcard != Wildcard::None,
}
}
Expand Down Expand Up @@ -476,7 +472,7 @@ impl DescriptorPublicKey {
secp: &Secp256k1<C>,
) -> Result<bitcoin::PublicKey, ConversionError> {
match *self {
DescriptorPublicKey::SinglePub(ref pk) => match pk.key {
DescriptorPublicKey::Single(ref pk) => match pk.key {
SinglePubKey::FullKey(pk) => Ok(pk),
SinglePubKey::XOnly(xpk) => Ok(xpk.to_public_key()),
},
Expand Down Expand Up @@ -504,7 +500,7 @@ impl FromStr for DescriptorSecretKey {
if key_part.len() <= 52 {
let sk = bitcoin::PrivateKey::from_str(key_part)
.map_err(|_| DescriptorKeyParseError("Error while parsing a WIF private key"))?;
Ok(DescriptorSecretKey::SinglePriv(DescriptorSinglePriv {
Ok(DescriptorSecretKey::Single(SinglePriv {
key: sk,
origin: None,
}))
Expand Down Expand Up @@ -694,7 +690,7 @@ impl MiniscriptKey for DescriptorPublicKey {

fn is_uncompressed(&self) -> bool {
match self {
DescriptorPublicKey::SinglePub(DescriptorSinglePub {
DescriptorPublicKey::Single(SinglePub {
key: SinglePubKey::FullKey(ref key),
..
}) => key.is_uncompressed(),
Expand All @@ -704,7 +700,7 @@ impl MiniscriptKey for DescriptorPublicKey {

fn is_x_only_key(&self) -> bool {
match self {
DescriptorPublicKey::SinglePub(DescriptorSinglePub {
DescriptorPublicKey::Single(SinglePub {
key: SinglePubKey::XOnly(ref _key),
..
}) => true,
Expand Down
Loading