Skip to content

Commit b84258e

Browse files
committed
tr: Spend Simplicity descriptors
The max weight calculations seem to be for convenience and not important for spending, so we will leave the Simplicity implementation for later.
1 parent ff1dea4 commit b84258e

File tree

2 files changed

+127
-42
lines changed

2 files changed

+127
-42
lines changed

src/descriptor/tr.rs

Lines changed: 91 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,8 @@ impl<Pk: MiniscriptKey, Ext: Extension> Tr<Pk, Ext> {
374374
Some(tree) => tree,
375375
};
376376

377+
// TODO: Max weight calculation for Simplicity policies
378+
377379
tree.iter()
378380
.filter_map(|(depth, ms)| {
379381
let script_size = ms.script_size();
@@ -820,54 +822,102 @@ where
820822
S: Satisfier<Pk>,
821823
Ext: ParseableExt,
822824
{
823-
let spend_info = desc.spend_info();
824825
// First try the key spend path
825826
if let Some(sig) = satisfier.lookup_tap_key_spend_sig() {
826827
Ok((vec![sig.to_vec()], Script::new()))
827828
} else {
828-
// Since we have the complete descriptor we can ignore the satisfier. We don't use the control block
829-
// map (lookup_control_block) from the satisfier here.
830-
let (mut min_wit, mut min_wit_len) = (None, None);
831-
for (depth, ms) in desc.iter_scripts() {
832-
let mut wit = if allow_mall {
833-
match ms.satisfy_malleable(&satisfier) {
834-
Ok(wit) => wit,
835-
Err(..) => continue, // No witness for this script in tr descriptor, look for next one
836-
}
837-
} else {
838-
match ms.satisfy(&satisfier) {
839-
Ok(wit) => wit,
840-
Err(..) => continue, // No witness for this script in tr descriptor, look for next one
841-
}
842-
};
843-
// Compute the final witness size
844-
// Control block len + script len + witnesssize + varint(wit.len + 2)
845-
// The extra +2 elements are control block and script itself
846-
let wit_size = witness_size(&wit)
847-
+ control_block_len(depth)
848-
+ ms.script_size()
849-
+ varint_len(ms.script_size());
850-
if min_wit_len.is_some() && Some(wit_size) > min_wit_len {
851-
continue;
852-
} else {
853-
let leaf_script = (ms.encode(), LeafVersion::default());
854-
let control_block = spend_info
855-
.control_block(&leaf_script)
856-
.expect("Control block must exist in script map for every known leaf");
857-
wit.push(leaf_script.0.into_bytes()); // Push the leaf script
858-
// There can be multiple control blocks for a (script, ver) pair
859-
// Find the smallest one amongst those
860-
wit.push(control_block.serialize());
861-
// Finally, save the minimum
862-
min_wit = Some(wit);
863-
min_wit_len = Some(wit_size);
864-
}
829+
if desc.get_simplicity().is_some() {
830+
best_simplicity_spend(desc, satisfier)
831+
} else {
832+
best_miniscript_spend(desc, satisfier, allow_mall)
865833
}
866-
match min_wit {
867-
Some(wit) => Ok((wit, Script::new())),
868-
None => Err(Error::CouldNotSatisfy), // Could not satisfy all miniscripts inside Tr
834+
}
835+
}
836+
837+
fn best_miniscript_spend<Pk, S, Ext>(
838+
desc: &Tr<Pk, Ext>,
839+
satisfier: S,
840+
allow_mall: bool,
841+
) -> Result<(Vec<Vec<u8>>, Script), Error>
842+
where
843+
Pk: ToPublicKey,
844+
S: Satisfier<Pk>,
845+
Ext: ParseableExt,
846+
{
847+
// Since we have the complete descriptor we can ignore the satisfier. We don't use the control block
848+
// map (lookup_control_block) from the satisfier here.
849+
let (mut min_wit, mut min_wit_len) = (None, None);
850+
for (depth, ms) in desc.iter_scripts() {
851+
let mut wit = if allow_mall {
852+
match ms.satisfy_malleable(&satisfier) {
853+
Ok(wit) => wit,
854+
Err(..) => continue, // No witness for this script in tr descriptor, look for next one
855+
}
856+
} else {
857+
match ms.satisfy(&satisfier) {
858+
Ok(wit) => wit,
859+
Err(..) => continue, // No witness for this script in tr descriptor, look for next one
860+
}
861+
};
862+
// Compute the final witness size
863+
// Control block len + script len + witnesssize + varint(wit.len + 2)
864+
// The extra +2 elements are control block and script itself
865+
let wit_size = witness_size(&wit)
866+
+ control_block_len(depth)
867+
+ ms.script_size()
868+
+ varint_len(ms.script_size());
869+
if min_wit_len.is_some() && Some(wit_size) > min_wit_len {
870+
continue;
871+
} else {
872+
let leaf_script = (ms.encode(), LeafVersion::default());
873+
let control_block = desc
874+
.spend_info()
875+
.control_block(&leaf_script)
876+
.expect("Control block must exist in script map for every known leaf");
877+
wit.push(leaf_script.0.into_bytes()); // Push the leaf script
878+
// There can be multiple control blocks for a (script, ver) pair
879+
// Find the smallest one amongst those
880+
wit.push(control_block.serialize());
881+
// Finally, save the minimum
882+
min_wit = Some(wit);
883+
min_wit_len = Some(wit_size);
869884
}
870885
}
886+
match min_wit {
887+
Some(wit) => Ok((wit, Script::new())),
888+
None => Err(Error::CouldNotSatisfy), // Could not satisfy all miniscripts inside Tr
889+
}
890+
}
891+
892+
fn best_simplicity_spend<Pk, S, Ext>(
893+
desc: &Tr<Pk, Ext>,
894+
satisfier: S,
895+
) -> Result<(Vec<Vec<u8>>, Script), Error>
896+
where
897+
Pk: ToPublicKey,
898+
S: Satisfier<Pk>,
899+
Ext: ParseableExt,
900+
{
901+
let policy = desc.get_simplicity().ok_or(Error::CouldNotSatisfy)?;
902+
let satisfier = crate::simplicity::SatisfierWrapper::new(satisfier);
903+
let program = policy.satisfy(&satisfier).map_err(|_| Error::CouldNotSatisfy)?;
904+
905+
let program_and_witness_bytes = program.encode_to_vec();
906+
let cmr_bytes = Vec::from(program.cmr().as_ref());
907+
908+
let script = elements::Script::from(program.cmr().as_ref().to_vec());
909+
let script_ver = (script, simplicity::leaf_version());
910+
let control_block = desc
911+
.spend_info()
912+
.control_block(&script_ver)
913+
.expect("Control block must exist in script map for every known leaf");
914+
915+
let witness = vec![
916+
program_and_witness_bytes,
917+
cmr_bytes,
918+
control_block.serialize(),
919+
];
920+
Ok((witness, Script::new()))
871921
}
872922

873923
#[cfg(test)]

src/simplicity.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
// SPDX-License-Identifier: CC0-1.0
22
use std::fmt;
3+
use std::marker::PhantomData;
34
use std::str::FromStr;
45
use std::sync::Arc;
56

6-
use simplicity::{Policy, FailEntropy};
7+
use bitcoin_miniscript::ToPublicKey;
8+
use elements::{LockTime, SchnorrSig, Sequence};
9+
use elements::taproot::TapLeafHash;
10+
use simplicity::{Policy, FailEntropy, Preimage32};
711

812
use crate::policy::concrete::PolicyError;
913
use crate::{expression, Error, MiniscriptKey};
@@ -121,6 +125,37 @@ where
121125
true
122126
}
123127

128+
// We could make crate::Satisfier a subtrait of simplicity::Satisfier,
129+
// but then we would have to implement simplicity::Satisfier for all the blanket implementations
130+
// of crate::Satisfier, such as HashMap<Pk, ElementsSig>, which is annoying
131+
// We might choose to do so in the future, but for now a crate-local wrapper is easier
132+
// This wrapper is internally used by `Tr` and is never encountered by users
133+
pub(crate) struct SatisfierWrapper<Pk: ToPublicKey, S: crate::Satisfier<Pk>>(S, PhantomData<Pk>);
134+
135+
impl<Pk: ToPublicKey, S: crate::Satisfier<Pk>> SatisfierWrapper<Pk, S> {
136+
pub fn new(satisfier: S) -> Self {
137+
Self(satisfier, PhantomData)
138+
}
139+
}
140+
141+
impl<Pk: ToPublicKey, S: crate::Satisfier<Pk>> simplicity::Satisfier<Pk> for SatisfierWrapper<Pk, S> {
142+
fn lookup_tap_leaf_script_sig(&self, pk: &Pk, hash: &TapLeafHash) -> Option<SchnorrSig> {
143+
self.0.lookup_tap_leaf_script_sig(pk, hash)
144+
}
145+
146+
fn lookup_sha256(&self, hash: &Pk::Sha256) -> Option<Preimage32> {
147+
self.0.lookup_sha256(hash)
148+
}
149+
150+
fn check_older(&self, sequence: Sequence) -> bool {
151+
self.0.check_older(sequence)
152+
}
153+
154+
fn check_after(&self, locktime: LockTime) -> bool {
155+
self.0.check_after(locktime)
156+
}
157+
}
158+
124159
#[cfg(test)]
125160
mod tests {
126161
use secp256k1::XOnlyPublicKey;

0 commit comments

Comments
 (0)