simplicity/node/
redeem.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use crate::analysis::NodeBounds;
4use crate::bit_machine::{ExecutionError, SetTracker};
5use crate::dag::{DagLike, InternalSharing, MaxSharing, PostOrderIterItem};
6use crate::jet::Jet;
7use crate::types::{self, arrow::FinalArrow};
8use crate::{encode, BitMachine};
9use crate::{Amr, BitIter, BitWriter, Cmr, Error, Ihr, Imr, Value};
10
11use super::{
12    Commit, CommitData, CommitNode, Construct, ConstructData, ConstructNode, Constructible,
13    Converter, Hide, Inner, Marker, NoDisconnect, NoWitness, Node,
14};
15
16use std::collections::HashSet;
17use std::io;
18use std::marker::PhantomData;
19use std::sync::Arc;
20
21#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
22pub struct Redeem<J> {
23    /// Makes the type non-constructible.
24    never: std::convert::Infallible,
25    /// Required by Rust.
26    phantom: std::marker::PhantomData<J>,
27}
28
29impl<J: Jet> Marker for Redeem<J> {
30    type CachedData = Arc<RedeemData<J>>;
31    type Witness = Value;
32    type Disconnect = Arc<RedeemNode<J>>;
33    type SharingId = Ihr;
34    type Jet = J;
35
36    fn compute_sharing_id(_: Cmr, cached_data: &Arc<RedeemData<J>>) -> Option<Ihr> {
37        Some(cached_data.ihr)
38    }
39}
40
41pub type RedeemNode<J> = Node<Redeem<J>>;
42
43#[derive(Clone, Debug)]
44pub struct RedeemData<J> {
45    amr: Amr,
46    imr: Imr,
47    ihr: Ihr,
48    arrow: FinalArrow,
49    bounds: NodeBounds,
50    /// This isn't really necessary, but it helps type inference if every
51    /// struct has a \<J\> parameter, since it forces the choice of jets to
52    /// be consistent without the user needing to specify it too many times.
53    phantom: PhantomData<J>,
54}
55
56impl<J> PartialEq for RedeemData<J> {
57    fn eq(&self, other: &Self) -> bool {
58        self.ihr == other.ihr
59    }
60}
61impl<J> Eq for RedeemData<J> {}
62
63impl<J> std::hash::Hash for RedeemData<J> {
64    fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
65        self.ihr.hash(hasher)
66    }
67}
68
69impl<J: Jet> RedeemData<J> {
70    pub fn new(arrow: FinalArrow, inner: Inner<&Arc<Self>, J, &Arc<Self>, Value>) -> Self {
71        let (amr, imr, bounds) = match inner {
72            Inner::Iden => (
73                Amr::iden(&arrow),
74                Imr::iden(),
75                NodeBounds::iden(arrow.source.bit_width()),
76            ),
77            Inner::Unit => (Amr::unit(&arrow), Imr::unit(), NodeBounds::unit()),
78            Inner::InjL(child) => (
79                Amr::injl(&arrow, child.amr),
80                Imr::injl(child.imr),
81                NodeBounds::injl(child.bounds),
82            ),
83            Inner::InjR(child) => (
84                Amr::injr(&arrow, child.amr),
85                Imr::injr(child.imr),
86                NodeBounds::injr(child.bounds),
87            ),
88            Inner::Take(child) => (
89                Amr::take(&arrow, child.amr),
90                Imr::take(child.imr),
91                NodeBounds::take(child.bounds),
92            ),
93            Inner::Drop(child) => (
94                Amr::drop(&arrow, child.amr),
95                Imr::drop(child.imr),
96                NodeBounds::drop(child.bounds),
97            ),
98            Inner::Comp(left, right) => (
99                Amr::comp(&arrow, &left.arrow, left.amr, right.amr),
100                Imr::comp(left.imr, right.imr),
101                NodeBounds::comp(left.bounds, right.bounds, left.arrow.target.bit_width()),
102            ),
103            Inner::Case(left, right) => (
104                Amr::case(&arrow, left.amr, right.amr),
105                Imr::case(left.imr, right.imr),
106                NodeBounds::case(left.bounds, right.bounds),
107            ),
108            Inner::AssertL(left, r_cmr) => (
109                Amr::assertl(&arrow, left.amr, r_cmr.into()),
110                Imr::case(left.imr, r_cmr.into()),
111                NodeBounds::assertl(left.bounds),
112            ),
113            Inner::AssertR(l_cmr, right) => (
114                Amr::assertr(&arrow, l_cmr.into(), right.amr),
115                Imr::case(l_cmr.into(), right.imr),
116                NodeBounds::assertr(right.bounds),
117            ),
118            Inner::Pair(left, right) => (
119                Amr::pair(&arrow, &left.arrow, &right.arrow, left.amr, right.amr),
120                Imr::pair(left.imr, right.imr),
121                NodeBounds::pair(left.bounds, right.bounds),
122            ),
123            Inner::Disconnect(left, right) => (
124                Amr::disconnect(&arrow, &right.arrow, left.amr, right.amr),
125                Imr::disconnect(left.imr, right.imr),
126                NodeBounds::disconnect(
127                    left.bounds,
128                    right.bounds,
129                    left.arrow.target.bit_width() - right.arrow.source.bit_width(),
130                    left.arrow.source.bit_width(),
131                    left.arrow.target.bit_width(),
132                ),
133            ),
134            Inner::Witness(ref value) => (
135                Amr::witness(&arrow, value),
136                Imr::witness(&arrow, value),
137                NodeBounds::witness(arrow.target.bit_width()),
138            ),
139            Inner::Fail(entropy) => (Amr::fail(entropy), Imr::fail(entropy), NodeBounds::fail()),
140            Inner::Jet(jet) => (Amr::jet(jet), Imr::jet(jet), NodeBounds::jet(jet)),
141            Inner::Word(ref val) => (
142                Amr::const_word(val),
143                Imr::const_word(val),
144                NodeBounds::const_word(val),
145            ),
146        };
147
148        RedeemData {
149            amr,
150            imr,
151            ihr: Ihr::from_imr(imr, &arrow),
152            arrow,
153            bounds,
154            phantom: PhantomData,
155        }
156    }
157}
158
159impl<J: Jet> RedeemNode<J> {
160    /// Accessor for the node's AMR
161    pub fn amr(&self) -> Amr {
162        self.data.amr
163    }
164
165    /// Accessor for the node's IHR
166    pub fn ihr(&self) -> Ihr {
167        self.data.ihr
168    }
169
170    /// Accessor for the node's type arrow
171    pub fn arrow(&self) -> &FinalArrow {
172        &self.data.arrow
173    }
174
175    /// Accessor for the node's bit machine bounds
176    pub fn bounds(&self) -> NodeBounds {
177        self.data.bounds
178    }
179
180    /// Convert a [`RedeemNode`] back to a [`CommitNode`] by forgetting witnesses
181    /// and cached data.
182    pub fn unfinalize(&self) -> Result<Arc<CommitNode<J>>, types::Error> {
183        struct Unfinalizer<J>(PhantomData<J>);
184
185        impl<J: Jet> Converter<Redeem<J>, Commit<J>> for Unfinalizer<J> {
186            type Error = types::Error;
187            fn convert_witness(
188                &mut self,
189                _: &PostOrderIterItem<&RedeemNode<J>>,
190                _: &Value,
191            ) -> Result<NoWitness, Self::Error> {
192                Ok(NoWitness)
193            }
194
195            fn convert_disconnect(
196                &mut self,
197                _: &PostOrderIterItem<&RedeemNode<J>>,
198                _: Option<&Arc<CommitNode<J>>>,
199                _: &Arc<RedeemNode<J>>,
200            ) -> Result<NoDisconnect, Self::Error> {
201                Ok(NoDisconnect)
202            }
203
204            fn convert_data(
205                &mut self,
206                data: &PostOrderIterItem<&RedeemNode<J>>,
207                inner: Inner<&Arc<CommitNode<J>>, J, &NoDisconnect, &NoWitness>,
208            ) -> Result<Arc<CommitData<J>>, Self::Error> {
209                let converted_data = inner.map(|node| node.cached_data());
210                Ok(Arc::new(CommitData::from_final(
211                    data.node.data.arrow.shallow_clone(),
212                    converted_data,
213                )))
214            }
215        }
216
217        self.convert::<MaxSharing<Redeem<J>>, _, _>(&mut Unfinalizer(PhantomData))
218    }
219
220    /// Convert a [`RedeemNode`] back into a [`ConstructNode`]
221    /// by loosening the finalized types, witness data and disconnected branches.
222    pub fn to_construct_node(&self) -> Arc<ConstructNode<J>> {
223        struct ToConstruct<J> {
224            inference_context: types::Context,
225            phantom: PhantomData<J>,
226        }
227
228        impl<J: Jet> Converter<Redeem<J>, Construct<J>> for ToConstruct<J> {
229            type Error = ();
230
231            fn convert_witness(
232                &mut self,
233                _: &PostOrderIterItem<&Node<Redeem<J>>>,
234                witness: &Value,
235            ) -> Result<Option<Value>, Self::Error> {
236                Ok(Some(witness.clone()))
237            }
238
239            fn convert_disconnect(
240                &mut self,
241                _: &PostOrderIterItem<&Node<Redeem<J>>>,
242                right: Option<&Arc<Node<Construct<J>>>>,
243                _: &Arc<RedeemNode<J>>,
244            ) -> Result<Option<Arc<Node<Construct<J>>>>, Self::Error> {
245                Ok(right.cloned())
246            }
247
248            fn convert_data(
249                &mut self,
250                _: &PostOrderIterItem<&Node<Redeem<J>>>,
251                inner: Inner<
252                    &Arc<Node<Construct<J>>>,
253                    J,
254                    &Option<Arc<ConstructNode<J>>>,
255                    &Option<Value>,
256                >,
257            ) -> Result<ConstructData<J>, Self::Error> {
258                let inner = inner
259                    .map(|node| node.cached_data())
260                    .map_witness(|maybe_value| maybe_value.clone());
261                Ok(ConstructData::from_inner(&self.inference_context, inner)
262                    .expect("types were already finalized"))
263            }
264        }
265
266        self.convert::<InternalSharing, _, _>(&mut ToConstruct {
267            inference_context: types::Context::new(),
268            phantom: PhantomData,
269        })
270        .unwrap()
271    }
272
273    /// Prune the redeem program for the given transaction environment.
274    ///
275    /// Pruning works as follows:
276    /// 1) Run the redeem program on the Bit Machine.
277    /// 2) Mark all (un)used case branches using the IHR of the case node.
278    /// 3) Rebuild the program and omit unused branches.
279    ///
280    /// The pruning result depends on the witness data (which is already part of the redeem program)
281    /// and on the transaction environment. These two inputs determine which case branches are
282    /// used and which are not. Pruning must be done for each transaction environment separately,
283    /// starting from the same original, unpruned program. Pruning is a lossy process, so pruning
284    /// an already pruned program is not sound.
285    ///
286    /// Pruning fails if the original, unpruned program fails to run on the Bit Machine (step 1).
287    /// In this case, the witness data needs to be revised.
288    /// The other pruning steps (2 & 3) never fail.
289    pub fn prune(&self, env: &J::Environment) -> Result<Arc<RedeemNode<J>>, ExecutionError> {
290        struct Pruner<J> {
291            inference_context: types::Context,
292            tracker: SetTracker,
293            phantom: PhantomData<J>,
294        }
295
296        impl<J: Jet> Converter<Redeem<J>, Construct<J>> for Pruner<J> {
297            type Error = std::convert::Infallible;
298
299            fn convert_witness(
300                &mut self,
301                _: &PostOrderIterItem<&RedeemNode<J>>,
302                witness: &Value,
303            ) -> Result<Option<Value>, Self::Error> {
304                // The pruned type is not finalized at this point,
305                // so we cannot prune the witness value.
306                Ok(Some(witness.shallow_clone()))
307            }
308
309            fn convert_disconnect(
310                &mut self,
311                _: &PostOrderIterItem<&RedeemNode<J>>,
312                right: Option<&Arc<ConstructNode<J>>>,
313                _: &Arc<RedeemNode<J>>,
314            ) -> Result<Option<Arc<ConstructNode<J>>>, Self::Error> {
315                debug_assert!(
316                    right.is_some(),
317                    "disconnected branch should exist in unpruned redeem program"
318                );
319                Ok(right.map(Arc::clone))
320            }
321
322            fn prune_case(
323                &mut self,
324                data: &PostOrderIterItem<&RedeemNode<J>>,
325                _left: &Arc<ConstructNode<J>>,
326                _right: &Arc<ConstructNode<J>>,
327            ) -> Result<Hide, Self::Error> {
328                // The IHR of the pruned program may change,
329                // but the Converter trait gives us access to the unpruned node (`data`).
330                // The Bit Machine tracked (un)used case branches based on the unpruned IHR.
331                match (
332                    self.tracker.left().contains(&data.node.ihr()),
333                    self.tracker.right().contains(&data.node.ihr()),
334                ) {
335                    (true, true) => Ok(Hide::Neither),
336                    (false, true) => Ok(Hide::Left),
337                    (true, false) => Ok(Hide::Right),
338                    (false, false) => Ok(Hide::Neither), // case nodes that were never executed will be pruned out by their ancestors
339                }
340            }
341
342            fn convert_data(
343                &mut self,
344                _: &PostOrderIterItem<&RedeemNode<J>>,
345                inner: Inner<
346                    &Arc<ConstructNode<J>>,
347                    J,
348                    &Option<Arc<ConstructNode<J>>>,
349                    &Option<Value>,
350                >,
351            ) -> Result<ConstructData<J>, Self::Error> {
352                let converted_inner = inner
353                    .map(|node| node.cached_data())
354                    .map_witness(Option::<Value>::clone);
355                let retyped = ConstructData::from_inner(&self.inference_context, converted_inner)
356                    .expect("pruned types should check out if unpruned types check out");
357                Ok(retyped)
358            }
359        }
360
361        struct Finalizer<J>(PhantomData<J>);
362
363        impl<J: Jet> Converter<Construct<J>, Redeem<J>> for Finalizer<J> {
364            type Error = std::convert::Infallible;
365
366            fn convert_witness(
367                &mut self,
368                data: &PostOrderIterItem<&ConstructNode<J>>,
369                witness: &Option<Value>,
370            ) -> Result<Value, Self::Error> {
371                let pruned_target_ty = data
372                    .node
373                    .arrow()
374                    .target
375                    .finalize()
376                    .expect("pruned types should check out if unpruned types check out");
377                let pruned_witness = witness
378                    .as_ref()
379                    .expect("witness node that originally stems from redeem program should be populated")
380                    .prune(&pruned_target_ty)
381                    .expect("pruned type should be shrunken version of unpruned type");
382                Ok(pruned_witness)
383            }
384
385            fn convert_disconnect(
386                &mut self,
387                _: &PostOrderIterItem<&ConstructNode<J>>,
388                right: Option<&Arc<RedeemNode<J>>>,
389                _: &Option<Arc<ConstructNode<J>>>,
390            ) -> Result<Arc<RedeemNode<J>>, Self::Error> {
391                Ok(right
392                    .map(Arc::clone)
393                    .expect("disconnect node that originally stems from redeem program should have all branches"))
394            }
395
396            fn convert_data(
397                &mut self,
398                data: &PostOrderIterItem<&ConstructNode<J>>,
399                inner: Inner<&Arc<RedeemNode<J>>, J, &Arc<RedeemNode<J>>, &Value>,
400            ) -> Result<Arc<RedeemData<J>>, Self::Error> {
401                // Finalize target types of witness nodes in advance so we can prune their values.
402                let final_arrow = data
403                    .node
404                    .arrow()
405                    .finalize()
406                    .expect("pruned types should check out if unpruned types check out");
407                let converted_inner = inner
408                    .map(|node| node.cached_data())
409                    .map_disconnect(|node| node.cached_data())
410                    .map_witness(Value::shallow_clone);
411                Ok(Arc::new(RedeemData::new(final_arrow, converted_inner)))
412            }
413        }
414
415        // 1) Run the Bit Machine and mark (un)used branches.
416        // This is the only fallible step in the pruning process.
417        let mut mac = BitMachine::for_program(self)?;
418        let tracker = mac.exec_prune(self, env)?;
419
420        // 2) Prune out unused case branches.
421        // Because the types of the pruned program may change,
422        // we construct a temporary witness program with unfinalized types.
423        let pruned_witness_program = self
424            .convert::<InternalSharing, _, _>(&mut Pruner {
425                inference_context: types::Context::new(),
426                tracker,
427                phantom: PhantomData,
428            })
429            .expect("pruning unused branches is infallible");
430
431        // 3) Finalize the types of the witness program.
432        // We obtain the pruned redeem program.
433        // Once the pruned type is finalized, we can proceed to prune witness values.
434        Ok(pruned_witness_program
435            .convert::<InternalSharing, _, _>(&mut Finalizer(PhantomData))
436            .expect("finalization is infallible"))
437    }
438
439    /// Decode a Simplicity program from bits, including the witness data.
440    pub fn decode<I1, I2>(
441        mut program: BitIter<I1>,
442        mut witness: BitIter<I2>,
443    ) -> Result<Arc<Self>, Error>
444    where
445        I1: Iterator<Item = u8>,
446        I2: Iterator<Item = u8>,
447    {
448        // 0. Set up a type to help with the call to `convert` below
449        struct DecodeFinalizer<'bits, J: Jet, I: Iterator<Item = u8>> {
450            bits: &'bits mut BitIter<I>,
451            phantom: PhantomData<J>,
452        }
453
454        impl<J: Jet, I: Iterator<Item = u8>> Converter<Construct<J>, Redeem<J>>
455            for DecodeFinalizer<'_, J, I>
456        {
457            type Error = Error;
458            fn convert_witness(
459                &mut self,
460                data: &PostOrderIterItem<&ConstructNode<J>>,
461                _: &Option<Value>,
462            ) -> Result<Value, Self::Error> {
463                let arrow = data.node.data.arrow();
464                let target_ty = arrow.target.finalize()?;
465                Value::from_compact_bits(self.bits, &target_ty).map_err(Error::from)
466            }
467
468            fn convert_disconnect(
469                &mut self,
470                _: &PostOrderIterItem<&ConstructNode<J>>,
471                right: Option<&Arc<RedeemNode<J>>>,
472                _: &Option<Arc<ConstructNode<J>>>,
473            ) -> Result<Arc<RedeemNode<J>>, Self::Error> {
474                if let Some(child) = right {
475                    Ok(Arc::clone(child))
476                } else {
477                    Err(Error::DisconnectRedeemTime)
478                }
479            }
480
481            fn convert_data(
482                &mut self,
483                data: &PostOrderIterItem<&ConstructNode<J>>,
484                inner: Inner<&Arc<RedeemNode<J>>, J, &Arc<RedeemNode<J>>, &Value>,
485            ) -> Result<Arc<RedeemData<J>>, Self::Error> {
486                let arrow = data.node.data.arrow().finalize()?;
487                let converted_data = inner
488                    .map(|node| node.cached_data())
489                    .map_disconnect(|node| node.cached_data())
490                    .map_witness(Value::shallow_clone);
491                Ok(Arc::new(RedeemData::new(arrow, converted_data)))
492            }
493        }
494
495        // 1. Decode program without witnesses as ConstructNode
496        let construct = crate::decode::decode_expression(&mut program)?;
497        program
498            .close()
499            .map_err(crate::decode::Error::BitIter)
500            .map_err(Error::Decode)?;
501        construct.set_arrow_to_program()?;
502
503        // Importantly, we  use `InternalSharing` here to make sure that we respect
504        // the sharing choices that were actually encoded in the bitstream.
505        let program: Arc<Self> =
506            construct.convert::<InternalSharing, _, _>(&mut DecodeFinalizer {
507                bits: &mut witness,
508                phantom: PhantomData,
509            })?;
510
511        // 3. Check that we read exactly as much witness data as we expected
512        witness
513            .close()
514            .map_err(crate::decode::Error::BitIter)
515            .map_err(Error::Decode)?;
516
517        // 4. Check sharing
518        // This loop is equivalent to using `program.is_shared_as::<MaxSharing>()`
519        // but is faster since it only runs a single iterator.
520        let mut ihrs: HashSet<Ihr> = HashSet::new();
521        for data in program.as_ref().post_order_iter::<InternalSharing>() {
522            if !ihrs.insert(data.node.ihr()) {
523                return Err(Error::Decode(crate::decode::Error::SharingNotMaximal));
524            }
525        }
526
527        Ok(program)
528    }
529
530    /// Encode the program to bits.
531    ///
532    /// Includes witness data. Returns the number of written bits.
533    pub fn encode<W1, W2>(
534        &self,
535        prog: &mut BitWriter<W1>,
536        witness: &mut BitWriter<W2>,
537    ) -> io::Result<usize>
538    where
539        W1: io::Write,
540        W2: io::Write,
541    {
542        let sharing_iter = self.post_order_iter::<MaxSharing<Redeem<J>>>();
543        let program_bits = encode::encode_program(self, prog)?;
544        prog.flush_all()?;
545        let witness_bits = encode::encode_witness(sharing_iter.into_witnesses(), witness)?;
546        witness.flush_all()?;
547        Ok(program_bits + witness_bits)
548    }
549
550    /// Encode the program and witness data to byte vectors.
551    pub fn encode_to_vec(&self) -> (Vec<u8>, Vec<u8>) {
552        let mut ret_1 = vec![];
553        let mut ret_2 = vec![];
554        self.encode(
555            &mut BitWriter::new(&mut ret_1),
556            &mut BitWriter::new(&mut ret_2),
557        )
558        .unwrap();
559        (ret_1, ret_2)
560    }
561}
562
563#[cfg(test)]
564mod tests {
565    use super::*;
566    use crate::human_encoding::Forest;
567    use crate::jet::Core;
568    use crate::node::SimpleFinalizer;
569    use crate::types::Final;
570    use hex::DisplayHex;
571    use std::collections::HashMap;
572    use std::fmt;
573
574    fn assert_program_deserializable<J: Jet>(
575        prog_bytes: &[u8],
576        witness_bytes: &[u8],
577        cmr_str: &str,
578        amr_str: &str,
579        ihr_str: &str,
580    ) -> Arc<RedeemNode<J>> {
581        let prog_hex = prog_bytes.as_hex();
582        let witness_hex = witness_bytes.as_hex();
583
584        let prog = BitIter::from(prog_bytes);
585        let witness = BitIter::from(witness_bytes);
586        let prog = match RedeemNode::<J>::decode(prog, witness) {
587            Ok(prog) => prog,
588            Err(e) => panic!("program {} failed: {}", prog_hex, e),
589        };
590
591        assert_eq!(
592            prog.cmr().to_string(),
593            cmr_str,
594            "CMR mismatch (got {} expected {}) for program {}",
595            prog.cmr(),
596            cmr_str,
597            prog_hex,
598        );
599
600        assert_eq!(
601            prog.amr().to_string(),
602            amr_str,
603            "AMR mismatch (got {} expected {}) for program {}",
604            prog.amr(),
605            amr_str,
606            prog_hex,
607        );
608        assert_eq!(
609            prog.ihr().to_string(),
610            ihr_str,
611            "IHR mismatch (got {} expected {}) for program {}",
612            prog.ihr(),
613            ihr_str,
614            prog_hex,
615        );
616
617        let (reser_prog, reser_witness) = prog.encode_to_vec();
618        assert_eq!(
619            prog_bytes,
620            &reser_prog[..],
621            "program {} reserialized as {}",
622            prog_hex,
623            reser_prog.as_hex(),
624        );
625        assert_eq!(
626            witness_bytes,
627            &reser_witness[..],
628            "witness {} reserialized as {}",
629            witness_hex,
630            reser_witness.as_hex(),
631        );
632
633        prog
634    }
635
636    fn assert_program_not_deserializable<J: Jet>(
637        prog_bytes: &[u8],
638        witness_bytes: &[u8],
639        err: &dyn fmt::Display,
640    ) {
641        let prog_hex = prog_bytes.as_hex();
642        let witness_hex = witness_bytes.as_hex();
643        let err_str = err.to_string();
644
645        let prog = BitIter::from(prog_bytes);
646        let witness = BitIter::from(witness_bytes);
647        match RedeemNode::<J>::decode(prog, witness) {
648            Ok(prog) => panic!(
649                "Program {} wit {} succeded (expected error {}). Program parsed as:\n{}",
650                prog_hex, witness_hex, err, prog
651            ),
652            Err(e) if e.to_string() == err_str => {} // ok
653            Err(e) => panic!(
654                "Program {} wit {} failed with error {} (expected error {})",
655                prog_hex, witness_hex, e, err
656            ),
657        };
658    }
659
660    #[test]
661    fn encode_shared_witnesses() {
662        // # Program code:
663        // wit1 = witness :: 1 -> 2^32
664        // wit2 = witness :: 1 -> 2^32
665        //
666        // wits_are_equal = comp (pair wit1 wit2) jet_eq_32 :: 1 -> 2
667        // main = comp wits_are_equal jet_verify            :: 1 -> 1
668        let eqwits = [0xcd, 0xdc, 0x51, 0xb6, 0xe2, 0x08, 0xc0, 0x40];
669        let iter = BitIter::from(&eqwits[..]);
670        let eqwits_prog = CommitNode::<Core>::decode(iter).unwrap();
671
672        let eqwits_final = eqwits_prog
673            .finalize(&mut SimpleFinalizer::new(std::iter::repeat(Value::u32(
674                0xDEADBEEF,
675            ))))
676            .unwrap();
677        let output = eqwits_final.encode_to_vec();
678
679        assert_eq!(
680            output,
681            (
682                [0xc9, 0xc4, 0x6d, 0xb8, 0x82, 0x30, 0x10].into(),
683                [0xde, 0xad, 0xbe, 0xef].into(),
684            ),
685            "output {} {}",
686            output.0.as_hex(),
687            output.1.as_hex()
688        );
689    }
690
691    #[test]
692    fn decode_shared_witnesses() {
693        // This program is exactly the output from the `encode_shared_witnesses` test.
694        // The point of this is to make sure that our witness-unsharing logic doesn't
695        // get confused here and try to read two witnesses when there are only one.
696        assert_program_deserializable::<Core>(
697            &[0xc9, 0xc4, 0x6d, 0xb8, 0x82, 0x30, 0x10],
698            &[0xde, 0xad, 0xbe, 0xef],
699            "d7969920eff9a1ed0359aaa8545b239c69969e22c304c645a7b49bcc976a40a8",
700            "f7acbb077e7661a08384818bc8e3a275ed42ad446252575a35a35f71689fef78",
701            "3ce4a6390b4e4bda6330acda4800e66e5d2cae0f5a2888564c706f2b910146b8",
702        );
703    }
704
705    #[test]
706    fn unshared_child() {
707        // # id1 and id2 should be shared, but are not!
708        // id1 = iden          :: A -> A # cmr dbfefcfc...
709        // id2 = iden          :: A -> A # cmr dbfefcfc...
710        // cp3 = comp id1 id2  :: A -> A # cmr c1ae55b5...
711        // main = comp cp3 cp3 :: A -> A # cmr 314e2879...
712        assert_program_not_deserializable::<Core>(
713            &[0xc1, 0x08, 0x04, 0x00],
714            &[],
715            &Error::Decode(crate::decode::Error::SharingNotMaximal),
716        );
717    }
718
719    #[test]
720    fn witness_consumed() {
721        // "main = unit", but with a witness attached. Found by fuzzer.
722        let prog = BitIter::from(&[0x24][..]);
723        let wit = BitIter::from(&[0x00][..]);
724        match RedeemNode::<Core>::decode(prog, wit) {
725            Err(Error::Decode(crate::decode::Error::BitIter(
726                crate::BitIterCloseError::TrailingBytes { first_byte: 0 },
727            ))) => {} // ok,
728            Err(e) => panic!("got incorrect error {e}"),
729            Ok(_) => panic!("accepted program with bad witness length"),
730        }
731    }
732
733    #[test]
734    fn shared_grandchild() {
735        // # This program repeats the node `cp2` three times; during iteration it will
736        // # be placed on the stack as part of the initial `comp` combinator, but by
737        // # the time we get to it, it will have already been yielded. Makes sure this
738        // # does not confuse the iteration logic and break the decoded program structure.
739        // id1 = iden
740        // cp2 = comp id1 id1
741        // cp3 = comp cp2 cp2
742        // main = comp cp3 cp2
743        assert_program_deserializable::<Core>(
744            &[0xc1, 0x00, 0x00, 0x01, 0x00],
745            &[],
746            "8a54101335ca2cf7e933d74cdb15f99becc4e540799ba5e2d19c00c9d7219e71",
747            "74e868bd640c250bc45522085158a9723fc7e277bb16a8d582c4012ebbb1f6f1",
748            "39b8f72bd1539de87d26673890603d6548cfc8b68571d996bdf9b1d8b557bd35",
749        );
750    }
751
752    #[test]
753    #[rustfmt::skip]
754    fn assert_lr() {
755        // asst = assertl unit deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef
756        // input0 = pair (injl unit) unit
757        // main = comp input0 asst
758        assert_program_deserializable::<Core>(
759            &[
760                0xcd, 0x24, 0x08, 0x4b, 0x6f, 0x56, 0xdf, 0x77,
761                0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
762                0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
763                0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
764                0xef, 0x56, 0xdf, 0x77, 0x86, 0x01, 0x80,
765            ],
766            &[],
767            "abdd773fc7a503908739b4a63198416fdd470948830cb5a6516b98fe0a3bfa85",
768            "1362ee53ae75218ed51dc4bd46cdbfa585f934ac6c6c3ff787e27dce91ccd80b",
769            "251c6778129e0f12da3f2388ab30184e815e9d9456b5931e54802a6715d9ca42",
770        );
771
772
773        // asst = assertr deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef unit
774        // input1 = pair (injr unit) unit
775        // main = comp input1 asst
776        assert_program_deserializable::<Core>(
777            &[
778                0xcd, 0x25, 0x08, 0x6d, 0xea, 0xdb, 0xee, 0xfd,
779                0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
780                0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
781                0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
782                0xea, 0xdb, 0xee, 0xf4, 0x86, 0x01, 0x80,
783            ],
784            &[],
785            "f6c678dfb180b94567a9d524e05fbc893f6905e0e3db931ff01dc2701e783d4c",
786            "212d4fa3dbe2b33db1e11bb6f4cc973be5de0896a3775387a06056483b8feb0f",
787            "7a583edcc733b6bba66998110be403ac61fab2d93fc09ba3c84ab2509b538043",
788        );
789    }
790
791    #[test]
792    #[rustfmt::skip]
793    fn disconnect() {
794        // id1 = iden                 :: (2^256 * B) -> (2^256 * B)                       # cmr dbfefcfc...
795        // pr2 = pair id1 id1         :: (2^256 * B) -> ((2^256 * B) * (2^256 * B))       # cmr a62c628c...
796        // disc3 = disconnect pr2 pr2 :: B -> ((2^256 * B) * ((2^256 * B) * (2^256 * B))) # cmr d81d6f28...
797        // ut4 = unit                 :: ((2^256 * B) * ((2^256 * B) * (2^256 * B))) -> 1 # cmr 62274a89...
798        // main = comp disc3 ut4      :: B -> 1                                           # cmr a453360c...
799        assert_program_deserializable::<Core>(
800            &[0xc5, 0x02, 0x06, 0x24, 0x10],
801            &[],
802            "afe8f5f8bd3f64bfa51d2f29ffa22523604d9654c0d9862dbf2dc67ba097cbb2",
803            "15239708cb7b448cedc6a0b6401dce86ed74084056dd95831928860dd0c3ca67",
804            "9cdacb48b16e108ccbd6bcbce459a64056df285c2dc6e02dca6d13c4b1530fb0",
805        );
806    }
807
808    #[test]
809    #[rustfmt::skip]
810    #[cfg(feature = "elements")]
811    fn disconnect2() {
812        // Program that Russell posted on IRC 2023-06-22 that tickled `Dag::right_child`
813        // bug that had been introduced that day. Probably not the most minimal test
814        // vector but might as well include it as it seems like an interesting program.
815        //
816        // # Witnesses
817        // wit1 = witness :: 1 -> 2^512
818        //
819        // # Constants
820        // const1 = word_jet 0x00000000000000000000003b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63 :: 1 -> 2^256 # cmr a9e3dbca...
821        //
822        // # Program code
823        // id1 = iden                 :: (2^256 * 1) -> (2^256 * 1)     # cmr dbfefcfc...
824        // jt2 = jet_sig_all_hash     :: 1 -> 2^256                     # cmr 9902bc0f...
825        // disc3 = disconnect id1 jt2 :: 1 -> 2^512                     # cmr 6968f10e...
826        // pr4 = pair const1 disc3    :: 1 -> (2^256 * 2^512)           # cmr 378ad609...
827        // pr5 = pair pr4 wit1        :: 1 -> ((2^256 * 2^512) * 2^512) # cmr 0d51ff00...
828        // jt6 = jet_check_sig_verify :: ((2^256 * 2^512) * 2^512) -> 1 # cmr 297459d8...
829        //
830        // main = comp pr5 jt6        :: 1 -> 1                         # cmr 14a5e0cc...
831        assert_program_deserializable::<crate::jet::Elements>(
832            &[
833                0xd3, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce,
834                0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, 0xd6, 0x79, 0x5f,
835                0x9c, 0x63, 0x47, 0x07, 0x02, 0xc0, 0xe2, 0x8d, 0x88, 0x10, 
836            ],
837            &[
838                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce, 0x56, 0x3f,
839                0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, 0xd6, 0x79, 0x5f, 0x9c, 0x63,
840                0xdb, 0x86, 0x8d, 0x45, 0xa0, 0xbc, 0x1d, 0x19, 0x01, 0x30, 0x2b, 0xc8, 0x7a, 0x87, 0x1c, 0xf1,
841                0x58, 0xe2, 0xbd, 0xe2, 0xcf, 0xa6, 0x45, 0xa8, 0x95, 0xc1, 0xb4, 0x5d, 0x68, 0xea, 0x24, 0xc0, 
842            ],
843            "f3cd4537d7ebb201732203195b30b549b8dc0c2c6257b3a0d53bedb08ea02874",
844            "107fa80454ed0f2d95d7c18d307912b1497505b98de47198fee23b5018efa544",
845            "d52021c638ba742a90bead9b3055efd66091fb50bb131aa8b10eb7c13ef464d1",
846        );
847    }
848
849    #[test]
850    #[rustfmt::skip]
851    #[cfg(feature = "elements")]
852    fn disconnect3() {
853        // Yet another disconnect-based program that hit a bug in our AMR computation
854        // (passing left arrow in place of right arrow to the AMR constructor.)
855        // # Program code
856        // id1 = iden                 :: (2^256 * 1) -> (2^256 * 1) # cmr dbfefcfc...
857        // ut2 = unit                 :: 1 -> 1                     # cmr 62274a89...
858        // jl3 = injl ut2             :: 1 -> 2                     # cmr bd0cce93...
859        // disc4 = disconnect id1 jl3 :: 1 -> (2^256 * 2)           # cmr 6968f10e...
860        // ut5 = unit                 :: (2^256 * 2) -> 1           # cmr 62274a89...
861        // main = comp disc4 ut5      :: 1 -> 1                     # cmr a8c9cc7a...
862        assert_program_deserializable::<crate::jet::Elements>(
863            &[0xc9, 0x09, 0x20, 0x74, 0x90, 0x40],
864            &[],
865            "b689bdee289c8dd4e2e283358d187813363d441776cf826dafc27cc8a81ec441",
866            "3c68660a1afde7982ce4aa9d499ad382bc32f5f9ad894a5e915f76e66303a25b",
867            "85313720ee43ae0ee03f88b05e6d9e4494308c6897bdeb3e93b94559c3317484",
868        );
869    }
870
871    #[test]
872    #[cfg(feature = "elements")]
873    fn decode_schnorr() {
874        #[rustfmt::skip]
875        let schnorr0 = vec![
876            0xc6, 0xd5, 0xf2, 0x61, 0x14, 0x03, 0x24, 0xb1, 0x86, 0x20, 0x92, 0x68, 0x9f, 0x0b, 0xf1, 0x3a,
877            0xa4, 0x53, 0x6a, 0x63, 0x90, 0x8b, 0x06, 0xdf, 0x33, 0x61, 0x0c, 0x03, 0xe2, 0x27, 0x79, 0xc0,
878            0x6d, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
879            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
880            0x00, 0x00, 0xe2, 0x8d, 0x8c, 0x04, 0x00,
881        ];
882        #[rustfmt::skip]
883        let schnorr0_wit = vec![
884            0xe9, 0x07, 0x83, 0x1f, 0x80, 0x84, 0x8d, 0x10, 0x69, 0xa5, 0x37, 0x1b, 0x40, 0x24, 0x10, 0x36,
885            0x4b, 0xdf, 0x1c, 0x5f, 0x83, 0x07, 0xb0, 0x08, 0x4c, 0x55, 0xf1, 0xce, 0x2d, 0xca, 0x82, 0x15,
886            0x25, 0xf6, 0x6a, 0x4a, 0x85, 0xea, 0x8b, 0x71, 0xe4, 0x82, 0xa7, 0x4f, 0x38, 0x2d, 0x2c, 0xe5,
887            0xeb, 0xee, 0xe8, 0xfd, 0xb2, 0x17, 0x2f, 0x47, 0x7d, 0xf4, 0x90, 0x0d, 0x31, 0x05, 0x36, 0xc0,
888        ];
889        assert_program_deserializable::<crate::jet::Elements>(
890            &schnorr0,
891            &schnorr0_wit,
892            "8a9e97676b24be7797d9ee0bf32dd76bcd78028e973025f785eae8dc91c8a0da",
893            "ec97c8774cb6bfb381fdbbcc8d964380fb3a3b45779322624490d6231ae777a4",
894            "ad7c38b16b9129646dc89b52cff144de94a80e383c4983b53de65e3575abcf38",
895        );
896    }
897
898    #[cfg(feature = "elements")]
899    fn assert_correct_pruning<J: Jet>(
900        unpruned_prog: &str,
901        unpruned_wit: &HashMap<Arc<str>, Value>,
902        expected_pruned_prog: &str,
903        expected_pruned_wit: &HashMap<Arc<str>, Value>,
904        env: &J::Environment,
905    ) {
906        let unpruned_program = Forest::<J>::parse(unpruned_prog)
907            .expect("unpruned program should parse")
908            .to_witness_node(unpruned_wit)
909            .expect("unpruned program should have main")
910            .finalize_unpruned()
911            .expect("unpruned program should finalize");
912        let expected_unpruned_program = Forest::<J>::parse(expected_pruned_prog)
913            .expect("expected pruned program should parse")
914            .to_witness_node(expected_pruned_wit)
915            .expect("expected pruned program should have main")
916            .finalize_unpruned()
917            .expect("expected pruned program should finalize");
918
919        let mut mac = BitMachine::for_program(&unpruned_program)
920            .expect("unpruned program has reasonable bounds");
921        let unpruned_output = mac
922            .exec(&unpruned_program, env)
923            .expect("unpruned program should run without failure");
924
925        let pruned_program = unpruned_program
926            .prune(env)
927            .expect("pruning should not fail if execution succeeded");
928        assert_eq!(
929            pruned_program.ihr(),
930            expected_unpruned_program.ihr(),
931            "pruning result differs from expected result"
932        );
933
934        let mut mac =
935            BitMachine::for_program(&pruned_program).expect("pruned program has reasonable bounds");
936        let pruned_output = mac
937            .exec(&pruned_program, env)
938            .expect("pruned program should run without failure");
939        assert_eq!(
940            unpruned_output, pruned_output,
941            "pruned program should return same output as unpruned program"
942        );
943    }
944
945    #[test]
946    #[cfg(feature = "elements")]
947    fn prune() {
948        let env = crate::jet::elements::ElementsEnv::dummy();
949
950        /*
951         * 1) Prune a product type / value
952         */
953        let unpruned_prog = r#"wit1 := witness : 1 -> 2
954wit2 := witness : 1 -> 2^64 * 2^64
955input := pair wit1 wit2 : 1 -> 2 * (2^64 * 2^64)
956process := case (drop take jet_is_zero_64) (drop drop jet_is_zero_64) : 2 * (2^64 * 2^64) -> 2
957main := comp input comp process jet_verify : 1 -> 1"#;
958
959        // 1.1) Prune right
960        let unpruned_wit = HashMap::from([
961            (Arc::from("wit1"), Value::u1(0)),
962            (
963                Arc::from("wit2"),
964                Value::product(Value::u64(0), Value::u64(0)),
965            ),
966        ]);
967        let pruned_prog = r#"wit1 := witness : 1 -> 2
968wit2 := witness : 1 -> 2^64 * 1 -- right component was pruned
969input := pair wit1 wit2 : 1 -> 2 * (2^64 * 1)
970process := assertl (drop take jet_is_zero_64) #{drop drop jet_is_zero_64} : 2 * (2^64 * 1) -> 2 -- case became assertl
971main := comp input comp process jet_verify : 1 -> 1"#;
972        let pruned_wit = HashMap::from([
973            (Arc::from("wit1"), Value::u1(0)),
974            (
975                Arc::from("wit2"),
976                Value::product(Value::u64(0), Value::unit()),
977            ),
978        ]);
979        assert_correct_pruning::<crate::jet::Elements>(
980            unpruned_prog,
981            &unpruned_wit,
982            pruned_prog,
983            &pruned_wit,
984            &env,
985        );
986
987        // 1.2) Prune left
988        let unpruned_wit = HashMap::from([
989            (Arc::from("wit1"), Value::u1(1)),
990            (
991                Arc::from("wit2"),
992                Value::product(Value::u64(0), Value::u64(0)),
993            ),
994        ]);
995        let pruned_prog = r#"wit1 := witness : 1 -> 2
996wit2 := witness : 1 -> 1 * 2^64 -- left component was pruned
997input := pair wit1 wit2 : 1 -> 2 * (1 * 2^64)
998process := assertr #{drop take jet_is_zero_64} (drop drop jet_is_zero_64) : 2 * (1 * 2^64) -> 2 -- case became assertr
999main := comp input comp process jet_verify : 1 -> 1"#;
1000        let pruned_wit = HashMap::from([
1001            (Arc::from("wit1"), Value::u1(1)),
1002            (
1003                Arc::from("wit2"),
1004                Value::product(Value::unit(), Value::u64(0)),
1005            ),
1006        ]);
1007        assert_correct_pruning::<crate::jet::Elements>(
1008            unpruned_prog,
1009            &unpruned_wit,
1010            pruned_prog,
1011            &pruned_wit,
1012            &env,
1013        );
1014
1015        /*
1016         * 1) Prune a sum type / value
1017         */
1018        let prune_sum = r#"wit1 := witness : 1 -> 2^64 + 2^64
1019input := pair wit1 unit : 1 -> (2^64 + 2^64) * 1
1020process := case (take jet_is_zero_64) (take jet_is_zero_64) : (2^64 + 2^64) * 1 -> 2
1021main := comp input comp process jet_verify : 1 -> 1"#;
1022
1023        // 1.1) Prune right
1024        let unpruned_wit =
1025            HashMap::from([(Arc::from("wit1"), Value::left(Value::u64(0), Final::u64()))]);
1026        let pruned_prog = r#"wit1 := witness : 1 -> 2^64 + 1 -- right sub type became unit
1027input := pair wit1 unit : 1 -> (2^64 + 1) * 1
1028process := assertl (take jet_is_zero_64) #{take jet_is_zero_64} : (2^64 + 1) * 1 -> 2 -- case became assertl
1029main := comp input comp process jet_verify : 1 -> 1"#;
1030        let pruned_wit =
1031            HashMap::from([(Arc::from("wit1"), Value::left(Value::u64(0), Final::unit()))]);
1032        assert_correct_pruning::<crate::jet::Elements>(
1033            prune_sum,
1034            &unpruned_wit,
1035            pruned_prog,
1036            &pruned_wit,
1037            &env,
1038        );
1039
1040        // 1.2) Prune left
1041        let unpruned_wit = HashMap::from([(
1042            Arc::from("wit1"),
1043            Value::right(Final::unit(), Value::u64(0)),
1044        )]);
1045        let pruned_prog = r#"wit1 := witness : 1 -> 1 + 2^64 -- left sub type became unit
1046input := pair wit1 unit : 1 -> (1 + 2^64) * 1
1047process := assertr #{take jet_is_zero_64} (take jet_is_zero_64) : (1 + 2^64) * 1 -> 2 -- case became assertr
1048main := comp input comp process jet_verify : 1 -> 1"#;
1049        let pruned_wit = HashMap::from([(
1050            Arc::from("wit1"),
1051            Value::right(Final::unit(), Value::u64(0)),
1052        )]);
1053        assert_correct_pruning::<crate::jet::Elements>(
1054            prune_sum,
1055            &unpruned_wit,
1056            pruned_prog,
1057            &pruned_wit,
1058            &env,
1059        );
1060    }
1061}