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