1use crate::analysis::NodeBounds;
4use crate::bit_machine::{ExecutionError, PruneTracker, SetTracker};
5use crate::dag::{DagLike, InternalSharing, MaxSharing, PostOrderIterItem};
6use crate::jet::{Jet, JetEnvironment};
7use crate::types::{self, arrow::FinalArrow};
8use crate::{encode, BitMachine};
9use crate::{Amr, BitIter, BitWriter, Cmr, DecodeError, 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 {
23 never: std::convert::Infallible,
25}
26
27impl Marker for Redeem {
28 type CachedData = Arc<RedeemData>;
29 type Witness = Value;
30 type Disconnect = Arc<RedeemNode>;
31 type SharingId = Ihr;
32
33 fn compute_sharing_id(_: Cmr, cached_data: &Arc<RedeemData>) -> Option<Ihr> {
34 Some(cached_data.ihr)
35 }
36}
37
38pub type RedeemNode = Node<Redeem>;
39
40#[derive(Clone, Debug)]
41pub struct RedeemData {
42 amr: Amr,
43 imr: Imr,
44 ihr: Ihr,
45 arrow: FinalArrow,
46 bounds: NodeBounds,
47}
48
49impl PartialEq for RedeemData {
50 fn eq(&self, other: &Self) -> bool {
51 self.ihr == other.ihr
52 }
53}
54impl Eq for RedeemData {}
55
56impl std::hash::Hash for RedeemData {
57 fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
58 self.ihr.hash(hasher)
59 }
60}
61
62impl RedeemData {
63 pub fn new(arrow: FinalArrow, inner: Inner<&Arc<Self>, &Arc<Self>, Value>) -> Self {
64 let (amr, imr, bounds) = match inner {
65 Inner::Iden => (
66 Amr::iden(&arrow),
67 Imr::iden(),
68 NodeBounds::iden(arrow.source.bit_width()),
69 ),
70 Inner::Unit => (Amr::unit(&arrow), Imr::unit(), NodeBounds::unit()),
71 Inner::InjL(child) => (
72 Amr::injl(&arrow, child.amr),
73 Imr::injl(child.imr),
74 NodeBounds::injl(child.bounds),
75 ),
76 Inner::InjR(child) => (
77 Amr::injr(&arrow, child.amr),
78 Imr::injr(child.imr),
79 NodeBounds::injr(child.bounds),
80 ),
81 Inner::Take(child) => (
82 Amr::take(&arrow, child.amr),
83 Imr::take(child.imr),
84 NodeBounds::take(child.bounds),
85 ),
86 Inner::Drop(child) => (
87 Amr::drop(&arrow, child.amr),
88 Imr::drop(child.imr),
89 NodeBounds::drop(child.bounds),
90 ),
91 Inner::Comp(left, right) => (
92 Amr::comp(&arrow, &left.arrow, left.amr, right.amr),
93 Imr::comp(left.imr, right.imr),
94 NodeBounds::comp(left.bounds, right.bounds, left.arrow.target.bit_width()),
95 ),
96 Inner::Case(left, right) => (
97 Amr::case(&arrow, left.amr, right.amr),
98 Imr::case(left.imr, right.imr),
99 NodeBounds::case(left.bounds, right.bounds),
100 ),
101 Inner::AssertL(left, r_cmr) => (
102 Amr::assertl(&arrow, left.amr, r_cmr.into()),
103 Imr::case(left.imr, r_cmr.into()),
104 NodeBounds::assertl(left.bounds),
105 ),
106 Inner::AssertR(l_cmr, right) => (
107 Amr::assertr(&arrow, l_cmr.into(), right.amr),
108 Imr::case(l_cmr.into(), right.imr),
109 NodeBounds::assertr(right.bounds),
110 ),
111 Inner::Pair(left, right) => (
112 Amr::pair(&arrow, &left.arrow, &right.arrow, left.amr, right.amr),
113 Imr::pair(left.imr, right.imr),
114 NodeBounds::pair(left.bounds, right.bounds),
115 ),
116 Inner::Disconnect(left, right) => (
117 Amr::disconnect(&arrow, &right.arrow, left.amr, right.amr),
118 Imr::disconnect(left.imr, right.imr),
119 NodeBounds::disconnect(
120 left.bounds,
121 right.bounds,
122 left.arrow.target.bit_width() - right.arrow.source.bit_width(),
123 left.arrow.source.bit_width(),
124 left.arrow.target.bit_width(),
125 ),
126 ),
127 Inner::Witness(ref value) => (
128 Amr::witness(&arrow, value),
129 Imr::witness(&arrow, value),
130 NodeBounds::witness(arrow.target.bit_width()),
131 ),
132 Inner::Fail(entropy) => (Amr::fail(entropy), Imr::fail(entropy), NodeBounds::fail()),
133 Inner::Jet(jet) => (
134 Amr::jet(jet.as_ref()),
135 Imr::jet(jet.as_ref()),
136 NodeBounds::jet(jet.as_ref()),
137 ),
138 Inner::Word(ref val) => (
139 Amr::const_word(val),
140 Imr::const_word(val),
141 NodeBounds::const_word(val),
142 ),
143 };
144
145 RedeemData {
146 amr,
147 imr,
148 ihr: Ihr::from_imr(imr, &arrow),
149 arrow,
150 bounds,
151 }
152 }
153}
154
155impl RedeemNode {
156 pub fn amr(&self) -> Amr {
158 self.data.amr
159 }
160
161 pub fn ihr(&self) -> Ihr {
163 self.data.ihr
164 }
165
166 pub fn arrow(&self) -> &FinalArrow {
168 &self.data.arrow
169 }
170
171 pub fn bounds(&self) -> NodeBounds {
173 self.data.bounds
174 }
175
176 pub fn unfinalize(&self) -> Result<Arc<CommitNode>, types::Error> {
179 struct Unfinalizer(PhantomData<()>);
180
181 impl Converter<Redeem, Commit> for Unfinalizer {
182 type Error = types::Error;
183 fn convert_witness(
184 &mut self,
185 _: &PostOrderIterItem<&RedeemNode>,
186 _: &Value,
187 ) -> Result<NoWitness, Self::Error> {
188 Ok(NoWitness)
189 }
190
191 fn convert_disconnect(
192 &mut self,
193 _: &PostOrderIterItem<&RedeemNode>,
194 _: Option<&Arc<CommitNode>>,
195 _: &Arc<RedeemNode>,
196 ) -> Result<NoDisconnect, Self::Error> {
197 Ok(NoDisconnect)
198 }
199
200 fn convert_data(
201 &mut self,
202 data: &PostOrderIterItem<&RedeemNode>,
203 inner: Inner<&Arc<CommitNode>, &NoDisconnect, &NoWitness>,
204 ) -> Result<Arc<CommitData>, Self::Error> {
205 let converted_data = inner.map(|node| node.cached_data());
206 Ok(Arc::new(CommitData::from_final(
207 data.node.data.arrow.shallow_clone(),
208 converted_data,
209 )))
210 }
211 }
212
213 self.convert::<MaxSharing<Redeem>, _, _>(&mut Unfinalizer(PhantomData))
214 }
215
216 pub fn to_construct_node<'brand>(
219 &self,
220 inference_context: &types::Context<'brand>,
221 ) -> Arc<ConstructNode<'brand>> {
222 struct ToConstruct<'a, 'brand> {
223 inference_context: &'a types::Context<'brand>,
224 }
225
226 impl<'brand> Converter<Redeem, Construct<'brand>> for ToConstruct<'_, 'brand> {
227 type Error = ();
228
229 fn convert_witness(
230 &mut self,
231 _: &PostOrderIterItem<&Node<Redeem>>,
232 witness: &Value,
233 ) -> Result<Option<Value>, Self::Error> {
234 Ok(Some(witness.clone()))
235 }
236
237 fn convert_disconnect(
238 &mut self,
239 _: &PostOrderIterItem<&Node<Redeem>>,
240 right: Option<&Arc<Node<Construct<'brand>>>>,
241 _: &Arc<RedeemNode>,
242 ) -> Result<Option<Arc<Node<Construct<'brand>>>>, Self::Error> {
243 Ok(right.cloned())
244 }
245
246 fn convert_data(
247 &mut self,
248 _: &PostOrderIterItem<&Node<Redeem>>,
249 inner: Inner<
250 &Arc<Node<Construct<'brand>>>,
251 &Option<Arc<ConstructNode<'brand>>>,
252 &Option<Value>,
253 >,
254 ) -> Result<ConstructData<'brand>, Self::Error> {
255 let inner = inner
256 .map(|node| node.cached_data())
257 .map_witness(|maybe_value| maybe_value.clone());
258 Ok(ConstructData::from_inner(self.inference_context, inner)
259 .expect("types were already finalized"))
260 }
261 }
262
263 self.convert::<InternalSharing, _, _>(&mut ToConstruct { inference_context })
264 .unwrap()
265 }
266
267 pub fn prune<JE: JetEnvironment>(&self, env: &JE) -> Result<Arc<RedeemNode>, ExecutionError> {
284 self.prune_with_tracker(env, &mut SetTracker::default())
285 }
286
287 pub fn prune_with_tracker<JE: JetEnvironment, T: PruneTracker>(
293 &self,
294 env: &JE,
295 tracker: &mut T,
296 ) -> Result<Arc<RedeemNode>, ExecutionError> {
297 struct Pruner<'brand, 't, T> {
298 inference_context: types::Context<'brand>,
299 tracker: &'t mut T,
300 }
301
302 impl<'brand, 't, T> Converter<Redeem, Construct<'brand>> for Pruner<'brand, 't, T>
303 where
304 T: PruneTracker,
305 {
306 type Error = std::convert::Infallible;
307
308 fn convert_witness(
309 &mut self,
310 _: &PostOrderIterItem<&RedeemNode>,
311 witness: &Value,
312 ) -> Result<Option<Value>, Self::Error> {
313 Ok(Some(witness.shallow_clone()))
316 }
317
318 fn convert_disconnect(
319 &mut self,
320 _: &PostOrderIterItem<&RedeemNode>,
321 right: Option<&Arc<ConstructNode<'brand>>>,
322 _: &Arc<RedeemNode>,
323 ) -> Result<Option<Arc<ConstructNode<'brand>>>, Self::Error> {
324 debug_assert!(
325 right.is_some(),
326 "disconnected branch should exist in unpruned redeem program"
327 );
328 Ok(right.map(Arc::clone))
329 }
330
331 fn prune_case(
332 &mut self,
333 data: &PostOrderIterItem<&RedeemNode>,
334 _left: &Arc<ConstructNode>,
335 _right: &Arc<ConstructNode>,
336 ) -> Result<Hide, Self::Error> {
337 match (
341 self.tracker.contains_left(data.node.ihr()),
342 self.tracker.contains_right(data.node.ihr()),
343 ) {
344 (true, true) => Ok(Hide::Neither),
345 (false, true) => Ok(Hide::Left),
346 (true, false) => Ok(Hide::Right),
347 (false, false) => Ok(Hide::Neither), }
349 }
350
351 fn convert_data(
352 &mut self,
353 _: &PostOrderIterItem<&RedeemNode>,
354 inner: Inner<
355 &Arc<ConstructNode<'brand>>,
356 &Option<Arc<ConstructNode<'brand>>>,
357 &Option<Value>,
358 >,
359 ) -> Result<ConstructData<'brand>, Self::Error> {
360 let converted_inner = inner
361 .map(|node| node.cached_data())
362 .map_witness(Option::<Value>::clone);
363 let retyped = ConstructData::from_inner(&self.inference_context, converted_inner)
364 .expect("pruned types should check out if unpruned types check out");
365 Ok(retyped)
366 }
367 }
368
369 struct Finalizer;
370
371 impl<'brand> Converter<Construct<'brand>, Redeem> for Finalizer {
372 type Error = std::convert::Infallible;
373
374 fn convert_witness(
375 &mut self,
376 data: &PostOrderIterItem<&ConstructNode>,
377 witness: &Option<Value>,
378 ) -> Result<Value, Self::Error> {
379 let pruned_target_ty = data
380 .node
381 .arrow()
382 .target
383 .finalize()
384 .expect("pruned types should check out if unpruned types check out");
385 let pruned_witness = witness
386 .as_ref()
387 .expect("witness node that originally stems from redeem program should be populated")
388 .prune(&pruned_target_ty)
389 .expect("pruned type should be shrunken version of unpruned type");
390 Ok(pruned_witness)
391 }
392
393 fn convert_disconnect(
394 &mut self,
395 _: &PostOrderIterItem<&ConstructNode>,
396 right: Option<&Arc<RedeemNode>>,
397 _: &Option<Arc<ConstructNode>>,
398 ) -> Result<Arc<RedeemNode>, Self::Error> {
399 Ok(right
400 .map(Arc::clone)
401 .expect("disconnect node that originally stems from redeem program should have all branches"))
402 }
403
404 fn convert_data(
405 &mut self,
406 data: &PostOrderIterItem<&ConstructNode>,
407 inner: Inner<&Arc<RedeemNode>, &Arc<RedeemNode>, &Value>,
408 ) -> Result<Arc<RedeemData>, Self::Error> {
409 let final_arrow = data
411 .node
412 .arrow()
413 .finalize()
414 .expect("pruned types should check out if unpruned types check out");
415 let converted_inner = inner
416 .map(|node| node.cached_data())
417 .map_disconnect(|node| node.cached_data())
418 .map_witness(Value::shallow_clone);
419 Ok(Arc::new(RedeemData::new(final_arrow, converted_inner)))
420 }
421 }
422
423 let mut mac = BitMachine::for_program(self)?;
426 mac.exec_with_tracker(self, env, tracker)?;
427
428 types::Context::with_context(|inference_context| {
432 let pruned_witness_program = self
433 .convert::<InternalSharing, _, _>(&mut Pruner {
434 inference_context,
435 tracker,
436 })
437 .expect("pruning unused branches is infallible");
438
439 Ok(pruned_witness_program
443 .convert::<InternalSharing, _, _>(&mut Finalizer)
444 .expect("finalization is infallible"))
445 })
446 }
447
448 pub fn decode<I1, I2, J: Jet>(
450 program: BitIter<I1>,
451 mut witness: BitIter<I2>,
452 ) -> Result<Arc<Self>, DecodeError>
453 where
454 I1: Iterator<Item = u8>,
455 I2: Iterator<Item = u8>,
456 {
457 struct DecodeFinalizer<'bits, I: Iterator<Item = u8>> {
459 bits: &'bits mut BitIter<I>,
460 }
461
462 impl<'brand, I: Iterator<Item = u8>> Converter<Construct<'brand>, Redeem>
463 for DecodeFinalizer<'_, I>
464 {
465 type Error = DecodeError;
466 fn convert_witness(
467 &mut self,
468 data: &PostOrderIterItem<&ConstructNode>,
469 _: &Option<Value>,
470 ) -> Result<Value, Self::Error> {
471 let arrow = data.node.data.arrow();
472 let target_ty = arrow.target.finalize().map_err(DecodeError::Type)?;
473 Value::from_compact_bits(self.bits, &target_ty)
474 .map_err(crate::decode::Error::from)
475 .map_err(DecodeError::Decode)
476 }
477
478 fn convert_disconnect(
479 &mut self,
480 _: &PostOrderIterItem<&ConstructNode>,
481 right: Option<&Arc<RedeemNode>>,
482 _: &Option<Arc<ConstructNode>>,
483 ) -> Result<Arc<RedeemNode>, Self::Error> {
484 if let Some(child) = right {
485 Ok(Arc::clone(child))
486 } else {
487 Err(DecodeError::DisconnectRedeemTime)
488 }
489 }
490
491 fn convert_data(
492 &mut self,
493 data: &PostOrderIterItem<&ConstructNode>,
494 inner: Inner<&Arc<RedeemNode>, &Arc<RedeemNode>, &Value>,
495 ) -> Result<Arc<RedeemData>, Self::Error> {
496 let arrow = data
497 .node
498 .data
499 .arrow()
500 .finalize()
501 .map_err(DecodeError::Type)?;
502 let converted_data = inner
503 .map(|node| node.cached_data())
504 .map_disconnect(|node| node.cached_data())
505 .map_witness(Value::shallow_clone);
506 Ok(Arc::new(RedeemData::new(arrow, converted_data)))
507 }
508 }
509
510 let program: Arc<Self> = types::Context::with_context(|ctx| {
512 let construct =
513 crate::ConstructNode::decode::<_, J>(&ctx, program).map_err(DecodeError::Decode)?;
514 construct
515 .set_arrow_to_program()
516 .map_err(DecodeError::Type)?;
517
518 construct.convert::<InternalSharing, _, _>(&mut DecodeFinalizer { bits: &mut witness })
521 })?;
522
523 witness
525 .close()
526 .map_err(crate::decode::Error::BitIter)
527 .map_err(DecodeError::Decode)?;
528
529 let mut ihrs: HashSet<Ihr> = HashSet::new();
533 for data in program.as_ref().post_order_iter::<InternalSharing>() {
534 if !ihrs.insert(data.node.ihr()) {
535 return Err(DecodeError::Decode(crate::decode::Error::SharingNotMaximal));
536 }
537 }
538
539 Ok(program)
540 }
541
542 #[cfg(feature = "base64")]
543 #[allow(clippy::should_implement_trait)] pub fn from_str<J: Jet>(prog: &str, wit: &str) -> Result<Arc<Self>, crate::ParseError> {
545 use crate::base64::engine::general_purpose;
546 use crate::base64::Engine as _;
547 use crate::hex::FromHex as _;
548
549 let v = general_purpose::STANDARD
550 .decode(prog)
551 .map_err(crate::ParseError::Base64)?;
552 let prog_iter = crate::BitIter::new(v.into_iter());
553
554 let v = Vec::from_hex(wit).map_err(crate::ParseError::Hex)?;
555 let wit_iter = crate::BitIter::new(v.into_iter());
556 Self::decode::<_, _, J>(prog_iter, wit_iter).map_err(crate::ParseError::Decode)
557 }
558
559 #[deprecated(since = "0.5.0", note = "use Self::encode_with_witness instead")]
563 pub fn encode(
564 &self,
565 prog: &mut BitWriter<&mut dyn io::Write>,
566 witness: &mut BitWriter<&mut dyn io::Write>,
567 ) -> io::Result<usize> {
568 let sharing_iter = self.post_order_iter::<MaxSharing<Redeem>>();
569 let program_bits = encode::encode_program(self, prog)?;
570 prog.flush_all()?;
571 let witness_bits = encode::encode_witness(sharing_iter.into_witnesses(), witness)?;
572 witness.flush_all()?;
573 Ok(program_bits + witness_bits)
574 }
575
576 #[deprecated(since = "0.5.0", note = "use Self::to_vec_with_witness instead")]
578 pub fn encode_to_vec(&self) -> (Vec<u8>, Vec<u8>) {
579 let mut ret_1 = vec![];
580 let mut ret_2 = vec![];
581 self.encode_with_witness(&mut ret_1, &mut ret_2).unwrap();
582 (ret_1, ret_2)
583 }
584}
585
586#[cfg(test)]
587mod tests {
588 use super::*;
589 #[cfg(feature = "human_encoding")]
590 use crate::human_encoding::Forest;
591 use crate::jet::Core;
592 use crate::node::SimpleFinalizer;
593 use hex::DisplayHex;
594 use std::fmt;
595 #[cfg(all(feature = "elements", feature = "human_encoding"))]
596 use {crate::types::Final, std::collections::HashMap};
597
598 #[cfg_attr(not(feature = "base64"), allow(unused_variables))]
599 #[track_caller]
600 fn assert_program_deserializable<J: Jet>(
601 prog_bytes: &[u8],
602 witness_bytes: &[u8],
603 cmr_str: &str,
604 amr_str: &str,
605 ihr_str: &str,
606 b64_str: &str,
607 ) -> Arc<RedeemNode> {
608 let prog_hex = prog_bytes.as_hex();
609 let witness_hex = witness_bytes.as_hex();
610
611 let prog = BitIter::from(prog_bytes);
612 let witness = BitIter::from(witness_bytes);
613 let prog = match RedeemNode::decode::<_, _, J>(prog, witness) {
614 Ok(prog) => prog,
615 Err(e) => panic!("program {} failed: {}", prog_hex, e),
616 };
617
618 assert_eq!(
619 prog.cmr().to_string(),
620 cmr_str,
621 "CMR mismatch (got {} expected {}) for program {}",
622 prog.cmr(),
623 cmr_str,
624 prog_hex,
625 );
626
627 assert_eq!(
628 prog.amr().to_string(),
629 amr_str,
630 "AMR mismatch (got {} expected {}) for program {}",
631 prog.amr(),
632 amr_str,
633 prog_hex,
634 );
635 assert_eq!(
636 prog.ihr().to_string(),
637 ihr_str,
638 "IHR mismatch (got {} expected {}) for program {}",
639 prog.ihr(),
640 ihr_str,
641 prog_hex,
642 );
643
644 let (reser_prog, reser_witness) = prog.to_vec_with_witness();
645 assert_eq!(
646 prog_bytes,
647 &reser_prog[..],
648 "program {} reserialized as {}",
649 prog_hex,
650 reser_prog.as_hex(),
651 );
652 assert_eq!(
653 witness_bytes,
654 &reser_witness[..],
655 "witness {} reserialized as {}",
656 witness_hex,
657 reser_witness.as_hex(),
658 );
659
660 #[cfg(feature = "base64")]
661 {
662 let disp = prog.display();
663 assert_eq!(prog.to_string(), b64_str);
664 assert_eq!(disp.program().to_string(), b64_str);
665 assert_eq!(
666 disp.witness().to_string(),
667 witness_bytes.as_hex().to_string()
668 );
669 }
670
671 prog
672 }
673
674 #[track_caller]
675 fn assert_program_not_deserializable<J: Jet>(
676 prog_bytes: &[u8],
677 witness_bytes: &[u8],
678 err: &dyn fmt::Display,
679 ) {
680 let prog_hex = prog_bytes.as_hex();
681 let witness_hex = witness_bytes.as_hex();
682 let err_str = err.to_string();
683
684 let prog = BitIter::from(prog_bytes);
685 let witness = BitIter::from(witness_bytes);
686 match RedeemNode::decode::<_, _, J>(prog, witness) {
687 Ok(prog) => panic!(
688 "Program {} wit {} succeded (expected error {}). Program parsed as:\n{:?}",
689 prog_hex, witness_hex, err, prog
690 ),
691 Err(e) if e.to_string() == err_str => {} Err(e) => panic!(
693 "Program {} wit {} failed with error {} (expected error {})",
694 prog_hex, witness_hex, e, err
695 ),
696 };
697 }
698
699 #[test]
700 fn encode_shared_witnesses() {
701 let eqwits = [0xcd, 0xdc, 0x51, 0xb6, 0xe2, 0x08, 0xc0, 0x40];
708 let iter = BitIter::from(&eqwits[..]);
709 let eqwits_prog = CommitNode::decode::<_, Core>(iter).unwrap();
710
711 let eqwits_final = eqwits_prog
712 .finalize(&mut SimpleFinalizer::new(std::iter::repeat(Value::u32(
713 0xDEADBEEF,
714 ))))
715 .unwrap();
716 let output = eqwits_final.to_vec_with_witness();
717
718 assert_eq!(
719 output,
720 (
721 [0xc9, 0xc4, 0x6d, 0xb8, 0x82, 0x30, 0x10].into(),
722 [0xde, 0xad, 0xbe, 0xef].into(),
723 ),
724 "output {} {}",
725 output.0.as_hex(),
726 output.1.as_hex()
727 );
728 }
729
730 #[test]
731 fn decode_shared_witnesses() {
732 assert_program_deserializable::<Core>(
736 &[0xc9, 0xc4, 0x6d, 0xb8, 0x82, 0x30, 0x10],
737 &[0xde, 0xad, 0xbe, 0xef],
738 "ee2d966aeccfba7f1f1e54bc130237a6ae575db9c1132193d513aeb14b18151a",
739 "1f98ab7a78af799dc2efd3f4288a5934f288a73502b79db581eaf7342798a415",
740 "ce44dd4dfa9589ee67ad70fd1122421baf0b37b2b18d244702c93a9cf032dd17",
741 "ycRtuIIwEA==",
742 );
743 }
744
745 #[test]
746 fn unshared_child() {
747 assert_program_not_deserializable::<Core>(
753 &[0xc1, 0x08, 0x04, 0x00],
754 &[],
755 &DecodeError::Decode(crate::decode::Error::SharingNotMaximal),
756 );
757 }
758
759 #[test]
760 fn witness_consumed() {
761 let prog = BitIter::from(&[0x24][..]);
763 let wit = BitIter::from(&[0x00][..]);
764 match RedeemNode::decode::<_, _, Core>(prog, wit) {
765 Err(DecodeError::Decode(crate::decode::Error::BitIter(
766 crate::BitIterCloseError::TrailingBytes { first_byte: 0 },
767 ))) => {} Err(e) => panic!("got incorrect error {e}"),
769 Ok(_) => panic!("accepted program with bad witness length"),
770 }
771 }
772
773 #[test]
774 fn shared_grandchild() {
775 assert_program_deserializable::<Core>(
784 &[0xc1, 0x00, 0x00, 0x01, 0x00],
785 &[],
786 "8a54101335ca2cf7e933d74cdb15f99becc4e540799ba5e2d19c00c9d7219e71",
787 "74e868bd640c250bc45522085158a9723fc7e277bb16a8d582c4012ebbb1f6f1",
788 "39b8f72bd1539de87d26673890603d6548cfc8b68571d996bdf9b1d8b557bd35",
789 "wQAAAQA=",
790 );
791 }
792
793 #[test]
794 #[rustfmt::skip]
795 fn assert_lr() {
796 assert_program_deserializable::<Core>(
800 &[
801 0xcd, 0x24, 0x08, 0x4b, 0x6f, 0x56, 0xdf, 0x77,
802 0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
803 0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
804 0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
805 0xef, 0x56, 0xdf, 0x77, 0x86, 0x01, 0x80,
806 ],
807 &[],
808 "abdd773fc7a503908739b4a63198416fdd470948830cb5a6516b98fe0a3bfa85",
809 "1362ee53ae75218ed51dc4bd46cdbfa585f934ac6c6c3ff787e27dce91ccd80b",
810 "251c6778129e0f12da3f2388ab30184e815e9d9456b5931e54802a6715d9ca42",
811 "zSQIS29W33fvVt9371bfd+9W33fvVt9371bfd+9W33fvVt93hgGA",
812 );
813
814
815 assert_program_deserializable::<Core>(
819 &[
820 0xcd, 0x25, 0x08, 0x6d, 0xea, 0xdb, 0xee, 0xfd,
821 0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
822 0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
823 0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
824 0xea, 0xdb, 0xee, 0xf4, 0x86, 0x01, 0x80,
825 ],
826 &[],
827 "f6c678dfb180b94567a9d524e05fbc893f6905e0e3db931ff01dc2701e783d4c",
828 "212d4fa3dbe2b33db1e11bb6f4cc973be5de0896a3775387a06056483b8feb0f",
829 "7a583edcc733b6bba66998110be403ac61fab2d93fc09ba3c84ab2509b538043",
830 "zSUIberb7v3q2+796tvu/erb7v3q2+796tvu/erb7v3q2+70hgGA",
831 );
832 }
833
834 #[test]
835 #[rustfmt::skip]
836 fn disconnect() {
837 assert_program_deserializable::<Core>(
843 &[0xc5, 0x02, 0x06, 0x24, 0x10],
844 &[],
845 "afe8f5f8bd3f64bfa51d2f29ffa22523604d9654c0d9862dbf2dc67ba097cbb2",
846 "15239708cb7b448cedc6a0b6401dce86ed74084056dd95831928860dd0c3ca67",
847 "9cdacb48b16e108ccbd6bcbce459a64056df285c2dc6e02dca6d13c4b1530fb0",
848 "xQIGJBA=",
849 );
850 }
851
852 #[test]
853 #[rustfmt::skip]
854 #[cfg(feature = "elements")]
855 fn disconnect2() {
856 assert_program_deserializable::<crate::jet::Elements>(
876 &[
877 0xd3, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce,
878 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, 0xd6, 0x79, 0x5f,
879 0x9c, 0x63, 0x47, 0x07, 0x02, 0xc0, 0xe2, 0x8d, 0x88, 0x10,
880 ],
881 &[
882 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce, 0x56, 0x3f,
883 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, 0xd6, 0x79, 0x5f, 0x9c, 0x63,
884 0xdb, 0x86, 0x8d, 0x45, 0xa0, 0xbc, 0x1d, 0x19, 0x01, 0x30, 0x2b, 0xc8, 0x7a, 0x87, 0x1c, 0xf1,
885 0x58, 0xe2, 0xbd, 0xe2, 0xcf, 0xa6, 0x45, 0xa8, 0x95, 0xc1, 0xb4, 0x5d, 0x68, 0xea, 0x24, 0xc0,
886 ],
887 "f3cd4537d7ebb201732203195b30b549b8dc0c2c6257b3a0d53bedb08ea02874",
888 "107fa80454ed0f2d95d7c18d307912b1497505b98de47198fee23b5018efa544",
889 "d52021c638ba742a90bead9b3055efd66091fb50bb131aa8b10eb7c13ef464d1",
890 "02kAAAAAAAAAAAAAADt4zlY/iaDtlBT1qiitDZbWeV+cY0cHAsDijYgQ",
891 );
892 }
893
894 #[test]
895 #[rustfmt::skip]
896 #[cfg(feature = "elements")]
897 fn disconnect3() {
898 assert_program_deserializable::<crate::jet::Elements>(
908 &[0xc9, 0x09, 0x20, 0x74, 0x90, 0x40],
909 &[],
910 "b689bdee289c8dd4e2e283358d187813363d441776cf826dafc27cc8a81ec441",
911 "3c68660a1afde7982ce4aa9d499ad382bc32f5f9ad894a5e915f76e66303a25b",
912 "85313720ee43ae0ee03f88b05e6d9e4494308c6897bdeb3e93b94559c3317484",
913 "yQkgdJBA",
914 );
915 }
916
917 #[test]
918 #[cfg(feature = "elements")]
919 fn decode_schnorr() {
920 #[rustfmt::skip]
921 let schnorr0 = vec![
922 0xc6, 0xd5, 0xf2, 0x61, 0x14, 0x03, 0x24, 0xb1, 0x86, 0x20, 0x92, 0x68, 0x9f, 0x0b, 0xf1, 0x3a,
923 0xa4, 0x53, 0x6a, 0x63, 0x90, 0x8b, 0x06, 0xdf, 0x33, 0x61, 0x0c, 0x03, 0xe2, 0x27, 0x79, 0xc0,
924 0x6d, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
925 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
926 0x00, 0x00, 0xe2, 0x8d, 0x8c, 0x04, 0x00,
927 ];
928 #[rustfmt::skip]
929 let schnorr0_wit = vec![
930 0xe9, 0x07, 0x83, 0x1f, 0x80, 0x84, 0x8d, 0x10, 0x69, 0xa5, 0x37, 0x1b, 0x40, 0x24, 0x10, 0x36,
931 0x4b, 0xdf, 0x1c, 0x5f, 0x83, 0x07, 0xb0, 0x08, 0x4c, 0x55, 0xf1, 0xce, 0x2d, 0xca, 0x82, 0x15,
932 0x25, 0xf6, 0x6a, 0x4a, 0x85, 0xea, 0x8b, 0x71, 0xe4, 0x82, 0xa7, 0x4f, 0x38, 0x2d, 0x2c, 0xe5,
933 0xeb, 0xee, 0xe8, 0xfd, 0xb2, 0x17, 0x2f, 0x47, 0x7d, 0xf4, 0x90, 0x0d, 0x31, 0x05, 0x36, 0xc0,
934 ];
935 assert_program_deserializable::<crate::jet::Elements>(
936 &schnorr0,
937 &schnorr0_wit,
938 "8a9e97676b24be7797d9ee0bf32dd76bcd78028e973025f785eae8dc91c8a0da",
939 "ec97c8774cb6bfb381fdbbcc8d964380fb3a3b45779322624490d6231ae777a4",
940 "ad7c38b16b9129646dc89b52cff144de94a80e383c4983b53de65e3575abcf38",
941 "xtXyYRQDJLGGIJJonwvxOqRTamOQiwbfM2EMA+InecBt8gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4o2MBAA=",
942 );
943 }
944
945 #[cfg(all(feature = "elements", feature = "human_encoding"))]
946 fn assert_correct_pruning<JE: JetEnvironment>(
947 unpruned_prog: &str,
948 unpruned_wit: &HashMap<Arc<str>, Value>,
949 expected_pruned_prog: &str,
950 expected_pruned_wit: &HashMap<Arc<str>, Value>,
951 env: &JE,
952 ) {
953 let unpruned_program = types::Context::with_context(|ctx| {
954 Forest::parse::<JE::Jet>(unpruned_prog)
955 .expect("unpruned program should parse")
956 .to_witness_node(&ctx, unpruned_wit)
957 .expect("unpruned program should have main")
958 .finalize_unpruned()
959 .expect("unpruned program should finalize")
960 });
961 let expected_unpruned_program = types::Context::with_context(|ctx| {
962 Forest::parse::<JE::Jet>(expected_pruned_prog)
963 .expect("expected pruned program should parse")
964 .to_witness_node(&ctx, expected_pruned_wit)
965 .expect("expected pruned program should have main")
966 .finalize_unpruned()
967 .expect("expected pruned program should finalize")
968 });
969
970 let mut mac = BitMachine::for_program(&unpruned_program)
971 .expect("unpruned program has reasonable bounds");
972 let unpruned_output = mac
973 .exec(&unpruned_program, env)
974 .expect("unpruned program should run without failure");
975
976 let pruned_program = unpruned_program
977 .prune(env)
978 .expect("pruning should not fail if execution succeeded");
979 assert_eq!(
980 pruned_program.ihr(),
981 expected_unpruned_program.ihr(),
982 "pruning result differs from expected result"
983 );
984
985 let mut mac =
986 BitMachine::for_program(&pruned_program).expect("pruned program has reasonable bounds");
987 let pruned_output = mac
988 .exec(&pruned_program, env)
989 .expect("pruned program should run without failure");
990 assert_eq!(
991 unpruned_output, pruned_output,
992 "pruned program should return same output as unpruned program"
993 );
994 }
995
996 #[test]
997 #[cfg(all(feature = "elements", feature = "human_encoding"))]
998 fn prune() {
999 use crate::jet::ElementsTxEnv;
1000
1001 let env = crate::jet::elements::ElementsEnv::dummy();
1002
1003 let unpruned_prog = r#"wit1 := witness : 1 -> 2
1007wit2 := witness : 1 -> 2^64 * 2^64
1008input := pair wit1 wit2 : 1 -> 2 * (2^64 * 2^64)
1009process := case (drop take jet_is_zero_64) (drop drop jet_is_zero_64) : 2 * (2^64 * 2^64) -> 2
1010main := comp input comp process jet_verify : 1 -> 1"#;
1011
1012 let unpruned_wit = HashMap::from([
1014 (Arc::from("wit1"), Value::u1(0)),
1015 (
1016 Arc::from("wit2"),
1017 Value::product(Value::u64(0), Value::u64(0)),
1018 ),
1019 ]);
1020 let pruned_prog = r#"wit1 := witness : 1 -> 2
1021wit2 := witness : 1 -> 2^64 * 1 -- right component was pruned
1022input := pair wit1 wit2 : 1 -> 2 * (2^64 * 1)
1023process := assertl (drop take jet_is_zero_64) #{drop drop jet_is_zero_64} : 2 * (2^64 * 1) -> 2 -- case became assertl
1024main := comp input comp process jet_verify : 1 -> 1"#;
1025 let pruned_wit = HashMap::from([
1026 (Arc::from("wit1"), Value::u1(0)),
1027 (
1028 Arc::from("wit2"),
1029 Value::product(Value::u64(0), Value::unit()),
1030 ),
1031 ]);
1032 assert_correct_pruning::<ElementsTxEnv>(
1033 unpruned_prog,
1034 &unpruned_wit,
1035 pruned_prog,
1036 &pruned_wit,
1037 &env,
1038 );
1039
1040 let unpruned_wit = HashMap::from([
1042 (Arc::from("wit1"), Value::u1(1)),
1043 (
1044 Arc::from("wit2"),
1045 Value::product(Value::u64(0), Value::u64(0)),
1046 ),
1047 ]);
1048 let pruned_prog = r#"wit1 := witness : 1 -> 2
1049wit2 := witness : 1 -> 1 * 2^64 -- left component was pruned
1050input := pair wit1 wit2 : 1 -> 2 * (1 * 2^64)
1051process := assertr #{drop take jet_is_zero_64} (drop drop jet_is_zero_64) : 2 * (1 * 2^64) -> 2 -- case became assertr
1052main := comp input comp process jet_verify : 1 -> 1"#;
1053 let pruned_wit = HashMap::from([
1054 (Arc::from("wit1"), Value::u1(1)),
1055 (
1056 Arc::from("wit2"),
1057 Value::product(Value::unit(), Value::u64(0)),
1058 ),
1059 ]);
1060 assert_correct_pruning::<ElementsTxEnv>(
1061 unpruned_prog,
1062 &unpruned_wit,
1063 pruned_prog,
1064 &pruned_wit,
1065 &env,
1066 );
1067
1068 let prune_sum = r#"wit1 := witness : 1 -> 2^64 + 2^64
1072input := pair wit1 unit : 1 -> (2^64 + 2^64) * 1
1073process := case (take jet_is_zero_64) (take jet_is_zero_64) : (2^64 + 2^64) * 1 -> 2
1074main := comp input comp process jet_verify : 1 -> 1"#;
1075
1076 let unpruned_wit =
1078 HashMap::from([(Arc::from("wit1"), Value::left(Value::u64(0), Final::u64()))]);
1079 let pruned_prog = r#"wit1 := witness : 1 -> 2^64 + 1 -- right sub type became unit
1080input := pair wit1 unit : 1 -> (2^64 + 1) * 1
1081process := assertl (take jet_is_zero_64) #{take jet_is_zero_64} : (2^64 + 1) * 1 -> 2 -- case became assertl
1082main := comp input comp process jet_verify : 1 -> 1"#;
1083 let pruned_wit =
1084 HashMap::from([(Arc::from("wit1"), Value::left(Value::u64(0), Final::unit()))]);
1085 assert_correct_pruning::<ElementsTxEnv>(
1086 prune_sum,
1087 &unpruned_wit,
1088 pruned_prog,
1089 &pruned_wit,
1090 &env,
1091 );
1092
1093 let unpruned_wit = HashMap::from([(
1095 Arc::from("wit1"),
1096 Value::right(Final::unit(), Value::u64(0)),
1097 )]);
1098 let pruned_prog = r#"wit1 := witness : 1 -> 1 + 2^64 -- left sub type became unit
1099input := pair wit1 unit : 1 -> (1 + 2^64) * 1
1100process := assertr #{take jet_is_zero_64} (take jet_is_zero_64) : (1 + 2^64) * 1 -> 2 -- case became assertr
1101main := comp input comp process jet_verify : 1 -> 1"#;
1102 let pruned_wit = HashMap::from([(
1103 Arc::from("wit1"),
1104 Value::right(Final::unit(), Value::u64(0)),
1105 )]);
1106 assert_correct_pruning::<ElementsTxEnv>(
1107 prune_sum,
1108 &unpruned_wit,
1109 pruned_prog,
1110 &pruned_wit,
1111 &env,
1112 );
1113 }
1114}
1115
1116#[cfg(bench)]
1117#[cfg(feature = "elements")]
1118mod benches {
1119 use super::*;
1120
1121 use crate::bit_encoding::BitIter;
1122 use crate::jet::Elements;
1123
1124 use test::{black_box, Bencher};
1125
1126 #[bench]
1127 fn decode_fixed_program(bh: &mut Bencher) {
1128 let prog = &[
1129 0xd3, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b,
1130 0x78, 0xce, 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d,
1131 0x96, 0xd6, 0x79, 0x5f, 0x9c, 0x63, 0x47, 0x07, 0x02, 0xc0, 0xe2, 0x8d, 0x88, 0x10,
1132 ][..];
1133 let witness = &[
1134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce,
1135 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, 0xd6,
1136 0x79, 0x5f, 0x9c, 0x63, 0xdb, 0x86, 0x8d, 0x45, 0xa0, 0xbc, 0x1d, 0x19, 0x01, 0x30,
1137 0x2b, 0xc8, 0x7a, 0x87, 0x1c, 0xf1, 0x58, 0xe2, 0xbd, 0xe2, 0xcf, 0xa6, 0x45, 0xa8,
1138 0x95, 0xc1, 0xb4, 0x5d, 0x68, 0xea, 0x24, 0xc0,
1139 ][..];
1140 bh.iter(|| {
1141 let prog = BitIter::from(prog);
1142 let witness = BitIter::from(witness);
1143 black_box(RedeemNode::<Elements>::decode(
1144 black_box(prog),
1145 black_box(witness),
1146 ))
1147 .unwrap();
1148 });
1149 }
1150}