Skip to content

Commit ff5a4bf

Browse files
committed
Add MiniscriptKey::is_xonly
1 parent fa4eefd commit ff5a4bf

File tree

2 files changed

+67
-3
lines changed

2 files changed

+67
-3
lines changed

src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ pub trait MiniscriptKey: Clone + Eq + Ord + fmt::Debug + fmt::Display + hash::Ha
136136
fn is_uncompressed(&self) -> bool {
137137
false
138138
}
139+
140+
/// Check if the publicKey is x-only. The default
141+
/// implementation returns false
142+
//
143+
// This is required to know what in DescriptorPublicKey to know whether the inner
144+
// key in allowed in descriptor context
145+
fn is_x_only_key(&self) -> bool {
146+
false
147+
}
148+
139149
/// The associated Hash type with the publicKey
140150
type Hash: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash;
141151

@@ -165,6 +175,10 @@ impl MiniscriptKey for bitcoin::secp256k1::XOnlyPublicKey {
165175
fn to_pubkeyhash(&self) -> Self::Hash {
166176
hash160::Hash::hash(&self.serialize())
167177
}
178+
179+
fn is_x_only_key(&self) -> bool {
180+
true
181+
}
168182
}
169183

170184
impl MiniscriptKey for String {

src/miniscript/context.rs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ pub enum ScriptContextError {
4545
/// Only Compressed keys allowed under current descriptor
4646
/// Segwitv0 fragments do not allow uncompressed pubkeys
4747
CompressedOnly(String),
48+
/// XOnly keys are only allowed in Tap context
49+
/// The first element is key, and second element is current script context
50+
XOnlyKeysNotAllowed(String, &'static str),
4851
/// Tapscript descriptors cannot contain uncompressed keys
4952
/// Tap context can contain compressed or xonly
5053
UncompressedKeysNotAllowed,
@@ -97,6 +100,9 @@ impl fmt::Display for ScriptContextError {
97100
pk
98101
)
99102
}
103+
ScriptContextError::XOnlyKeysNotAllowed(ref pk, ref ctx) => {
104+
write!(f, "x-only key {} not allowed in {}", pk, ctx)
105+
}
100106
ScriptContextError::UncompressedKeysNotAllowed => {
101107
write!(
102108
f,
@@ -345,10 +351,24 @@ impl ScriptContext for Legacy {
345351
}
346352

347353
match ms.node {
354+
Terminal::PkK(ref key) if key.is_x_only_key() => {
355+
return Err(ScriptContextError::XOnlyKeysNotAllowed(
356+
key.to_string(),
357+
Self::name_str(),
358+
))
359+
}
348360
Terminal::Multi(_k, ref pks) => {
349361
if pks.len() > MAX_PUBKEYS_PER_MULTISIG {
350362
return Err(ScriptContextError::CheckMultiSigLimitExceeded);
351363
}
364+
for pk in pks.iter() {
365+
if pk.is_x_only_key() {
366+
return Err(ScriptContextError::XOnlyKeysNotAllowed(
367+
pk.to_string(),
368+
Self::name_str(),
369+
));
370+
}
371+
}
352372
}
353373
Terminal::MultiA(..) => {
354374
return Err(ScriptContextError::MultiANotAllowed);
@@ -440,6 +460,11 @@ impl ScriptContext for Segwitv0 {
440460
Terminal::PkK(ref pk) => {
441461
if pk.is_uncompressed() {
442462
return Err(ScriptContextError::CompressedOnly(pk.to_string()));
463+
} else if pk.is_x_only_key() {
464+
return Err(ScriptContextError::XOnlyKeysNotAllowed(
465+
pk.to_string(),
466+
Self::name_str(),
467+
));
443468
}
444469
Ok(())
445470
}
@@ -450,6 +475,11 @@ impl ScriptContext for Segwitv0 {
450475
for pk in pks.iter() {
451476
if pk.is_uncompressed() {
452477
return Err(ScriptContextError::CompressedOnly(pk.to_string()));
478+
} else if pk.is_x_only_key() {
479+
return Err(ScriptContextError::XOnlyKeysNotAllowed(
480+
pk.to_string(),
481+
Self::name_str(),
482+
));
453483
}
454484
}
455485
Ok(())
@@ -652,10 +682,30 @@ impl ScriptContext for BareCtx {
652682
if ms.ext.pk_cost > MAX_SCRIPT_SIZE {
653683
return Err(ScriptContextError::MaxWitnessScriptSizeExceeded);
654684
}
655-
if let Terminal::MultiA(..) = ms.node {
656-
return Err(ScriptContextError::MultiANotAllowed);
685+
match ms.node {
686+
Terminal::PkK(ref key) if key.is_x_only_key() => {
687+
return Err(ScriptContextError::XOnlyKeysNotAllowed(
688+
key.to_string(),
689+
Self::name_str(),
690+
))
691+
}
692+
Terminal::Multi(_k, ref pks) => {
693+
if pks.len() > MAX_PUBKEYS_PER_MULTISIG {
694+
return Err(ScriptContextError::CheckMultiSigLimitExceeded);
695+
}
696+
for pk in pks.iter() {
697+
if pk.is_x_only_key() {
698+
return Err(ScriptContextError::XOnlyKeysNotAllowed(
699+
pk.to_string(),
700+
Self::name_str(),
701+
));
702+
}
703+
}
704+
Ok(())
705+
}
706+
Terminal::MultiA(..) => return Err(ScriptContextError::MultiANotAllowed),
707+
_ => Ok(()),
657708
}
658-
Ok(())
659709
}
660710

661711
fn check_local_consensus_validity<Pk: MiniscriptKey>(

0 commit comments

Comments
 (0)