simplicity/node/
mod.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Simplicity Program Nodes
4//!
5//! The types in this module are used to represent Simplicity expressions as
6//! DAGs. The nodes of this DAG are individual combinators along with some
7//! cached data about the node, which depends on the specific node type.
8//!
9//! All nodes represent the root of an expression. Expressions whose source
10//! and target types are both unit are called "programs". Generally speaking,
11//! any nodes that users hold directly will be programs.
12//!
13//! There are three main node types:
14//!
15//! 1. [`crate::RedeemNode`] represents a Simplicity node as it exists on the blockchain.
16//!    Every witness node is populated with a correctly-typed [`Value`], every
17//!    disconnect node has a child, every non-executed branch of a `case` combinator
18//!    is pruned, and there is nothing you can do to modify the expression.
19//!
20//!    `RedeemNode`s can be executed on the bit machine and have complete types
21//!    and resource bounds, and can be serialized in the consensus bit-encoding.
22//!
23//! 2. [`CommitNode`] represents a Simplicity node as it is *committed to* on
24//!    the blockchain. This means that witness and (TODO) disconnect nodes are not
25//!    populated, but type inference is complete and resource bounds are
26//!    available. `case` combinators may have pruned children (in which case they
27//!    are instead considered `assertl` or `assertr` combinators), or not.
28//!
29//!    There is a bit-encoding for `CommitNode`s which is essentially only used
30//!    by this library. It consists of the bit-encoding.of the combinators, fully
31//!    shared *except* that witness and disconnect nodes (and their ancestors)
32//!    are unshared. No witness data is included.
33//!
34//!    TODO there is also a human-readable encoding.
35//!
36//! 3. [`ConstructNode`] represents an "under-construction" Simplicity expression.
37//!    These nodes' types are not necessarily complete, and are inferred as the
38//!    program is constructed. This is the only node that you can programmatically
39//!    construct. It has no encoding, human-readable or bitwise, and is intended
40//!    to exist only ephemerally.
41//!
42//! The following conversions are possible between the node types:
43//!
44//! 1. [`ConstructNode::finalize_types`] converts a [`ConstructNode`] to a
45//!    [`CommitNode`] by setting any free variables, as well as the source and
46//!    target of the root node, to unit.
47//!
48//!    This conversion requires no input from the user but may fail with a type
49//!    error, in case of infinitely-sized types or in the case that the unit
50//!    bounds cannot be applied.
51//!
52//! 2. [`CommitNode::finalize`] converts a [`CommitNode`] to a [`RedeemNode`]
53//!    by attaching witnesses to each witness node, and deciding whether to hide
54//!    branches for each `case` node.
55//!
56//! 3. [`CommitNode::unfinalize_types`] converts a [`CommitNode`] to a
57//!    [`ConstructNode`] by throwing away all types and re-inferring them. It
58//!    cannot fail.
59//!
60//! 4. [`RedeemNode::unfinalize`] converts a [`RedeemNode`] to a [`CommitNode`]
61//!    by throwing away witness and (TODO) disconnect data. It cannot recover
62//!    pruned branches so is of limited usefulness, but it is included for
63//!    completeness.
64//!
65
66use crate::dag::{DagLike, MaxSharing, SharingTracker};
67use crate::jet::Jet;
68use crate::{types, Cmr, FailEntropy, HasCmr, Value};
69
70use std::sync::Arc;
71use std::{fmt, hash};
72
73mod commit;
74mod construct;
75mod convert;
76mod disconnect;
77mod display;
78mod hiding;
79mod inner;
80mod redeem;
81
82use crate::value::Word;
83pub use commit::{Commit, CommitData, CommitNode};
84pub use construct::{Construct, ConstructData, ConstructNode};
85pub use convert::{Converter, Hide, SimpleFinalizer};
86pub use disconnect::{Disconnectable, NoDisconnect};
87use display::DisplayExpr;
88pub use hiding::Hiding;
89pub use inner::Inner;
90pub use redeem::{Redeem, RedeemData, RedeemNode};
91
92// This trait should only be implemented on empty types, so we can demand
93// every trait bound under the sun. Doing so will make #[derive]s easier
94// for downstream users.
95pub trait Marker:
96    Copy + Clone + PartialEq + Eq + PartialOrd + Ord + fmt::Debug + hash::Hash
97{
98    /// Precomputed data about the node, such as its type arrow or various Merkle roots.
99    type CachedData: Clone;
100
101    /// Type of witness data attached to DAGs of this node type. Typically either [`Value`]
102    /// or [`NoWitness`].
103    type Witness: Clone;
104
105    /// Type of disconnect data attached to DAGs of this node type.
106    type Disconnect: Disconnectable<Node<Self>> + Clone;
107
108    /// A type which uniquely identifies a node, for purposes of sharing
109    /// during iteration over the DAG.
110    type SharingId: hash::Hash + Clone + Eq;
111
112    /// The jet catalogue used with this node type.
113    type Jet: Jet;
114
115    /// Yields the sharing ID for a given type, starting from its CMR and its cached data.
116    ///
117    /// If the type cannot be uniquely identified (e.g. because it is missing data), then
118    /// this method returns `None`. In this case, the node will not be shared with any
119    /// other node.
120    fn compute_sharing_id(cmr: Cmr, cached_data: &Self::CachedData) -> Option<Self::SharingId>;
121}
122
123/// Null data type used as dummy for [`Marker::Witness`]
124#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
125pub struct NoWitness;
126
127pub trait Constructible<J, X, W>:
128    JetConstructible<J>
129    + DisconnectConstructible<X>
130    + WitnessConstructible<W>
131    + CoreConstructible
132    + Sized
133{
134    fn from_inner(
135        inference_context: &types::Context,
136        inner: Inner<&Self, J, &X, W>,
137    ) -> Result<Self, types::Error> {
138        match inner {
139            Inner::Iden => Ok(Self::iden(inference_context)),
140            Inner::Unit => Ok(Self::unit(inference_context)),
141            Inner::InjL(child) => Ok(Self::injl(child)),
142            Inner::InjR(child) => Ok(Self::injr(child)),
143            Inner::Take(child) => Ok(Self::take(child)),
144            Inner::Drop(child) => Ok(Self::drop_(child)),
145            Inner::Comp(left, right) => Self::comp(left, right),
146            Inner::Case(left, right) => Self::case(left, right),
147            Inner::AssertL(left, r_cmr) => Self::assertl(left, r_cmr),
148            Inner::AssertR(l_cmr, right) => Self::assertr(l_cmr, right),
149            Inner::Pair(left, right) => Self::pair(left, right),
150            Inner::Disconnect(left, right) => Self::disconnect(left, right),
151            Inner::Fail(entropy) => Ok(Self::fail(inference_context, entropy)),
152            Inner::Word(ref w) => Ok(Self::const_word(inference_context, w.shallow_clone())),
153            Inner::Jet(j) => Ok(Self::jet(inference_context, j)),
154            Inner::Witness(w) => Ok(Self::witness(inference_context, w)),
155        }
156    }
157}
158
159impl<J, X, W, T> Constructible<J, X, W> for T where
160    T: DisconnectConstructible<X>
161        + JetConstructible<J>
162        + WitnessConstructible<W>
163        + CoreConstructible
164        + Sized
165{
166}
167
168pub trait CoreConstructible: Sized {
169    fn iden(inference_context: &types::Context) -> Self;
170    fn unit(inference_context: &types::Context) -> Self;
171    fn injl(child: &Self) -> Self;
172    fn injr(child: &Self) -> Self;
173    fn take(child: &Self) -> Self;
174    fn drop_(child: &Self) -> Self;
175    fn comp(left: &Self, right: &Self) -> Result<Self, types::Error>;
176    fn case(left: &Self, right: &Self) -> Result<Self, types::Error>;
177    fn assertl(left: &Self, right: Cmr) -> Result<Self, types::Error>;
178    fn assertr(left: Cmr, right: &Self) -> Result<Self, types::Error>;
179    fn pair(left: &Self, right: &Self) -> Result<Self, types::Error>;
180    fn fail(inference_context: &types::Context, entropy: FailEntropy) -> Self;
181    fn const_word(inference_context: &types::Context, word: Word) -> Self;
182
183    /// Accessor for the type inference context used to create the object.
184    fn inference_context(&self) -> &types::Context;
185
186    /// Create an expression that produces the given `value`.
187    ///
188    /// The expression is minimized by using as many word jets as possible.
189    fn scribe(ctx: &types::Context, value: &Value) -> Self {
190        use crate::value::ValueRef;
191
192        #[derive(Debug, Clone)]
193        enum Task<'v> {
194            Process(ValueRef<'v>),
195            MakeLeft,
196            MakeRight,
197            MakeProduct,
198        }
199
200        let mut input = vec![Task::Process(value.as_ref())];
201        let mut output = vec![];
202        while let Some(top) = input.pop() {
203            match top {
204                Task::Process(value) => {
205                    if value.is_unit() {
206                        output.push(Self::unit(ctx));
207                    } else if let Some(word) = value.to_word() {
208                        output.push(Self::const_word(ctx, word));
209                    } else if let Some(left) = value.as_left() {
210                        input.push(Task::MakeLeft);
211                        input.push(Task::Process(left));
212                    } else if let Some(right) = value.as_right() {
213                        input.push(Task::MakeRight);
214                        input.push(Task::Process(right));
215                    } else if let Some((left, right)) = value.as_product() {
216                        input.push(Task::MakeProduct);
217                        input.push(Task::Process(right));
218                        input.push(Task::Process(left));
219                    }
220                }
221                Task::MakeLeft => {
222                    let inner = output.pop().unwrap();
223                    output.push(Self::injl(&inner));
224                }
225                Task::MakeRight => {
226                    let inner = output.pop().unwrap();
227                    output.push(Self::injr(&inner));
228                }
229                Task::MakeProduct => {
230                    let right = output.pop().unwrap();
231                    let left = output.pop().unwrap();
232                    // simfony::PairBuilder would remove this `.expect()` call
233                    output.push(
234                        Self::pair(&left, &right).expect(
235                            "`pair` should always succeed because input type is unrestricted",
236                        ),
237                    );
238                }
239            }
240        }
241        debug_assert_eq!(output.len(), 1);
242        output.pop().unwrap()
243    }
244
245    /// Create a DAG that takes any input and returns bit `0` as constant output.
246    ///
247    /// _Overall type: A → 2_
248    fn bit_false(inference_context: &types::Context) -> Self {
249        let unit = Self::unit(inference_context);
250        Self::injl(&unit)
251    }
252
253    /// Create a DAG that takes any input and returns bit `1` as constant output.
254    ///
255    /// _Overall type: A → 2_
256    fn bit_true(inference_context: &types::Context) -> Self {
257        let unit = Self::unit(inference_context);
258        Self::injr(&unit)
259    }
260
261    /// Create a DAG that takes a bit and an input,
262    /// such that the `left` child is evaluated on the input if the bit is `1` _(if branch)_
263    /// and the `right` child is evaluated on the input otherwise _(else branch)_.
264    ///
265    /// _Overall type: 2 × A → B where `left`: A → B and `right`: A → B_
266    ///
267    /// _Type inference will fail if children are not of the correct type._
268    fn cond(left: &Self, right: &Self) -> Result<Self, types::Error> {
269        let drop_left = Self::drop_(left);
270        let drop_right = Self::drop_(right);
271        Self::case(&drop_right, &drop_left)
272    }
273
274    /// Create a DAG that asserts that its child returns `true`, and fails otherwise.
275    /// The `hash` identifies the assertion and is returned upon failure.
276    ///
277    /// _Overall type: A → 1 where `child`: A → 2_
278    ///
279    /// _Type inference will fail if children are not of the correct type._
280    fn assert(child: &Self, hash: Cmr) -> Result<Self, types::Error> {
281        let unit = Self::unit(child.inference_context());
282        let pair_child_unit = Self::pair(child, &unit)?;
283        let assertr_hidden_unit = Self::assertr(hash, &unit)?;
284
285        Self::comp(&pair_child_unit, &assertr_hidden_unit)
286    }
287
288    /// Create a DAG that computes Boolean _NOT_ of the `child`.
289    ///
290    /// _Overall type: A → 2 where `child`: A → 2_
291    ///
292    /// _Type inference will fail if children are not of the correct type._
293    #[allow(clippy::should_implement_trait)]
294    fn not(child: &Self) -> Result<Self, types::Error> {
295        let unit = Self::unit(child.inference_context());
296        let pair_child_unit = Self::pair(child, &unit)?;
297        let bit_true = Self::bit_true(child.inference_context());
298        let bit_false = Self::bit_false(child.inference_context());
299        let case_true_false = Self::case(&bit_true, &bit_false)?;
300
301        Self::comp(&pair_child_unit, &case_true_false)
302    }
303
304    /// Create a DAG that computes Boolean _AND_ of the `left` and `right` child.
305    ///
306    /// _Overall type: A → 2 where `left`: A → 2 and `right`: A → 2_
307    ///
308    /// _Type inference will fail if children are not of the correct type._
309    fn and(left: &Self, right: &Self) -> Result<Self, types::Error> {
310        left.inference_context()
311            .check_eq(right.inference_context())?;
312        let iden = Self::iden(left.inference_context());
313        let pair_left_iden = Self::pair(left, &iden)?;
314        let bit_false = Self::bit_false(left.inference_context());
315        let drop_right = Self::drop_(right);
316        let case_false_right = Self::case(&bit_false, &drop_right)?;
317
318        Self::comp(&pair_left_iden, &case_false_right)
319    }
320
321    /// Create a DAG that computes Boolean _OR_ of the `left` and `right`.
322    ///
323    /// _Overall type: A → 2 where `left`: A → 2 and `right`: A → 2_
324    ///
325    /// _Type inference will fail if children are not of the correct type._
326    fn or(left: &Self, right: &Self) -> Result<Self, types::Error> {
327        left.inference_context()
328            .check_eq(right.inference_context())?;
329        let iden = Self::iden(left.inference_context());
330        let pair_left_iden = Self::pair(left, &iden)?;
331        let drop_right = Self::drop_(right);
332        let bit_true = Self::bit_true(left.inference_context());
333        let case_right_true = Self::case(&drop_right, &bit_true)?;
334
335        Self::comp(&pair_left_iden, &case_right_true)
336    }
337}
338
339pub trait DisconnectConstructible<X>: Sized {
340    fn disconnect(left: &Self, right: &X) -> Result<Self, types::Error>;
341}
342
343pub trait JetConstructible<J>: Sized {
344    fn jet(inference_context: &types::Context, jet: J) -> Self;
345}
346
347pub trait WitnessConstructible<W>: Sized {
348    fn witness(inference_context: &types::Context, witness: W) -> Self;
349}
350
351/// A node in a Simplicity expression.
352///
353/// There are three node types provided by this library: `ConstructNode`, `CommitNode`,
354/// and `RedeemNode`, which represent Simplicty programs during construction, at
355/// commitment time, and at redemption time, respectively.
356///
357/// This generic structure is used to define conversions and mapping functions over
358/// nodes and DAGs, and allows users to define their own custom node types.
359///
360/// For equality and hashing purposes, nodes are characterized entirely by their
361/// CMR and cached data. Users who create custom nodes should define a custom type
362/// for [`Marker::CachedData`] and think carefully about whether and how to
363/// implement the [`std::hash::Hash`] or equality traits.
364pub struct Node<N: Marker> {
365    inner: Inner<Arc<Node<N>>, N::Jet, N::Disconnect, N::Witness>,
366    cmr: Cmr,
367    data: N::CachedData,
368}
369
370impl<N: Marker> PartialEq for Node<N>
371where
372    N::CachedData: PartialEq,
373{
374    fn eq(&self, other: &Self) -> bool {
375        self.cmr == other.cmr && self.data == other.data
376    }
377}
378impl<N: Marker> Eq for Node<N> where N::CachedData: Eq {}
379
380impl<N: Marker> hash::Hash for Node<N>
381where
382    N::CachedData: hash::Hash,
383{
384    fn hash<H: hash::Hasher>(&self, h: &mut H) {
385        self.cmr.hash(h);
386        self.data.hash(h);
387    }
388}
389
390impl<N: Marker> fmt::Debug for Node<N>
391where
392    for<'a> &'a Node<N>: DagLike,
393{
394    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
395        fmt::Display::fmt(self, f)
396    }
397}
398
399impl<N: Marker> fmt::Display for Node<N>
400where
401    for<'a> &'a Node<N>: DagLike,
402{
403    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404        self.post_order_iter::<MaxSharing<N>>().into_display(
405            f,
406            |node, f| fmt::Display::fmt(&node.inner, f),
407            |_, _| Ok(()),
408        )
409    }
410}
411
412impl<N: Marker> HasCmr for Node<N> {
413    fn cmr(&self) -> Cmr {
414        self.cmr
415    }
416}
417
418impl<N: Marker> HasCmr for Arc<Node<N>> {
419    fn cmr(&self) -> Cmr {
420        self.cmr
421    }
422}
423
424impl<N> CoreConstructible for Arc<Node<N>>
425where
426    N: Marker,
427    N::CachedData: CoreConstructible,
428{
429    fn iden(inference_context: &types::Context) -> Self {
430        Arc::new(Node {
431            cmr: Cmr::iden(),
432            data: N::CachedData::iden(inference_context),
433            inner: Inner::Iden,
434        })
435    }
436
437    fn unit(inference_context: &types::Context) -> Self {
438        Arc::new(Node {
439            cmr: Cmr::unit(),
440            data: N::CachedData::unit(inference_context),
441            inner: Inner::Unit,
442        })
443    }
444
445    fn injl(child: &Self) -> Self {
446        Arc::new(Node {
447            cmr: Cmr::injl(child.cmr()),
448            data: N::CachedData::injl(&child.data),
449            inner: Inner::InjL(Arc::clone(child)),
450        })
451    }
452
453    fn injr(child: &Self) -> Self {
454        Arc::new(Node {
455            cmr: Cmr::injr(child.cmr()),
456            data: N::CachedData::injr(&child.data),
457            inner: Inner::InjR(Arc::clone(child)),
458        })
459    }
460
461    fn take(child: &Self) -> Self {
462        Arc::new(Node {
463            cmr: Cmr::take(child.cmr()),
464            data: N::CachedData::take(&child.data),
465            inner: Inner::Take(Arc::clone(child)),
466        })
467    }
468
469    fn drop_(child: &Self) -> Self {
470        Arc::new(Node {
471            cmr: Cmr::drop(child.cmr()),
472            data: N::CachedData::drop_(&child.data),
473            inner: Inner::Drop(Arc::clone(child)),
474        })
475    }
476
477    fn comp(left: &Self, right: &Self) -> Result<Self, types::Error> {
478        Ok(Arc::new(Node {
479            cmr: Cmr::comp(left.cmr(), right.cmr()),
480            data: N::CachedData::comp(&left.data, &right.data)?,
481            inner: Inner::Comp(Arc::clone(left), Arc::clone(right)),
482        }))
483    }
484
485    fn case(left: &Self, right: &Self) -> Result<Self, types::Error> {
486        Ok(Arc::new(Node {
487            cmr: Cmr::case(left.cmr(), right.cmr()),
488            data: N::CachedData::case(&left.data, &right.data)?,
489            inner: Inner::Case(Arc::clone(left), Arc::clone(right)),
490        }))
491    }
492
493    fn assertl(left: &Self, r_cmr: Cmr) -> Result<Self, types::Error> {
494        Ok(Arc::new(Node {
495            cmr: Cmr::case(left.cmr(), r_cmr),
496            data: N::CachedData::assertl(&left.data, r_cmr)?,
497            inner: Inner::AssertL(Arc::clone(left), r_cmr),
498        }))
499    }
500
501    fn assertr(l_cmr: Cmr, right: &Self) -> Result<Self, types::Error> {
502        Ok(Arc::new(Node {
503            cmr: Cmr::case(l_cmr, right.cmr()),
504            data: N::CachedData::assertr(l_cmr, &right.data)?,
505            inner: Inner::AssertR(l_cmr, Arc::clone(right)),
506        }))
507    }
508
509    fn pair(left: &Self, right: &Self) -> Result<Self, types::Error> {
510        Ok(Arc::new(Node {
511            cmr: Cmr::pair(left.cmr(), right.cmr()),
512            data: N::CachedData::pair(&left.data, &right.data)?,
513            inner: Inner::Pair(Arc::clone(left), Arc::clone(right)),
514        }))
515    }
516
517    fn fail(inference_context: &types::Context, entropy: FailEntropy) -> Self {
518        Arc::new(Node {
519            cmr: Cmr::fail(entropy),
520            data: N::CachedData::fail(inference_context, entropy),
521            inner: Inner::Fail(entropy),
522        })
523    }
524
525    fn const_word(inference_context: &types::Context, word: Word) -> Self {
526        Arc::new(Node {
527            cmr: Cmr::const_word(&word),
528            data: N::CachedData::const_word(inference_context, word.shallow_clone()),
529            inner: Inner::Word(word),
530        })
531    }
532
533    fn inference_context(&self) -> &types::Context {
534        self.data.inference_context()
535    }
536}
537
538impl<N> DisconnectConstructible<N::Disconnect> for Arc<Node<N>>
539where
540    N: Marker,
541    N::CachedData: DisconnectConstructible<N::Disconnect>,
542{
543    fn disconnect(left: &Self, right: &N::Disconnect) -> Result<Self, types::Error> {
544        Ok(Arc::new(Node {
545            cmr: Cmr::disconnect(left.cmr()),
546            data: N::CachedData::disconnect(&left.data, right)?,
547            inner: Inner::Disconnect(Arc::clone(left), right.clone()),
548        }))
549    }
550}
551
552impl<N> WitnessConstructible<N::Witness> for Arc<Node<N>>
553where
554    N: Marker,
555    N::CachedData: WitnessConstructible<N::Witness>,
556{
557    fn witness(inference_context: &types::Context, value: N::Witness) -> Self {
558        Arc::new(Node {
559            cmr: Cmr::witness(),
560            data: N::CachedData::witness(inference_context, value.clone()),
561            inner: Inner::Witness(value),
562        })
563    }
564}
565
566impl<N> JetConstructible<N::Jet> for Arc<Node<N>>
567where
568    N: Marker,
569    N::CachedData: JetConstructible<N::Jet>,
570{
571    fn jet(inference_context: &types::Context, jet: N::Jet) -> Self {
572        Arc::new(Node {
573            cmr: Cmr::jet(jet),
574            data: N::CachedData::jet(inference_context, jet),
575            inner: Inner::Jet(jet),
576        })
577    }
578}
579
580impl<N: Marker> Node<N> {
581    /// Accessor for the node's "inner value", i.e. its combinator
582    pub fn inner(&self) -> &Inner<Arc<Node<N>>, N::Jet, N::Disconnect, N::Witness> {
583        &self.inner
584    }
585
586    /// Accessor for the node's CMR
587    pub fn cmr(&self) -> Cmr {
588        self.cmr
589    }
590
591    /// Accessor for the node's cached data
592    pub fn sharing_id(&self) -> Option<N::SharingId> {
593        N::compute_sharing_id(self.cmr, &self.data)
594    }
595
596    /// Accessor for the node's cached data
597    pub fn cached_data(&self) -> &N::CachedData {
598        &self.data
599    }
600
601    /// Contruct a node from its constituent parts.
602    ///
603    /// This method can be used to directly costruct a node. It will compute the CMR
604    /// automatically based on the value of `inner` but requires that `cached_data`
605    /// be provided.
606    ///
607    /// If available, [`Constructible'] and its dependent traits will be easier to
608    /// use.
609    pub fn from_parts(
610        inner: Inner<Arc<Self>, N::Jet, N::Disconnect, N::Witness>,
611        data: N::CachedData,
612    ) -> Self {
613        let cmr = match inner {
614            Inner::Unit => Cmr::unit(),
615            Inner::Iden => Cmr::iden(),
616            Inner::InjL(ref c) => Cmr::injl(c.cmr()),
617            Inner::InjR(ref c) => Cmr::injr(c.cmr()),
618            Inner::Take(ref c) => Cmr::take(c.cmr()),
619            Inner::Drop(ref c) => Cmr::drop(c.cmr()),
620            Inner::Comp(ref cl, ref cr) => Cmr::comp(cl.cmr(), cr.cmr()),
621            Inner::Case(ref cl, ref cr) => Cmr::case(cl.cmr(), cr.cmr()),
622            Inner::AssertL(ref c, cmr) => Cmr::case(c.cmr(), cmr),
623            Inner::AssertR(cmr, ref c) => Cmr::case(cmr, c.cmr()),
624            Inner::Pair(ref cl, ref cr) => Cmr::pair(cl.cmr(), cr.cmr()),
625            Inner::Disconnect(ref cl, _) => Cmr::disconnect(cl.cmr()),
626            Inner::Witness(_) => Cmr::witness(),
627            Inner::Fail(entropy) => Cmr::fail(entropy),
628            Inner::Jet(j) => Cmr::jet(j),
629            Inner::Word(ref w) => Cmr::const_word(w),
630        };
631
632        Node { cmr, inner, data }
633    }
634
635    /// Generic conversion function from one type of node to another, with the
636    /// ability to prune during the conversion.
637    ///
638    /// Parameterized over what kind of sharing to use when iterating over the
639    /// DAG, and what conversion logic to use.
640    ///
641    /// See the documentation for [`Converter`] for details.
642    pub fn convert<S, M, C>(&self, converter: &mut C) -> Result<Arc<Node<M>>, C::Error>
643    where
644        S: for<'a> SharingTracker<&'a Self> + Default,
645        M: Marker<Jet = <N as Marker>::Jet>,
646        C: Converter<N, M>,
647    {
648        let mut converted: Vec<Arc<Node<M>>> = vec![];
649        for data in self.post_order_iter::<S>() {
650            // First, tell the converter about the iterator state..
651            converter.visit_node(&data);
652
653            // Construct an Inner<usize> where pointers are replaced by indices.
654            // Note that `map_left_right`'s internal logic will ensure that these
655            // `unwrap`s are only called when they will succeed.
656            let indexed_inner: Inner<usize, N::Jet, &N::Disconnect, &N::Witness> = data
657                .node
658                .inner
659                .as_ref()
660                .map_left_right(|_| data.left_index.unwrap(), |_| data.right_index.unwrap());
661
662            // Then, convert witness data, if this is a witness node.
663            let witness_inner: Inner<&usize, M::Jet, &&N::Disconnect, M::Witness> = indexed_inner
664                .as_ref()
665                .map_witness_result(|wit| converter.convert_witness(&data, wit))?;
666
667            // Then convert disconnect nodes data.
668            let maybe_converted = data.right_index.map(|idx| &converted[idx]);
669            let witness_inner: Inner<&usize, N::Jet, M::Disconnect, M::Witness> = witness_inner
670                .map_disconnect_result(|disc| {
671                    converter.convert_disconnect(&data, maybe_converted, disc)
672                })?;
673
674            // Then put the converted nodes in place (it's easier to do this in this
675            // order because of the way the reference types work out).
676            let converted_inner: Inner<Arc<Node<M>>, M::Jet, M::Disconnect, M::Witness> =
677                witness_inner.map(|idx| Arc::clone(&converted[*idx]));
678
679            // Next, prune case nodes into asserts, if applicable
680            let pruned_inner = if let Inner::Case(left, right) = converted_inner {
681                let hide = converter.prune_case(&data, &left, &right)?;
682
683                match hide {
684                    Hide::Neither => Inner::Case(left, right),
685                    Hide::Left => Inner::AssertR(left.cmr(), right),
686                    Hide::Right => Inner::AssertL(left, right.cmr()),
687                }
688            } else {
689                converted_inner
690            };
691
692            // Finally, construct the node
693            converted.push(Arc::new(Node {
694                data: converter.convert_data(&data, pruned_inner.as_ref())?,
695                cmr: data.node.cmr,
696                inner: pruned_inner,
697            }));
698        }
699        Ok(converted.pop().unwrap())
700    }
701
702    /// Display the Simplicity expression as a linear string.
703    ///
704    /// The linear string has no sharing and may be **exponentially larger**
705    /// than the originally shared expression!
706    pub fn display_expr(&self) -> DisplayExpr<N> {
707        DisplayExpr::from(self)
708    }
709}
710
711#[cfg(test)]
712#[cfg(all(feature = "test-utils", feature = "elements"))]
713mod tests {
714
715    use ffi::tests::TestData;
716
717    use crate::analysis::Cost;
718    use crate::ffi;
719    use crate::jet::Elements;
720    use crate::BitIter;
721    use crate::RedeemNode;
722
723    fn check_merkle_roots(test: &TestData) {
724        let prog = BitIter::from(test.prog.as_slice());
725        let witness = BitIter::from(test.witness.as_slice());
726        ffi::tests::run_program(&test.prog, &test.witness, ffi::tests::TestUpTo::CheckOneOne)
727            .unwrap();
728        let prog = RedeemNode::<Elements>::decode(prog, witness).unwrap();
729        assert_eq!(prog.cmr().to_byte_array(), test.cmr);
730        assert_eq!(prog.amr().to_byte_array(), test.amr);
731        assert_eq!(prog.ihr().to_byte_array(), test.ihr);
732        assert_eq!(prog.bounds().cost, Cost::from_milliweight(test.cost))
733    }
734
735    #[test]
736    fn progs_cmr() {
737        let schnorr0 = ffi::tests::schnorr0_test_data();
738        let schnorr6 = ffi::tests::schnorr6_test_data();
739        let ctx8_unpruned = ffi::tests::ctx8_unpruned_test_data();
740        let ctx8_pruned = ffi::tests::ctx8_pruned_test_data();
741        // check_merkle_roots(&hash_block); Need 1 -> 1 for now.
742        check_merkle_roots(&schnorr0);
743        check_merkle_roots(&schnorr6);
744        check_merkle_roots(&ctx8_unpruned);
745        check_merkle_roots(&ctx8_pruned);
746    }
747}