miniscript_debug/miniscript/
iter.rs

1// Miniscript
2// Written in 2020 by
3//     Dr Maxim Orlovsky <orlovsky@pandoracore.com>
4//
5// To the extent possible under law, the author(s) have dedicated all
6// copyright and related and neighboring rights to this software to
7// the public domain worldwide. This software is distributed without
8// any warranty.
9//
10// You should have received a copy of the CC0 Public Domain Dedication
11// along with this software.
12// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13//
14
15//! Miniscript Iterators
16//!
17//! Iterators for Miniscript with special functions for iterating
18//! over Public Keys, Public Key Hashes or both.
19use core::ops::Deref;
20
21use sync::Arc;
22
23use super::decode::Terminal;
24use super::{Miniscript, MiniscriptKey, ScriptContext};
25use crate::prelude::*;
26
27/// Iterator-related extensions for [Miniscript]
28impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
29    /// Creates a new [Iter] iterator that will iterate over all [Miniscript] items within
30    /// AST by traversing its branches. For the specific algorithm please see
31    /// [Iter::next] function.
32    pub fn iter(&self) -> Iter<Pk, Ctx> {
33        Iter::new(self)
34    }
35
36    /// Creates a new [PkIter] iterator that will iterate over all plain public keys (and not
37    /// key hash values) present in [Miniscript] items within AST by traversing all its branches.
38    /// For the specific algorithm please see [PkIter::next] function.
39    pub fn iter_pk(&self) -> PkIter<Pk, Ctx> {
40        PkIter::new(self)
41    }
42
43    /// Enumerates all child nodes of the current AST node (`self`) and returns a `Vec` referencing
44    /// them.
45    pub fn branches(&self) -> Vec<&Miniscript<Pk, Ctx>> {
46        match self.node {
47            Terminal::PkK(_) | Terminal::PkH(_) | Terminal::RawPkH(_) | Terminal::Multi(_, _) => {
48                vec![]
49            }
50
51            Terminal::Alt(ref node)
52            | Terminal::Swap(ref node)
53            | Terminal::Check(ref node)
54            | Terminal::DupIf(ref node)
55            | Terminal::Verify(ref node)
56            | Terminal::NonZero(ref node)
57            | Terminal::ZeroNotEqual(ref node) => vec![node],
58
59            Terminal::AndV(ref node1, ref node2)
60            | Terminal::AndB(ref node1, ref node2)
61            | Terminal::OrB(ref node1, ref node2)
62            | Terminal::OrD(ref node1, ref node2)
63            | Terminal::OrC(ref node1, ref node2)
64            | Terminal::OrI(ref node1, ref node2) => vec![node1, node2],
65
66            Terminal::AndOr(ref node1, ref node2, ref node3) => vec![node1, node2, node3],
67
68            Terminal::Thresh(_, ref node_vec) => node_vec.iter().map(Arc::deref).collect(),
69
70            _ => vec![],
71        }
72    }
73
74    /// Returns child node with given index, if any
75    pub fn get_nth_child(&self, n: usize) -> Option<&Miniscript<Pk, Ctx>> {
76        match (n, &self.node) {
77            (0, &Terminal::Alt(ref node))
78            | (0, &Terminal::Swap(ref node))
79            | (0, &Terminal::Check(ref node))
80            | (0, &Terminal::DupIf(ref node))
81            | (0, &Terminal::Verify(ref node))
82            | (0, &Terminal::NonZero(ref node))
83            | (0, &Terminal::ZeroNotEqual(ref node))
84            | (0, &Terminal::AndV(ref node, _))
85            | (0, &Terminal::AndB(ref node, _))
86            | (0, &Terminal::OrB(ref node, _))
87            | (0, &Terminal::OrD(ref node, _))
88            | (0, &Terminal::OrC(ref node, _))
89            | (0, &Terminal::OrI(ref node, _))
90            | (1, &Terminal::AndV(_, ref node))
91            | (1, &Terminal::AndB(_, ref node))
92            | (1, &Terminal::OrB(_, ref node))
93            | (1, &Terminal::OrD(_, ref node))
94            | (1, &Terminal::OrC(_, ref node))
95            | (1, &Terminal::OrI(_, ref node))
96            | (0, &Terminal::AndOr(ref node, _, _))
97            | (1, &Terminal::AndOr(_, ref node, _))
98            | (2, &Terminal::AndOr(_, _, ref node)) => Some(node),
99
100            (n, &Terminal::Thresh(_, ref node_vec)) => node_vec.get(n).map(|x| &**x),
101
102            _ => None,
103        }
104    }
105
106    /// Returns `Option::Some` with cloned n'th public key from the current miniscript item,
107    /// if any. Otherwise returns `Option::None`.
108    ///
109    /// NB: The function analyzes only single miniscript item and not any of its descendants in AST.
110    pub fn get_nth_pk(&self, n: usize) -> Option<Pk> {
111        match (&self.node, n) {
112            (&Terminal::PkK(ref key), 0) | (&Terminal::PkH(ref key), 0) => Some(key.clone()),
113            (&Terminal::Multi(_, ref keys), _) | (&Terminal::MultiA(_, ref keys), _) => {
114                keys.get(n).cloned()
115            }
116            _ => None,
117        }
118    }
119}
120
121/// Iterator for traversing all [Miniscript] miniscript AST references starting from some specific
122/// node which constructs the iterator via [Miniscript::iter] method.
123pub struct Iter<'a, Pk: MiniscriptKey, Ctx: ScriptContext> {
124    next: Option<&'a Miniscript<Pk, Ctx>>,
125    // Here we store vec of path elements, where each element is a tuple, consisting of:
126    // 1. Miniscript node on the path
127    // 2. Index of the current branch
128    path: Vec<(&'a Miniscript<Pk, Ctx>, usize)>,
129}
130
131impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iter<'a, Pk, Ctx> {
132    fn new(miniscript: &'a Miniscript<Pk, Ctx>) -> Self {
133        Iter {
134            next: Some(miniscript),
135            path: vec![],
136        }
137    }
138}
139
140impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for Iter<'a, Pk, Ctx> {
141    type Item = &'a Miniscript<Pk, Ctx>;
142
143    /// First, the function returns `self`, then the first child of the self (if any),
144    /// then proceeds to the child of the child — down to a leaf of the tree in its first branch.
145    /// When the leaf is reached, it goes in the reverse direction on the same branch until it
146    /// founds a first branching node that had more than a single branch and returns it, traversing
147    /// it with the same algorithm again.
148    ///
149    /// For example, for the given AST
150    /// ```text
151    /// A --+--> B -----> C --+--> D -----> E
152    ///     |                 |
153    ///     |                 +--> F
154    ///     |                 |
155    ///     |                 +--> G --+--> H
156    ///     |                          |
157    ///     |                          +--> I -----> J
158    ///     +--> K
159    /// ```
160    /// `Iter::next()` will iterate over the nodes in the following order:
161    /// `A > B > C > D > E > F > G > H > I > J > K`
162    ///
163    /// To enumerate the branches iterator uses [Miniscript::branches] function.
164    fn next(&mut self) -> Option<Self::Item> {
165        let mut curr = self.next;
166        if curr.is_none() {
167            while let Some((node, child)) = self.path.pop() {
168                curr = node.get_nth_child(child);
169                if curr.is_some() {
170                    self.path.push((node, child + 1));
171                    break;
172                }
173            }
174        }
175        if let Some(node) = curr {
176            self.next = node.get_nth_child(0);
177            self.path.push((node, 1));
178        }
179        curr
180    }
181}
182
183/// Iterator for traversing all [MiniscriptKey]'s in AST starting from some specific node which
184/// constructs the iterator via [Miniscript::iter_pk] method.
185pub struct PkIter<'a, Pk: MiniscriptKey, Ctx: ScriptContext> {
186    node_iter: Iter<'a, Pk, Ctx>,
187    curr_node: Option<&'a Miniscript<Pk, Ctx>>,
188    key_index: usize,
189}
190
191impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> PkIter<'a, Pk, Ctx> {
192    fn new(miniscript: &'a Miniscript<Pk, Ctx>) -> Self {
193        let mut iter = Iter::new(miniscript);
194        PkIter {
195            curr_node: iter.next(),
196            node_iter: iter,
197            key_index: 0,
198        }
199    }
200}
201
202impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for PkIter<'a, Pk, Ctx> {
203    type Item = Pk;
204
205    fn next(&mut self) -> Option<Self::Item> {
206        loop {
207            match self.curr_node {
208                None => break None,
209                Some(node) => match node.get_nth_pk(self.key_index) {
210                    None => {
211                        self.curr_node = self.node_iter.next();
212                        self.key_index = 0;
213                        continue;
214                    }
215                    Some(pk) => {
216                        self.key_index += 1;
217                        break Some(pk);
218                    }
219                },
220            }
221        }
222    }
223}
224
225// Module is public since it export testcase generation which may be used in
226// dependent libraries for their own tasts based on Miniscript AST
227#[cfg(test)]
228pub mod test {
229    use bitcoin;
230    use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
231    use bitcoin::secp256k1;
232
233    use super::Miniscript;
234    use crate::miniscript::context::Segwitv0;
235
236    pub type TestData = (
237        Miniscript<bitcoin::PublicKey, Segwitv0>,
238        Vec<bitcoin::PublicKey>,
239        Vec<hash160::Hash>,
240        bool, // Indicates that the top-level contains public key or hashes
241    );
242
243    pub fn gen_secp_pubkeys(n: usize) -> Vec<secp256k1::PublicKey> {
244        let mut ret = Vec::with_capacity(n);
245        let secp = secp256k1::Secp256k1::new();
246        let mut sk = [0; 32];
247
248        for i in 1..n + 1 {
249            sk[0] = i as u8;
250            sk[1] = (i >> 8) as u8;
251            sk[2] = (i >> 16) as u8;
252
253            ret.push(secp256k1::PublicKey::from_secret_key(
254                &secp,
255                &secp256k1::SecretKey::from_slice(&sk[..]).unwrap(),
256            ));
257        }
258        ret
259    }
260
261    pub fn gen_bitcoin_pubkeys(n: usize, compressed: bool) -> Vec<bitcoin::PublicKey> {
262        gen_secp_pubkeys(n)
263            .into_iter()
264            .map(|inner| bitcoin::PublicKey { inner, compressed })
265            .collect()
266    }
267
268    pub fn gen_testcases() -> Vec<TestData> {
269        let k = gen_bitcoin_pubkeys(10, true);
270        let _h: Vec<hash160::Hash> = k
271            .iter()
272            .map(|pk| hash160::Hash::hash(&pk.to_bytes()))
273            .collect();
274
275        let preimage = vec![0xab as u8; 32];
276        let sha256_hash = sha256::Hash::hash(&preimage);
277        let sha256d_hash_rev = sha256d::Hash::hash(&preimage);
278        let mut sha256d_hash_bytes = sha256d_hash_rev.clone().into_inner();
279        sha256d_hash_bytes.reverse();
280        let sha256d_hash = sha256d::Hash::from_inner(sha256d_hash_bytes);
281        let hash160_hash = hash160::Hash::hash(&preimage);
282        let ripemd160_hash = ripemd160::Hash::hash(&preimage);
283
284        vec![
285            (ms_str!("after({})", 1000), vec![], vec![], false),
286            (ms_str!("older({})", 1000), vec![], vec![], false),
287            (ms_str!("sha256({})", sha256_hash), vec![], vec![], false),
288            (ms_str!("hash256({})", sha256d_hash), vec![], vec![], false),
289            (ms_str!("hash160({})", hash160_hash), vec![], vec![], false),
290            (
291                ms_str!("ripemd160({})", ripemd160_hash),
292                vec![],
293                vec![],
294                false,
295            ),
296            (ms_str!("c:pk_k({})", k[0]), vec![k[0]], vec![], true),
297            (ms_str!("c:pk_h({})", k[0]), vec![k[0]], vec![], true),
298            (
299                ms_str!("and_v(vc:pk_k({}),c:pk_h({}))", k[0], k[1]),
300                vec![k[0], k[1]],
301                vec![],
302                false,
303            ),
304            (
305                ms_str!("and_b(c:pk_k({}),sjtv:sha256({}))", k[0], sha256_hash),
306                vec![k[0]],
307                vec![],
308                false,
309            ),
310            (
311                ms_str!(
312                    "andor(c:pk_k({}),jtv:sha256({}),c:pk_h({}))",
313                    k[1],
314                    sha256_hash,
315                    k[2]
316                ),
317                vec![k[1], k[2]],
318                vec![],
319                false,
320            ),
321            (
322                ms_str!("multi(3,{},{},{},{},{})", k[9], k[8], k[7], k[0], k[1]),
323                vec![k[9], k[8], k[7], k[0], k[1]],
324                vec![],
325                true,
326            ),
327            (
328                ms_str!(
329                    "thresh(3,c:pk_k({}),sc:pk_k({}),sc:pk_k({}),sc:pk_k({}),sc:pk_k({}))",
330                    k[2],
331                    k[3],
332                    k[4],
333                    k[5],
334                    k[6]
335                ),
336                vec![k[2], k[3], k[4], k[5], k[6]],
337                vec![],
338                false,
339            ),
340            (
341                ms_str!(
342                    "or_d(multi(2,{},{}),and_v(v:multi(2,{},{}),older(10000)))",
343                    k[6],
344                    k[7],
345                    k[8],
346                    k[9]
347                ),
348                vec![k[6], k[7], k[8], k[9]],
349                vec![],
350                false,
351            ),
352            (
353                ms_str!(
354                    "or_d(multi(3,{},{},{},{},{}),\
355                      and_v(v:thresh(2,c:pk_h({}),\
356                      ac:pk_h({}),ac:pk_h({})),older(10000)))",
357                    k[0],
358                    k[2],
359                    k[4],
360                    k[6],
361                    k[9],
362                    k[1],
363                    k[3],
364                    k[5]
365                ),
366                vec![k[0], k[2], k[4], k[6], k[9], k[1], k[3], k[5]],
367                vec![],
368                false,
369            ),
370        ]
371    }
372
373    #[test]
374    fn find_keys() {
375        gen_testcases().into_iter().for_each(|(ms, k, _, _)| {
376            assert_eq!(ms.iter_pk().collect::<Vec<bitcoin::PublicKey>>(), k);
377        })
378    }
379}