elements_miniscript/extensions/
mod.rs

1//! Extensions to elements-miniscript
2//! Users should implement the [`Extension`] trait to extend miniscript to have newer leaf nodes
3//! Look at examples for implementation of ver_eq fragment
4
5use 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
38/// Failed to extract a token from an iterator of tokens
39pub struct FromTokenIterError;
40
41/// Extensions to elements-miniscript.
42/// Refer to implementations(unimplemented!) for example and tutorials
43pub trait Extension: Clone + Eq + Ord + fmt::Debug + fmt::Display + hash::Hash {
44    /// Calculate the correctness property for the leaf fragment.
45    /// See miniscript reference for more info on different types
46    fn corr_prop(&self) -> Correctness;
47
48    /// Calculate the malleability property for the leaf fragment.
49    /// See miniscript reference for more info on different types
50    fn mall_prop(&self) -> Malleability;
51
52    /// Calculate the Extra properties property for the leaf fragment.
53    /// See current implementation for different fragments in extra_props.rs
54    fn extra_prop(&self) -> ExtData;
55
56    /// Get the script size of the current fragment
57    fn script_size(&self) -> usize;
58
59    /// Validity rules for fragment in segwit context
60    fn segwit_ctx_checks(&self) -> Result<(), ScriptContextError>;
61
62    /// Validity rules for fragment in tap context
63    fn tap_ctx_checks(&self) -> Result<(), ScriptContextError> {
64        Ok(())
65    }
66
67    /// Create an instance of this object from a Tree with root name and children as
68    /// `Vec<Tree>`.
69    // Ideally, we would want a FromTree implementation here, but that is not possible
70    // as we would need to create a new Tree by removing wrappers from root.
71    fn from_name_tree(_name: &str, children: &[Tree<'_>]) -> Result<Self, FromTokenIterError>;
72}
73
74/// Support for parsing/serializing/satisfaction of extensions.
75/// [`Extension`] trait reasons about extension in abstract way whereas
76/// this trait reasons about the concrete data structures.
77/// Extension is similar to [`MiniscriptKey`], whereas ParseableExt is similar to
78/// [`ToPublicKey`].
79//
80// Come up with better name for this trait
81pub trait ParseableExt:
82    Extension + Clone + Eq + Ord + fmt::Debug + fmt::Display + hash::Hash
83{
84    /// Parse the terminal from [`TokenIter`]. Implementers of this trait are responsible
85    /// for making sure tokens is mutated correctly. If parsing is not successful, the tokens
86    /// should not be consumed.
87    fn from_token_iter(_tokens: &mut TokenIter<'_>) -> Result<Self, FromTokenIterError>;
88
89    /// Interpreter support
90    /// Evaluate the fragment based on inputs from stack. If an implementation of this
91    /// is provided the user can use the interpreter API to parse scripts from blockchain
92    /// and check which constraints are satisfied
93    /// Output Ok(true) when the ext fragment is satisfied.
94    /// Output Ok(false) when the ext fragment is dissatisfied,
95    /// Output Some(Err) when there is an error in interpreter value.
96    fn evaluate(
97        &self,
98        stack: &mut Stack,
99        txenv: Option<&TxEnv>,
100    ) -> Result<bool, interpreter::Error>;
101
102    /// Encoding of the current fragment
103    fn push_to_builder(&self, builder: Builder) -> Builder;
104
105    /// Produce a satisfaction for this from satisfier.
106    /// See satisfaction code in satisfy.rs for example
107    /// Note that the [`Satisfaction`] struct also covers the case when
108    /// satisfaction is impossible/unavailable
109    fn satisfy<Pk, S>(&self, _sat: &S) -> Satisfaction
110    where
111        Pk: ToPublicKey,
112        S: Satisfier<Pk>;
113
114    /// Produce a satisfaction for this from satisfier.
115    /// See satisfaction code in satisfy.rs for example
116    /// Note that the [`Satisfaction`] struct also covers the case when
117    /// dissatisfaction is impossible/unavailable
118    fn dissatisfy<Pk, S>(&self, _sat: &S) -> Satisfaction
119    where
120        Pk: ToPublicKey,
121        S: Satisfier<Pk>;
122}
123
124/// No Extensions for elements-miniscript
125/// All the implementations for the this function are unreachable
126#[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        // No extensions should not parse any extensions from String
148        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        // No extensions should return Err on parsing
187        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/// All known Extensions for elements-miniscript
219#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
220pub enum CovenantExt<T: ExtParam> {
221    /// Version Equal
222    LegacyVerEq(LegacyVerEq),
223    /// Outputs Prefix equal
224    LegacyOutputsPref(LegacyOutputsPref),
225    /// CSFS
226    Csfs(CheckSigFromStack<T>),
227    /// Arith opcodes
228    Arith(Arith<T>),
229    /// Cov opcodes
230    Introspect(CovOps<T>),
231}
232
233// Apply the function on each arm
234macro_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
246// try all extensions one by one
247// Self::$f(args)
248macro_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/// A satisfier for Covenant descriptors
356/// that can do transaction introspection
357/// 'tx denotes the lifetime of the transaction
358/// being satisfied and 'ptx denotes the lifetime
359/// of the previous transaction inputs
360#[derive(Debug, Clone, PartialEq, Eq)]
361pub struct TxEnv<'tx, 'ptx> {
362    /// The transaction being spent
363    tx: &'tx Transaction,
364    /// Spent utxos
365    spent_utxos: &'ptx [TxOut],
366    /// The input index being spent
367    idx: usize,
368}
369
370impl<'tx, 'ptx> TxEnv<'tx, 'ptx> {
371    /// Returns None when spent_utos.len() != tx.input.len()
372    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    /// Obtains the tx
385    pub fn tx(&self) -> &Transaction {
386        self.tx
387    }
388
389    /// Obtains the spend utxos
390    pub fn spent_utxos(&self) -> &[TxOut] {
391        self.spent_utxos
392    }
393
394    /// Obtains the current input index
395    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
414/// API to check sig from fragment `price_oracle_1`
415pub 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(&timestamp.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
431/// [`secp256k1_zkp::Message`] for fragment `price_oracle_1`.
432/// To be used in for signing with schnorr signatures.
433pub fn sighash_msg_price_oracle_1(timestamp: u64, price: u64) -> secp256k1_zkp::Message {
434    let mut buf = Vec::with_capacity(16);
435    buf.extend(&timestamp.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}