1mod frame;
10mod limits;
11
12use std::collections::HashSet;
13use std::error;
14use std::fmt;
15use std::sync::Arc;
16
17use crate::jet::{Jet, JetFailed};
18use crate::node::{self, RedeemNode};
19use crate::types::Final;
20use crate::{analysis, Ihr};
21use crate::{Cmr, FailEntropy, Value};
22use frame::Frame;
23
24pub use self::limits::LimitError;
25
26pub struct BitMachine {
28 data: Vec<u8>,
31 next_frame_start: usize,
33 read: Vec<Frame>,
35 write: Vec<Frame>,
37 source_ty: Arc<Final>,
39}
40
41impl BitMachine {
42 pub fn for_program<J: Jet>(program: &RedeemNode<J>) -> Result<Self, LimitError> {
44 LimitError::check_program(program)?;
45 let io_width = program.arrow().source.bit_width() + program.arrow().target.bit_width();
46
47 Ok(Self {
48 data: vec![0; (io_width + program.bounds().extra_cells).div_ceil(8)],
49 next_frame_start: 0,
50 read: Vec::with_capacity(program.bounds().extra_frames + analysis::IO_EXTRA_FRAMES),
51 write: Vec::with_capacity(program.bounds().extra_frames + analysis::IO_EXTRA_FRAMES),
52 source_ty: program.arrow().source.clone(),
53 })
54 }
55
56 #[cfg(test)]
57 pub fn test_exec<J: Jet>(
58 program: Arc<crate::node::ConstructNode<J>>,
59 env: &J::Environment,
60 ) -> Result<Value, ExecutionError> {
61 use crate::node::SimpleFinalizer;
62
63 let prog = program
64 .finalize_types_non_program()
65 .expect("finalizing types")
66 .finalize(&mut SimpleFinalizer::new(None.into_iter()))
67 .expect("finalizing");
68 let mut mac = BitMachine::for_program(&prog).expect("program has reasonable bounds");
69 mac.exec(&prog, env)
70 }
71
72 fn new_frame(&mut self, len: usize) {
74 debug_assert!(
75 self.next_frame_start + len <= self.data.len() * 8,
76 "Data out of bounds: number of cells"
77 );
78 debug_assert!(
79 self.write.len() + self.read.len() < self.read.capacity(),
80 "Stacks out of bounds: number of frames"
81 );
82
83 self.write.push(Frame::new(self.next_frame_start, len));
84 self.next_frame_start += len;
85 }
86
87 fn move_frame(&mut self) {
89 let mut _active_write_frame = self.write.pop().unwrap();
90 _active_write_frame.reset_cursor();
91 self.read.push(_active_write_frame);
92 }
93
94 fn drop_frame(&mut self) {
96 let active_read_frame = self.read.pop().unwrap();
97 self.next_frame_start -= active_read_frame.bit_width();
98 assert_eq!(self.next_frame_start, active_read_frame.start());
99 }
100
101 fn write_bit(&mut self, bit: bool) {
103 self.write
104 .last_mut()
105 .expect("Empty write frame stack")
106 .write_bit(bit, &mut self.data);
107 }
108
109 fn skip(&mut self, n: usize) {
112 if n == 0 {
114 return;
115 }
116 let idx = self.write.len() - 1;
117 self.write[idx].move_cursor_forward(n);
118 }
119
120 fn copy(&mut self, n: usize) {
123 if n == 0 {
125 return;
126 }
127 let widx = self.write.len() - 1;
128 let ridx = self.read.len() - 1;
129 self.write[widx].copy_from(&self.read[ridx], n, &mut self.data);
130 }
131
132 fn fwd(&mut self, n: usize) {
135 if n == 0 {
137 return;
138 }
139 let idx = self.read.len() - 1;
140 self.read[idx].move_cursor_forward(n);
141 }
142
143 fn back(&mut self, n: usize) {
146 if n == 0 {
148 return;
149 }
150 let idx = self.read.len() - 1;
151 self.read[idx].move_cursor_backward(n);
152 }
153
154 fn write_u8(&mut self, value: u8) {
156 self.write
157 .last_mut()
158 .expect("Empty write frame stack")
159 .write_u8(value, &mut self.data);
160 }
161
162 fn read_bit(&mut self) -> bool {
164 self.read
165 .last_mut()
166 .expect("Empty read frame stack")
167 .read_bit(&self.data)
168 }
169
170 fn write_bytes(&mut self, bytes: &[u8]) {
172 for bit in bytes {
173 self.write_u8(*bit);
174 }
175 }
176
177 fn write_value(&mut self, val: &Value) {
179 for bit in val.iter_padded() {
180 self.write_bit(bit);
181 }
182 }
183
184 fn active_read_bit_width(&self) -> usize {
186 self.read.last().map(|frame| frame.bit_width()).unwrap_or(0)
187 }
188
189 fn active_write_bit_width(&self) -> usize {
191 self.write
192 .last()
193 .map(|frame| frame.bit_width())
194 .unwrap_or(0)
195 }
196
197 pub fn input(&mut self, input: &Value) -> Result<(), ExecutionError> {
200 if !input.is_of_type(&self.source_ty) {
201 return Err(ExecutionError::InputWrongType(self.source_ty.clone()));
202 }
203 if !input.is_empty() {
205 self.new_frame(input.padded_len());
206 self.write_value(input);
207 self.move_frame();
208 }
209 Ok(())
210 }
211
212 pub fn exec<J: Jet>(
218 &mut self,
219 program: &RedeemNode<J>,
220 env: &J::Environment,
221 ) -> Result<Value, ExecutionError> {
222 self.exec_with_tracker(program, env, &mut NoTracker)
223 }
224
225 pub(crate) fn exec_prune<J: Jet>(
236 &mut self,
237 program: &RedeemNode<J>,
238 env: &J::Environment,
239 ) -> Result<SetTracker, ExecutionError> {
240 let mut tracker = SetTracker::default();
241 self.exec_with_tracker(program, env, &mut tracker)?;
242 Ok(tracker)
243 }
244
245 fn exec_with_tracker<J: Jet, T: CaseTracker>(
246 &mut self,
247 program: &RedeemNode<J>,
248 env: &J::Environment,
249 tracker: &mut T,
250 ) -> Result<Value, ExecutionError> {
251 enum CallStack<'a, J: Jet> {
252 Goto(&'a RedeemNode<J>),
253 MoveFrame,
254 DropFrame,
255 CopyFwd(usize),
256 Back(usize),
257 }
258
259 impl<J: Jet> fmt::Debug for CallStack<'_, J> {
261 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
262 match self {
263 CallStack::Goto(ins) => write!(f, "goto {}", ins.inner()),
264 CallStack::MoveFrame => f.write_str("move frame"),
265 CallStack::DropFrame => f.write_str("drop frame"),
266 CallStack::CopyFwd(n) => write!(f, "copy/fwd {}", n),
267 CallStack::Back(n) => write!(f, "back {}", n),
268 }
269 }
270 }
271
272 if self.read.is_empty() != self.source_ty.is_empty() {
273 return Err(ExecutionError::InputWrongType(self.source_ty.clone()));
274 }
275
276 let mut ip = program;
277 let mut call_stack = vec![];
278
279 let output_width = ip.arrow().target.bit_width();
280 if output_width > 0 {
281 self.new_frame(output_width);
282 }
283
284 'main_loop: loop {
285 match ip.inner() {
286 node::Inner::Unit => {}
287 node::Inner::Iden => {
288 let size_a = ip.arrow().source.bit_width();
289 self.copy(size_a);
290 }
291 node::Inner::InjL(left) => {
292 let (b, c) = ip.arrow().target.as_sum().unwrap();
293 self.write_bit(false);
294 self.skip(b.pad_left(c));
295 call_stack.push(CallStack::Goto(left));
296 }
297 node::Inner::InjR(left) => {
298 let (b, c) = ip.arrow().target.as_sum().unwrap();
299 self.write_bit(true);
300 self.skip(b.pad_right(c));
301 call_stack.push(CallStack::Goto(left));
302 }
303 node::Inner::Pair(left, right) => {
304 call_stack.push(CallStack::Goto(right));
305 call_stack.push(CallStack::Goto(left));
306 }
307 node::Inner::Comp(left, right) => {
308 let size_b = left.arrow().target.bit_width();
309
310 self.new_frame(size_b);
311 call_stack.push(CallStack::DropFrame);
312 call_stack.push(CallStack::Goto(right));
313 call_stack.push(CallStack::MoveFrame);
314 call_stack.push(CallStack::Goto(left));
315 }
316 node::Inner::Disconnect(left, right) => {
317 let size_prod_256_a = left.arrow().source.bit_width();
318 let size_a = size_prod_256_a - 256;
319 let size_prod_b_c = left.arrow().target.bit_width();
320 let size_b = size_prod_b_c - right.arrow().source.bit_width();
321
322 self.new_frame(size_prod_256_a);
323 self.write_bytes(right.cmr().as_ref());
324 self.copy(size_a);
325 self.move_frame();
326 self.new_frame(size_prod_b_c);
327
328 call_stack.push(CallStack::DropFrame);
330 call_stack.push(CallStack::DropFrame);
331 call_stack.push(CallStack::Goto(right));
332 call_stack.push(CallStack::CopyFwd(size_b));
333 call_stack.push(CallStack::MoveFrame);
334 call_stack.push(CallStack::Goto(left));
335 }
336 node::Inner::Take(left) => call_stack.push(CallStack::Goto(left)),
337 node::Inner::Drop(left) => {
338 let size_a = ip.arrow().source.as_product().unwrap().0.bit_width();
339 self.fwd(size_a);
340 call_stack.push(CallStack::Back(size_a));
341 call_stack.push(CallStack::Goto(left));
342 }
343 node::Inner::Case(..) | node::Inner::AssertL(..) | node::Inner::AssertR(..) => {
344 let choice_bit = self.read[self.read.len() - 1].peek_bit(&self.data);
345
346 let (sum_a_b, _c) = ip.arrow().source.as_product().unwrap();
347 let (a, b) = sum_a_b.as_sum().unwrap();
348
349 match (ip.inner(), choice_bit) {
350 (node::Inner::Case(_, right), true)
351 | (node::Inner::AssertR(_, right), true) => {
352 self.fwd(1 + a.pad_right(b));
353 call_stack.push(CallStack::Back(1 + a.pad_right(b)));
354 call_stack.push(CallStack::Goto(right));
355 tracker.track_right(ip.ihr());
356 }
357 (node::Inner::Case(left, _), false)
358 | (node::Inner::AssertL(left, _), false) => {
359 self.fwd(1 + a.pad_left(b));
360 call_stack.push(CallStack::Back(1 + a.pad_left(b)));
361 call_stack.push(CallStack::Goto(left));
362 tracker.track_left(ip.ihr());
363 }
364 (node::Inner::AssertL(_, r_cmr), true) => {
365 return Err(ExecutionError::ReachedPrunedBranch(*r_cmr))
366 }
367 (node::Inner::AssertR(l_cmr, _), false) => {
368 return Err(ExecutionError::ReachedPrunedBranch(*l_cmr))
369 }
370 _ => unreachable!(),
371 }
372 }
373 node::Inner::Witness(value) => self.write_value(value),
374 node::Inner::Jet(jet) => self.exec_jet(*jet, env)?,
375 node::Inner::Word(value) => self.write_value(value.as_value()),
376 node::Inner::Fail(entropy) => {
377 return Err(ExecutionError::ReachedFailNode(*entropy))
378 }
379 }
380
381 ip = loop {
382 match call_stack.pop() {
383 Some(CallStack::Goto(next)) => break next,
384 Some(CallStack::MoveFrame) => self.move_frame(),
385 Some(CallStack::DropFrame) => self.drop_frame(),
386 Some(CallStack::CopyFwd(n)) => {
387 self.copy(n);
388 self.fwd(n);
389 }
390 Some(CallStack::Back(n)) => self.back(n),
391 None => break 'main_loop,
392 };
393 };
394 }
395
396 if output_width > 0 {
397 let out_frame = self.write.last_mut().unwrap();
398 out_frame.reset_cursor();
399 let value = Value::from_padded_bits(
400 &mut out_frame.as_bit_iter(&self.data),
401 &program.arrow().target,
402 )
403 .expect("Decode value of output frame");
404
405 Ok(value)
406 } else {
407 Ok(Value::unit())
408 }
409 }
410
411 fn exec_jet<J: Jet>(&mut self, jet: J, env: &J::Environment) -> Result<(), JetFailed> {
412 use crate::ffi::c_jets::frame_ffi::{c_readBit, c_writeBit, CFrameItem};
413 use crate::ffi::c_jets::uword_width;
414 use crate::ffi::ffi::UWORD;
415
416 unsafe fn get_input_frame(
428 mac: &mut BitMachine,
429 bit_width: usize,
430 ) -> (CFrameItem, Vec<UWORD>) {
431 assert!(bit_width <= mac.active_read_bit_width());
432 let uword_width = uword_width(bit_width);
433 let mut buffer = vec![0; uword_width];
434
435 let buffer_end = buffer.as_mut_ptr().add(uword_width);
437 let mut write_frame = CFrameItem::new_write(bit_width, buffer_end);
438 for _ in 0..bit_width {
439 let bit = mac.read_bit();
440 c_writeBit(&mut write_frame, bit);
441 }
442 mac.back(bit_width);
443
444 let buffer_ptr = buffer.as_mut_ptr();
446 let read_frame = CFrameItem::new_read(bit_width, buffer_ptr);
447
448 (read_frame, buffer)
449 }
450
451 unsafe fn get_output_frame(bit_width: usize) -> (CFrameItem, Vec<UWORD>) {
459 let uword_width = uword_width(bit_width);
460 let mut buffer = vec![0; uword_width];
461
462 let buffer_end = buffer.as_mut_ptr().add(uword_width);
464 let write_frame = CFrameItem::new_write(bit_width, buffer_end);
465
466 (write_frame, buffer)
467 }
468
469 fn update_active_write_frame(mac: &mut BitMachine, bit_width: usize, buffer: &[UWORD]) {
477 assert!(bit_width <= mac.active_write_bit_width());
478 assert!(uword_width(bit_width) <= buffer.len());
479 let buffer_ptr = buffer.as_ptr();
480 let mut read_frame = unsafe { CFrameItem::new_read(bit_width, buffer_ptr) };
481
482 for _ in 0..bit_width {
483 let bit = unsafe { c_readBit(&mut read_frame) };
484 mac.write_bit(bit);
485 }
486 }
487
488 if !simplicity_sys::c_jets::sanity_checks() {
490 return Err(JetFailed);
491 }
492
493 let input_width = jet.source_ty().to_bit_width();
494 let output_width = jet.target_ty().to_bit_width();
495 let (input_read_frame, _input_buffer) = unsafe { get_input_frame(self, input_width) };
498 let (mut output_write_frame, output_buffer) = unsafe { get_output_frame(output_width) };
499
500 let jet_fn = jet.c_jet_ptr();
501 let c_env = J::c_jet_env(env);
502 let success = jet_fn(&mut output_write_frame, input_read_frame, c_env);
503
504 if !success {
505 Err(JetFailed)
506 } else {
507 update_active_write_frame(self, output_width, &output_buffer);
508 Ok(())
509 }
510 }
511}
512
513trait CaseTracker {
522 fn track_left(&mut self, ihr: Ihr);
524
525 fn track_right(&mut self, ihr: Ihr);
527}
528
529#[derive(Clone, Debug, Default)]
531pub(crate) struct SetTracker {
532 left: HashSet<Ihr>,
533 right: HashSet<Ihr>,
534}
535
536impl SetTracker {
537 pub fn left(&self) -> &HashSet<Ihr> {
539 &self.left
540 }
541
542 pub fn right(&self) -> &HashSet<Ihr> {
544 &self.right
545 }
546}
547
548#[derive(Copy, Clone, Debug)]
549struct NoTracker;
550
551impl CaseTracker for SetTracker {
552 fn track_left(&mut self, ihr: Ihr) {
553 self.left.insert(ihr);
554 }
555
556 fn track_right(&mut self, ihr: Ihr) {
557 self.right.insert(ihr);
558 }
559}
560
561impl CaseTracker for NoTracker {
562 fn track_left(&mut self, _: Ihr) {}
563
564 fn track_right(&mut self, _: Ihr) {}
565}
566
567#[derive(Debug)]
569pub enum ExecutionError {
570 InputWrongType(Arc<Final>),
572 ReachedFailNode(FailEntropy),
574 ReachedPrunedBranch(Cmr),
576 LimitExceeded(LimitError),
578 JetFailed(JetFailed),
580}
581
582impl fmt::Display for ExecutionError {
583 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
584 match self {
585 ExecutionError::InputWrongType(expected_ty) => {
586 write!(f, "Expected input of type: {expected_ty}")
587 }
588 ExecutionError::ReachedFailNode(entropy) => {
589 write!(f, "Execution reached a fail node: {}", entropy)
590 }
591 ExecutionError::ReachedPrunedBranch(hash) => {
592 write!(f, "Execution reached a pruned branch: {}", hash)
593 }
594 ExecutionError::LimitExceeded(e) => e.fmt(f),
595 ExecutionError::JetFailed(jet_failed) => jet_failed.fmt(f),
596 }
597 }
598}
599
600impl error::Error for ExecutionError {
601 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
602 match self {
603 Self::InputWrongType(..)
604 | Self::ReachedFailNode(..)
605 | Self::ReachedPrunedBranch(..) => None,
606 Self::LimitExceeded(ref e) => Some(e),
607 Self::JetFailed(ref e) => Some(e),
608 }
609 }
610}
611
612impl From<LimitError> for ExecutionError {
613 fn from(e: LimitError) -> Self {
614 ExecutionError::LimitExceeded(e)
615 }
616}
617
618impl From<JetFailed> for ExecutionError {
619 fn from(jet_failed: JetFailed) -> Self {
620 ExecutionError::JetFailed(jet_failed)
621 }
622}
623
624#[cfg(test)]
625mod tests {
626 use super::*;
627
628 #[cfg(feature = "elements")]
629 use crate::jet::{elements::ElementsEnv, Elements};
630 #[cfg(feature = "elements")]
631 use crate::{node::RedeemNode, BitIter};
632 #[cfg(feature = "elements")]
633 use hex::DisplayHex;
634
635 #[cfg(feature = "elements")]
636 fn run_program_elements(
637 prog_bytes: &[u8],
638 witness_bytes: &[u8],
639 cmr_str: &str,
640 amr_str: &str,
641 ihr_str: &str,
642 ) -> Result<Value, ExecutionError> {
643 let prog_hex = prog_bytes.as_hex();
644
645 let prog = BitIter::from(prog_bytes);
646 let witness = BitIter::from(witness_bytes);
647 let prog = match RedeemNode::<Elements>::decode(prog, witness) {
648 Ok(prog) => prog,
649 Err(e) => panic!("program {} failed: {}", prog_hex, e),
650 };
651
652 assert_eq!(
655 prog.cmr().to_string(),
656 cmr_str,
657 "CMR mismatch (got {} expected {}) for program {}",
658 prog.cmr(),
659 cmr_str,
660 prog_hex,
661 );
662 assert_eq!(
663 prog.amr().to_string(),
664 amr_str,
665 "AMR mismatch (got {} expected {}) for program {}",
666 prog.amr(),
667 amr_str,
668 prog_hex,
669 );
670 assert_eq!(
671 prog.ihr().to_string(),
672 ihr_str,
673 "IHR mismatch (got {} expected {}) for program {}",
674 prog.ihr(),
675 ihr_str,
676 prog_hex,
677 );
678
679 let env = ElementsEnv::dummy();
681 BitMachine::for_program(&prog)
682 .expect("program has reasonable bounds")
683 .exec(&prog, &env)
684 }
685
686 #[test]
687 #[cfg(feature = "elements")]
688 fn crash_regression1() {
689 let res = run_program_elements(
704 &[0xcf, 0xe1, 0x8f, 0xb4, 0x40, 0x28, 0x87, 0x04, 0x00],
705 &[],
706 "0075f5368af7b453c2f7318493df12567bc6d733cf1ebb69a08ce93e1e529956",
707 "0ac9baaee94e416c6598a271dfc18d6014f751ac300cfe69eb758c20f26c624b",
708 "61f2cf59bfec55bb6e44cbae71c3ba225f1059f9a5679c0b42a7177daff52b5a",
709 );
710 assert_eq!(res.unwrap(), Value::unit());
711 }
712
713 #[test]
714 fn crash_regression2() {
715 use crate::node::{CoreConstructible as _, JetConstructible as _};
716
717 type Node = Arc<crate::ConstructNode<crate::jet::Core>>;
718
719 let mut bomb = Node::jet(
720 &crate::types::Context::new(),
721 crate::jet::Core::Ch8, );
723 for _ in 0..100 {
724 bomb = Node::pair(&bomb, &bomb).unwrap();
725 }
726 let _ = bomb.finalize_pruned(&());
727 }
728}