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