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