Skip to content

Commit e396c80

Browse files
Use KeySource instead of definite keys in Assets
1 parent 025c72c commit e396c80

File tree

2 files changed

+49
-48
lines changed

2 files changed

+49
-48
lines changed

src/descriptor/key.rs

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -721,41 +721,6 @@ impl DescriptorPublicKey {
721721
}
722722
}
723723
}
724-
725-
/// Whether this key is the "parent" of a [`DefiniteDescriptorKey`]
726-
///
727-
/// The key is considered "parent" if it represents the non-derived version of a definite key,
728-
/// meaning it contains a wildcard where the definite key has a definite derivation number.
729-
///
730-
/// If `self` is a single key or doesn't contain any wildcards, the definite key will have to
731-
/// be exactly the same.
732-
///
733-
/// Returns the derivation path to apply to `self` to obtain the definite key.
734-
pub fn is_parent(&self, definite_key: &DefiniteDescriptorKey) -> Option<bip32::DerivationPath> {
735-
// If the key is `Single` or it's an `XPub` with no wildcard it will match the definite key
736-
// exactly, so we try this check first
737-
if self == &definite_key.0 {
738-
return Some(bip32::DerivationPath::default());
739-
}
740-
741-
match (self, &definite_key.0) {
742-
(DescriptorPublicKey::XPub(self_xkey), DescriptorPublicKey::XPub(definite_xkey))
743-
if definite_xkey.derivation_path.len() > 0 =>
744-
{
745-
let definite_path_len = definite_xkey.derivation_path.len();
746-
if self_xkey.origin == definite_xkey.origin
747-
&& self_xkey.xkey == definite_xkey.xkey
748-
&& self_xkey.derivation_path.as_ref()
749-
== &definite_xkey.derivation_path[..(definite_path_len - 1)]
750-
{
751-
Some(vec![definite_xkey.derivation_path[definite_path_len - 1]].into())
752-
} else {
753-
None
754-
}
755-
}
756-
_ => None,
757-
}
758-
}
759724
}
760725

761726
impl FromStr for DescriptorSecretKey {

src/plan.rs

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -535,8 +535,12 @@ impl TaprootAvailableLeaves {
535535
/// The Assets we can use to satisfy a particular spending path
536536
#[derive(Debug, Default)]
537537
pub struct Assets {
538-
/// Keys the user can sign for, and how
539-
pub keys: HashSet<(DescriptorPublicKey, CanSign)>,
538+
/// Keys the user can sign for, and how. A pair `(fingerprint, derivation_path)` is
539+
/// provided, meaning that the user can sign using the key with `fingerprint`,
540+
/// derived with either `derivation_path` or a derivation path that extends `derivation_path`
541+
/// by exactly one child number. For example, if the derivation path `m/0/1` is provided, the
542+
/// user can sign with either `m/0/1` or `m/0/1/*`.
543+
pub keys: HashSet<(bip32::KeySource, CanSign)>,
540544
/// Set of available sha256 preimages
541545
pub sha256_preimages: HashSet<sha256::Hash>,
542546
/// Set of available hash256 preimages
@@ -551,16 +555,44 @@ pub struct Assets {
551555
pub relative_timelock: Option<Sequence>,
552556
}
553557

558+
// Checks if the `pk` is a "direct child" of the `derivation_path` provided.
559+
// Direct child means that the key derivation path is either the same as the
560+
// `derivation_path`, or the same extened by exactly one child number.
561+
// For example, `pk/0/1/2` is a direct child of `m/0/1` and of `m/0/1/2`,
562+
// but not of `m/0`.
563+
fn is_key_direct_child_of(
564+
pk: &DefiniteDescriptorKey,
565+
derivation_path: &bip32::DerivationPath,
566+
) -> bool {
567+
for pk_derivation_path in pk.full_derivation_paths() {
568+
if &pk_derivation_path == derivation_path {
569+
return true;
570+
}
571+
572+
let definite_path_len = pk_derivation_path.len();
573+
if derivation_path.as_ref() == &pk_derivation_path[..(definite_path_len - 1)] {
574+
return true;
575+
}
576+
}
577+
578+
false
579+
}
580+
554581
impl Assets {
555582
pub(crate) fn has_ecdsa_key(&self, pk: &DefiniteDescriptorKey) -> bool {
556-
self.keys
557-
.iter()
558-
.any(|(key, can_sign)| can_sign.ecdsa && key.is_parent(pk).is_some())
583+
self.keys.iter().any(|(keysource, can_sign)| {
584+
can_sign.ecdsa
585+
&& pk.master_fingerprint() == keysource.0
586+
&& is_key_direct_child_of(pk, &keysource.1)
587+
})
559588
}
560589

561590
pub(crate) fn has_taproot_internal_key(&self, pk: &DefiniteDescriptorKey) -> Option<usize> {
562-
self.keys.iter().find_map(|(key, can_sign)| {
563-
if !can_sign.taproot.key_spend || !key.is_parent(pk).is_some() {
591+
self.keys.iter().find_map(|(keysource, can_sign)| {
592+
if !can_sign.taproot.key_spend
593+
|| pk.master_fingerprint() != keysource.0
594+
|| !is_key_direct_child_of(pk, &keysource.1)
595+
{
564596
None
565597
} else {
566598
Some(can_sign.taproot.sig_len())
@@ -573,9 +605,10 @@ impl Assets {
573605
pk: &DefiniteDescriptorKey,
574606
tap_leaf_hash: &TapLeafHash,
575607
) -> Option<usize> {
576-
self.keys.iter().find_map(|(key, can_sign)| {
608+
self.keys.iter().find_map(|(keysource, can_sign)| {
577609
if !can_sign.taproot.script_spend.is_available(tap_leaf_hash)
578-
|| !key.is_parent(pk).is_some()
610+
|| pk.master_fingerprint() != keysource.0
611+
|| !is_key_direct_child_of(pk, &keysource.1)
579612
{
580613
None
581614
} else {
@@ -640,11 +673,14 @@ impl AssetProvider<DefiniteDescriptorKey> for Assets {
640673

641674
impl FromIterator<DescriptorPublicKey> for Assets {
642675
fn from_iter<I: IntoIterator<Item = DescriptorPublicKey>>(iter: I) -> Self {
676+
let mut keys = HashSet::new();
677+
for pk in iter {
678+
for deriv_path in pk.full_derivation_paths() {
679+
keys.insert(((pk.master_fingerprint(), deriv_path), CanSign::default()));
680+
}
681+
}
643682
Assets {
644-
keys: iter
645-
.into_iter()
646-
.map(|pk| (pk, CanSign::default()))
647-
.collect(),
683+
keys,
648684
..Default::default()
649685
}
650686
}

0 commit comments

Comments
 (0)