Skip to content

Commit

Permalink
Use KeySource instead of definite keys in Assets
Browse files Browse the repository at this point in the history
  • Loading branch information
danielabrozzoni committed Aug 18, 2023
1 parent 081a07a commit ba6c8f2
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 48 deletions.
35 changes: 0 additions & 35 deletions src/descriptor/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -721,41 +721,6 @@ impl DescriptorPublicKey {
}
}
}

/// Whether this key is the "parent" of a [`DefiniteDescriptorKey`]
///
/// The key is considered "parent" if it represents the non-derived version of a definite key,
/// meaning it contains a wildcard where the definite key has a definite derivation number.
///
/// If `self` is a single key or doesn't contain any wildcards, the definite key will have to
/// be exactly the same.
///
/// Returns the derivation path to apply to `self` to obtain the definite key.
pub fn is_parent(&self, definite_key: &DefiniteDescriptorKey) -> Option<bip32::DerivationPath> {
// If the key is `Single` or it's an `XPub` with no wildcard it will match the definite key
// exactly, so we try this check first
if self == &definite_key.0 {
return Some(bip32::DerivationPath::default());
}

match (self, &definite_key.0) {
(DescriptorPublicKey::XPub(self_xkey), DescriptorPublicKey::XPub(definite_xkey))
if definite_xkey.derivation_path.len() > 0 =>
{
let definite_path_len = definite_xkey.derivation_path.len();
if self_xkey.origin == definite_xkey.origin
&& self_xkey.xkey == definite_xkey.xkey
&& self_xkey.derivation_path.as_ref()
== &definite_xkey.derivation_path[..(definite_path_len - 1)]
{
Some(vec![definite_xkey.derivation_path[definite_path_len - 1]].into())
} else {
None
}
}
_ => None,
}
}
}

impl FromStr for DescriptorSecretKey {
Expand Down
62 changes: 49 additions & 13 deletions src/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,12 @@ impl TaprootAvailableLeaves {
/// The Assets we can use to satisfy a particular spending path
#[derive(Debug, Default)]
pub struct Assets {
/// Keys the user can sign for, and how
pub keys: HashSet<(DescriptorPublicKey, CanSign)>,
/// Keys the user can sign for, and how. A pair `(fingerprint, derivation_path)` is
/// provided, meaning that the user can sign using the key with `fingerprint`,
/// derived with either `derivation_path` or a derivation path that extends `derivation_path`
/// by exactly one child number. For example, if the derivation path `m/0/1` is provided, the
/// user can sign with either `m/0/1` or `m/0/1/*`.
pub keys: HashSet<(bip32::KeySource, CanSign)>,
/// Set of available sha256 preimages
pub sha256_preimages: HashSet<sha256::Hash>,
/// Set of available hash256 preimages
Expand All @@ -550,16 +554,44 @@ pub struct Assets {
pub relative_timelock: Option<Sequence>,
}

// Checks if the `pk` is a "direct child" of the `derivation_path` provided.
// Direct child means that the key derivation path is either the same as the
// `derivation_path`, or the same extened by exactly one child number.
// For example, `pk/0/1/2` is a direct child of `m/0/1` and of `m/0/1/2`,
// but not of `m/0`.
fn is_key_direct_child_of(
pk: &DefiniteDescriptorKey,
derivation_path: &bip32::DerivationPath,
) -> bool {
for pk_derivation_path in pk.full_derivation_paths() {
if &pk_derivation_path == derivation_path {
return true;
}

let definite_path_len = pk_derivation_path.len();
if derivation_path.as_ref() == &pk_derivation_path[..(definite_path_len - 1)] {
return true;
}
}

return false;
}

impl Assets {
pub(crate) fn has_ecdsa_key(&self, pk: &DefiniteDescriptorKey) -> bool {
self.keys
.iter()
.any(|(key, can_sign)| can_sign.ecdsa && key.is_parent(pk).is_some())
self.keys.iter().any(|(keysource, can_sign)| {
can_sign.ecdsa
&& pk.master_fingerprint() == keysource.0
&& is_key_direct_child_of(pk, &keysource.1)
})
}

pub(crate) fn has_taproot_internal_key(&self, pk: &DefiniteDescriptorKey) -> Option<usize> {
self.keys.iter().find_map(|(key, can_sign)| {
if !can_sign.taproot.key_spend || !key.is_parent(pk).is_some() {
self.keys.iter().find_map(|(keysource, can_sign)| {
if !can_sign.taproot.key_spend
|| pk.master_fingerprint() != keysource.0
|| !is_key_direct_child_of(pk, &keysource.1)
{
None
} else {
Some(can_sign.taproot.sig_len())
Expand All @@ -572,9 +604,10 @@ impl Assets {
pk: &DefiniteDescriptorKey,
tap_leaf_hash: &TapLeafHash,
) -> Option<usize> {
self.keys.iter().find_map(|(key, can_sign)| {
self.keys.iter().find_map(|(keysource, can_sign)| {
if !can_sign.taproot.script_spend.is_available(tap_leaf_hash)
|| !key.is_parent(pk).is_some()
|| pk.master_fingerprint() != keysource.0
|| !is_key_direct_child_of(pk, &keysource.1)
{
None
} else {
Expand Down Expand Up @@ -639,11 +672,14 @@ impl AssetProvider<DefiniteDescriptorKey> for Assets {

impl FromIterator<DescriptorPublicKey> for Assets {
fn from_iter<I: IntoIterator<Item = DescriptorPublicKey>>(iter: I) -> Self {
let mut keys = HashSet::new();
for pk in iter {
for deriv_path in pk.full_derivation_paths() {
keys.insert(((pk.master_fingerprint(), deriv_path), CanSign::default()));
}
}
Assets {
keys: iter
.into_iter()
.map(|pk| (pk, CanSign::default()))
.collect(),
keys,
..Default::default()
}
}
Expand Down

0 comments on commit ba6c8f2

Please sign in to comment.