1use crate::dag::{DagLike, MaxSharing, NoSharing, PostOrderIterItem};
4use crate::jet::Jet;
5use crate::types::{Arrow, FinalArrow};
6use crate::{encode, types, Value};
7use crate::{Amr, BitIter, BitWriter, Cmr, DecodeError, Ihr, Imr};
8
9use super::{
10 Construct, ConstructData, ConstructNode, Converter, Inner, Marker, NoDisconnect, NoWitness,
11 Node, Redeem, RedeemNode,
12};
13
14use std::io;
15use std::sync::Arc;
16
17#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
18pub struct Commit {
19 never: std::convert::Infallible,
21}
22
23impl Marker for Commit {
24 type CachedData = Arc<CommitData>;
25 type Witness = NoWitness;
26 type Disconnect = NoDisconnect;
27 type SharingId = Ihr;
28
29 fn compute_sharing_id(_: Cmr, cached_data: &Arc<CommitData>) -> Option<Ihr> {
30 cached_data.ihr
31 }
32}
33
34#[derive(Clone, Debug, PartialEq, Eq, Hash)]
35pub struct CommitData {
36 arrow: FinalArrow,
38 imr: Option<Imr>,
41 amr: Option<Amr>,
44 ihr: Option<Ihr>,
47}
48
49impl CommitData {
50 pub fn arrow(&self) -> &FinalArrow {
52 &self.arrow
53 }
54
55 pub fn ihr(&self) -> Option<Ihr> {
57 self.ihr
58 }
59
60 fn incomplete_amr(
62 inner: Inner<&Arc<Self>, &NoDisconnect, &NoWitness>,
63 arrow: &FinalArrow,
64 ) -> Option<Amr> {
65 match inner {
66 Inner::Iden => Some(Amr::iden(arrow)),
67 Inner::Unit => Some(Amr::unit(arrow)),
68 Inner::InjL(child) => child.amr.map(|amr| Amr::injl(arrow, amr)),
69 Inner::InjR(child) => child.amr.map(|amr| Amr::injr(arrow, amr)),
70 Inner::Take(child) => child.amr.map(|amr| Amr::take(arrow, amr)),
71 Inner::Drop(child) => child.amr.map(|amr| Amr::drop(arrow, amr)),
72 Inner::Comp(left, right) => left
73 .amr
74 .zip(right.amr)
75 .map(|(a, b)| Amr::comp(arrow, &left.arrow, a, b)),
76 Inner::Case(left, right) => {
77 left.amr.zip(right.amr).map(|(a, b)| Amr::case(arrow, a, b))
78 }
79 Inner::AssertL(left, r_cmr) => left
80 .amr
81 .map(|l_amr| Amr::assertl(arrow, l_amr, r_cmr.into())),
82 Inner::AssertR(l_cmr, right) => right
83 .amr
84 .map(|r_amr| Amr::assertr(arrow, l_cmr.into(), r_amr)),
85 Inner::Pair(left, right) => left
86 .amr
87 .zip(right.amr)
88 .map(|(a, b)| Amr::pair(arrow, &left.arrow, &right.arrow, a, b)),
89 Inner::Disconnect(..) => None,
90 Inner::Witness(..) => None,
91 Inner::Fail(entropy) => Some(Amr::fail(entropy)),
92 Inner::Jet(jet) => Some(Amr::jet(jet.as_ref())),
93 Inner::Word(ref val) => Some(Amr::const_word(val)),
94 }
95 }
96
97 fn imr(inner: Inner<&Arc<Self>, &NoDisconnect, &NoWitness>) -> Option<Imr> {
99 match inner {
100 Inner::Iden => Some(Imr::iden()),
101 Inner::Unit => Some(Imr::unit()),
102 Inner::InjL(child) => child.imr.map(Imr::injl),
103 Inner::InjR(child) => child.imr.map(Imr::injr),
104 Inner::Take(child) => child.imr.map(Imr::take),
105 Inner::Drop(child) => child.imr.map(Imr::drop),
106 Inner::Comp(left, right) => left.imr.zip(right.imr).map(|(a, b)| Imr::comp(a, b)),
107 Inner::Case(left, right) => left.imr.zip(right.imr).map(|(a, b)| Imr::case(a, b)),
108 Inner::AssertL(left, r_cmr) => left.imr.map(|l_ihr| Imr::case(l_ihr, r_cmr.into())),
109 Inner::AssertR(l_cmr, right) => right.imr.map(|r_ihr| Imr::case(l_cmr.into(), r_ihr)),
110 Inner::Pair(left, right) => left.imr.zip(right.imr).map(|(a, b)| Imr::pair(a, b)),
111 Inner::Disconnect(..) => None,
112 Inner::Witness(..) => None,
113 Inner::Fail(entropy) => Some(Imr::fail(entropy)),
114 Inner::Jet(jet) => Some(Imr::jet(jet.as_ref())),
115 Inner::Word(ref val) => Some(Imr::const_word(val)),
116 }
117 }
118
119 pub fn new(
120 arrow: &Arrow,
121 inner: Inner<&Arc<Self>, &NoDisconnect, &NoWitness>,
122 ) -> Result<Self, types::Error> {
123 let final_arrow = arrow.finalize()?;
124 let imr = Self::imr(inner.clone());
125 let amr = Self::incomplete_amr(inner, &final_arrow);
126 Ok(CommitData {
127 imr,
128 amr,
129 ihr: imr.map(|ihr| Ihr::from_imr(ihr, &final_arrow)),
130 arrow: final_arrow,
131 })
132 }
133
134 pub fn from_final(
135 arrow: FinalArrow,
136 inner: Inner<&Arc<Self>, &NoDisconnect, &NoWitness>,
137 ) -> Self {
138 let imr = Self::imr(inner.clone());
139 let amr = Self::incomplete_amr(inner, &arrow);
140 CommitData {
141 imr,
142 amr,
143 ihr: imr.map(|ihr| Ihr::from_imr(ihr, &arrow)),
144 arrow,
145 }
146 }
147}
148
149pub type CommitNode = Node<Commit>;
150
151impl CommitNode {
152 pub fn arrow(&self) -> &FinalArrow {
154 &self.data.arrow
155 }
156
157 pub fn amr(&self) -> Option<Amr> {
159 self.data.amr
160 }
161
162 pub fn ihr(&self) -> Option<Ihr> {
164 self.data.ihr
165 }
166
167 pub fn finalize<C: Converter<Commit, Redeem>>(
173 &self,
174 converter: &mut C,
175 ) -> Result<Arc<RedeemNode>, C::Error> {
176 self.convert::<NoSharing, Redeem, _>(converter)
177 }
178
179 pub fn unfinalize_types<'brand>(
181 &self,
182 inference_context: &types::Context<'brand>,
183 ) -> Result<Arc<ConstructNode<'brand>>, types::Error> {
184 struct UnfinalizeTypes<'a, 'brand> {
185 inference_context: &'a types::Context<'brand>,
186 }
187
188 impl<'brand> Converter<Commit, Construct<'brand>> for UnfinalizeTypes<'_, 'brand> {
189 type Error = types::Error;
190 fn convert_witness(
191 &mut self,
192 _: &PostOrderIterItem<&CommitNode>,
193 _: &NoWitness,
194 ) -> Result<Option<Value>, Self::Error> {
195 Ok(None)
196 }
197
198 fn convert_disconnect(
199 &mut self,
200 _: &PostOrderIterItem<&CommitNode>,
201 _: Option<&Arc<ConstructNode<'brand>>>,
202 _: &NoDisconnect,
203 ) -> Result<Option<Arc<ConstructNode<'brand>>>, Self::Error> {
204 Ok(None)
205 }
206
207 fn convert_data(
208 &mut self,
209 _: &PostOrderIterItem<&CommitNode>,
210 inner: Inner<
211 &Arc<ConstructNode<'brand>>,
212 &Option<Arc<ConstructNode<'brand>>>,
213 &Option<Value>,
214 >,
215 ) -> Result<ConstructData<'brand>, Self::Error> {
216 use crate::node::DisconnectConstructible as _;
217
218 let new_arrow = match inner {
219 Inner::Iden => Arrow::iden(self.inference_context),
220 Inner::Unit => Arrow::unit(self.inference_context),
221 Inner::InjL(child) => Arrow::injl(child.arrow()),
222 Inner::InjR(child) => Arrow::injr(child.arrow()),
223 Inner::Take(child) => Arrow::take(child.arrow()),
224 Inner::Drop(child) => Arrow::drop_(child.arrow()),
225 Inner::Comp(lft, rgt) => Arrow::comp(lft.arrow(), rgt.arrow())?,
226 Inner::Case(lft, rgt) => Arrow::case(lft.arrow(), rgt.arrow())?,
227 Inner::Pair(lft, rgt) => Arrow::pair(lft.arrow(), rgt.arrow())?,
228 Inner::Disconnect(lft, rgt) => {
229 Arrow::disconnect(lft.arrow(), &rgt.as_ref().map(|node| node.arrow()))?
230 }
231 Inner::AssertL(lft, _) => Arrow::assertl(lft.arrow())?,
232 Inner::AssertR(_, rgt) => Arrow::assertr(rgt.arrow())?,
233 Inner::Witness(_) => Arrow::witness(self.inference_context),
234 Inner::Fail(_) => Arrow::fail(self.inference_context),
235 Inner::Jet(ref jet) => Arrow::jet(self.inference_context, jet.as_ref()),
236 Inner::Word(ref word) => Arrow::const_word(self.inference_context, word),
237 };
238
239 Ok(ConstructData::new(new_arrow))
240 }
241 }
242
243 self.convert::<MaxSharing<Commit>, _, _>(&mut UnfinalizeTypes { inference_context })
244 }
245
246 pub fn decode<I: Iterator<Item = u8>, J: Jet>(
256 bits: BitIter<I>,
257 ) -> Result<Arc<Self>, DecodeError> {
258 use crate::decode;
259
260 let program = types::Context::with_context(|ctx| {
262 let construct =
263 crate::ConstructNode::decode::<I, J>(&ctx, bits).map_err(DecodeError::Decode)?;
264 construct.finalize_types().map_err(DecodeError::Type)
265 })?;
266 if program.as_ref().is_shared_as::<MaxSharing<Commit>>() {
268 Ok(program)
269 } else {
270 Err(DecodeError::Decode(decode::Error::SharingNotMaximal))
271 }
272 }
273
274 #[cfg(feature = "base64")]
275 #[allow(clippy::should_implement_trait)] pub fn from_str(s: &str) -> Result<Arc<Self>, crate::ParseError> {
277 use crate::base64::engine::general_purpose;
278 use crate::base64::Engine as _;
279
280 let v = general_purpose::STANDARD
281 .decode(s)
282 .map_err(crate::ParseError::Base64)?;
283 let iter = crate::BitIter::new(v.into_iter());
284 Self::decode::<_, crate::jet::Core>(iter).map_err(crate::ParseError::Decode)
285 }
286
287 #[deprecated(since = "0.5.0", note = "use Self::encode_without_witness instead")]
289 pub fn encode(&self, w: &mut BitWriter<&mut dyn io::Write>) -> io::Result<usize> {
290 let program_bits = encode::encode_program(self, w)?;
291 w.flush_all()?;
292 Ok(program_bits)
293 }
294
295 #[deprecated(since = "0.5.0", note = "use Self::to_vec_without_witness instead")]
297 pub fn encode_to_vec(&self) -> Vec<u8> {
298 let mut program = Vec::<u8>::new();
299 self.encode_without_witness(&mut program)
300 .expect("write to vector never fails");
301 debug_assert!(!program.is_empty());
302
303 program
304 }
305}
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310
311 use hex::DisplayHex;
312 use std::fmt;
313
314 use crate::{decode::Error, jet::Core};
315 #[cfg(feature = "human_encoding")]
316 use crate::{human_encoding::Forest, jet::CoreEnv, node::SimpleFinalizer, BitMachine, Value};
317
318 #[cfg(feature = "human_encoding")]
319 #[cfg_attr(not(feature = "base64"), allow(unused_variables))]
320 #[track_caller]
321 fn assert_program_deserializable<J: Jet>(
322 prog_str: &str,
323 prog_bytes: &[u8],
324 cmr_str: &str,
325 b64_str: &str,
326 ) -> Arc<CommitNode> {
327 let forest = match Forest::parse::<J>(prog_str) {
328 Ok(forest) => forest,
329 Err(e) => panic!("Failed to parse program `{}`: {}", prog_str, e),
330 };
331 assert_eq!(
332 forest.roots().len(),
333 1,
334 "program `{}` has multiple roots",
335 prog_str
336 );
337 let main = match forest.roots().get("main") {
338 Some(root) => root,
339 None => panic!("Program `{}` has no main", prog_str),
340 };
341
342 let prog_hex = prog_bytes.as_hex();
343 let main_bytes = main.to_vec_without_witness();
344 assert_eq!(
345 prog_bytes,
346 main_bytes,
347 "Program string `{}` encoded to {} (expected {})",
348 prog_str,
349 main_bytes.as_hex(),
350 prog_hex,
351 );
352
353 let iter = BitIter::from(prog_bytes);
354 let prog = match CommitNode::decode::<_, J>(iter) {
355 Ok(prog) => prog,
356 Err(e) => panic!("program {} failed: {}", prog_hex, e),
357 };
358
359 assert_eq!(
360 prog.cmr().to_string(),
361 cmr_str,
362 "CMR mismatch (got {} expected {}) for program {}",
363 prog.cmr(),
364 cmr_str,
365 prog_hex,
366 );
367
368 let reser_sink = prog.to_vec_without_witness();
369 assert_eq!(
370 prog_bytes,
371 &reser_sink[..],
372 "program {} reserialized as {}",
373 prog_hex,
374 reser_sink.as_hex(),
375 );
376
377 #[cfg(feature = "base64")]
378 {
379 assert_eq!(prog.to_string(), b64_str);
380 assert_eq!(prog.display().program().to_string(), b64_str);
381 assert_eq!(prog, CommitNode::from_str(b64_str).unwrap());
382 }
383
384 prog
385 }
386
387 #[track_caller]
388 fn assert_program_not_deserializable<J: Jet>(prog: &[u8], err: &dyn fmt::Display) {
389 let prog_hex = prog.as_hex();
390 let err_str = err.to_string();
391
392 let iter = BitIter::from(prog);
393 match CommitNode::decode::<_, J>(iter) {
394 Ok(prog) => panic!(
395 "Program {} succeded (expected error {}). Program parsed as:\n{:?}",
396 prog_hex, err, prog
397 ),
398 Err(e) if e.to_string() == err_str => {} Err(e) => panic!(
400 "Program {} failed with error {} (expected error {})",
401 prog_hex, e, err
402 ),
403 };
404 }
405
406 #[test]
407 fn canonical_order() {
408 assert_program_not_deserializable::<Core>(&[0xa8, 0x48, 0x10], &Error::NotInCanonicalOrder);
412
413 assert_program_not_deserializable::<Core>(
415 &[0xc1, 0x00, 0x06, 0x20],
416 &Error::NotInCanonicalOrder,
417 );
418 }
419
420 #[test]
421 fn hidden_node() {
422 #[rustfmt::skip]
424 let hidden = [
425 0x36, 0xf5, 0x6d, 0xf7, 0x7e, 0xf5, 0x6d, 0xf7,
426 0x7e, 0xf5, 0x6d, 0xf7, 0x7e, 0xf5, 0x6d, 0xf7,
427 0x7e, 0xf5, 0x6d, 0xf7, 0x7e, 0xf5, 0x6d, 0xf7,
428 0x7e, 0xf5, 0x6d, 0xf7, 0x7e, 0xf5, 0x6d, 0xf7,
429 78,
430 ];
431 assert_program_not_deserializable::<Core>(&hidden, &Error::HiddenNode);
432
433 let hidden = [
435 0xae, 0xdb, 0xd5, 0xb7, 0xdd, 0xfb, 0xd5, 0xb7, 0xdd, 0xfb, 0xd5, 0xb7, 0xdd, 0xfb,
436 0xd5, 0xb7, 0xdd, 0xfb, 0xd5, 0xb7, 0xdd, 0xfb, 0xd5, 0xb7, 0xdd, 0xfb, 0xd5, 0xb7,
437 0xdd, 0xfb, 0xd5, 0xb7, 0xdd, 0xe0, 0x80,
438 ];
439 assert_program_not_deserializable::<Core>(&hidden, &Error::HiddenNode);
440 }
441
442 #[test]
443 fn case_both_children_hidden() {
444 #[rustfmt::skip]
447 let hidden = [
448 0x8d, 0xbd, 0x5b, 0x7d, 0xdf, 0xbd, 0x5b, 0x7d,
449 0xdf, 0xbd, 0x5b, 0x7d, 0xdf, 0xbd, 0x5b, 0x7d,
450 0xdf, 0xbd, 0x5b, 0x7d, 0xdf, 0xbd, 0x5b, 0x7d,
451 0xdf, 0xbd, 0x5b, 0x7d, 0xdf, 0xbd, 0x5b, 0x7d,
452 0xde, 0x10,
453 ];
454 assert_program_not_deserializable::<Core>(&hidden, &Error::BothChildrenHidden);
455 }
456
457 #[test]
458 fn unshared_hidden() {
459 #[rustfmt::skip]
462 let hidden = [
463 0xd6, 0xe9, 0x62, 0x56, 0x62, 0xc9, 0x38, 0x8a,
464 0x44, 0x31, 0x85, 0xee, 0xc2, 0x2b, 0x91, 0x48,
465 0x87, 0xe1, 0xfd, 0x18, 0x57, 0xc2, 0x8c, 0x4a,
466 0x28, 0x44, 0x2f, 0xa8, 0x61, 0x5c, 0xa7, 0x6e,
467 0x8c, 0xf9, 0x80, 0xc2, 0x18, 0x95, 0x98, 0xb2,
468 0x4e, 0x22, 0x91, 0x0c, 0x61, 0x7b, 0xb0, 0x8a,
469 0xe4, 0x52, 0x21, 0xf8, 0x7f, 0x46, 0x15, 0xf0,
470 0xa3, 0x12, 0x8a, 0x11, 0x0b, 0xea, 0x18, 0x57,
471 0x29, 0xdb, 0xa3, 0x3e, 0x60, 0x30, 0x2c, 0x00,
472 0xd0, 0x48, 0x20,
473 ];
474 assert_program_not_deserializable::<Core>(&hidden, &Error::SharingNotMaximal);
475 }
476
477 #[test]
478 #[cfg(feature = "human_encoding")]
479 fn shared_witnesses() {
480 assert_program_deserializable::<Core>(
481 "main := witness",
482 &[0x38],
483 "a0fc8debd6796917c86b77aded82e6c61649889ae8f2ed65b57b41aa9d90e375",
484 "OA==",
485 );
486
487 #[rustfmt::skip]
488 let bad_diff1s = vec![
489 vec![
492 0xda, 0xe2, 0x39, 0xa3, 0x10, 0x42, 0x0e, 0x05,
493 0x71, 0x88, 0xa3, 0x6d, 0xc4, 0x11, 0x80, 0x80
494 ],
495 vec![
499 0xde, 0x87, 0x04, 0x08, 0xe6, 0x8c, 0x41, 0x08,
500 0x38, 0x15, 0xc6, 0x22, 0x8d, 0xb7, 0x10, 0x46,
501 0x02, 0x00,
502 ],
503 ];
504 for bad_diff1 in bad_diff1s {
505 assert_program_not_deserializable::<Core>(&bad_diff1, &Error::SharingNotMaximal);
506 }
507
508 #[rustfmt::skip]
509 let diff1s = vec![
510 (
511 "
513 -- Program which demands two 32-bit witnesses, the first one == the second + 1
514 wit1 := witness : 1 -> 2^32
515 wit2 := witness : 1 -> 2^32
516
517 wit_diff := comp (comp (pair wit1 wit2) jet_subtract_32) (drop iden) : 1 -> 2^32
518 diff_is_one := comp (pair wit_diff jet_one_32) jet_eq_32 : 1 -> 2
519 main := comp diff_is_one jet_verify : 1 -> 1
520 ",
521 vec![
522 0xdc, 0xee, 0x28, 0xe6, 0x8c, 0x41, 0x08, 0x38,
523 0x15, 0xc6, 0x22, 0x8d, 0xb7, 0x10, 0x46, 0x02,
524 0x00,
525 ],
526 "e7661630013b789c535146485c72001cad7eea92d04bc4135dc9c2d9e48093b7",
528 "3O4o5oxBCDgVxiKNtxBGAgA=",
529 ),
530 (
532 "
533 -- Program which demands two 32-bit witnesses, the first one == the second + 1
534 wit1 := witness : 1 -> 2^32
535 wit2 := witness : 1 -> 2^32
536 compwit1 := comp iden wit1
537 compwit2 := comp iden wit2
538
539 wit_diff := comp (comp (pair compwit1 compwit2) jet_subtract_32) (drop iden)
540 diff_is_one := comp (pair wit_diff jet_one_32) jet_eq_32 : 1 -> 2
541 main := comp diff_is_one jet_verify : 1 -> 1
542 ",
543 vec![
544 0xe0, 0x28, 0x70, 0x43, 0x83, 0x00, 0xab, 0x9a,
545 0x31, 0x04, 0x20, 0xe0, 0x57, 0x18, 0x8a, 0x36,
546 0xdc, 0x41, 0x18, 0x08,
547 ],
548 "774105cb723e00ab3ac48452aa2dd3744999605393f0343eedc8c6387aa5b3c8",
550 "4ChwQ4MAq5oxBCDgVxiKNtxBGAg=",
551 )
552 ];
553
554 for (prog_str, diff1, cmr, b64) in diff1s {
555 let diff1_prog = crate::node::commit::tests::assert_program_deserializable::<Core>(
556 prog_str, &diff1, cmr, b64,
557 );
558
559 let mut counter = 0..100;
562 let witness_iter = (&mut counter).rev().map(Value::u32);
563 let diff1_final = diff1_prog
564 .finalize(&mut SimpleFinalizer::new(witness_iter))
565 .unwrap();
566 assert_eq!(counter, 0..98);
567
568 let mut mac =
570 BitMachine::for_program(&diff1_final).expect("program has reasonable bounds");
571 mac.exec(&diff1_final, &CoreEnv::new()).unwrap();
572 }
573 }
574
575 #[test]
576 fn extra_nodes() {
577 assert_program_not_deserializable::<Core>(&[0xa9, 0x48, 0x00], &Error::NotInCanonicalOrder);
580 }
581
582 #[test]
583 #[cfg(feature = "human_encoding")]
584 fn regression_177() {
585 let bad_prog = "
593 id := iden
594 main := case (drop id) id
595 ";
596 match Forest::parse::<Core>(bad_prog) {
597 Ok(_) => panic!("program should have failed"),
598 Err(set) => {
599 let mut errs_happened = (false, false);
600 for err in set.iter() {
601 match err {
602 crate::human_encoding::Error::TypeCheck(e @ types::Error::Bind { .. }) => {
603 errs_happened.0 = true;
604 e.to_string();
605 }
606 crate::human_encoding::Error::TypeCheck(
607 e @ types::Error::OccursCheck { .. },
608 ) => {
609 errs_happened.1 = true;
610 e.to_string();
611 }
612 x => panic!("unexpected error {x:?}"),
613 }
614 }
615 assert_eq!(errs_happened, (true, true));
616 }
617 };
618 }
619}