Skip to content

Commit 816bf94

Browse files
committed
[wip] Remove explicit signatures from Assets
Instead of storing keys and signatures in the `Assets` struct, only store keys with extra conditions on how the key can sign
1 parent c3ba4d3 commit 816bf94

File tree

4 files changed

+233
-201
lines changed

4 files changed

+233
-201
lines changed

src/descriptor/tr.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ use sync::Arc;
1414
use super::checksum::{self, verify_checksum};
1515
use crate::descriptor::{DefiniteDescriptorKey, DescriptorType};
1616
use crate::expression::{self, FromTree};
17-
use crate::miniscript::satisfy::{Placeholder, Satisfaction, Witness, WitnessTemplate};
17+
use crate::miniscript::satisfy::{
18+
Placeholder, Satisfaction, SchnorrSigType, Witness, WitnessTemplate,
19+
};
1820
use crate::miniscript::Miniscript;
1921
use crate::plan::{AssetProvider, Plan};
2022
use crate::policy::semantic::Policy;
@@ -656,11 +658,14 @@ where
656658
{
657659
let spend_info = desc.spend_info();
658660
// First try the key spend path
659-
if provider.lookup_tap_key_spend_sig(&desc.internal_key) {
661+
if let Some(size) = provider.lookup_tap_key_spend_sig(&desc.internal_key) {
660662
Satisfaction {
661663
stack: Witness::Stack(vec![Placeholder::SchnorrSig(
662664
desc.internal_key.clone(),
663-
None,
665+
SchnorrSigType::KeySpend {
666+
merkle_root: spend_info.merkle_root(),
667+
},
668+
size,
664669
)]),
665670
has_sig: true,
666671
absolute_timelock: None,

src/miniscript/satisfy.rs

+57-130
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ use core::{cmp, fmt, i64, mem};
2222

2323
use bitcoin::hashes::hash160;
2424
use bitcoin::secp256k1::XOnlyPublicKey;
25-
use bitcoin::util::taproot::{ControlBlock, LeafVersion, TapLeafHash};
25+
use bitcoin::util::taproot::{ControlBlock, LeafVersion, TapBranchHash, TapLeafHash};
2626
use bitcoin::{LockTime, PackedLockTime, Script, Sequence};
2727
use sync::Arc;
2828

2929
use super::context::SigType;
3030
use crate::descriptor::DescriptorType;
31-
use crate::plan::{AssetProvider, Plan, RequiredPreimage, RequiredSig};
31+
use crate::plan::{AssetProvider, Plan};
3232
use crate::prelude::*;
3333
use crate::util::witness_size;
3434
use crate::{
@@ -530,6 +530,21 @@ impl_tuple_satisfier!(A, B, C, D, E, F);
530530
impl_tuple_satisfier!(A, B, C, D, E, F, G);
531531
impl_tuple_satisfier!(A, B, C, D, E, F, G, H);
532532

533+
#[derive(Debug, Clone, PartialEq, Eq)]
534+
/// Type of schnorr signature to produce
535+
pub enum SchnorrSigType {
536+
/// Key spend signature
537+
KeySpend {
538+
/// Merkle root to tweak the key, if present
539+
merkle_root: Option<TapBranchHash>,
540+
},
541+
/// Script spend signature
542+
ScriptSpend {
543+
/// Leaf hash of the script
544+
leaf_hash: TapLeafHash,
545+
},
546+
}
547+
533548
#[derive(Debug, Clone, PartialEq, Eq)]
534549
/// Placeholder for some data in a [`WitnessTemplate`]
535550
pub enum Placeholder<Pk: MiniscriptKey> {
@@ -541,10 +556,10 @@ pub enum Placeholder<Pk: MiniscriptKey> {
541556
EcdsaSigPk(Pk),
542557
/// ECDSA signature given the pubkey hash
543558
EcdsaSigHash(hash160::Hash),
544-
/// Schnorr signature
545-
SchnorrSig(Pk, Option<TapLeafHash>),
546-
/// Schnorr signature given the pubkey hash and the leaf hash
547-
SchnorrSigHash(hash160::Hash, TapLeafHash),
559+
/// Schnorr signature and its size
560+
SchnorrSig(Pk, SchnorrSigType, usize),
561+
/// Schnorr signature given the pubkey hash and the leaf hash, plus its size
562+
SchnorrSigHash(hash160::Hash, TapLeafHash, usize),
548563
/// SHA-256 preimage
549564
Sha256Preimage(Pk::Sha256),
550565
/// HASH256 preimage
@@ -575,12 +590,16 @@ impl<Pk: MiniscriptKey> fmt::Display for Placeholder<Pk> {
575590
PubkeyHash(pkh, size) => write!(f, "PubkeyHash(pkh: {}, size: {})", pkh, size),
576591
EcdsaSigPk(pk) => write!(f, "EcdsaSigPk(pk: {})", pk),
577592
EcdsaSigHash(hash) => write!(f, "EcdsaSigHash(hash: {})", hash),
578-
SchnorrSig(pk, tap_leaf_hash) => write!(
593+
SchnorrSig(pk, tap_leaf_hash, size) => write!(
579594
f,
580-
"SchnorrSig(pk: {}, tap_leaf_hash: {:?})",
581-
pk, tap_leaf_hash
595+
"SchnorrSig(pk: {}, tap_leaf_hash: {:?}, size: {})",
596+
pk, tap_leaf_hash, size
597+
),
598+
SchnorrSigHash(pkh, lh, size) => write!(
599+
f,
600+
"SchnorrSigHash(pkh: {}, leaf_hash: {}, size: {})",
601+
pkh, lh, size
582602
),
583-
SchnorrSigHash(pkh, lh) => write!(f, "SchnorrSigHash(pkh: {}, leaf_hash: {})", pkh, lh),
584603
Sha256Preimage(hash) => write!(f, "Sha256Preimage(hash: {})", hash),
585604
Hash256Preimage(hash) => write!(f, "Hash256Preimage(hash: {})", hash),
586605
Ripemd160Preimage(hash) => write!(f, "Ripemd160Preimage(hash: {})", hash),
@@ -612,8 +631,8 @@ impl<Pk: MiniscriptKey + ToPublicKey> Placeholder<Pk> {
612631
.or(sat.lookup_raw_pkh_ecdsa_sig(pkh).map(|(p, _)| p))
613632
.map(|pk| {
614633
let pk = pk.to_bytes();
615-
// We have to add a 1-byte OP_PUSH
616-
debug_assert!(1 + pk.len() == *size);
634+
// Need to add +1 because the size in the placeholder also accounts for the OP_PUSH
635+
debug_assert!(pk.len() + 1 == *size);
617636
pk
618637
}),
619638
Placeholder::Hash256Preimage(h) => sat.lookup_hash256(h).map(|p| p.to_vec()),
@@ -624,13 +643,26 @@ impl<Pk: MiniscriptKey + ToPublicKey> Placeholder<Pk> {
624643
Placeholder::EcdsaSigHash(pkh) => {
625644
sat.lookup_raw_pkh_ecdsa_sig(pkh).map(|(_, s)| s.to_vec())
626645
}
627-
Placeholder::SchnorrSig(pk, Some(leaf_hash)) => sat
646+
Placeholder::SchnorrSig(pk, SchnorrSigType::ScriptSpend { leaf_hash }, size) => sat
628647
.lookup_tap_leaf_script_sig(pk, leaf_hash)
629-
.map(|s| s.to_vec()),
630-
Placeholder::SchnorrSigHash(pkh, lh) => sat
648+
.map(|s| s.to_vec())
649+
.map(|s| {
650+
debug_assert!(s.len() == *size);
651+
s
652+
}),
653+
Placeholder::SchnorrSigHash(pkh, lh, size) => sat
631654
.lookup_raw_pkh_tap_leaf_script_sig(&(*pkh, *lh))
632-
.map(|(_, s)| s.to_vec()),
633-
Placeholder::SchnorrSig(_, _) => sat.lookup_tap_key_spend_sig().map(|s| s.to_vec()),
655+
.map(|(_, s)| s.to_vec())
656+
.map(|s| {
657+
debug_assert!(s.len() == *size);
658+
s
659+
}),
660+
Placeholder::SchnorrSig(_, _, size) => {
661+
sat.lookup_tap_key_spend_sig().map(|s| s.to_vec()).map(|s| {
662+
debug_assert!(s.len() == *size);
663+
s
664+
})
665+
}
634666
Placeholder::HashDissatisfaction => Some(vec![0; 32]),
635667
Placeholder::PushZero => Some(vec![]),
636668
Placeholder::PushOne => Some(vec![1]),
@@ -653,29 +685,6 @@ pub enum Witness<T> {
653685
Impossible,
654686
}
655687

656-
/// Enum for partially satisfied witness templates
657-
pub enum PartialSatisfaction<Pk: MiniscriptKey> {
658-
/// Placeholder item (not yet satisfied)
659-
Placeholder(Placeholder<Pk>),
660-
/// Actual data
661-
Data(Vec<u8>),
662-
}
663-
664-
impl<Pk: MiniscriptKey> PartialSatisfaction<Pk> {
665-
/// Whether the item is a placeholder
666-
pub fn is_placeholder(&self) -> bool {
667-
match &self {
668-
PartialSatisfaction::Placeholder(_) => true,
669-
_ => false,
670-
}
671-
}
672-
673-
/// Whether the item is data
674-
pub fn is_data(&self) -> bool {
675-
!self.is_placeholder()
676-
}
677-
}
678-
679688
/// Template of a witness being constructed interactively
680689
///
681690
/// The generic `I` type determines the available API:
@@ -710,91 +719,6 @@ impl<Pk: MiniscriptKey + ToPublicKey> WitnessTemplate<Placeholder<Pk>> {
710719

711720
Some(stack)
712721
}
713-
714-
/// Being an interactive satisfaction session
715-
pub fn interactive_satisfaction(self) -> WitnessTemplate<PartialSatisfaction<Pk>> {
716-
WitnessTemplate {
717-
stack: self
718-
.stack
719-
.into_iter()
720-
.map(PartialSatisfaction::Placeholder)
721-
.collect(),
722-
}
723-
}
724-
725-
/// Returns the list of required signatures
726-
pub fn required_signatures(&self) -> Vec<RequiredSig<'_, Pk>> {
727-
self.stack
728-
.iter()
729-
.filter_map(|item| match item {
730-
Placeholder::EcdsaSigPk(pk) => Some(RequiredSig::Ecdsa(pk)),
731-
Placeholder::SchnorrSig(pk, None) => Some(RequiredSig::SchnorrTapKey(pk)),
732-
Placeholder::SchnorrSig(pk, Some(lh)) => {
733-
Some(RequiredSig::SchnorrTapScript(pk, lh))
734-
}
735-
_ => None,
736-
})
737-
.collect()
738-
}
739-
740-
/// Returns the list of required preimages
741-
pub fn required_preimages(&self) -> Vec<RequiredPreimage<'_, Pk>> {
742-
self.stack
743-
.iter()
744-
.filter_map(|item| match item {
745-
Placeholder::Sha256Preimage(h) => Some(RequiredPreimage::Sha256(h)),
746-
Placeholder::Hash256Preimage(h) => Some(RequiredPreimage::Hash256(h)),
747-
Placeholder::Ripemd160Preimage(h) => Some(RequiredPreimage::Ripemd160(h)),
748-
Placeholder::Hash160Preimage(h) => Some(RequiredPreimage::Hash160(h)),
749-
_ => None,
750-
})
751-
.collect()
752-
}
753-
}
754-
755-
impl<Pk: MiniscriptKey + ToPublicKey> WitnessTemplate<PartialSatisfaction<Pk>> {
756-
/// Apply the items needed from a satisfier
757-
///
758-
/// Returns the completed witness if all the placeholders have been filled, or `Err` with itself a list of missing
759-
/// items otherwise.
760-
pub fn apply<Sat: Satisfier<Pk>>(
761-
self,
762-
stfr: &Sat,
763-
) -> Result<Vec<Vec<u8>>, (Self, Vec<Placeholder<Pk>>)> {
764-
let mut unsatisfied = vec![];
765-
766-
let stack = self
767-
.stack
768-
.into_iter()
769-
.map(|ps| {
770-
let placeholder = match &ps {
771-
PartialSatisfaction::Placeholder(p) => p,
772-
PartialSatisfaction::Data(_) => return ps,
773-
};
774-
775-
if let Some(data) = placeholder.satisfy_self(stfr) {
776-
return PartialSatisfaction::Data(data);
777-
}
778-
779-
unsatisfied.push(placeholder.clone());
780-
ps
781-
})
782-
.collect::<Vec<_>>();
783-
784-
if unsatisfied.is_empty() {
785-
Ok(stack
786-
.into_iter()
787-
.map(|ps| match ps {
788-
PartialSatisfaction::Data(d) => d,
789-
PartialSatisfaction::Placeholder(_) => {
790-
unreachable!("there shouldn't be any placeholder left")
791-
}
792-
})
793-
.collect())
794-
} else {
795-
Err((WitnessTemplate { stack }, unsatisfied))
796-
}
797-
}
798722
}
799723

800724
impl<Pk: MiniscriptKey> PartialOrd for Witness<Placeholder<Pk>> {
@@ -838,10 +762,13 @@ impl<Pk: MiniscriptKey + ToPublicKey> Witness<Placeholder<Pk>> {
838762
}
839763
}
840764
super::context::SigType::Schnorr => {
841-
if sat.lookup_tap_leaf_script_sig(pk, leaf_hash) {
765+
if let Some(size) = sat.lookup_tap_leaf_script_sig(pk, leaf_hash) {
842766
Witness::Stack(vec![Placeholder::SchnorrSig(
843767
pk.clone(),
844-
Some(leaf_hash.clone()),
768+
SchnorrSigType::ScriptSpend {
769+
leaf_hash: *leaf_hash,
770+
},
771+
size,
845772
)])
846773
} else {
847774
// Signatures cannot be forged
@@ -885,11 +812,11 @@ impl<Pk: MiniscriptKey + ToPublicKey> Witness<Placeholder<Pk>> {
885812
None => Witness::Impossible,
886813
},
887814
SigType::Schnorr => match sat.lookup_raw_pkh_tap_leaf_script_sig(&(*pkh, *leaf_hash)) {
888-
true => Witness::Stack(vec![
889-
Placeholder::SchnorrSigHash(pkh.clone(), *leaf_hash),
815+
Some(size) => Witness::Stack(vec![
816+
Placeholder::SchnorrSigHash(pkh.clone(), *leaf_hash, size),
890817
Placeholder::PubkeyHash(pkh.clone(), 32),
891818
]),
892-
false => Witness::Impossible,
819+
None => Witness::Impossible,
893820
},
894821
}
895822
}

0 commit comments

Comments
 (0)