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, Error, Ihr, Imr, Value};
10
11use super::{
12 Commit, CommitData, CommitNode, Construct, ConstructData, ConstructNode, Constructible,
13 Converter, Hide, Inner, Marker, NoDisconnect, NoWitness, Node,
14};
15
16use std::collections::HashSet;
17use std::io;
18use std::marker::PhantomData;
19use std::sync::Arc;
20
21#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
22pub struct Redeem<J> {
23 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(&self) -> Arc<ConstructNode<J>> {
223 struct ToConstruct<J> {
224 inference_context: types::Context,
225 phantom: PhantomData<J>,
226 }
227
228 impl<J: Jet> Converter<Redeem<J>, Construct<J>> for ToConstruct<J> {
229 type Error = ();
230
231 fn convert_witness(
232 &mut self,
233 _: &PostOrderIterItem<&Node<Redeem<J>>>,
234 witness: &Value,
235 ) -> Result<Option<Value>, Self::Error> {
236 Ok(Some(witness.clone()))
237 }
238
239 fn convert_disconnect(
240 &mut self,
241 _: &PostOrderIterItem<&Node<Redeem<J>>>,
242 right: Option<&Arc<Node<Construct<J>>>>,
243 _: &Arc<RedeemNode<J>>,
244 ) -> Result<Option<Arc<Node<Construct<J>>>>, Self::Error> {
245 Ok(right.cloned())
246 }
247
248 fn convert_data(
249 &mut self,
250 _: &PostOrderIterItem<&Node<Redeem<J>>>,
251 inner: Inner<
252 &Arc<Node<Construct<J>>>,
253 J,
254 &Option<Arc<ConstructNode<J>>>,
255 &Option<Value>,
256 >,
257 ) -> Result<ConstructData<J>, Self::Error> {
258 let inner = inner
259 .map(|node| node.cached_data())
260 .map_witness(|maybe_value| maybe_value.clone());
261 Ok(ConstructData::from_inner(&self.inference_context, inner)
262 .expect("types were already finalized"))
263 }
264 }
265
266 self.convert::<InternalSharing, _, _>(&mut ToConstruct {
267 inference_context: types::Context::new(),
268 phantom: PhantomData,
269 })
270 .unwrap()
271 }
272
273 pub fn prune(&self, env: &J::Environment) -> Result<Arc<RedeemNode<J>>, ExecutionError> {
290 struct Pruner<J> {
291 inference_context: types::Context,
292 tracker: SetTracker,
293 phantom: PhantomData<J>,
294 }
295
296 impl<J: Jet> Converter<Redeem<J>, Construct<J>> for Pruner<J> {
297 type Error = std::convert::Infallible;
298
299 fn convert_witness(
300 &mut self,
301 _: &PostOrderIterItem<&RedeemNode<J>>,
302 witness: &Value,
303 ) -> Result<Option<Value>, Self::Error> {
304 Ok(Some(witness.shallow_clone()))
307 }
308
309 fn convert_disconnect(
310 &mut self,
311 _: &PostOrderIterItem<&RedeemNode<J>>,
312 right: Option<&Arc<ConstructNode<J>>>,
313 _: &Arc<RedeemNode<J>>,
314 ) -> Result<Option<Arc<ConstructNode<J>>>, Self::Error> {
315 debug_assert!(
316 right.is_some(),
317 "disconnected branch should exist in unpruned redeem program"
318 );
319 Ok(right.map(Arc::clone))
320 }
321
322 fn prune_case(
323 &mut self,
324 data: &PostOrderIterItem<&RedeemNode<J>>,
325 _left: &Arc<ConstructNode<J>>,
326 _right: &Arc<ConstructNode<J>>,
327 ) -> Result<Hide, Self::Error> {
328 match (
332 self.tracker.left().contains(&data.node.ihr()),
333 self.tracker.right().contains(&data.node.ihr()),
334 ) {
335 (true, true) => Ok(Hide::Neither),
336 (false, true) => Ok(Hide::Left),
337 (true, false) => Ok(Hide::Right),
338 (false, false) => Ok(Hide::Neither), }
340 }
341
342 fn convert_data(
343 &mut self,
344 _: &PostOrderIterItem<&RedeemNode<J>>,
345 inner: Inner<
346 &Arc<ConstructNode<J>>,
347 J,
348 &Option<Arc<ConstructNode<J>>>,
349 &Option<Value>,
350 >,
351 ) -> Result<ConstructData<J>, Self::Error> {
352 let converted_inner = inner
353 .map(|node| node.cached_data())
354 .map_witness(Option::<Value>::clone);
355 let retyped = ConstructData::from_inner(&self.inference_context, converted_inner)
356 .expect("pruned types should check out if unpruned types check out");
357 Ok(retyped)
358 }
359 }
360
361 struct Finalizer<J>(PhantomData<J>);
362
363 impl<J: Jet> Converter<Construct<J>, Redeem<J>> for Finalizer<J> {
364 type Error = std::convert::Infallible;
365
366 fn convert_witness(
367 &mut self,
368 data: &PostOrderIterItem<&ConstructNode<J>>,
369 witness: &Option<Value>,
370 ) -> Result<Value, Self::Error> {
371 let pruned_target_ty = data
372 .node
373 .arrow()
374 .target
375 .finalize()
376 .expect("pruned types should check out if unpruned types check out");
377 let pruned_witness = witness
378 .as_ref()
379 .expect("witness node that originally stems from redeem program should be populated")
380 .prune(&pruned_target_ty)
381 .expect("pruned type should be shrunken version of unpruned type");
382 Ok(pruned_witness)
383 }
384
385 fn convert_disconnect(
386 &mut self,
387 _: &PostOrderIterItem<&ConstructNode<J>>,
388 right: Option<&Arc<RedeemNode<J>>>,
389 _: &Option<Arc<ConstructNode<J>>>,
390 ) -> Result<Arc<RedeemNode<J>>, Self::Error> {
391 Ok(right
392 .map(Arc::clone)
393 .expect("disconnect node that originally stems from redeem program should have all branches"))
394 }
395
396 fn convert_data(
397 &mut self,
398 data: &PostOrderIterItem<&ConstructNode<J>>,
399 inner: Inner<&Arc<RedeemNode<J>>, J, &Arc<RedeemNode<J>>, &Value>,
400 ) -> Result<Arc<RedeemData<J>>, Self::Error> {
401 let final_arrow = data
403 .node
404 .arrow()
405 .finalize()
406 .expect("pruned types should check out if unpruned types check out");
407 let converted_inner = inner
408 .map(|node| node.cached_data())
409 .map_disconnect(|node| node.cached_data())
410 .map_witness(Value::shallow_clone);
411 Ok(Arc::new(RedeemData::new(final_arrow, converted_inner)))
412 }
413 }
414
415 let mut mac = BitMachine::for_program(self)?;
418 let tracker = mac.exec_prune(self, env)?;
419
420 let pruned_witness_program = self
424 .convert::<InternalSharing, _, _>(&mut Pruner {
425 inference_context: types::Context::new(),
426 tracker,
427 phantom: PhantomData,
428 })
429 .expect("pruning unused branches is infallible");
430
431 Ok(pruned_witness_program
435 .convert::<InternalSharing, _, _>(&mut Finalizer(PhantomData))
436 .expect("finalization is infallible"))
437 }
438
439 pub fn decode<I1, I2>(
441 mut program: BitIter<I1>,
442 mut witness: BitIter<I2>,
443 ) -> Result<Arc<Self>, Error>
444 where
445 I1: Iterator<Item = u8>,
446 I2: Iterator<Item = u8>,
447 {
448 struct DecodeFinalizer<'bits, J: Jet, I: Iterator<Item = u8>> {
450 bits: &'bits mut BitIter<I>,
451 phantom: PhantomData<J>,
452 }
453
454 impl<J: Jet, I: Iterator<Item = u8>> Converter<Construct<J>, Redeem<J>>
455 for DecodeFinalizer<'_, J, I>
456 {
457 type Error = Error;
458 fn convert_witness(
459 &mut self,
460 data: &PostOrderIterItem<&ConstructNode<J>>,
461 _: &Option<Value>,
462 ) -> Result<Value, Self::Error> {
463 let arrow = data.node.data.arrow();
464 let target_ty = arrow.target.finalize()?;
465 Value::from_compact_bits(self.bits, &target_ty).map_err(Error::from)
466 }
467
468 fn convert_disconnect(
469 &mut self,
470 _: &PostOrderIterItem<&ConstructNode<J>>,
471 right: Option<&Arc<RedeemNode<J>>>,
472 _: &Option<Arc<ConstructNode<J>>>,
473 ) -> Result<Arc<RedeemNode<J>>, Self::Error> {
474 if let Some(child) = right {
475 Ok(Arc::clone(child))
476 } else {
477 Err(Error::DisconnectRedeemTime)
478 }
479 }
480
481 fn convert_data(
482 &mut self,
483 data: &PostOrderIterItem<&ConstructNode<J>>,
484 inner: Inner<&Arc<RedeemNode<J>>, J, &Arc<RedeemNode<J>>, &Value>,
485 ) -> Result<Arc<RedeemData<J>>, Self::Error> {
486 let arrow = data.node.data.arrow().finalize()?;
487 let converted_data = inner
488 .map(|node| node.cached_data())
489 .map_disconnect(|node| node.cached_data())
490 .map_witness(Value::shallow_clone);
491 Ok(Arc::new(RedeemData::new(arrow, converted_data)))
492 }
493 }
494
495 let construct = crate::decode::decode_expression(&mut program)?;
497 program
498 .close()
499 .map_err(crate::decode::Error::BitIter)
500 .map_err(Error::Decode)?;
501 construct.set_arrow_to_program()?;
502
503 let program: Arc<Self> =
506 construct.convert::<InternalSharing, _, _>(&mut DecodeFinalizer {
507 bits: &mut witness,
508 phantom: PhantomData,
509 })?;
510
511 witness
513 .close()
514 .map_err(crate::decode::Error::BitIter)
515 .map_err(Error::Decode)?;
516
517 let mut ihrs: HashSet<Ihr> = HashSet::new();
521 for data in program.as_ref().post_order_iter::<InternalSharing>() {
522 if !ihrs.insert(data.node.ihr()) {
523 return Err(Error::Decode(crate::decode::Error::SharingNotMaximal));
524 }
525 }
526
527 Ok(program)
528 }
529
530 pub fn encode<W1, W2>(
534 &self,
535 prog: &mut BitWriter<W1>,
536 witness: &mut BitWriter<W2>,
537 ) -> io::Result<usize>
538 where
539 W1: io::Write,
540 W2: io::Write,
541 {
542 let sharing_iter = self.post_order_iter::<MaxSharing<Redeem<J>>>();
543 let program_bits = encode::encode_program(self, prog)?;
544 prog.flush_all()?;
545 let witness_bits = encode::encode_witness(sharing_iter.into_witnesses(), witness)?;
546 witness.flush_all()?;
547 Ok(program_bits + witness_bits)
548 }
549
550 pub fn encode_to_vec(&self) -> (Vec<u8>, Vec<u8>) {
552 let mut ret_1 = vec![];
553 let mut ret_2 = vec![];
554 self.encode(
555 &mut BitWriter::new(&mut ret_1),
556 &mut BitWriter::new(&mut ret_2),
557 )
558 .unwrap();
559 (ret_1, ret_2)
560 }
561}
562
563#[cfg(test)]
564mod tests {
565 use super::*;
566 use crate::human_encoding::Forest;
567 use crate::jet::Core;
568 use crate::node::SimpleFinalizer;
569 use crate::types::Final;
570 use hex::DisplayHex;
571 use std::collections::HashMap;
572 use std::fmt;
573
574 fn assert_program_deserializable<J: Jet>(
575 prog_bytes: &[u8],
576 witness_bytes: &[u8],
577 cmr_str: &str,
578 amr_str: &str,
579 ihr_str: &str,
580 ) -> Arc<RedeemNode<J>> {
581 let prog_hex = prog_bytes.as_hex();
582 let witness_hex = witness_bytes.as_hex();
583
584 let prog = BitIter::from(prog_bytes);
585 let witness = BitIter::from(witness_bytes);
586 let prog = match RedeemNode::<J>::decode(prog, witness) {
587 Ok(prog) => prog,
588 Err(e) => panic!("program {} failed: {}", prog_hex, e),
589 };
590
591 assert_eq!(
592 prog.cmr().to_string(),
593 cmr_str,
594 "CMR mismatch (got {} expected {}) for program {}",
595 prog.cmr(),
596 cmr_str,
597 prog_hex,
598 );
599
600 assert_eq!(
601 prog.amr().to_string(),
602 amr_str,
603 "AMR mismatch (got {} expected {}) for program {}",
604 prog.amr(),
605 amr_str,
606 prog_hex,
607 );
608 assert_eq!(
609 prog.ihr().to_string(),
610 ihr_str,
611 "IHR mismatch (got {} expected {}) for program {}",
612 prog.ihr(),
613 ihr_str,
614 prog_hex,
615 );
616
617 let (reser_prog, reser_witness) = prog.encode_to_vec();
618 assert_eq!(
619 prog_bytes,
620 &reser_prog[..],
621 "program {} reserialized as {}",
622 prog_hex,
623 reser_prog.as_hex(),
624 );
625 assert_eq!(
626 witness_bytes,
627 &reser_witness[..],
628 "witness {} reserialized as {}",
629 witness_hex,
630 reser_witness.as_hex(),
631 );
632
633 prog
634 }
635
636 fn assert_program_not_deserializable<J: Jet>(
637 prog_bytes: &[u8],
638 witness_bytes: &[u8],
639 err: &dyn fmt::Display,
640 ) {
641 let prog_hex = prog_bytes.as_hex();
642 let witness_hex = witness_bytes.as_hex();
643 let err_str = err.to_string();
644
645 let prog = BitIter::from(prog_bytes);
646 let witness = BitIter::from(witness_bytes);
647 match RedeemNode::<J>::decode(prog, witness) {
648 Ok(prog) => panic!(
649 "Program {} wit {} succeded (expected error {}). Program parsed as:\n{}",
650 prog_hex, witness_hex, err, prog
651 ),
652 Err(e) if e.to_string() == err_str => {} Err(e) => panic!(
654 "Program {} wit {} failed with error {} (expected error {})",
655 prog_hex, witness_hex, e, err
656 ),
657 };
658 }
659
660 #[test]
661 fn encode_shared_witnesses() {
662 let eqwits = [0xcd, 0xdc, 0x51, 0xb6, 0xe2, 0x08, 0xc0, 0x40];
669 let iter = BitIter::from(&eqwits[..]);
670 let eqwits_prog = CommitNode::<Core>::decode(iter).unwrap();
671
672 let eqwits_final = eqwits_prog
673 .finalize(&mut SimpleFinalizer::new(std::iter::repeat(Value::u32(
674 0xDEADBEEF,
675 ))))
676 .unwrap();
677 let output = eqwits_final.encode_to_vec();
678
679 assert_eq!(
680 output,
681 (
682 [0xc9, 0xc4, 0x6d, 0xb8, 0x82, 0x30, 0x10].into(),
683 [0xde, 0xad, 0xbe, 0xef].into(),
684 ),
685 "output {} {}",
686 output.0.as_hex(),
687 output.1.as_hex()
688 );
689 }
690
691 #[test]
692 fn decode_shared_witnesses() {
693 assert_program_deserializable::<Core>(
697 &[0xc9, 0xc4, 0x6d, 0xb8, 0x82, 0x30, 0x10],
698 &[0xde, 0xad, 0xbe, 0xef],
699 "d7969920eff9a1ed0359aaa8545b239c69969e22c304c645a7b49bcc976a40a8",
700 "f7acbb077e7661a08384818bc8e3a275ed42ad446252575a35a35f71689fef78",
701 "3ce4a6390b4e4bda6330acda4800e66e5d2cae0f5a2888564c706f2b910146b8",
702 );
703 }
704
705 #[test]
706 fn unshared_child() {
707 assert_program_not_deserializable::<Core>(
713 &[0xc1, 0x08, 0x04, 0x00],
714 &[],
715 &Error::Decode(crate::decode::Error::SharingNotMaximal),
716 );
717 }
718
719 #[test]
720 fn witness_consumed() {
721 let prog = BitIter::from(&[0x24][..]);
723 let wit = BitIter::from(&[0x00][..]);
724 match RedeemNode::<Core>::decode(prog, wit) {
725 Err(Error::Decode(crate::decode::Error::BitIter(
726 crate::BitIterCloseError::TrailingBytes { first_byte: 0 },
727 ))) => {} Err(e) => panic!("got incorrect error {e}"),
729 Ok(_) => panic!("accepted program with bad witness length"),
730 }
731 }
732
733 #[test]
734 fn shared_grandchild() {
735 assert_program_deserializable::<Core>(
744 &[0xc1, 0x00, 0x00, 0x01, 0x00],
745 &[],
746 "8a54101335ca2cf7e933d74cdb15f99becc4e540799ba5e2d19c00c9d7219e71",
747 "74e868bd640c250bc45522085158a9723fc7e277bb16a8d582c4012ebbb1f6f1",
748 "39b8f72bd1539de87d26673890603d6548cfc8b68571d996bdf9b1d8b557bd35",
749 );
750 }
751
752 #[test]
753 #[rustfmt::skip]
754 fn assert_lr() {
755 assert_program_deserializable::<Core>(
759 &[
760 0xcd, 0x24, 0x08, 0x4b, 0x6f, 0x56, 0xdf, 0x77,
761 0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
762 0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
763 0xef, 0x56, 0xdf, 0x77, 0xef, 0x56, 0xdf, 0x77,
764 0xef, 0x56, 0xdf, 0x77, 0x86, 0x01, 0x80,
765 ],
766 &[],
767 "abdd773fc7a503908739b4a63198416fdd470948830cb5a6516b98fe0a3bfa85",
768 "1362ee53ae75218ed51dc4bd46cdbfa585f934ac6c6c3ff787e27dce91ccd80b",
769 "251c6778129e0f12da3f2388ab30184e815e9d9456b5931e54802a6715d9ca42",
770 );
771
772
773 assert_program_deserializable::<Core>(
777 &[
778 0xcd, 0x25, 0x08, 0x6d, 0xea, 0xdb, 0xee, 0xfd,
779 0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
780 0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
781 0xea, 0xdb, 0xee, 0xfd, 0xea, 0xdb, 0xee, 0xfd,
782 0xea, 0xdb, 0xee, 0xf4, 0x86, 0x01, 0x80,
783 ],
784 &[],
785 "f6c678dfb180b94567a9d524e05fbc893f6905e0e3db931ff01dc2701e783d4c",
786 "212d4fa3dbe2b33db1e11bb6f4cc973be5de0896a3775387a06056483b8feb0f",
787 "7a583edcc733b6bba66998110be403ac61fab2d93fc09ba3c84ab2509b538043",
788 );
789 }
790
791 #[test]
792 #[rustfmt::skip]
793 fn disconnect() {
794 assert_program_deserializable::<Core>(
800 &[0xc5, 0x02, 0x06, 0x24, 0x10],
801 &[],
802 "afe8f5f8bd3f64bfa51d2f29ffa22523604d9654c0d9862dbf2dc67ba097cbb2",
803 "15239708cb7b448cedc6a0b6401dce86ed74084056dd95831928860dd0c3ca67",
804 "9cdacb48b16e108ccbd6bcbce459a64056df285c2dc6e02dca6d13c4b1530fb0",
805 );
806 }
807
808 #[test]
809 #[rustfmt::skip]
810 #[cfg(feature = "elements")]
811 fn disconnect2() {
812 assert_program_deserializable::<crate::jet::Elements>(
832 &[
833 0xd3, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce,
834 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, 0xd6, 0x79, 0x5f,
835 0x9c, 0x63, 0x47, 0x07, 0x02, 0xc0, 0xe2, 0x8d, 0x88, 0x10,
836 ],
837 &[
838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce, 0x56, 0x3f,
839 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, 0xd6, 0x79, 0x5f, 0x9c, 0x63,
840 0xdb, 0x86, 0x8d, 0x45, 0xa0, 0xbc, 0x1d, 0x19, 0x01, 0x30, 0x2b, 0xc8, 0x7a, 0x87, 0x1c, 0xf1,
841 0x58, 0xe2, 0xbd, 0xe2, 0xcf, 0xa6, 0x45, 0xa8, 0x95, 0xc1, 0xb4, 0x5d, 0x68, 0xea, 0x24, 0xc0,
842 ],
843 "f3cd4537d7ebb201732203195b30b549b8dc0c2c6257b3a0d53bedb08ea02874",
844 "107fa80454ed0f2d95d7c18d307912b1497505b98de47198fee23b5018efa544",
845 "d52021c638ba742a90bead9b3055efd66091fb50bb131aa8b10eb7c13ef464d1",
846 );
847 }
848
849 #[test]
850 #[rustfmt::skip]
851 #[cfg(feature = "elements")]
852 fn disconnect3() {
853 assert_program_deserializable::<crate::jet::Elements>(
863 &[0xc9, 0x09, 0x20, 0x74, 0x90, 0x40],
864 &[],
865 "b689bdee289c8dd4e2e283358d187813363d441776cf826dafc27cc8a81ec441",
866 "3c68660a1afde7982ce4aa9d499ad382bc32f5f9ad894a5e915f76e66303a25b",
867 "85313720ee43ae0ee03f88b05e6d9e4494308c6897bdeb3e93b94559c3317484",
868 );
869 }
870
871 #[test]
872 #[cfg(feature = "elements")]
873 fn decode_schnorr() {
874 #[rustfmt::skip]
875 let schnorr0 = vec![
876 0xc6, 0xd5, 0xf2, 0x61, 0x14, 0x03, 0x24, 0xb1, 0x86, 0x20, 0x92, 0x68, 0x9f, 0x0b, 0xf1, 0x3a,
877 0xa4, 0x53, 0x6a, 0x63, 0x90, 0x8b, 0x06, 0xdf, 0x33, 0x61, 0x0c, 0x03, 0xe2, 0x27, 0x79, 0xc0,
878 0x6d, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
879 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
880 0x00, 0x00, 0xe2, 0x8d, 0x8c, 0x04, 0x00,
881 ];
882 #[rustfmt::skip]
883 let schnorr0_wit = vec![
884 0xe9, 0x07, 0x83, 0x1f, 0x80, 0x84, 0x8d, 0x10, 0x69, 0xa5, 0x37, 0x1b, 0x40, 0x24, 0x10, 0x36,
885 0x4b, 0xdf, 0x1c, 0x5f, 0x83, 0x07, 0xb0, 0x08, 0x4c, 0x55, 0xf1, 0xce, 0x2d, 0xca, 0x82, 0x15,
886 0x25, 0xf6, 0x6a, 0x4a, 0x85, 0xea, 0x8b, 0x71, 0xe4, 0x82, 0xa7, 0x4f, 0x38, 0x2d, 0x2c, 0xe5,
887 0xeb, 0xee, 0xe8, 0xfd, 0xb2, 0x17, 0x2f, 0x47, 0x7d, 0xf4, 0x90, 0x0d, 0x31, 0x05, 0x36, 0xc0,
888 ];
889 assert_program_deserializable::<crate::jet::Elements>(
890 &schnorr0,
891 &schnorr0_wit,
892 "8a9e97676b24be7797d9ee0bf32dd76bcd78028e973025f785eae8dc91c8a0da",
893 "ec97c8774cb6bfb381fdbbcc8d964380fb3a3b45779322624490d6231ae777a4",
894 "ad7c38b16b9129646dc89b52cff144de94a80e383c4983b53de65e3575abcf38",
895 );
896 }
897
898 #[cfg(feature = "elements")]
899 fn assert_correct_pruning<J: Jet>(
900 unpruned_prog: &str,
901 unpruned_wit: &HashMap<Arc<str>, Value>,
902 expected_pruned_prog: &str,
903 expected_pruned_wit: &HashMap<Arc<str>, Value>,
904 env: &J::Environment,
905 ) {
906 let unpruned_program = Forest::<J>::parse(unpruned_prog)
907 .expect("unpruned program should parse")
908 .to_witness_node(unpruned_wit)
909 .expect("unpruned program should have main")
910 .finalize_unpruned()
911 .expect("unpruned program should finalize");
912 let expected_unpruned_program = Forest::<J>::parse(expected_pruned_prog)
913 .expect("expected pruned program should parse")
914 .to_witness_node(expected_pruned_wit)
915 .expect("expected pruned program should have main")
916 .finalize_unpruned()
917 .expect("expected pruned program should finalize");
918
919 let mut mac = BitMachine::for_program(&unpruned_program)
920 .expect("unpruned program has reasonable bounds");
921 let unpruned_output = mac
922 .exec(&unpruned_program, env)
923 .expect("unpruned program should run without failure");
924
925 let pruned_program = unpruned_program
926 .prune(env)
927 .expect("pruning should not fail if execution succeeded");
928 assert_eq!(
929 pruned_program.ihr(),
930 expected_unpruned_program.ihr(),
931 "pruning result differs from expected result"
932 );
933
934 let mut mac =
935 BitMachine::for_program(&pruned_program).expect("pruned program has reasonable bounds");
936 let pruned_output = mac
937 .exec(&pruned_program, env)
938 .expect("pruned program should run without failure");
939 assert_eq!(
940 unpruned_output, pruned_output,
941 "pruned program should return same output as unpruned program"
942 );
943 }
944
945 #[test]
946 #[cfg(feature = "elements")]
947 fn prune() {
948 let env = crate::jet::elements::ElementsEnv::dummy();
949
950 let unpruned_prog = r#"wit1 := witness : 1 -> 2
954wit2 := witness : 1 -> 2^64 * 2^64
955input := pair wit1 wit2 : 1 -> 2 * (2^64 * 2^64)
956process := case (drop take jet_is_zero_64) (drop drop jet_is_zero_64) : 2 * (2^64 * 2^64) -> 2
957main := comp input comp process jet_verify : 1 -> 1"#;
958
959 let unpruned_wit = HashMap::from([
961 (Arc::from("wit1"), Value::u1(0)),
962 (
963 Arc::from("wit2"),
964 Value::product(Value::u64(0), Value::u64(0)),
965 ),
966 ]);
967 let pruned_prog = r#"wit1 := witness : 1 -> 2
968wit2 := witness : 1 -> 2^64 * 1 -- right component was pruned
969input := pair wit1 wit2 : 1 -> 2 * (2^64 * 1)
970process := assertl (drop take jet_is_zero_64) #{drop drop jet_is_zero_64} : 2 * (2^64 * 1) -> 2 -- case became assertl
971main := comp input comp process jet_verify : 1 -> 1"#;
972 let pruned_wit = HashMap::from([
973 (Arc::from("wit1"), Value::u1(0)),
974 (
975 Arc::from("wit2"),
976 Value::product(Value::u64(0), Value::unit()),
977 ),
978 ]);
979 assert_correct_pruning::<crate::jet::Elements>(
980 unpruned_prog,
981 &unpruned_wit,
982 pruned_prog,
983 &pruned_wit,
984 &env,
985 );
986
987 let unpruned_wit = HashMap::from([
989 (Arc::from("wit1"), Value::u1(1)),
990 (
991 Arc::from("wit2"),
992 Value::product(Value::u64(0), Value::u64(0)),
993 ),
994 ]);
995 let pruned_prog = r#"wit1 := witness : 1 -> 2
996wit2 := witness : 1 -> 1 * 2^64 -- left component was pruned
997input := pair wit1 wit2 : 1 -> 2 * (1 * 2^64)
998process := assertr #{drop take jet_is_zero_64} (drop drop jet_is_zero_64) : 2 * (1 * 2^64) -> 2 -- case became assertr
999main := comp input comp process jet_verify : 1 -> 1"#;
1000 let pruned_wit = HashMap::from([
1001 (Arc::from("wit1"), Value::u1(1)),
1002 (
1003 Arc::from("wit2"),
1004 Value::product(Value::unit(), Value::u64(0)),
1005 ),
1006 ]);
1007 assert_correct_pruning::<crate::jet::Elements>(
1008 unpruned_prog,
1009 &unpruned_wit,
1010 pruned_prog,
1011 &pruned_wit,
1012 &env,
1013 );
1014
1015 let prune_sum = r#"wit1 := witness : 1 -> 2^64 + 2^64
1019input := pair wit1 unit : 1 -> (2^64 + 2^64) * 1
1020process := case (take jet_is_zero_64) (take jet_is_zero_64) : (2^64 + 2^64) * 1 -> 2
1021main := comp input comp process jet_verify : 1 -> 1"#;
1022
1023 let unpruned_wit =
1025 HashMap::from([(Arc::from("wit1"), Value::left(Value::u64(0), Final::u64()))]);
1026 let pruned_prog = r#"wit1 := witness : 1 -> 2^64 + 1 -- right sub type became unit
1027input := pair wit1 unit : 1 -> (2^64 + 1) * 1
1028process := assertl (take jet_is_zero_64) #{take jet_is_zero_64} : (2^64 + 1) * 1 -> 2 -- case became assertl
1029main := comp input comp process jet_verify : 1 -> 1"#;
1030 let pruned_wit =
1031 HashMap::from([(Arc::from("wit1"), Value::left(Value::u64(0), Final::unit()))]);
1032 assert_correct_pruning::<crate::jet::Elements>(
1033 prune_sum,
1034 &unpruned_wit,
1035 pruned_prog,
1036 &pruned_wit,
1037 &env,
1038 );
1039
1040 let unpruned_wit = HashMap::from([(
1042 Arc::from("wit1"),
1043 Value::right(Final::unit(), Value::u64(0)),
1044 )]);
1045 let pruned_prog = r#"wit1 := witness : 1 -> 1 + 2^64 -- left sub type became unit
1046input := pair wit1 unit : 1 -> (1 + 2^64) * 1
1047process := assertr #{take jet_is_zero_64} (take jet_is_zero_64) : (1 + 2^64) * 1 -> 2 -- case became assertr
1048main := comp input comp process jet_verify : 1 -> 1"#;
1049 let pruned_wit = HashMap::from([(
1050 Arc::from("wit1"),
1051 Value::right(Final::unit(), Value::u64(0)),
1052 )]);
1053 assert_correct_pruning::<crate::jet::Elements>(
1054 prune_sum,
1055 &unpruned_wit,
1056 pruned_prog,
1057 &pruned_wit,
1058 &env,
1059 );
1060 }
1061}