Skip to content

Commit

Permalink
Add feature simplicity
Browse files Browse the repository at this point in the history
rust-simplicity is still evolving and it might need fixes or
interface changes. Make it optional.
  • Loading branch information
LeoComandini committed Jan 15, 2024
1 parent 259f7c4 commit d9b3caf
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 15 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ base64 = ["bitcoin/base64"]
bitcoin = "0.30.0"
elements = "0.23.0"
bitcoin-miniscript = { package = "miniscript", version = "10.0" }
simplicity = { git = "https://github.com/BlockstreamResearch/rust-simplicity", rev = "d5c0d65320816bfdf36411feed4bdff0708b5b12" }
simplicity = { git = "https://github.com/BlockstreamResearch/rust-simplicity", rev = "d5c0d65320816bfdf36411feed4bdff0708b5b12", optional = true }

# Do NOT use this as a feature! Use the `serde` feature instead.
actual-serde = { package = "serde", version = "1.0", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion contrib/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

set -ex

FEATURES="compiler serde rand base64"
FEATURES="compiler serde rand base64 simplicity"

cargo --version
rustc --version
Expand Down
54 changes: 41 additions & 13 deletions src/descriptor/tr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub enum TapTree<Pk: MiniscriptKey, Ext: Extension = NoExt> {
// are of Leafversion::default
Leaf(Arc<Miniscript<Pk, Tap, Ext>>),
/// A taproot leaf denoting a spending condition in terms of Simplicity
#[cfg(feature = "simplicity")]
SimplicityLeaf(Arc<simplicity::Policy<Pk>>),
}

Expand Down Expand Up @@ -119,7 +120,9 @@ impl<Pk: MiniscriptKey, Ext: Extension> TapTree<Pk, Ext> {
TapTree::Tree(ref left_tree, ref right_tree) => {
1 + max(left_tree.taptree_height(), right_tree.taptree_height())
}
TapTree::Leaf(..) | TapTree::SimplicityLeaf(..) => 0,
TapTree::Leaf(..) => 0,
#[cfg(feature = "simplicity")]
TapTree::SimplicityLeaf(..) => 0,
}
}

Expand All @@ -138,8 +141,10 @@ impl<Pk: MiniscriptKey, Ext: Extension> TapTree<Pk, Ext> {
Q: MiniscriptKey,
Ext: Extension,
{
#[cfg(feature = "simplicity")]
struct SimTranslator<'a, T>(&'a mut T);

#[cfg(feature = "simplicity")]
impl<'a, Pk, T, Q, Error> simplicity::Translator<Pk, Q, Error> for SimTranslator<'a, T>
where
Pk: MiniscriptKey,
Expand All @@ -161,6 +166,7 @@ impl<Pk: MiniscriptKey, Ext: Extension> TapTree<Pk, Ext> {
Arc::new(r.translate_helper(t)?),
),
TapTree::Leaf(ms) => TapTree::Leaf(Arc::new(ms.translate_pk(t)?)),
#[cfg(feature = "simplicity")]
TapTree::SimplicityLeaf(sim) => TapTree::SimplicityLeaf(Arc::new(sim.translate(&mut SimTranslator(t))?))
};
Ok(frag)
Expand All @@ -179,6 +185,7 @@ impl<Pk: MiniscriptKey, Ext: Extension> TapTree<Pk, Ext> {
Arc::new(r.translate_ext_helper(t)?),
),
TapTree::Leaf(ms) => TapTree::Leaf(Arc::new(ms.translate_ext(t)?)),
#[cfg(feature = "simplicity")]
TapTree::SimplicityLeaf(sim) => TapTree::SimplicityLeaf(Arc::clone(sim)),
};
Ok(frag)
Expand All @@ -190,6 +197,7 @@ impl<Pk: MiniscriptKey, Ext: Extension> fmt::Display for TapTree<Pk, Ext> {
match self {
TapTree::Tree(ref left, ref right) => write!(f, "{{{},{}}}", *left, *right),
TapTree::Leaf(ref script) => write!(f, "{}", *script),
#[cfg(feature = "simplicity")]
TapTree::SimplicityLeaf(ref policy) => write!(f, "sim{{{}}}", policy),
}
}
Expand All @@ -200,6 +208,7 @@ impl<Pk: MiniscriptKey, Ext: Extension> fmt::Debug for TapTree<Pk, Ext> {
match self {
TapTree::Tree(ref left, ref right) => write!(f, "{{{:?},{:?}}}", *left, *right),
TapTree::Leaf(ref script) => write!(f, "{:?}", *script),
#[cfg(feature = "simplicity")]
TapTree::SimplicityLeaf(ref policy) => write!(f, "{:?}", policy),
}
}
Expand Down Expand Up @@ -288,6 +297,7 @@ impl<Pk: MiniscriptKey, Ext: Extension> Tr<Pk, Ext> {
match script {
TapLeafScript::Miniscript(ms) => ms.sanity_check()?,
// TODO: Add sanity check for Simplicity policies
#[cfg(feature = "simplicity")]
TapLeafScript::Simplicity(..) => {},
}
}
Expand Down Expand Up @@ -436,6 +446,7 @@ pub enum TapLeafScript<'a, Pk: MiniscriptKey, Ext: Extension> {
/// Miniscript leaf
Miniscript(&'a Miniscript<Pk, Tap, Ext>),
/// Simplicity leaf
#[cfg(feature = "simplicity")]
Simplicity(&'a simplicity::Policy<Pk>)
}

Expand All @@ -444,11 +455,13 @@ impl<'a, Pk: MiniscriptKey, Ext: Extension> TapLeafScript<'a, Pk, Ext> {
pub fn as_miniscript(&self) -> Option<&'a Miniscript<Pk, Tap, Ext>> {
match self {
TapLeafScript::Miniscript(ms) => Some(ms),
#[cfg(feature = "simplicity")]
_ => None,
}
}

/// Get the Simplicity policy at the leaf, if it exists.
#[cfg(feature = "simplicity")]
pub fn as_simplicity(&self) -> Option<&'a simplicity::Policy<Pk>> {
match self {
TapLeafScript::Simplicity(sim) => Some(sim),
Expand All @@ -460,6 +473,7 @@ impl<'a, Pk: MiniscriptKey, Ext: Extension> TapLeafScript<'a, Pk, Ext> {
pub fn version(&self) -> LeafVersion {
match self {
TapLeafScript::Miniscript(..) => LeafVersion::default(),
#[cfg(feature = "simplicity")]
TapLeafScript::Simplicity(..) => simplicity::leaf_version(),
}
}
Expand All @@ -469,6 +483,7 @@ impl<'a, Pk: MiniscriptKey, Ext: Extension> TapLeafScript<'a, Pk, Ext> {
match self {
TapLeafScript::Miniscript(ms) => ms.script_size(),
// Simplicity's witness script is always a 32-byte CMR
#[cfg(feature = "simplicity")]
TapLeafScript::Simplicity(..) => 32,
}
}
Expand All @@ -482,6 +497,7 @@ impl<'a, Pk: MiniscriptKey, Ext: Extension> TapLeafScript<'a, Pk, Ext> {
// (1) Encoded program+witness
// (2) CMR program
// The third element is the control block, which is not counted by this method.
#[cfg(feature = "simplicity")]
TapLeafScript::Simplicity(..) => Ok(2),
}
}
Expand All @@ -493,6 +509,7 @@ impl<'a, Pk: MiniscriptKey, Ext: Extension> TapLeafScript<'a, Pk, Ext> {
// There is currently no way to bound the Simplicity witness size without producing one
// We mark the witness size as malleable since it depends on the chosen spending path
// TODO: Add method to simplicity::Policy and use it here
#[cfg(feature = "simplicity")]
TapLeafScript::Simplicity(..) => Err(Error::AnalysisError(crate::AnalysisError::Malleable))
}
}
Expand All @@ -501,6 +518,7 @@ impl<'a, Pk: MiniscriptKey, Ext: Extension> TapLeafScript<'a, Pk, Ext> {
pub fn iter_pk(&self) -> Box<dyn Iterator<Item=Pk> + 'a> {
match self {
TapLeafScript::Miniscript(ms) => Box::new(ms.iter_pk()),
#[cfg(feature = "simplicity")]
TapLeafScript::Simplicity(sim) => Box::new(sim.iter_pk()),
}
}
Expand All @@ -511,6 +529,7 @@ impl<'a, Pk: ToPublicKey, Ext: ParseableExt> TapLeafScript<'a, Pk, Ext> {
pub fn encode(&self) -> Script {
match self {
TapLeafScript::Miniscript(ms) => ms.encode(),
#[cfg(feature = "simplicity")]
TapLeafScript::Simplicity(sim) => {
Script::from(sim.cmr().as_ref().to_vec())
}
Expand All @@ -522,6 +541,7 @@ impl<'a, Pk: ToPublicKey, Ext: ParseableExt> TapLeafScript<'a, Pk, Ext> {
match self {
TapLeafScript::Miniscript(ms) => ms.satisfy_malleable(satisfier),
// There doesn't (yet?) exist a malleable satisfaction of Simplicity policy
#[cfg(feature = "simplicity")]
TapLeafScript::Simplicity(..) => self.satisfy(satisfier),
}
}
Expand All @@ -530,6 +550,7 @@ impl<'a, Pk: ToPublicKey, Ext: ParseableExt> TapLeafScript<'a, Pk, Ext> {
pub fn satisfy<S: Satisfier<Pk>>(&self, satisfier: S) -> Result<Vec<Vec<u8>>, Error> {
match self {
TapLeafScript::Miniscript(ms) => ms.satisfy(satisfier),
#[cfg(feature = "simplicity")]
TapLeafScript::Simplicity(sim) => {
let satisfier = crate::simplicity::SatisfierWrapper::new(satisfier);
let program = sim.satisfy(&satisfier).map_err(|_| Error::CouldNotSatisfy)?;
Expand Down Expand Up @@ -577,6 +598,7 @@ where
TapTree::Leaf(ref ms) => {
return Some((depth, TapLeafScript::Miniscript(ms)))
},
#[cfg(feature = "simplicity")]
TapTree::SimplicityLeaf(ref sim) => {
return Some((depth, TapLeafScript::Simplicity(sim)))
}
Expand All @@ -593,6 +615,7 @@ impl_block_str!(
// Helper function to parse taproot script path
fn parse_tr_script_spend(tree: &expression::Tree,) -> Result<TapTree<Pk, Ext>, Error> {
match tree {
#[cfg(feature = "simplicity")]
expression::Tree { name, args } if *name == "sim" && args.len() == 1 => {
let policy = crate::simplicity::PolicyWrapper::<Pk>::from_str(args[0].name)?;
Ok(TapTree::SimplicityLeaf(Arc::new(policy.0)))
Expand Down Expand Up @@ -771,6 +794,7 @@ impl<Pk: MiniscriptKey, Ext: Extension> Liftable<Pk> for TapTree<Pk, Ext> {
Ok(Policy::Threshold(1, vec![lift_helper(l)?, lift_helper(r)?]))
}
TapTree::Leaf(ref leaf) => leaf.lift(),
#[cfg(feature = "simplicity")]
TapTree::SimplicityLeaf(..) => panic!("FIXME: Cannot lift Simplicity policy to Miniscript semantic policy"),
}
}
Expand Down Expand Up @@ -802,6 +826,7 @@ impl<Pk: MiniscriptKey, Ext: Extension> ForEachKey<Pk> for Tr<Pk, Ext> {
.all(|(_d, script)| {
match script {
TapLeafScript::Miniscript(ms) => ms.for_each_key(&mut pred),
#[cfg(feature = "simplicity")]
TapLeafScript::Simplicity(sim) => crate::simplicity::for_each_key(sim, &mut pred),
}
});
Expand Down Expand Up @@ -976,17 +1001,20 @@ mod tests {
&[TapLeafScript::Miniscript(&ms)]
);

// Simplicity key spend
let sim = simplicity::Policy::Key("a".to_string());
verify_from_str(
"eltr(internal,sim{pk(a)})#duhmnzmm", "internal",
&[TapLeafScript::Simplicity(&sim)]
);

// Mixed Miniscript and Simplicity
verify_from_str(
"eltr(internal,{pk(a),sim{pk(a)}})#7vmfhpaj", "internal",
&[TapLeafScript::Miniscript(&ms), TapLeafScript::Simplicity(&sim)]
);
#[cfg(feature = "simplicity")]
{
// Simplicity key spend
let sim = simplicity::Policy::Key("a".to_string());
verify_from_str(
"eltr(internal,sim{pk(a)})#duhmnzmm", "internal",
&[TapLeafScript::Simplicity(&sim)]
);

// Mixed Miniscript and Simplicity
verify_from_str(
"eltr(internal,{pk(a),sim{pk(a)}})#7vmfhpaj", "internal",
&[TapLeafScript::Miniscript(&ms), TapLeafScript::Simplicity(&sim)]
);
}
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ pub mod psbt;
#[cfg(test)]
mod test_utils;
mod util;
#[cfg(feature = "simplicity")]
mod simplicity;

use std::{cmp, error, fmt, str};
Expand Down

0 comments on commit d9b3caf

Please sign in to comment.