Skip to content

Commit ac59283

Browse files
committed
descriptor: sort out BIP341 NUMS keys
1 parent 6f80c44 commit ac59283

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed

src/descriptor.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub use mscript_12_0 as miniscript;
44
pub use mscript_12_3_5 as miniscript;
55

66
use std::collections::{BTreeSet, HashSet};
7+
use std::str::FromStr;
78

89
use miniscript::{
910
bitcoin::{self, bip32::DerivationPath, secp256k1},
@@ -33,12 +34,28 @@ fn dpk_to_deriv_path(key: &DescriptorPublicKey) -> Option<DerivationPath> {
3334
}
3435
}
3536

37+
// See
38+
// https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs:
39+
// > One example of such a point is H =
40+
// > lift_x(0x50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0) which is constructed
41+
// > by taking the hash of the standard uncompressed encoding of the secp256k1 base point G as X
42+
// > coordinate.
43+
fn bip341_nums() -> bitcoin::secp256k1::PublicKey {
44+
bitcoin::secp256k1::PublicKey::from_str(
45+
"0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0",
46+
)
47+
.expect("Valid pubkey: NUMS from BIP341")
48+
}
49+
3650
pub fn descr_to_dpks(
3751
descriptor: &Descriptor<DescriptorPublicKey>,
3852
) -> Result<Vec<DescriptorPublicKey>, Error> {
3953
let mut keys = BTreeSet::new();
4054
descriptor.for_each_key(|k| {
41-
keys.insert(k.clone());
55+
let pk = dpk_to_pk(k);
56+
if pk != bip341_nums() {
57+
keys.insert(k.clone());
58+
}
4259
true
4360
});
4461
let keys: Vec<_> = keys.into_iter().collect();
@@ -127,6 +144,24 @@ pub mod tests {
127144
assert_eq!(dpks, expected);
128145
}
129146

147+
#[test]
148+
fn test_descriptor_to_dpk_unspendable() {
149+
let descr_str = "tr(tpubD6NzVbkrYhZ4XWBqjZ7DTB4eFvi8eQZ79UvNbQFsxXiaMNaBn83jpMWTXLX2Gx6JgC5n9jWvx6vnijcAUgxXmRtFd4ntasRGNsYSCvQteSr/<0;1>/*,{and_v(v:and_v(v:pk([d4ab66f1/48'/1'/0'/2']tpubDEXYN145WM4rVKtcWpySBYiVQ229pmrnyAGJT14BBh2QJr7ABJswchDicZfFaauLyXhDad1nCoCZQEwAW87JPotP93ykC9WJvoASnBjYBxW/<2;3>/*),pk([79af2d8a/48'/1'/0'/2']tpubDEtHs6m9crfv1oeETj6EXteAtW7eoSSBVBaypEdWZt8VftbHF9R12xSZpzWGNuAofeGPL6cz48dLdCYbVioHL8ygA56yuPW76Xz5WZ3dt8o/<2;3>/*)),older(52596)),and_v(v:pk([d4ab66f1/48'/1'/0'/2']tpubDEXYN145WM4rVKtcWpySBYiVQ229pmrnyAGJT14BBh2QJr7ABJswchDicZfFaauLyXhDad1nCoCZQEwAW87JPotP93ykC9WJvoASnBjYBxW/<0;1>/*),pk([79af2d8a/48'/1'/0'/2']tpubDEtHs6m9crfv1oeETj6EXteAtW7eoSSBVBaypEdWZt8VftbHF9R12xSZpzWGNuAofeGPL6cz48dLdCYbVioHL8ygA56yuPW76Xz5WZ3dt8o/<0;1>/*))})#vudj49fm";
150+
let descriptor = Descriptor::<DescriptorPublicKey>::from_str(descr_str).unwrap();
151+
// unspendable keys must have been dropped
152+
let keys = descr_to_dpks(&descriptor).unwrap();
153+
for key in keys {
154+
let pk = dpk_to_pk(&key);
155+
assert_ne!(pk, bip341_nums());
156+
}
157+
// but the descriptor contains unspendable
158+
let contains_unspendable = descriptor.for_any_key(|k| {
159+
let pk = dpk_to_pk(k);
160+
pk == bip341_nums()
161+
});
162+
assert!(contains_unspendable);
163+
}
164+
130165
#[test]
131166
fn test_dpks_to_deriv_paths() {
132167
let dpks = vec![dpk_1(), dpk_2()];

0 commit comments

Comments
 (0)