1use crate::analysis::NodeBounds;
4use crate::bit_machine::{ExecutionError, PruneTracker, 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, 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<J> {
23 never: std::convert::Infallible,
25 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 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 pub fn amr(&self) -> Amr {
162 self.data.amr
163 }
164
165 pub fn ihr(&self) -> Ihr {
167 self.data.ihr
168 }
169
170 pub fn arrow(&self) -> &FinalArrow {
172 &self.data.arrow
173 }
174
175 pub fn bounds(&self) -> NodeBounds {
177 self.data.bounds
178 }
179
180 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 pub fn to_construct_node<'brand>(
223 &self,
224 inference_context: &types::Context<'brand>,
225 ) -> Arc<ConstructNode<'brand, J>> {
226 struct ToConstruct<'a, 'brand, J> {
227 inference_context: &'a types::Context<'brand>,
228 phantom: PhantomData<J>,
229 }
230
231 impl<'brand, J: Jet> Converter<Redeem<J>, Construct<'brand, J>> for ToConstruct<'_, 'brand, J> {
232 type Error = ();
233
234 fn convert_witness(
235 &mut self,
236 _: &PostOrderIterItem<&Node<Redeem<J>>>,
237 witness: &Value,
238 ) -> Result<Option<Value>, Self::Error> {
239 Ok(Some(witness.clone()))
240 }
241
242 fn convert_disconnect(
243 &mut self,
244 _: &PostOrderIterItem<&Node<Redeem<J>>>,
245 right: Option<&Arc<Node<Construct<'brand, J>>>>,
246 _: &Arc<RedeemNode<J>>,
247 ) -> Result<Option<Arc<Node<Construct<'brand, J>>>>, Self::Error> {
248 Ok(right.cloned())
249 }
250
251 fn convert_data(
252 &mut self,
253 _: &PostOrderIterItem<&Node<Redeem<J>>>,
254 inner: Inner<
255 &Arc<Node<Construct<'brand, J>>>,
256 J,
257 &Option<Arc<ConstructNode<'brand, J>>>,
258 &Option<Value>,
259 >,
260 ) -> Result<ConstructData<'brand, J>, Self::Error> {
261 let inner = inner
262 .map(|node| node.cached_data())
263 .map_witness(|maybe_value| maybe_value.clone());
264 Ok(ConstructData::from_inner(self.inference_context, inner)
265 .expect("types were already finalized"))
266 }
267 }
268
269 self.convert::<InternalSharing, _, _>(&mut ToConstruct {
270 inference_context,
271 phantom: PhantomData,
272 })
273 .unwrap()
274 }
275
276 pub fn prune(&self, env: &J::Environment) -> Result<Arc<RedeemNode<J>>, ExecutionError> {
293 self.prune_with_tracker(env, &mut SetTracker::default())
294 }
295
296 pub fn prune_with_tracker<T: PruneTracker<J>>(
302 &self,
303 env: &J::Environment,
304 tracker: &mut T,
305 ) -> Result<Arc<RedeemNode<J>>, ExecutionError> {
306 struct Pruner<'brand, 't, J, T> {
307 inference_context: types::Context<'brand>,
308 tracker: &'t mut T,
309 phantom: PhantomData<J>,
310 }
311
312 impl<'brand, 't, J, T> Converter<Redeem<J>, Construct<'brand, J>> for Pruner<'brand, 't, J, T>
313 where
314 J: Jet,
315 T: PruneTracker<J>,
316 {
317 type Error = std::convert::Infallible;
318
319 fn convert_witness(
320 &mut self,
321 _: &PostOrderIterItem<&RedeemNode<J>>,
322 witness: &Value,
323 ) -> Result<Option<Value>, Self::Error> {
324 Ok(Some(witness.shallow_clone()))
327 }
328
329 fn convert_disconnect(
330 &mut self,
331 _: &PostOrderIterItem<&RedeemNode<J>>,
332 right: Option<&Arc<ConstructNode<'brand, J>>>,
333 _: &Arc<RedeemNode<J>>,
334 ) -> Result<Option<Arc<ConstructNode<'brand, J>>>, Self::Error> {
335 debug_assert!(
336 right.is_some(),
337 "disconnected branch should exist in unpruned redeem program"
338 );
339 Ok(right.map(Arc::clone))
340 }
341
342 fn prune_case(
343 &mut self,
344 data: &PostOrderIterItem<&RedeemNode<J>>,
345 _left: &Arc<ConstructNode<J>>,
346 _right: &Arc<ConstructNode<J>>,
347 ) -> Result<Hide, Self::Error> {
348 match (
352 self.tracker.contains_left(data.node.ihr()),
353 self.tracker.contains_right(data.node.ihr()),
354 ) {
355 (true, true) => Ok(Hide::Neither),
356 (false, true) => Ok(Hide::Left),
357 (true, false) => Ok(Hide::Right),
358 (false, false) => Ok(Hide::Neither), }
360 }
361
362 fn convert_data(
363 &mut self,
364 _: &PostOrderIterItem<&RedeemNode<J>>,
365 inner: Inner<
366 &Arc<ConstructNode<'brand, J>>,
367 J,
368 &Option<Arc<ConstructNode<'brand, J>>>,
369 &Option<Value>,
370 >,
371 ) -> Result<ConstructData<'brand, J>, Self::Error> {
372 let converted_inner = inner
373 .map(|node| node.cached_data())
374 .map_witness(Option::<Value>::clone);
375 let retyped = ConstructData::from_inner(&self.inference_context, converted_inner)
376 .expect("pruned types should check out if unpruned types check out");
377 Ok(retyped)
378 }
379 }
380
381 struct Finalizer<J>(PhantomData<J>);
382
383 impl<'brand, J: Jet> Converter<Construct<'brand, J>, Redeem<J>> for Finalizer<J> {
384 type Error = std::convert::Infallible;
385
386 fn convert_witness(
387 &mut self,
388 data: &PostOrderIterItem<&ConstructNode<J>>,
389 witness: &Option<Value>,
390 ) -> Result<Value, Self::Error> {
391 let pruned_target_ty = data
392 .node
393 .arrow()
394 .target
395 .finalize()
396 .expect("pruned types should check out if unpruned types check out");
397 let pruned_witness = witness
398 .as_ref()
399 .expect("witness node that originally stems from redeem program should be populated")
400 .prune(&pruned_target_ty)
401 .expect("pruned type should be shrunken version of unpruned type");
402 Ok(pruned_witness)
403 }
404
405 fn convert_disconnect(
406 &mut self,
407 _: &PostOrderIterItem<&ConstructNode<J>>,
408 right: Option<&Arc<RedeemNode<J>>>,
409 _: &Option<Arc<ConstructNode<J>>>,
410 ) -> Result<Arc<RedeemNode<J>>, Self::Error> {
411 Ok(right
412 .map(Arc::clone)
413 .expect("disconnect node that originally stems from redeem program should have all branches"))
414 }
415
416 fn convert_data(
417 &mut self,
418 data: &PostOrderIterItem<&ConstructNode<J>>,
419 inner: Inner<&Arc<RedeemNode<J>>, J, &Arc<RedeemNode<J>>, &Value>,
420 ) -> Result<Arc<RedeemData<J>>, Self::Error> {
421 let final_arrow = data
423 .node
424 .arrow()
425 .finalize()
426 .expect("pruned types should check out if unpruned types check out");
427 let converted_inner = inner
428 .map(|node| node.cached_data())
429 .map_disconnect(|node| node.cached_data())
430 .map_witness(Value::shallow_clone);
431 Ok(Arc::new(RedeemData::new(final_arrow, converted_inner)))
432 }
433 }
434
435 let mut mac = BitMachine::for_program(self)?;
438 mac.exec_with_tracker(self, env, tracker)?;
439
440 types::Context::with_context(|inference_context| {
444 let pruned_witness_program = self
445 .convert::<InternalSharing, _, _>(&mut Pruner {
446 inference_context,
447 tracker,
448 phantom: PhantomData,
449 })
450 .expect("pruning unused branches is infallible");
451
452 Ok(pruned_witness_program
456 .convert::<InternalSharing, _, _>(&mut Finalizer(PhantomData))
457 .expect("finalization is infallible"))
458 })
459 }
460
461 pub fn decode<I1, I2>(
463 program: BitIter<I1>,
464 mut witness: BitIter<I2>,
465 ) -> Result<Arc<Self>, DecodeError>
466 where
467 I1: Iterator<Item = u8>,
468 I2: Iterator<Item = u8>,
469 {
470 struct DecodeFinalizer<'bits, J: Jet, I: Iterator<Item = u8>> {
472 bits: &'bits mut BitIter<I>,
473 phantom: PhantomData<J>,
474 }
475
476 impl<'brand, J: Jet, I: Iterator<Item = u8>> Converter<Construct<'brand, J>, Redeem<J>>
477 for DecodeFinalizer<'_, J, I>
478 {
479 type Error = DecodeError;
480 fn convert_witness(
481 &mut self,
482 data: &PostOrderIterItem<&ConstructNode<J>>,
483 _: &Option<Value>,
484 ) -> Result<Value, Self::Error> {
485 let arrow = data.node.data.arrow();
486 let target_ty = arrow.target.finalize().map_err(DecodeError::Type)?;
487 Value::from_compact_bits(self.bits, &target_ty)
488 .map_err(crate::decode::Error::from)
489 .map_err(DecodeError::Decode)
490 }
491
492 fn convert_disconnect(
493 &mut self,
494 _: &PostOrderIterItem<&ConstructNode<J>>,
495 right: Option<&Arc<RedeemNode<J>>>,
496 _: &Option<Arc<ConstructNode<J>>>,
497 ) -> Result<Arc<RedeemNode<J>>, Self::Error> {
498 if let Some(child) = right {
499 Ok(Arc::clone(child))
500 } else {
501 Err(DecodeError::DisconnectRedeemTime)
502 }
503 }
504
505 fn convert_data(
506 &mut self,
507 data: &PostOrderIterItem<&ConstructNode<J>>,
508 inner: Inner<&Arc<RedeemNode<J>>, J, &Arc<RedeemNode<J>>, &Value>,
509 ) -> Result<Arc<RedeemData<J>>, Self::Error> {
510 let arrow = data
511 .node
512 .data
513 .arrow()
514 .finalize()
515 .map_err(DecodeError::Type)?;
516 let converted_data = inner
517 .map(|node| node.cached_data())
518 .map_disconnect(|node| node.cached_data())
519 .map_witness(Value::shallow_clone);
520 Ok(Arc::new(RedeemData::new(arrow, converted_data)))
521 }
522 }
523
524 let program: Arc<Self> = types::Context::with_context(|ctx| {
526 let construct =
527 crate::ConstructNode::decode(&ctx, program).map_err(DecodeError::Decode)?;
528 construct
529 .set_arrow_to_program()
530 .map_err(DecodeError::Type)?;
531
532 construct.convert::<InternalSharing, _, _>(&mut DecodeFinalizer {
535 bits: &mut witness,
536 phantom: PhantomData,
537 })
538 })?;
539
540 witness
542 .close()
543 .map_err(crate::decode::Error::BitIter)
544 .map_err(DecodeError::Decode)?;
545
546 let mut ihrs: HashSet<Ihr> = HashSet::new();
550 for data in program.as_ref().post_order_iter::<InternalSharing>() {
551 if !ihrs.insert(data.node.ihr()) {
552 return Err(DecodeError::Decode(crate::decode::Error::SharingNotMaximal));
553 }
554 }
555
556 Ok(program)
557 }
558
559 #[cfg(feature = "base64")]
560 #[allow(clippy::should_implement_trait)] pub fn from_str(prog: &str, wit: &str) -> Result<Arc<Self>, crate::ParseError> {
562 use crate::base64::engine::general_purpose;
563 use crate::base64::Engine as _;
564 use crate::hex::FromHex as _;
565
566 let v = general_purpose::STANDARD
567 .decode(prog)
568 .map_err(crate::ParseError::Base64)?;
569 let prog_iter = crate::BitIter::new(v.into_iter());
570
571 let v = Vec::from_hex(wit).map_err(crate::ParseError::Hex)?;
572 let wit_iter = crate::BitIter::new(v.into_iter());
573 Self::decode(prog_iter, wit_iter).map_err(crate::ParseError::Decode)
574 }
575
576 #[deprecated(since = "0.5.0", note = "use Self::encode_with_witness instead")]
580 pub fn encode<W1, W2>(
581 &self,
582 prog: &mut BitWriter<W1>,
583 witness: &mut BitWriter<W2>,
584 ) -> io::Result<usize>
585 where
586 W1: io::Write,
587 W2: io::Write,
588 {
589 let sharing_iter = self.post_order_iter::<MaxSharing<Redeem<J>>>();
590 let program_bits = encode::encode_program(self, prog)?;
591 prog.flush_all()?;
592 let witness_bits = encode::encode_witness(sharing_iter.into_witnesses(), witness)?;
593 witness.flush_all()?;
594 Ok(program_bits + witness_bits)
595 }
596
597 #[deprecated(since = "0.5.0", note = "use Self::to_vec_with_witness instead")]
599 pub fn encode_to_vec(&self) -> (Vec<u8>, Vec<u8>) {
600 let mut ret_1 = vec![];
601 let mut ret_2 = vec![];
602 self.encode_with_witness(&mut ret_1, &mut ret_2).unwrap();
603 (ret_1, ret_2)
604 }
605}
606
607#[cfg(test)]
608mod tests {
609 use super::*;
610 use crate::human_encoding::Forest;
611 use crate::jet::Core;
612 use crate::node::SimpleFinalizer;
613 use crate::types::Final;
614 use hex::DisplayHex;
615 use std::collections::HashMap;
616 use std::fmt;
617
618 #[cfg_attr(not(feature = "base64"), allow(unused_variables))]
619 #[track_caller]
620 fn assert_program_deserializable<J: Jet>(
621 prog_bytes: &[u8],
622 witness_bytes: &[u8],
623 cmr_str: &str,
624 amr_str: &str,
625 ihr_str: &str,
626 b64_str: &str,
627 ) -> Arc<RedeemNode<J>> {
628 let prog_hex = prog_bytes.as_hex();
629 let witness_hex = witness_bytes.as_hex();
630
631 let prog = BitIter::from(prog_bytes);
632 let witness = BitIter::from(witness_bytes);
633 let prog = match RedeemNode::<J>::decode(prog, witness) {
634 Ok(prog) => prog,
635 Err(e) => panic!("program {} failed: {}", prog_hex, e),
636 };
637
638 assert_eq!(
639 prog.cmr().to_string(),
640 cmr_str,
641 "CMR mismatch (got {} expected {}) for program {}",
642 prog.cmr(),
643 cmr_str,
644 prog_hex,
645 );
646
647 assert_eq!(
648 prog.amr().to_string(),
649 amr_str,
650 "AMR mismatch (got {} expected {}) for program {}",
651 prog.amr(),
652 amr_str,
653 prog_hex,
654 );
655 assert_eq!(
656 prog.ihr().to_string(),
657 ihr_str,
658 "IHR mismatch (got {} expected {}) for program {}",
659 prog.ihr(),
660 ihr_str,
661 prog_hex,
662 );
663
664 let (reser_prog, reser_witness) = prog.to_vec_with_witness();
665 assert_eq!(
666 prog_bytes,
667 &reser_prog[..],
668 "program {} reserialized as {}",
669 prog_hex,
670 reser_prog.as_hex(),
671 );
672 assert_eq!(
673 witness_bytes,
674 &reser_witness[..],
675 "witness {} reserialized as {}",
676 witness_hex,
677 reser_witness.as_hex(),
678 );
679
680 #[cfg(feature = "base64")]
681 {
682 let disp = prog.display();
683 assert_eq!(prog.to_string(), b64_str);
684 assert_eq!(disp.program().to_string(), b64_str);
685 assert_eq!(
686 disp.witness().to_string(),
687 witness_bytes.as_hex().to_string()
688 );
689 }
690
691 prog
692 }
693
694 #[track_caller]
695 fn assert_program_not_deserializable<J: Jet>(
696 prog_bytes: &[u8],
697 witness_bytes: &[u8],
698 err: &dyn fmt::Display,
699 ) {
700 let prog_hex = prog_bytes.as_hex();
701 let witness_hex = witness_bytes.as_hex();
702 let err_str = err.to_string();
703
704 let prog = BitIter::from(prog_bytes);
705 let witness = BitIter::from(witness_bytes);
706 match RedeemNode::<J>::decode(prog, witness) {
707 Ok(prog) => panic!(
708 "Program {} wit {} succeded (expected error {}). Program parsed as:\n{:?}",
709 prog_hex, witness_hex, err, prog
710 ),
711 Err(e) if e.to_string() == err_str => {} Err(e) => panic!(
713 "Program {} wit {} failed with error {} (expected error {})",
714 prog_hex, witness_hex, e, err
715 ),
716 };
717 }
718
719 #[test]
720 fn encode_shared_witnesses() {
721 let eqwits = [0xcd, 0xdc, 0x51, 0xb6, 0xe2, 0x08, 0xc0, 0x40];
728 let iter = BitIter::from(&eqwits[..]);
729 let eqwits_prog = CommitNode::<Core>::decode(iter).unwrap();
730
731 let eqwits_final = eqwits_prog
732 .finalize(&mut SimpleFinalizer::new(std::iter::repeat(Value::u32(
733 0xDEADBEEF,
734 ))))
735 .unwrap();
736 let output = eqwits_final.to_vec_with_witness();
737
738 assert_eq!(
739 output,
740 (
741 [0xc9, 0xc4, 0x6d, 0xb8, 0x82, 0x30, 0x10].into(),
742 [0xde, 0xad, 0xbe, 0xef].into(),
743 ),
744 "output {} {}",
745 output.0.as_hex(),
746 output.1.as_hex()
747 );
748 }
749
750 #[test]
751 fn decode_shared_witnesses() {
752 assert_program_deserializable::<Core>(
756 &[0xc9, 0xc4, 0x6d, 0xb8, 0x82, 0x30, 0x10],
757 &[0xde, 0xad, 0xbe, 0xef],
758 "d7969920eff9a1ed0359aaa8545b239c69969e22c304c645a7b49bcc976a40a8",
759 "f7acbb077e7661a08384818bc8e3a275ed42ad446252575a35a35f71689fef78",
760 "3ce4a6390b4e4bda6330acda4800e66e5d2cae0f5a2888564c706f2b910146b8",
761 "ycRtuIIwEA==",
762 );
763 }
764
765 #[test]
766 fn unshared_child() {
767 assert_program_not_deserializable::<Core>(
773 &[0xc1, 0x08, 0x04, 0x00],
774 &[],
775 &DecodeError::Decode(crate::decode::Error::SharingNotMaximal),
776 );
777 }
778
779 #[test]
780 fn witness_consumed() {
781 let prog = BitIter::from(&[0x24][..]);
783 let wit = BitIter::from(&[0x00][..]);
784 match RedeemNode::<Core>::decode(prog, wit) {
785 Err(DecodeError::Decode(crate::decode::Error::BitIter(
786 crate::BitIterCloseError::TrailingBytes { first_byte: 0 },
787 ))) => {} Err(e) => panic!("got incorrect error {e}"),
789 Ok(_) => panic!("accepted program with bad witness length"),
790 }
791 }
792
793 #[test]
794 fn shared_grandchild() {
795 assert_program_deserializable::<Core>(
804 &[0xc1, 0x00, 0x00, 0x01, 0x00],
805 &[],
806 "8a54101335ca2cf7e933d74cdb15f99becc4e540799ba5e2d19c00c9d7219e71",
807 "74e868bd640c250bc45522085158a9723fc7e277bb16a8d582c4012ebbb1f6f1",
808 "39b8f72bd1539de87d26673890603d6548cfc8b68571d996bdf9b1d8b557bd35",
809 "wQAAAQA=",
810 );
811 }
812
813 #[test]
814 #[rustfmt::skip]
815 fn assert_lr() {
816 assert_program_deserializable::<Core>(
820 &[
821 0xcd, 0x24, 0x08, 0x4b, 0x6f, 0x56, 0xdf, 0x77,
822 0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
823 0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
824 0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
825 0xef, 0x56, 0xdf, 0x77, 0x86, 0x01, 0x80,
826 ],
827 &[],
828 "abdd773fc7a503908739b4a63198416fdd470948830cb5a6516b98fe0a3bfa85",
829 "1362ee53ae75218ed51dc4bd46cdbfa585f934ac6c6c3ff787e27dce91ccd80b",
830 "251c6778129e0f12da3f2388ab30184e815e9d9456b5931e54802a6715d9ca42",
831 "zSQIS29W33fvVt9371bfd+9W33fvVt9371bfd+9W33fvVt93hgGA",
832 );
833
834
835 assert_program_deserializable::<Core>(
839 &[
840 0xcd, 0x25, 0x08, 0x6d, 0xea, 0xdb, 0xee, 0xfd,
841 0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
842 0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
843 0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
844 0xea, 0xdb, 0xee, 0xf4, 0x86, 0x01, 0x80,
845 ],
846 &[],
847 "f6c678dfb180b94567a9d524e05fbc893f6905e0e3db931ff01dc2701e783d4c",
848 "212d4fa3dbe2b33db1e11bb6f4cc973be5de0896a3775387a06056483b8feb0f",
849 "7a583edcc733b6bba66998110be403ac61fab2d93fc09ba3c84ab2509b538043",
850 "zSUIberb7v3q2+796tvu/erb7v3q2+796tvu/erb7v3q2+70hgGA",
851 );
852 }
853
854 #[test]
855 #[rustfmt::skip]
856 fn disconnect() {
857 assert_program_deserializable::<Core>(
863 &[0xc5, 0x02, 0x06, 0x24, 0x10],
864 &[],
865 "afe8f5f8bd3f64bfa51d2f29ffa22523604d9654c0d9862dbf2dc67ba097cbb2",
866 "15239708cb7b448cedc6a0b6401dce86ed74084056dd95831928860dd0c3ca67",
867 "9cdacb48b16e108ccbd6bcbce459a64056df285c2dc6e02dca6d13c4b1530fb0",
868 "xQIGJBA=",
869 );
870 }
871
872 #[test]
873 #[rustfmt::skip]
874 #[cfg(feature = "elements")]
875 fn disconnect2() {
876 assert_program_deserializable::<crate::jet::Elements>(
896 &[
897 0xd3, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce,
898 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, 0xd6, 0x79, 0x5f,
899 0x9c, 0x63, 0x47, 0x07, 0x02, 0xc0, 0xe2, 0x8d, 0x88, 0x10,
900 ],
901 &[
902 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce, 0x56, 0x3f,
903 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, 0xd6, 0x79, 0x5f, 0x9c, 0x63,
904 0xdb, 0x86, 0x8d, 0x45, 0xa0, 0xbc, 0x1d, 0x19, 0x01, 0x30, 0x2b, 0xc8, 0x7a, 0x87, 0x1c, 0xf1,
905 0x58, 0xe2, 0xbd, 0xe2, 0xcf, 0xa6, 0x45, 0xa8, 0x95, 0xc1, 0xb4, 0x5d, 0x68, 0xea, 0x24, 0xc0,
906 ],
907 "f3cd4537d7ebb201732203195b30b549b8dc0c2c6257b3a0d53bedb08ea02874",
908 "107fa80454ed0f2d95d7c18d307912b1497505b98de47198fee23b5018efa544",
909 "d52021c638ba742a90bead9b3055efd66091fb50bb131aa8b10eb7c13ef464d1",
910 "02kAAAAAAAAAAAAAADt4zlY/iaDtlBT1qiitDZbWeV+cY0cHAsDijYgQ",
911 );
912 }
913
914 #[test]
915 #[rustfmt::skip]
916 #[cfg(feature = "elements")]
917 fn disconnect3() {
918 assert_program_deserializable::<crate::jet::Elements>(
928 &[0xc9, 0x09, 0x20, 0x74, 0x90, 0x40],
929 &[],
930 "b689bdee289c8dd4e2e283358d187813363d441776cf826dafc27cc8a81ec441",
931 "3c68660a1afde7982ce4aa9d499ad382bc32f5f9ad894a5e915f76e66303a25b",
932 "85313720ee43ae0ee03f88b05e6d9e4494308c6897bdeb3e93b94559c3317484",
933 "yQkgdJBA",
934 );
935 }
936
937 #[test]
938 #[cfg(feature = "elements")]
939 fn decode_schnorr() {
940 #[rustfmt::skip]
941 let schnorr0 = vec![
942 0xc6, 0xd5, 0xf2, 0x61, 0x14, 0x03, 0x24, 0xb1, 0x86, 0x20, 0x92, 0x68, 0x9f, 0x0b, 0xf1, 0x3a,
943 0xa4, 0x53, 0x6a, 0x63, 0x90, 0x8b, 0x06, 0xdf, 0x33, 0x61, 0x0c, 0x03, 0xe2, 0x27, 0x79, 0xc0,
944 0x6d, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
945 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
946 0x00, 0x00, 0xe2, 0x8d, 0x8c, 0x04, 0x00,
947 ];
948 #[rustfmt::skip]
949 let schnorr0_wit = vec![
950 0xe9, 0x07, 0x83, 0x1f, 0x80, 0x84, 0x8d, 0x10, 0x69, 0xa5, 0x37, 0x1b, 0x40, 0x24, 0x10, 0x36,
951 0x4b, 0xdf, 0x1c, 0x5f, 0x83, 0x07, 0xb0, 0x08, 0x4c, 0x55, 0xf1, 0xce, 0x2d, 0xca, 0x82, 0x15,
952 0x25, 0xf6, 0x6a, 0x4a, 0x85, 0xea, 0x8b, 0x71, 0xe4, 0x82, 0xa7, 0x4f, 0x38, 0x2d, 0x2c, 0xe5,
953 0xeb, 0xee, 0xe8, 0xfd, 0xb2, 0x17, 0x2f, 0x47, 0x7d, 0xf4, 0x90, 0x0d, 0x31, 0x05, 0x36, 0xc0,
954 ];
955 assert_program_deserializable::<crate::jet::Elements>(
956 &schnorr0,
957 &schnorr0_wit,
958 "8a9e97676b24be7797d9ee0bf32dd76bcd78028e973025f785eae8dc91c8a0da",
959 "ec97c8774cb6bfb381fdbbcc8d964380fb3a3b45779322624490d6231ae777a4",
960 "ad7c38b16b9129646dc89b52cff144de94a80e383c4983b53de65e3575abcf38",
961 "xtXyYRQDJLGGIJJonwvxOqRTamOQiwbfM2EMA+InecBt8gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4o2MBAA=",
962 );
963 }
964
965 #[cfg(feature = "elements")]
966 fn assert_correct_pruning<J: Jet>(
967 unpruned_prog: &str,
968 unpruned_wit: &HashMap<Arc<str>, Value>,
969 expected_pruned_prog: &str,
970 expected_pruned_wit: &HashMap<Arc<str>, Value>,
971 env: &J::Environment,
972 ) {
973 let unpruned_program = types::Context::with_context(|ctx| {
974 Forest::<J>::parse(unpruned_prog)
975 .expect("unpruned program should parse")
976 .to_witness_node(&ctx, unpruned_wit)
977 .expect("unpruned program should have main")
978 .finalize_unpruned()
979 .expect("unpruned program should finalize")
980 });
981 let expected_unpruned_program = types::Context::with_context(|ctx| {
982 Forest::<J>::parse(expected_pruned_prog)
983 .expect("expected pruned program should parse")
984 .to_witness_node(&ctx, expected_pruned_wit)
985 .expect("expected pruned program should have main")
986 .finalize_unpruned()
987 .expect("expected pruned program should finalize")
988 });
989
990 let mut mac = BitMachine::for_program(&unpruned_program)
991 .expect("unpruned program has reasonable bounds");
992 let unpruned_output = mac
993 .exec(&unpruned_program, env)
994 .expect("unpruned program should run without failure");
995
996 let pruned_program = unpruned_program
997 .prune(env)
998 .expect("pruning should not fail if execution succeeded");
999 assert_eq!(
1000 pruned_program.ihr(),
1001 expected_unpruned_program.ihr(),
1002 "pruning result differs from expected result"
1003 );
1004
1005 let mut mac =
1006 BitMachine::for_program(&pruned_program).expect("pruned program has reasonable bounds");
1007 let pruned_output = mac
1008 .exec(&pruned_program, env)
1009 .expect("pruned program should run without failure");
1010 assert_eq!(
1011 unpruned_output, pruned_output,
1012 "pruned program should return same output as unpruned program"
1013 );
1014 }
1015
1016 #[test]
1017 #[cfg(feature = "elements")]
1018 fn prune() {
1019 let env = crate::jet::elements::ElementsEnv::dummy();
1020
1021 let unpruned_prog = r#"wit1 := witness : 1 -> 2
1025wit2 := witness : 1 -> 2^64 * 2^64
1026input := pair wit1 wit2 : 1 -> 2 * (2^64 * 2^64)
1027process := case (drop take jet_is_zero_64) (drop drop jet_is_zero_64) : 2 * (2^64 * 2^64) -> 2
1028main := comp input comp process jet_verify : 1 -> 1"#;
1029
1030 let unpruned_wit = HashMap::from([
1032 (Arc::from("wit1"), Value::u1(0)),
1033 (
1034 Arc::from("wit2"),
1035 Value::product(Value::u64(0), Value::u64(0)),
1036 ),
1037 ]);
1038 let pruned_prog = r#"wit1 := witness : 1 -> 2
1039wit2 := witness : 1 -> 2^64 * 1 -- right component was pruned
1040input := pair wit1 wit2 : 1 -> 2 * (2^64 * 1)
1041process := assertl (drop take jet_is_zero_64) #{drop drop jet_is_zero_64} : 2 * (2^64 * 1) -> 2 -- case became assertl
1042main := comp input comp process jet_verify : 1 -> 1"#;
1043 let pruned_wit = HashMap::from([
1044 (Arc::from("wit1"), Value::u1(0)),
1045 (
1046 Arc::from("wit2"),
1047 Value::product(Value::u64(0), Value::unit()),
1048 ),
1049 ]);
1050 assert_correct_pruning::<crate::jet::Elements>(
1051 unpruned_prog,
1052 &unpruned_wit,
1053 pruned_prog,
1054 &pruned_wit,
1055 &env,
1056 );
1057
1058 let unpruned_wit = HashMap::from([
1060 (Arc::from("wit1"), Value::u1(1)),
1061 (
1062 Arc::from("wit2"),
1063 Value::product(Value::u64(0), Value::u64(0)),
1064 ),
1065 ]);
1066 let pruned_prog = r#"wit1 := witness : 1 -> 2
1067wit2 := witness : 1 -> 1 * 2^64 -- left component was pruned
1068input := pair wit1 wit2 : 1 -> 2 * (1 * 2^64)
1069process := assertr #{drop take jet_is_zero_64} (drop drop jet_is_zero_64) : 2 * (1 * 2^64) -> 2 -- case became assertr
1070main := comp input comp process jet_verify : 1 -> 1"#;
1071 let pruned_wit = HashMap::from([
1072 (Arc::from("wit1"), Value::u1(1)),
1073 (
1074 Arc::from("wit2"),
1075 Value::product(Value::unit(), Value::u64(0)),
1076 ),
1077 ]);
1078 assert_correct_pruning::<crate::jet::Elements>(
1079 unpruned_prog,
1080 &unpruned_wit,
1081 pruned_prog,
1082 &pruned_wit,
1083 &env,
1084 );
1085
1086 let prune_sum = r#"wit1 := witness : 1 -> 2^64 + 2^64
1090input := pair wit1 unit : 1 -> (2^64 + 2^64) * 1
1091process := case (take jet_is_zero_64) (take jet_is_zero_64) : (2^64 + 2^64) * 1 -> 2
1092main := comp input comp process jet_verify : 1 -> 1"#;
1093
1094 let unpruned_wit =
1096 HashMap::from([(Arc::from("wit1"), Value::left(Value::u64(0), Final::u64()))]);
1097 let pruned_prog = r#"wit1 := witness : 1 -> 2^64 + 1 -- right sub type became unit
1098input := pair wit1 unit : 1 -> (2^64 + 1) * 1
1099process := assertl (take jet_is_zero_64) #{take jet_is_zero_64} : (2^64 + 1) * 1 -> 2 -- case became assertl
1100main := comp input comp process jet_verify : 1 -> 1"#;
1101 let pruned_wit =
1102 HashMap::from([(Arc::from("wit1"), Value::left(Value::u64(0), Final::unit()))]);
1103 assert_correct_pruning::<crate::jet::Elements>(
1104 prune_sum,
1105 &unpruned_wit,
1106 pruned_prog,
1107 &pruned_wit,
1108 &env,
1109 );
1110
1111 let unpruned_wit = HashMap::from([(
1113 Arc::from("wit1"),
1114 Value::right(Final::unit(), Value::u64(0)),
1115 )]);
1116 let pruned_prog = r#"wit1 := witness : 1 -> 1 + 2^64 -- left sub type became unit
1117input := pair wit1 unit : 1 -> (1 + 2^64) * 1
1118process := assertr #{take jet_is_zero_64} (take jet_is_zero_64) : (1 + 2^64) * 1 -> 2 -- case became assertr
1119main := comp input comp process jet_verify : 1 -> 1"#;
1120 let pruned_wit = HashMap::from([(
1121 Arc::from("wit1"),
1122 Value::right(Final::unit(), Value::u64(0)),
1123 )]);
1124 assert_correct_pruning::<crate::jet::Elements>(
1125 prune_sum,
1126 &unpruned_wit,
1127 pruned_prog,
1128 &pruned_wit,
1129 &env,
1130 );
1131 }
1132}
1133
1134#[cfg(bench)]
1135#[cfg(feature = "elements")]
1136mod benches {
1137 use super::*;
1138
1139 use crate::bit_encoding::BitIter;
1140 use crate::jet::Elements;
1141
1142 use test::{black_box, Bencher};
1143
1144 #[bench]
1145 fn decode_fixed_program(bh: &mut Bencher) {
1146 let prog = &[
1147 0xd3, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b,
1148 0x78, 0xce, 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d,
1149 0x96, 0xd6, 0x79, 0x5f, 0x9c, 0x63, 0x47, 0x07, 0x02, 0xc0, 0xe2, 0x8d, 0x88, 0x10,
1150 ][..];
1151 let witness = &[
1152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce,
1153 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, 0xd6,
1154 0x79, 0x5f, 0x9c, 0x63, 0xdb, 0x86, 0x8d, 0x45, 0xa0, 0xbc, 0x1d, 0x19, 0x01, 0x30,
1155 0x2b, 0xc8, 0x7a, 0x87, 0x1c, 0xf1, 0x58, 0xe2, 0xbd, 0xe2, 0xcf, 0xa6, 0x45, 0xa8,
1156 0x95, 0xc1, 0xb4, 0x5d, 0x68, 0xea, 0x24, 0xc0,
1157 ][..];
1158 bh.iter(|| {
1159 let prog = BitIter::from(prog);
1160 let witness = BitIter::from(witness);
1161 black_box(RedeemNode::<Elements>::decode(
1162 black_box(prog),
1163 black_box(witness),
1164 ))
1165 .unwrap();
1166 });
1167 }
1168}