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