1use crate::dag::{DagLike, MaxSharing, SharingTracker};
67use crate::encode;
68use crate::jet::Jet;
69use crate::{types, BitWriter, Cmr, FailEntropy, HasCmr, Value};
70
71use std::sync::Arc;
72use std::{fmt, hash, io};
73
74mod commit;
75mod construct;
76mod convert;
77mod disconnect;
78mod display;
79mod hiding;
80mod inner;
81mod redeem;
82
83use crate::value::Word;
84pub use commit::{Commit, CommitData, CommitNode};
85pub use construct::{Construct, ConstructData, ConstructNode};
86pub use convert::{Converter, Hide, SimpleFinalizer};
87pub use disconnect::{Disconnectable, NoDisconnect};
88pub use display::{Display, DisplayAsGraph, DisplayExpr, GraphFormat, SharingLevel};
89pub use hiding::Hiding;
90pub use inner::Inner;
91pub use redeem::{Redeem, RedeemData, RedeemNode};
92
93#[doc(hidden)]
98#[deprecated(note = "subsumed by CoreConstructible")]
99pub enum JetConstructible {}
100
101pub trait Marker:
105 Copy + Clone + PartialEq + Eq + PartialOrd + Ord + fmt::Debug + hash::Hash
106{
107 type CachedData: Clone;
109
110 type Witness: Clone;
113
114 type Disconnect: Disconnectable<Node<Self>> + Clone;
116
117 type SharingId: hash::Hash + Clone + Eq;
120
121 fn compute_sharing_id(cmr: Cmr, cached_data: &Self::CachedData) -> Option<Self::SharingId>;
127}
128
129#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
131pub struct NoWitness;
132
133impl From<NoWitness> for Option<Value> {
134 fn from(_: NoWitness) -> Self {
135 None
136 }
137}
138
139pub trait Constructible<'brand, X, W>:
140 DisconnectConstructible<'brand, X>
141 + WitnessConstructible<'brand, W>
142 + CoreConstructible<'brand>
143 + Sized
144{
145 fn from_inner(
146 inference_context: &types::Context<'brand>,
147 inner: Inner<&Self, &X, W>,
148 ) -> Result<Self, types::Error> {
149 match inner {
150 Inner::Iden => Ok(Self::iden(inference_context)),
151 Inner::Unit => Ok(Self::unit(inference_context)),
152 Inner::InjL(child) => Ok(Self::injl(child)),
153 Inner::InjR(child) => Ok(Self::injr(child)),
154 Inner::Take(child) => Ok(Self::take(child)),
155 Inner::Drop(child) => Ok(Self::drop_(child)),
156 Inner::Comp(left, right) => Self::comp(left, right),
157 Inner::Case(left, right) => Self::case(left, right),
158 Inner::AssertL(left, r_cmr) => Self::assertl(left, r_cmr),
159 Inner::AssertR(l_cmr, right) => Self::assertr(l_cmr, right),
160 Inner::Pair(left, right) => Self::pair(left, right),
161 Inner::Disconnect(left, right) => Self::disconnect(left, right),
162 Inner::Fail(entropy) => Ok(Self::fail(inference_context, entropy)),
163 Inner::Word(ref w) => Ok(Self::const_word(inference_context, w.shallow_clone())),
164 Inner::Jet(j) => Ok(Self::jet(inference_context, j.as_ref())),
165 Inner::Witness(w) => Ok(Self::witness(inference_context, w)),
166 }
167 }
168}
169
170impl<'brand, X, W, T> Constructible<'brand, X, W> for T where
171 T: DisconnectConstructible<'brand, X>
172 + WitnessConstructible<'brand, W>
173 + CoreConstructible<'brand>
174 + Sized
175{
176}
177
178pub trait CoreConstructible<'brand>: Sized {
179 fn iden(inference_context: &types::Context<'brand>) -> Self;
180 fn unit(inference_context: &types::Context<'brand>) -> Self;
181 fn injl(child: &Self) -> Self;
182 fn injr(child: &Self) -> Self;
183 fn take(child: &Self) -> Self;
184 fn drop_(child: &Self) -> Self;
185 fn comp(left: &Self, right: &Self) -> Result<Self, types::Error>;
186 fn case(left: &Self, right: &Self) -> Result<Self, types::Error>;
187 fn assertl(left: &Self, right: Cmr) -> Result<Self, types::Error>;
188 fn assertr(left: Cmr, right: &Self) -> Result<Self, types::Error>;
189 fn pair(left: &Self, right: &Self) -> Result<Self, types::Error>;
190 fn fail(inference_context: &types::Context<'brand>, entropy: FailEntropy) -> Self;
191 fn const_word(inference_context: &types::Context<'brand>, word: Word) -> Self;
192 fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self;
193
194 #[inline]
196 fn inference_context(&self) -> &types::Context<'brand> {
197 &self.arrow().inference_context
198 }
199 fn arrow(&self) -> &types::Arrow<'brand>;
200
201 fn scribe(ctx: &types::Context<'brand>, value: &Value) -> Self {
205 use crate::value::ValueRef;
206
207 #[derive(Debug, Clone)]
208 enum Task<'v> {
209 Process(ValueRef<'v>),
210 MakeLeft,
211 MakeRight,
212 MakeProduct,
213 }
214
215 let mut input = vec![Task::Process(value.as_ref())];
216 let mut output = vec![];
217 while let Some(top) = input.pop() {
218 match top {
219 Task::Process(value) => {
220 if value.is_unit() {
221 output.push(Self::unit(ctx));
222 } else if let Some(word) = value.to_word() {
223 output.push(Self::const_word(ctx, word));
224 } else if let Some(left) = value.as_left() {
225 input.push(Task::MakeLeft);
226 input.push(Task::Process(left));
227 } else if let Some(right) = value.as_right() {
228 input.push(Task::MakeRight);
229 input.push(Task::Process(right));
230 } else if let Some((left, right)) = value.as_product() {
231 input.push(Task::MakeProduct);
232 input.push(Task::Process(right));
233 input.push(Task::Process(left));
234 }
235 }
236 Task::MakeLeft => {
237 let inner = output.pop().unwrap();
238 output.push(Self::injl(&inner));
239 }
240 Task::MakeRight => {
241 let inner = output.pop().unwrap();
242 output.push(Self::injr(&inner));
243 }
244 Task::MakeProduct => {
245 let right = output.pop().unwrap();
246 let left = output.pop().unwrap();
247 output.push(
249 Self::pair(&left, &right).expect(
250 "`pair` should always succeed because input type is unrestricted",
251 ),
252 );
253 }
254 }
255 }
256 debug_assert_eq!(output.len(), 1);
257 output.pop().unwrap()
258 }
259
260 fn bit_false(inference_context: &types::Context<'brand>) -> Self {
264 let unit = Self::unit(inference_context);
265 Self::injl(&unit)
266 }
267
268 fn bit_true(inference_context: &types::Context<'brand>) -> Self {
272 let unit = Self::unit(inference_context);
273 Self::injr(&unit)
274 }
275
276 fn cond(left: &Self, right: &Self) -> Result<Self, types::Error> {
284 let drop_left = Self::drop_(left);
285 let drop_right = Self::drop_(right);
286 Self::case(&drop_right, &drop_left)
287 }
288
289 fn assert(child: &Self, hash: Cmr) -> Result<Self, types::Error> {
296 let unit = Self::unit(child.inference_context());
297 let pair_child_unit = Self::pair(child, &unit)?;
298 let assertr_hidden_unit = Self::assertr(hash, &unit)?;
299
300 Self::comp(&pair_child_unit, &assertr_hidden_unit)
301 }
302
303 #[allow(clippy::should_implement_trait)]
309 fn not(child: &Self) -> Result<Self, types::Error> {
310 let unit = Self::unit(child.inference_context());
311 let pair_child_unit = Self::pair(child, &unit)?;
312 let bit_true = Self::bit_true(child.inference_context());
313 let bit_false = Self::bit_false(child.inference_context());
314 let case_true_false = Self::case(&bit_true, &bit_false)?;
315
316 Self::comp(&pair_child_unit, &case_true_false)
317 }
318
319 fn and(left: &Self, right: &Self) -> Result<Self, types::Error> {
325 left.inference_context()
326 .check_eq(right.inference_context())?;
327 let iden = Self::iden(left.inference_context());
328 let pair_left_iden = Self::pair(left, &iden)?;
329 let bit_false = Self::bit_false(left.inference_context());
330 let drop_right = Self::drop_(right);
331 let case_false_right = Self::case(&bit_false, &drop_right)?;
332
333 Self::comp(&pair_left_iden, &case_false_right)
334 }
335
336 fn or(left: &Self, right: &Self) -> Result<Self, types::Error> {
342 left.inference_context()
343 .check_eq(right.inference_context())?;
344 let iden = Self::iden(left.inference_context());
345 let pair_left_iden = Self::pair(left, &iden)?;
346 let drop_right = Self::drop_(right);
347 let bit_true = Self::bit_true(left.inference_context());
348 let case_right_true = Self::case(&drop_right, &bit_true)?;
349
350 Self::comp(&pair_left_iden, &case_right_true)
351 }
352}
353
354pub trait DisconnectConstructible<'brand, X>: Sized {
355 fn disconnect(left: &Self, right: &X) -> Result<Self, types::Error>;
356}
357
358pub trait WitnessConstructible<'brand, W>: Sized {
359 fn witness(inference_context: &types::Context<'brand>, witness: W) -> Self;
360}
361
362pub struct Node<N: Marker> {
376 inner: Inner<Arc<Node<N>>, N::Disconnect, N::Witness>,
377 cmr: Cmr,
378 data: N::CachedData,
379}
380
381impl<N: Marker> PartialEq for Node<N>
382where
383 N::CachedData: PartialEq,
384{
385 fn eq(&self, other: &Self) -> bool {
386 self.cmr == other.cmr && self.data == other.data
387 }
388}
389impl<N: Marker> Eq for Node<N> where N::CachedData: Eq {}
390
391impl<N: Marker> hash::Hash for Node<N>
392where
393 N::CachedData: hash::Hash,
394{
395 fn hash<H: hash::Hasher>(&self, h: &mut H) {
396 self.cmr.hash(h);
397 self.data.hash(h);
398 }
399}
400
401impl<N: Marker> fmt::Debug for Node<N>
402where
403 for<'a> &'a Node<N>: DagLike,
404{
405 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406 self.post_order_iter::<MaxSharing<N>>().into_display(
407 f,
408 |node, f| fmt::Display::fmt(&node.inner, f),
409 |_, _| Ok(()),
410 )
411 }
412}
413
414#[cfg(feature = "base64")]
415impl<N: Marker> fmt::Display for Node<N> {
416 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
420 use crate::base64::display::Base64Display;
421 use crate::base64::engine::general_purpose;
422
423 let v = self.to_vec_without_witness();
424 Base64Display::new(&v, &general_purpose::STANDARD).fmt(f)
425 }
426}
427
428impl<N: Marker> HasCmr for Node<N> {
429 fn cmr(&self) -> Cmr {
430 self.cmr
431 }
432}
433
434impl<N: Marker> HasCmr for Arc<Node<N>> {
435 fn cmr(&self) -> Cmr {
436 self.cmr
437 }
438}
439
440impl<'brand, N> CoreConstructible<'brand> for Arc<Node<N>>
441where
442 N: Marker,
443 N::CachedData: CoreConstructible<'brand>,
444{
445 fn iden(inference_context: &types::Context<'brand>) -> Self {
446 Arc::new(Node {
447 cmr: Cmr::iden(),
448 data: N::CachedData::iden(inference_context),
449 inner: Inner::Iden,
450 })
451 }
452
453 fn unit(inference_context: &types::Context<'brand>) -> Self {
454 Arc::new(Node {
455 cmr: Cmr::unit(),
456 data: N::CachedData::unit(inference_context),
457 inner: Inner::Unit,
458 })
459 }
460
461 fn injl(child: &Self) -> Self {
462 Arc::new(Node {
463 cmr: Cmr::injl(child.cmr()),
464 data: N::CachedData::injl(&child.data),
465 inner: Inner::InjL(Arc::clone(child)),
466 })
467 }
468
469 fn injr(child: &Self) -> Self {
470 Arc::new(Node {
471 cmr: Cmr::injr(child.cmr()),
472 data: N::CachedData::injr(&child.data),
473 inner: Inner::InjR(Arc::clone(child)),
474 })
475 }
476
477 fn take(child: &Self) -> Self {
478 Arc::new(Node {
479 cmr: Cmr::take(child.cmr()),
480 data: N::CachedData::take(&child.data),
481 inner: Inner::Take(Arc::clone(child)),
482 })
483 }
484
485 fn drop_(child: &Self) -> Self {
486 Arc::new(Node {
487 cmr: Cmr::drop(child.cmr()),
488 data: N::CachedData::drop_(&child.data),
489 inner: Inner::Drop(Arc::clone(child)),
490 })
491 }
492
493 fn comp(left: &Self, right: &Self) -> Result<Self, types::Error> {
494 Ok(Arc::new(Node {
495 cmr: Cmr::comp(left.cmr(), right.cmr()),
496 data: N::CachedData::comp(&left.data, &right.data)?,
497 inner: Inner::Comp(Arc::clone(left), Arc::clone(right)),
498 }))
499 }
500
501 fn case(left: &Self, right: &Self) -> Result<Self, types::Error> {
502 Ok(Arc::new(Node {
503 cmr: Cmr::case(left.cmr(), right.cmr()),
504 data: N::CachedData::case(&left.data, &right.data)?,
505 inner: Inner::Case(Arc::clone(left), Arc::clone(right)),
506 }))
507 }
508
509 fn assertl(left: &Self, r_cmr: Cmr) -> Result<Self, types::Error> {
510 Ok(Arc::new(Node {
511 cmr: Cmr::case(left.cmr(), r_cmr),
512 data: N::CachedData::assertl(&left.data, r_cmr)?,
513 inner: Inner::AssertL(Arc::clone(left), r_cmr),
514 }))
515 }
516
517 fn assertr(l_cmr: Cmr, right: &Self) -> Result<Self, types::Error> {
518 Ok(Arc::new(Node {
519 cmr: Cmr::case(l_cmr, right.cmr()),
520 data: N::CachedData::assertr(l_cmr, &right.data)?,
521 inner: Inner::AssertR(l_cmr, Arc::clone(right)),
522 }))
523 }
524
525 fn pair(left: &Self, right: &Self) -> Result<Self, types::Error> {
526 Ok(Arc::new(Node {
527 cmr: Cmr::pair(left.cmr(), right.cmr()),
528 data: N::CachedData::pair(&left.data, &right.data)?,
529 inner: Inner::Pair(Arc::clone(left), Arc::clone(right)),
530 }))
531 }
532
533 fn fail(inference_context: &types::Context<'brand>, entropy: FailEntropy) -> Self {
534 Arc::new(Node {
535 cmr: Cmr::fail(entropy),
536 data: N::CachedData::fail(inference_context, entropy),
537 inner: Inner::Fail(entropy),
538 })
539 }
540
541 fn const_word(inference_context: &types::Context<'brand>, word: Word) -> Self {
542 Arc::new(Node {
543 cmr: Cmr::const_word(&word),
544 data: N::CachedData::const_word(inference_context, word.shallow_clone()),
545 inner: Inner::Word(word),
546 })
547 }
548
549 fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self {
550 Arc::new(Node {
551 cmr: Cmr::jet(jet),
552 data: N::CachedData::jet(inference_context, jet),
553 inner: Inner::Jet(jet.dyn_clone()),
554 })
555 }
556
557 fn arrow(&self) -> &types::Arrow<'brand> {
558 self.data.arrow()
559 }
560}
561
562impl<'brand, N> DisconnectConstructible<'brand, N::Disconnect> for Arc<Node<N>>
563where
564 N: Marker,
565 N::CachedData: DisconnectConstructible<'brand, N::Disconnect>,
566{
567 fn disconnect(left: &Self, right: &N::Disconnect) -> Result<Self, types::Error> {
568 Ok(Arc::new(Node {
569 cmr: Cmr::disconnect(left.cmr()),
570 data: N::CachedData::disconnect(&left.data, right)?,
571 inner: Inner::Disconnect(Arc::clone(left), right.clone()),
572 }))
573 }
574}
575
576impl<'brand, N> WitnessConstructible<'brand, N::Witness> for Arc<Node<N>>
577where
578 N: Marker,
579 N::CachedData: WitnessConstructible<'brand, N::Witness>,
580{
581 fn witness(inference_context: &types::Context<'brand>, value: N::Witness) -> Self {
582 Arc::new(Node {
583 cmr: Cmr::witness(),
584 data: N::CachedData::witness(inference_context, value.clone()),
585 inner: Inner::Witness(value),
586 })
587 }
588}
589
590impl<N: Marker> Node<N> {
591 pub fn inner(&self) -> &Inner<Arc<Node<N>>, N::Disconnect, N::Witness> {
593 &self.inner
594 }
595
596 pub fn cmr(&self) -> Cmr {
598 self.cmr
599 }
600
601 pub fn sharing_id(&self) -> Option<N::SharingId> {
603 N::compute_sharing_id(self.cmr, &self.data)
604 }
605
606 pub fn cached_data(&self) -> &N::CachedData {
608 &self.data
609 }
610
611 pub fn from_parts(
620 inner: Inner<Arc<Self>, N::Disconnect, N::Witness>,
621 data: N::CachedData,
622 ) -> Self {
623 let cmr = match &inner {
624 Inner::Unit => Cmr::unit(),
625 Inner::Iden => Cmr::iden(),
626 Inner::InjL(ref c) => Cmr::injl(c.cmr()),
627 Inner::InjR(ref c) => Cmr::injr(c.cmr()),
628 Inner::Take(ref c) => Cmr::take(c.cmr()),
629 Inner::Drop(ref c) => Cmr::drop(c.cmr()),
630 Inner::Comp(ref cl, ref cr) => Cmr::comp(cl.cmr(), cr.cmr()),
631 Inner::Case(ref cl, ref cr) => Cmr::case(cl.cmr(), cr.cmr()),
632 Inner::AssertL(ref c, cmr) => Cmr::case(c.cmr(), *cmr),
633 Inner::AssertR(cmr, ref c) => Cmr::case(*cmr, c.cmr()),
634 Inner::Pair(ref cl, ref cr) => Cmr::pair(cl.cmr(), cr.cmr()),
635 Inner::Disconnect(ref cl, _) => Cmr::disconnect(cl.cmr()),
636 Inner::Witness(_) => Cmr::witness(),
637 Inner::Fail(entropy) => Cmr::fail(*entropy),
638 Inner::Jet(j) => Cmr::jet(j.as_ref()),
639 Inner::Word(ref w) => Cmr::const_word(w),
640 };
641
642 Node { cmr, inner, data }
643 }
644
645 pub fn convert<S, M, C>(&self, converter: &mut C) -> Result<Arc<Node<M>>, C::Error>
653 where
654 S: for<'a> SharingTracker<&'a Self> + Default,
655 M: Marker,
656 C: Converter<N, M>,
657 {
658 let mut converted: Vec<Arc<Node<M>>> = vec![];
659 for data in self.post_order_iter::<S>() {
660 converter.visit_node(&data);
662
663 let indexed_inner: Inner<usize, &N::Disconnect, &N::Witness> = data
667 .node
668 .inner
669 .as_ref()
670 .map_left_right(|_| data.left_index.unwrap(), |_| data.right_index.unwrap());
671
672 let witness_inner: Inner<&usize, &&N::Disconnect, M::Witness> = indexed_inner
674 .as_ref()
675 .map_witness_result(|wit| converter.convert_witness(&data, wit))?;
676
677 let maybe_converted = data.right_index.map(|idx| &converted[idx]);
679 let witness_inner: Inner<&usize, M::Disconnect, M::Witness> = witness_inner
680 .map_disconnect_result(|disc| {
681 converter.convert_disconnect(&data, maybe_converted, disc)
682 })?;
683
684 let converted_inner: Inner<Arc<Node<M>>, M::Disconnect, M::Witness> =
687 witness_inner.map(|idx| Arc::clone(&converted[*idx]));
688
689 let pruned_inner = if let Inner::Case(left, right) = converted_inner {
691 let hide = converter.prune_case(&data, &left, &right)?;
692
693 match hide {
694 Hide::Neither => Inner::Case(left, right),
695 Hide::Left => Inner::AssertR(left.cmr(), right),
696 Hide::Right => Inner::AssertL(left, right.cmr()),
697 }
698 } else {
699 converted_inner
700 };
701
702 converted.push(Arc::new(Node {
704 data: converter.convert_data(&data, pruned_inner.as_ref())?,
705 cmr: data.node.cmr,
706 inner: pruned_inner,
707 }));
708 }
709 Ok(converted.pop().unwrap())
710 }
711
712 pub fn display(&self) -> Display<'_, N> {
713 Display::from(self)
714 }
715
716 pub fn display_expr(&self) -> DisplayExpr<'_, N> {
721 DisplayExpr::from(self)
722 }
723
724 pub fn display_as_graph(
735 &self,
736 format: GraphFormat,
737 sharing_level: SharingLevel,
738 ) -> DisplayAsGraph<'_, N> {
739 DisplayAsGraph::new(self, format, sharing_level)
740 }
741
742 pub fn display_as_dot(&self) -> DisplayAsGraph<'_, N> {
747 DisplayAsGraph::new(self, GraphFormat::Dot, SharingLevel::None)
748 }
749
750 pub fn display_as_mermaid(&self) -> DisplayAsGraph<'_, N> {
755 DisplayAsGraph::new(self, GraphFormat::Mermaid, SharingLevel::None)
756 }
757
758 pub fn encode_without_witness(&self, prog: &mut dyn io::Write) -> io::Result<usize> {
760 let mut w = BitWriter::new(prog);
761 let program_bits = encode::encode_program(self, &mut w)?;
762 w.flush_all()?;
763 Ok(program_bits)
764 }
765
766 pub fn to_vec_without_witness(&self) -> Vec<u8> {
768 let mut program = Vec::<u8>::new();
769 self.encode_without_witness(&mut program)
770 .expect("Vec::write is infallible");
771 debug_assert!(!program.is_empty());
772 program
773 }
774}
775
776impl<N: Marker<Witness = Value>> Node<N> {
777 pub fn encode_with_witness(
781 &self,
782 prog: &mut dyn io::Write,
783 witness: &mut dyn io::Write,
784 ) -> io::Result<(usize, usize)> {
785 let mut prog = BitWriter::new(prog);
786 let mut witness = BitWriter::new(witness);
787
788 let sharing_iter = self.post_order_iter::<MaxSharing<N>>();
789 let program_bits = encode::encode_program(self, &mut prog)?;
790 prog.flush_all()?;
791 let witness_bits = encode::encode_witness(sharing_iter.into_witnesses(), &mut witness)?;
792 witness.flush_all()?;
793 Ok((program_bits, witness_bits))
794 }
795
796 pub fn to_vec_with_witness(&self) -> (Vec<u8>, Vec<u8>) {
798 let mut ret_1 = vec![];
799 let mut ret_2 = vec![];
800 self.encode_with_witness(&mut ret_1, &mut ret_2)
801 .expect("Vec::write is infallible");
802 (ret_1, ret_2)
803 }
804}
805
806impl<N: Marker> Drop for Node<N> {
807 fn drop(&mut self) {
808 fn push_children<N: Marker>(
810 stack: &mut Vec<Arc<Node<N>>>,
811 inner: Inner<Arc<Node<N>>, N::Disconnect, N::Witness>,
812 ) {
813 use crate::dag::Dag;
814 match inner.into_dag() {
815 Dag::Nullary => {}
816 Dag::Unary(child) => stack.push(child),
817 Dag::Binary(left, right) => {
818 stack.push(left);
819 stack.push(right);
820 }
821 }
822 }
823
824 let mut stack = Vec::new();
825 push_children(&mut stack, std::mem::replace(&mut self.inner, Inner::Unit));
826 while let Some(child) = stack.pop() {
827 if let Some(mut child) = Arc::into_inner(child) {
828 push_children(&mut stack, std::mem::replace(&mut child.inner, Inner::Unit));
829 }
830 }
831 }
832}
833
834#[cfg(test)]
835#[cfg(all(feature = "test-utils", feature = "elements"))]
836mod tests {
837 use ffi::tests::TestData;
838
839 use crate::analysis::Cost;
840 use crate::ffi;
841 use crate::jet::Elements;
842 use crate::BitIter;
843 use crate::RedeemNode;
844
845 fn check_merkle_roots(test: &TestData) {
846 let prog = BitIter::from(test.prog.as_slice());
847 let witness = BitIter::from(test.witness.as_slice());
848 ffi::tests::run_program(
849 &test.prog,
850 &test.witness,
851 ffi::tests::TestUpTo::CheckOneOne,
852 None,
853 None,
854 )
855 .unwrap();
856 let prog = RedeemNode::decode::<_, _, Elements>(prog, witness).unwrap();
857 assert_eq!(prog.cmr().to_byte_array(), test.cmr);
858 assert_eq!(prog.amr().to_byte_array(), test.amr);
859 assert_eq!(prog.ihr().to_byte_array(), test.ihr);
860 assert_eq!(prog.bounds().cost, Cost::from_milliweight(test.cost))
861 }
862
863 #[test]
864 fn progs_cmr() {
865 let schnorr0 = ffi::tests::schnorr0_test_data();
866 let schnorr6 = ffi::tests::schnorr6_test_data();
867 let ctx8_unpruned = ffi::tests::ctx8_unpruned_test_data();
868 let ctx8_pruned = ffi::tests::ctx8_pruned_test_data();
869 check_merkle_roots(&schnorr0);
871 check_merkle_roots(&schnorr6);
872 check_merkle_roots(&ctx8_unpruned);
873 check_merkle_roots(&ctx8_pruned);
874 }
875}