1use 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, 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 struct Pruner<'brand, J> {
294 inference_context: types::Context<'brand>,
295 tracker: SetTracker,
296 phantom: PhantomData<J>,
297 }
298
299 impl<'brand, J: Jet> Converter<Redeem<J>, Construct<'brand, J>> for Pruner<'brand, J> {
300 type Error = std::convert::Infallible;
301
302 fn convert_witness(
303 &mut self,
304 _: &PostOrderIterItem<&RedeemNode<J>>,
305 witness: &Value,
306 ) -> Result<Option<Value>, Self::Error> {
307 Ok(Some(witness.shallow_clone()))
310 }
311
312 fn convert_disconnect(
313 &mut self,
314 _: &PostOrderIterItem<&RedeemNode<J>>,
315 right: Option<&Arc<ConstructNode<'brand, J>>>,
316 _: &Arc<RedeemNode<J>>,
317 ) -> Result<Option<Arc<ConstructNode<'brand, J>>>, Self::Error> {
318 debug_assert!(
319 right.is_some(),
320 "disconnected branch should exist in unpruned redeem program"
321 );
322 Ok(right.map(Arc::clone))
323 }
324
325 fn prune_case(
326 &mut self,
327 data: &PostOrderIterItem<&RedeemNode<J>>,
328 _left: &Arc<ConstructNode<J>>,
329 _right: &Arc<ConstructNode<J>>,
330 ) -> Result<Hide, Self::Error> {
331 match (
335 self.tracker.left().contains(&data.node.ihr()),
336 self.tracker.right().contains(&data.node.ihr()),
337 ) {
338 (true, true) => Ok(Hide::Neither),
339 (false, true) => Ok(Hide::Left),
340 (true, false) => Ok(Hide::Right),
341 (false, false) => Ok(Hide::Neither), }
343 }
344
345 fn convert_data(
346 &mut self,
347 _: &PostOrderIterItem<&RedeemNode<J>>,
348 inner: Inner<
349 &Arc<ConstructNode<'brand, J>>,
350 J,
351 &Option<Arc<ConstructNode<'brand, J>>>,
352 &Option<Value>,
353 >,
354 ) -> Result<ConstructData<'brand, J>, Self::Error> {
355 let converted_inner = inner
356 .map(|node| node.cached_data())
357 .map_witness(Option::<Value>::clone);
358 let retyped = ConstructData::from_inner(&self.inference_context, converted_inner)
359 .expect("pruned types should check out if unpruned types check out");
360 Ok(retyped)
361 }
362 }
363
364 struct Finalizer<J>(PhantomData<J>);
365
366 impl<'brand, J: Jet> Converter<Construct<'brand, J>, Redeem<J>> for Finalizer<J> {
367 type Error = std::convert::Infallible;
368
369 fn convert_witness(
370 &mut self,
371 data: &PostOrderIterItem<&ConstructNode<J>>,
372 witness: &Option<Value>,
373 ) -> Result<Value, Self::Error> {
374 let pruned_target_ty = data
375 .node
376 .arrow()
377 .target
378 .finalize()
379 .expect("pruned types should check out if unpruned types check out");
380 let pruned_witness = witness
381 .as_ref()
382 .expect("witness node that originally stems from redeem program should be populated")
383 .prune(&pruned_target_ty)
384 .expect("pruned type should be shrunken version of unpruned type");
385 Ok(pruned_witness)
386 }
387
388 fn convert_disconnect(
389 &mut self,
390 _: &PostOrderIterItem<&ConstructNode<J>>,
391 right: Option<&Arc<RedeemNode<J>>>,
392 _: &Option<Arc<ConstructNode<J>>>,
393 ) -> Result<Arc<RedeemNode<J>>, Self::Error> {
394 Ok(right
395 .map(Arc::clone)
396 .expect("disconnect node that originally stems from redeem program should have all branches"))
397 }
398
399 fn convert_data(
400 &mut self,
401 data: &PostOrderIterItem<&ConstructNode<J>>,
402 inner: Inner<&Arc<RedeemNode<J>>, J, &Arc<RedeemNode<J>>, &Value>,
403 ) -> Result<Arc<RedeemData<J>>, Self::Error> {
404 let final_arrow = data
406 .node
407 .arrow()
408 .finalize()
409 .expect("pruned types should check out if unpruned types check out");
410 let converted_inner = inner
411 .map(|node| node.cached_data())
412 .map_disconnect(|node| node.cached_data())
413 .map_witness(Value::shallow_clone);
414 Ok(Arc::new(RedeemData::new(final_arrow, converted_inner)))
415 }
416 }
417
418 let mut mac = BitMachine::for_program(self)?;
421 let tracker = mac.exec_prune(self, env)?;
422
423 types::Context::with_context(|inference_context| {
427 let pruned_witness_program = self
428 .convert::<InternalSharing, _, _>(&mut Pruner {
429 inference_context,
430 tracker,
431 phantom: PhantomData,
432 })
433 .expect("pruning unused branches is infallible");
434
435 Ok(pruned_witness_program
439 .convert::<InternalSharing, _, _>(&mut Finalizer(PhantomData))
440 .expect("finalization is infallible"))
441 })
442 }
443
444 pub fn decode<I1, I2>(
446 program: BitIter<I1>,
447 mut witness: BitIter<I2>,
448 ) -> Result<Arc<Self>, DecodeError>
449 where
450 I1: Iterator<Item = u8>,
451 I2: Iterator<Item = u8>,
452 {
453 struct DecodeFinalizer<'bits, J: Jet, I: Iterator<Item = u8>> {
455 bits: &'bits mut BitIter<I>,
456 phantom: PhantomData<J>,
457 }
458
459 impl<'brand, J: Jet, I: Iterator<Item = u8>> Converter<Construct<'brand, J>, Redeem<J>>
460 for DecodeFinalizer<'_, J, I>
461 {
462 type Error = DecodeError;
463 fn convert_witness(
464 &mut self,
465 data: &PostOrderIterItem<&ConstructNode<J>>,
466 _: &Option<Value>,
467 ) -> Result<Value, Self::Error> {
468 let arrow = data.node.data.arrow();
469 let target_ty = arrow.target.finalize().map_err(DecodeError::Type)?;
470 Value::from_compact_bits(self.bits, &target_ty)
471 .map_err(crate::decode::Error::from)
472 .map_err(DecodeError::Decode)
473 }
474
475 fn convert_disconnect(
476 &mut self,
477 _: &PostOrderIterItem<&ConstructNode<J>>,
478 right: Option<&Arc<RedeemNode<J>>>,
479 _: &Option<Arc<ConstructNode<J>>>,
480 ) -> Result<Arc<RedeemNode<J>>, Self::Error> {
481 if let Some(child) = right {
482 Ok(Arc::clone(child))
483 } else {
484 Err(DecodeError::DisconnectRedeemTime)
485 }
486 }
487
488 fn convert_data(
489 &mut self,
490 data: &PostOrderIterItem<&ConstructNode<J>>,
491 inner: Inner<&Arc<RedeemNode<J>>, J, &Arc<RedeemNode<J>>, &Value>,
492 ) -> Result<Arc<RedeemData<J>>, Self::Error> {
493 let arrow = data
494 .node
495 .data
496 .arrow()
497 .finalize()
498 .map_err(DecodeError::Type)?;
499 let converted_data = inner
500 .map(|node| node.cached_data())
501 .map_disconnect(|node| node.cached_data())
502 .map_witness(Value::shallow_clone);
503 Ok(Arc::new(RedeemData::new(arrow, converted_data)))
504 }
505 }
506
507 let program: Arc<Self> = types::Context::with_context(|ctx| {
509 let construct =
510 crate::ConstructNode::decode(&ctx, program).map_err(DecodeError::Decode)?;
511 construct
512 .set_arrow_to_program()
513 .map_err(DecodeError::Type)?;
514
515 construct.convert::<InternalSharing, _, _>(&mut DecodeFinalizer {
518 bits: &mut witness,
519 phantom: PhantomData,
520 })
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(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(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<W1, W2>(
564 &self,
565 prog: &mut BitWriter<W1>,
566 witness: &mut BitWriter<W2>,
567 ) -> io::Result<usize>
568 where
569 W1: io::Write,
570 W2: io::Write,
571 {
572 let sharing_iter = self.post_order_iter::<MaxSharing<Redeem<J>>>();
573 let program_bits = encode::encode_program(self, prog)?;
574 prog.flush_all()?;
575 let witness_bits = encode::encode_witness(sharing_iter.into_witnesses(), witness)?;
576 witness.flush_all()?;
577 Ok(program_bits + witness_bits)
578 }
579
580 #[deprecated(since = "0.5.0", note = "use Self::to_vec_with_witness instead")]
582 pub fn encode_to_vec(&self) -> (Vec<u8>, Vec<u8>) {
583 let mut ret_1 = vec![];
584 let mut ret_2 = vec![];
585 self.encode_with_witness(&mut ret_1, &mut ret_2).unwrap();
586 (ret_1, ret_2)
587 }
588}
589
590#[cfg(test)]
591mod tests {
592 use super::*;
593 use crate::human_encoding::Forest;
594 use crate::jet::Core;
595 use crate::node::SimpleFinalizer;
596 use crate::types::Final;
597 use hex::DisplayHex;
598 use std::collections::HashMap;
599 use std::fmt;
600
601 #[cfg_attr(not(feature = "base64"), allow(unused_variables))]
602 #[track_caller]
603 fn assert_program_deserializable<J: Jet>(
604 prog_bytes: &[u8],
605 witness_bytes: &[u8],
606 cmr_str: &str,
607 amr_str: &str,
608 ihr_str: &str,
609 b64_str: &str,
610 ) -> Arc<RedeemNode<J>> {
611 let prog_hex = prog_bytes.as_hex();
612 let witness_hex = witness_bytes.as_hex();
613
614 let prog = BitIter::from(prog_bytes);
615 let witness = BitIter::from(witness_bytes);
616 let prog = match RedeemNode::<J>::decode(prog, witness) {
617 Ok(prog) => prog,
618 Err(e) => panic!("program {} failed: {}", prog_hex, e),
619 };
620
621 assert_eq!(
622 prog.cmr().to_string(),
623 cmr_str,
624 "CMR mismatch (got {} expected {}) for program {}",
625 prog.cmr(),
626 cmr_str,
627 prog_hex,
628 );
629
630 assert_eq!(
631 prog.amr().to_string(),
632 amr_str,
633 "AMR mismatch (got {} expected {}) for program {}",
634 prog.amr(),
635 amr_str,
636 prog_hex,
637 );
638 assert_eq!(
639 prog.ihr().to_string(),
640 ihr_str,
641 "IHR mismatch (got {} expected {}) for program {}",
642 prog.ihr(),
643 ihr_str,
644 prog_hex,
645 );
646
647 let (reser_prog, reser_witness) = prog.to_vec_with_witness();
648 assert_eq!(
649 prog_bytes,
650 &reser_prog[..],
651 "program {} reserialized as {}",
652 prog_hex,
653 reser_prog.as_hex(),
654 );
655 assert_eq!(
656 witness_bytes,
657 &reser_witness[..],
658 "witness {} reserialized as {}",
659 witness_hex,
660 reser_witness.as_hex(),
661 );
662
663 #[cfg(feature = "base64")]
664 {
665 let disp = prog.display();
666 assert_eq!(prog.to_string(), b64_str);
667 assert_eq!(disp.program().to_string(), b64_str);
668 assert_eq!(
669 disp.witness().to_string(),
670 witness_bytes.as_hex().to_string()
671 );
672 }
673
674 prog
675 }
676
677 #[track_caller]
678 fn assert_program_not_deserializable<J: Jet>(
679 prog_bytes: &[u8],
680 witness_bytes: &[u8],
681 err: &dyn fmt::Display,
682 ) {
683 let prog_hex = prog_bytes.as_hex();
684 let witness_hex = witness_bytes.as_hex();
685 let err_str = err.to_string();
686
687 let prog = BitIter::from(prog_bytes);
688 let witness = BitIter::from(witness_bytes);
689 match RedeemNode::<J>::decode(prog, witness) {
690 Ok(prog) => panic!(
691 "Program {} wit {} succeded (expected error {}). Program parsed as:\n{:?}",
692 prog_hex, witness_hex, err, prog
693 ),
694 Err(e) if e.to_string() == err_str => {} Err(e) => panic!(
696 "Program {} wit {} failed with error {} (expected error {})",
697 prog_hex, witness_hex, e, err
698 ),
699 };
700 }
701
702 #[test]
703 fn encode_shared_witnesses() {
704 let eqwits = [0xcd, 0xdc, 0x51, 0xb6, 0xe2, 0x08, 0xc0, 0x40];
711 let iter = BitIter::from(&eqwits[..]);
712 let eqwits_prog = CommitNode::<Core>::decode(iter).unwrap();
713
714 let eqwits_final = eqwits_prog
715 .finalize(&mut SimpleFinalizer::new(std::iter::repeat(Value::u32(
716 0xDEADBEEF,
717 ))))
718 .unwrap();
719 let output = eqwits_final.to_vec_with_witness();
720
721 assert_eq!(
722 output,
723 (
724 [0xc9, 0xc4, 0x6d, 0xb8, 0x82, 0x30, 0x10].into(),
725 [0xde, 0xad, 0xbe, 0xef].into(),
726 ),
727 "output {} {}",
728 output.0.as_hex(),
729 output.1.as_hex()
730 );
731 }
732
733 #[test]
734 fn decode_shared_witnesses() {
735 assert_program_deserializable::<Core>(
739 &[0xc9, 0xc4, 0x6d, 0xb8, 0x82, 0x30, 0x10],
740 &[0xde, 0xad, 0xbe, 0xef],
741 "d7969920eff9a1ed0359aaa8545b239c69969e22c304c645a7b49bcc976a40a8",
742 "f7acbb077e7661a08384818bc8e3a275ed42ad446252575a35a35f71689fef78",
743 "3ce4a6390b4e4bda6330acda4800e66e5d2cae0f5a2888564c706f2b910146b8",
744 "ycRtuIIwEA==",
745 );
746 }
747
748 #[test]
749 fn unshared_child() {
750 assert_program_not_deserializable::<Core>(
756 &[0xc1, 0x08, 0x04, 0x00],
757 &[],
758 &DecodeError::Decode(crate::decode::Error::SharingNotMaximal),
759 );
760 }
761
762 #[test]
763 fn witness_consumed() {
764 let prog = BitIter::from(&[0x24][..]);
766 let wit = BitIter::from(&[0x00][..]);
767 match RedeemNode::<Core>::decode(prog, wit) {
768 Err(DecodeError::Decode(crate::decode::Error::BitIter(
769 crate::BitIterCloseError::TrailingBytes { first_byte: 0 },
770 ))) => {} Err(e) => panic!("got incorrect error {e}"),
772 Ok(_) => panic!("accepted program with bad witness length"),
773 }
774 }
775
776 #[test]
777 fn shared_grandchild() {
778 assert_program_deserializable::<Core>(
787 &[0xc1, 0x00, 0x00, 0x01, 0x00],
788 &[],
789 "8a54101335ca2cf7e933d74cdb15f99becc4e540799ba5e2d19c00c9d7219e71",
790 "74e868bd640c250bc45522085158a9723fc7e277bb16a8d582c4012ebbb1f6f1",
791 "39b8f72bd1539de87d26673890603d6548cfc8b68571d996bdf9b1d8b557bd35",
792 "wQAAAQA=",
793 );
794 }
795
796 #[test]
797 #[rustfmt::skip]
798 fn assert_lr() {
799 assert_program_deserializable::<Core>(
803 &[
804 0xcd, 0x24, 0x08, 0x4b, 0x6f, 0x56, 0xdf, 0x77,
805 0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
806 0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
807 0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
808 0xef, 0x56, 0xdf, 0x77, 0x86, 0x01, 0x80,
809 ],
810 &[],
811 "abdd773fc7a503908739b4a63198416fdd470948830cb5a6516b98fe0a3bfa85",
812 "1362ee53ae75218ed51dc4bd46cdbfa585f934ac6c6c3ff787e27dce91ccd80b",
813 "251c6778129e0f12da3f2388ab30184e815e9d9456b5931e54802a6715d9ca42",
814 "zSQIS29W33fvVt9371bfd+9W33fvVt9371bfd+9W33fvVt93hgGA",
815 );
816
817
818 assert_program_deserializable::<Core>(
822 &[
823 0xcd, 0x25, 0x08, 0x6d, 0xea, 0xdb, 0xee, 0xfd,
824 0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
825 0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
826 0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
827 0xea, 0xdb, 0xee, 0xf4, 0x86, 0x01, 0x80,
828 ],
829 &[],
830 "f6c678dfb180b94567a9d524e05fbc893f6905e0e3db931ff01dc2701e783d4c",
831 "212d4fa3dbe2b33db1e11bb6f4cc973be5de0896a3775387a06056483b8feb0f",
832 "7a583edcc733b6bba66998110be403ac61fab2d93fc09ba3c84ab2509b538043",
833 "zSUIberb7v3q2+796tvu/erb7v3q2+796tvu/erb7v3q2+70hgGA",
834 );
835 }
836
837 #[test]
838 #[rustfmt::skip]
839 fn disconnect() {
840 assert_program_deserializable::<Core>(
846 &[0xc5, 0x02, 0x06, 0x24, 0x10],
847 &[],
848 "afe8f5f8bd3f64bfa51d2f29ffa22523604d9654c0d9862dbf2dc67ba097cbb2",
849 "15239708cb7b448cedc6a0b6401dce86ed74084056dd95831928860dd0c3ca67",
850 "9cdacb48b16e108ccbd6bcbce459a64056df285c2dc6e02dca6d13c4b1530fb0",
851 "xQIGJBA=",
852 );
853 }
854
855 #[test]
856 #[rustfmt::skip]
857 #[cfg(feature = "elements")]
858 fn disconnect2() {
859 assert_program_deserializable::<crate::jet::Elements>(
879 &[
880 0xd3, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce,
881 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, 0xd6, 0x79, 0x5f,
882 0x9c, 0x63, 0x47, 0x07, 0x02, 0xc0, 0xe2, 0x8d, 0x88, 0x10,
883 ],
884 &[
885 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce, 0x56, 0x3f,
886 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, 0xd6, 0x79, 0x5f, 0x9c, 0x63,
887 0xdb, 0x86, 0x8d, 0x45, 0xa0, 0xbc, 0x1d, 0x19, 0x01, 0x30, 0x2b, 0xc8, 0x7a, 0x87, 0x1c, 0xf1,
888 0x58, 0xe2, 0xbd, 0xe2, 0xcf, 0xa6, 0x45, 0xa8, 0x95, 0xc1, 0xb4, 0x5d, 0x68, 0xea, 0x24, 0xc0,
889 ],
890 "f3cd4537d7ebb201732203195b30b549b8dc0c2c6257b3a0d53bedb08ea02874",
891 "107fa80454ed0f2d95d7c18d307912b1497505b98de47198fee23b5018efa544",
892 "d52021c638ba742a90bead9b3055efd66091fb50bb131aa8b10eb7c13ef464d1",
893 "02kAAAAAAAAAAAAAADt4zlY/iaDtlBT1qiitDZbWeV+cY0cHAsDijYgQ",
894 );
895 }
896
897 #[test]
898 #[rustfmt::skip]
899 #[cfg(feature = "elements")]
900 fn disconnect3() {
901 assert_program_deserializable::<crate::jet::Elements>(
911 &[0xc9, 0x09, 0x20, 0x74, 0x90, 0x40],
912 &[],
913 "b689bdee289c8dd4e2e283358d187813363d441776cf826dafc27cc8a81ec441",
914 "3c68660a1afde7982ce4aa9d499ad382bc32f5f9ad894a5e915f76e66303a25b",
915 "85313720ee43ae0ee03f88b05e6d9e4494308c6897bdeb3e93b94559c3317484",
916 "yQkgdJBA",
917 );
918 }
919
920 #[test]
921 #[cfg(feature = "elements")]
922 fn decode_schnorr() {
923 #[rustfmt::skip]
924 let schnorr0 = vec![
925 0xc6, 0xd5, 0xf2, 0x61, 0x14, 0x03, 0x24, 0xb1, 0x86, 0x20, 0x92, 0x68, 0x9f, 0x0b, 0xf1, 0x3a,
926 0xa4, 0x53, 0x6a, 0x63, 0x90, 0x8b, 0x06, 0xdf, 0x33, 0x61, 0x0c, 0x03, 0xe2, 0x27, 0x79, 0xc0,
927 0x6d, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
928 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
929 0x00, 0x00, 0xe2, 0x8d, 0x8c, 0x04, 0x00,
930 ];
931 #[rustfmt::skip]
932 let schnorr0_wit = vec![
933 0xe9, 0x07, 0x83, 0x1f, 0x80, 0x84, 0x8d, 0x10, 0x69, 0xa5, 0x37, 0x1b, 0x40, 0x24, 0x10, 0x36,
934 0x4b, 0xdf, 0x1c, 0x5f, 0x83, 0x07, 0xb0, 0x08, 0x4c, 0x55, 0xf1, 0xce, 0x2d, 0xca, 0x82, 0x15,
935 0x25, 0xf6, 0x6a, 0x4a, 0x85, 0xea, 0x8b, 0x71, 0xe4, 0x82, 0xa7, 0x4f, 0x38, 0x2d, 0x2c, 0xe5,
936 0xeb, 0xee, 0xe8, 0xfd, 0xb2, 0x17, 0x2f, 0x47, 0x7d, 0xf4, 0x90, 0x0d, 0x31, 0x05, 0x36, 0xc0,
937 ];
938 assert_program_deserializable::<crate::jet::Elements>(
939 &schnorr0,
940 &schnorr0_wit,
941 "8a9e97676b24be7797d9ee0bf32dd76bcd78028e973025f785eae8dc91c8a0da",
942 "ec97c8774cb6bfb381fdbbcc8d964380fb3a3b45779322624490d6231ae777a4",
943 "ad7c38b16b9129646dc89b52cff144de94a80e383c4983b53de65e3575abcf38",
944 "xtXyYRQDJLGGIJJonwvxOqRTamOQiwbfM2EMA+InecBt8gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4o2MBAA=",
945 );
946 }
947
948 #[cfg(feature = "elements")]
949 fn assert_correct_pruning<J: Jet>(
950 unpruned_prog: &str,
951 unpruned_wit: &HashMap<Arc<str>, Value>,
952 expected_pruned_prog: &str,
953 expected_pruned_wit: &HashMap<Arc<str>, Value>,
954 env: &J::Environment,
955 ) {
956 let unpruned_program = types::Context::with_context(|ctx| {
957 Forest::<J>::parse(unpruned_prog)
958 .expect("unpruned program should parse")
959 .to_witness_node(&ctx, unpruned_wit)
960 .expect("unpruned program should have main")
961 .finalize_unpruned()
962 .expect("unpruned program should finalize")
963 });
964 let expected_unpruned_program = types::Context::with_context(|ctx| {
965 Forest::<J>::parse(expected_pruned_prog)
966 .expect("expected pruned program should parse")
967 .to_witness_node(&ctx, expected_pruned_wit)
968 .expect("expected pruned program should have main")
969 .finalize_unpruned()
970 .expect("expected pruned program should finalize")
971 });
972
973 let mut mac = BitMachine::for_program(&unpruned_program)
974 .expect("unpruned program has reasonable bounds");
975 let unpruned_output = mac
976 .exec(&unpruned_program, env)
977 .expect("unpruned program should run without failure");
978
979 let pruned_program = unpruned_program
980 .prune(env)
981 .expect("pruning should not fail if execution succeeded");
982 assert_eq!(
983 pruned_program.ihr(),
984 expected_unpruned_program.ihr(),
985 "pruning result differs from expected result"
986 );
987
988 let mut mac =
989 BitMachine::for_program(&pruned_program).expect("pruned program has reasonable bounds");
990 let pruned_output = mac
991 .exec(&pruned_program, env)
992 .expect("pruned program should run without failure");
993 assert_eq!(
994 unpruned_output, pruned_output,
995 "pruned program should return same output as unpruned program"
996 );
997 }
998
999 #[test]
1000 #[cfg(feature = "elements")]
1001 fn prune() {
1002 let env = crate::jet::elements::ElementsEnv::dummy();
1003
1004 let unpruned_prog = r#"wit1 := witness : 1 -> 2
1008wit2 := witness : 1 -> 2^64 * 2^64
1009input := pair wit1 wit2 : 1 -> 2 * (2^64 * 2^64)
1010process := case (drop take jet_is_zero_64) (drop drop jet_is_zero_64) : 2 * (2^64 * 2^64) -> 2
1011main := comp input comp process jet_verify : 1 -> 1"#;
1012
1013 let unpruned_wit = HashMap::from([
1015 (Arc::from("wit1"), Value::u1(0)),
1016 (
1017 Arc::from("wit2"),
1018 Value::product(Value::u64(0), Value::u64(0)),
1019 ),
1020 ]);
1021 let pruned_prog = r#"wit1 := witness : 1 -> 2
1022wit2 := witness : 1 -> 2^64 * 1 -- right component was pruned
1023input := pair wit1 wit2 : 1 -> 2 * (2^64 * 1)
1024process := assertl (drop take jet_is_zero_64) #{drop drop jet_is_zero_64} : 2 * (2^64 * 1) -> 2 -- case became assertl
1025main := comp input comp process jet_verify : 1 -> 1"#;
1026 let pruned_wit = HashMap::from([
1027 (Arc::from("wit1"), Value::u1(0)),
1028 (
1029 Arc::from("wit2"),
1030 Value::product(Value::u64(0), Value::unit()),
1031 ),
1032 ]);
1033 assert_correct_pruning::<crate::jet::Elements>(
1034 unpruned_prog,
1035 &unpruned_wit,
1036 pruned_prog,
1037 &pruned_wit,
1038 &env,
1039 );
1040
1041 let unpruned_wit = HashMap::from([
1043 (Arc::from("wit1"), Value::u1(1)),
1044 (
1045 Arc::from("wit2"),
1046 Value::product(Value::u64(0), Value::u64(0)),
1047 ),
1048 ]);
1049 let pruned_prog = r#"wit1 := witness : 1 -> 2
1050wit2 := witness : 1 -> 1 * 2^64 -- left component was pruned
1051input := pair wit1 wit2 : 1 -> 2 * (1 * 2^64)
1052process := assertr #{drop take jet_is_zero_64} (drop drop jet_is_zero_64) : 2 * (1 * 2^64) -> 2 -- case became assertr
1053main := comp input comp process jet_verify : 1 -> 1"#;
1054 let pruned_wit = HashMap::from([
1055 (Arc::from("wit1"), Value::u1(1)),
1056 (
1057 Arc::from("wit2"),
1058 Value::product(Value::unit(), Value::u64(0)),
1059 ),
1060 ]);
1061 assert_correct_pruning::<crate::jet::Elements>(
1062 unpruned_prog,
1063 &unpruned_wit,
1064 pruned_prog,
1065 &pruned_wit,
1066 &env,
1067 );
1068
1069 let prune_sum = r#"wit1 := witness : 1 -> 2^64 + 2^64
1073input := pair wit1 unit : 1 -> (2^64 + 2^64) * 1
1074process := case (take jet_is_zero_64) (take jet_is_zero_64) : (2^64 + 2^64) * 1 -> 2
1075main := comp input comp process jet_verify : 1 -> 1"#;
1076
1077 let unpruned_wit =
1079 HashMap::from([(Arc::from("wit1"), Value::left(Value::u64(0), Final::u64()))]);
1080 let pruned_prog = r#"wit1 := witness : 1 -> 2^64 + 1 -- right sub type became unit
1081input := pair wit1 unit : 1 -> (2^64 + 1) * 1
1082process := assertl (take jet_is_zero_64) #{take jet_is_zero_64} : (2^64 + 1) * 1 -> 2 -- case became assertl
1083main := comp input comp process jet_verify : 1 -> 1"#;
1084 let pruned_wit =
1085 HashMap::from([(Arc::from("wit1"), Value::left(Value::u64(0), Final::unit()))]);
1086 assert_correct_pruning::<crate::jet::Elements>(
1087 prune_sum,
1088 &unpruned_wit,
1089 pruned_prog,
1090 &pruned_wit,
1091 &env,
1092 );
1093
1094 let unpruned_wit = HashMap::from([(
1096 Arc::from("wit1"),
1097 Value::right(Final::unit(), Value::u64(0)),
1098 )]);
1099 let pruned_prog = r#"wit1 := witness : 1 -> 1 + 2^64 -- left sub type became unit
1100input := pair wit1 unit : 1 -> (1 + 2^64) * 1
1101process := assertr #{take jet_is_zero_64} (take jet_is_zero_64) : (1 + 2^64) * 1 -> 2 -- case became assertr
1102main := comp input comp process jet_verify : 1 -> 1"#;
1103 let pruned_wit = HashMap::from([(
1104 Arc::from("wit1"),
1105 Value::right(Final::unit(), Value::u64(0)),
1106 )]);
1107 assert_correct_pruning::<crate::jet::Elements>(
1108 prune_sum,
1109 &unpruned_wit,
1110 pruned_prog,
1111 &pruned_wit,
1112 &env,
1113 );
1114 }
1115}
1116
1117#[cfg(bench)]
1118#[cfg(feature = "elements")]
1119mod benches {
1120 use super::*;
1121
1122 use crate::bit_encoding::BitIter;
1123 use crate::jet::Elements;
1124
1125 use test::{black_box, Bencher};
1126
1127 #[bench]
1128 fn decode_fixed_program(bh: &mut Bencher) {
1129 let prog = &[
1130 0xd3, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b,
1131 0x78, 0xce, 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d,
1132 0x96, 0xd6, 0x79, 0x5f, 0x9c, 0x63, 0x47, 0x07, 0x02, 0xc0, 0xe2, 0x8d, 0x88, 0x10,
1133 ][..];
1134 let witness = &[
1135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce,
1136 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, 0xd6,
1137 0x79, 0x5f, 0x9c, 0x63, 0xdb, 0x86, 0x8d, 0x45, 0xa0, 0xbc, 0x1d, 0x19, 0x01, 0x30,
1138 0x2b, 0xc8, 0x7a, 0x87, 0x1c, 0xf1, 0x58, 0xe2, 0xbd, 0xe2, 0xcf, 0xa6, 0x45, 0xa8,
1139 0x95, 0xc1, 0xb4, 0x5d, 0x68, 0xea, 0x24, 0xc0,
1140 ][..];
1141 bh.iter(|| {
1142 let prog = BitIter::from(prog);
1143 let witness = BitIter::from(witness);
1144 black_box(RedeemNode::<Elements>::decode(
1145 black_box(prog),
1146 black_box(witness),
1147 ))
1148 .unwrap();
1149 });
1150 }
1151}