Skip to content

Commit 297c954

Browse files
committed
Add KeyExpr inside Taproot descriptor
1 parent ef43456 commit 297c954

File tree

9 files changed

+61
-32
lines changed

9 files changed

+61
-32
lines changed

examples/taproot.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ fn main() {
7575
if let Descriptor::Tr(ref p) = desc {
7676
// Check if internal key is correctly inferred as Ca
7777
// assert_eq!(p.internal_key(), &pubkeys[2]);
78-
assert_eq!(p.internal_key(), "Ca");
78+
assert_eq!(p.internal_key().single_key().unwrap(), "Ca");
7979

8080
// Iterate through scripts
8181
let mut iter = p.iter_scripts();

src/descriptor/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
271271

272272
/// Create new tr descriptor
273273
/// Errors when miniscript exceeds resource limits under Tap context
274-
pub fn new_tr(key: Pk, script: Option<tr::TapTree<Pk>>) -> Result<Self, Error> {
274+
pub fn new_tr(key: KeyExpr<Pk>, script: Option<tr::TapTree<Pk>>) -> Result<Self, Error> {
275275
Ok(Descriptor::Tr(Tr::new(key, script)?))
276276
}
277277

src/descriptor/tr.rs

+16-15
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use sync::Arc;
1313

1414
use super::checksum::{desc_checksum, verify_checksum};
1515
use crate::expression::{self, FromTree};
16+
use crate::miniscript::musig_key::KeyExpr;
1617
use crate::miniscript::Miniscript;
1718
use crate::policy::semantic::Policy;
1819
use crate::policy::Liftable;
@@ -39,7 +40,7 @@ pub enum TapTree<Pk: MiniscriptKey> {
3940
/// A taproot descriptor
4041
pub struct Tr<Pk: MiniscriptKey> {
4142
/// A taproot internal key
42-
internal_key: Pk,
43+
internal_key: KeyExpr<Pk>,
4344
/// Optional Taproot Tree with spending conditions
4445
tree: Option<TapTree<Pk>>,
4546
/// Optional spending information associated with the descriptor
@@ -163,9 +164,8 @@ impl<Pk: MiniscriptKey> fmt::Debug for TapTree<Pk> {
163164

164165
impl<Pk: MiniscriptKey> Tr<Pk> {
165166
/// Create a new [`Tr`] descriptor from internal key and [`TapTree`]
166-
pub fn new(internal_key: Pk, tree: Option<TapTree<Pk>>) -> Result<Self, Error> {
167+
pub fn new(internal_key: KeyExpr<Pk>, tree: Option<TapTree<Pk>>) -> Result<Self, Error> {
167168
let nodes = tree.as_ref().map(|t| t.taptree_height()).unwrap_or(0);
168-
169169
if nodes <= TAPROOT_CONTROL_MAX_NODE_COUNT {
170170
Ok(Self {
171171
internal_key,
@@ -186,7 +186,7 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
186186
}
187187

188188
/// Obtain the internal key of [`Tr`] descriptor
189-
pub fn internal_key(&self) -> &Pk {
189+
pub fn internal_key(&self) -> &KeyExpr<Pk> {
190190
&self.internal_key
191191
}
192192

@@ -226,7 +226,7 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
226226
let secp = secp256k1::Secp256k1::verification_only();
227227
// Key spend path with no merkle root
228228
let data = if self.tree.is_none() {
229-
TaprootSpendInfo::new_key_spend(&secp, self.internal_key.to_x_only_pubkey(), None)
229+
TaprootSpendInfo::new_key_spend(&secp, self.internal_key.key_agg(), None)
230230
} else {
231231
let mut builder = TaprootBuilder::new();
232232
for (depth, ms) in self.iter_scripts() {
@@ -236,7 +236,7 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
236236
.expect("Computing spend data on a valid Tree should always succeed");
237237
}
238238
// Assert builder cannot error here because we have a well formed descriptor
239-
match builder.finalize(&secp, self.internal_key.to_x_only_pubkey()) {
239+
match builder.finalize(&secp, self.internal_key.key_agg()) {
240240
Ok(data) => data,
241241
Err(e) => match e {
242242
TaprootBuilderError::InvalidMerkleTreeDepth(_) => {
@@ -419,7 +419,7 @@ impl_from_tree!(
419419
key.args.len()
420420
)));
421421
}
422-
Tr::new(expression::terminal(key, Pk::from_str)?, None)
422+
Tr::new(expression::terminal(key, KeyExpr::<Pk>::from_str)?, None)
423423
}
424424
2 => {
425425
let key = &top.args[0];
@@ -431,7 +431,10 @@ impl_from_tree!(
431431
}
432432
let tree = &top.args[1];
433433
let ret = Self::parse_tr_script_spend(tree)?;
434-
Tr::new(expression::terminal(key, Pk::from_str)?, Some(ret))
434+
Tr::new(
435+
expression::terminal(key, KeyExpr::<Pk>::from_str)?,
436+
Some(ret),
437+
)
435438
}
436439
_ => {
437440
return Err(Error::Unexpected(format!(
@@ -567,12 +570,10 @@ impl<Pk: MiniscriptKey> Liftable<Pk> for Tr<Pk> {
567570
match &self.tree {
568571
Some(root) => Ok(Policy::Threshold(
569572
1,
570-
vec![
571-
Policy::KeyHash(self.internal_key.to_pubkeyhash()),
572-
root.lift()?,
573-
],
573+
vec![self.internal_key.lift()?, root.lift()?],
574574
)),
575-
None => Ok(Policy::KeyHash(self.internal_key.to_pubkeyhash())),
575+
// None => Ok(Policy::KeyHash(self.internal_key.to_pubkeyhash())),
576+
None => self.internal_key.lift(),
576577
}
577578
}
578579
}
@@ -586,7 +587,7 @@ impl<Pk: MiniscriptKey> ForEachKey<Pk> for Tr<Pk> {
586587
let script_keys_res = self
587588
.iter_scripts()
588589
.all(|(_d, ms)| ms.for_each_key(&mut pred));
589-
script_keys_res && pred(&self.internal_key)
590+
script_keys_res && self.internal_key().for_any_key(pred)
590591
}
591592
}
592593

@@ -602,7 +603,7 @@ where
602603
T: Translator<P, Q, E>,
603604
{
604605
let translate_desc = Tr {
605-
internal_key: translate.pk(&self.internal_key)?,
606+
internal_key: self.internal_key.translate_pk(translate)?,
606607
tree: match &self.tree {
607608
Some(tree) => Some(tree.translate_helper(translate)?),
608609
None => None,

src/miniscript/mod.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -519,11 +519,10 @@ mod tests {
519519
let desc = Descriptor::<String>::from_str("tr(X,{pk(musig(X1)),multi_a(1,X2,X3)})");
520520
assert_eq!(desc.is_ok(), true);
521521

522-
let desc =
523-
Descriptor::<String>::from_str("tr(pk(musig(E)),{pk(A),multi_a(1,B,musig(C,D))})");
522+
let desc = Descriptor::<String>::from_str("tr(musig(E),{pk(A),multi_a(1,B,musig(C,D))})");
524523
assert_eq!(desc.is_ok(), true);
525524

526-
let desc = Descriptor::<String>::from_str("tr(pk(musig(D)),pk(musig(A,B,musig(C))))");
525+
let desc = Descriptor::<String>::from_str("tr(musig(D),pk(musig(A,B,musig(C))))");
527526
assert_eq!(desc.is_ok(), true);
528527
}
529528

src/miniscript/musig_key.rs

+19
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use bitcoin::secp256k1::{Secp256k1, VerifyOnly};
77
use secp256k1_zkp::MusigKeyAggCache;
88

99
use crate::expression::{FromTree, Tree};
10+
use crate::policy::semantic::{Policy, Policy as Semantic};
11+
use crate::policy::Liftable;
1012
use crate::prelude::*;
1113
use crate::{expression, Error, ForEachKey, MiniscriptKey, ToPublicKey, TranslatePk, Translator};
1214

@@ -50,6 +52,23 @@ where
5052
}
5153
}
5254

55+
impl<Pk: MiniscriptKey> Liftable<Pk> for KeyExpr<Pk> {
56+
fn lift(&self) -> Result<Policy<Pk>, Error> {
57+
let res = match self {
58+
KeyExpr::SingleKey(pk) => Semantic::KeyHash(pk.to_pubkeyhash()),
59+
KeyExpr::MuSig(keys) => {
60+
let mut policy_vec: Vec<Semantic<Pk>> = vec![];
61+
for key in keys {
62+
policy_vec.push((key.clone()).lift()?)
63+
}
64+
Semantic::Threshold(keys.len(), policy_vec)
65+
}
66+
}
67+
.normalized();
68+
Ok(res)
69+
}
70+
}
71+
5372
#[derive(Debug, Clone)]
5473
/// Iterator for [`KeyExpr`]
5574
pub struct KeyExprIter<'a, Pk: MiniscriptKey> {

src/policy/concrete.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use std::error;
2222
#[cfg(feature = "compiler")]
2323
use {
2424
crate::descriptor::TapTree,
25+
crate::miniscript::musig_key::KeyExpr,
2526
crate::miniscript::ScriptContext,
2627
crate::policy::compiler::CompilerError,
2728
crate::policy::compiler::OrdF64,
@@ -277,7 +278,8 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
277278
_ => {
278279
let (internal_key, policy) = self.clone().extract_key(unspendable_key)?;
279280
let tree = Descriptor::new_tr(
280-
internal_key,
281+
// Temporary solution, need to decide what we should write in place of singlekey
282+
KeyExpr::SingleKey(internal_key),
281283
match policy {
282284
Policy::Trivial => None,
283285
policy => {

src/policy/mod.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ mod tests {
256256

257257
use super::super::miniscript::context::{Segwitv0, Tap};
258258
use super::super::miniscript::Miniscript;
259+
#[cfg(feature = "compiler")]
260+
use super::KeyExpr;
259261
use super::{Concrete, Liftable, Semantic};
260262
use crate::prelude::*;
261263
use crate::DummyKey;
@@ -448,7 +450,8 @@ mod tests {
448450
let ms_compilation: Miniscript<String, Tap> = ms_str!("multi_a(2,A,B,C,D)");
449451
let tree: TapTree<String> = TapTree::Leaf(Arc::new(ms_compilation));
450452
let expected_descriptor =
451-
Descriptor::new_tr(unspendable_key.clone(), Some(tree)).unwrap();
453+
Descriptor::new_tr(KeyExpr::SingleKey(unspendable_key.clone()), Some(tree))
454+
.unwrap();
452455
assert_eq!(descriptor, expected_descriptor);
453456
}
454457

@@ -465,7 +468,8 @@ mod tests {
465468
let right_node: Arc<TapTree<String>> = Arc::from(TapTree::Leaf(right_ms_compilation));
466469
let tree: TapTree<String> = TapTree::Tree(left_node, right_node);
467470
let expected_descriptor =
468-
Descriptor::new_tr(unspendable_key.clone(), Some(tree)).unwrap();
471+
Descriptor::new_tr(KeyExpr::SingleKey(unspendable_key.clone()), Some(tree))
472+
.unwrap();
469473
assert_eq!(descriptor, expected_descriptor);
470474
}
471475

@@ -548,7 +552,8 @@ mod tests {
548552
)),
549553
);
550554

551-
let expected_descriptor = Descriptor::new_tr("E".to_string(), Some(tree)).unwrap();
555+
let expected_descriptor =
556+
Descriptor::new_tr(KeyExpr::SingleKey("E".to_string()), Some(tree)).unwrap();
552557
assert_eq!(descriptor, expected_descriptor);
553558
}
554559
}

src/psbt/mod.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use bitcoin::{self, EcdsaSighashType, SchnorrSighashType, Script};
3333

3434
use crate::miniscript::iter::PkPkh;
3535
use crate::miniscript::limits::SEQUENCE_LOCKTIME_DISABLE_FLAG;
36+
use crate::miniscript::musig_key::KeyExpr;
3637
use crate::miniscript::satisfy::{After, Older};
3738
use crate::prelude::*;
3839
use crate::{
@@ -1017,13 +1018,15 @@ fn update_input_with_descriptor_helper(
10171018
let ik_xpk = tr_xpk.internal_key();
10181019
input.tap_internal_key = Some(ik_derived);
10191020
input.tap_merkle_root = spend_info.merkle_root();
1020-
input.tap_key_origins.insert(
1021-
ik_derived,
1022-
(
1023-
vec![],
1024-
(ik_xpk.master_fingerprint(), ik_xpk.full_derivation_path()),
1025-
),
1026-
);
1021+
match ik_xpk {
1022+
KeyExpr::SingleKey(pk) => {
1023+
input.tap_key_origins.insert(
1024+
ik_derived,
1025+
(vec![], (pk.master_fingerprint(), pk.full_derivation_path())),
1026+
);
1027+
}
1028+
KeyExpr::MuSig(_) => (), // Need to fix this, when we add full support to KeyExpr
1029+
};
10271030

10281031
for ((_depth_der, ms_derived), (_depth, ms)) in
10291032
tr_derived.iter_scripts().zip(tr_xpk.iter_scripts())

tests/test_desc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ pub fn test_desc_satisfy(
156156

157157
let internal_key_present = x_only_pks
158158
.iter()
159-
.position(|&x| x.to_public_key() == *tr.internal_key());
159+
.position(|&x| x.to_public_key() == *tr.internal_key().single_key().unwrap());
160160
let internal_keypair = internal_key_present.map(|idx| xonly_keypairs[idx].clone());
161161
let prevouts = [witness_utxo];
162162
let prevouts = sighash::Prevouts::All(&prevouts);

0 commit comments

Comments
 (0)