1use core::fmt;
13#[cfg(feature = "std")]
14use std::error;
15
16#[cfg(feature = "compiler")]
17pub mod compiler;
18pub mod concrete;
19pub mod semantic;
20
21pub use self::concrete::Policy as Concrete;
22pub use self::semantic::Policy as Semantic;
23use crate::descriptor::Descriptor;
24use crate::iter::TreeLike as _;
25use crate::miniscript::{Miniscript, ScriptContext};
26use crate::sync::Arc;
27#[cfg(all(not(feature = "std"), not(test)))]
28use crate::Vec;
29use crate::{Error, MiniscriptKey, Terminal, Threshold};
30
31const ENTAILMENT_MAX_TERMINALS: usize = 20;
33
34pub trait Liftable<Pk: MiniscriptKey> {
51 fn lift(&self) -> Result<Semantic<Pk>, Error>;
53}
54
55#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
57pub enum LiftError {
58 HeightTimelockCombination,
60 BranchExceedResourceLimits,
62 RawDescriptorLift,
64}
65
66impl fmt::Display for LiftError {
67 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68 match *self {
69 LiftError::HeightTimelockCombination => {
70 f.write_str("Cannot lift policies that have a heightlock and timelock combination")
71 }
72 LiftError::BranchExceedResourceLimits => f.write_str(
73 "Cannot lift policies containing one branch that exceeds resource limits",
74 ),
75 LiftError::RawDescriptorLift => f.write_str("Cannot lift raw descriptors"),
76 }
77 }
78}
79
80#[cfg(feature = "std")]
81impl error::Error for LiftError {
82 fn cause(&self) -> Option<&dyn error::Error> {
83 use self::LiftError::*;
84
85 match self {
86 HeightTimelockCombination | BranchExceedResourceLimits | RawDescriptorLift => None,
87 }
88 }
89}
90
91impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
92 pub fn lift_check(&self) -> Result<(), LiftError> {
100 if !self.within_resource_limits() {
101 Err(LiftError::BranchExceedResourceLimits)
102 } else if self.has_mixed_timelocks() {
103 Err(LiftError::HeightTimelockCombination)
104 } else {
105 Ok(())
106 }
107 }
108}
109
110impl<Pk: MiniscriptKey, Ctx: ScriptContext> Liftable<Pk> for Miniscript<Pk, Ctx> {
111 fn lift(&self) -> Result<Semantic<Pk>, Error> {
112 self.lift_check()?;
115
116 let mut stack = vec![];
117 for item in self.rtl_post_order_iter() {
118 let new_term = match item.node.node {
119 Terminal::PkK(ref pk) | Terminal::PkH(ref pk) => {
120 Arc::new(Semantic::Key(pk.clone()))
121 }
122 Terminal::RawPkH(ref _pkh) => {
123 return Err(Error::LiftError(LiftError::RawDescriptorLift))
124 }
125 Terminal::After(t) => Arc::new(Semantic::After(t)),
126 Terminal::Older(t) => Arc::new(Semantic::Older(t)),
127 Terminal::Sha256(ref h) => Arc::new(Semantic::Sha256(h.clone())),
128 Terminal::Hash256(ref h) => Arc::new(Semantic::Hash256(h.clone())),
129 Terminal::Ripemd160(ref h) => Arc::new(Semantic::Ripemd160(h.clone())),
130 Terminal::Hash160(ref h) => Arc::new(Semantic::Hash160(h.clone())),
131 Terminal::False => Arc::new(Semantic::Unsatisfiable),
132 Terminal::True => Arc::new(Semantic::Trivial),
133 Terminal::Alt(..)
134 | Terminal::Swap(..)
135 | Terminal::Check(..)
136 | Terminal::DupIf(..)
137 | Terminal::Verify(..)
138 | Terminal::NonZero(..)
139 | Terminal::ZeroNotEqual(..) => stack.pop().unwrap(),
140 Terminal::AndV(..) | Terminal::AndB(..) => Arc::new(Semantic::Thresh(
141 Threshold::and(stack.pop().unwrap(), stack.pop().unwrap()),
142 )),
143 Terminal::AndOr(..) => Arc::new(Semantic::Thresh(Threshold::or(
144 Arc::new(Semantic::Thresh(Threshold::and(
145 stack.pop().unwrap(),
146 stack.pop().unwrap(),
147 ))),
148 stack.pop().unwrap(),
149 ))),
150 Terminal::OrB(..) | Terminal::OrD(..) | Terminal::OrC(..) | Terminal::OrI(..) => {
151 Arc::new(Semantic::Thresh(Threshold::or(
152 stack.pop().unwrap(),
153 stack.pop().unwrap(),
154 )))
155 }
156 Terminal::Thresh(ref thresh) => {
157 Arc::new(Semantic::Thresh(thresh.map_ref(|_| stack.pop().unwrap())))
158 }
159 Terminal::Multi(ref thresh) => Arc::new(Semantic::Thresh(
160 thresh
161 .map_ref(|key| Arc::new(Semantic::Key(key.clone())))
162 .forget_maximum(),
163 )),
164 Terminal::MultiA(ref thresh) => Arc::new(Semantic::Thresh(
165 thresh
166 .map_ref(|key| Arc::new(Semantic::Key(key.clone())))
167 .forget_maximum(),
168 )),
169 };
170 stack.push(new_term)
171 }
172 Ok(Arc::try_unwrap(stack.pop().unwrap()).unwrap().normalized())
173 }
174}
175
176impl<Pk: MiniscriptKey> Liftable<Pk> for Descriptor<Pk> {
177 fn lift(&self) -> Result<Semantic<Pk>, Error> {
178 match *self {
179 Descriptor::Bare(ref bare) => bare.lift(),
180 Descriptor::Pkh(ref pkh) => pkh.lift(),
181 Descriptor::Wpkh(ref wpkh) => wpkh.lift(),
182 Descriptor::Wsh(ref wsh) => wsh.lift(),
183 Descriptor::Sh(ref sh) => sh.lift(),
184 Descriptor::Tr(ref tr) => tr.lift(),
185 }
186 }
187}
188
189impl<Pk: MiniscriptKey> Liftable<Pk> for Semantic<Pk> {
190 fn lift(&self) -> Result<Semantic<Pk>, Error> { Ok(self.clone()) }
191}
192
193impl<Pk: MiniscriptKey> Liftable<Pk> for Concrete<Pk> {
194 fn lift(&self) -> Result<Semantic<Pk>, Error> {
195 self.check_timelocks().map_err(Error::ConcretePolicy)?;
198 let ret = match *self {
199 Concrete::Unsatisfiable => Semantic::Unsatisfiable,
200 Concrete::Trivial => Semantic::Trivial,
201 Concrete::Key(ref pk) => Semantic::Key(pk.clone()),
202 Concrete::After(t) => Semantic::After(t),
203 Concrete::Older(t) => Semantic::Older(t),
204 Concrete::Sha256(ref h) => Semantic::Sha256(h.clone()),
205 Concrete::Hash256(ref h) => Semantic::Hash256(h.clone()),
206 Concrete::Ripemd160(ref h) => Semantic::Ripemd160(h.clone()),
207 Concrete::Hash160(ref h) => Semantic::Hash160(h.clone()),
208 Concrete::And(ref subs) => {
209 let semantic_subs: Result<Vec<Semantic<Pk>>, Error> =
210 subs.iter().map(Liftable::lift).collect();
211 let semantic_subs = semantic_subs?.into_iter().map(Arc::new).collect();
212 Semantic::Thresh(Threshold::new(2, semantic_subs).unwrap())
213 }
214 Concrete::Or(ref subs) => {
215 let semantic_subs: Result<Vec<Semantic<Pk>>, Error> =
216 subs.iter().map(|(_p, sub)| sub.lift()).collect();
217 let semantic_subs = semantic_subs?.into_iter().map(Arc::new).collect();
218 Semantic::Thresh(Threshold::new(1, semantic_subs).unwrap())
219 }
220 Concrete::Thresh(ref thresh) => {
221 Semantic::Thresh(thresh.translate_ref(|sub| Liftable::lift(sub).map(Arc::new))?)
222 }
223 }
224 .normalized();
225 Ok(ret)
226 }
227}
228impl<Pk: MiniscriptKey> Liftable<Pk> for Arc<Concrete<Pk>> {
229 fn lift(&self) -> Result<Semantic<Pk>, Error> { self.as_ref().lift() }
230}
231
232#[cfg(test)]
233mod tests {
234 use core::str::FromStr;
235
236 use super::*;
237 #[cfg(feature = "compiler")]
238 use crate::descriptor::Tr;
239 use crate::miniscript::context::Segwitv0;
240 use crate::prelude::*;
241 use crate::RelLockTime;
242 #[cfg(feature = "compiler")]
243 use crate::{descriptor::TapTree, Tap};
244
245 type ConcretePol = Concrete<String>;
246 type SemanticPol = Semantic<String>;
247
248 fn concrete_policy_rtt(s: &str) {
249 let conc = ConcretePol::from_str(s).unwrap();
250 let output = conc.to_string();
251 assert_eq!(s.to_lowercase(), output.to_lowercase());
252 }
253
254 fn semantic_policy_rtt(s: &str) {
255 let sem = SemanticPol::from_str(s).unwrap();
256 let output = sem.normalized().to_string();
257 assert_eq!(s.to_lowercase(), output.to_lowercase());
258 }
259
260 #[test]
261 fn test_timelock_validity() {
262 assert!(ConcretePol::from_str("after(100)").is_ok());
264 assert!(ConcretePol::from_str("after(1000000000)").is_ok());
266 assert!(ConcretePol::from_str("or(after(1000000000),after(100))").is_ok());
268 assert!(ConcretePol::from_str("and(after(1000000000),after(100))").is_err());
270 assert!(ConcretePol::from_str("thresh(1,pk(),after(1000000000),after(100))").is_ok());
272 assert!(ConcretePol::from_str("thresh(2,after(1000000000),after(100),pk())").is_err());
274 }
275 #[test]
276 fn policy_rtt_tests() {
277 concrete_policy_rtt("pk()");
278 concrete_policy_rtt("or(1@pk(X),1@pk(Y))");
279 concrete_policy_rtt("or(99@pk(X),1@pk(Y))");
280 concrete_policy_rtt("and(pk(X),or(99@pk(Y),1@older(12960)))");
281
282 semantic_policy_rtt("pk()");
283 semantic_policy_rtt("or(pk(X),pk(Y))");
284 semantic_policy_rtt("and(pk(X),pk(Y))");
285
286 assert!(ConcretePol::from_str("thresh()").is_err());
288 assert!(SemanticPol::from_str("thresh(0)").is_err());
289 assert!(SemanticPol::from_str("thresh()").is_err());
290 concrete_policy_rtt("ripemd160()");
291 }
292
293 #[test]
294 fn compile_invalid() {
295 assert_eq!(
298 ConcretePol::from_str("thresh(2,pk(),thresh(0))")
299 .unwrap_err()
300 .to_string(),
301 "thresholds in Miniscript must be nonempty",
302 );
303 assert_eq!(
304 ConcretePol::from_str("thresh(2,pk(),thresh(0,pk()))")
305 .unwrap_err()
306 .to_string(),
307 "thresholds in Miniscript must have k > 0",
308 );
309 assert_eq!(
310 ConcretePol::from_str("and(pk())").unwrap_err().to_string(),
311 "and must have 2 children, but found 1"
312 );
313 assert_eq!(
314 ConcretePol::from_str("or(pk())").unwrap_err().to_string(),
315 "or must have 2 children, but found 1"
316 );
317 assert_eq!(
320 ConcretePol::from_str("thresh(3,after(0),pk(),pk())")
321 .unwrap_err()
322 .to_string(),
323 "absolute locktimes in Miniscript have a minimum value of 1",
324 );
325
326 assert_eq!(
327 ConcretePol::from_str("thresh(2,older(2147483650),pk(),pk())")
328 .unwrap_err()
329 .to_string(),
330 "locktime value 2147483650 is not a valid BIP68 relative locktime"
331 );
332 }
333
334 #[test]
336 fn heavy_nest() {
337 let policy_string = "thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk()))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))";
338 ConcretePol::from_str(policy_string).unwrap_err();
339 }
340
341 #[test]
342 fn lift_andor() {
343 let key_a: bitcoin::PublicKey =
344 "02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e"
345 .parse()
346 .unwrap();
347 let key_b: bitcoin::PublicKey =
348 "03b506a1dbe57b4bf48c95e0c7d417b87dd3b4349d290d2e7e9ba72c912652d80a"
349 .parse()
350 .unwrap();
351
352 let ms_str: Miniscript<bitcoin::PublicKey, Segwitv0> =
353 format!("andor(multi(1,{}),older(42),c:pk_k({}))", key_a.inner, key_b.inner)
354 .parse()
355 .unwrap();
356 assert_eq!(
357 Semantic::Thresh(Threshold::or(
358 Arc::new(Semantic::Thresh(Threshold::and(
359 Arc::new(Semantic::Key(key_a)),
360 Arc::new(Semantic::Older(RelLockTime::from_height(42)))
361 ))),
362 Arc::new(Semantic::Key(key_b))
363 )),
364 ms_str.lift().unwrap()
365 );
366 }
367
368 #[test]
369 #[cfg(feature = "compiler")]
370 fn taproot_compile() {
371 let unspendable_key: String = "UNSPENDABLE".to_string();
373 {
374 let policy: Concrete<String> = policy_str!("thresh(2,pk(A),pk(B),pk(C),pk(D))");
375 let descriptor = policy.compile_tr(Some(unspendable_key.clone())).unwrap();
376
377 let ms_compilation: Miniscript<String, Tap> = ms_str!("multi_a(2,A,B,C,D)");
378 let tree: TapTree<String> = TapTree::leaf(ms_compilation);
379 let expected_descriptor =
380 Descriptor::new_tr(unspendable_key.clone(), Some(tree)).unwrap();
381 assert_eq!(descriptor, expected_descriptor);
382 }
383
384 {
386 let policy: Concrete<String> = policy_str!("or(and(pk(A),pk(B)),and(pk(C),pk(D)))");
387 let descriptor = policy.compile_tr(Some(unspendable_key.clone())).unwrap();
388
389 let left_ms_compilation: Miniscript<String, Tap> = ms_str!("and_v(v:pk(C),pk(D))");
390 let right_ms_compilation: Miniscript<String, Tap> = ms_str!("and_v(v:pk(A),pk(B))");
391
392 let left = TapTree::leaf(left_ms_compilation);
393 let right = TapTree::leaf(right_ms_compilation);
394 let tree = TapTree::combine(left, right).unwrap();
395
396 let expected_descriptor =
397 Descriptor::new_tr(unspendable_key.clone(), Some(tree)).unwrap();
398 assert_eq!(descriptor, expected_descriptor);
399 }
400
401 {
402 let policy: Concrete<String> = policy_str!("or(and(pk(A),pk(B)),and(pk(A),pk(D)))");
404 let descriptor = policy.compile_tr(Some(unspendable_key.clone()));
405
406 assert_eq!(descriptor.unwrap_err().to_string(), "Policy contains duplicate keys");
407 }
408
409 {
411 let node_policies = [
412 "and(pk(A),pk(B))",
413 "and(pk(C),older(12960))",
414 "pk(D)",
415 "pk(E)",
416 "thresh(3,pk(F),pk(G),pk(H))",
417 "and(and(or(2@pk(I),1@pk(J)),or(1@pk(K),20@pk(L))),pk(M))",
418 "pk(N)",
419 ];
420
421 let node_probabilities: [f64; 7] =
423 [0.12000002, 0.28, 0.08, 0.12, 0.19, 0.18999998, 0.02];
424
425 let policy: Concrete<String> = policy_str!(
426 "{}",
427 &format!(
428 "or(4@or(3@{},7@{}),6@thresh(1,or(4@{},6@{}),{},or(9@{},1@{})))",
429 node_policies[0],
430 node_policies[1],
431 node_policies[2],
432 node_policies[3],
433 node_policies[4],
434 node_policies[5],
435 node_policies[6]
436 )
437 );
438 let descriptor = policy.compile_tr(Some(unspendable_key.clone())).unwrap();
439
440 let mut sorted_policy_prob = node_policies
441 .iter()
442 .zip(node_probabilities.iter())
443 .collect::<Vec<_>>();
444 sorted_policy_prob.sort_by(|a, b| (a.1).partial_cmp(b.1).unwrap());
445 let sorted_policies = sorted_policy_prob
446 .into_iter()
447 .map(|(x, _prob)| x)
448 .collect::<Vec<_>>();
449
450 let node_compilations = sorted_policies
452 .into_iter()
453 .map(|x| {
454 let leaf_policy: Concrete<String> = policy_str!("{}", x);
455 TapTree::leaf(leaf_policy.compile::<Tap>().unwrap())
456 })
457 .collect::<Vec<_>>();
458
459 let tree = TapTree::combine(
461 TapTree::combine(node_compilations[4].clone(), node_compilations[5].clone())
462 .unwrap(),
463 TapTree::combine(
464 TapTree::combine(
465 TapTree::combine(
466 node_compilations[0].clone(),
467 node_compilations[1].clone(),
468 )
469 .unwrap(),
470 node_compilations[3].clone(),
471 )
472 .unwrap(),
473 node_compilations[6].clone(),
474 )
475 .unwrap(),
476 )
477 .unwrap();
478
479 let expected_descriptor = Descriptor::new_tr("E".to_string(), Some(tree)).unwrap();
480 assert_eq!(descriptor, expected_descriptor);
481 }
482 }
483
484 #[test]
485 #[cfg(feature = "compiler")]
486 fn experimental_taproot_compile() {
487 let unspendable_key = "UNSPEND".to_string();
488
489 {
490 let pol = Concrete::<String>::from_str(
491 "thresh(7,pk(A),pk(B),pk(C),pk(D),pk(E),pk(F),pk(G),pk(H))",
492 )
493 .unwrap();
494 let desc = pol
495 .compile_tr_private_experimental(Some(unspendable_key.clone()))
496 .unwrap();
497 let expected_desc = Descriptor::Tr(
498 Tr::<String>::from_str(
499 "tr(UNSPEND ,{
500 {
501 {and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:pk(B),pk(C)),pk(D)),pk(E)),pk(F)),pk(G)),pk(H)),and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:pk(A),pk(C)),pk(D)),pk(E)),pk(F)),pk(G)),pk(H))},
502 {and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:pk(A),pk(B)),pk(D)),pk(E)),pk(F)),pk(G)),pk(H)),and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:pk(A),pk(B)),pk(C)),pk(E)),pk(F)),pk(G)),pk(H))}
503 },
504 {
505 {and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:pk(A),pk(B)),pk(C)),pk(D)),pk(F)),pk(G)),pk(H)),and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:pk(A),pk(B)),pk(C)),pk(D)),pk(E)),pk(G)),pk(H))},
506 {and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:pk(A),pk(B)),pk(C)),pk(D)),pk(E)),pk(F)),pk(H)),and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:and_v(v:pk(A),pk(B)),pk(C)),pk(D)),pk(E)),pk(F)),pk(G))}
507 }})"
508 .replace(&['\t', ' ', '\n'][..], "")
509 .as_str(),
510 )
511 .unwrap(),
512 );
513 assert_eq!(desc, expected_desc);
514 }
515
516 {
517 let pol =
518 Concrete::<String>::from_str("thresh(3,pk(A),pk(B),pk(C),pk(D),pk(E))").unwrap();
519 let desc = pol
520 .compile_tr_private_experimental(Some(unspendable_key.clone()))
521 .unwrap();
522 println!("{}", desc);
523 let expected_desc = Descriptor::Tr(
524 Tr::<String>::from_str(
525 "tr(UNSPEND,
526 {{
527 {and_v(v:and_v(v:pk(A),pk(D)),pk(E)),and_v(v:and_v(v:pk(A),pk(C)),pk(E))},
528 {and_v(v:and_v(v:pk(A),pk(C)),pk(D)),and_v(v:and_v(v:pk(A),pk(B)),pk(E))}
529 },
530 {
531 {and_v(v:and_v(v:pk(A),pk(B)),pk(D)),and_v(v:and_v(v:pk(A),pk(B)),pk(C))},
532 {
533 {and_v(v:and_v(v:pk(C),pk(D)),pk(E)),and_v(v:and_v(v:pk(B),pk(D)),pk(E))},
534 {and_v(v:and_v(v:pk(B),pk(C)),pk(E)),and_v(v:and_v(v:pk(B),pk(C)),pk(D))}
535 }}})"
536 .replace(&['\t', ' ', '\n'][..], "")
537 .as_str(),
538 )
539 .unwrap(),
540 );
541 assert_eq!(desc, expected_desc);
542 }
543 }
544}