cairo_vm/
typed_operations.rs1use crate::math_utils::{
2 qm31_packed_reduced_add, qm31_packed_reduced_div, qm31_packed_reduced_mul,
3 qm31_packed_reduced_sub,
4};
5use crate::stdlib::prelude::*;
6use crate::types::relocatable::MaybeRelocatable;
7use crate::types::{errors::math_errors::MathError, instruction::OpcodeExtension};
8use crate::vm::errors::vm_errors::VirtualMachineError;
9use crate::Felt252;
10
11pub fn typed_add(
17 x: &MaybeRelocatable,
18 y: &MaybeRelocatable,
19 opcode_extension: OpcodeExtension,
20) -> Result<MaybeRelocatable, VirtualMachineError> {
21 match opcode_extension {
22 OpcodeExtension::Stone => Ok(x.add(y)?),
23 OpcodeExtension::QM31Operation => {
24 if let (MaybeRelocatable::Int(num_x), MaybeRelocatable::Int(num_y)) = (x, y) {
25 Ok(MaybeRelocatable::Int(qm31_packed_reduced_add(
26 *num_x, *num_y,
27 )?))
28 } else {
29 Err(VirtualMachineError::Math(MathError::RelocatableQM31Add(
30 Box::new((x.clone(), y.clone())),
31 )))
32 }
33 }
34 _ => Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension(
35 "typed_add".to_owned().into_boxed_str(),
36 )),
37 }
38}
39
40pub fn typed_sub(
46 x: &MaybeRelocatable,
47 y: &MaybeRelocatable,
48 opcode_extension: OpcodeExtension,
49) -> Result<MaybeRelocatable, VirtualMachineError> {
50 match opcode_extension {
51 OpcodeExtension::Stone => Ok(x.sub(y)?),
52 OpcodeExtension::QM31Operation => {
53 if let (MaybeRelocatable::Int(num_x), MaybeRelocatable::Int(num_y)) = (x, y) {
54 Ok(MaybeRelocatable::Int(qm31_packed_reduced_sub(
55 *num_x, *num_y,
56 )?))
57 } else {
58 Err(VirtualMachineError::Math(MathError::RelocatableQM31Sub(
59 Box::new((x.clone(), y.clone())),
60 )))
61 }
62 }
63 _ => Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension(
64 "typed_sub".to_owned().into_boxed_str(),
65 )),
66 }
67}
68
69pub fn typed_mul(
75 x: &MaybeRelocatable,
76 y: &MaybeRelocatable,
77 opcode_extension: OpcodeExtension,
78) -> Result<MaybeRelocatable, VirtualMachineError> {
79 if let (MaybeRelocatable::Int(num_x), MaybeRelocatable::Int(num_y)) = (x, y) {
80 match opcode_extension {
81 OpcodeExtension::Stone => Ok(MaybeRelocatable::Int(num_x * num_y)),
82 OpcodeExtension::QM31Operation => Ok(MaybeRelocatable::Int(qm31_packed_reduced_mul(
83 *num_x, *num_y,
84 )?)),
85 _ => Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension(
86 "typed_mul".to_owned().into_boxed_str(),
87 )),
88 }
89 } else {
90 Err(VirtualMachineError::ComputeResRelocatableMul(Box::new((
91 x.clone(),
92 y.clone(),
93 ))))
94 }
95}
96
97pub fn typed_div(
102 x: &Felt252,
103 y: &Felt252,
104 opcode_extension: OpcodeExtension,
105) -> Result<Felt252, VirtualMachineError> {
106 match opcode_extension {
107 OpcodeExtension::Stone => {
108 Ok(x.field_div(&y.try_into().map_err(|_| MathError::DividedByZero)?))
109 }
110 OpcodeExtension::QM31Operation => Ok(qm31_packed_reduced_div(*x, *y)?),
111 _ => Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension(
112 "typed_div".to_owned().into_boxed_str(),
113 )),
114 }
115}
116#[cfg(test)]
117mod decoder_test {
118 use super::*;
119 use assert_matches::assert_matches;
120
121 #[cfg(target_arch = "wasm32")]
122 use wasm_bindgen_test::*;
123
124 #[test]
125 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
126 fn typed_add_blake() {
127 let a = &MaybeRelocatable::from(5);
128 let b = &MaybeRelocatable::from(6);
129 let error = typed_add(a, b, OpcodeExtension::Blake);
130 assert_matches!(
131 error,
132 Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension(ref message)) if message.as_ref() == "typed_add"
133 );
134 }
135
136 #[test]
137 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
138 fn typed_sub_blake() {
139 let a = &MaybeRelocatable::from(7);
140 let b = &MaybeRelocatable::from(3);
141 let error = typed_sub(a, b, OpcodeExtension::Blake);
142 assert_matches!(
143 error,
144 Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension(ref message)) if message.as_ref() == "typed_sub"
145 );
146 }
147
148 #[test]
149 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
150 fn relocatable_typed_sub_q31_operation() {
151 let a = &MaybeRelocatable::from((6, 8));
152 let b = &MaybeRelocatable::from(2);
153 let error = typed_sub(a, b, OpcodeExtension::QM31Operation);
154 assert_matches!(
155 error,
156 Err(VirtualMachineError::Math(MathError::RelocatableQM31Sub(bx))) if *bx ==
157 (MaybeRelocatable::from((6, 8)), MaybeRelocatable::from(2))
158 );
159 }
160
161 #[test]
162 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
163 fn typed_mul_blake_finalize() {
164 let a = &MaybeRelocatable::from(4);
165 let b = &MaybeRelocatable::from(9);
166 let error = typed_mul(a, b, OpcodeExtension::BlakeFinalize);
167 assert_matches!(
168 error,
169 Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension(ref message)) if message.as_ref() == "typed_mul"
170 );
171 }
172}