1use crate::math_utils::signed_felt;
2use crate::stdlib::{any::Any, borrow::Cow, collections::HashMap, prelude::*};
3use crate::types::builtin_name::BuiltinName;
4#[cfg(feature = "extensive_hints")]
5use crate::types::program::HintRange;
6use crate::{
7 hint_processor::{
8 builtin_hint_processor::blake2s_hash::blake2s_compress,
9 hint_processor_definition::HintProcessor,
10 },
11 typed_operations::{typed_add, typed_div, typed_mul, typed_sub},
12 types::{
13 errors::math_errors::MathError,
14 exec_scope::ExecutionScopes,
15 instruction::{
16 is_call_instruction, ApUpdate, FpUpdate, Instruction, Opcode, OpcodeExtension,
17 PcUpdate, Res,
18 },
19 relocatable::{MaybeRelocatable, Relocatable},
20 },
21 vm::{
22 context::run_context::RunContext,
23 decoding::decoder::decode_instruction,
24 errors::{
25 exec_scope_errors::ExecScopeError, memory_errors::MemoryError,
26 vm_errors::VirtualMachineError,
27 },
28 runners::builtin_runner::{
29 BuiltinRunner, OutputBuiltinRunner, RangeCheckBuiltinRunner, SignatureBuiltinRunner,
30 },
31 trace::trace_entry::TraceEntry,
32 vm_memory::memory_segments::MemorySegmentManager,
33 },
34};
35
36use crate::Felt252;
37use core::cmp::Ordering;
38#[cfg(feature = "extensive_hints")]
39use core::num::NonZeroUsize;
40use num_traits::{ToPrimitive, Zero};
41
42use super::errors::runner_errors::RunnerError;
43use super::runners::builtin_runner::{ModBuiltinRunner, RC_N_PARTS_STANDARD};
44use super::runners::cairo_pie::CairoPie;
45
46const MAX_TRACEBACK_ENTRIES: u32 = 20;
47
48#[derive(PartialEq, Eq, Debug)]
49pub struct Operands {
50 dst: MaybeRelocatable,
51 res: Option<MaybeRelocatable>,
52 op0: MaybeRelocatable,
53 op1: MaybeRelocatable,
54}
55
56#[derive(PartialEq, Eq, Debug)]
57pub struct OperandsAddresses {
58 dst_addr: Relocatable,
59 op0_addr: Relocatable,
60 op1_addr: Relocatable,
61}
62
63#[derive(Default, Debug, Clone, Copy)]
64pub struct DeducedOperands(u8);
65
66impl DeducedOperands {
67 fn set_dst(&mut self, value: bool) {
68 self.0 |= value as u8;
69 }
70 fn set_op0(&mut self, value: bool) {
71 self.0 |= (value as u8) << 1;
72 }
73 fn set_op1(&mut self, value: bool) {
74 self.0 |= (value as u8) << 2;
75 }
76
77 fn was_dest_deducted(&self) -> bool {
78 self.0 & 1 != 0
79 }
80 fn was_op0_deducted(&self) -> bool {
81 self.0 & 1 << 1 != 0
82 }
83 fn was_op1_deducted(&self) -> bool {
84 self.0 & 1 << 2 != 0
85 }
86}
87
88pub struct VirtualMachine {
89 pub(crate) run_context: RunContext,
90 pub builtin_runners: Vec<BuiltinRunner>,
91 pub segments: MemorySegmentManager,
92 pub(crate) trace: Option<Vec<TraceEntry>>,
93 pub(crate) current_step: usize,
94 pub(crate) rc_limits: Option<(isize, isize)>,
95 skip_instruction_execution: bool,
96 run_finished: bool,
97 pub(crate) disable_trace_padding: bool,
99 instruction_cache: Vec<Option<Instruction>>,
100 #[cfg(feature = "test_utils")]
101 pub(crate) hooks: crate::vm::hooks::Hooks,
102 pub(crate) relocation_table: Option<Vec<usize>>,
103}
104
105impl VirtualMachine {
106 pub fn new(trace_enabled: bool, disable_trace_padding: bool) -> VirtualMachine {
107 let run_context = RunContext {
108 pc: Relocatable::from((0, 0)),
109 ap: 0,
110 fp: 0,
111 };
112
113 let trace = if trace_enabled {
114 Some(Vec::<TraceEntry>::new())
115 } else {
116 None
117 };
118
119 VirtualMachine {
120 run_context,
121 builtin_runners: Vec::new(),
122 trace,
123 current_step: 0,
124 skip_instruction_execution: false,
125 segments: MemorySegmentManager::new(),
126 rc_limits: None,
127 run_finished: false,
128 disable_trace_padding,
129 instruction_cache: Vec::new(),
130 #[cfg(feature = "test_utils")]
131 hooks: Default::default(),
132 relocation_table: None,
133 }
134 }
135
136 pub fn compute_segments_effective_sizes(&mut self) {
137 self.segments.compute_effective_sizes();
138 }
139
140 fn update_fp(
141 &mut self,
142 instruction: &Instruction,
143 operands: &Operands,
144 ) -> Result<(), VirtualMachineError> {
145 let new_fp_offset: usize = match instruction.fp_update {
146 FpUpdate::APPlus2 => self.run_context.ap + 2,
147 FpUpdate::Dst => match operands.dst {
148 MaybeRelocatable::RelocatableValue(ref rel) => rel.offset,
149 MaybeRelocatable::Int(ref num) => num
150 .to_usize()
151 .ok_or_else(|| MathError::Felt252ToUsizeConversion(Box::new(*num)))?,
152 },
153 FpUpdate::Regular => return Ok(()),
154 };
155 self.run_context.fp = new_fp_offset;
156 Ok(())
157 }
158
159 fn update_ap(
160 &mut self,
161 instruction: &Instruction,
162 operands: &Operands,
163 ) -> Result<(), VirtualMachineError> {
164 let new_apset: usize = match instruction.ap_update {
165 ApUpdate::Add => match &operands.res {
166 Some(res) => (self.run_context.get_ap() + res)?.offset,
167 None => return Err(VirtualMachineError::UnconstrainedResAdd),
168 },
169 ApUpdate::Add1 => self.run_context.ap + 1,
170 ApUpdate::Add2 => self.run_context.ap + 2,
171 ApUpdate::Regular => return Ok(()),
172 };
173 self.run_context.ap = new_apset;
174 Ok(())
175 }
176
177 fn update_pc(
178 &mut self,
179 instruction: &Instruction,
180 operands: &Operands,
181 ) -> Result<(), VirtualMachineError> {
182 let new_pc: Relocatable = match instruction.pc_update {
183 PcUpdate::Regular => (self.run_context.pc + instruction.size())?,
184 PcUpdate::Jump => match operands.res.as_ref().and_then(|x| x.get_relocatable()) {
185 Some(ref res) => *res,
186 None => return Err(VirtualMachineError::UnconstrainedResJump),
187 },
188 PcUpdate::JumpRel => match &operands.res {
189 Some(res) => match res {
190 MaybeRelocatable::Int(num_res) => (self.run_context.pc + num_res)?,
191 _ => return Err(VirtualMachineError::JumpRelNotInt),
192 },
193 None => return Err(VirtualMachineError::UnconstrainedResJumpRel),
194 },
195 PcUpdate::Jnz => match VirtualMachine::is_zero(&operands.dst) {
196 true => (self.run_context.pc + instruction.size())?,
197 false => (self.run_context.pc + &operands.op1)?,
198 },
199 };
200 self.run_context.pc = new_pc;
201 Ok(())
202 }
203
204 fn update_registers(
205 &mut self,
206 instruction: &Instruction,
207 operands: Operands,
208 ) -> Result<(), VirtualMachineError> {
209 self.update_fp(instruction, &operands)?;
210 self.update_ap(instruction, &operands)?;
211 self.update_pc(instruction, &operands)?;
212 Ok(())
213 }
214
215 fn is_zero(addr: &MaybeRelocatable) -> bool {
218 match addr {
219 MaybeRelocatable::Int(num) => num.is_zero(),
220 _ => false,
221 }
222 }
223
224 fn deduce_op0(
228 &self,
229 instruction: &Instruction,
230 dst: Option<&MaybeRelocatable>,
231 op1: Option<&MaybeRelocatable>,
232 ) -> Result<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError> {
233 match instruction.opcode {
234 Opcode::Call => Ok((
235 Some(MaybeRelocatable::from(
236 (self.run_context.pc + instruction.size())?,
237 )),
238 None,
239 )),
240 Opcode::AssertEq => match (&instruction.res, dst, op1) {
241 (Res::Add, Some(dst_addr), Some(op1_addr)) => Ok((
242 Some(typed_sub(dst_addr, op1_addr, instruction.opcode_extension)?),
243 dst.cloned(),
244 )),
245 (
246 Res::Mul,
247 Some(MaybeRelocatable::Int(num_dst)),
248 Some(MaybeRelocatable::Int(num_op1)),
249 ) if !num_op1.is_zero() => {
250 let num_op0 = typed_div(num_dst, num_op1, instruction.opcode_extension)?;
251 Ok((Some(MaybeRelocatable::Int(num_op0)), dst.cloned()))
252 }
253 _ => Ok((None, None)),
254 },
255 _ => Ok((None, None)),
256 }
257 }
258
259 fn deduce_op1(
263 &self,
264 instruction: &Instruction,
265 dst: Option<&MaybeRelocatable>,
266 op0: Option<MaybeRelocatable>,
267 ) -> Result<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError> {
268 if let Opcode::AssertEq = instruction.opcode {
269 match instruction.res {
270 Res::Op1 => return Ok((dst.cloned(), dst.cloned())),
271 Res::Add => {
272 return Ok((
273 dst.zip(op0).and_then(|(dst, op0)| {
274 typed_sub(dst, &op0, instruction.opcode_extension).ok()
275 }),
276 dst.cloned(),
277 ))
278 }
279 Res::Mul => match (dst, op0) {
280 (
281 Some(MaybeRelocatable::Int(num_dst)),
282 Some(MaybeRelocatable::Int(num_op0)),
283 ) if !num_op0.is_zero() => {
284 let num_op1 = typed_div(num_dst, &num_op0, instruction.opcode_extension)?;
285 return Ok((Some(MaybeRelocatable::Int(num_op1)), dst.cloned()));
286 }
287 _ => (),
288 },
289 _ => (),
290 };
291 };
292 Ok((None, None))
293 }
294
295 fn deduce_memory_cell(
296 &self,
297 address: Relocatable,
298 ) -> Result<Option<MaybeRelocatable>, VirtualMachineError> {
299 for builtin in self.builtin_runners.iter() {
300 if builtin.base() as isize == address.segment_index {
301 match builtin.deduce_memory_cell(address, &self.segments.memory) {
302 Ok(maybe_reloc) => return Ok(maybe_reloc),
303 Err(error) => return Err(VirtualMachineError::RunnerError(error)),
304 };
305 }
306 }
307 Ok(None)
308 }
309
310 fn compute_res(
312 &self,
313 instruction: &Instruction,
314 op0: &MaybeRelocatable,
315 op1: &MaybeRelocatable,
316 ) -> Result<Option<MaybeRelocatable>, VirtualMachineError> {
317 match instruction.res {
318 Res::Op1 => Ok(Some(op1.clone())),
319 Res::Add => Ok(Some(typed_add(op0, op1, instruction.opcode_extension)?)),
320 Res::Mul => Ok(Some(typed_mul(op0, op1, instruction.opcode_extension)?)),
321 Res::Unconstrained => Ok(None),
322 }
323 }
324
325 fn deduce_dst(
326 &self,
327 instruction: &Instruction,
328 res: &Option<MaybeRelocatable>,
329 ) -> Result<MaybeRelocatable, VirtualMachineError> {
330 let dst = match (instruction.opcode, res) {
331 (Opcode::AssertEq, Some(res)) => res.clone(),
332 (Opcode::Call, _) => MaybeRelocatable::from(self.run_context.get_fp()),
333 _ => return Err(VirtualMachineError::NoDst),
334 };
335 Ok(dst)
336 }
337
338 fn opcode_assertions(
339 &self,
340 instruction: &Instruction,
341 operands: &Operands,
342 ) -> Result<(), VirtualMachineError> {
343 match instruction.opcode {
344 Opcode::AssertEq => match &operands.res {
345 None => Err(VirtualMachineError::UnconstrainedResAssertEq),
346 Some(res) if res != &operands.dst => Err(VirtualMachineError::DiffAssertValues(
347 Box::new((operands.dst.clone(), res.clone())),
348 )),
349 _ => Ok(()),
350 },
351 Opcode::Call => {
352 let return_pc = MaybeRelocatable::from((self.run_context.pc + instruction.size())?);
353 if operands.op0 != return_pc {
354 return Err(VirtualMachineError::CantWriteReturnPc(Box::new((
355 operands.op0.clone(),
356 return_pc,
357 ))));
358 };
359
360 if MaybeRelocatable::from(self.run_context.get_fp()) != operands.dst {
361 return Err(VirtualMachineError::CantWriteReturnFp(Box::new((
362 operands.dst.clone(),
363 MaybeRelocatable::from(self.run_context.get_fp()),
364 ))));
365 };
366 Ok(())
367 }
368 _ => Ok(()),
369 }
370 }
371
372 fn insert_deduced_operands(
373 &mut self,
374 deduced_operands: DeducedOperands,
375 operands: &Operands,
376 operands_addresses: &OperandsAddresses,
377 ) -> Result<(), VirtualMachineError> {
378 if deduced_operands.was_op0_deducted() {
379 self.segments
380 .memory
381 .insert(operands_addresses.op0_addr, &operands.op0)
382 .map_err(VirtualMachineError::Memory)?;
383 }
384 if deduced_operands.was_op1_deducted() {
385 self.segments
386 .memory
387 .insert(operands_addresses.op1_addr, &operands.op1)
388 .map_err(VirtualMachineError::Memory)?;
389 }
390 if deduced_operands.was_dest_deducted() {
391 self.segments
392 .memory
393 .insert(operands_addresses.dst_addr, &operands.dst)
394 .map_err(VirtualMachineError::Memory)?;
395 }
396
397 Ok(())
398 }
399
400 fn run_instruction(&mut self, instruction: &Instruction) -> Result<(), VirtualMachineError> {
401 let (operands, operands_addresses, deduced_operands) =
402 self.compute_operands(instruction)?;
403 self.insert_deduced_operands(deduced_operands, &operands, &operands_addresses)?;
404 self.opcode_assertions(instruction, &operands)?;
405
406 if let Some(ref mut trace) = &mut self.trace {
407 trace.push(TraceEntry {
408 pc: self.run_context.pc,
409 ap: self.run_context.ap,
410 fp: self.run_context.fp,
411 });
412 }
413
414 const OFFSET_BITS: u32 = 16;
416 let (off0, off1, off2) = (
417 instruction.off0 + (1_isize << (OFFSET_BITS - 1)),
418 instruction.off1 + (1_isize << (OFFSET_BITS - 1)),
419 instruction.off2 + (1_isize << (OFFSET_BITS - 1)),
420 );
421 let (min, max) = self.rc_limits.unwrap_or((off0, off0));
422 self.rc_limits = Some((
423 min.min(off0).min(off1).min(off2),
424 max.max(off0).max(off1).max(off2),
425 ));
426
427 self.segments
428 .memory
429 .mark_as_accessed(operands_addresses.dst_addr);
430 self.segments
431 .memory
432 .mark_as_accessed(operands_addresses.op0_addr);
433 self.segments
434 .memory
435 .mark_as_accessed(operands_addresses.op1_addr);
436
437 if instruction.opcode_extension == OpcodeExtension::Blake
438 || instruction.opcode_extension == OpcodeExtension::BlakeFinalize
439 {
440 self.handle_blake2s_instruction(
441 &operands_addresses,
442 instruction.opcode_extension == OpcodeExtension::BlakeFinalize,
443 )?;
444 }
445
446 self.update_registers(instruction, operands)?;
447 self.current_step += 1;
448
449 Ok(())
450 }
451
452 fn handle_blake2s_instruction(
464 &mut self,
465 operands_addresses: &OperandsAddresses,
466 is_last_block: bool,
467 ) -> Result<(), VirtualMachineError> {
468 let counter = self.segments.memory.get_u32(operands_addresses.dst_addr)?;
469
470 let state: [u32; 8] = (self.get_u32_range(
471 self.segments
472 .memory
473 .get_relocatable(operands_addresses.op0_addr)?,
474 8,
475 )?)
476 .try_into()
477 .map_err(|_| VirtualMachineError::Blake2sInvalidOperand(0, 8))?;
478
479 let message: [u32; 16] = (self.get_u32_range(
480 self.segments
481 .memory
482 .get_relocatable(operands_addresses.op1_addr)?,
483 16,
484 )?)
485 .try_into()
486 .map_err(|_| VirtualMachineError::Blake2sInvalidOperand(1, 16))?;
487
488 let f0 = if is_last_block { 0xffffffff } else { 0 };
489
490 let ap = self.run_context.get_ap();
491 let output_address = self.segments.memory.get_relocatable(ap)?;
492
493 let new_state = blake2s_compress(&state, &message, counter, 0, f0, 0);
494
495 for (i, &val) in new_state.iter().enumerate() {
496 self.segments.memory.insert_as_accessed(
497 (output_address + i)?,
498 MaybeRelocatable::Int(Felt252::from(val)),
499 )?;
500 }
501
502 Ok(())
503 }
504
505 fn decode_current_instruction(&self) -> Result<Instruction, VirtualMachineError> {
506 let instruction = self
507 .segments
508 .memory
509 .get_integer(self.run_context.pc)?
510 .to_u128()
511 .ok_or(VirtualMachineError::InvalidInstructionEncoding)?;
512 decode_instruction(instruction)
513 }
514
515 #[cfg(not(feature = "extensive_hints"))]
516 pub fn step_hint(
517 &mut self,
518 hint_processor: &mut dyn HintProcessor,
519 exec_scopes: &mut ExecutionScopes,
520 hint_datas: &[Box<dyn Any>],
521 constants: &HashMap<String, Felt252>,
522 ) -> Result<(), VirtualMachineError> {
523 for (hint_index, hint_data) in hint_datas.iter().enumerate() {
524 hint_processor
525 .execute_hint(self, exec_scopes, hint_data, constants)
526 .map_err(|err| VirtualMachineError::Hint(Box::new((hint_index, err))))?
527 }
528 Ok(())
529 }
530
531 #[cfg(feature = "extensive_hints")]
532 pub fn step_hint(
533 &mut self,
534 hint_processor: &mut dyn HintProcessor,
535 exec_scopes: &mut ExecutionScopes,
536 hint_datas: &mut Vec<Box<dyn Any>>,
537 hint_ranges: &mut HashMap<Relocatable, HintRange>,
538 constants: &HashMap<String, Felt252>,
539 ) -> Result<(), VirtualMachineError> {
540 if let Some((s, l)) = hint_ranges.get(&self.run_context.pc) {
542 let s = *s;
544 for idx in s..(s + l.get()) {
546 let hint_extension = hint_processor
547 .execute_hint_extensive(
548 self,
549 exec_scopes,
550 hint_datas.get(idx).ok_or(VirtualMachineError::Unexpected)?,
551 constants,
552 )
553 .map_err(|err| VirtualMachineError::Hint(Box::new((idx - s, err))))?;
554 for (hint_pc, hints) in hint_extension {
556 if let Ok(len) = NonZeroUsize::try_from(hints.len()) {
557 hint_ranges.insert(hint_pc, (hint_datas.len(), len));
558 hint_datas.extend(hints);
559 }
560 }
561 }
562 }
563 Ok(())
564 }
565
566 pub fn step_instruction(&mut self) -> Result<(), VirtualMachineError> {
567 if self.run_context.pc.segment_index == 0 {
568 let pc = self.run_context.pc.offset;
570
571 if self.segments.memory.data[0].len() <= pc {
572 return Err(MemoryError::UnknownMemoryCell(Box::new((0, pc).into())))?;
573 }
574
575 let mut inst_cache = core::mem::take(&mut self.instruction_cache);
576 inst_cache.resize((pc + 1).max(inst_cache.len()), None);
577
578 let instruction = inst_cache.get_mut(pc).unwrap();
579 if instruction.is_none() {
580 *instruction = Some(self.decode_current_instruction()?);
581 }
582 let instruction = instruction.as_ref().unwrap();
583
584 if !self.skip_instruction_execution {
585 self.run_instruction(instruction)?;
586 } else {
587 self.run_context.pc += instruction.size();
588 self.skip_instruction_execution = false;
589 }
590 self.instruction_cache = inst_cache;
591 } else {
592 let instruction = self.decode_current_instruction()?;
594
595 if !self.skip_instruction_execution {
596 self.run_instruction(&instruction)?;
597 } else {
598 self.run_context.pc += instruction.size();
599 self.skip_instruction_execution = false;
600 }
601 }
602 Ok(())
603 }
604
605 pub fn step(
606 &mut self,
607 hint_processor: &mut dyn HintProcessor,
608 exec_scopes: &mut ExecutionScopes,
609 #[cfg(feature = "extensive_hints")] hint_datas: &mut Vec<Box<dyn Any>>,
610 #[cfg(not(feature = "extensive_hints"))] hint_datas: &[Box<dyn Any>],
611 #[cfg(feature = "extensive_hints")] hint_ranges: &mut HashMap<Relocatable, HintRange>,
612 constants: &HashMap<String, Felt252>,
613 ) -> Result<(), VirtualMachineError> {
614 self.step_hint(
615 hint_processor,
616 exec_scopes,
617 hint_datas,
618 #[cfg(feature = "extensive_hints")]
619 hint_ranges,
620 constants,
621 )?;
622
623 #[cfg(feature = "test_utils")]
624 self.execute_pre_step_instruction(hint_processor, exec_scopes, hint_datas, constants)?;
625 self.step_instruction()?;
626 #[cfg(feature = "test_utils")]
627 self.execute_post_step_instruction(hint_processor, exec_scopes, hint_datas, constants)?;
628
629 Ok(())
630 }
631
632 fn compute_op0_deductions(
633 &self,
634 op0_addr: Relocatable,
635 res: &mut Option<MaybeRelocatable>,
636 instruction: &Instruction,
637 dst_op: &Option<MaybeRelocatable>,
638 op1_op: &Option<MaybeRelocatable>,
639 ) -> Result<MaybeRelocatable, VirtualMachineError> {
640 let op0_op = match self.deduce_memory_cell(op0_addr)? {
641 None => {
642 let op0;
643 (op0, *res) = self.deduce_op0(instruction, dst_op.as_ref(), op1_op.as_ref())?;
644 op0
645 }
646 deduced_memory_cell => deduced_memory_cell,
647 };
648 let op0 = op0_op.ok_or_else(|| {
649 VirtualMachineError::FailedToComputeOperands(Box::new(("op0".to_string(), op0_addr)))
650 })?;
651 Ok(op0)
652 }
653
654 fn compute_op1_deductions(
655 &self,
656 op1_addr: Relocatable,
657 res: &mut Option<MaybeRelocatable>,
658 instruction: &Instruction,
659 dst_op: &Option<MaybeRelocatable>,
660 op0: &MaybeRelocatable,
661 ) -> Result<MaybeRelocatable, VirtualMachineError> {
662 let op1_op = match self.deduce_memory_cell(op1_addr)? {
663 None => {
664 let (op1, deduced_res) =
665 self.deduce_op1(instruction, dst_op.as_ref(), Some(op0.clone()))?;
666 if res.is_none() {
667 *res = deduced_res
668 }
669 op1
670 }
671 deduced_memory_cell => deduced_memory_cell,
672 };
673 let op1 = op1_op.ok_or_else(|| {
674 VirtualMachineError::FailedToComputeOperands(Box::new(("op1".to_string(), op1_addr)))
675 })?;
676 Ok(op1)
677 }
678
679 pub fn compute_operands(
682 &self,
683 instruction: &Instruction,
684 ) -> Result<(Operands, OperandsAddresses, DeducedOperands), VirtualMachineError> {
685 let dst_addr = self.run_context.compute_dst_addr(instruction)?;
687 let dst_op = self.segments.memory.get(&dst_addr).map(Cow::into_owned);
688
689 let op0_addr = self.run_context.compute_op0_addr(instruction)?;
690 let op0_op = self.segments.memory.get(&op0_addr).map(Cow::into_owned);
691
692 let op1_addr = self
693 .run_context
694 .compute_op1_addr(instruction, op0_op.as_ref())?;
695 let op1_op = self.segments.memory.get(&op1_addr).map(Cow::into_owned);
696
697 let mut res: Option<MaybeRelocatable> = None;
698
699 let mut deduced_operands = DeducedOperands::default();
700
701 let op0 = match op0_op {
703 Some(op0) => op0,
704 None => {
705 deduced_operands.set_op0(true);
706 self.compute_op0_deductions(op0_addr, &mut res, instruction, &dst_op, &op1_op)?
707 }
708 };
709
710 let op1 = match op1_op {
712 Some(op1) => op1,
713 None => {
714 deduced_operands.set_op1(true);
715 self.compute_op1_deductions(op1_addr, &mut res, instruction, &dst_op, &op0)?
716 }
717 };
718
719 if res.is_none() {
721 res = self.compute_res(instruction, &op0, &op1)?;
722 }
723
724 let dst = match dst_op {
726 Some(dst) => dst,
727 None => {
728 deduced_operands.set_dst(true);
729 self.deduce_dst(instruction, &res)?
730 }
731 };
732 let accessed_addresses = OperandsAddresses {
733 dst_addr,
734 op0_addr,
735 op1_addr,
736 };
737 Ok((
738 Operands { dst, op0, op1, res },
739 accessed_addresses,
740 deduced_operands,
741 ))
742 }
743
744 pub fn verify_auto_deductions(&self) -> Result<(), VirtualMachineError> {
746 for builtin in self.builtin_runners.iter() {
747 let index: usize = builtin.base();
748 for (offset, value) in self.segments.memory.data[index].iter().enumerate() {
749 if let Some(deduced_memory_cell) = builtin
750 .deduce_memory_cell(
751 Relocatable::from((index as isize, offset)),
752 &self.segments.memory,
753 )
754 .map_err(VirtualMachineError::RunnerError)?
755 {
756 let value = value.get_value();
757 if Some(&deduced_memory_cell) != value.as_ref() && value.is_some() {
758 return Err(VirtualMachineError::InconsistentAutoDeduction(Box::new((
759 builtin.name(),
760 deduced_memory_cell,
761 value,
762 ))));
763 }
764 }
765 }
766 }
767 Ok(())
768 }
769
770 pub fn verify_auto_deductions_for_addr(
772 &self,
773 addr: Relocatable,
774 builtin: &BuiltinRunner,
775 ) -> Result<(), VirtualMachineError> {
776 let value = match builtin.deduce_memory_cell(addr, &self.segments.memory)? {
777 Some(value) => value,
778 None => return Ok(()),
779 };
780 let current_value = match self.segments.memory.get(&addr) {
781 Some(value) => value.into_owned(),
782 None => return Ok(()),
783 };
784 if value != current_value {
785 return Err(VirtualMachineError::InconsistentAutoDeduction(Box::new((
786 builtin.name(),
787 value,
788 Some(current_value),
789 ))));
790 }
791 Ok(())
792 }
793
794 pub fn end_run(&mut self, exec_scopes: &ExecutionScopes) -> Result<(), VirtualMachineError> {
795 self.verify_auto_deductions()?;
796 self.run_finished = true;
797 match exec_scopes.data.len() {
798 1 => Ok(()),
799 _ => Err(ExecScopeError::NoScopeError.into()),
800 }
801 }
802
803 pub fn mark_address_range_as_accessed(
804 &mut self,
805 base: Relocatable,
806 len: usize,
807 ) -> Result<(), VirtualMachineError> {
808 if !self.run_finished {
809 return Err(VirtualMachineError::RunNotFinished);
810 }
811 for i in 0..len {
812 self.segments.memory.mark_as_accessed((base + i)?);
813 }
814 Ok(())
815 }
816
817 pub(crate) fn get_traceback_entries(&self) -> Vec<(Relocatable, Relocatable)> {
820 let mut entries = Vec::<(Relocatable, Relocatable)>::new();
821 let mut fp = Relocatable::from((1, self.run_context.fp));
822 for _ in 0..MAX_TRACEBACK_ENTRIES {
824 let ret_pc = match (fp - 1)
826 .ok()
827 .map(|r| self.segments.memory.get_relocatable(r))
828 {
829 Some(Ok(opt_pc)) => opt_pc,
830 _ => break,
831 };
832 match (fp - 2)
834 .ok()
835 .map(|r| self.segments.memory.get_relocatable(r))
836 {
837 Some(Ok(opt_fp)) if opt_fp != fp => fp = opt_fp,
838 _ => break,
839 }
840 let call_pc = match (ret_pc - 1)
843 .ok()
844 .map(|r| self.segments.memory.get_integer(r))
845 {
846 Some(Ok(instruction1)) => {
847 match is_call_instruction(&instruction1) {
848 true => (ret_pc - 1).unwrap(), false => {
850 match (ret_pc - 2)
851 .ok()
852 .map(|r| self.segments.memory.get_integer(r))
853 {
854 Some(Ok(instruction0)) => {
855 match is_call_instruction(&instruction0) {
856 true => (ret_pc - 2).unwrap(), false => break,
858 }
859 }
860 _ => break,
861 }
862 }
863 }
864 }
865 _ => break,
866 };
867 entries.push((fp, call_pc))
869 }
870 entries.reverse();
871 entries
872 }
873
874 pub fn add_memory_segment(&mut self) -> Relocatable {
876 self.segments.add()
877 }
878
879 pub fn get_ap(&self) -> Relocatable {
880 self.run_context.get_ap()
881 }
882
883 pub fn get_fp(&self) -> Relocatable {
884 self.run_context.get_fp()
885 }
886
887 pub fn get_pc(&self) -> Relocatable {
888 self.run_context.get_pc()
889 }
890
891 pub fn get_integer(&self, key: Relocatable) -> Result<Cow<Felt252>, MemoryError> {
893 self.segments.memory.get_integer(key)
894 }
895
896 pub fn get_relocatable(&self, key: Relocatable) -> Result<Relocatable, MemoryError> {
898 self.segments.memory.get_relocatable(key)
899 }
900
901 pub fn get_maybe<'a, 'b: 'a, K: 'a>(&'b self, key: &'a K) -> Option<MaybeRelocatable>
903 where
904 Relocatable: TryFrom<&'a K>,
905 {
906 self.segments.memory.get(key).map(|x| x.into_owned())
907 }
908
909 pub fn get_builtin_runners(&self) -> &Vec<BuiltinRunner> {
911 &self.builtin_runners
912 }
913
914 pub fn get_builtin_runners_as_mut(&mut self) -> &mut Vec<BuiltinRunner> {
916 &mut self.builtin_runners
917 }
918
919 pub fn insert_value<T: Into<MaybeRelocatable>>(
921 &mut self,
922 key: Relocatable,
923 val: T,
924 ) -> Result<(), MemoryError> {
925 self.segments.memory.insert_value(key, val)
926 }
927
928 pub fn load_data(
930 &mut self,
931 ptr: Relocatable,
932 data: &[MaybeRelocatable],
933 ) -> Result<Relocatable, MemoryError> {
934 if ptr.segment_index == 0 {
935 self.instruction_cache.resize(data.len(), None);
936 }
937 self.segments.load_data(ptr, data)
938 }
939
940 pub fn write_arg(
942 &mut self,
943 ptr: Relocatable,
944 arg: &dyn Any,
945 ) -> Result<MaybeRelocatable, MemoryError> {
946 self.segments.write_arg(ptr, arg)
947 }
948
949 pub fn memcmp(&self, lhs: Relocatable, rhs: Relocatable, len: usize) -> (Ordering, usize) {
950 self.segments.memory.memcmp(lhs, rhs, len)
951 }
952
953 pub fn mem_eq(&self, lhs: Relocatable, rhs: Relocatable, len: usize) -> bool {
954 self.segments.memory.mem_eq(lhs, rhs, len)
955 }
956
957 pub fn get_return_values(&self, n_ret: usize) -> Result<Vec<MaybeRelocatable>, MemoryError> {
959 let addr = (self.run_context.get_ap() - n_ret)
960 .map_err(|_| MemoryError::FailedToGetReturnValues(Box::new((n_ret, self.get_ap()))))?;
961 self.segments.memory.get_continuous_range(addr, n_ret)
962 }
963
964 pub fn get_range(&self, addr: Relocatable, size: usize) -> Vec<Option<Cow<MaybeRelocatable>>> {
966 self.segments.memory.get_range(addr, size)
967 }
968
969 pub fn get_continuous_range(
971 &self,
972 addr: Relocatable,
973 size: usize,
974 ) -> Result<Vec<MaybeRelocatable>, MemoryError> {
975 self.segments.memory.get_continuous_range(addr, size)
976 }
977
978 pub fn get_integer_range(
980 &self,
981 addr: Relocatable,
982 size: usize,
983 ) -> Result<Vec<Cow<Felt252>>, MemoryError> {
984 self.segments.memory.get_integer_range(addr, size)
985 }
986
987 pub fn get_u32_range(&self, addr: Relocatable, size: usize) -> Result<Vec<u32>, MemoryError> {
990 self.segments.memory.get_u32_range(addr, size)
991 }
992
993 pub fn get_range_check_builtin(
994 &self,
995 ) -> Result<&RangeCheckBuiltinRunner<RC_N_PARTS_STANDARD>, VirtualMachineError> {
996 for builtin in &self.builtin_runners {
997 if let BuiltinRunner::RangeCheck(range_check_builtin) = builtin {
998 return Ok(range_check_builtin);
999 };
1000 }
1001 Err(VirtualMachineError::NoRangeCheckBuiltin)
1002 }
1003
1004 pub fn get_signature_builtin(
1005 &mut self,
1006 ) -> Result<&mut SignatureBuiltinRunner, VirtualMachineError> {
1007 for builtin in self.get_builtin_runners_as_mut() {
1008 if let BuiltinRunner::Signature(signature_builtin) = builtin {
1009 return Ok(signature_builtin);
1010 };
1011 }
1012
1013 Err(VirtualMachineError::NoSignatureBuiltin)
1014 }
1015
1016 pub fn get_output_builtin_mut(
1017 &mut self,
1018 ) -> Result<&mut OutputBuiltinRunner, VirtualMachineError> {
1019 for builtin in self.get_builtin_runners_as_mut() {
1020 if let BuiltinRunner::Output(output_builtin) = builtin {
1021 return Ok(output_builtin);
1022 };
1023 }
1024
1025 Err(VirtualMachineError::NoOutputBuiltin)
1026 }
1027
1028 #[cfg(feature = "tracer")]
1029 pub fn relocate_segments(&self) -> Result<Vec<usize>, MemoryError> {
1030 self.segments.relocate_segments()
1031 }
1032
1033 #[doc(hidden)]
1034 pub fn skip_next_instruction_execution(&mut self) {
1035 self.skip_instruction_execution = true;
1036 }
1037
1038 #[doc(hidden)]
1039 pub fn set_ap(&mut self, ap: usize) {
1040 self.run_context.set_ap(ap)
1041 }
1042
1043 #[doc(hidden)]
1044 pub fn set_fp(&mut self, fp: usize) {
1045 self.run_context.set_fp(fp)
1046 }
1047
1048 #[doc(hidden)]
1049 pub fn set_pc(&mut self, pc: Relocatable) {
1050 self.run_context.set_pc(pc)
1051 }
1052
1053 pub fn get_segment_used_size(&self, index: usize) -> Option<usize> {
1054 self.segments.get_segment_used_size(index)
1055 }
1056
1057 pub fn get_segment_size(&self, index: usize) -> Option<usize> {
1058 self.segments.get_segment_size(index)
1059 }
1060
1061 pub fn add_temporary_segment(&mut self) -> Relocatable {
1062 self.segments.add_temporary_segment()
1063 }
1064
1065 pub fn add_relocation_rule(
1076 &mut self,
1077 src_ptr: Relocatable,
1078 #[cfg(not(feature = "extensive_hints"))] dst_ptr: Relocatable,
1079 #[cfg(feature = "extensive_hints")] dst_ptr: MaybeRelocatable,
1080 ) -> Result<(), MemoryError> {
1081 self.segments.memory.add_relocation_rule(src_ptr, dst_ptr)
1082 }
1083
1084 pub fn gen_arg(&mut self, arg: &dyn Any) -> Result<MaybeRelocatable, MemoryError> {
1085 self.segments.gen_arg(arg)
1086 }
1087
1088 pub fn write_output(
1091 &mut self,
1092 writer: &mut impl core::fmt::Write,
1093 ) -> Result<(), VirtualMachineError> {
1094 let builtin = match self
1095 .builtin_runners
1096 .iter()
1097 .find(|b| b.name() == BuiltinName::output)
1098 {
1099 Some(x) => x,
1100 _ => return Ok(()),
1101 };
1102
1103 let segment_used_sizes = self.segments.compute_effective_sizes();
1104 let segment_index = builtin.base();
1105 for i in 0..segment_used_sizes[segment_index] {
1106 let formatted_value = match self
1107 .segments
1108 .memory
1109 .get(&Relocatable::from((segment_index as isize, i)))
1110 {
1111 Some(val) => match val.as_ref() {
1112 MaybeRelocatable::Int(num) => format!("{}", signed_felt(*num)),
1113 MaybeRelocatable::RelocatableValue(rel) => format!("{}", rel),
1114 },
1115 _ => "<missing>".to_string(),
1116 };
1117 writeln!(writer, "{formatted_value}")
1118 .map_err(|_| VirtualMachineError::FailedToWriteOutput)?;
1119 }
1120
1121 Ok(())
1122 }
1123
1124 pub fn get_public_memory_addresses(&self) -> Result<Vec<(usize, usize)>, VirtualMachineError> {
1126 if let Some(relocation_table) = &self.relocation_table {
1127 self.segments
1128 .get_public_memory_addresses(relocation_table)
1129 .map_err(VirtualMachineError::Memory)
1130 } else {
1131 Err(MemoryError::UnrelocatedMemory.into())
1132 }
1133 }
1134
1135 #[doc(hidden)]
1136 pub fn builtins_final_stack_from_stack_pointer_dict(
1137 &mut self,
1138 builtin_name_to_stack_pointer: &HashMap<BuiltinName, Relocatable>,
1139 skip_output: bool,
1140 ) -> Result<(), RunnerError> {
1141 for builtin in self.builtin_runners.iter_mut() {
1142 if matches!(builtin, BuiltinRunner::Output(_)) && skip_output {
1143 continue;
1144 }
1145 builtin.final_stack(
1146 &self.segments,
1147 builtin_name_to_stack_pointer
1148 .get(&builtin.name())
1149 .cloned()
1150 .unwrap_or_default(),
1151 )?;
1152 }
1153 Ok(())
1154 }
1155
1156 #[doc(hidden)]
1157 pub fn set_output_stop_ptr_offset(&mut self, offset: usize) {
1158 if let Some(BuiltinRunner::Output(builtin)) = self.builtin_runners.first_mut() {
1159 builtin.set_stop_ptr_offset(offset);
1160 if let Some(segment_used_sizes) = &mut self.segments.segment_used_sizes {
1161 segment_used_sizes[builtin.base()] = offset;
1162 }
1163 }
1164 }
1165
1166 pub fn mod_builtin_fill_memory(
1171 &mut self,
1172 add_mod_ptr_n: Option<(Relocatable, usize)>,
1173 mul_mod_ptr_n: Option<(Relocatable, usize)>,
1174 batch_size: Option<usize>,
1175 ) -> Result<(), VirtualMachineError> {
1176 let fetch_builtin_params = |mod_params: Option<(Relocatable, usize)>,
1177 mod_name: BuiltinName|
1178 -> Result<
1179 Option<(Relocatable, &ModBuiltinRunner, usize)>,
1180 VirtualMachineError,
1181 > {
1182 if let Some((ptr, n)) = mod_params {
1183 let mod_builtin = self
1184 .builtin_runners
1185 .iter()
1186 .find_map(|b| match b {
1187 BuiltinRunner::Mod(b) if b.name() == mod_name => Some(b),
1188 _ => None,
1189 })
1190 .ok_or_else(|| VirtualMachineError::NoModBuiltin(mod_name))?;
1191 if let Some(batch_size) = batch_size {
1192 if mod_builtin.batch_size() != batch_size {
1193 return Err(VirtualMachineError::ModBuiltinBatchSize(Box::new((
1194 mod_builtin.name(),
1195 batch_size,
1196 ))));
1197 }
1198 }
1199 Ok(Some((ptr, mod_builtin, n)))
1200 } else {
1201 Ok(None)
1202 }
1203 };
1204
1205 ModBuiltinRunner::fill_memory(
1206 &mut self.segments.memory,
1207 fetch_builtin_params(add_mod_ptr_n, BuiltinName::add_mod)?,
1208 fetch_builtin_params(mul_mod_ptr_n, BuiltinName::mul_mod)?,
1209 )
1210 .map_err(VirtualMachineError::RunnerError)
1211 }
1212
1213 pub(crate) fn finalize_segments_by_cairo_pie(&mut self, pie: &CairoPie) {
1214 let mut segment_infos = vec![
1215 &pie.metadata.program_segment,
1216 &pie.metadata.execution_segment,
1217 &pie.metadata.ret_fp_segment,
1218 &pie.metadata.ret_pc_segment,
1219 ];
1220 segment_infos.extend(pie.metadata.builtin_segments.values());
1221 segment_infos.extend(pie.metadata.extra_segments.iter());
1222 for info in segment_infos {
1223 self.segments
1224 .finalize(Some(info.size), info.index as usize, None)
1225 }
1226 }
1227}
1228
1229pub struct VirtualMachineBuilder {
1230 pub(crate) run_context: RunContext,
1231 pub(crate) builtin_runners: Vec<BuiltinRunner>,
1232 pub(crate) segments: MemorySegmentManager,
1233 pub(crate) trace: Option<Vec<TraceEntry>>,
1234 pub(crate) current_step: usize,
1235 skip_instruction_execution: bool,
1236 run_finished: bool,
1237 #[cfg(feature = "test_utils")]
1238 pub(crate) hooks: crate::vm::hooks::Hooks,
1239}
1240
1241impl Default for VirtualMachineBuilder {
1242 fn default() -> Self {
1243 let run_context = RunContext {
1244 pc: Relocatable::from((0, 0)),
1245 ap: 0,
1246 fp: 0,
1247 };
1248
1249 VirtualMachineBuilder {
1250 run_context,
1251 builtin_runners: Vec::new(),
1252 trace: None,
1253 current_step: 0,
1254 skip_instruction_execution: false,
1255 segments: MemorySegmentManager::new(),
1256 run_finished: false,
1257 #[cfg(feature = "test_utils")]
1258 hooks: Default::default(),
1259 }
1260 }
1261}
1262
1263impl VirtualMachineBuilder {
1264 pub fn run_context(mut self, run_context: RunContext) -> VirtualMachineBuilder {
1265 self.run_context = run_context;
1266 self
1267 }
1268
1269 pub fn builtin_runners(mut self, builtin_runners: Vec<BuiltinRunner>) -> VirtualMachineBuilder {
1270 self.builtin_runners = builtin_runners;
1271 self
1272 }
1273
1274 pub fn segments(mut self, segments: MemorySegmentManager) -> VirtualMachineBuilder {
1275 self.segments = segments;
1276 self
1277 }
1278
1279 pub fn trace(mut self, trace: Option<Vec<TraceEntry>>) -> VirtualMachineBuilder {
1280 self.trace = trace;
1281 self
1282 }
1283
1284 pub fn current_step(mut self, current_step: usize) -> VirtualMachineBuilder {
1285 self.current_step = current_step;
1286 self
1287 }
1288
1289 pub fn skip_instruction_execution(
1290 mut self,
1291 skip_instruction_execution: bool,
1292 ) -> VirtualMachineBuilder {
1293 self.skip_instruction_execution = skip_instruction_execution;
1294 self
1295 }
1296
1297 pub fn run_finished(mut self, run_finished: bool) -> VirtualMachineBuilder {
1298 self.run_finished = run_finished;
1299 self
1300 }
1301
1302 #[cfg(feature = "test_utils")]
1303 pub fn hooks(mut self, hooks: crate::vm::hooks::Hooks) -> VirtualMachineBuilder {
1304 self.hooks = hooks;
1305 self
1306 }
1307
1308 pub fn build(self) -> VirtualMachine {
1309 VirtualMachine {
1310 run_context: self.run_context,
1311 builtin_runners: self.builtin_runners,
1312 trace: self.trace,
1313 current_step: self.current_step,
1314 skip_instruction_execution: self.skip_instruction_execution,
1315 segments: self.segments,
1316 rc_limits: None,
1317 run_finished: self.run_finished,
1318 instruction_cache: Vec::new(),
1319 #[cfg(feature = "test_utils")]
1320 hooks: self.hooks,
1321 relocation_table: None,
1322 disable_trace_padding: false,
1323 }
1324 }
1325}
1326
1327#[cfg(test)]
1328mod tests {
1329 use super::*;
1330 use crate::felt_hex;
1331 use crate::math_utils::{qm31_coordinates_to_packed_reduced, STWO_PRIME};
1332 use crate::stdlib::collections::HashMap;
1333 use crate::types::instruction::OpcodeExtension;
1334 use crate::types::layout_name::LayoutName;
1335 use crate::types::program::Program;
1336 use crate::{
1337 any_box,
1338 hint_processor::builtin_hint_processor::builtin_hint_processor_definition::{
1339 BuiltinHintProcessor, HintProcessorData,
1340 },
1341 relocatable,
1342 types::{
1343 instruction::{Op1Addr, Register},
1344 relocatable::Relocatable,
1345 },
1346 utils::test_utils::*,
1347 vm::{
1348 errors::memory_errors::MemoryError,
1349 runners::builtin_runner::{BitwiseBuiltinRunner, EcOpBuiltinRunner, HashBuiltinRunner},
1350 },
1351 };
1352 use assert_matches::assert_matches;
1353
1354 #[cfg(target_arch = "wasm32")]
1355 use wasm_bindgen_test::*;
1356
1357 #[test]
1358 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1359 fn update_fp_ap_plus2() {
1360 let instruction = Instruction {
1361 off0: 1,
1362 off1: 2,
1363 off2: 3,
1364 dst_register: Register::FP,
1365 op0_register: Register::AP,
1366 op1_addr: Op1Addr::AP,
1367 res: Res::Add,
1368 pc_update: PcUpdate::Regular,
1369 ap_update: ApUpdate::Regular,
1370 fp_update: FpUpdate::APPlus2,
1371 opcode: Opcode::NOp,
1372 opcode_extension: OpcodeExtension::Stone,
1373 };
1374
1375 let operands = Operands {
1376 dst: MaybeRelocatable::Int(Felt252::from(11)),
1377 res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1378 op0: MaybeRelocatable::Int(Felt252::from(9)),
1379 op1: MaybeRelocatable::Int(Felt252::from(10)),
1380 };
1381
1382 let mut vm = vm!();
1383 run_context!(vm, 4, 5, 6);
1384 assert_matches!(
1385 vm.update_fp(&instruction, &operands),
1386 Ok::<(), VirtualMachineError>(())
1387 );
1388 assert_eq!(vm.run_context.fp, 7)
1389 }
1390
1391 #[test]
1392 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1393 fn update_fp_dst() {
1394 let instruction = Instruction {
1395 off0: 1,
1396 off1: 2,
1397 off2: 3,
1398 dst_register: Register::FP,
1399 op0_register: Register::AP,
1400 op1_addr: Op1Addr::AP,
1401 res: Res::Add,
1402 pc_update: PcUpdate::Regular,
1403 ap_update: ApUpdate::Regular,
1404 fp_update: FpUpdate::Dst,
1405 opcode: Opcode::NOp,
1406 opcode_extension: OpcodeExtension::Stone,
1407 };
1408
1409 let operands = Operands {
1410 dst: mayberelocatable!(1, 6),
1411 res: Some(mayberelocatable!(8)),
1412 op0: mayberelocatable!(9),
1413 op1: mayberelocatable!(10),
1414 };
1415
1416 let mut vm = vm!();
1417
1418 assert_matches!(
1419 vm.update_fp(&instruction, &operands),
1420 Ok::<(), VirtualMachineError>(())
1421 );
1422 assert_eq!(vm.run_context.fp, 6)
1423 }
1424
1425 #[test]
1426 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1427 fn update_fp_regular() {
1428 let instruction = Instruction {
1429 off0: 1,
1430 off1: 2,
1431 off2: 3,
1432 dst_register: Register::FP,
1433 op0_register: Register::AP,
1434 op1_addr: Op1Addr::AP,
1435 res: Res::Add,
1436 pc_update: PcUpdate::Regular,
1437 ap_update: ApUpdate::Regular,
1438 fp_update: FpUpdate::Regular,
1439 opcode: Opcode::NOp,
1440 opcode_extension: OpcodeExtension::Stone,
1441 };
1442
1443 let operands = Operands {
1444 dst: MaybeRelocatable::Int(Felt252::from(11_u64)),
1445 res: Some(MaybeRelocatable::Int(Felt252::from(8_u64))),
1446 op0: MaybeRelocatable::Int(Felt252::from(9_u64)),
1447 op1: MaybeRelocatable::Int(Felt252::from(10_u64)),
1448 };
1449
1450 let mut vm = vm!();
1451
1452 assert_matches!(
1453 vm.update_fp(&instruction, &operands),
1454 Ok::<(), VirtualMachineError>(())
1455 );
1456 assert_eq!(vm.run_context.fp, 0)
1457 }
1458
1459 #[test]
1460 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1461 fn update_fp_dst_num() {
1462 let instruction = Instruction {
1463 off0: 1,
1464 off1: 2,
1465 off2: 3,
1466 dst_register: Register::FP,
1467 op0_register: Register::AP,
1468 op1_addr: Op1Addr::AP,
1469 res: Res::Add,
1470 pc_update: PcUpdate::Regular,
1471 ap_update: ApUpdate::Regular,
1472 fp_update: FpUpdate::Dst,
1473 opcode: Opcode::NOp,
1474 opcode_extension: OpcodeExtension::Stone,
1475 };
1476
1477 let operands = Operands {
1478 dst: MaybeRelocatable::Int(Felt252::from(11)),
1479 res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1480 op0: MaybeRelocatable::Int(Felt252::from(9)),
1481 op1: MaybeRelocatable::Int(Felt252::from(10)),
1482 };
1483
1484 let mut vm = vm!();
1485 run_context!(vm, 4, 5, 6);
1486
1487 assert_matches!(
1488 vm.update_fp(&instruction, &operands),
1489 Ok::<(), VirtualMachineError>(())
1490 );
1491 assert_eq!(vm.run_context.fp, 11)
1492 }
1493
1494 #[test]
1495 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1496 fn update_ap_add_with_res() {
1497 let instruction = Instruction {
1498 off0: 1,
1499 off1: 2,
1500 off2: 3,
1501 dst_register: Register::FP,
1502 op0_register: Register::AP,
1503 op1_addr: Op1Addr::AP,
1504 res: Res::Add,
1505 pc_update: PcUpdate::Regular,
1506 ap_update: ApUpdate::Add,
1507 fp_update: FpUpdate::Regular,
1508 opcode: Opcode::NOp,
1509 opcode_extension: OpcodeExtension::Stone,
1510 };
1511
1512 let operands = Operands {
1513 dst: MaybeRelocatable::Int(Felt252::from(11)),
1514 res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1515 op0: MaybeRelocatable::Int(Felt252::from(9)),
1516 op1: MaybeRelocatable::Int(Felt252::from(10)),
1517 };
1518
1519 let mut vm = VirtualMachine::new(false, false);
1520 vm.run_context.pc = Relocatable::from((0, 4));
1521 vm.run_context.ap = 5;
1522 vm.run_context.fp = 6;
1523
1524 assert_matches!(
1525 vm.update_ap(&instruction, &operands),
1526 Ok::<(), VirtualMachineError>(())
1527 );
1528 assert_eq!(vm.run_context.ap, 13);
1529 }
1530
1531 #[test]
1532 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1533 fn update_ap_add_without_res() {
1534 let instruction = Instruction {
1535 off0: 1,
1536 off1: 2,
1537 off2: 3,
1538 dst_register: Register::FP,
1539 op0_register: Register::AP,
1540 op1_addr: Op1Addr::AP,
1541 res: Res::Add,
1542 pc_update: PcUpdate::Regular,
1543 ap_update: ApUpdate::Add,
1544 fp_update: FpUpdate::Regular,
1545 opcode: Opcode::NOp,
1546 opcode_extension: OpcodeExtension::Stone,
1547 };
1548
1549 let operands = Operands {
1550 dst: MaybeRelocatable::Int(Felt252::from(11)),
1551 res: None,
1552 op0: MaybeRelocatable::Int(Felt252::from(9)),
1553 op1: MaybeRelocatable::Int(Felt252::from(10)),
1554 };
1555
1556 let mut vm = vm!();
1557 vm.run_context.pc = Relocatable::from((0, 4));
1558 vm.run_context.ap = 5;
1559 vm.run_context.fp = 6;
1560
1561 assert_matches!(
1562 vm.update_ap(&instruction, &operands),
1563 Err(VirtualMachineError::UnconstrainedResAdd)
1564 );
1565 }
1566
1567 #[test]
1568 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1569 fn update_ap_add1() {
1570 let instruction = Instruction {
1571 off0: 1,
1572 off1: 2,
1573 off2: 3,
1574 dst_register: Register::FP,
1575 op0_register: Register::AP,
1576 op1_addr: Op1Addr::AP,
1577 res: Res::Add,
1578 pc_update: PcUpdate::Regular,
1579 ap_update: ApUpdate::Add1,
1580 fp_update: FpUpdate::Regular,
1581 opcode: Opcode::NOp,
1582 opcode_extension: OpcodeExtension::Stone,
1583 };
1584
1585 let operands = Operands {
1586 dst: MaybeRelocatable::Int(Felt252::from(11)),
1587 res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1588 op0: MaybeRelocatable::Int(Felt252::from(9)),
1589 op1: MaybeRelocatable::Int(Felt252::from(10)),
1590 };
1591
1592 let mut vm = vm!();
1593 vm.run_context.pc = Relocatable::from((0, 4));
1594 vm.run_context.ap = 5;
1595 vm.run_context.fp = 6;
1596
1597 assert_matches!(
1598 vm.update_ap(&instruction, &operands),
1599 Ok::<(), VirtualMachineError>(())
1600 );
1601 assert_eq!(vm.run_context.ap, 6);
1602 }
1603
1604 #[test]
1605 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1606 fn update_ap_add2() {
1607 let instruction = Instruction {
1608 off0: 1,
1609 off1: 2,
1610 off2: 3,
1611 dst_register: Register::FP,
1612 op0_register: Register::AP,
1613 op1_addr: Op1Addr::AP,
1614 res: Res::Add,
1615 pc_update: PcUpdate::Regular,
1616 ap_update: ApUpdate::Add2,
1617 fp_update: FpUpdate::Regular,
1618 opcode: Opcode::NOp,
1619 opcode_extension: OpcodeExtension::Stone,
1620 };
1621
1622 let operands = Operands {
1623 dst: MaybeRelocatable::Int(Felt252::from(11_u64)),
1624 res: Some(MaybeRelocatable::Int(Felt252::from(8_u64))),
1625 op0: MaybeRelocatable::Int(Felt252::from(9_u64)),
1626 op1: MaybeRelocatable::Int(Felt252::from(10_u64)),
1627 };
1628
1629 let mut vm = vm!();
1630 vm.run_context.pc = Relocatable::from((0, 4));
1631 vm.run_context.ap = 5;
1632 vm.run_context.fp = 6;
1633
1634 assert_matches!(
1635 vm.update_ap(&instruction, &operands),
1636 Ok::<(), VirtualMachineError>(())
1637 );
1638 assert_eq!(vm.run_context.ap, 7);
1639 }
1640
1641 #[test]
1642 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1643 fn update_ap_regular() {
1644 let instruction = Instruction {
1645 off0: 1,
1646 off1: 2,
1647 off2: 3,
1648 dst_register: Register::FP,
1649 op0_register: Register::AP,
1650 op1_addr: Op1Addr::AP,
1651 res: Res::Add,
1652 pc_update: PcUpdate::Regular,
1653 ap_update: ApUpdate::Regular,
1654 fp_update: FpUpdate::Regular,
1655 opcode: Opcode::NOp,
1656 opcode_extension: OpcodeExtension::Stone,
1657 };
1658
1659 let operands = Operands {
1660 dst: MaybeRelocatable::Int(Felt252::from(11)),
1661 res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1662 op0: MaybeRelocatable::Int(Felt252::from(9)),
1663 op1: MaybeRelocatable::Int(Felt252::from(10)),
1664 };
1665
1666 let mut vm = vm!();
1667 vm.run_context.pc = Relocatable::from((0, 4));
1668 vm.run_context.ap = 5;
1669 vm.run_context.fp = 6;
1670
1671 assert_matches!(
1672 vm.update_ap(&instruction, &operands),
1673 Ok::<(), VirtualMachineError>(())
1674 );
1675 assert_eq!(vm.run_context.ap, 5);
1676 }
1677
1678 #[test]
1679 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1680 fn update_pc_regular_instruction_no_imm() {
1681 let instruction = Instruction {
1682 off0: 1,
1683 off1: 2,
1684 off2: 3,
1685 dst_register: Register::FP,
1686 op0_register: Register::AP,
1687 op1_addr: Op1Addr::AP,
1688 res: Res::Add,
1689 pc_update: PcUpdate::Regular,
1690 ap_update: ApUpdate::Regular,
1691 fp_update: FpUpdate::Regular,
1692 opcode: Opcode::NOp,
1693 opcode_extension: OpcodeExtension::Stone,
1694 };
1695
1696 let operands = Operands {
1697 dst: MaybeRelocatable::Int(Felt252::from(11)),
1698 res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1699 op0: MaybeRelocatable::Int(Felt252::from(9)),
1700 op1: MaybeRelocatable::Int(Felt252::from(10)),
1701 };
1702
1703 let mut vm = vm!();
1704
1705 assert_matches!(
1706 vm.update_pc(&instruction, &operands),
1707 Ok::<(), VirtualMachineError>(())
1708 );
1709 assert_eq!(vm.run_context.pc, Relocatable::from((0, 1)));
1710 }
1711
1712 #[test]
1713 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1714 fn update_pc_regular_instruction_has_imm() {
1715 let instruction = Instruction {
1716 off0: 1,
1717 off1: 2,
1718 off2: 3,
1719 dst_register: Register::FP,
1720 op0_register: Register::AP,
1721 op1_addr: Op1Addr::Imm,
1722 res: Res::Add,
1723 pc_update: PcUpdate::Regular,
1724 ap_update: ApUpdate::Regular,
1725 fp_update: FpUpdate::Regular,
1726 opcode: Opcode::NOp,
1727 opcode_extension: OpcodeExtension::Stone,
1728 };
1729
1730 let operands = Operands {
1731 dst: MaybeRelocatable::Int(Felt252::from(11)),
1732 res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1733 op0: MaybeRelocatable::Int(Felt252::from(9)),
1734 op1: MaybeRelocatable::Int(Felt252::from(10)),
1735 };
1736
1737 let mut vm = vm!();
1738
1739 assert_matches!(
1740 vm.update_pc(&instruction, &operands),
1741 Ok::<(), VirtualMachineError>(())
1742 );
1743 assert_eq!(vm.run_context.pc, Relocatable::from((0, 2)));
1744 }
1745
1746 #[test]
1747 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1748 fn update_pc_jump_with_res() {
1749 let instruction = Instruction {
1750 off0: 1,
1751 off1: 2,
1752 off2: 3,
1753 dst_register: Register::FP,
1754 op0_register: Register::AP,
1755 op1_addr: Op1Addr::AP,
1756 res: Res::Add,
1757 pc_update: PcUpdate::Jump,
1758 ap_update: ApUpdate::Regular,
1759 fp_update: FpUpdate::Regular,
1760 opcode: Opcode::NOp,
1761 opcode_extension: OpcodeExtension::Stone,
1762 };
1763
1764 let operands = Operands {
1765 dst: mayberelocatable!(1, 11),
1766 res: Some(mayberelocatable!(0, 8)),
1767 op0: MaybeRelocatable::Int(Felt252::from(9)),
1768 op1: MaybeRelocatable::Int(Felt252::from(10)),
1769 };
1770
1771 let mut vm = vm!();
1772
1773 assert_matches!(
1774 vm.update_pc(&instruction, &operands),
1775 Ok::<(), VirtualMachineError>(())
1776 );
1777 assert_eq!(vm.run_context.pc, Relocatable::from((0, 8)));
1778 }
1779
1780 #[test]
1781 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1782 fn update_pc_jump_without_res() {
1783 let instruction = Instruction {
1784 off0: 1,
1785 off1: 2,
1786 off2: 3,
1787 dst_register: Register::FP,
1788 op0_register: Register::AP,
1789 op1_addr: Op1Addr::AP,
1790 res: Res::Add,
1791 pc_update: PcUpdate::Jump,
1792 ap_update: ApUpdate::Regular,
1793 fp_update: FpUpdate::Regular,
1794 opcode: Opcode::NOp,
1795 opcode_extension: OpcodeExtension::Stone,
1796 };
1797
1798 let operands = Operands {
1799 dst: MaybeRelocatable::Int(Felt252::from(11)),
1800 res: None,
1801 op0: MaybeRelocatable::Int(Felt252::from(9)),
1802 op1: MaybeRelocatable::Int(Felt252::from(10)),
1803 };
1804
1805 let mut vm = vm!();
1806 vm.run_context.pc = Relocatable::from((0, 4));
1807 vm.run_context.ap = 5;
1808 vm.run_context.fp = 6;
1809
1810 assert_matches!(
1811 vm.update_pc(&instruction, &operands),
1812 Err(VirtualMachineError::UnconstrainedResJump)
1813 );
1814 }
1815
1816 #[test]
1817 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1818 fn update_pc_jump_rel_with_int_res() {
1819 let instruction = Instruction {
1820 off0: 1,
1821 off1: 2,
1822 off2: 3,
1823 dst_register: Register::FP,
1824 op0_register: Register::AP,
1825 op1_addr: Op1Addr::AP,
1826 res: Res::Add,
1827 pc_update: PcUpdate::JumpRel,
1828 ap_update: ApUpdate::Regular,
1829 fp_update: FpUpdate::Regular,
1830 opcode: Opcode::NOp,
1831 opcode_extension: OpcodeExtension::Stone,
1832 };
1833
1834 let operands = Operands {
1835 dst: MaybeRelocatable::Int(Felt252::from(11)),
1836 res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1837 op0: MaybeRelocatable::Int(Felt252::from(9)),
1838 op1: MaybeRelocatable::Int(Felt252::from(10)),
1839 };
1840
1841 let mut vm = vm!();
1842 run_context!(vm, 1, 1, 1);
1843
1844 assert_matches!(
1845 vm.update_pc(&instruction, &operands),
1846 Ok::<(), VirtualMachineError>(())
1847 );
1848 assert_eq!(vm.run_context.pc, Relocatable::from((0, 9)));
1849 }
1850
1851 #[test]
1852 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1853 fn update_pc_jump_rel_without_res() {
1854 let instruction = Instruction {
1855 off0: 1,
1856 off1: 2,
1857 off2: 3,
1858 dst_register: Register::FP,
1859 op0_register: Register::AP,
1860 op1_addr: Op1Addr::AP,
1861 res: Res::Add,
1862 pc_update: PcUpdate::JumpRel,
1863 ap_update: ApUpdate::Regular,
1864 fp_update: FpUpdate::Regular,
1865 opcode: Opcode::NOp,
1866 opcode_extension: OpcodeExtension::Stone,
1867 };
1868
1869 let operands = Operands {
1870 dst: MaybeRelocatable::Int(Felt252::from(11)),
1871 res: None,
1872 op0: MaybeRelocatable::Int(Felt252::from(9)),
1873 op1: MaybeRelocatable::Int(Felt252::from(10)),
1874 };
1875
1876 let mut vm = vm!();
1877
1878 assert_matches!(
1879 vm.update_pc(&instruction, &operands),
1880 Err(VirtualMachineError::UnconstrainedResJumpRel)
1881 );
1882 }
1883
1884 #[test]
1885 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1886 fn update_pc_jump_rel_with_non_int_res() {
1887 let instruction = Instruction {
1888 off0: 1,
1889 off1: 2,
1890 off2: 3,
1891 dst_register: Register::FP,
1892 op0_register: Register::AP,
1893 op1_addr: Op1Addr::AP,
1894 res: Res::Add,
1895 pc_update: PcUpdate::JumpRel,
1896 ap_update: ApUpdate::Regular,
1897 fp_update: FpUpdate::Regular,
1898 opcode: Opcode::NOp,
1899 opcode_extension: OpcodeExtension::Stone,
1900 };
1901
1902 let operands = Operands {
1903 dst: MaybeRelocatable::Int(Felt252::from(11)),
1904 res: Some(MaybeRelocatable::from((1, 4))),
1905 op0: MaybeRelocatable::Int(Felt252::from(9)),
1906 op1: MaybeRelocatable::Int(Felt252::from(10)),
1907 };
1908
1909 let mut vm = vm!();
1910 assert_matches!(
1911 vm.update_pc(&instruction, &operands),
1912 Err::<(), VirtualMachineError>(VirtualMachineError::JumpRelNotInt)
1913 );
1914 }
1915
1916 #[test]
1917 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1918 fn update_pc_jnz_dst_is_zero() {
1919 let instruction = Instruction {
1920 off0: 1,
1921 off1: 2,
1922 off2: 3,
1923 dst_register: Register::FP,
1924 op0_register: Register::AP,
1925 op1_addr: Op1Addr::AP,
1926 res: Res::Add,
1927 pc_update: PcUpdate::Jnz,
1928 ap_update: ApUpdate::Regular,
1929 fp_update: FpUpdate::Regular,
1930 opcode: Opcode::NOp,
1931 opcode_extension: OpcodeExtension::Stone,
1932 };
1933
1934 let operands = Operands {
1935 dst: MaybeRelocatable::Int(Felt252::from(0)),
1936 res: Some(MaybeRelocatable::Int(Felt252::from(0))),
1937 op0: MaybeRelocatable::Int(Felt252::from(9)),
1938 op1: MaybeRelocatable::Int(Felt252::from(10)),
1939 };
1940
1941 let mut vm = vm!();
1942
1943 assert_matches!(
1944 vm.update_pc(&instruction, &operands),
1945 Ok::<(), VirtualMachineError>(())
1946 );
1947 assert_eq!(vm.run_context.pc, Relocatable::from((0, 1)));
1948 }
1949
1950 #[test]
1951 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1952 fn update_pc_jnz_dst_is_not_zero() {
1953 let instruction = Instruction {
1954 off0: 1,
1955 off1: 2,
1956 off2: 3,
1957 dst_register: Register::FP,
1958 op0_register: Register::AP,
1959 op1_addr: Op1Addr::AP,
1960 res: Res::Add,
1961 pc_update: PcUpdate::Jnz,
1962 ap_update: ApUpdate::Regular,
1963 fp_update: FpUpdate::Regular,
1964 opcode: Opcode::NOp,
1965 opcode_extension: OpcodeExtension::Stone,
1966 };
1967
1968 let operands = Operands {
1969 dst: MaybeRelocatable::Int(Felt252::from(11)),
1970 res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1971 op0: MaybeRelocatable::Int(Felt252::from(9)),
1972 op1: MaybeRelocatable::Int(Felt252::from(10)),
1973 };
1974
1975 let mut vm = vm!();
1976
1977 assert_matches!(
1978 vm.update_pc(&instruction, &operands),
1979 Ok::<(), VirtualMachineError>(())
1980 );
1981 assert_eq!(vm.run_context.pc, Relocatable::from((0, 10)));
1982 }
1983
1984 #[test]
1985 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1986 fn update_registers_all_regular() {
1987 let instruction = Instruction {
1988 off0: 1,
1989 off1: 2,
1990 off2: 3,
1991 dst_register: Register::FP,
1992 op0_register: Register::AP,
1993 op1_addr: Op1Addr::AP,
1994 res: Res::Add,
1995 pc_update: PcUpdate::Regular,
1996 ap_update: ApUpdate::Regular,
1997 fp_update: FpUpdate::Regular,
1998 opcode: Opcode::NOp,
1999 opcode_extension: OpcodeExtension::Stone,
2000 };
2001
2002 let operands = Operands {
2003 dst: MaybeRelocatable::Int(Felt252::from(11)),
2004 res: Some(MaybeRelocatable::Int(Felt252::from(8))),
2005 op0: MaybeRelocatable::Int(Felt252::from(9)),
2006 op1: MaybeRelocatable::Int(Felt252::from(10)),
2007 };
2008
2009 let mut vm = vm!();
2010 vm.run_context.pc = Relocatable::from((0, 4));
2011 vm.run_context.ap = 5;
2012 vm.run_context.fp = 6;
2013
2014 assert_matches!(
2015 vm.update_registers(&instruction, operands),
2016 Ok::<(), VirtualMachineError>(())
2017 );
2018 assert_eq!(vm.run_context.pc, Relocatable::from((0, 5)));
2019 assert_eq!(vm.run_context.ap, 5);
2020 assert_eq!(vm.run_context.fp, 6);
2021 }
2022
2023 #[test]
2024 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2025 fn update_registers_mixed_types() {
2026 let instruction = Instruction {
2027 off0: 1,
2028 off1: 2,
2029 off2: 3,
2030 dst_register: Register::FP,
2031 op0_register: Register::AP,
2032 op1_addr: Op1Addr::AP,
2033 res: Res::Add,
2034 pc_update: PcUpdate::JumpRel,
2035 ap_update: ApUpdate::Add2,
2036 fp_update: FpUpdate::Dst,
2037 opcode: Opcode::NOp,
2038 opcode_extension: OpcodeExtension::Stone,
2039 };
2040
2041 let operands = Operands {
2042 dst: MaybeRelocatable::from((1, 11)),
2043 res: Some(MaybeRelocatable::Int(Felt252::from(8))),
2044 op0: MaybeRelocatable::Int(Felt252::from(9)),
2045 op1: MaybeRelocatable::Int(Felt252::from(10)),
2046 };
2047
2048 let mut vm = vm!();
2049 run_context!(vm, 4, 5, 6);
2050
2051 assert_matches!(
2052 vm.update_registers(&instruction, operands),
2053 Ok::<(), VirtualMachineError>(())
2054 );
2055 assert_eq!(vm.run_context.pc, Relocatable::from((0, 12)));
2056 assert_eq!(vm.run_context.ap, 7);
2057 assert_eq!(vm.run_context.fp, 11);
2058 }
2059
2060 #[test]
2061 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2062 fn is_zero_int_value() {
2063 let value = MaybeRelocatable::Int(Felt252::from(1));
2064 assert!(!VirtualMachine::is_zero(&value));
2065 }
2066
2067 #[test]
2068 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2069 fn is_zero_relocatable_value() {
2070 let value = MaybeRelocatable::from((1, 2));
2071 assert!(!VirtualMachine::is_zero(&value));
2072 }
2073
2074 #[test]
2075 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2076 fn deduce_op0_opcode_call() {
2077 let instruction = Instruction {
2078 off0: 1,
2079 off1: 2,
2080 off2: 3,
2081 dst_register: Register::FP,
2082 op0_register: Register::AP,
2083 op1_addr: Op1Addr::AP,
2084 res: Res::Add,
2085 pc_update: PcUpdate::Jump,
2086 ap_update: ApUpdate::Regular,
2087 fp_update: FpUpdate::Regular,
2088 opcode: Opcode::Call,
2089 opcode_extension: OpcodeExtension::Stone,
2090 };
2091
2092 let vm = vm!();
2093
2094 assert_matches!(
2095 vm.deduce_op0(&instruction, None, None),
2096 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2097 Some(x),
2098 None
2099 )) if x == MaybeRelocatable::from((0, 1))
2100 );
2101 }
2102
2103 #[test]
2104 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2105 fn deduce_op0_opcode_assert_eq_res_add_with_optionals() {
2106 let instruction = Instruction {
2107 off0: 1,
2108 off1: 2,
2109 off2: 3,
2110 dst_register: Register::FP,
2111 op0_register: Register::AP,
2112 op1_addr: Op1Addr::AP,
2113 res: Res::Add,
2114 pc_update: PcUpdate::Jump,
2115 ap_update: ApUpdate::Regular,
2116 fp_update: FpUpdate::Regular,
2117 opcode: Opcode::AssertEq,
2118 opcode_extension: OpcodeExtension::Stone,
2119 };
2120
2121 let vm = vm!();
2122
2123 let dst = MaybeRelocatable::Int(Felt252::from(3));
2124 let op1 = MaybeRelocatable::Int(Felt252::from(2));
2125
2126 assert_matches!(
2127 vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2128 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2129 x,
2130 y
2131 )) if x == Some(MaybeRelocatable::Int(Felt252::from(1))) &&
2132 y == Some(MaybeRelocatable::Int(Felt252::from(3)))
2133 );
2134 }
2135
2136 #[test]
2137 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2138 fn deduce_op0_opcode_assert_eq_res_add_without_optionals() {
2139 let instruction = Instruction {
2140 off0: 1,
2141 off1: 2,
2142 off2: 3,
2143 dst_register: Register::FP,
2144 op0_register: Register::AP,
2145 op1_addr: Op1Addr::AP,
2146 res: Res::Add,
2147 pc_update: PcUpdate::Jump,
2148 ap_update: ApUpdate::Regular,
2149 fp_update: FpUpdate::Regular,
2150 opcode: Opcode::AssertEq,
2151 opcode_extension: OpcodeExtension::Stone,
2152 };
2153
2154 let vm = vm!();
2155
2156 assert_matches!(
2157 vm.deduce_op0(&instruction, None, None),
2158 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2159 None, None
2160 ))
2161 );
2162 }
2163
2164 #[test]
2165 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2166 fn deduce_op0_opcode_assert_eq_res_mul_non_zero_op1() {
2167 let instruction = Instruction {
2168 off0: 1,
2169 off1: 2,
2170 off2: 3,
2171 dst_register: Register::FP,
2172 op0_register: Register::AP,
2173 op1_addr: Op1Addr::AP,
2174 res: Res::Mul,
2175 pc_update: PcUpdate::Jump,
2176 ap_update: ApUpdate::Regular,
2177 fp_update: FpUpdate::Regular,
2178 opcode: Opcode::AssertEq,
2179 opcode_extension: OpcodeExtension::Stone,
2180 };
2181
2182 let vm = vm!();
2183
2184 let dst = MaybeRelocatable::Int(Felt252::from(4));
2185 let op1 = MaybeRelocatable::Int(Felt252::from(2));
2186
2187 assert_matches!(
2188 vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2189 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2190 Some(x),
2191 Some(y)
2192 )) if x == MaybeRelocatable::Int(Felt252::from(2)) &&
2193 y == MaybeRelocatable::Int(Felt252::from(4))
2194 );
2195 }
2196
2197 #[test]
2198 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2199 fn deduce_op0_opcode_assert_eq_res_mul_zero_op1() {
2200 let instruction = Instruction {
2201 off0: 1,
2202 off1: 2,
2203 off2: 3,
2204 dst_register: Register::FP,
2205 op0_register: Register::AP,
2206 op1_addr: Op1Addr::AP,
2207 res: Res::Mul,
2208 pc_update: PcUpdate::Jump,
2209 ap_update: ApUpdate::Regular,
2210 fp_update: FpUpdate::Regular,
2211 opcode: Opcode::AssertEq,
2212 opcode_extension: OpcodeExtension::Stone,
2213 };
2214
2215 let vm = vm!();
2216
2217 let dst = MaybeRelocatable::Int(Felt252::from(4));
2218 let op1 = MaybeRelocatable::Int(Felt252::from(0));
2219 assert_matches!(
2220 vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2221 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2222 None, None
2223 ))
2224 );
2225 }
2226
2227 #[test]
2228 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2229 fn deduce_op0_opcode_assert_eq_res_op1() {
2230 let instruction = Instruction {
2231 off0: 1,
2232 off1: 2,
2233 off2: 3,
2234 dst_register: Register::FP,
2235 op0_register: Register::AP,
2236 op1_addr: Op1Addr::AP,
2237 res: Res::Op1,
2238 pc_update: PcUpdate::Jump,
2239 ap_update: ApUpdate::Regular,
2240 fp_update: FpUpdate::Regular,
2241 opcode: Opcode::AssertEq,
2242 opcode_extension: OpcodeExtension::Stone,
2243 };
2244
2245 let vm = vm!();
2246
2247 let dst = MaybeRelocatable::Int(Felt252::from(4));
2248 let op1 = MaybeRelocatable::Int(Felt252::from(0));
2249 assert_matches!(
2250 vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2251 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2252 None, None
2253 ))
2254 );
2255 }
2256
2257 #[test]
2258 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2259 fn deduce_op0_opcode_ret() {
2260 let instruction = Instruction {
2261 off0: 1,
2262 off1: 2,
2263 off2: 3,
2264 dst_register: Register::FP,
2265 op0_register: Register::AP,
2266 op1_addr: Op1Addr::AP,
2267 res: Res::Mul,
2268 pc_update: PcUpdate::Jump,
2269 ap_update: ApUpdate::Regular,
2270 fp_update: FpUpdate::Regular,
2271 opcode: Opcode::Ret,
2272 opcode_extension: OpcodeExtension::Stone,
2273 };
2274
2275 let vm = vm!();
2276
2277 let dst = MaybeRelocatable::Int(Felt252::from(4));
2278 let op1 = MaybeRelocatable::Int(Felt252::from(0));
2279
2280 assert_matches!(
2281 vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2282 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2283 None, None
2284 ))
2285 );
2286 }
2287
2288 #[test]
2289 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2290 fn deduce_op0_qm31_add_int_operands() {
2291 let instruction = Instruction {
2292 off0: 1,
2293 off1: 2,
2294 off2: 3,
2295 dst_register: Register::FP,
2296 op0_register: Register::AP,
2297 op1_addr: Op1Addr::AP,
2298 res: Res::Add,
2299 pc_update: PcUpdate::Regular,
2300 ap_update: ApUpdate::Regular,
2301 fp_update: FpUpdate::Regular,
2302 opcode: Opcode::AssertEq,
2303 opcode_extension: OpcodeExtension::QM31Operation,
2304 };
2305
2306 let vm = vm!();
2307
2308 let op1_coordinates = [STWO_PRIME - 10, 5, STWO_PRIME - 5, 1];
2309 let dst_coordinates = [STWO_PRIME - 4, 2, 12, 3];
2310 let op1_packed = qm31_coordinates_to_packed_reduced(op1_coordinates);
2311 let dst_packed = qm31_coordinates_to_packed_reduced(dst_coordinates);
2312 let op1 = MaybeRelocatable::Int(op1_packed);
2313 let dst = MaybeRelocatable::Int(dst_packed);
2314 assert_matches!(
2315 vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2316 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2317 x,
2318 y
2319 )) if x == Some(MaybeRelocatable::Int(qm31_coordinates_to_packed_reduced([6, STWO_PRIME-3, 17, 2]))) &&
2320 y == Some(MaybeRelocatable::Int(dst_packed))
2321 );
2322 }
2323
2324 #[test]
2325 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2326 fn deduce_op0_qm31_mul_int_operands() {
2327 let instruction = Instruction {
2328 off0: 1,
2329 off1: 2,
2330 off2: 3,
2331 dst_register: Register::FP,
2332 op0_register: Register::AP,
2333 op1_addr: Op1Addr::AP,
2334 res: Res::Mul,
2335 pc_update: PcUpdate::Regular,
2336 ap_update: ApUpdate::Regular,
2337 fp_update: FpUpdate::Regular,
2338 opcode: Opcode::AssertEq,
2339 opcode_extension: OpcodeExtension::QM31Operation,
2340 };
2341
2342 let vm = vm!();
2343
2344 let op1_coordinates = [0, 0, 1, 0];
2345 let dst_coordinates = [0, 0, 0, 1];
2346 let op1_packed = qm31_coordinates_to_packed_reduced(op1_coordinates);
2347 let dst_packed = qm31_coordinates_to_packed_reduced(dst_coordinates);
2348 let op1 = MaybeRelocatable::Int(op1_packed);
2349 let dst = MaybeRelocatable::Int(dst_packed);
2350 assert_matches!(
2351 vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2352 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2353 x,
2354 y
2355 )) if x == Some(MaybeRelocatable::Int(qm31_coordinates_to_packed_reduced([0, 1, 0, 0]))) &&
2356 y == Some(MaybeRelocatable::Int(dst_packed))
2357 );
2358 }
2359
2360 #[test]
2361 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2362 fn deduce_op0_blake_finalize_add_int_operands() {
2363 let instruction = Instruction {
2364 off0: 1,
2365 off1: 2,
2366 off2: 3,
2367 dst_register: Register::FP,
2368 op0_register: Register::AP,
2369 op1_addr: Op1Addr::AP,
2370 res: Res::Add,
2371 pc_update: PcUpdate::Regular,
2372 ap_update: ApUpdate::Regular,
2373 fp_update: FpUpdate::Regular,
2374 opcode: Opcode::AssertEq,
2375 opcode_extension: OpcodeExtension::BlakeFinalize,
2376 };
2377
2378 let vm = vm!();
2379
2380 let op1 = MaybeRelocatable::Int(Felt252::from(5));
2381 let dst = MaybeRelocatable::Int(Felt252::from(15));
2382 assert_matches!(
2383 vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2384 Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension(ref message)) if message.as_ref() == "typed_sub"
2385 );
2386 }
2387
2388 #[test]
2389 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2390 fn deduce_op1_opcode_call() {
2391 let instruction = Instruction {
2392 off0: 1,
2393 off1: 2,
2394 off2: 3,
2395 dst_register: Register::FP,
2396 op0_register: Register::AP,
2397 op1_addr: Op1Addr::AP,
2398 res: Res::Add,
2399 pc_update: PcUpdate::Jump,
2400 ap_update: ApUpdate::Regular,
2401 fp_update: FpUpdate::Regular,
2402 opcode: Opcode::Call,
2403 opcode_extension: OpcodeExtension::Stone,
2404 };
2405
2406 let vm = vm!();
2407
2408 assert_matches!(
2409 vm.deduce_op1(&instruction, None, None),
2410 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2411 None, None
2412 ))
2413 );
2414 }
2415
2416 #[test]
2417 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2418 fn deduce_op1_opcode_assert_eq_res_add_with_optionals() {
2419 let instruction = Instruction {
2420 off0: 1,
2421 off1: 2,
2422 off2: 3,
2423 dst_register: Register::FP,
2424 op0_register: Register::AP,
2425 op1_addr: Op1Addr::AP,
2426 res: Res::Add,
2427 pc_update: PcUpdate::Jump,
2428 ap_update: ApUpdate::Regular,
2429 fp_update: FpUpdate::Regular,
2430 opcode: Opcode::AssertEq,
2431 opcode_extension: OpcodeExtension::Stone,
2432 };
2433
2434 let vm = vm!();
2435
2436 let dst = MaybeRelocatable::Int(Felt252::from(3));
2437 let op0 = MaybeRelocatable::Int(Felt252::from(2));
2438 assert_matches!(
2439 vm.deduce_op1(&instruction, Some(&dst), Some(op0)),
2440 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2441 x,
2442 y
2443 )) if x == Some(MaybeRelocatable::Int(Felt252::from(1))) &&
2444 y == Some(MaybeRelocatable::Int(Felt252::from(3)))
2445 );
2446 }
2447
2448 #[test]
2449 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2450 fn deduce_op1_opcode_assert_eq_res_add_without_optionals() {
2451 let instruction = Instruction {
2452 off0: 1,
2453 off1: 2,
2454 off2: 3,
2455 dst_register: Register::FP,
2456 op0_register: Register::AP,
2457 op1_addr: Op1Addr::AP,
2458 res: Res::Add,
2459 pc_update: PcUpdate::Jump,
2460 ap_update: ApUpdate::Regular,
2461 fp_update: FpUpdate::Regular,
2462 opcode: Opcode::AssertEq,
2463 opcode_extension: OpcodeExtension::Stone,
2464 };
2465
2466 let vm = vm!();
2467 assert_matches!(
2468 vm.deduce_op1(&instruction, None, None),
2469 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2470 None, None
2471 ))
2472 );
2473 }
2474
2475 #[test]
2476 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2477 fn deduce_op1_opcode_assert_eq_res_mul_non_zero_op0() {
2478 let instruction = Instruction {
2479 off0: 1,
2480 off1: 2,
2481 off2: 3,
2482 dst_register: Register::FP,
2483 op0_register: Register::AP,
2484 op1_addr: Op1Addr::AP,
2485 res: Res::Mul,
2486 pc_update: PcUpdate::Jump,
2487 ap_update: ApUpdate::Regular,
2488 fp_update: FpUpdate::Regular,
2489 opcode: Opcode::AssertEq,
2490 opcode_extension: OpcodeExtension::Stone,
2491 };
2492
2493 let vm = vm!();
2494
2495 let dst = MaybeRelocatable::Int(Felt252::from(4));
2496 let op0 = MaybeRelocatable::Int(Felt252::from(2));
2497 assert_matches!(
2498 vm.deduce_op1(&instruction, Some(&dst), Some(op0)),
2499 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2500 x,
2501 y
2502 )) if x == Some(MaybeRelocatable::Int(Felt252::from(2))) &&
2503 y == Some(MaybeRelocatable::Int(Felt252::from(4)))
2504 );
2505 }
2506
2507 #[test]
2508 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2509 fn deduce_op1_opcode_assert_eq_res_mul_zero_op0() {
2510 let instruction = Instruction {
2511 off0: 1,
2512 off1: 2,
2513 off2: 3,
2514 dst_register: Register::FP,
2515 op0_register: Register::AP,
2516 op1_addr: Op1Addr::AP,
2517 res: Res::Mul,
2518 pc_update: PcUpdate::Jump,
2519 ap_update: ApUpdate::Regular,
2520 fp_update: FpUpdate::Regular,
2521 opcode: Opcode::AssertEq,
2522 opcode_extension: OpcodeExtension::Stone,
2523 };
2524
2525 let vm = vm!();
2526
2527 let dst = MaybeRelocatable::Int(Felt252::from(4));
2528 let op0 = MaybeRelocatable::Int(Felt252::from(0));
2529 assert_matches!(
2530 vm.deduce_op1(&instruction, Some(&dst), Some(op0)),
2531 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2532 None, None
2533 ))
2534 );
2535 }
2536
2537 #[test]
2538 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2539 fn deduce_op1_opcode_assert_eq_res_op1_without_dst() {
2540 let instruction = Instruction {
2541 off0: 1,
2542 off1: 2,
2543 off2: 3,
2544 dst_register: Register::FP,
2545 op0_register: Register::AP,
2546 op1_addr: Op1Addr::AP,
2547 res: Res::Op1,
2548 pc_update: PcUpdate::Jump,
2549 ap_update: ApUpdate::Regular,
2550 fp_update: FpUpdate::Regular,
2551 opcode: Opcode::AssertEq,
2552 opcode_extension: OpcodeExtension::Stone,
2553 };
2554
2555 let vm = vm!();
2556
2557 let op0 = MaybeRelocatable::Int(Felt252::from(0));
2558 assert_matches!(
2559 vm.deduce_op1(&instruction, None, Some(op0)),
2560 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2561 None, None
2562 ))
2563 );
2564 }
2565
2566 #[test]
2567 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2568 fn deduce_op1_opcode_assert_eq_res_op1_with_dst() {
2569 let instruction = Instruction {
2570 off0: 1,
2571 off1: 2,
2572 off2: 3,
2573 dst_register: Register::FP,
2574 op0_register: Register::AP,
2575 op1_addr: Op1Addr::AP,
2576 res: Res::Op1,
2577 pc_update: PcUpdate::Jump,
2578 ap_update: ApUpdate::Regular,
2579 fp_update: FpUpdate::Regular,
2580 opcode: Opcode::AssertEq,
2581 opcode_extension: OpcodeExtension::Stone,
2582 };
2583
2584 let vm = vm!();
2585
2586 let dst = MaybeRelocatable::Int(Felt252::from(7));
2587 assert_matches!(
2588 vm.deduce_op1(&instruction, Some(&dst), None),
2589 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2590 x,
2591 y
2592 )) if x == Some(MaybeRelocatable::Int(Felt252::from(7))) &&
2593 y == Some(MaybeRelocatable::Int(Felt252::from(7)))
2594 );
2595 }
2596
2597 #[test]
2598 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2599 fn deduce_op1_qm31_add_int_operands() {
2600 let instruction = Instruction {
2601 off0: 1,
2602 off1: 2,
2603 off2: 3,
2604 dst_register: Register::FP,
2605 op0_register: Register::AP,
2606 op1_addr: Op1Addr::AP,
2607 res: Res::Add,
2608 pc_update: PcUpdate::Regular,
2609 ap_update: ApUpdate::Regular,
2610 fp_update: FpUpdate::Regular,
2611 opcode: Opcode::AssertEq,
2612 opcode_extension: OpcodeExtension::QM31Operation,
2613 };
2614
2615 let vm = vm!();
2616
2617 let op0_coordinates = [4, STWO_PRIME - 13, 3, 7];
2618 let dst_coordinates = [8, 7, 6, 5];
2619 let op0_packed = qm31_coordinates_to_packed_reduced(op0_coordinates);
2620 let dst_packed = qm31_coordinates_to_packed_reduced(dst_coordinates);
2621 let op0 = MaybeRelocatable::Int(op0_packed);
2622 let dst = MaybeRelocatable::Int(dst_packed);
2623 assert_matches!(
2624 vm.deduce_op1(&instruction, Some(&dst), Some(op0)),
2625 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2626 x,
2627 y
2628 )) if x == Some(MaybeRelocatable::Int(qm31_coordinates_to_packed_reduced([4, 20, 3, STWO_PRIME - 2]))) &&
2629 y == Some(MaybeRelocatable::Int(dst_packed))
2630 );
2631 }
2632
2633 #[test]
2634 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2635 fn deduce_op1_qm31_mul_int_operands() {
2636 let instruction = Instruction {
2637 off0: 1,
2638 off1: 2,
2639 off2: 3,
2640 dst_register: Register::FP,
2641 op0_register: Register::AP,
2642 op1_addr: Op1Addr::AP,
2643 res: Res::Mul,
2644 pc_update: PcUpdate::Regular,
2645 ap_update: ApUpdate::Regular,
2646 fp_update: FpUpdate::Regular,
2647 opcode: Opcode::AssertEq,
2648 opcode_extension: OpcodeExtension::QM31Operation,
2649 };
2650
2651 let vm = vm!();
2652
2653 let op0_coordinates = [0, 1, 0, 0];
2654 let dst_coordinates = [STWO_PRIME - 1, 0, 0, 0];
2655 let op0_packed = qm31_coordinates_to_packed_reduced(op0_coordinates);
2656 let dst_packed = qm31_coordinates_to_packed_reduced(dst_coordinates);
2657 let op0 = MaybeRelocatable::Int(op0_packed);
2658 let dst = MaybeRelocatable::Int(dst_packed);
2659 assert_matches!(
2660 vm.deduce_op1(&instruction, Some(&dst), Some(op0)),
2661 Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2662 x,
2663 y
2664 )) if x == Some(MaybeRelocatable::Int(qm31_coordinates_to_packed_reduced([0, 1, 0, 0]))) &&
2665 y == Some(MaybeRelocatable::Int(dst_packed))
2666 );
2667 }
2668
2669 #[test]
2670 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2671 fn deduce_op1_blake_mul_int_operands() {
2672 let instruction = Instruction {
2673 off0: 1,
2674 off1: 2,
2675 off2: 3,
2676 dst_register: Register::FP,
2677 op0_register: Register::AP,
2678 op1_addr: Op1Addr::AP,
2679 res: Res::Mul,
2680 pc_update: PcUpdate::Regular,
2681 ap_update: ApUpdate::Regular,
2682 fp_update: FpUpdate::Regular,
2683 opcode: Opcode::AssertEq,
2684 opcode_extension: OpcodeExtension::Blake,
2685 };
2686
2687 let vm = vm!();
2688
2689 let op0 = MaybeRelocatable::Int(Felt252::from(4));
2690 let dst = MaybeRelocatable::Int(Felt252::from(16));
2691 assert_matches!(
2692 vm.deduce_op1(&instruction, Some(&dst), Some(op0)),
2693 Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension(ref message)) if message.as_ref() == "typed_div"
2694 );
2695 }
2696
2697 #[test]
2698 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2699 fn compute_res_op1() {
2700 let instruction = Instruction {
2701 off0: 1,
2702 off1: 2,
2703 off2: 3,
2704 dst_register: Register::FP,
2705 op0_register: Register::AP,
2706 op1_addr: Op1Addr::AP,
2707 res: Res::Op1,
2708 pc_update: PcUpdate::Jump,
2709 ap_update: ApUpdate::Regular,
2710 fp_update: FpUpdate::Regular,
2711 opcode: Opcode::AssertEq,
2712 opcode_extension: OpcodeExtension::Stone,
2713 };
2714
2715 let vm = vm!();
2716
2717 let op1 = MaybeRelocatable::Int(Felt252::from(7));
2718 let op0 = MaybeRelocatable::Int(Felt252::from(9));
2719 assert_matches!(
2720 vm.compute_res(&instruction, &op0, &op1),
2721 Ok::<Option<MaybeRelocatable>, VirtualMachineError>(Some(MaybeRelocatable::Int(
2722 x
2723 ))) if x == Felt252::from(7)
2724 );
2725 }
2726
2727 #[test]
2728 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2729 fn compute_res_add() {
2730 let instruction = Instruction {
2731 off0: 1,
2732 off1: 2,
2733 off2: 3,
2734 dst_register: Register::FP,
2735 op0_register: Register::AP,
2736 op1_addr: Op1Addr::AP,
2737 res: Res::Add,
2738 pc_update: PcUpdate::Jump,
2739 ap_update: ApUpdate::Regular,
2740 fp_update: FpUpdate::Regular,
2741 opcode: Opcode::AssertEq,
2742 opcode_extension: OpcodeExtension::Stone,
2743 };
2744
2745 let vm = vm!();
2746
2747 let op1 = MaybeRelocatable::Int(Felt252::from(7));
2748 let op0 = MaybeRelocatable::Int(Felt252::from(9));
2749 assert_matches!(
2750 vm.compute_res(&instruction, &op0, &op1),
2751 Ok::<Option<MaybeRelocatable>, VirtualMachineError>(Some(MaybeRelocatable::Int(
2752 x
2753 ))) if x == Felt252::from(16)
2754 );
2755 }
2756
2757 #[test]
2758 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2759 fn compute_res_mul_int_operands() {
2760 let instruction = Instruction {
2761 off0: 1,
2762 off1: 2,
2763 off2: 3,
2764 dst_register: Register::FP,
2765 op0_register: Register::AP,
2766 op1_addr: Op1Addr::AP,
2767 res: Res::Mul,
2768 pc_update: PcUpdate::Jump,
2769 ap_update: ApUpdate::Regular,
2770 fp_update: FpUpdate::Regular,
2771 opcode: Opcode::AssertEq,
2772 opcode_extension: OpcodeExtension::Stone,
2773 };
2774
2775 let vm = vm!();
2776
2777 let op1 = MaybeRelocatable::Int(Felt252::from(7));
2778 let op0 = MaybeRelocatable::Int(Felt252::from(9));
2779 assert_matches!(
2780 vm.compute_res(&instruction, &op0, &op1),
2781 Ok::<Option<MaybeRelocatable>, VirtualMachineError>(Some(MaybeRelocatable::Int(
2782 x
2783 ))) if x == Felt252::from(63)
2784 );
2785 }
2786
2787 #[test]
2788 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2789 fn compute_res_mul_relocatable_values() {
2790 let instruction = Instruction {
2791 off0: 1,
2792 off1: 2,
2793 off2: 3,
2794 dst_register: Register::FP,
2795 op0_register: Register::AP,
2796 op1_addr: Op1Addr::AP,
2797 res: Res::Mul,
2798 pc_update: PcUpdate::Jump,
2799 ap_update: ApUpdate::Regular,
2800 fp_update: FpUpdate::Regular,
2801 opcode: Opcode::AssertEq,
2802 opcode_extension: OpcodeExtension::Stone,
2803 };
2804
2805 let vm = vm!();
2806
2807 let op1 = MaybeRelocatable::from((2, 3));
2808 let op0 = MaybeRelocatable::from((2, 6));
2809 assert_matches!(
2810 vm.compute_res(&instruction, &op0, &op1),
2811 Err(VirtualMachineError::ComputeResRelocatableMul(bx)) if *bx == (op0, op1)
2812 );
2813 }
2814
2815 #[test]
2816 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2817 fn compute_res_qm31_add_relocatable_values() {
2818 let instruction = Instruction {
2819 off0: 1,
2820 off1: 2,
2821 off2: 3,
2822 dst_register: Register::FP,
2823 op0_register: Register::AP,
2824 op1_addr: Op1Addr::AP,
2825 res: Res::Add,
2826 pc_update: PcUpdate::Regular,
2827 ap_update: ApUpdate::Regular,
2828 fp_update: FpUpdate::Regular,
2829 opcode: Opcode::AssertEq,
2830 opcode_extension: OpcodeExtension::QM31Operation,
2831 };
2832
2833 let vm = vm!();
2834
2835 let op1 = MaybeRelocatable::from((2, 3));
2836 let op0 = MaybeRelocatable::from(7);
2837 assert_matches!(
2838 vm.compute_res(&instruction, &op0, &op1),
2839 Err(VirtualMachineError::Math(MathError::RelocatableQM31Add(bx))) if *bx == (op0, op1)
2840 );
2841 }
2842
2843 #[test]
2844 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2845 fn compute_res_qm31_add_int_operands() {
2846 let instruction = Instruction {
2847 off0: 1,
2848 off1: 2,
2849 off2: 3,
2850 dst_register: Register::FP,
2851 op0_register: Register::AP,
2852 op1_addr: Op1Addr::AP,
2853 res: Res::Add,
2854 pc_update: PcUpdate::Regular,
2855 ap_update: ApUpdate::Regular,
2856 fp_update: FpUpdate::Regular,
2857 opcode: Opcode::AssertEq,
2858 opcode_extension: OpcodeExtension::QM31Operation,
2859 };
2860
2861 let vm = vm!();
2862
2863 let op1_coordinates = [1, 2, 3, 4];
2864 let op0_coordinates = [10, 11, STWO_PRIME - 1, 13];
2865 let op1_packed = qm31_coordinates_to_packed_reduced(op1_coordinates);
2866 let op0_packed = qm31_coordinates_to_packed_reduced(op0_coordinates);
2867 let op1 = MaybeRelocatable::Int(op1_packed);
2868 let op0 = MaybeRelocatable::Int(op0_packed);
2869 assert_matches!(
2870 vm.compute_res(&instruction, &op0, &op1),
2871 Ok::<Option<MaybeRelocatable>, VirtualMachineError>(Some(MaybeRelocatable::Int(
2872 x
2873 ))) if x == qm31_coordinates_to_packed_reduced([11, 13, 2, 17])
2874 );
2875 }
2876
2877 #[test]
2878 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2879 fn compute_res_qm31_mul_int_operands() {
2880 let instruction = Instruction {
2881 off0: 1,
2882 off1: 2,
2883 off2: 3,
2884 dst_register: Register::FP,
2885 op0_register: Register::AP,
2886 op1_addr: Op1Addr::AP,
2887 res: Res::Mul,
2888 pc_update: PcUpdate::Regular,
2889 ap_update: ApUpdate::Regular,
2890 fp_update: FpUpdate::Regular,
2891 opcode: Opcode::AssertEq,
2892 opcode_extension: OpcodeExtension::QM31Operation,
2893 };
2894
2895 let vm = vm!();
2896
2897 let op1_coordinates = [0, 0, 1, 0];
2898 let op0_coordinates = [0, 0, 1, 0];
2899 let op1_packed = qm31_coordinates_to_packed_reduced(op1_coordinates);
2900 let op0_packed = qm31_coordinates_to_packed_reduced(op0_coordinates);
2901 let op1 = MaybeRelocatable::Int(op1_packed);
2902 let op0 = MaybeRelocatable::Int(op0_packed);
2903 assert_matches!(
2904 vm.compute_res(&instruction, &op0, &op1),
2905 Ok::<Option<MaybeRelocatable>, VirtualMachineError>(Some(MaybeRelocatable::Int(
2906 x
2907 ))) if x == qm31_coordinates_to_packed_reduced([2, 1, 0, 0])
2908 );
2909 }
2910
2911 #[test]
2912 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2913 fn compute_res_blake_mul_int_operands() {
2914 let instruction = Instruction {
2915 off0: 1,
2916 off1: 2,
2917 off2: 3,
2918 dst_register: Register::FP,
2919 op0_register: Register::AP,
2920 op1_addr: Op1Addr::AP,
2921 res: Res::Mul,
2922 pc_update: PcUpdate::Regular,
2923 ap_update: ApUpdate::Regular,
2924 fp_update: FpUpdate::Regular,
2925 opcode: Opcode::AssertEq,
2926 opcode_extension: OpcodeExtension::Blake,
2927 };
2928
2929 let vm = vm!();
2930
2931 let op1 = MaybeRelocatable::Int(Felt252::from(11));
2932 let op0 = MaybeRelocatable::Int(Felt252::from(12));
2933 assert_matches!(
2934 vm.compute_res(&instruction, &op0, &op1),
2935 Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension(ref message)) if message.as_ref() == "typed_mul"
2936 );
2937 }
2938
2939 #[test]
2940 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2941 fn compute_res_unconstrained() {
2942 let instruction = Instruction {
2943 off0: 1,
2944 off1: 2,
2945 off2: 3,
2946 dst_register: Register::FP,
2947 op0_register: Register::AP,
2948 op1_addr: Op1Addr::AP,
2949 res: Res::Unconstrained,
2950 pc_update: PcUpdate::Jump,
2951 ap_update: ApUpdate::Regular,
2952 fp_update: FpUpdate::Regular,
2953 opcode: Opcode::AssertEq,
2954 opcode_extension: OpcodeExtension::Stone,
2955 };
2956
2957 let vm = vm!();
2958
2959 let op1 = MaybeRelocatable::Int(Felt252::from(7));
2960 let op0 = MaybeRelocatable::Int(Felt252::from(9));
2961 assert_matches!(
2962 vm.compute_res(&instruction, &op0, &op1),
2963 Ok::<Option<MaybeRelocatable>, VirtualMachineError>(None)
2964 );
2965 }
2966
2967 #[test]
2968 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2969 fn deduce_dst_opcode_assert_eq_with_res() {
2970 let instruction = Instruction {
2971 off0: 1,
2972 off1: 2,
2973 off2: 3,
2974 dst_register: Register::FP,
2975 op0_register: Register::AP,
2976 op1_addr: Op1Addr::AP,
2977 res: Res::Unconstrained,
2978 pc_update: PcUpdate::Jump,
2979 ap_update: ApUpdate::Regular,
2980 fp_update: FpUpdate::Regular,
2981 opcode: Opcode::AssertEq,
2982 opcode_extension: OpcodeExtension::Stone,
2983 };
2984
2985 let vm = vm!();
2986
2987 let res = MaybeRelocatable::Int(Felt252::from(7));
2988 assert_eq!(
2989 MaybeRelocatable::Int(Felt252::from(7)),
2990 vm.deduce_dst(&instruction, &Some(res)).unwrap()
2991 );
2992 }
2993
2994 #[test]
2995 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2996 fn deduce_dst_opcode_assert_eq_without_res() {
2997 let instruction = Instruction {
2998 off0: 1,
2999 off1: 2,
3000 off2: 3,
3001 dst_register: Register::FP,
3002 op0_register: Register::AP,
3003 op1_addr: Op1Addr::AP,
3004 res: Res::Unconstrained,
3005 pc_update: PcUpdate::Jump,
3006 ap_update: ApUpdate::Regular,
3007 fp_update: FpUpdate::Regular,
3008 opcode: Opcode::AssertEq,
3009 opcode_extension: OpcodeExtension::Stone,
3010 };
3011
3012 let vm = vm!();
3013
3014 assert!(vm.deduce_dst(&instruction, &None).is_err());
3015 }
3016
3017 #[test]
3018 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3019 fn deduce_dst_opcode_call() {
3020 let instruction = Instruction {
3021 off0: 1,
3022 off1: 2,
3023 off2: 3,
3024 dst_register: Register::FP,
3025 op0_register: Register::AP,
3026 op1_addr: Op1Addr::AP,
3027 res: Res::Unconstrained,
3028 pc_update: PcUpdate::Jump,
3029 ap_update: ApUpdate::Regular,
3030 fp_update: FpUpdate::Regular,
3031 opcode: Opcode::Call,
3032 opcode_extension: OpcodeExtension::Stone,
3033 };
3034
3035 let vm = vm!();
3036
3037 assert_eq!(
3038 MaybeRelocatable::from((1, 0)),
3039 vm.deduce_dst(&instruction, &None).unwrap()
3040 );
3041 }
3042
3043 #[test]
3044 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3045 fn deduce_dst_opcode_ret() {
3046 let instruction = Instruction {
3047 off0: 1,
3048 off1: 2,
3049 off2: 3,
3050 dst_register: Register::FP,
3051 op0_register: Register::AP,
3052 op1_addr: Op1Addr::AP,
3053 res: Res::Unconstrained,
3054 pc_update: PcUpdate::Jump,
3055 ap_update: ApUpdate::Regular,
3056 fp_update: FpUpdate::Regular,
3057 opcode: Opcode::Ret,
3058 opcode_extension: OpcodeExtension::Stone,
3059 };
3060
3061 let vm = vm!();
3062
3063 assert!(vm.deduce_dst(&instruction, &None).is_err());
3064 }
3065
3066 #[test]
3067 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3068 fn compute_operands_add_ap() {
3069 let inst = Instruction {
3070 off0: 0,
3071 off1: 1,
3072 off2: 2,
3073 dst_register: Register::AP,
3074 op0_register: Register::AP,
3075 op1_addr: Op1Addr::AP,
3076 res: Res::Add,
3077 pc_update: PcUpdate::Regular,
3078 ap_update: ApUpdate::Regular,
3079 fp_update: FpUpdate::Regular,
3080 opcode: Opcode::NOp,
3081 opcode_extension: OpcodeExtension::Stone,
3082 };
3083
3084 let mut vm = vm!();
3085 for _ in 0..2 {
3086 vm.segments.add();
3087 }
3088
3089 vm.segments.memory.data.push(Vec::new());
3090 let dst_addr = Relocatable::from((1, 0));
3091 let dst_addr_value = MaybeRelocatable::Int(Felt252::from(5));
3092 let op0_addr = Relocatable::from((1, 1));
3093 let op0_addr_value = MaybeRelocatable::Int(Felt252::from(2));
3094 let op1_addr = Relocatable::from((1, 2));
3095 let op1_addr_value = MaybeRelocatable::Int(Felt252::from(3));
3096 vm.segments
3097 .memory
3098 .insert(dst_addr, &dst_addr_value)
3099 .unwrap();
3100 vm.segments
3101 .memory
3102 .insert(op0_addr, &op0_addr_value)
3103 .unwrap();
3104 vm.segments
3105 .memory
3106 .insert(op1_addr, &op1_addr_value)
3107 .unwrap();
3108
3109 let expected_operands = Operands {
3110 dst: dst_addr_value.clone(),
3111 res: Some(dst_addr_value.clone()),
3112 op0: op0_addr_value.clone(),
3113 op1: op1_addr_value.clone(),
3114 };
3115
3116 let expected_addresses = OperandsAddresses {
3117 dst_addr,
3118 op0_addr,
3119 op1_addr,
3120 };
3121
3122 let (operands, addresses, _) = vm.compute_operands(&inst).unwrap();
3123 assert!(operands == expected_operands);
3124 assert!(addresses == expected_addresses);
3125 }
3126
3127 #[test]
3128 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3129 fn compute_operands_mul_fp() {
3130 let inst = Instruction {
3131 off0: 0,
3132 off1: 1,
3133 off2: 2,
3134 dst_register: Register::FP,
3135 op0_register: Register::FP,
3136 op1_addr: Op1Addr::FP,
3137 res: Res::Mul,
3138 pc_update: PcUpdate::Regular,
3139 ap_update: ApUpdate::Regular,
3140 fp_update: FpUpdate::Regular,
3141 opcode: Opcode::NOp,
3142 opcode_extension: OpcodeExtension::Stone,
3143 };
3144 let mut vm = vm!();
3145 for _ in 0..2 {
3147 vm.segments.add();
3148 }
3149 vm.segments.memory.data.push(Vec::new());
3150 let dst_addr = relocatable!(1, 0);
3151 let dst_addr_value = mayberelocatable!(6);
3152 let op0_addr = relocatable!(1, 1);
3153 let op0_addr_value = mayberelocatable!(2);
3154 let op1_addr = relocatable!(1, 2);
3155 let op1_addr_value = mayberelocatable!(3);
3156 vm.segments
3157 .memory
3158 .insert(dst_addr, &dst_addr_value)
3159 .unwrap();
3160 vm.segments
3161 .memory
3162 .insert(op0_addr, &op0_addr_value)
3163 .unwrap();
3164 vm.segments
3165 .memory
3166 .insert(op1_addr, &op1_addr_value)
3167 .unwrap();
3168
3169 let expected_operands = Operands {
3170 dst: dst_addr_value.clone(),
3171 res: Some(dst_addr_value.clone()),
3172 op0: op0_addr_value.clone(),
3173 op1: op1_addr_value.clone(),
3174 };
3175
3176 let expected_addresses = OperandsAddresses {
3177 dst_addr,
3178 op0_addr,
3179 op1_addr,
3180 };
3181
3182 let (operands, addresses, _) = vm.compute_operands(&inst).unwrap();
3183 assert!(operands == expected_operands);
3184 assert!(addresses == expected_addresses);
3185 }
3186
3187 #[test]
3188 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3189 fn compute_jnz() {
3190 let instruction = Instruction {
3191 off0: 1,
3192 off1: 1,
3193 off2: 1,
3194 dst_register: Register::AP,
3195 op0_register: Register::AP,
3196 op1_addr: Op1Addr::Imm,
3197 res: Res::Unconstrained,
3198 pc_update: PcUpdate::Jnz,
3199 ap_update: ApUpdate::Regular,
3200 fp_update: FpUpdate::Regular,
3201 opcode: Opcode::NOp,
3202 opcode_extension: OpcodeExtension::Stone,
3203 };
3204
3205 let mut vm = vm!();
3206 vm.segments = segments![
3207 ((0, 0), 0x206800180018001_i64),
3208 ((1, 1), 0x4),
3209 ((0, 1), 0x4)
3210 ];
3211
3212 let expected_operands = Operands {
3213 dst: mayberelocatable!(4),
3214 res: None,
3215 op0: mayberelocatable!(4),
3216 op1: mayberelocatable!(4),
3217 };
3218
3219 let expected_addresses = OperandsAddresses {
3220 dst_addr: relocatable!(1, 1),
3221 op0_addr: relocatable!(1, 1),
3222 op1_addr: relocatable!(0, 1),
3223 };
3224
3225 let (operands, addresses, _) = vm.compute_operands(&instruction).unwrap();
3226 assert!(operands == expected_operands);
3227 assert!(addresses == expected_addresses);
3228 let mut hint_processor = BuiltinHintProcessor::new_empty();
3229 assert_matches!(
3230 vm.step(
3231 &mut hint_processor,
3232 exec_scopes_ref!(),
3233 &mut Vec::new(),
3234 #[cfg(feature = "extensive_hints")]
3235 &mut HashMap::new(),
3236 &HashMap::new(),
3237 ),
3238 Ok(())
3239 );
3240 assert_eq!(vm.run_context.pc, relocatable!(0, 4));
3241 }
3242
3243 #[test]
3244 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3245 fn compute_operands_deduce_dst_none() {
3246 let instruction = Instruction {
3247 off0: 2,
3248 off1: 0,
3249 off2: 0,
3250 dst_register: Register::FP,
3251 op0_register: Register::AP,
3252 op1_addr: Op1Addr::AP,
3253 res: Res::Unconstrained,
3254 pc_update: PcUpdate::Regular,
3255 ap_update: ApUpdate::Regular,
3256 fp_update: FpUpdate::Regular,
3257 opcode: Opcode::NOp,
3258 opcode_extension: OpcodeExtension::Stone,
3259 };
3260
3261 let mut vm = vm!();
3262
3263 vm.segments = segments!(((1, 0), 145944781867024385_i64));
3264
3265 let error = vm.compute_operands(&instruction).unwrap_err();
3266 assert_matches!(error, VirtualMachineError::NoDst);
3267 }
3268
3269 #[test]
3270 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3271 fn opcode_assertions_res_unconstrained() {
3272 let instruction = Instruction {
3273 off0: 1,
3274 off1: 2,
3275 off2: 3,
3276 dst_register: Register::FP,
3277 op0_register: Register::AP,
3278 op1_addr: Op1Addr::AP,
3279 res: Res::Add,
3280 pc_update: PcUpdate::Regular,
3281 ap_update: ApUpdate::Regular,
3282 fp_update: FpUpdate::APPlus2,
3283 opcode: Opcode::AssertEq,
3284 opcode_extension: OpcodeExtension::Stone,
3285 };
3286
3287 let operands = Operands {
3288 dst: MaybeRelocatable::Int(Felt252::from(8)),
3289 res: None,
3290 op0: MaybeRelocatable::Int(Felt252::from(9)),
3291 op1: MaybeRelocatable::Int(Felt252::from(10)),
3292 };
3293
3294 let vm = vm!();
3295
3296 let error = vm.opcode_assertions(&instruction, &operands);
3297 assert_matches!(error, Err(VirtualMachineError::UnconstrainedResAssertEq));
3298 }
3299
3300 #[test]
3301 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3302 fn opcode_assertions_instruction_failed() {
3303 let instruction = Instruction {
3304 off0: 1,
3305 off1: 2,
3306 off2: 3,
3307 dst_register: Register::FP,
3308 op0_register: Register::AP,
3309 op1_addr: Op1Addr::AP,
3310 res: Res::Add,
3311 pc_update: PcUpdate::Regular,
3312 ap_update: ApUpdate::Regular,
3313 fp_update: FpUpdate::APPlus2,
3314 opcode: Opcode::AssertEq,
3315 opcode_extension: OpcodeExtension::Stone,
3316 };
3317
3318 let operands = Operands {
3319 dst: MaybeRelocatable::Int(Felt252::from(9_i32)),
3320 res: Some(MaybeRelocatable::Int(Felt252::from(8_i32))),
3321 op0: MaybeRelocatable::Int(Felt252::from(9_i32)),
3322 op1: MaybeRelocatable::Int(Felt252::from(10_i32)),
3323 };
3324
3325 let vm = vm!();
3326
3327 assert_matches!(
3328 vm.opcode_assertions(&instruction, &operands),
3329 Err(VirtualMachineError::DiffAssertValues(bx))
3330 if *bx == (MaybeRelocatable::Int(Felt252::from(9_i32)),
3331 MaybeRelocatable::Int(Felt252::from(8_i32)))
3332 );
3333 }
3334
3335 #[test]
3336 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3337 fn opcode_assertions_instruction_failed_relocatables() {
3338 let instruction = Instruction {
3339 off0: 1,
3340 off1: 2,
3341 off2: 3,
3342 dst_register: Register::FP,
3343 op0_register: Register::AP,
3344 op1_addr: Op1Addr::AP,
3345 res: Res::Add,
3346 pc_update: PcUpdate::Regular,
3347 ap_update: ApUpdate::Regular,
3348 fp_update: FpUpdate::APPlus2,
3349 opcode: Opcode::AssertEq,
3350 opcode_extension: OpcodeExtension::Stone,
3351 };
3352
3353 let operands = Operands {
3354 dst: MaybeRelocatable::from((1, 1)),
3355 res: Some(MaybeRelocatable::from((1, 2))),
3356 op0: MaybeRelocatable::Int(Felt252::from(9_i32)),
3357 op1: MaybeRelocatable::Int(Felt252::from(10_i32)),
3358 };
3359
3360 let vm = vm!();
3361
3362 assert_matches!(
3363 vm.opcode_assertions(&instruction, &operands),
3364 Err(VirtualMachineError::DiffAssertValues(bx)) if *bx == (MaybeRelocatable::from((1, 1)), MaybeRelocatable::from((1, 2)))
3365 );
3366 }
3367
3368 #[test]
3369 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3370 fn opcode_assertions_inconsistent_op0() {
3371 let instruction = Instruction {
3372 off0: 1,
3373 off1: 2,
3374 off2: 3,
3375 dst_register: Register::FP,
3376 op0_register: Register::AP,
3377 op1_addr: Op1Addr::AP,
3378 res: Res::Add,
3379 pc_update: PcUpdate::Regular,
3380 ap_update: ApUpdate::Regular,
3381 fp_update: FpUpdate::APPlus2,
3382 opcode: Opcode::Call,
3383 opcode_extension: OpcodeExtension::Stone,
3384 };
3385
3386 let operands = Operands {
3387 dst: mayberelocatable!(0, 8),
3388 res: Some(mayberelocatable!(8)),
3389 op0: mayberelocatable!(9),
3390 op1: mayberelocatable!(10),
3391 };
3392
3393 let mut vm = vm!();
3394 vm.run_context.pc = relocatable!(0, 4);
3395
3396 assert_matches!(
3397 vm.opcode_assertions(&instruction, &operands),
3398 Err(VirtualMachineError::CantWriteReturnPc(bx)) if *bx == (mayberelocatable!(9), mayberelocatable!(0, 5))
3399 );
3400 }
3401
3402 #[test]
3403 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3404 fn opcode_assertions_inconsistent_dst() {
3405 let instruction = Instruction {
3406 off0: 1,
3407 off1: 2,
3408 off2: 3,
3409 dst_register: Register::FP,
3410 op0_register: Register::AP,
3411 op1_addr: Op1Addr::AP,
3412 res: Res::Add,
3413 pc_update: PcUpdate::Regular,
3414 ap_update: ApUpdate::Regular,
3415 fp_update: FpUpdate::APPlus2,
3416 opcode: Opcode::Call,
3417 opcode_extension: OpcodeExtension::Stone,
3418 };
3419
3420 let operands = Operands {
3421 dst: mayberelocatable!(8),
3422 res: Some(mayberelocatable!(8)),
3423 op0: mayberelocatable!(0, 1),
3424 op1: mayberelocatable!(10),
3425 };
3426 let mut vm = vm!();
3427 vm.run_context.fp = 6;
3428
3429 assert_matches!(
3430 vm.opcode_assertions(&instruction, &operands),
3431 Err(VirtualMachineError::CantWriteReturnFp(bx)) if *bx == (mayberelocatable!(8), mayberelocatable!(1, 6))
3432 );
3433 }
3434
3435 #[test]
3436 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3437 fn test_step_for_preset_memory() {
3454 let mut vm = vm!(true);
3455
3456 let mut hint_processor = BuiltinHintProcessor::new_empty();
3457
3458 run_context!(vm, 0, 2, 2);
3459
3460 vm.segments = segments![
3461 ((0, 0), 2345108766317314046_u64),
3462 ((1, 0), (2, 0)),
3463 ((1, 1), (3, 0))
3464 ];
3465
3466 assert_matches!(
3467 vm.step(
3468 &mut hint_processor,
3469 exec_scopes_ref!(),
3470 &mut Vec::new(),
3471 #[cfg(feature = "extensive_hints")]
3472 &mut HashMap::new(),
3473 &HashMap::new(),
3474 ),
3475 Ok(())
3476 );
3477 let trace = vm.trace.unwrap();
3478 trace_check(&trace, &[((0, 0).into(), 2, 2)]);
3479
3480 assert_eq!(vm.run_context.pc, Relocatable::from((3, 0)));
3481 assert_eq!(vm.run_context.ap, 2);
3482 assert_eq!(vm.run_context.fp, 0);
3483
3484 let mem = vm.segments.memory.data;
3487 assert!(mem[1][0].is_accessed());
3488 assert!(mem[1][1].is_accessed());
3489 }
3490
3491 #[test]
3492 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3493 fn test_step_for_preset_memory_function_call() {
3524 let mut vm = vm!(true);
3525
3526 run_context!(vm, 3, 2, 2);
3527
3528 vm.segments.memory =
3530 memory![
3531 ((0, 0), 5207990763031199744_i64),
3532 ((0, 1), 2),
3533 ((0, 2), 2345108766317314046_i64),
3534 ((0, 3), 5189976364521848832_i64),
3535 ((0, 4), 1),
3536 ((0, 5), 1226245742482522112_i64),
3537 (
3538 (0, 6),
3539 ("3618502788666131213697322783095070105623107215331596699973092056135872020476",10)
3540 ),
3541 ((0, 7), 2345108766317314046_i64),
3542 ((1, 0), (2, 0)),
3543 ((1, 1), (3, 0))
3544 ];
3545
3546 let final_pc = Relocatable::from((3, 0));
3547 let mut hint_processor = BuiltinHintProcessor::new_empty();
3548 while vm.run_context.pc != final_pc {
3550 assert_matches!(
3551 vm.step(
3552 &mut hint_processor,
3553 exec_scopes_ref!(),
3554 &mut Vec::new(),
3555 #[cfg(feature = "extensive_hints")]
3556 &mut HashMap::new(),
3557 &HashMap::new()
3558 ),
3559 Ok(())
3560 );
3561 }
3562
3563 assert_eq!(vm.run_context.pc, Relocatable::from((3, 0)));
3565
3566 assert_eq!(vm.run_context.ap, 6);
3567
3568 assert_eq!(vm.run_context.fp, 0);
3569 let trace = vm.trace.unwrap();
3571 assert_eq!(trace.len(), 5);
3572 trace_check(
3573 &trace,
3574 &[
3575 ((0, 3).into(), 2, 2),
3576 ((0, 5).into(), 3, 2),
3577 ((0, 0).into(), 5, 5),
3578 ((0, 2).into(), 6, 5),
3579 ((0, 7).into(), 6, 2),
3580 ],
3581 );
3582 let mem = &vm.segments.memory.data;
3585 assert!(mem[0][1].is_accessed());
3586 assert!(mem[0][4].is_accessed());
3587 assert!(mem[0][6].is_accessed());
3588 assert!(mem[1][0].is_accessed());
3589 assert!(mem[1][1].is_accessed());
3590 assert!(mem[1][2].is_accessed());
3591 assert!(mem[1][3].is_accessed());
3592 assert!(mem[1][4].is_accessed());
3593 assert!(mem[1][5].is_accessed());
3594 assert_eq!(
3595 vm.segments
3596 .memory
3597 .get_amount_of_accessed_addresses_for_segment(0),
3598 Some(3)
3599 );
3600 assert_eq!(
3601 vm.segments
3602 .memory
3603 .get_amount_of_accessed_addresses_for_segment(1),
3604 Some(6)
3605 );
3606 }
3607
3608 #[test]
3609 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3610 fn multiplication_and_different_ap_increase() {
3632 let mut vm = vm!();
3633 vm.segments = segments![
3634 ((0, 0), 0x400680017fff8000_i64),
3635 ((0, 1), 0x4),
3636 ((0, 2), 0x40780017fff7fff_i64),
3637 ((0, 3), 0x1),
3638 ((0, 4), 0x480680017fff8000_i64),
3639 ((0, 5), 0x5),
3640 ((0, 6), 0x40507ffe7fff8000_i64),
3641 ((0, 7), 0x208b7fff7fff7ffe_i64),
3642 ((1, 0), (2, 0)),
3643 ((1, 1), (3, 0)),
3644 ((1, 2), 0x4),
3645 ((1, 3), 0x5),
3646 ((1, 4), 0x14)
3647 ];
3648
3649 run_context!(vm, 0, 2, 2);
3650
3651 assert_eq!(vm.run_context.pc, Relocatable::from((0, 0)));
3652 assert_eq!(vm.run_context.ap, 2);
3653 let mut hint_processor = BuiltinHintProcessor::new_empty();
3654 assert_matches!(
3655 vm.step(
3656 &mut hint_processor,
3657 exec_scopes_ref!(),
3658 &mut Vec::new(),
3659 #[cfg(feature = "extensive_hints")]
3660 &mut HashMap::new(),
3661 &HashMap::new()
3662 ),
3663 Ok(())
3664 );
3665 assert_eq!(vm.run_context.pc, Relocatable::from((0, 2)));
3666 assert_eq!(vm.run_context.ap, 2);
3667
3668 assert_eq!(
3669 vm.segments
3670 .memory
3671 .get(&vm.run_context.get_ap())
3672 .unwrap()
3673 .as_ref(),
3674 &MaybeRelocatable::Int(Felt252::from(0x4)),
3675 );
3676 let mut hint_processor = BuiltinHintProcessor::new_empty();
3677 assert_matches!(
3678 vm.step(
3679 &mut hint_processor,
3680 exec_scopes_ref!(),
3681 &mut Vec::new(),
3682 #[cfg(feature = "extensive_hints")]
3683 &mut HashMap::new(),
3684 &HashMap::new()
3685 ),
3686 Ok(())
3687 );
3688 assert_eq!(vm.run_context.pc, Relocatable::from((0, 4)));
3689 assert_eq!(vm.run_context.ap, 3);
3690
3691 assert_eq!(
3692 vm.segments
3693 .memory
3694 .get(&vm.run_context.get_ap())
3695 .unwrap()
3696 .as_ref(),
3697 &MaybeRelocatable::Int(Felt252::from(0x5))
3698 );
3699
3700 let mut hint_processor = BuiltinHintProcessor::new_empty();
3701 assert_matches!(
3702 vm.step(
3703 &mut hint_processor,
3704 exec_scopes_ref!(),
3705 &mut Vec::new(),
3706 #[cfg(feature = "extensive_hints")]
3707 &mut HashMap::new(),
3708 &HashMap::new()
3709 ),
3710 Ok(())
3711 );
3712 assert_eq!(vm.run_context.pc, Relocatable::from((0, 6)));
3713 assert_eq!(vm.run_context.ap, 4);
3714
3715 assert_eq!(
3716 vm.segments
3717 .memory
3718 .get(&vm.run_context.get_ap())
3719 .unwrap()
3720 .as_ref(),
3721 &MaybeRelocatable::Int(Felt252::from(0x14)),
3722 );
3723 }
3724
3725 #[test]
3726 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3727 fn deduce_memory_cell_no_pedersen_builtin() {
3728 let vm = vm!();
3729 assert_matches!(vm.deduce_memory_cell(Relocatable::from((0, 0))), Ok(None));
3730 }
3731
3732 #[test]
3733 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3734 fn deduce_memory_cell_pedersen_builtin_valid() {
3735 let mut vm = vm!();
3736 let builtin = HashBuiltinRunner::new(Some(8), true);
3737 vm.builtin_runners.push(builtin.into());
3738 vm.segments = segments![((0, 3), 32), ((0, 4), 72), ((0, 5), 0)];
3739 assert_matches!(
3740 vm.deduce_memory_cell(Relocatable::from((0, 5))),
3741 Ok(i) if i == Some(MaybeRelocatable::from(crate::felt_hex!(
3742 "0x73b3ec210cccbb970f80c6826fb1c40ae9f487617696234ff147451405c339f"
3743 )))
3744 );
3745 }
3746
3747 #[test]
3748 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3749 fn compute_operands_pedersen() {
3773 let instruction = Instruction {
3774 off0: 0,
3775 off1: -5,
3776 off2: 2,
3777 dst_register: Register::AP,
3778 op0_register: Register::FP,
3779 op1_addr: Op1Addr::Op0,
3780 res: Res::Op1,
3781 pc_update: PcUpdate::Regular,
3782 ap_update: ApUpdate::Add1,
3783 fp_update: FpUpdate::Regular,
3784 opcode: Opcode::AssertEq,
3785 opcode_extension: OpcodeExtension::Stone,
3786 };
3787 let mut builtin = HashBuiltinRunner::new(Some(8), true);
3788 builtin.base = 3;
3789 let mut vm = vm!();
3790 vm.builtin_runners.push(builtin.into());
3791 run_context!(vm, 0, 13, 12);
3792
3793 vm.segments = segments![
3795 ((3, 0), 32),
3796 ((3, 1), 72),
3797 ((1, 0), (2, 0)),
3798 ((1, 1), (3, 0)),
3799 ((1, 2), (4, 0)),
3800 ((1, 3), (5, 0)),
3801 ((1, 4), (3, 0)),
3802 ((1, 5), (1, 4)),
3803 ((1, 6), (0, 21)),
3804 ((1, 7), (3, 0)),
3805 ((1, 8), 32),
3806 ((1, 9), 72),
3807 ((1, 10), (1, 7)),
3808 ((1, 11), (0, 17)),
3809 ((1, 12), (3, 3))
3810 ];
3811
3812 let expected_operands = Operands {
3813 dst: MaybeRelocatable::from(crate::felt_hex!(
3814 "0x73b3ec210cccbb970f80c6826fb1c40ae9f487617696234ff147451405c339f"
3815 )),
3816 res: Some(MaybeRelocatable::from(crate::felt_hex!(
3817 "0x73b3ec210cccbb970f80c6826fb1c40ae9f487617696234ff147451405c339f"
3818 ))),
3819 op0: MaybeRelocatable::from((3, 0)),
3820 op1: MaybeRelocatable::from(crate::felt_hex!(
3821 "0x73b3ec210cccbb970f80c6826fb1c40ae9f487617696234ff147451405c339f"
3822 )),
3823 };
3824 let expected_operands_mem_addresses = OperandsAddresses {
3825 dst_addr: Relocatable::from((1, 13)),
3826 op0_addr: Relocatable::from((1, 7)),
3827 op1_addr: Relocatable::from((3, 2)),
3828 };
3829 let (operands, operands_mem_address, _) = vm.compute_operands(&instruction).unwrap();
3830 assert_eq!(operands, expected_operands);
3831 assert_eq!(operands_mem_address, expected_operands_mem_addresses);
3832 }
3833
3834 #[test]
3835 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3836 fn deduce_memory_cell_bitwise_builtin_valid_and() {
3837 let mut vm = vm!();
3838 let builtin = BitwiseBuiltinRunner::new(Some(256), true);
3839 vm.builtin_runners.push(builtin.into());
3840 vm.segments = segments![((0, 5), 10), ((0, 6), 12), ((0, 7), 0)];
3841 assert_matches!(
3842 vm.deduce_memory_cell(Relocatable::from((0, 7))),
3843 Ok(i) if i == Some(MaybeRelocatable::from(Felt252::from(8_i32)))
3844 );
3845 }
3846
3847 #[test]
3848 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3849 fn compute_operands_bitwise() {
3862 let instruction = Instruction {
3863 off0: 0,
3864 off1: -5,
3865 off2: 2,
3866 dst_register: Register::AP,
3867 op0_register: Register::FP,
3868 op1_addr: Op1Addr::Op0,
3869 res: Res::Op1,
3870 pc_update: PcUpdate::Regular,
3871 ap_update: ApUpdate::Add1,
3872 fp_update: FpUpdate::Regular,
3873 opcode: Opcode::AssertEq,
3874 opcode_extension: OpcodeExtension::Stone,
3875 };
3876
3877 let mut builtin = BitwiseBuiltinRunner::new(Some(256), true);
3878 builtin.base = 2;
3879 let mut vm = vm!();
3880
3881 vm.builtin_runners.push(builtin.into());
3882 run_context!(vm, 0, 9, 8);
3883
3884 vm.segments = segments![
3886 ((2, 0), 12),
3887 ((2, 1), 10),
3888 ((1, 0), (2, 0)),
3889 ((1, 1), (3, 0)),
3890 ((1, 2), (4, 0)),
3891 ((1, 3), (2, 0)),
3892 ((1, 4), 12),
3893 ((1, 5), 10),
3894 ((1, 6), (1, 3)),
3895 ((1, 7), (0, 13))
3896 ];
3897
3898 let expected_operands = Operands {
3899 dst: MaybeRelocatable::from(Felt252::from(8_i32)),
3900 res: Some(MaybeRelocatable::from(Felt252::from(8_i32))),
3901 op0: MaybeRelocatable::from((2, 0)),
3902 op1: MaybeRelocatable::from(Felt252::from(8_i32)),
3903 };
3904 let expected_operands_mem_addresses = OperandsAddresses {
3905 dst_addr: Relocatable::from((1, 9)),
3906 op0_addr: Relocatable::from((1, 3)),
3907 op1_addr: Relocatable::from((2, 2)),
3908 };
3909 let (operands, operands_mem_address, _) = vm.compute_operands(&instruction).unwrap();
3910 assert_eq!(operands, expected_operands);
3911 assert_eq!(operands_mem_address, expected_operands_mem_addresses);
3912 }
3913
3914 #[test]
3915 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3916 fn deduce_memory_cell_ec_op_builtin_valid() {
3917 let mut vm = vm!();
3918 let builtin = EcOpBuiltinRunner::new(Some(256), true);
3919 vm.builtin_runners.push(builtin.into());
3920
3921 vm.segments = segments![
3922 (
3923 (0, 0),
3924 (
3925 "0x68caa9509b7c2e90b4d92661cbf7c465471c1e8598c5f989691eef6653e0f38",
3926 16
3927 )
3928 ),
3929 (
3930 (0, 1),
3931 (
3932 "0x79a8673f498531002fc549e06ff2010ffc0c191cceb7da5532acb95cdcb591",
3933 16
3934 )
3935 ),
3936 (
3937 (0, 2),
3938 (
3939 "0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca",
3940 16
3941 )
3942 ),
3943 (
3944 (0, 3),
3945 (
3946 "0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f",
3947 16
3948 )
3949 ),
3950 ((0, 4), 34),
3951 (
3952 (0, 5),
3953 (
3954 "0x6245403e2fafe5df3b79ea28d050d477771bc560fc59e915b302cc9b70a92f5",
3955 16
3956 )
3957 )
3958 ];
3959
3960 assert_matches!(
3961 vm.deduce_memory_cell(Relocatable::from((0, 6))),
3962 Ok(i) if i == Some(MaybeRelocatable::from(felt_hex!(
3963 "0x7f49de2c3a7d1671437406869edb1805ba43e1c0173b35f8c2e8fcc13c3fa6d"
3964 )))
3965 );
3966 }
3967
3968 #[test]
3969 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3970 fn verify_auto_deductions_for_ec_op_builtin_valid() {
3987 let mut builtin = EcOpBuiltinRunner::new(Some(256), true);
3988 builtin.base = 3;
3989 let mut vm = vm!();
3990 vm.builtin_runners.push(builtin.into());
3991 vm.segments = segments![
3992 (
3993 (3, 0),
3994 (
3995 "2962412995502985605007699495352191122971573493113767820301112397466445942584",
3996 10
3997 )
3998 ),
3999 (
4000 (3, 1),
4001 (
4002 "214950771763870898744428659242275426967582168179217139798831865603966154129",
4003 10
4004 )
4005 ),
4006 (
4007 (3, 2),
4008 (
4009 "874739451078007766457464989774322083649278607533249481151382481072868806602",
4010 10
4011 )
4012 ),
4013 (
4014 (3, 3),
4015 (
4016 "152666792071518830868575557812948353041420400780739481342941381225525861407",
4017 10
4018 )
4019 ),
4020 ((3, 4), 34),
4021 (
4022 (3, 5),
4023 (
4024 "2778063437308421278851140253538604815869848682781135193774472480292420096757",
4025 10
4026 )
4027 )
4028 ];
4029 assert_matches!(vm.verify_auto_deductions(), Ok(()));
4030 }
4031
4032 #[test]
4033 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4034 fn verify_auto_deductions_for_ec_op_builtin_valid_points_invalid_result() {
4035 let mut builtin = EcOpBuiltinRunner::new(Some(256), true);
4036 builtin.base = 3;
4037 let mut vm = vm!();
4038 vm.builtin_runners.push(builtin.into());
4039 vm.segments = segments![
4040 (
4041 (3, 0),
4042 (
4043 "2962412995502985605007699495352191122971573493113767820301112397466445942584",
4044 10
4045 )
4046 ),
4047 (
4048 (3, 1),
4049 (
4050 "214950771763870898744428659242275426967582168179217139798831865603966154129",
4051 10
4052 )
4053 ),
4054 (
4055 (3, 2),
4056 (
4057 "2089986280348253421170679821480865132823066470938446095505822317253594081284",
4058 10
4059 )
4060 ),
4061 (
4062 (3, 3),
4063 (
4064 "1713931329540660377023406109199410414810705867260802078187082345529207694986",
4065 10
4066 )
4067 ),
4068 ((3, 4), 34),
4069 (
4070 (3, 5),
4071 (
4072 "2778063437308421278851140253538604815869848682781135193774472480292420096757",
4073 10
4074 )
4075 )
4076 ];
4077 let error = vm.verify_auto_deductions();
4078 assert_matches!(
4079 error,
4080 Err(VirtualMachineError::InconsistentAutoDeduction(bx))
4081 if *bx == (BuiltinName::ec_op,
4082 MaybeRelocatable::Int(crate::felt_str!(
4083 "2739017437753868763038285897969098325279422804143820990343394856167768859289"
4084 )),
4085 Some(MaybeRelocatable::Int(crate::felt_str!(
4086 "2778063437308421278851140253538604815869848682781135193774472480292420096757"
4087 ))))
4088 );
4089 }
4090
4091 #[test]
4092 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4093 fn verify_auto_deductions_bitwise() {
4106 let mut builtin = BitwiseBuiltinRunner::new(Some(256), true);
4107 builtin.base = 2;
4108 let mut vm = vm!();
4109 vm.builtin_runners.push(builtin.into());
4110 vm.segments = segments![((2, 0), 12), ((2, 1), 10)];
4111 assert_matches!(vm.verify_auto_deductions(), Ok(()));
4112 }
4113
4114 #[test]
4115 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4116 fn verify_auto_deductions_for_addr_bitwise() {
4129 let mut builtin = BitwiseBuiltinRunner::new(Some(256), true);
4130 builtin.base = 2;
4131 let builtin: BuiltinRunner = builtin.into();
4132 let mut vm = vm!();
4133 vm.segments = segments![((2, 0), 12), ((2, 1), 10)];
4134 assert_matches!(
4135 vm.verify_auto_deductions_for_addr(relocatable!(2, 0), &builtin),
4136 Ok(())
4137 );
4138 assert_matches!(
4139 vm.verify_auto_deductions_for_addr(relocatable!(2, 1), &builtin),
4140 Ok(())
4141 );
4142 }
4143
4144 #[test]
4145 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4146 fn verify_auto_deductions_pedersen() {
4170 let mut builtin = HashBuiltinRunner::new(Some(8), true);
4171 builtin.base = 3;
4172 let mut vm = vm!();
4173 vm.builtin_runners.push(builtin.into());
4174 vm.segments = segments![((3, 0), 32), ((3, 1), 72)];
4175 assert_matches!(vm.verify_auto_deductions(), Ok(()));
4176 }
4177
4178 #[test]
4179 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4180 fn can_get_return_values() {
4181 let mut vm = vm!();
4182 vm.set_ap(4);
4183 vm.segments = segments![((1, 0), 1), ((1, 1), 2), ((1, 2), 3), ((1, 3), 4)];
4184 let expected = vec![
4185 MaybeRelocatable::Int(Felt252::from(1_i32)),
4186 MaybeRelocatable::Int(Felt252::from(2_i32)),
4187 MaybeRelocatable::Int(Felt252::from(3_i32)),
4188 MaybeRelocatable::Int(Felt252::from(4_i32)),
4189 ];
4190 assert_eq!(vm.get_return_values(4).unwrap(), expected);
4191 }
4192
4193 #[test]
4194 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4195 fn get_return_values_fails_when_ap_is_0() {
4196 let mut vm = vm!();
4197 vm.segments = segments![((1, 0), 1), ((1, 1), 2), ((1, 2), 3), ((1, 3), 4)];
4198 assert_matches!(vm.get_return_values(3),
4199 Err(MemoryError::FailedToGetReturnValues(bx))
4200 if *bx == (3, Relocatable::from((1,0))));
4201 }
4202
4203 #[test]
4225 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4226 fn test_step_for_preset_memory_with_alloc_hint() {
4227 let mut vm = vm!(true);
4228 let hint_data = vec![any_box!(HintProcessorData::new_default(
4229 "memory[ap] = segments.add()".to_string(),
4230 HashMap::new(),
4231 ))];
4232
4233 run_context!(vm, 3, 2, 2);
4235
4236 for _ in 0..2 {
4238 vm.segments.add();
4239 }
4240 let mut hint_processor = BuiltinHintProcessor::new_empty();
4243
4244 vm.segments = segments![
4245 ((0, 0), 290341444919459839_i64),
4246 ((0, 1), 1),
4247 ((0, 2), 2345108766317314046_i64),
4248 ((0, 3), 1226245742482522112_i64),
4249 (
4250 (0, 4),
4251 (
4252 "3618502788666131213697322783095070105623107215331596699973092056135872020478",
4253 10
4254 )
4255 ),
4256 ((0, 5), 5189976364521848832_i64),
4257 ((0, 6), 1),
4258 ((0, 7), 4611826758063128575_i64),
4259 ((0, 8), 2345108766317314046_i64),
4260 ((1, 0), (2, 0)),
4261 ((1, 1), (3, 0))
4262 ];
4263
4264 #[cfg(feature = "extensive_hints")]
4265 let mut hint_data = hint_data;
4266
4267 for _ in 0..6 {
4269 #[cfg(not(feature = "extensive_hints"))]
4270 let mut hint_data = if vm.run_context.pc == (0, 0).into() {
4271 &hint_data[0..]
4272 } else {
4273 &hint_data[0..0]
4274 };
4275 assert_matches!(
4276 vm.step(
4277 &mut hint_processor,
4278 exec_scopes_ref!(),
4279 &mut hint_data,
4280 #[cfg(feature = "extensive_hints")]
4281 &mut HashMap::from([(
4282 Relocatable::from((0, 0)),
4283 (0_usize, NonZeroUsize::new(1).unwrap())
4284 )]),
4285 &HashMap::new(),
4286 ),
4287 Ok(())
4288 );
4289 }
4290 let trace = vm.trace.unwrap();
4292 trace_check(
4293 &trace,
4294 &[
4295 ((0, 3).into(), 2, 2),
4296 ((0, 0).into(), 4, 4),
4297 ((0, 2).into(), 5, 4),
4298 ((0, 5).into(), 5, 2),
4299 ((0, 7).into(), 6, 2),
4300 ((0, 8).into(), 6, 2),
4301 ],
4302 );
4303
4304 assert_eq!(vm.run_context.pc, Relocatable::from((3, 0)));
4306 assert_eq!(vm.run_context.ap, 6);
4307 assert_eq!(vm.run_context.fp, 0);
4308
4309 check_memory!(vm.segments.memory, ((2, 0), 1));
4312 }
4313
4314 #[test]
4315 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4316 fn test_get_builtin_runners() {
4317 let mut vm = vm!();
4318 let hash_builtin = HashBuiltinRunner::new(Some(8), true);
4319 let bitwise_builtin = BitwiseBuiltinRunner::new(Some(256), true);
4320 vm.builtin_runners.push(hash_builtin.into());
4321 vm.builtin_runners.push(bitwise_builtin.into());
4322
4323 let builtins = vm.get_builtin_runners();
4324
4325 assert_eq!(builtins[0].name(), BuiltinName::pedersen);
4326 assert_eq!(builtins[1].name(), BuiltinName::bitwise);
4327 }
4328
4329 #[test]
4330 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4331 fn test_get_output_builtin_mut() {
4332 let mut vm = vm!();
4333
4334 assert_matches!(
4335 vm.get_output_builtin_mut(),
4336 Err(VirtualMachineError::NoOutputBuiltin)
4337 );
4338
4339 let output_builtin = OutputBuiltinRunner::new(true);
4340 vm.builtin_runners.push(output_builtin.clone().into());
4341
4342 let vm_output_builtin = vm
4343 .get_output_builtin_mut()
4344 .expect("Output builtin should be returned");
4345
4346 assert_eq!(vm_output_builtin.base(), output_builtin.base());
4347 assert_eq!(vm_output_builtin.pages, output_builtin.pages);
4348 assert_eq!(vm_output_builtin.attributes, output_builtin.attributes);
4349 assert_eq!(vm_output_builtin.stop_ptr, output_builtin.stop_ptr);
4350 assert_eq!(vm_output_builtin.included, output_builtin.included);
4351 }
4352
4353 #[test]
4354 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4355 fn get_range_for_continuous_memory() {
4356 let mut vm = vm!();
4357 vm.segments = segments![((1, 0), 2), ((1, 1), 3), ((1, 2), 4)];
4358
4359 let value1 = MaybeRelocatable::from(Felt252::from(2_i32));
4360 let value2 = MaybeRelocatable::from(Felt252::from(3_i32));
4361 let value3 = MaybeRelocatable::from(Felt252::from(4_i32));
4362
4363 let expected_vec = vec![
4364 Some(Cow::Borrowed(&value1)),
4365 Some(Cow::Borrowed(&value2)),
4366 Some(Cow::Borrowed(&value3)),
4367 ];
4368 assert_eq!(vm.get_range(Relocatable::from((1, 0)), 3), expected_vec);
4369 }
4370
4371 #[test]
4372 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4373 fn get_range_for_non_continuous_memory() {
4374 let mut vm = vm!();
4375 vm.segments = segments![((1, 0), 2), ((1, 1), 3), ((1, 3), 4)];
4376
4377 let value1 = MaybeRelocatable::from(Felt252::from(2_i32));
4378 let value2 = MaybeRelocatable::from(Felt252::from(3_i32));
4379 let value3 = MaybeRelocatable::from(Felt252::from(4_i32));
4380
4381 let expected_vec = vec![
4382 Some(Cow::Borrowed(&value1)),
4383 Some(Cow::Borrowed(&value2)),
4384 None,
4385 Some(Cow::Borrowed(&value3)),
4386 ];
4387 assert_eq!(vm.get_range(Relocatable::from((1, 0)), 4), expected_vec);
4388 }
4389
4390 #[test]
4391 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4392 fn get_continuous_range_for_continuous_memory() {
4393 let mut vm = vm!();
4394 vm.segments = segments![((1, 0), 2), ((1, 1), 3), ((1, 2), 4)];
4395
4396 let value1 = MaybeRelocatable::from(Felt252::from(2_i32));
4397 let value2 = MaybeRelocatable::from(Felt252::from(3_i32));
4398 let value3 = MaybeRelocatable::from(Felt252::from(4_i32));
4399
4400 let expected_vec = vec![value1, value2, value3];
4401 assert_eq!(
4402 vm.get_continuous_range(Relocatable::from((1, 0)), 3),
4403 Ok(expected_vec)
4404 );
4405 }
4406
4407 #[test]
4408 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4409 fn get_continuous_range_for_non_continuous_memory() {
4410 let mut vm = vm!();
4411 vm.segments = segments![((1, 0), 2), ((1, 1), 3), ((1, 3), 4)];
4412
4413 assert_eq!(
4414 vm.get_continuous_range(Relocatable::from((1, 0)), 3),
4415 Err(MemoryError::GetRangeMemoryGap(Box::new(((1, 0).into(), 3))))
4416 );
4417 }
4418
4419 #[test]
4420 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4421 fn get_segment_used_size_after_computing_used() {
4422 let mut vm = vm!();
4423 vm.segments = segments![
4424 ((0, 2), 1),
4425 ((0, 5), 1),
4426 ((0, 7), 1),
4427 ((1, 1), 1),
4428 ((2, 2), 1),
4429 ((2, 4), 1),
4430 ((2, 7), 1)
4431 ];
4432 vm.segments.compute_effective_sizes();
4433 assert_eq!(Some(8), vm.get_segment_used_size(2));
4434 }
4435
4436 #[test]
4437 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4438 fn get_segment_size_before_computing_used() {
4439 let vm = vm!();
4440 assert_eq!(None, vm.get_segment_size(2));
4441 }
4442
4443 #[test]
4444 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4445 fn get_segment_size_before_computing_used_set_size() {
4446 let mut vm = vm!();
4447 vm.segments.segment_sizes.insert(2, 2);
4448 assert_eq!(Some(2), vm.get_segment_size(2));
4449 }
4450
4451 #[test]
4452 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4453 fn get_segment_size_after_computing_used() {
4454 let mut vm = vm!();
4455 vm.segments = segments![
4456 ((0, 2), 1),
4457 ((0, 5), 1),
4458 ((0, 7), 1),
4459 ((1, 1), 1),
4460 ((2, 2), 1),
4461 ((2, 4), 1),
4462 ((2, 7), 1)
4463 ];
4464 vm.segments.compute_effective_sizes();
4465 assert_eq!(Some(8), vm.get_segment_size(2));
4466 }
4467
4468 #[test]
4469 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4470 fn get_segment_used_size_before_computing_used() {
4471 let vm = vm!();
4472 assert_eq!(None, vm.get_segment_used_size(2));
4473 }
4474
4475 #[test]
4476 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4477 fn get_and_set_pc() {
4478 let mut vm = vm!();
4479 vm.set_pc(Relocatable {
4480 segment_index: 3,
4481 offset: 4,
4482 });
4483 assert_eq!(
4484 vm.get_pc(),
4485 Relocatable {
4486 segment_index: 3,
4487 offset: 4
4488 }
4489 )
4490 }
4491
4492 #[test]
4493 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4494 fn get_and_set_fp() {
4495 let mut vm = vm!();
4496 vm.set_fp(3);
4497 assert_eq!(
4498 vm.get_fp(),
4499 Relocatable {
4500 segment_index: 1,
4501 offset: 3
4502 }
4503 )
4504 }
4505
4506 #[test]
4507 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4508 fn get_maybe_key_not_in_memory() {
4509 let vm = vm!();
4510 assert_eq!(
4511 vm.get_maybe(&Relocatable {
4512 segment_index: 5,
4513 offset: 2
4514 }),
4515 None
4516 );
4517 }
4518
4519 #[test]
4520 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4521 fn get_maybe_error() {
4522 let vm = vm!();
4523 assert_eq!(
4524 vm.get_maybe(&MaybeRelocatable::Int(Felt252::from(0_i32))),
4525 None,
4526 );
4527 }
4528
4529 #[test]
4530 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4531 fn end_run_error() {
4532 let mut vm = vm!();
4533 let scopes = exec_scopes_ref!();
4534 scopes.enter_scope(HashMap::new());
4535
4536 assert_matches!(
4537 vm.end_run(scopes),
4538 Err(VirtualMachineError::MainScopeError(
4539 ExecScopeError::NoScopeError
4540 ))
4541 );
4542 }
4543
4544 #[test]
4545 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4546 fn add_temporary_segments() {
4547 let mut vm = vm!();
4548 let mut _base = vm.add_temporary_segment();
4549 assert_eq!(
4550 _base,
4551 Relocatable {
4552 segment_index: -1,
4553 offset: 0
4554 }
4555 );
4556 let mut _base = vm.add_temporary_segment();
4557 assert_eq!(
4558 _base,
4559 Relocatable {
4560 segment_index: -2,
4561 offset: 0
4562 }
4563 );
4564 }
4565
4566 #[test]
4567 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4568 fn decode_current_instruction_invalid_encoding() {
4569 let mut vm = vm!();
4570 vm.segments = segments![((0, 0), ("112233445566778899112233445566778899", 16))];
4571 assert_matches!(
4572 vm.decode_current_instruction(),
4573 Err(VirtualMachineError::InvalidInstructionEncoding)
4574 );
4575 }
4576
4577 #[test]
4578 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4579 fn add_relocation_rule_test() {
4580 let mut vm = vm!();
4581
4582 assert_eq!(
4583 vm.add_relocation_rule((-1, 0).into(), (1, 2).into()),
4584 Ok(()),
4585 );
4586 assert_eq!(
4587 vm.add_relocation_rule((-2, 0).into(), (-1, 1).into()),
4588 Ok(()),
4589 );
4590 assert_eq!(
4591 vm.add_relocation_rule((5, 0).into(), (0, 0).into()),
4592 Err(MemoryError::AddressNotInTemporarySegment(5)),
4593 );
4594 assert_eq!(
4595 vm.add_relocation_rule((-3, 6).into(), (0, 0).into()),
4596 Err(MemoryError::NonZeroOffset(6)),
4597 );
4598 assert_eq!(
4599 vm.add_relocation_rule((-1, 0).into(), (0, 0).into()),
4600 Err(MemoryError::DuplicatedRelocation(-1)),
4601 );
4602 }
4603
4604 #[test]
4605 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4606 fn gen_arg_relocatable() {
4607 let mut vm = vm!();
4608
4609 assert_matches!(
4610 vm.gen_arg(&mayberelocatable!(0, 0)),
4611 Ok(x) if x == mayberelocatable!(0, 0)
4612 );
4613 }
4614
4615 #[test]
4618 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4619 fn gen_arg_bigint() {
4620 let mut vm = vm!();
4621
4622 assert_matches!(
4623 vm.gen_arg(&mayberelocatable!(1234)),
4624 Ok(x) if x == mayberelocatable!(1234)
4625 );
4626 }
4627
4628 #[test]
4631 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4632 fn gen_arg_bigint_prime() {
4633 let mut vm = vm!();
4634 let prime = felt_hex!(crate::utils::PRIME_STR);
4635 let prime_maybe = MaybeRelocatable::from(prime);
4636
4637 assert_matches!(vm.gen_arg(&prime_maybe), Ok(x) if x == mayberelocatable!(0));
4638 }
4639
4640 #[test]
4643 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4644 fn gen_arg_vec() {
4645 let mut vm = vm!();
4646
4647 assert_matches!(
4648 vm.gen_arg(&vec![
4649 mayberelocatable!(0),
4650 mayberelocatable!(1),
4651 mayberelocatable!(2),
4652 mayberelocatable!(3),
4653 mayberelocatable!(0, 0),
4654 mayberelocatable!(0, 1),
4655 mayberelocatable!(0, 2),
4656 mayberelocatable!(0, 3),
4657 ]),
4658 Ok(x) if x == mayberelocatable!(0, 0)
4659 );
4660 }
4661
4662 #[test]
4664 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4665 fn compute_effective_sizes() {
4666 let mut vm = vm!();
4667
4668 let segment = vm.segments.add();
4669 vm.load_data(
4670 segment,
4671 &[
4672 mayberelocatable!(1),
4673 mayberelocatable!(2),
4674 mayberelocatable!(3),
4675 mayberelocatable!(4),
4676 ],
4677 )
4678 .expect("Could not load data into memory.");
4679
4680 assert_eq!(vm.segments.compute_effective_sizes(), &vec![4]);
4681 }
4682
4683 #[test]
4685 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4686 fn compute_segment_effective_sizes() {
4687 let mut vm = vm!();
4688
4689 let segment = vm.segments.add();
4690 vm.load_data(
4691 segment,
4692 &[
4693 mayberelocatable!(1),
4694 mayberelocatable!(2),
4695 mayberelocatable!(3),
4696 mayberelocatable!(4),
4697 ],
4698 )
4699 .expect("Could not load data into memory.");
4700
4701 assert_eq!(vm.segments.compute_effective_sizes(), &vec![4]);
4702 }
4703
4704 #[test]
4705 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4706 fn mark_as_accessed() {
4707 let mut vm = vm!();
4708 vm.run_finished = true;
4709 vm.segments.memory = memory![
4710 ((0, 0), 0),
4711 ((0, 1), 0),
4712 ((0, 2), 1),
4713 ((0, 10), 10),
4714 ((1, 1), 1)
4715 ];
4716 vm.mark_address_range_as_accessed((0, 0).into(), 3).unwrap();
4717 vm.mark_address_range_as_accessed((0, 10).into(), 2)
4718 .unwrap();
4719 vm.mark_address_range_as_accessed((1, 1).into(), 1).unwrap();
4720 let mem = &vm.segments.memory.data;
4723 assert!(mem[0][0].is_accessed());
4724 assert!(mem[0][1].is_accessed());
4725 assert!(mem[0][2].is_accessed());
4726 assert!(mem[0][10].is_accessed());
4727 assert!(mem[1][1].is_accessed());
4728 assert_eq!(
4729 vm.segments
4730 .memory
4731 .get_amount_of_accessed_addresses_for_segment(0),
4732 Some(4)
4733 );
4734 assert_eq!(
4735 vm.segments
4736 .memory
4737 .get_amount_of_accessed_addresses_for_segment(1),
4738 Some(1)
4739 );
4740 }
4741
4742 #[test]
4743 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4744 fn mark_as_accessed_run_not_finished() {
4745 let mut vm = vm!();
4746 assert_matches!(
4747 vm.mark_address_range_as_accessed((0, 0).into(), 3),
4748 Err(VirtualMachineError::RunNotFinished)
4749 );
4750 }
4751
4752 #[test]
4753 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4754 fn mark_as_accessed_missing_accessed_addresses() {
4755 let mut vm = vm!();
4756 assert_matches!(
4757 vm.mark_address_range_as_accessed((0, 0).into(), 3),
4758 Err(VirtualMachineError::RunNotFinished)
4759 );
4760 }
4761
4762 #[test]
4763 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4764 fn get_u32_range_ok() {
4765 let mut vm = vm!();
4766 vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967295), ((0, 3), 3)];
4767 let expected_vector = vec![1, 4294967295];
4768 assert_eq!(vm.get_u32_range((0, 1).into(), 2), Ok(expected_vector));
4769 }
4770
4771 #[test]
4772 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4773 fn get_u32_range_relocatable() {
4774 let mut vm = vm!();
4775 vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), (0, 0)), ((0, 3), 3)];
4776 assert_matches!(vm.get_u32_range((0, 1).into(), 2), Err(MemoryError::ExpectedInteger(bx)) if *bx == (0, 2).into());
4777 }
4778
4779 #[test]
4780 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4781 fn get_u32_range_over_32_bits() {
4782 let mut vm = vm!();
4783 vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967296), ((0, 3), 3)];
4784 assert_matches!(vm.get_u32_range((0, 1).into(), 2), Err(MemoryError::Math(MathError::Felt252ToU32Conversion(bx))) if *bx == Felt252::from(4294967296_u64));
4785 }
4786
4787 #[test]
4788 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4789 fn get_u32_range_memory_gap() {
4790 let mut vm = vm!();
4791 vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 3), 3)];
4792 assert_matches!(vm.get_u32_range((0, 1).into(), 3), Err(MemoryError::UnknownMemoryCell(bx)) if *bx == (0, 2).into());
4793 }
4794
4795 #[test]
4796 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4797 fn handle_blake2s_instruction_state_too_short() {
4798 let mut vm = vm!();
4799 vm.segments.memory = memory![
4800 ((0, 0), 0),
4801 ((0, 1), 0),
4802 ((0, 2), 0),
4803 ((0, 3), 0),
4804 ((0, 4), 0),
4805 ((0, 5), 0),
4806 ((0, 6), 0),
4807 ((2, 0), (0, 0))
4808 ];
4809 let operands_addresses = OperandsAddresses {
4810 dst_addr: (0, 0).into(),
4811 op0_addr: (2, 0).into(),
4812 op1_addr: (2, 0).into(),
4813 };
4814 vm.run_context = RunContext {
4815 pc: (0, 0).into(),
4816 ap: 0,
4817 fp: 0,
4818 };
4819
4820 assert_matches!(
4821 vm.handle_blake2s_instruction(&operands_addresses, false),
4822 Err(VirtualMachineError::Memory(MemoryError::UnknownMemoryCell(bx))) if *bx == (0, 7).into()
4823 );
4824 }
4825
4826 #[test]
4827 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4828 fn handle_blake2s_instruction_message_too_short() {
4829 let mut vm = vm!();
4830 vm.segments.memory = memory![
4831 ((0, 0), 0),
4832 ((0, 1), 0),
4833 ((0, 2), 0),
4834 ((0, 3), 0),
4835 ((0, 4), 0),
4836 ((0, 5), 0),
4837 ((0, 6), 0),
4838 ((0, 7), 0),
4839 ((2, 0), (0, 0))
4840 ];
4841 let operands_addresses = OperandsAddresses {
4842 dst_addr: (0, 0).into(),
4843 op0_addr: (2, 0).into(),
4844 op1_addr: (2, 0).into(),
4845 };
4846 vm.run_context = RunContext {
4847 pc: (0, 0).into(),
4848 ap: 0,
4849 fp: 0,
4850 };
4851
4852 assert_matches!(
4853 vm.handle_blake2s_instruction(&operands_addresses, false),
4854 Err(VirtualMachineError::Memory(MemoryError::UnknownMemoryCell(bx))) if *bx == (0, 8).into()
4855 );
4856 }
4857
4858 #[test]
4859 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4860 fn handle_blake2s_instruction_ap_points_to_inconsistent_memory() {
4861 let mut vm = vm!();
4862 vm.segments.memory = memory![
4863 ((0, 0), 0),
4864 ((0, 1), 0),
4865 ((0, 2), 0),
4866 ((0, 3), 0),
4867 ((0, 4), 0),
4868 ((0, 5), 0),
4869 ((0, 6), 0),
4870 ((0, 7), 0),
4871 ((0, 8), 0),
4872 ((0, 9), 0),
4873 ((0, 10), 0),
4874 ((0, 11), 0),
4875 ((0, 12), 0),
4876 ((0, 13), 0),
4877 ((0, 14), 0),
4878 ((0, 15), 0),
4879 ((1, 0), (0, 0))
4880 ];
4881 let operands_addresses = OperandsAddresses {
4882 dst_addr: (0, 0).into(),
4883 op0_addr: (1, 0).into(),
4884 op1_addr: (1, 0).into(),
4885 };
4886 vm.run_context = RunContext {
4887 pc: (0, 0).into(),
4888 ap: 0,
4889 fp: 0,
4890 };
4891
4892 assert_matches!(
4893 vm.handle_blake2s_instruction(&operands_addresses, false),
4894 Err(VirtualMachineError::Memory(MemoryError::InconsistentMemory(bx))) if *bx == ((0, 0).into(),0.into(),1848029226.into())
4895 );
4896 }
4897
4898 #[test]
4899 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4900 fn handle_blake2s_instruction_ok() {
4901 let mut vm = vm!();
4902 vm.segments.memory = memory![
4903 ((0, 0), 0x6B08E647),
4905 ((0, 1), 0xBB67AE85),
4906 ((0, 2), 0x3C6EF372),
4907 ((0, 3), 0xA54FF53A),
4908 ((0, 4), 0x510E527F),
4909 ((0, 5), 0x9B05688C),
4910 ((0, 6), 0x1F83D9AB),
4911 ((0, 7), 0x5BE0CD19),
4912 ((0, 8), 930933030),
4914 ((0, 9), 1766240503),
4915 ((0, 10), 3660871006),
4916 ((0, 11), 388409270),
4917 ((0, 12), 1948594622),
4918 ((0, 13), 3119396969),
4919 ((0, 14), 3924579183),
4920 ((0, 15), 2089920034),
4921 ((0, 16), 3857888532),
4922 ((0, 17), 929304360),
4923 ((0, 18), 1810891574),
4924 ((0, 19), 860971754),
4925 ((0, 20), 1822893775),
4926 ((0, 21), 2008495810),
4927 ((0, 22), 2958962335),
4928 ((0, 23), 2340515744),
4929 ((0, 24), 64),
4931 ((1, 0), (0, 25)),
4933 ((2, 0), (0, 0)),
4934 ((2, 1), (0, 8))
4935 ];
4936 let operands_addresses = OperandsAddresses {
4937 dst_addr: (0, 24).into(),
4938 op0_addr: (2, 0).into(),
4939 op1_addr: (2, 1).into(),
4940 };
4941 vm.run_context = RunContext {
4942 pc: (0, 0).into(),
4943 ap: 0,
4944 fp: 0,
4945 };
4946 assert_matches!(
4947 vm.handle_blake2s_instruction(&operands_addresses, false),
4948 Ok(())
4949 );
4950
4951 let state: [u32; 8] = vm
4952 .get_u32_range((0, 0).into(), 8)
4953 .unwrap()
4954 .try_into()
4955 .unwrap();
4956 let message: [u32; 16] = vm
4957 .get_u32_range((0, 8).into(), 16)
4958 .unwrap()
4959 .try_into()
4960 .unwrap();
4961 let counter = vm.segments.memory.get_u32((0, 24).into()).unwrap();
4962
4963 let expected_new_state: [u32; 8] = blake2s_compress(&state, &message, counter, 0, 0, 0)
4964 .try_into()
4965 .unwrap();
4966
4967 let new_state: [u32; 8] = vm
4968 .get_u32_range((0, 25).into(), 8)
4969 .unwrap()
4970 .try_into()
4971 .unwrap();
4972 assert_eq!(new_state, expected_new_state);
4973 }
4974
4975 #[test]
4976 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4977 fn handle_blake2s_last_block_instruction_ok() {
4978 let mut vm = vm!();
4979 vm.segments.memory = memory![
4980 ((0, 0), 0x6B08E647),
4982 ((0, 1), 0xBB67AE85),
4983 ((0, 2), 0x3C6EF372),
4984 ((0, 3), 0xA54FF53A),
4985 ((0, 4), 0x510E527F),
4986 ((0, 5), 0x9B05688C),
4987 ((0, 6), 0x1F83D9AB),
4988 ((0, 7), 0x5BE0CD19),
4989 ((0, 8), 930933030),
4991 ((0, 9), 1766240503),
4992 ((0, 10), 3660871006),
4993 ((0, 11), 388409270),
4994 ((0, 12), 1948594622),
4995 ((0, 13), 3119396969),
4996 ((0, 14), 3924579183),
4997 ((0, 15), 2089920034),
4998 ((0, 16), 3857888532),
4999 ((0, 17), 929304360),
5000 ((0, 18), 1810891574),
5001 ((0, 19), 860971754),
5002 ((0, 20), 1822893775),
5003 ((0, 21), 2008495810),
5004 ((0, 22), 2958962335),
5005 ((0, 23), 2340515744),
5006 ((0, 24), 64),
5008 ((1, 0), (0, 25)),
5010 ((2, 0), (0, 0)),
5011 ((2, 1), (0, 8))
5012 ];
5013 let operands_addresses = OperandsAddresses {
5014 dst_addr: (0, 24).into(),
5015 op0_addr: (2, 0).into(),
5016 op1_addr: (2, 1).into(),
5017 };
5018 vm.run_context = RunContext {
5019 pc: (0, 0).into(),
5020 ap: 0,
5021 fp: 0,
5022 };
5023 assert_matches!(
5024 vm.handle_blake2s_instruction(&operands_addresses, true),
5025 Ok(())
5026 );
5027
5028 let state: [u32; 8] = vm
5029 .get_u32_range((0, 0).into(), 8)
5030 .unwrap()
5031 .try_into()
5032 .unwrap();
5033 let message: [u32; 16] = vm
5034 .get_u32_range((0, 8).into(), 16)
5035 .unwrap()
5036 .try_into()
5037 .unwrap();
5038 let counter = vm.segments.memory.get_u32((0, 24).into()).unwrap();
5039
5040 let expected_new_state: [u32; 8] =
5041 blake2s_compress(&state, &message, counter, 0, 0xffffffff, 0)
5042 .try_into()
5043 .unwrap();
5044
5045 let new_state: [u32; 8] = vm
5046 .get_u32_range((0, 25).into(), 8)
5047 .unwrap()
5048 .try_into()
5049 .unwrap();
5050 assert_eq!(new_state, expected_new_state);
5051 }
5052
5053 #[test]
5054 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5055 fn get_traceback_entries_bad_usort() {
5056 let program = Program::from_bytes(
5057 include_bytes!("../../../cairo_programs/bad_programs/bad_usort.json"),
5058 Some("main"),
5059 )
5060 .unwrap();
5061
5062 let mut hint_processor = BuiltinHintProcessor::new_empty();
5063 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false);
5064
5065 let end = cairo_runner.initialize(false).unwrap();
5066 assert!(cairo_runner.run_until_pc(end, &mut hint_processor).is_err());
5067 let expected_traceback = vec![
5068 (Relocatable::from((1, 3)), Relocatable::from((0, 97))),
5069 (Relocatable::from((1, 14)), Relocatable::from((0, 30))),
5070 (Relocatable::from((1, 26)), Relocatable::from((0, 60))),
5071 ];
5072 assert_eq!(cairo_runner.vm.get_traceback_entries(), expected_traceback);
5073 }
5074
5075 #[test]
5076 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5077 fn get_traceback_entries_bad_dict_update() {
5078 let program = Program::from_bytes(
5079 include_bytes!("../../../cairo_programs/bad_programs/bad_dict_update.json"),
5080 Some("main"),
5081 )
5082 .unwrap();
5083
5084 let mut hint_processor = BuiltinHintProcessor::new_empty();
5085 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false);
5086
5087 let end = cairo_runner.initialize(false).unwrap();
5088 assert!(cairo_runner.run_until_pc(end, &mut hint_processor).is_err());
5089 let expected_traceback = vec![(Relocatable::from((1, 2)), Relocatable::from((0, 34)))];
5090 assert_eq!(cairo_runner.vm.get_traceback_entries(), expected_traceback);
5091 }
5092
5093 #[test]
5094 fn builder_test() {
5095 let virtual_machine_builder: VirtualMachineBuilder = VirtualMachineBuilder::default()
5096 .run_finished(true)
5097 .current_step(12)
5098 .builtin_runners(vec![BuiltinRunner::from(HashBuiltinRunner::new(
5099 Some(12),
5100 true,
5101 ))])
5102 .run_context(RunContext {
5103 pc: Relocatable::from((0, 0)),
5104 ap: 18,
5105 fp: 0,
5106 })
5107 .segments({
5108 let mut segments = MemorySegmentManager::new();
5109 segments.segment_used_sizes = Some(vec![1]);
5110 segments
5111 })
5112 .skip_instruction_execution(true)
5113 .trace(Some(vec![TraceEntry {
5114 pc: (0, 1).into(),
5115 ap: 1,
5116 fp: 1,
5117 }]));
5118
5119 #[cfg(feature = "test_utils")]
5120 fn before_first_step_hook(
5121 _vm: &mut VirtualMachine,
5122 _hint_data: &[Box<dyn Any>],
5123 ) -> Result<(), VirtualMachineError> {
5124 Err(VirtualMachineError::Unexpected)
5125 }
5126 #[cfg(feature = "test_utils")]
5127 let virtual_machine_builder = virtual_machine_builder.hooks(crate::vm::hooks::Hooks::new(
5128 Some(std::sync::Arc::new(before_first_step_hook)),
5129 None,
5130 None,
5131 ));
5132
5133 #[allow(unused_mut)]
5134 let mut virtual_machine_from_builder = virtual_machine_builder.build();
5135
5136 assert!(virtual_machine_from_builder.run_finished);
5137 assert_eq!(virtual_machine_from_builder.current_step, 12);
5138 assert_eq!(
5139 virtual_machine_from_builder
5140 .builtin_runners
5141 .first()
5142 .unwrap()
5143 .name(),
5144 BuiltinName::pedersen
5145 );
5146 assert_eq!(virtual_machine_from_builder.run_context.ap, 18,);
5147 assert_eq!(
5148 virtual_machine_from_builder.segments.segment_used_sizes,
5149 Some(vec![1])
5150 );
5151 assert!(virtual_machine_from_builder.skip_instruction_execution,);
5152 assert_eq!(
5153 virtual_machine_from_builder.trace,
5154 Some(vec![TraceEntry {
5155 pc: (0, 1).into(),
5156 ap: 1,
5157 fp: 1,
5158 }])
5159 );
5160 #[cfg(feature = "test_utils")]
5161 {
5162 let program = crate::types::program::Program::from_bytes(
5163 include_bytes!("../../../cairo_programs/sqrt.json"),
5164 Some("main"),
5165 )
5166 .expect("Call to `Program::from_file()` failed.");
5167 let mut hint_processor = BuiltinHintProcessor::new_empty();
5168 let mut cairo_runner = cairo_runner!(program);
5169 cairo_runner.vm = virtual_machine_from_builder;
5170 let end = cairo_runner.initialize(false).unwrap();
5171
5172 assert!(cairo_runner.run_until_pc(end, &mut hint_processor).is_err());
5173 }
5174 }
5175
5176 #[test]
5177 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5178 fn test_step_for_preset_memory_program_loaded_into_user_segment() {
5195 let mut vm = vm!(true);
5196
5197 let mut hint_processor = BuiltinHintProcessor::new_empty();
5198
5199 run_context!(vm, 0, 2, 2);
5200
5201 vm.segments = segments![
5202 ((2, 0), 2345108766317314046_u64), ((1, 0), (2, 0)),
5204 ((1, 1), (3, 0))
5205 ];
5206 vm.run_context.pc.segment_index = 2;
5208
5209 assert_matches!(
5210 vm.step(
5211 &mut hint_processor,
5212 exec_scopes_ref!(),
5213 &mut Vec::new(),
5214 #[cfg(feature = "extensive_hints")]
5215 &mut HashMap::new(),
5216 &HashMap::new()
5217 ),
5218 Ok(())
5219 );
5220 let trace = vm.trace.unwrap();
5221 trace_check(&trace, &[((2, 0).into(), 2, 2)]);
5222
5223 assert_eq!(vm.run_context.pc, Relocatable::from((3, 0)));
5224 assert_eq!(vm.run_context.ap, 2);
5225 assert_eq!(vm.run_context.fp, 0);
5226
5227 let mem = vm.segments.memory.data;
5230 assert!(mem[1][0].is_accessed());
5231 assert!(mem[1][1].is_accessed());
5232 }
5233
5234 #[test]
5235 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5236 fn test_step_for_preset_memory_function_call_program_loaded_into_user_segment() {
5267 let mut vm = vm!(true);
5268
5269 run_context!(vm, 3, 2, 2);
5270 vm.run_context.pc.segment_index = 4;
5272
5273 vm.segments.memory =
5275 memory![
5276 ((4, 0), 5207990763031199744_i64),
5278 ((4, 1), 2),
5279 ((4, 2), 2345108766317314046_i64),
5280 ((4, 3), 5189976364521848832_i64),
5281 ((4, 4), 1),
5282 ((4, 5), 1226245742482522112_i64),
5283 (
5284 (4, 6),
5285 ("3618502788666131213697322783095070105623107215331596699973092056135872020476",10)
5286 ),
5287 ((4, 7), 2345108766317314046_i64),
5288 ((1, 0), (2, 0)),
5289 ((1, 1), (3, 0))
5290 ];
5291
5292 let final_pc = Relocatable::from((3, 0));
5293 let mut hint_processor = BuiltinHintProcessor::new_empty();
5294 while vm.run_context.pc != final_pc {
5296 assert_matches!(
5297 vm.step(
5298 &mut hint_processor,
5299 exec_scopes_ref!(),
5300 &mut Vec::new(),
5301 #[cfg(feature = "extensive_hints")]
5302 &mut HashMap::new(),
5303 &HashMap::new()
5304 ),
5305 Ok(())
5306 );
5307 }
5308
5309 assert_eq!(vm.run_context.pc, Relocatable::from((3, 0)));
5311
5312 assert_eq!(vm.run_context.ap, 6);
5313
5314 assert_eq!(vm.run_context.fp, 0);
5315 let trace = vm.trace.unwrap();
5317 assert_eq!(trace.len(), 5);
5318 trace_check(
5319 &trace,
5320 &[
5321 ((4, 3).into(), 2, 2),
5322 ((4, 5).into(), 3, 2),
5323 ((4, 0).into(), 5, 5),
5324 ((4, 2).into(), 6, 5),
5325 ((4, 7).into(), 6, 2),
5326 ],
5327 );
5328 let mem = &vm.segments.memory.data;
5331 assert!(mem[4][1].is_accessed());
5332 assert!(mem[4][4].is_accessed());
5333 assert!(mem[4][6].is_accessed());
5334 assert!(mem[1][0].is_accessed());
5335 assert!(mem[1][1].is_accessed());
5336 assert!(mem[1][2].is_accessed());
5337 assert!(mem[1][3].is_accessed());
5338 assert!(mem[1][4].is_accessed());
5339 assert!(mem[1][5].is_accessed());
5340 assert_eq!(
5341 vm.segments
5342 .memory
5343 .get_amount_of_accessed_addresses_for_segment(4),
5344 Some(3)
5345 );
5346 assert_eq!(
5347 vm.segments
5348 .memory
5349 .get_amount_of_accessed_addresses_for_segment(1),
5350 Some(6)
5351 );
5352 }
5353}