Skip to main content

md_codec/
to_miniscript.rs

1//! v0.32 AST → `miniscript::Descriptor<DescriptorPublicKey>` converter.
2//!
3//! Replaces the v0.14-era hand-rolled 5-shape allow-list with a generic
4//! converter that builds a miniscript `Descriptor` from any
5//! BIP-388-parseable md1 wire AST. Address derivation
6//! ([`crate::Descriptor::derive_address`]) delegates to this module then
7//! to `miniscript::Descriptor::address`.
8//!
9//! Feature-gated behind `derive` (default-on).
10
11use crate::canonicalize::{ExpandedKey, expand_per_at_n};
12use crate::derive::xpub_from_tlv_bytes;
13use crate::encode::Descriptor;
14use crate::error::Error;
15use crate::origin_path::OriginPath;
16use crate::tag::Tag;
17use crate::tree::{Body, Node};
18use crate::use_site_path::UseSitePath;
19
20use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint};
21use miniscript::descriptor::{
22    DescriptorPublicKey, DescriptorXKey, SinglePub, SinglePubKey, Wildcard,
23};
24use miniscript::miniscript::limits::{MAX_PUBKEYS_IN_CHECKSIGADD, MAX_PUBKEYS_PER_MULTISIG};
25use miniscript::{
26    AbsLockTime, Legacy, Miniscript, RelLockTime, ScriptContext, Segwitv0, Tap, Terminal, Threshold,
27};
28use std::str::FromStr;
29use std::sync::Arc;
30
31/// BIP-341 NUMS H-point x-only coordinate. Used as the internal key when
32/// `Body::Tr { is_nums: true, .. }`.
33const NUMS_H_POINT_X_ONLY_HEX: &str =
34    "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0";
35
36/// Convert an md1 [`Descriptor`] AST to a
37/// `miniscript::Descriptor<DescriptorPublicKey>` for `chain` (the
38/// multipath alt selector). The trailing wildcard `/*` remains for
39/// `miniscript::Descriptor::at_derivation_index` to resolve.
40///
41/// `chain` is resolved in-place during key construction (multipath alt
42/// substituted into each `DescriptorXKey.derivation_path`); the resulting
43/// `Descriptor` is single-path.
44///
45/// # Errors
46///
47/// - [`Error::MissingPubkey`] / [`Error::InvalidXpubBytes`] /
48///   [`Error::MissingExplicitOrigin`] propagated from
49///   [`expand_per_at_n`].
50/// - [`Error::AddressDerivationFailed`] wrapping any miniscript-layer
51///   failure (type check, context error, unsupported fragment) or arity
52///   mismatch raised by the converter.
53pub fn to_miniscript_descriptor(
54    d: &Descriptor,
55    chain: u32,
56) -> Result<miniscript::Descriptor<DescriptorPublicKey>, Error> {
57    let expanded = expand_per_at_n(d)?;
58    let mut keys: Vec<DescriptorPublicKey> = Vec::with_capacity(expanded.len());
59    for e in &expanded {
60        keys.push(build_descriptor_public_key(e, &d.use_site_path, chain)?);
61    }
62    node_to_descriptor(&d.tree, &keys)
63}
64
65/// Build a `DescriptorPublicKey::XPub` for one expanded `@N`, with the
66/// chain alt substituted into `derivation_path` in-place.
67fn build_descriptor_public_key(
68    e: &ExpandedKey,
69    use_site: &UseSitePath,
70    chain: u32,
71) -> Result<DescriptorPublicKey, Error> {
72    let xpub_bytes = e.xpub.ok_or(Error::MissingPubkey { idx: e.idx })?;
73    let xkey = xpub_from_tlv_bytes(e.idx, &xpub_bytes)?;
74
75    let origin = e.fingerprint.map(|fp| {
76        (
77            Fingerprint::from(fp),
78            origin_path_to_derivation(&e.origin_path),
79        )
80    });
81
82    // Derivation path is the use-site multipath alt (without the trailing
83    // wildcard, which is handled via `Wildcard::Unhardened`).
84    let derivation_path = use_site_to_derivation_path(use_site, chain)?;
85
86    Ok(DescriptorPublicKey::XPub(DescriptorXKey {
87        origin,
88        xkey,
89        derivation_path,
90        wildcard: Wildcard::Unhardened,
91    }))
92}
93
94/// Translate an `OriginPath` into a `bip32::DerivationPath`.
95fn origin_path_to_derivation(p: &OriginPath) -> DerivationPath {
96    let children: Vec<ChildNumber> = p
97        .components
98        .iter()
99        .map(|c| {
100            if c.hardened {
101                ChildNumber::from_hardened_idx(c.value)
102                    .unwrap_or(ChildNumber::Hardened { index: c.value })
103            } else {
104                ChildNumber::from_normal_idx(c.value)
105                    .unwrap_or(ChildNumber::Normal { index: c.value })
106            }
107        })
108        .collect();
109    DerivationPath::from(children)
110}
111
112/// Build the per-key `derivation_path` from the use-site multipath: a
113/// single `ChildNumber` for `multipath[chain]`, or empty when no
114/// multipath. The trailing `/*` wildcard is encoded via the `wildcard`
115/// field, not the path.
116fn use_site_to_derivation_path(u: &UseSitePath, chain: u32) -> Result<DerivationPath, Error> {
117    let mut comps: Vec<ChildNumber> = Vec::new();
118    if let Some(alts) = &u.multipath {
119        let alt = alts
120            .get(chain as usize)
121            .ok_or(Error::ChainIndexOutOfRange {
122                chain,
123                alt_count: alts.len(),
124            })?;
125        if alt.hardened {
126            return Err(Error::HardenedPublicDerivation);
127        }
128        comps.push(ChildNumber::Normal { index: alt.value });
129    }
130    Ok(DerivationPath::from(comps))
131}
132
133/// Map an md1 top-level tree node onto a `miniscript::Descriptor`.
134fn node_to_descriptor(
135    node: &Node,
136    keys: &[DescriptorPublicKey],
137) -> Result<miniscript::Descriptor<DescriptorPublicKey>, Error> {
138    match (&node.tag, &node.body) {
139        (Tag::Pkh, Body::KeyArg { index }) => {
140            let pk = lookup_key(keys, *index)?;
141            miniscript::Descriptor::new_pkh(pk).map_err(|e| failed(e.to_string()))
142        }
143        (Tag::Wpkh, Body::KeyArg { index }) => {
144            let pk = lookup_key(keys, *index)?;
145            miniscript::Descriptor::new_wpkh(pk).map_err(|e| failed(e.to_string()))
146        }
147        (Tag::Sh, Body::Children(children)) if children.len() == 1 => {
148            sh_inner_to_descriptor(&children[0], keys)
149        }
150        (Tag::Wsh, Body::Children(children)) if children.len() == 1 => {
151            wsh_inner_to_descriptor(&children[0], keys)
152        }
153        (
154            Tag::Tr,
155            Body::Tr {
156                is_nums,
157                key_index,
158                tree,
159            },
160        ) => {
161            let internal_key = if *is_nums {
162                build_nums_internal_key()?
163            } else {
164                lookup_key(keys, *key_index)?
165            };
166            let script_tree = if let Some(t) = tree {
167                Some(tree_to_taptree(t, keys)?)
168            } else {
169                None
170            };
171            miniscript::Descriptor::new_tr(internal_key, script_tree)
172                .map_err(|e| failed(e.to_string()))
173        }
174        _ => Err(failed(format!(
175            "unsupported top-level tag {:?} with body shape",
176            node.tag
177        ))),
178    }
179}
180
181/// Build the NUMS-point `DescriptorPublicKey` (BIP-341 H-point as a
182/// single x-only descriptor key, no origin/path).
183fn build_nums_internal_key() -> Result<DescriptorPublicKey, Error> {
184    let x_only = bitcoin::secp256k1::XOnlyPublicKey::from_str(NUMS_H_POINT_X_ONLY_HEX)
185        .map_err(|e| failed(format!("NUMS x-only parse: {e}")))?;
186    Ok(DescriptorPublicKey::Single(SinglePub {
187        origin: None,
188        key: SinglePubKey::XOnly(x_only),
189    }))
190}
191
192/// Descriptor-level `wsh(...)` inner: choose between
193/// `Descriptor::new_wsh_sortedmulti` and `Descriptor::new_wsh(<Miniscript>)`.
194fn wsh_inner_to_descriptor(
195    inner: &Node,
196    keys: &[DescriptorPublicKey],
197) -> Result<miniscript::Descriptor<DescriptorPublicKey>, Error> {
198    if let (Tag::SortedMulti, Body::MultiKeys { k, indices }) = (&inner.tag, &inner.body) {
199        let thresh = build_multi_threshold::<{ MAX_PUBKEYS_PER_MULTISIG }>(
200            *k,
201            indices,
202            keys,
203            "wsh-sortedmulti",
204        )?;
205        return miniscript::Descriptor::new_wsh_sortedmulti(thresh)
206            .map_err(|e| failed(e.to_string()));
207    }
208    let ms = node_to_miniscript::<Segwitv0>(inner, keys)?;
209    miniscript::Descriptor::new_wsh(ms).map_err(|e| failed(e.to_string()))
210}
211
212/// Descriptor-level `sh(...)` inner: dispatch between `sh(wsh(...))`,
213/// `sh(wpkh(...))`, `sh(sortedmulti(...))`, and `sh(<miniscript>)`
214/// (Legacy context).
215fn sh_inner_to_descriptor(
216    inner: &Node,
217    keys: &[DescriptorPublicKey],
218) -> Result<miniscript::Descriptor<DescriptorPublicKey>, Error> {
219    match (&inner.tag, &inner.body) {
220        (Tag::Wsh, Body::Children(grand)) if grand.len() == 1 => {
221            let grandchild = &grand[0];
222            if let (Tag::SortedMulti, Body::MultiKeys { k, indices }) =
223                (&grandchild.tag, &grandchild.body)
224            {
225                let thresh = build_multi_threshold::<{ MAX_PUBKEYS_PER_MULTISIG }>(
226                    *k,
227                    indices,
228                    keys,
229                    "sh-wsh-sortedmulti",
230                )?;
231                return miniscript::Descriptor::new_sh_wsh_sortedmulti(thresh)
232                    .map_err(|e| failed(e.to_string()));
233            }
234            let ms = node_to_miniscript::<Segwitv0>(grandchild, keys)?;
235            miniscript::Descriptor::new_sh_wsh(ms).map_err(|e| failed(e.to_string()))
236        }
237        (Tag::Wpkh, Body::KeyArg { index }) => {
238            let pk = lookup_key(keys, *index)?;
239            miniscript::Descriptor::new_sh_wpkh(pk).map_err(|e| failed(e.to_string()))
240        }
241        (Tag::SortedMulti, Body::MultiKeys { k, indices }) => {
242            let thresh = build_multi_threshold::<{ MAX_PUBKEYS_PER_MULTISIG }>(
243                *k,
244                indices,
245                keys,
246                "sh-sortedmulti",
247            )?;
248            miniscript::Descriptor::new_sh_sortedmulti(thresh).map_err(|e| failed(e.to_string()))
249        }
250        _ => {
251            let ms = node_to_miniscript::<Legacy>(inner, keys)?;
252            miniscript::Descriptor::new_sh(ms).map_err(|e| failed(e.to_string()))
253        }
254    }
255}
256
257/// Recurse into a tap-script-tree node. Returns a `miniscript::TapTree`.
258fn tree_to_taptree(
259    node: &Node,
260    keys: &[DescriptorPublicKey],
261) -> Result<miniscript::descriptor::TapTree<DescriptorPublicKey>, Error> {
262    if let (Tag::TapTree, Body::Children(children)) = (&node.tag, &node.body) {
263        if children.len() != 2 {
264            return Err(failed(format!(
265                "Tag::TapTree expected 2 children, got {}",
266                children.len()
267            )));
268        }
269        let l = tree_to_taptree(&children[0], keys)?;
270        let r = tree_to_taptree(&children[1], keys)?;
271        return miniscript::descriptor::TapTree::combine(l, r)
272            .map_err(|e| failed(format!("TapTree depth: {e}")));
273    }
274    // Single bare leaf — including the v0.30 single-leaf wire optimization
275    // where `Body::Tr { tree: Some(<bare PkK Node>) }` skips the `Tag::TapTree`
276    // wrap.
277    let ms = node_to_miniscript::<Tap>(node, keys)?;
278    Ok(miniscript::descriptor::TapTree::leaf(Arc::new(ms)))
279}
280
281/// Convert a miniscript-leaf md1 node into a `Miniscript<Pk, Ctx>`.
282fn node_to_miniscript<Ctx>(
283    node: &Node,
284    keys: &[DescriptorPublicKey],
285) -> Result<Miniscript<DescriptorPublicKey, Ctx>, Error>
286where
287    Ctx: ScriptContext,
288{
289    let term: Terminal<DescriptorPublicKey, Ctx> = match (&node.tag, &node.body) {
290        (Tag::PkK, Body::KeyArg { index }) => {
291            // Phase E: bare PkK always emits as Check(pk_k(...)) since
292            // miniscript leaves require a `K` (check'd-key) at any
293            // satisfied position. md1 wire normalises by stripping the
294            // outer `c:` wrapper; re-apply here.
295            let pk = lookup_key(keys, *index)?;
296            let inner = Miniscript::from_ast(Terminal::PkK(pk)).map_err(into_failed)?;
297            Terminal::Check(Arc::new(inner))
298        }
299        (Tag::PkH, Body::KeyArg { index }) => {
300            let pk = lookup_key(keys, *index)?;
301            let inner = Miniscript::from_ast(Terminal::PkH(pk)).map_err(into_failed)?;
302            Terminal::Check(Arc::new(inner))
303        }
304        (Tag::Check, Body::Children(children)) => {
305            arity_eq(node.tag, children.len(), 1)?;
306            // Check-idempotence (`to-miniscript-check-pkh-double-wrap`): a
307            // `Tag::Check` over a BARE key tag denotes the same fragment as the
308            // bare tag — both mean `c:pk_k`/`c:pk_h` (type B), and the PkK/PkH
309            // arms above already re-apply `Check`. Wrapping a second `Check`
310            // yields `Check(Check(PkH))` = `c:` over type-B → "cannot wrap a
311            // fragment of type B". The toolkit walker (non-tap context) and
312            // pre-v0.30 md-cli cards both emit this `Tag::Check(Tag::PkK/PkH)`
313            // wire shape, and such cards are already engraved — the renderer
314            // must accept it. A `Tag::Check` whose child is NOT a bare key
315            // (`Check(Check(..))`, shape C `Check(or_i(pk_k,pk_k))`) still
316            // double-wraps below and correctly errors — never a wrong descriptor.
317            if matches!(
318                (&children[0].tag, &children[0].body),
319                (Tag::PkK | Tag::PkH, Body::KeyArg { .. })
320            ) {
321                return node_to_miniscript::<Ctx>(&children[0], keys);
322            }
323            Terminal::Check(Arc::new(node_to_miniscript::<Ctx>(&children[0], keys)?))
324        }
325        (Tag::Verify, Body::Children(children)) => {
326            arity_eq(node.tag, children.len(), 1)?;
327            Terminal::Verify(Arc::new(node_to_miniscript::<Ctx>(&children[0], keys)?))
328        }
329        (Tag::Swap, Body::Children(children)) => {
330            arity_eq(node.tag, children.len(), 1)?;
331            Terminal::Swap(Arc::new(node_to_miniscript::<Ctx>(&children[0], keys)?))
332        }
333        (Tag::Alt, Body::Children(children)) => {
334            arity_eq(node.tag, children.len(), 1)?;
335            Terminal::Alt(Arc::new(node_to_miniscript::<Ctx>(&children[0], keys)?))
336        }
337        (Tag::DupIf, Body::Children(children)) => {
338            arity_eq(node.tag, children.len(), 1)?;
339            Terminal::DupIf(Arc::new(node_to_miniscript::<Ctx>(&children[0], keys)?))
340        }
341        (Tag::NonZero, Body::Children(children)) => {
342            arity_eq(node.tag, children.len(), 1)?;
343            Terminal::NonZero(Arc::new(node_to_miniscript::<Ctx>(&children[0], keys)?))
344        }
345        (Tag::ZeroNotEqual, Body::Children(children)) => {
346            arity_eq(node.tag, children.len(), 1)?;
347            Terminal::ZeroNotEqual(Arc::new(node_to_miniscript::<Ctx>(&children[0], keys)?))
348        }
349        (Tag::AndV, Body::Children(children)) => {
350            arity_eq(node.tag, children.len(), 2)?;
351            let l = node_to_miniscript::<Ctx>(&children[0], keys)?;
352            let r = node_to_miniscript::<Ctx>(&children[1], keys)?;
353            Terminal::AndV(Arc::new(l), Arc::new(r))
354        }
355        (Tag::AndB, Body::Children(children)) => {
356            arity_eq(node.tag, children.len(), 2)?;
357            let l = node_to_miniscript::<Ctx>(&children[0], keys)?;
358            let r = node_to_miniscript::<Ctx>(&children[1], keys)?;
359            Terminal::AndB(Arc::new(l), Arc::new(r))
360        }
361        (Tag::AndOr, Body::Children(children)) => {
362            arity_eq(node.tag, children.len(), 3)?;
363            let a = node_to_miniscript::<Ctx>(&children[0], keys)?;
364            let b = node_to_miniscript::<Ctx>(&children[1], keys)?;
365            let c = node_to_miniscript::<Ctx>(&children[2], keys)?;
366            Terminal::AndOr(Arc::new(a), Arc::new(b), Arc::new(c))
367        }
368        (Tag::OrB, Body::Children(children)) => {
369            arity_eq(node.tag, children.len(), 2)?;
370            let l = node_to_miniscript::<Ctx>(&children[0], keys)?;
371            let r = node_to_miniscript::<Ctx>(&children[1], keys)?;
372            Terminal::OrB(Arc::new(l), Arc::new(r))
373        }
374        (Tag::OrC, Body::Children(children)) => {
375            arity_eq(node.tag, children.len(), 2)?;
376            let l = node_to_miniscript::<Ctx>(&children[0], keys)?;
377            let r = node_to_miniscript::<Ctx>(&children[1], keys)?;
378            Terminal::OrC(Arc::new(l), Arc::new(r))
379        }
380        (Tag::OrD, Body::Children(children)) => {
381            arity_eq(node.tag, children.len(), 2)?;
382            let l = node_to_miniscript::<Ctx>(&children[0], keys)?;
383            let r = node_to_miniscript::<Ctx>(&children[1], keys)?;
384            Terminal::OrD(Arc::new(l), Arc::new(r))
385        }
386        (Tag::OrI, Body::Children(children)) => {
387            arity_eq(node.tag, children.len(), 2)?;
388            let l = node_to_miniscript::<Ctx>(&children[0], keys)?;
389            let r = node_to_miniscript::<Ctx>(&children[1], keys)?;
390            Terminal::OrI(Arc::new(l), Arc::new(r))
391        }
392        (Tag::Thresh, Body::Variable { k, children }) => {
393            let mut subs: Vec<Arc<Miniscript<DescriptorPublicKey, Ctx>>> =
394                Vec::with_capacity(children.len());
395            for c in children {
396                subs.push(Arc::new(node_to_miniscript::<Ctx>(c, keys)?));
397            }
398            let thresh =
399                Threshold::<_, 0>::new(*k as usize, subs).map_err(|e| failed(e.to_string()))?;
400            Terminal::Thresh(thresh)
401        }
402        (Tag::Multi, Body::MultiKeys { k, indices }) => {
403            // `Terminal::Multi` is `Ctx`-generic at the variant level;
404            // rust-miniscript's `Miniscript::from_ast` enforces context-
405            // appropriateness (rejects Multi inside Tap, MultiA inside
406            // Segwitv0) via `check_global_consensus_validity`.
407            let thresh =
408                build_multi_threshold::<{ MAX_PUBKEYS_PER_MULTISIG }>(*k, indices, keys, "multi")?;
409            Terminal::Multi(thresh)
410        }
411        (Tag::MultiA, Body::MultiKeys { k, indices }) => {
412            let thresh = build_multi_threshold::<{ MAX_PUBKEYS_IN_CHECKSIGADD }>(
413                *k, indices, keys, "multi_a",
414            )?;
415            Terminal::MultiA(thresh)
416        }
417        (Tag::SortedMulti, Body::MultiKeys { .. }) => {
418            return Err(failed(
419                "Tag::SortedMulti must be the sole child of wsh/sh; cannot appear as a miniscript leaf"
420                    .to_string(),
421            ));
422        }
423        (Tag::SortedMultiA, Body::MultiKeys { .. }) => {
424            return Err(failed(
425                "Tag::SortedMultiA must be a tap-leaf root child; rust-miniscript v13 has no Terminal::SortedMultiA fragment"
426                    .to_string(),
427            ));
428        }
429        (Tag::After, Body::Timelock(v)) => {
430            let lt = AbsLockTime::from_consensus(*v).map_err(|e| failed(e.to_string()))?;
431            Terminal::After(lt)
432        }
433        (Tag::Older, Body::Timelock(v)) => {
434            let lt = RelLockTime::from_consensus(*v).map_err(|e| failed(e.to_string()))?;
435            Terminal::Older(lt)
436        }
437        (Tag::Sha256, Body::Hash256Body(h)) => {
438            let hash = sha256_from_bytes(h)?;
439            Terminal::Sha256(hash)
440        }
441        (Tag::Hash256, Body::Hash256Body(h)) => {
442            let hash = hash256_from_bytes(h)?;
443            Terminal::Hash256(hash)
444        }
445        (Tag::Ripemd160, Body::Hash160Body(h)) => {
446            let hash = ripemd160_from_bytes(h)?;
447            Terminal::Ripemd160(hash)
448        }
449        (Tag::Hash160, Body::Hash160Body(h)) => {
450            let hash = hash160_from_bytes(h)?;
451            Terminal::Hash160(hash)
452        }
453        (Tag::RawPkH, Body::Hash160Body(_)) => {
454            return Err(failed(
455                "Tag::RawPkH is not constructible through miniscript's public API".to_string(),
456            ));
457        }
458        (Tag::False, Body::Empty) => Terminal::False,
459        (Tag::True, Body::Empty) => Terminal::True,
460        (Tag::TapTree, _) => {
461            return Err(failed(
462                "Tag::TapTree is a tap-tree internal node, not a miniscript leaf".to_string(),
463            ));
464        }
465        (Tag::Tr, _) | (Tag::Wsh, _) | (Tag::Sh, _) | (Tag::Wpkh, _) | (Tag::Pkh, _) => {
466            return Err(failed(format!(
467                "top-level wrapper {:?} cannot appear inside a miniscript context",
468                node.tag
469            )));
470        }
471        _ => {
472            return Err(failed(format!(
473                "tag {:?} unsupported with body shape",
474                node.tag
475            )));
476        }
477    };
478    Miniscript::from_ast(term).map_err(into_failed)
479}
480
481fn lookup_key(keys: &[DescriptorPublicKey], idx: u8) -> Result<DescriptorPublicKey, Error> {
482    keys.get(idx as usize)
483        .cloned()
484        .ok_or_else(|| failed(format!("@{idx} out of range")))
485}
486
487fn build_multi_threshold<const MAX: usize>(
488    k: u8,
489    indices: &[u8],
490    keys: &[DescriptorPublicKey],
491    label: &str,
492) -> Result<Threshold<DescriptorPublicKey, MAX>, Error> {
493    let pks: Vec<DescriptorPublicKey> = indices
494        .iter()
495        .map(|i| lookup_key(keys, *i))
496        .collect::<Result<_, _>>()?;
497    Threshold::<DescriptorPublicKey, MAX>::new(k as usize, pks)
498        .map_err(|e| failed(format!("{label} threshold: {e}")))
499}
500
501fn arity_eq(tag: Tag, got: usize, expected: usize) -> Result<(), Error> {
502    if got != expected {
503        return Err(failed(format!(
504            "{tag:?} expected {expected} children, got {got}"
505        )));
506    }
507    Ok(())
508}
509
510fn failed(detail: String) -> Error {
511    Error::AddressDerivationFailed { detail }
512}
513
514fn into_failed(e: miniscript::Error) -> Error {
515    failed(e.to_string())
516}
517
518// ─── Pk::Sha256 / Pk::Hash256 / Pk::Ripemd160 / Pk::Hash160 construction ─
519
520fn sha256_from_bytes(h: &[u8; 32]) -> Result<bitcoin::hashes::sha256::Hash, Error> {
521    use bitcoin::hashes::Hash;
522    Ok(bitcoin::hashes::sha256::Hash::from_byte_array(*h))
523}
524
525fn hash256_from_bytes(h: &[u8; 32]) -> Result<miniscript::hash256::Hash, Error> {
526    use bitcoin::hashes::Hash;
527    Ok(miniscript::hash256::Hash::from_byte_array(*h))
528}
529
530fn ripemd160_from_bytes(h: &[u8; 20]) -> Result<bitcoin::hashes::ripemd160::Hash, Error> {
531    use bitcoin::hashes::Hash;
532    Ok(bitcoin::hashes::ripemd160::Hash::from_byte_array(*h))
533}
534
535fn hash160_from_bytes(h: &[u8; 20]) -> Result<bitcoin::hashes::hash160::Hash, Error> {
536    use bitcoin::hashes::Hash;
537    Ok(bitcoin::hashes::hash160::Hash::from_byte_array(*h))
538}