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(&self) -> Result<Arc<ConstructNode<J>>, types::Error> {
191 struct UnfinalizeTypes<J: Jet> {
192 inference_context: types::Context,
193 phantom: PhantomData<J>,
194 }
195
196 impl<J: Jet> Converter<Commit<J>, Construct<J>> for UnfinalizeTypes<J> {
197 type Error = types::Error;
198 fn convert_witness(
199 &mut self,
200 _: &PostOrderIterItem<&CommitNode<J>>,
201 _: &NoWitness,
202 ) -> Result<Option<Value>, Self::Error> {
203 Ok(None)
204 }
205
206 fn convert_disconnect(
207 &mut self,
208 _: &PostOrderIterItem<&CommitNode<J>>,
209 _: Option<&Arc<ConstructNode<J>>>,
210 _: &NoDisconnect,
211 ) -> Result<Option<Arc<ConstructNode<J>>>, Self::Error> {
212 Ok(None)
213 }
214
215 fn convert_data(
216 &mut self,
217 _: &PostOrderIterItem<&CommitNode<J>>,
218 inner: Inner<
219 &Arc<ConstructNode<J>>,
220 J,
221 &Option<Arc<ConstructNode<J>>>,
222 &Option<Value>,
223 >,
224 ) -> Result<ConstructData<J>, Self::Error> {
225 let inner = inner
226 .map(|node| node.arrow())
227 .map_disconnect(|maybe_node| maybe_node.as_ref().map(|node| node.arrow()));
228 let inner = inner.disconnect_as_ref(); Ok(ConstructData::new(Arrow::from_inner(
230 &self.inference_context,
231 inner,
232 )?))
233 }
234 }
235
236 self.convert::<MaxSharing<Commit<J>>, _, _>(&mut UnfinalizeTypes {
237 inference_context: types::Context::new(),
238 phantom: PhantomData,
239 })
240 }
241
242 pub fn decode<I: Iterator<Item = u8>>(bits: BitIter<I>) -> Result<Arc<Self>, DecodeError> {
252 use crate::decode;
253
254 let construct = crate::ConstructNode::decode(bits).map_err(DecodeError::Decode)?;
256 let program = construct.finalize_types().map_err(DecodeError::Type)?;
257 if program.as_ref().is_shared_as::<MaxSharing<Commit<J>>>() {
259 Ok(program)
260 } else {
261 Err(DecodeError::Decode(decode::Error::SharingNotMaximal))
262 }
263 }
264
265 #[cfg(feature = "base64")]
266 #[allow(clippy::should_implement_trait)] pub fn from_str(s: &str) -> Result<Arc<Self>, crate::ParseError> {
268 use crate::base64::engine::general_purpose;
269 use crate::base64::Engine as _;
270
271 let v = general_purpose::STANDARD
272 .decode(s)
273 .map_err(crate::ParseError::Base64)?;
274 let iter = crate::BitIter::new(v.into_iter());
275 Self::decode(iter).map_err(crate::ParseError::Decode)
276 }
277
278 #[deprecated(since = "0.5.0", note = "use Self::encode_without_witness instead")]
280 pub fn encode<W: io::Write>(&self, w: &mut BitWriter<W>) -> io::Result<usize> {
281 let program_bits = encode::encode_program(self, w)?;
282 w.flush_all()?;
283 Ok(program_bits)
284 }
285
286 #[deprecated(since = "0.5.0", note = "use Self::to_vec_without_witness instead")]
288 pub fn encode_to_vec(&self) -> Vec<u8> {
289 let mut program = Vec::<u8>::new();
290 self.encode_without_witness(&mut program)
291 .expect("write to vector never fails");
292 debug_assert!(!program.is_empty());
293
294 program
295 }
296}
297
298#[cfg(test)]
299mod tests {
300 use super::*;
301
302 use hex::DisplayHex;
303 use std::fmt;
304
305 use crate::decode::Error;
306 use crate::human_encoding::Forest;
307 use crate::jet::Core;
308 use crate::node::SimpleFinalizer;
309 use crate::{BitMachine, Value};
310
311 #[cfg_attr(not(feature = "base64"), allow(unused_variables))]
312 #[track_caller]
313 fn assert_program_deserializable<J: Jet>(
314 prog_str: &str,
315 prog_bytes: &[u8],
316 cmr_str: &str,
317 b64_str: &str,
318 ) -> Arc<CommitNode<J>> {
319 let forest = match Forest::<J>::parse(prog_str) {
320 Ok(forest) => forest,
321 Err(e) => panic!("Failed to parse program `{}`: {}", prog_str, e),
322 };
323 assert_eq!(
324 forest.roots().len(),
325 1,
326 "program `{}` has multiple roots",
327 prog_str
328 );
329 let main = match forest.roots().get("main") {
330 Some(root) => root,
331 None => panic!("Program `{}` has no main", prog_str),
332 };
333
334 let prog_hex = prog_bytes.as_hex();
335 let main_bytes = main.to_vec_without_witness();
336 assert_eq!(
337 prog_bytes,
338 main_bytes,
339 "Program string `{}` encoded to {} (expected {})",
340 prog_str,
341 main_bytes.as_hex(),
342 prog_hex,
343 );
344
345 let iter = BitIter::from(prog_bytes);
346 let prog = match CommitNode::<J>::decode(iter) {
347 Ok(prog) => prog,
348 Err(e) => panic!("program {} failed: {}", prog_hex, e),
349 };
350
351 assert_eq!(
352 prog.cmr().to_string(),
353 cmr_str,
354 "CMR mismatch (got {} expected {}) for program {}",
355 prog.cmr(),
356 cmr_str,
357 prog_hex,
358 );
359
360 let reser_sink = prog.to_vec_without_witness();
361 assert_eq!(
362 prog_bytes,
363 &reser_sink[..],
364 "program {} reserialized as {}",
365 prog_hex,
366 reser_sink.as_hex(),
367 );
368
369 #[cfg(feature = "base64")]
370 {
371 assert_eq!(prog.to_string(), b64_str);
372 assert_eq!(prog.display().program().to_string(), b64_str);
373 assert_eq!(prog, CommitNode::from_str(b64_str).unwrap());
374 }
375
376 prog
377 }
378
379 #[track_caller]
380 fn assert_program_not_deserializable<J: Jet>(prog: &[u8], err: &dyn fmt::Display) {
381 let prog_hex = prog.as_hex();
382 let err_str = err.to_string();
383
384 let iter = BitIter::from(prog);
385 match CommitNode::<J>::decode(iter) {
386 Ok(prog) => panic!(
387 "Program {} succeded (expected error {}). Program parsed as:\n{:?}",
388 prog_hex, err, prog
389 ),
390 Err(e) if e.to_string() == err_str => {} Err(e) => panic!(
392 "Program {} failed with error {} (expected error {})",
393 prog_hex, e, err
394 ),
395 };
396 }
397
398 #[test]
399 fn canonical_order() {
400 assert_program_not_deserializable::<Core>(&[0xa8, 0x48, 0x10], &Error::NotInCanonicalOrder);
404
405 assert_program_not_deserializable::<Core>(
407 &[0xc1, 0x00, 0x06, 0x20],
408 &Error::NotInCanonicalOrder,
409 );
410 }
411
412 #[test]
413 fn hidden_node() {
414 #[rustfmt::skip]
416 let hidden = [
417 0x36, 0xf5, 0x6d, 0xf7, 0x7e, 0xf5, 0x6d, 0xf7,
418 0x7e, 0xf5, 0x6d, 0xf7, 0x7e, 0xf5, 0x6d, 0xf7,
419 0x7e, 0xf5, 0x6d, 0xf7, 0x7e, 0xf5, 0x6d, 0xf7,
420 0x7e, 0xf5, 0x6d, 0xf7, 0x7e, 0xf5, 0x6d, 0xf7,
421 78,
422 ];
423 assert_program_not_deserializable::<Core>(&hidden, &Error::HiddenNode);
424
425 let hidden = [
427 0xae, 0xdb, 0xd5, 0xb7, 0xdd, 0xfb, 0xd5, 0xb7, 0xdd, 0xfb, 0xd5, 0xb7, 0xdd, 0xfb,
428 0xd5, 0xb7, 0xdd, 0xfb, 0xd5, 0xb7, 0xdd, 0xfb, 0xd5, 0xb7, 0xdd, 0xfb, 0xd5, 0xb7,
429 0xdd, 0xfb, 0xd5, 0xb7, 0xdd, 0xe0, 0x80,
430 ];
431 assert_program_not_deserializable::<Core>(&hidden, &Error::HiddenNode);
432 }
433
434 #[test]
435 fn case_both_children_hidden() {
436 #[rustfmt::skip]
439 let hidden = [
440 0x8d, 0xbd, 0x5b, 0x7d, 0xdf, 0xbd, 0x5b, 0x7d,
441 0xdf, 0xbd, 0x5b, 0x7d, 0xdf, 0xbd, 0x5b, 0x7d,
442 0xdf, 0xbd, 0x5b, 0x7d, 0xdf, 0xbd, 0x5b, 0x7d,
443 0xdf, 0xbd, 0x5b, 0x7d, 0xdf, 0xbd, 0x5b, 0x7d,
444 0xde, 0x10,
445 ];
446 assert_program_not_deserializable::<Core>(&hidden, &Error::BothChildrenHidden);
447 }
448
449 #[test]
450 fn unshared_hidden() {
451 #[rustfmt::skip]
454 let hidden = [
455 0xd6, 0xe9, 0x62, 0x56, 0x62, 0xc9, 0x38, 0x8a,
456 0x44, 0x31, 0x85, 0xee, 0xc2, 0x2b, 0x91, 0x48,
457 0x87, 0xe1, 0xfd, 0x18, 0x57, 0xc2, 0x8c, 0x4a,
458 0x28, 0x44, 0x2f, 0xa8, 0x61, 0x5c, 0xa7, 0x6e,
459 0x8c, 0xf9, 0x80, 0xc2, 0x18, 0x95, 0x98, 0xb2,
460 0x4e, 0x22, 0x91, 0x0c, 0x61, 0x7b, 0xb0, 0x8a,
461 0xe4, 0x52, 0x21, 0xf8, 0x7f, 0x46, 0x15, 0xf0,
462 0xa3, 0x12, 0x8a, 0x11, 0x0b, 0xea, 0x18, 0x57,
463 0x29, 0xdb, 0xa3, 0x3e, 0x60, 0x30, 0x2c, 0x00,
464 0xd0, 0x48, 0x20,
465 ];
466 assert_program_not_deserializable::<Core>(&hidden, &Error::SharingNotMaximal);
467 }
468
469 #[test]
470 fn shared_witnesses() {
471 assert_program_deserializable::<Core>(
472 "main := witness",
473 &[0x38],
474 "a0fc8debd6796917c86b77aded82e6c61649889ae8f2ed65b57b41aa9d90e375",
475 "OA==",
476 );
477
478 #[rustfmt::skip]
479 let bad_diff1s = vec![
480 vec![
483 0xda, 0xe2, 0x39, 0xa3, 0x10, 0x42, 0x0e, 0x05,
484 0x71, 0x88, 0xa3, 0x6d, 0xc4, 0x11, 0x80, 0x80
485 ],
486 vec![
490 0xde, 0x87, 0x04, 0x08, 0xe6, 0x8c, 0x41, 0x08,
491 0x38, 0x15, 0xc6, 0x22, 0x8d, 0xb7, 0x10, 0x46,
492 0x02, 0x00,
493 ],
494 ];
495 for bad_diff1 in bad_diff1s {
496 assert_program_not_deserializable::<Core>(&bad_diff1, &Error::SharingNotMaximal);
497 }
498
499 #[rustfmt::skip]
500 let diff1s = vec![
501 (
502 "
504 -- Program which demands two 32-bit witnesses, the first one == the second + 1
505 wit1 := witness : 1 -> 2^32
506 wit2 := witness : 1 -> 2^32
507
508 wit_diff := comp (comp (pair wit1 wit2) jet_subtract_32) (drop iden) : 1 -> 2^32
509 diff_is_one := comp (pair wit_diff jet_one_32) jet_eq_32 : 1 -> 2
510 main := comp diff_is_one jet_verify : 1 -> 1
511 ",
512 vec![
513 0xdc, 0xee, 0x28, 0xe6, 0x8c, 0x41, 0x08, 0x38,
514 0x15, 0xc6, 0x22, 0x8d, 0xb7, 0x10, 0x46, 0x02,
515 0x00,
516 ],
517 "e9339a0d715c721bff752aedc02710cdf3399f3f8d86e64456e85a1bc06ecb7c",
519 "3O4o5oxBCDgVxiKNtxBGAgA=",
520 ),
521 (
523 "
524 -- Program which demands two 32-bit witnesses, the first one == the second + 1
525 wit1 := witness : 1 -> 2^32
526 wit2 := witness : 1 -> 2^32
527 compwit1 := comp iden wit1
528 compwit2 := comp iden wit2
529
530 wit_diff := comp (comp (pair compwit1 compwit2) jet_subtract_32) (drop iden)
531 diff_is_one := comp (pair wit_diff jet_one_32) jet_eq_32 : 1 -> 2
532 main := comp diff_is_one jet_verify : 1 -> 1
533 ",
534 vec![
535 0xe0, 0x28, 0x70, 0x43, 0x83, 0x00, 0xab, 0x9a,
536 0x31, 0x04, 0x20, 0xe0, 0x57, 0x18, 0x8a, 0x36,
537 0xdc, 0x41, 0x18, 0x08,
538 ],
539 "d03bf350f406aef3af0d48e6533b3325ff86f18a36e0e73895a5cd6d6692b860",
541 "4ChwQ4MAq5oxBCDgVxiKNtxBGAg=",
542 )
543 ];
544
545 for (prog_str, diff1, cmr, b64) in diff1s {
546 let diff1_prog = crate::node::commit::tests::assert_program_deserializable::<Core>(
547 prog_str, &diff1, cmr, b64,
548 );
549
550 let mut counter = 0..100;
553 let witness_iter = (&mut counter).rev().map(Value::u32);
554 let diff1_final = diff1_prog
555 .finalize(&mut SimpleFinalizer::new(witness_iter))
556 .unwrap();
557 assert_eq!(counter, 0..98);
558
559 let mut mac =
561 BitMachine::for_program(&diff1_final).expect("program has reasonable bounds");
562 mac.exec(&diff1_final, &()).unwrap();
563 }
564 }
565
566 #[test]
567 fn extra_nodes() {
568 assert_program_not_deserializable::<Core>(&[0xa9, 0x48, 0x00], &Error::NotInCanonicalOrder);
571 }
572
573 #[test]
574 fn regression_177() {
575 let bad_prog = "
583 id := iden
584 main := case (drop id) id
585 ";
586 match Forest::<Core>::parse(bad_prog) {
587 Ok(_) => panic!("program should have failed"),
588 Err(set) => {
589 let mut errs_happened = (false, false);
590 for err in set.iter() {
591 match err {
592 crate::human_encoding::Error::TypeCheck(e @ types::Error::Bind { .. }) => {
593 errs_happened.0 = true;
594 e.to_string();
595 }
596 crate::human_encoding::Error::TypeCheck(
597 e @ types::Error::OccursCheck { .. },
598 ) => {
599 errs_happened.1 = true;
600 e.to_string();
601 }
602 x => panic!("unexpected error {x:?}"),
603 }
604 }
605 assert_eq!(errs_happened, (true, true));
606 }
607 };
608 }
609}