Skip to main content

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::encode;
68use crate::jet::Jet;
69use crate::{types, BitWriter, Cmr, FailEntropy, HasCmr, Value};
70
71use std::sync::Arc;
72use std::{fmt, hash, io};
73
74mod commit;
75mod construct;
76mod convert;
77mod disconnect;
78mod display;
79mod hiding;
80mod inner;
81mod redeem;
82
83use crate::value::Word;
84pub use commit::{Commit, CommitData, CommitNode};
85pub use construct::{Construct, ConstructData, ConstructNode};
86pub use convert::{Converter, Hide, SimpleFinalizer};
87pub use disconnect::{Disconnectable, NoDisconnect};
88pub use display::{Display, DisplayAsGraph, DisplayExpr, GraphFormat, SharingLevel};
89pub use hiding::Hiding;
90pub use inner::Inner;
91pub use redeem::{Redeem, RedeemData, RedeemNode};
92
93// This trait should only be implemented on empty types, so we can demand
94// every trait bound under the sun. Doing so will make #[derive]s easier
95// for downstream users.
96pub trait Marker:
97    Copy + Clone + PartialEq + Eq + PartialOrd + Ord + fmt::Debug + hash::Hash
98{
99    /// Precomputed data about the node, such as its type arrow or various Merkle roots.
100    type CachedData: Clone;
101
102    /// Type of witness data attached to DAGs of this node type. Typically either [`Value`]
103    /// or [`NoWitness`].
104    type Witness: Clone;
105
106    /// Type of disconnect data attached to DAGs of this node type.
107    type Disconnect: Disconnectable<Node<Self>> + Clone;
108
109    /// A type which uniquely identifies a node, for purposes of sharing
110    /// during iteration over the DAG.
111    type SharingId: hash::Hash + Clone + Eq;
112
113    /// Yields the sharing ID for a given type, starting from its CMR and its cached data.
114    ///
115    /// If the type cannot be uniquely identified (e.g. because it is missing data), then
116    /// this method returns `None`. In this case, the node will not be shared with any
117    /// other node.
118    fn compute_sharing_id(cmr: Cmr, cached_data: &Self::CachedData) -> Option<Self::SharingId>;
119}
120
121/// Null data type used as dummy for [`Marker::Witness`]
122#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
123pub struct NoWitness;
124
125impl From<NoWitness> for Option<Value> {
126    fn from(_: NoWitness) -> Self {
127        None
128    }
129}
130
131pub trait Constructible<'brand, X, W>:
132    JetConstructible<'brand>
133    + DisconnectConstructible<'brand, X>
134    + WitnessConstructible<'brand, W>
135    + CoreConstructible<'brand>
136    + Sized
137{
138    fn from_inner(
139        inference_context: &types::Context<'brand>,
140        inner: Inner<&Self, &X, W>,
141    ) -> Result<Self, types::Error> {
142        match inner {
143            Inner::Iden => Ok(Self::iden(inference_context)),
144            Inner::Unit => Ok(Self::unit(inference_context)),
145            Inner::InjL(child) => Ok(Self::injl(child)),
146            Inner::InjR(child) => Ok(Self::injr(child)),
147            Inner::Take(child) => Ok(Self::take(child)),
148            Inner::Drop(child) => Ok(Self::drop_(child)),
149            Inner::Comp(left, right) => Self::comp(left, right),
150            Inner::Case(left, right) => Self::case(left, right),
151            Inner::AssertL(left, r_cmr) => Self::assertl(left, r_cmr),
152            Inner::AssertR(l_cmr, right) => Self::assertr(l_cmr, right),
153            Inner::Pair(left, right) => Self::pair(left, right),
154            Inner::Disconnect(left, right) => Self::disconnect(left, right),
155            Inner::Fail(entropy) => Ok(Self::fail(inference_context, entropy)),
156            Inner::Word(ref w) => Ok(Self::const_word(inference_context, w.shallow_clone())),
157            Inner::Jet(j) => Ok(Self::jet(inference_context, j.as_ref())),
158            Inner::Witness(w) => Ok(Self::witness(inference_context, w)),
159        }
160    }
161}
162
163impl<'brand, X, W, T> Constructible<'brand, X, W> for T where
164    T: DisconnectConstructible<'brand, X>
165        + JetConstructible<'brand>
166        + WitnessConstructible<'brand, W>
167        + CoreConstructible<'brand>
168        + Sized
169{
170}
171
172pub trait CoreConstructible<'brand>: Sized {
173    fn iden(inference_context: &types::Context<'brand>) -> Self;
174    fn unit(inference_context: &types::Context<'brand>) -> Self;
175    fn injl(child: &Self) -> Self;
176    fn injr(child: &Self) -> Self;
177    fn take(child: &Self) -> Self;
178    fn drop_(child: &Self) -> Self;
179    fn comp(left: &Self, right: &Self) -> Result<Self, types::Error>;
180    fn case(left: &Self, right: &Self) -> Result<Self, types::Error>;
181    fn assertl(left: &Self, right: Cmr) -> Result<Self, types::Error>;
182    fn assertr(left: Cmr, right: &Self) -> Result<Self, types::Error>;
183    fn pair(left: &Self, right: &Self) -> Result<Self, types::Error>;
184    fn fail(inference_context: &types::Context<'brand>, entropy: FailEntropy) -> Self;
185    fn const_word(inference_context: &types::Context<'brand>, word: Word) -> Self;
186
187    /// Accessor for the type inference context used to create the object.
188    fn inference_context(&self) -> &types::Context<'brand>;
189
190    /// Create an expression that produces the given `value`.
191    ///
192    /// The expression is minimized by using as many word jets as possible.
193    fn scribe(ctx: &types::Context<'brand>, value: &Value) -> Self {
194        use crate::value::ValueRef;
195
196        #[derive(Debug, Clone)]
197        enum Task<'v> {
198            Process(ValueRef<'v>),
199            MakeLeft,
200            MakeRight,
201            MakeProduct,
202        }
203
204        let mut input = vec![Task::Process(value.as_ref())];
205        let mut output = vec![];
206        while let Some(top) = input.pop() {
207            match top {
208                Task::Process(value) => {
209                    if value.is_unit() {
210                        output.push(Self::unit(ctx));
211                    } else if let Some(word) = value.to_word() {
212                        output.push(Self::const_word(ctx, word));
213                    } else if let Some(left) = value.as_left() {
214                        input.push(Task::MakeLeft);
215                        input.push(Task::Process(left));
216                    } else if let Some(right) = value.as_right() {
217                        input.push(Task::MakeRight);
218                        input.push(Task::Process(right));
219                    } else if let Some((left, right)) = value.as_product() {
220                        input.push(Task::MakeProduct);
221                        input.push(Task::Process(right));
222                        input.push(Task::Process(left));
223                    }
224                }
225                Task::MakeLeft => {
226                    let inner = output.pop().unwrap();
227                    output.push(Self::injl(&inner));
228                }
229                Task::MakeRight => {
230                    let inner = output.pop().unwrap();
231                    output.push(Self::injr(&inner));
232                }
233                Task::MakeProduct => {
234                    let right = output.pop().unwrap();
235                    let left = output.pop().unwrap();
236                    // simfony::PairBuilder would remove this `.expect()` call
237                    output.push(
238                        Self::pair(&left, &right).expect(
239                            "`pair` should always succeed because input type is unrestricted",
240                        ),
241                    );
242                }
243            }
244        }
245        debug_assert_eq!(output.len(), 1);
246        output.pop().unwrap()
247    }
248
249    /// Create a DAG that takes any input and returns bit `0` as constant output.
250    ///
251    /// _Overall type: A → 2_
252    fn bit_false(inference_context: &types::Context<'brand>) -> Self {
253        let unit = Self::unit(inference_context);
254        Self::injl(&unit)
255    }
256
257    /// Create a DAG that takes any input and returns bit `1` as constant output.
258    ///
259    /// _Overall type: A → 2_
260    fn bit_true(inference_context: &types::Context<'brand>) -> Self {
261        let unit = Self::unit(inference_context);
262        Self::injr(&unit)
263    }
264
265    /// Create a DAG that takes a bit and an input,
266    /// such that the `left` child is evaluated on the input if the bit is `1` _(if branch)_
267    /// and the `right` child is evaluated on the input otherwise _(else branch)_.
268    ///
269    /// _Overall type: 2 × A → B where `left`: A → B and `right`: A → B_
270    ///
271    /// _Type inference will fail if children are not of the correct type._
272    fn cond(left: &Self, right: &Self) -> Result<Self, types::Error> {
273        let drop_left = Self::drop_(left);
274        let drop_right = Self::drop_(right);
275        Self::case(&drop_right, &drop_left)
276    }
277
278    /// Create a DAG that asserts that its child returns `true`, and fails otherwise.
279    /// The `hash` identifies the assertion and is returned upon failure.
280    ///
281    /// _Overall type: A → 1 where `child`: A → 2_
282    ///
283    /// _Type inference will fail if children are not of the correct type._
284    fn assert(child: &Self, hash: Cmr) -> Result<Self, types::Error> {
285        let unit = Self::unit(child.inference_context());
286        let pair_child_unit = Self::pair(child, &unit)?;
287        let assertr_hidden_unit = Self::assertr(hash, &unit)?;
288
289        Self::comp(&pair_child_unit, &assertr_hidden_unit)
290    }
291
292    /// Create a DAG that computes Boolean _NOT_ of the `child`.
293    ///
294    /// _Overall type: A → 2 where `child`: A → 2_
295    ///
296    /// _Type inference will fail if children are not of the correct type._
297    #[allow(clippy::should_implement_trait)]
298    fn not(child: &Self) -> Result<Self, types::Error> {
299        let unit = Self::unit(child.inference_context());
300        let pair_child_unit = Self::pair(child, &unit)?;
301        let bit_true = Self::bit_true(child.inference_context());
302        let bit_false = Self::bit_false(child.inference_context());
303        let case_true_false = Self::case(&bit_true, &bit_false)?;
304
305        Self::comp(&pair_child_unit, &case_true_false)
306    }
307
308    /// Create a DAG that computes Boolean _AND_ of the `left` and `right` child.
309    ///
310    /// _Overall type: A → 2 where `left`: A → 2 and `right`: A → 2_
311    ///
312    /// _Type inference will fail if children are not of the correct type._
313    fn and(left: &Self, right: &Self) -> Result<Self, types::Error> {
314        left.inference_context()
315            .check_eq(right.inference_context())?;
316        let iden = Self::iden(left.inference_context());
317        let pair_left_iden = Self::pair(left, &iden)?;
318        let bit_false = Self::bit_false(left.inference_context());
319        let drop_right = Self::drop_(right);
320        let case_false_right = Self::case(&bit_false, &drop_right)?;
321
322        Self::comp(&pair_left_iden, &case_false_right)
323    }
324
325    /// Create a DAG that computes Boolean _OR_ of the `left` and `right`.
326    ///
327    /// _Overall type: A → 2 where `left`: A → 2 and `right`: A → 2_
328    ///
329    /// _Type inference will fail if children are not of the correct type._
330    fn or(left: &Self, right: &Self) -> Result<Self, types::Error> {
331        left.inference_context()
332            .check_eq(right.inference_context())?;
333        let iden = Self::iden(left.inference_context());
334        let pair_left_iden = Self::pair(left, &iden)?;
335        let drop_right = Self::drop_(right);
336        let bit_true = Self::bit_true(left.inference_context());
337        let case_right_true = Self::case(&drop_right, &bit_true)?;
338
339        Self::comp(&pair_left_iden, &case_right_true)
340    }
341}
342
343pub trait DisconnectConstructible<'brand, X>: Sized {
344    fn disconnect(left: &Self, right: &X) -> Result<Self, types::Error>;
345}
346
347pub trait JetConstructible<'brand>: Sized {
348    fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self;
349}
350
351pub trait WitnessConstructible<'brand, W>: Sized {
352    fn witness(inference_context: &types::Context<'brand>, witness: W) -> Self;
353}
354
355/// A node in a Simplicity expression.
356///
357/// There are three node types provided by this library: `ConstructNode`, `CommitNode`,
358/// and `RedeemNode`, which represent Simplicty programs during construction, at
359/// commitment time, and at redemption time, respectively.
360///
361/// This generic structure is used to define conversions and mapping functions over
362/// nodes and DAGs, and allows users to define their own custom node types.
363///
364/// For equality and hashing purposes, nodes are characterized entirely by their
365/// CMR and cached data. Users who create custom nodes should define a custom type
366/// for [`Marker::CachedData`] and think carefully about whether and how to
367/// implement the [`std::hash::Hash`] or equality traits.
368pub struct Node<N: Marker> {
369    inner: Inner<Arc<Node<N>>, N::Disconnect, N::Witness>,
370    cmr: Cmr,
371    data: N::CachedData,
372}
373
374impl<N: Marker> PartialEq for Node<N>
375where
376    N::CachedData: PartialEq,
377{
378    fn eq(&self, other: &Self) -> bool {
379        self.cmr == other.cmr && self.data == other.data
380    }
381}
382impl<N: Marker> Eq for Node<N> where N::CachedData: Eq {}
383
384impl<N: Marker> hash::Hash for Node<N>
385where
386    N::CachedData: hash::Hash,
387{
388    fn hash<H: hash::Hasher>(&self, h: &mut H) {
389        self.cmr.hash(h);
390        self.data.hash(h);
391    }
392}
393
394impl<N: Marker> fmt::Debug for Node<N>
395where
396    for<'a> &'a Node<N>: DagLike,
397{
398    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
399        self.post_order_iter::<MaxSharing<N>>().into_display(
400            f,
401            |node, f| fmt::Display::fmt(&node.inner, f),
402            |_, _| Ok(()),
403        )
404    }
405}
406
407#[cfg(feature = "base64")]
408impl<N: Marker> fmt::Display for Node<N> {
409    /// Displays the program data in base64.
410    ///
411    /// If you need witness data as well, then use [`Node::display`].
412    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
413        use crate::base64::display::Base64Display;
414        use crate::base64::engine::general_purpose;
415
416        let v = self.to_vec_without_witness();
417        Base64Display::new(&v, &general_purpose::STANDARD).fmt(f)
418    }
419}
420
421impl<N: Marker> HasCmr for Node<N> {
422    fn cmr(&self) -> Cmr {
423        self.cmr
424    }
425}
426
427impl<N: Marker> HasCmr for Arc<Node<N>> {
428    fn cmr(&self) -> Cmr {
429        self.cmr
430    }
431}
432
433impl<'brand, N> CoreConstructible<'brand> for Arc<Node<N>>
434where
435    N: Marker,
436    N::CachedData: CoreConstructible<'brand>,
437{
438    fn iden(inference_context: &types::Context<'brand>) -> Self {
439        Arc::new(Node {
440            cmr: Cmr::iden(),
441            data: N::CachedData::iden(inference_context),
442            inner: Inner::Iden,
443        })
444    }
445
446    fn unit(inference_context: &types::Context<'brand>) -> Self {
447        Arc::new(Node {
448            cmr: Cmr::unit(),
449            data: N::CachedData::unit(inference_context),
450            inner: Inner::Unit,
451        })
452    }
453
454    fn injl(child: &Self) -> Self {
455        Arc::new(Node {
456            cmr: Cmr::injl(child.cmr()),
457            data: N::CachedData::injl(&child.data),
458            inner: Inner::InjL(Arc::clone(child)),
459        })
460    }
461
462    fn injr(child: &Self) -> Self {
463        Arc::new(Node {
464            cmr: Cmr::injr(child.cmr()),
465            data: N::CachedData::injr(&child.data),
466            inner: Inner::InjR(Arc::clone(child)),
467        })
468    }
469
470    fn take(child: &Self) -> Self {
471        Arc::new(Node {
472            cmr: Cmr::take(child.cmr()),
473            data: N::CachedData::take(&child.data),
474            inner: Inner::Take(Arc::clone(child)),
475        })
476    }
477
478    fn drop_(child: &Self) -> Self {
479        Arc::new(Node {
480            cmr: Cmr::drop(child.cmr()),
481            data: N::CachedData::drop_(&child.data),
482            inner: Inner::Drop(Arc::clone(child)),
483        })
484    }
485
486    fn comp(left: &Self, right: &Self) -> Result<Self, types::Error> {
487        Ok(Arc::new(Node {
488            cmr: Cmr::comp(left.cmr(), right.cmr()),
489            data: N::CachedData::comp(&left.data, &right.data)?,
490            inner: Inner::Comp(Arc::clone(left), Arc::clone(right)),
491        }))
492    }
493
494    fn case(left: &Self, right: &Self) -> Result<Self, types::Error> {
495        Ok(Arc::new(Node {
496            cmr: Cmr::case(left.cmr(), right.cmr()),
497            data: N::CachedData::case(&left.data, &right.data)?,
498            inner: Inner::Case(Arc::clone(left), Arc::clone(right)),
499        }))
500    }
501
502    fn assertl(left: &Self, r_cmr: Cmr) -> Result<Self, types::Error> {
503        Ok(Arc::new(Node {
504            cmr: Cmr::case(left.cmr(), r_cmr),
505            data: N::CachedData::assertl(&left.data, r_cmr)?,
506            inner: Inner::AssertL(Arc::clone(left), r_cmr),
507        }))
508    }
509
510    fn assertr(l_cmr: Cmr, right: &Self) -> Result<Self, types::Error> {
511        Ok(Arc::new(Node {
512            cmr: Cmr::case(l_cmr, right.cmr()),
513            data: N::CachedData::assertr(l_cmr, &right.data)?,
514            inner: Inner::AssertR(l_cmr, Arc::clone(right)),
515        }))
516    }
517
518    fn pair(left: &Self, right: &Self) -> Result<Self, types::Error> {
519        Ok(Arc::new(Node {
520            cmr: Cmr::pair(left.cmr(), right.cmr()),
521            data: N::CachedData::pair(&left.data, &right.data)?,
522            inner: Inner::Pair(Arc::clone(left), Arc::clone(right)),
523        }))
524    }
525
526    fn fail(inference_context: &types::Context<'brand>, entropy: FailEntropy) -> Self {
527        Arc::new(Node {
528            cmr: Cmr::fail(entropy),
529            data: N::CachedData::fail(inference_context, entropy),
530            inner: Inner::Fail(entropy),
531        })
532    }
533
534    fn const_word(inference_context: &types::Context<'brand>, word: Word) -> Self {
535        Arc::new(Node {
536            cmr: Cmr::const_word(&word),
537            data: N::CachedData::const_word(inference_context, word.shallow_clone()),
538            inner: Inner::Word(word),
539        })
540    }
541
542    fn inference_context(&self) -> &types::Context<'brand> {
543        self.data.inference_context()
544    }
545}
546
547impl<'brand, N> DisconnectConstructible<'brand, N::Disconnect> for Arc<Node<N>>
548where
549    N: Marker,
550    N::CachedData: DisconnectConstructible<'brand, N::Disconnect>,
551{
552    fn disconnect(left: &Self, right: &N::Disconnect) -> Result<Self, types::Error> {
553        Ok(Arc::new(Node {
554            cmr: Cmr::disconnect(left.cmr()),
555            data: N::CachedData::disconnect(&left.data, right)?,
556            inner: Inner::Disconnect(Arc::clone(left), right.clone()),
557        }))
558    }
559}
560
561impl<'brand, N> WitnessConstructible<'brand, N::Witness> for Arc<Node<N>>
562where
563    N: Marker,
564    N::CachedData: WitnessConstructible<'brand, N::Witness>,
565{
566    fn witness(inference_context: &types::Context<'brand>, value: N::Witness) -> Self {
567        Arc::new(Node {
568            cmr: Cmr::witness(),
569            data: N::CachedData::witness(inference_context, value.clone()),
570            inner: Inner::Witness(value),
571        })
572    }
573}
574
575impl<'brand, N> JetConstructible<'brand> for Arc<Node<N>>
576where
577    N: Marker,
578    N::CachedData: JetConstructible<'brand>,
579{
580    fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self {
581        Arc::new(Node {
582            cmr: Cmr::jet(jet),
583            data: N::CachedData::jet(inference_context, jet),
584            inner: Inner::Jet(jet.dyn_clone()),
585        })
586    }
587}
588
589impl<N: Marker> Node<N> {
590    /// Accessor for the node's "inner value", i.e. its combinator
591    pub fn inner(&self) -> &Inner<Arc<Node<N>>, N::Disconnect, N::Witness> {
592        &self.inner
593    }
594
595    /// Accessor for the node's CMR
596    pub fn cmr(&self) -> Cmr {
597        self.cmr
598    }
599
600    /// Accessor for the node's cached data
601    pub fn sharing_id(&self) -> Option<N::SharingId> {
602        N::compute_sharing_id(self.cmr, &self.data)
603    }
604
605    /// Accessor for the node's cached data
606    pub fn cached_data(&self) -> &N::CachedData {
607        &self.data
608    }
609
610    /// Contruct a node from its constituent parts.
611    ///
612    /// This method can be used to directly costruct a node. It will compute the CMR
613    /// automatically based on the value of `inner` but requires that `cached_data`
614    /// be provided.
615    ///
616    /// If available, [`Constructible`] and its dependent traits will be easier to
617    /// use.
618    pub fn from_parts(
619        inner: Inner<Arc<Self>, N::Disconnect, N::Witness>,
620        data: N::CachedData,
621    ) -> Self {
622        let cmr = match &inner {
623            Inner::Unit => Cmr::unit(),
624            Inner::Iden => Cmr::iden(),
625            Inner::InjL(ref c) => Cmr::injl(c.cmr()),
626            Inner::InjR(ref c) => Cmr::injr(c.cmr()),
627            Inner::Take(ref c) => Cmr::take(c.cmr()),
628            Inner::Drop(ref c) => Cmr::drop(c.cmr()),
629            Inner::Comp(ref cl, ref cr) => Cmr::comp(cl.cmr(), cr.cmr()),
630            Inner::Case(ref cl, ref cr) => Cmr::case(cl.cmr(), cr.cmr()),
631            Inner::AssertL(ref c, cmr) => Cmr::case(c.cmr(), *cmr),
632            Inner::AssertR(cmr, ref c) => Cmr::case(*cmr, c.cmr()),
633            Inner::Pair(ref cl, ref cr) => Cmr::pair(cl.cmr(), cr.cmr()),
634            Inner::Disconnect(ref cl, _) => Cmr::disconnect(cl.cmr()),
635            Inner::Witness(_) => Cmr::witness(),
636            Inner::Fail(entropy) => Cmr::fail(*entropy),
637            Inner::Jet(j) => Cmr::jet(j.as_ref()),
638            Inner::Word(ref w) => Cmr::const_word(w),
639        };
640
641        Node { cmr, inner, data }
642    }
643
644    /// Generic conversion function from one type of node to another, with the
645    /// ability to prune during the conversion.
646    ///
647    /// Parameterized over what kind of sharing to use when iterating over the
648    /// DAG, and what conversion logic to use.
649    ///
650    /// See the documentation for [`Converter`] for details.
651    pub fn convert<S, M, C>(&self, converter: &mut C) -> Result<Arc<Node<M>>, C::Error>
652    where
653        S: for<'a> SharingTracker<&'a Self> + Default,
654        M: Marker,
655        C: Converter<N, M>,
656    {
657        let mut converted: Vec<Arc<Node<M>>> = vec![];
658        for data in self.post_order_iter::<S>() {
659            // First, tell the converter about the iterator state..
660            converter.visit_node(&data);
661
662            // Construct an Inner<usize> where pointers are replaced by indices.
663            // Note that `map_left_right`'s internal logic will ensure that these
664            // `unwrap`s are only called when they will succeed.
665            let indexed_inner: Inner<usize, &N::Disconnect, &N::Witness> = data
666                .node
667                .inner
668                .as_ref()
669                .map_left_right(|_| data.left_index.unwrap(), |_| data.right_index.unwrap());
670
671            // Then, convert witness data, if this is a witness node.
672            let witness_inner: Inner<&usize, &&N::Disconnect, M::Witness> = indexed_inner
673                .as_ref()
674                .map_witness_result(|wit| converter.convert_witness(&data, wit))?;
675
676            // Then convert disconnect nodes data.
677            let maybe_converted = data.right_index.map(|idx| &converted[idx]);
678            let witness_inner: Inner<&usize, M::Disconnect, M::Witness> = witness_inner
679                .map_disconnect_result(|disc| {
680                    converter.convert_disconnect(&data, maybe_converted, disc)
681                })?;
682
683            // Then put the converted nodes in place (it's easier to do this in this
684            // order because of the way the reference types work out).
685            let converted_inner: Inner<Arc<Node<M>>, M::Disconnect, M::Witness> =
686                witness_inner.map(|idx| Arc::clone(&converted[*idx]));
687
688            // Next, prune case nodes into asserts, if applicable
689            let pruned_inner = if let Inner::Case(left, right) = converted_inner {
690                let hide = converter.prune_case(&data, &left, &right)?;
691
692                match hide {
693                    Hide::Neither => Inner::Case(left, right),
694                    Hide::Left => Inner::AssertR(left.cmr(), right),
695                    Hide::Right => Inner::AssertL(left, right.cmr()),
696                }
697            } else {
698                converted_inner
699            };
700
701            // Finally, construct the node
702            converted.push(Arc::new(Node {
703                data: converter.convert_data(&data, pruned_inner.as_ref())?,
704                cmr: data.node.cmr,
705                inner: pruned_inner,
706            }));
707        }
708        Ok(converted.pop().unwrap())
709    }
710
711    pub fn display(&self) -> Display<'_, N> {
712        Display::from(self)
713    }
714
715    /// Display the Simplicity expression as a linear string.
716    ///
717    /// The linear string has no sharing and may be **exponentially larger**
718    /// than the originally shared expression!
719    pub fn display_expr(&self) -> DisplayExpr<'_, N> {
720        DisplayExpr::from(self)
721    }
722
723    /// Display the Simplicity expression as a graph in the given format and sharing level.
724    ///
725    /// This is the general form of [`display_as_dot`](Node::display_as_dot) and
726    /// [`display_as_mermaid`](Node::display_as_mermaid). Use those convenience methods for
727    /// the common case of DOT or Mermaid output with no sharing.
728    ///
729    /// The `format` field of the returned [`DisplayAsGraph`] can be changed after construction,
730    /// and the [`fmt::Display`] impl will use whatever `format` and `sharing` are set at that
731    /// point. See also [`DisplayAsGraph::to_dot_string`] and [`DisplayAsGraph::to_mermaid_string`]
732    /// to render to a specific format regardless of the stored `format` field.
733    pub fn display_as_graph(
734        &self,
735        format: GraphFormat,
736        sharing_level: SharingLevel,
737    ) -> DisplayAsGraph<'_, N> {
738        DisplayAsGraph::new(self, format, sharing_level)
739    }
740
741    /// Display the Simplicity expression as a Graphviz DOT graph.
742    ///
743    /// The DOT output can be rendered with `dot -Tsvg` or similar tools.
744    /// Shared nodes appear once in the graph with multiple incoming edges.
745    pub fn display_as_dot(&self) -> DisplayAsGraph<'_, N> {
746        DisplayAsGraph::new(self, GraphFormat::Dot, SharingLevel::None)
747    }
748
749    /// Display the Simplicity expression as a Mermaid diagram.
750    ///
751    /// The Mermaid output can be rendered in Markdown or the Mermaid live editor.
752    /// Shared nodes appear once in the diagram with multiple incoming edges.
753    pub fn display_as_mermaid(&self) -> DisplayAsGraph<'_, N> {
754        DisplayAsGraph::new(self, GraphFormat::Mermaid, SharingLevel::None)
755    }
756
757    /// Encode a Simplicity expression to bits without any witness data.
758    pub fn encode_without_witness(&self, prog: &mut dyn io::Write) -> io::Result<usize> {
759        let mut w = BitWriter::new(prog);
760        let program_bits = encode::encode_program(self, &mut w)?;
761        w.flush_all()?;
762        Ok(program_bits)
763    }
764
765    /// Encode a Simplicity expression to a vector of bytes, without any witness data.
766    pub fn to_vec_without_witness(&self) -> Vec<u8> {
767        let mut program = Vec::<u8>::new();
768        self.encode_without_witness(&mut program)
769            .expect("Vec::write is infallible");
770        debug_assert!(!program.is_empty());
771        program
772    }
773}
774
775impl<N: Marker<Witness = Value>> Node<N> {
776    /// Encode the program and witness data to bits.
777    ///
778    /// Returns the number of written bits for the program and witness, respectively.
779    pub fn encode_with_witness(
780        &self,
781        prog: &mut dyn io::Write,
782        witness: &mut dyn io::Write,
783    ) -> io::Result<(usize, usize)> {
784        let mut prog = BitWriter::new(prog);
785        let mut witness = BitWriter::new(witness);
786
787        let sharing_iter = self.post_order_iter::<MaxSharing<N>>();
788        let program_bits = encode::encode_program(self, &mut prog)?;
789        prog.flush_all()?;
790        let witness_bits = encode::encode_witness(sharing_iter.into_witnesses(), &mut witness)?;
791        witness.flush_all()?;
792        Ok((program_bits, witness_bits))
793    }
794
795    /// Encode the program and witness data to byte vectors.
796    pub fn to_vec_with_witness(&self) -> (Vec<u8>, Vec<u8>) {
797        let mut ret_1 = vec![];
798        let mut ret_2 = vec![];
799        self.encode_with_witness(&mut ret_1, &mut ret_2)
800            .expect("Vec::write is infallible");
801        (ret_1, ret_2)
802    }
803}
804
805#[cfg(test)]
806#[cfg(all(feature = "test-utils", feature = "elements"))]
807mod tests {
808    use ffi::tests::TestData;
809
810    use crate::analysis::Cost;
811    use crate::ffi;
812    use crate::jet::Elements;
813    use crate::BitIter;
814    use crate::RedeemNode;
815
816    fn check_merkle_roots(test: &TestData) {
817        let prog = BitIter::from(test.prog.as_slice());
818        let witness = BitIter::from(test.witness.as_slice());
819        ffi::tests::run_program(
820            &test.prog,
821            &test.witness,
822            ffi::tests::TestUpTo::CheckOneOne,
823            None,
824            None,
825        )
826        .unwrap();
827        let prog = RedeemNode::decode::<_, _, Elements>(prog, witness).unwrap();
828        assert_eq!(prog.cmr().to_byte_array(), test.cmr);
829        assert_eq!(prog.amr().to_byte_array(), test.amr);
830        assert_eq!(prog.ihr().to_byte_array(), test.ihr);
831        assert_eq!(prog.bounds().cost, Cost::from_milliweight(test.cost))
832    }
833
834    #[test]
835    fn progs_cmr() {
836        let schnorr0 = ffi::tests::schnorr0_test_data();
837        let schnorr6 = ffi::tests::schnorr6_test_data();
838        let ctx8_unpruned = ffi::tests::ctx8_unpruned_test_data();
839        let ctx8_pruned = ffi::tests::ctx8_pruned_test_data();
840        // check_merkle_roots(&hash_block); Need 1 -> 1 for now.
841        check_merkle_roots(&schnorr0);
842        check_merkle_roots(&schnorr6);
843        check_merkle_roots(&ctx8_unpruned);
844        check_merkle_roots(&ctx8_pruned);
845    }
846}