1use std::{fmt, hash};
6
7use bitcoin::hashes::Hash;
8use elements::script::Builder;
9use elements::{secp256k1_zkp, Transaction, TxOut};
10
11use crate::expression::Tree;
12use crate::interpreter::{self, Stack};
13use crate::miniscript::context::ScriptContextError;
14use crate::miniscript::lex::TokenIter;
15use crate::miniscript::satisfy::Satisfaction;
16use crate::miniscript::types::{Correctness, ExtData, Malleability};
17use crate::policy::Liftable;
18use crate::{policy, Error, ExtTranslator, MiniscriptKey, Satisfier, ToPublicKey, TranslateExt};
19
20#[allow(unused_imports)]
21mod arith;
22mod csfs;
23mod index_ops;
24mod introspect_ops;
25mod outputs_pref;
26pub mod param;
27mod tx_ver;
28
29pub use arith::{Arith, EvalError, Expr, ExprInner};
30pub use csfs::{CheckSigFromStack, CsfsKey, CsfsMsg};
31pub use index_ops::IdxExpr;
32pub use introspect_ops::{AssetExpr, CovOps, Spk, SpkExpr, ValueExpr};
33
34pub use self::outputs_pref::LegacyOutputsPref;
35pub use self::param::{ArgFromStr, CovExtArgs, ExtParam, NoExtParam};
36pub use self::tx_ver::LegacyVerEq;
37
38pub struct FromTokenIterError;
40
41pub trait Extension: Clone + Eq + Ord + fmt::Debug + fmt::Display + hash::Hash {
44 fn corr_prop(&self) -> Correctness;
47
48 fn mall_prop(&self) -> Malleability;
51
52 fn extra_prop(&self) -> ExtData;
55
56 fn script_size(&self) -> usize;
58
59 fn segwit_ctx_checks(&self) -> Result<(), ScriptContextError>;
61
62 fn tap_ctx_checks(&self) -> Result<(), ScriptContextError> {
64 Ok(())
65 }
66
67 fn from_name_tree(_name: &str, children: &[Tree<'_>]) -> Result<Self, FromTokenIterError>;
72}
73
74pub trait ParseableExt:
82 Extension + Clone + Eq + Ord + fmt::Debug + fmt::Display + hash::Hash
83{
84 fn from_token_iter(_tokens: &mut TokenIter<'_>) -> Result<Self, FromTokenIterError>;
88
89 fn evaluate(
97 &self,
98 stack: &mut Stack,
99 txenv: Option<&TxEnv>,
100 ) -> Result<bool, interpreter::Error>;
101
102 fn push_to_builder(&self, builder: Builder) -> Builder;
104
105 fn satisfy<Pk, S>(&self, _sat: &S) -> Satisfaction
110 where
111 Pk: ToPublicKey,
112 S: Satisfier<Pk>;
113
114 fn dissatisfy<Pk, S>(&self, _sat: &S) -> Satisfaction
119 where
120 Pk: ToPublicKey,
121 S: Satisfier<Pk>;
122}
123
124#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
127pub enum NoExt {}
128
129impl Extension for NoExt {
130 fn corr_prop(&self) -> Correctness {
131 match *self {}
132 }
133
134 fn mall_prop(&self) -> Malleability {
135 match *self {}
136 }
137
138 fn extra_prop(&self) -> ExtData {
139 match *self {}
140 }
141
142 fn script_size(&self) -> usize {
143 match *self {}
144 }
145
146 fn from_name_tree(_name: &str, _children: &[Tree<'_>]) -> Result<Self, FromTokenIterError> {
147 Err(FromTokenIterError)
149 }
150
151 fn segwit_ctx_checks(&self) -> Result<(), ScriptContextError> {
152 Ok(())
153 }
154}
155
156impl ParseableExt for NoExt {
157 fn satisfy<Pk, S>(&self, _sat: &S) -> Satisfaction
158 where
159 Pk: ToPublicKey,
160 S: Satisfier<Pk>,
161 {
162 match *self {}
163 }
164
165 fn dissatisfy<Pk, S>(&self, _sat: &S) -> Satisfaction
166 where
167 Pk: ToPublicKey,
168 S: Satisfier<Pk>,
169 {
170 match *self {}
171 }
172
173 fn evaluate(
174 &self,
175 _stack: &mut Stack,
176 _txenv: Option<&TxEnv>,
177 ) -> Result<bool, interpreter::Error> {
178 match *self {}
179 }
180
181 fn push_to_builder(&self, _builder: Builder) -> Builder {
182 match *self {}
183 }
184
185 fn from_token_iter(_tokens: &mut TokenIter<'_>) -> Result<Self, FromTokenIterError> {
186 Err(FromTokenIterError)
188 }
189}
190
191impl<Pk: MiniscriptKey> Liftable<Pk> for NoExt {
192 fn lift(&self) -> Result<policy::Semantic<Pk>, Error> {
193 match *self {}
194 }
195}
196
197impl fmt::Display for NoExt {
198 fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 match *self {}
200 }
201}
202
203impl<PExt, QExt> TranslateExt<PExt, QExt> for NoExt
204where
205 PExt: Extension,
206 QExt: Extension,
207{
208 type Output = NoExt;
209
210 fn translate_ext<T, E>(&self, _t: &mut T) -> Result<Self::Output, E>
211 where
212 T: ExtTranslator<PExt, QExt, E>,
213 {
214 match *self {}
215 }
216}
217
218#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
220pub enum CovenantExt<T: ExtParam> {
221 LegacyVerEq(LegacyVerEq),
223 LegacyOutputsPref(LegacyOutputsPref),
225 Csfs(CheckSigFromStack<T>),
227 Arith(Arith<T>),
229 Introspect(CovOps<T>),
231}
232
233macro_rules! all_arms_fn {
235 ($slf: ident, $trt: ident, $f: ident, $($args:ident, )* ) => {
236 match $slf {
237 CovenantExt::LegacyVerEq(v) => <LegacyVerEq as $trt>::$f(v, $($args, )*),
238 CovenantExt::LegacyOutputsPref(p) => <LegacyOutputsPref as $trt>::$f(p, $($args, )*),
239 CovenantExt::Csfs(csfs) => csfs.$f($($args, )*),
240 CovenantExt::Arith(e) => e.$f($($args, )*),
241 CovenantExt::Introspect(e) => e.$f($($args, )*),
242 }
243 };
244}
245
246macro_rules! try_from_arms {
249 ( $trt: ident, $ext_arg: ident, $f: ident, $($args: ident, )*) => {
250 if let Ok(v) = <LegacyVerEq as $trt>::$f($($args, )*) {
251 Ok(CovenantExt::LegacyVerEq(v))
252 } else if let Ok(v) = <LegacyOutputsPref as $trt>::$f($($args, )*) {
253 Ok(CovenantExt::LegacyOutputsPref(v))
254 } else if let Ok(v) = <CheckSigFromStack<$ext_arg> as $trt>::$f($($args, )*) {
255 Ok(CovenantExt::Csfs(v))
256 } else if let Ok(v) = <Arith<$ext_arg> as $trt>::$f($($args, )*) {
257 Ok(CovenantExt::Arith(v))
258 } else if let Ok(v) = <CovOps<$ext_arg> as $trt>::$f($($args, )*) {
259 Ok(CovenantExt::Introspect(v))
260 }else {
261 Err(FromTokenIterError)
262 }
263 };
264}
265
266impl<T: ExtParam> Extension for CovenantExt<T> {
267 fn corr_prop(&self) -> Correctness {
268 all_arms_fn!(self, Extension, corr_prop,)
269 }
270
271 fn mall_prop(&self) -> Malleability {
272 all_arms_fn!(self, Extension, mall_prop,)
273 }
274
275 fn extra_prop(&self) -> ExtData {
276 all_arms_fn!(self, Extension, extra_prop,)
277 }
278
279 fn script_size(&self) -> usize {
280 all_arms_fn!(self, Extension, script_size,)
281 }
282
283 fn from_name_tree(name: &str, children: &[Tree<'_>]) -> Result<Self, FromTokenIterError> {
284 try_from_arms!(Extension, T, from_name_tree, name, children,)
285 }
286
287 fn segwit_ctx_checks(&self) -> Result<(), ScriptContextError> {
288 all_arms_fn!(self, Extension, segwit_ctx_checks,)
289 }
290}
291
292impl ParseableExt for CovenantExt<CovExtArgs> {
293 fn satisfy<Pk, S>(&self, sat: &S) -> Satisfaction
294 where
295 Pk: ToPublicKey,
296 S: Satisfier<Pk>,
297 {
298 all_arms_fn!(self, ParseableExt, satisfy, sat,)
299 }
300
301 fn dissatisfy<Pk, S>(&self, sat: &S) -> Satisfaction
302 where
303 Pk: ToPublicKey,
304 S: Satisfier<Pk>,
305 {
306 all_arms_fn!(self, ParseableExt, dissatisfy, sat,)
307 }
308
309 fn evaluate(
310 &self,
311 stack: &mut Stack,
312 txenv: Option<&TxEnv>,
313 ) -> Result<bool, interpreter::Error> {
314 all_arms_fn!(self, ParseableExt, evaluate, stack, txenv,)
315 }
316
317 fn push_to_builder(&self, builder: Builder) -> Builder {
318 all_arms_fn!(self, ParseableExt, push_to_builder, builder,)
319 }
320
321 fn from_token_iter(tokens: &mut TokenIter<'_>) -> Result<Self, FromTokenIterError> {
322 try_from_arms!(ParseableExt, CovExtArgs, from_token_iter, tokens,)
323 }
324}
325
326impl<T: ExtParam> fmt::Display for CovenantExt<T> {
327 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
328 match self {
329 CovenantExt::LegacyVerEq(v) => v.fmt(f),
330 CovenantExt::LegacyOutputsPref(p) => p.fmt(f),
331 CovenantExt::Csfs(c) => c.fmt(f),
332 CovenantExt::Arith(e) => e.fmt(f),
333 CovenantExt::Introspect(e) => e.fmt(f),
334 }
335 }
336}
337
338impl<PArg, QArg> TranslateExt<CovenantExt<PArg>, CovenantExt<QArg>> for CovenantExt<PArg>
339where
340 CovenantExt<PArg>: Extension,
341 CovenantExt<QArg>: Extension,
342 PArg: ExtParam,
343 QArg: ExtParam,
344{
345 type Output = CovenantExt<QArg>;
346
347 fn translate_ext<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
348 where
349 T: ExtTranslator<CovenantExt<PArg>, CovenantExt<QArg>, E>,
350 {
351 t.ext(self)
352 }
353}
354
355#[derive(Debug, Clone, PartialEq, Eq)]
361pub struct TxEnv<'tx, 'ptx> {
362 tx: &'tx Transaction,
364 spent_utxos: &'ptx [TxOut],
366 idx: usize,
368}
369
370impl<'tx, 'ptx> TxEnv<'tx, 'ptx> {
371 pub fn new(tx: &'tx Transaction, spent_utxos: &'ptx [TxOut], idx: usize) -> Option<Self> {
373 if tx.input.len() != spent_utxos.len() {
374 None
375 } else {
376 Some(Self {
377 tx,
378 spent_utxos,
379 idx,
380 })
381 }
382 }
383
384 pub fn tx(&self) -> &Transaction {
386 self.tx
387 }
388
389 pub fn spent_utxos(&self) -> &[TxOut] {
391 self.spent_utxos
392 }
393
394 pub fn idx(&self) -> usize {
396 self.idx
397 }
398}
399
400impl<'tx, 'ptx, Pk: ToPublicKey> Satisfier<Pk> for TxEnv<'tx, 'ptx> {
401 fn lookup_tx(&self) -> Option<&elements::Transaction> {
402 Some(self.tx)
403 }
404
405 fn lookup_spent_utxos(&self) -> Option<&[elements::TxOut]> {
406 Some(self.spent_utxos)
407 }
408
409 fn lookup_curr_inp(&self) -> Option<usize> {
410 Some(self.idx)
411 }
412}
413
414pub fn check_sig_price_oracle_1<C: secp256k1_zkp::Verification>(
416 secp: &secp256k1_zkp::Secp256k1<C>,
417 sig: &elements::secp256k1_zkp::schnorr::Signature,
418 pk: &elements::secp256k1_zkp::XOnlyPublicKey,
419 timestamp: u64,
420 price: u64,
421) -> bool {
422 let mut buf = Vec::with_capacity(16);
423 buf.extend(×tamp.to_le_bytes());
424 buf.extend(&price.to_le_bytes());
425 let sha_msg = elements::hashes::sha256::Hash::hash(&buf);
426
427 let msg = elements::secp256k1_zkp::Message::from_digest_slice(&sha_msg[..]).unwrap();
428 secp.verify_schnorr(sig, &msg, pk).is_ok()
429}
430
431pub fn sighash_msg_price_oracle_1(timestamp: u64, price: u64) -> secp256k1_zkp::Message {
434 let mut buf = Vec::with_capacity(16);
435 buf.extend(×tamp.to_le_bytes());
436 buf.extend(&price.to_le_bytes());
437 let sha_msg = elements::hashes::sha256::Hash::hash(&buf);
438
439 elements::secp256k1_zkp::Message::from_digest_slice(&sha_msg[..]).unwrap()
440}