cairo_vm/vm/runners/builtin_runner/
mod.rs

1use crate::air_private_input::PrivateInput;
2use crate::math_utils::safe_div_usize;
3use crate::stdlib::prelude::*;
4use crate::types::builtin_name::BuiltinName;
5use crate::types::instance_definitions::bitwise_instance_def::{
6    CELLS_PER_BITWISE, INPUT_CELLS_PER_BITWISE,
7};
8use crate::types::instance_definitions::builtins_instance_def::BUILTIN_INSTANCES_PER_COMPONENT;
9use crate::types::instance_definitions::ec_op_instance_def::{
10    CELLS_PER_EC_OP, INPUT_CELLS_PER_EC_OP,
11};
12use crate::types::instance_definitions::ecdsa_instance_def::CELLS_PER_SIGNATURE;
13use crate::types::instance_definitions::keccak_instance_def::{
14    CELLS_PER_KECCAK, INPUT_CELLS_PER_KECCAK, KECCAK_INSTANCES_PER_COMPONENT,
15};
16use crate::types::instance_definitions::mod_instance_def::CELLS_PER_MOD;
17use crate::types::instance_definitions::pedersen_instance_def::{
18    CELLS_PER_HASH, INPUT_CELLS_PER_HASH,
19};
20use crate::types::instance_definitions::poseidon_instance_def::{
21    CELLS_PER_POSEIDON, INPUT_CELLS_PER_POSEIDON,
22};
23use crate::types::instance_definitions::range_check_instance_def::CELLS_PER_RANGE_CHECK;
24use crate::types::relocatable::{MaybeRelocatable, Relocatable};
25use crate::vm::errors::memory_errors::{self, InsufficientAllocatedCellsError, MemoryError};
26use crate::vm::errors::runner_errors::RunnerError;
27use crate::vm::errors::vm_errors::VirtualMachineError;
28use crate::vm::vm_core::VirtualMachine;
29use crate::vm::vm_memory::memory::Memory;
30use crate::vm::vm_memory::memory_segments::MemorySegmentManager;
31
32mod bitwise;
33mod ec_op;
34mod hash;
35mod keccak;
36mod modulo;
37mod output;
38mod poseidon;
39mod range_check;
40mod segment_arena;
41mod signature;
42
43pub use self::keccak::KeccakBuiltinRunner;
44pub(crate) use self::range_check::{RC_N_PARTS_96, RC_N_PARTS_STANDARD};
45use self::segment_arena::ARENA_BUILTIN_SIZE;
46pub use bitwise::BitwiseBuiltinRunner;
47pub use ec_op::EcOpBuiltinRunner;
48pub use hash::HashBuiltinRunner;
49pub use modulo::ModBuiltinRunner;
50use num_integer::{div_ceil, div_floor};
51pub use output::{OutputBuiltinRunner, OutputBuiltinState};
52pub use poseidon::PoseidonBuiltinRunner;
53pub use range_check::RangeCheckBuiltinRunner;
54pub use segment_arena::SegmentArenaBuiltinRunner;
55pub use signature::SignatureBuiltinRunner;
56
57use super::cairo_pie::BuiltinAdditionalData;
58
59/* NB: this enum is no accident: we may need (and cairo-vm-py *does* need)
60 * structs containing this to be `Send`. The only two ways to achieve that
61 * are either storing a `dyn Trait` inside an `Arc<Mutex<&dyn Trait>>` or
62 * making the type itself `Send`. We opted for not complicating the user nor
63 * moving the guarantees to runtime by using an `enum` rather than a `Trait`.
64 * This works under the assumption that we don't expect downstream users to
65 * extend Cairo by adding new builtin runners.
66 */
67#[derive(Debug, Clone)]
68pub enum BuiltinRunner {
69    Bitwise(BitwiseBuiltinRunner),
70    EcOp(EcOpBuiltinRunner),
71    Hash(HashBuiltinRunner),
72    Output(OutputBuiltinRunner),
73    RangeCheck(RangeCheckBuiltinRunner<RC_N_PARTS_STANDARD>),
74    RangeCheck96(RangeCheckBuiltinRunner<RC_N_PARTS_96>),
75    Keccak(KeccakBuiltinRunner),
76    Signature(SignatureBuiltinRunner),
77    Poseidon(PoseidonBuiltinRunner),
78    SegmentArena(SegmentArenaBuiltinRunner),
79    Mod(ModBuiltinRunner),
80}
81
82impl BuiltinRunner {
83    ///Creates the necessary segments for the builtin in the MemorySegmentManager and stores the first address on the builtin's base
84    pub fn initialize_segments(&mut self, segments: &mut MemorySegmentManager) {
85        match *self {
86            BuiltinRunner::Bitwise(ref mut bitwise) => bitwise.initialize_segments(segments),
87            BuiltinRunner::EcOp(ref mut ec) => ec.initialize_segments(segments),
88            BuiltinRunner::Hash(ref mut hash) => hash.initialize_segments(segments),
89            BuiltinRunner::Output(ref mut output) => output.initialize_segments(segments),
90            BuiltinRunner::RangeCheck(ref mut range_check) => {
91                range_check.initialize_segments(segments)
92            }
93            BuiltinRunner::RangeCheck96(ref mut range_check) => {
94                range_check.initialize_segments(segments)
95            }
96            BuiltinRunner::Keccak(ref mut keccak) => keccak.initialize_segments(segments),
97            BuiltinRunner::Signature(ref mut signature) => signature.initialize_segments(segments),
98            BuiltinRunner::Poseidon(ref mut poseidon) => poseidon.initialize_segments(segments),
99            BuiltinRunner::SegmentArena(ref mut segment_arena) => {
100                segment_arena.initialize_segments(segments)
101            }
102            BuiltinRunner::Mod(ref mut modulo) => modulo.initialize_segments(segments),
103        }
104    }
105
106    pub fn initial_stack(&self) -> Vec<MaybeRelocatable> {
107        match *self {
108            BuiltinRunner::Bitwise(ref bitwise) => bitwise.initial_stack(),
109            BuiltinRunner::EcOp(ref ec) => ec.initial_stack(),
110            BuiltinRunner::Hash(ref hash) => hash.initial_stack(),
111            BuiltinRunner::Output(ref output) => output.initial_stack(),
112            BuiltinRunner::RangeCheck(ref range_check) => range_check.initial_stack(),
113            BuiltinRunner::RangeCheck96(ref range_check) => range_check.initial_stack(),
114            BuiltinRunner::Keccak(ref keccak) => keccak.initial_stack(),
115            BuiltinRunner::Signature(ref signature) => signature.initial_stack(),
116            BuiltinRunner::Poseidon(ref poseidon) => poseidon.initial_stack(),
117            BuiltinRunner::SegmentArena(ref segment_arena) => segment_arena.initial_stack(),
118            BuiltinRunner::Mod(ref modulo) => modulo.initial_stack(),
119        }
120    }
121
122    ///Returns the builtin's final stack
123    pub fn final_stack(
124        &mut self,
125        segments: &MemorySegmentManager,
126        pointer: Relocatable,
127    ) -> Result<Relocatable, RunnerError> {
128        if let BuiltinRunner::Output(output) = self {
129            return output.final_stack(segments, pointer);
130        }
131        if self.included() {
132            let stop_pointer_addr =
133                (pointer - 1).map_err(|_| RunnerError::NoStopPointer(Box::new(self.name())))?;
134            let stop_pointer = segments
135                .memory
136                .get_relocatable(stop_pointer_addr)
137                .map_err(|_| RunnerError::NoStopPointer(Box::new(self.name())))?;
138            if self.base() as isize != stop_pointer.segment_index {
139                return Err(RunnerError::InvalidStopPointerIndex(Box::new((
140                    self.name(),
141                    stop_pointer,
142                    self.base(),
143                ))));
144            }
145            let stop_ptr = stop_pointer.offset;
146            let mut num_instances = self.get_used_instances(segments)?;
147            if matches!(self, BuiltinRunner::SegmentArena(_)) {
148                // SegmentArena builtin starts with one instance pre-loaded
149                // This is reflected in the builtin base's offset, but as we compare `stop_ptr.offset` agains `used`
150                // instead of comparing `stop_ptr` against `base + used` we need to account for the base offset (aka the pre-loaded instance) here
151                num_instances += 1;
152            }
153            let used = num_instances * self.cells_per_instance() as usize;
154            if stop_ptr != used {
155                return Err(RunnerError::InvalidStopPointer(Box::new((
156                    self.name(),
157                    Relocatable::from((self.base() as isize, used)),
158                    Relocatable::from((self.base() as isize, stop_ptr)),
159                ))));
160            }
161            self.set_stop_ptr(stop_ptr);
162            Ok(stop_pointer_addr)
163        } else {
164            self.set_stop_ptr(0);
165            Ok(pointer)
166        }
167    }
168
169    ///Returns the builtin's allocated memory units
170    pub fn get_allocated_memory_units(
171        &self,
172        vm: &VirtualMachine,
173    ) -> Result<usize, memory_errors::MemoryError> {
174        Ok(self.get_allocated_instances(vm)? * self.cells_per_instance() as usize)
175    }
176
177    ///Returns the builtin's allocated instances
178    pub fn get_allocated_instances(
179        &self,
180        vm: &VirtualMachine,
181    ) -> Result<usize, memory_errors::MemoryError> {
182        match *self {
183            BuiltinRunner::Output(_) | BuiltinRunner::SegmentArena(_) => Ok(0),
184            _ => {
185                match self.ratio() {
186                    None => {
187                        // Dynamic layout has the exact number of instances it needs (up to a power of 2).
188                        let instances: usize =
189                            self.get_used_cells(&vm.segments)? / self.cells_per_instance() as usize;
190                        let needed_components = instances / self.instances_per_component() as usize;
191
192                        let components = if needed_components > 0 {
193                            needed_components.next_power_of_two()
194                        } else {
195                            0
196                        };
197                        Ok(self.instances_per_component() as usize * components)
198                    }
199                    // Dynamic layout allows for builtins with ratio 0
200                    Some(0) => Ok(0),
201                    Some(ratio) => {
202                        let min_step_num = (ratio * self.instances_per_component()) as usize;
203                        let min_step = if let Some(ratio_den) = self.ratio_den() {
204                            div_ceil(min_step_num, ratio_den as usize)
205                        } else {
206                            min_step_num
207                        };
208
209                        if vm.current_step < min_step {
210                            return Err(InsufficientAllocatedCellsError::MinStepNotReached(
211                                Box::new((min_step, self.name())),
212                            )
213                            .into());
214                        };
215
216                        let allocated_instances = if let Some(ratio_den) = self.ratio_den() {
217                            safe_div_usize(vm.current_step * ratio_den as usize, ratio as usize)
218                                .map_err(|_| MemoryError::ErrorCalculatingMemoryUnits)?
219                        } else {
220                            safe_div_usize(vm.current_step, ratio as usize)
221                                .map_err(|_| MemoryError::ErrorCalculatingMemoryUnits)?
222                        };
223                        Ok(allocated_instances)
224                    }
225                }
226            }
227        }
228    }
229
230    /// Returns if the builtin is included in the program builtins
231    fn included(&self) -> bool {
232        match *self {
233            BuiltinRunner::Bitwise(ref bitwise) => bitwise.included,
234            BuiltinRunner::EcOp(ref ec) => ec.included,
235            BuiltinRunner::Hash(ref hash) => hash.included,
236            BuiltinRunner::Output(ref output) => output.included,
237            BuiltinRunner::RangeCheck(ref range_check) => range_check.included,
238            BuiltinRunner::RangeCheck96(ref range_check) => range_check.included,
239            BuiltinRunner::Keccak(ref keccak) => keccak.included,
240            BuiltinRunner::Signature(ref signature) => signature.included,
241            BuiltinRunner::Poseidon(ref poseidon) => poseidon.included,
242            BuiltinRunner::SegmentArena(ref segment_arena) => segment_arena.included,
243            BuiltinRunner::Mod(ref modulo) => modulo.included,
244        }
245    }
246
247    ///Returns the builtin's base
248    pub fn base(&self) -> usize {
249        match *self {
250            BuiltinRunner::Bitwise(ref bitwise) => bitwise.base(),
251            BuiltinRunner::EcOp(ref ec) => ec.base(),
252            BuiltinRunner::Hash(ref hash) => hash.base(),
253            BuiltinRunner::Output(ref output) => output.base(),
254            BuiltinRunner::RangeCheck(ref range_check) => range_check.base(),
255            BuiltinRunner::RangeCheck96(ref range_check) => range_check.base(),
256            BuiltinRunner::Keccak(ref keccak) => keccak.base(),
257            BuiltinRunner::Signature(ref signature) => signature.base(),
258            BuiltinRunner::Poseidon(ref poseidon) => poseidon.base(),
259            //Warning, returns only the segment index, base offset will be 3
260            BuiltinRunner::SegmentArena(ref segment_arena) => segment_arena.base(),
261            BuiltinRunner::Mod(ref modulo) => modulo.base(),
262        }
263    }
264
265    pub fn ratio(&self) -> Option<u32> {
266        match self {
267            BuiltinRunner::Bitwise(bitwise) => bitwise.ratio(),
268            BuiltinRunner::EcOp(ec) => ec.ratio(),
269            BuiltinRunner::Hash(hash) => hash.ratio(),
270            BuiltinRunner::Output(_) | BuiltinRunner::SegmentArena(_) => None,
271            BuiltinRunner::RangeCheck(range_check) => range_check.ratio(),
272            BuiltinRunner::RangeCheck96(range_check) => range_check.ratio(),
273            BuiltinRunner::Keccak(keccak) => keccak.ratio(),
274            BuiltinRunner::Signature(ref signature) => signature.ratio(),
275            BuiltinRunner::Poseidon(poseidon) => poseidon.ratio(),
276            BuiltinRunner::Mod(ref modulo) => modulo.ratio(),
277        }
278    }
279
280    pub fn ratio_den(&self) -> Option<u32> {
281        match self {
282            BuiltinRunner::RangeCheck(range_check) => range_check.ratio_den(),
283            BuiltinRunner::RangeCheck96(range_check) => range_check.ratio_den(),
284            BuiltinRunner::Mod(modulo) => modulo.ratio_den(),
285            _ => None,
286        }
287    }
288
289    pub fn add_validation_rule(&self, memory: &mut Memory) {
290        match *self {
291            BuiltinRunner::RangeCheck(ref range_check) => range_check.add_validation_rule(memory),
292            BuiltinRunner::RangeCheck96(ref range_check) => range_check.add_validation_rule(memory),
293            BuiltinRunner::Signature(ref signature) => signature.add_validation_rule(memory),
294            BuiltinRunner::Poseidon(ref poseidon) => poseidon.add_validation_rule(memory),
295            _ => {}
296        }
297    }
298
299    pub fn deduce_memory_cell(
300        &self,
301        address: Relocatable,
302        memory: &Memory,
303    ) -> Result<Option<MaybeRelocatable>, RunnerError> {
304        match *self {
305            BuiltinRunner::Bitwise(ref bitwise) => bitwise.deduce_memory_cell(address, memory),
306            BuiltinRunner::EcOp(ref ec) => ec.deduce_memory_cell(address, memory),
307            BuiltinRunner::Hash(ref hash) => hash.deduce_memory_cell(address, memory),
308            BuiltinRunner::Keccak(ref keccak) => keccak.deduce_memory_cell(address, memory),
309            BuiltinRunner::Poseidon(ref poseidon) => poseidon.deduce_memory_cell(address, memory),
310            _ => Ok(None),
311        }
312    }
313
314    pub fn get_memory_segment_addresses(&self) -> (usize, Option<usize>) {
315        (self.base(), self.stop_ptr())
316    }
317
318    pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result<usize, MemoryError> {
319        match self {
320            BuiltinRunner::Bitwise(ref bitwise) => bitwise.get_used_cells(segments),
321            BuiltinRunner::EcOp(ref ec) => ec.get_used_cells(segments),
322            BuiltinRunner::Hash(ref hash) => hash.get_used_cells(segments),
323            BuiltinRunner::Output(ref output) => output.get_used_cells(segments),
324            BuiltinRunner::RangeCheck(ref range_check) => range_check.get_used_cells(segments),
325            BuiltinRunner::RangeCheck96(ref range_check) => range_check.get_used_cells(segments),
326            BuiltinRunner::Keccak(ref keccak) => keccak.get_used_cells(segments),
327            BuiltinRunner::Signature(ref signature) => signature.get_used_cells(segments),
328            BuiltinRunner::Poseidon(ref poseidon) => poseidon.get_used_cells(segments),
329            BuiltinRunner::SegmentArena(ref segment_arena) => {
330                segment_arena.get_used_cells(segments)
331            }
332            BuiltinRunner::Mod(ref modulo) => modulo.get_used_cells(segments),
333        }
334    }
335
336    pub fn get_used_instances(
337        &self,
338        segments: &MemorySegmentManager,
339    ) -> Result<usize, MemoryError> {
340        match self {
341            BuiltinRunner::Bitwise(ref bitwise) => bitwise.get_used_instances(segments),
342            BuiltinRunner::EcOp(ref ec) => ec.get_used_instances(segments),
343            BuiltinRunner::Hash(ref hash) => hash.get_used_instances(segments),
344            BuiltinRunner::Output(ref output) => output.get_used_instances(segments),
345            BuiltinRunner::RangeCheck(ref range_check) => range_check.get_used_instances(segments),
346            BuiltinRunner::RangeCheck96(ref range_check) => {
347                range_check.get_used_instances(segments)
348            }
349            BuiltinRunner::Keccak(ref keccak) => keccak.get_used_instances(segments),
350            BuiltinRunner::Signature(ref signature) => signature.get_used_instances(segments),
351            BuiltinRunner::Poseidon(ref poseidon) => poseidon.get_used_instances(segments),
352            BuiltinRunner::SegmentArena(ref segment_arena) => {
353                segment_arena.get_used_instances(segments)
354            }
355            BuiltinRunner::Mod(modulo) => modulo.get_used_instances(segments),
356        }
357    }
358
359    pub fn get_range_check_usage(&self, memory: &Memory) -> Option<(usize, usize)> {
360        match self {
361            BuiltinRunner::RangeCheck(ref range_check) => range_check.get_range_check_usage(memory),
362            BuiltinRunner::RangeCheck96(ref range_check) => {
363                range_check.get_range_check_usage(memory)
364            }
365            _ => None,
366        }
367    }
368
369    /// Returns the number of range check units used by the builtin.
370    pub fn get_used_perm_range_check_units(
371        &self,
372        vm: &VirtualMachine,
373    ) -> Result<usize, MemoryError> {
374        match self {
375            BuiltinRunner::RangeCheck(range_check) => {
376                let (used_cells, _) = self.get_used_cells_and_allocated_size(vm)?;
377                Ok(used_cells * range_check.n_parts() as usize)
378            }
379            BuiltinRunner::RangeCheck96(range_check) => {
380                let (used_cells, _) = self.get_used_cells_and_allocated_size(vm)?;
381                Ok(used_cells * range_check.n_parts() as usize)
382            }
383            _ => Ok(0),
384        }
385    }
386
387    pub fn get_used_diluted_check_units(&self, diluted_spacing: u32, diluted_n_bits: u32) -> usize {
388        match self {
389            BuiltinRunner::Bitwise(ref bitwise) => {
390                bitwise.get_used_diluted_check_units(diluted_spacing, diluted_n_bits)
391            }
392            BuiltinRunner::Keccak(ref keccak) => {
393                keccak.get_used_diluted_check_units(diluted_n_bits)
394            }
395            _ => 0,
396        }
397    }
398
399    fn cells_per_instance(&self) -> u32 {
400        match self {
401            BuiltinRunner::Bitwise(_) => CELLS_PER_BITWISE,
402            BuiltinRunner::EcOp(_) => CELLS_PER_EC_OP,
403            BuiltinRunner::Hash(_) => CELLS_PER_HASH,
404            BuiltinRunner::RangeCheck(_) | BuiltinRunner::RangeCheck96(_) => CELLS_PER_RANGE_CHECK,
405            BuiltinRunner::Output(_) => 0,
406            BuiltinRunner::Keccak(_) => CELLS_PER_KECCAK,
407            BuiltinRunner::Signature(_) => CELLS_PER_SIGNATURE,
408            BuiltinRunner::Poseidon(_) => CELLS_PER_POSEIDON,
409            BuiltinRunner::SegmentArena(_) => ARENA_BUILTIN_SIZE,
410            BuiltinRunner::Mod(_) => CELLS_PER_MOD,
411        }
412    }
413
414    fn n_input_cells(&self) -> u32 {
415        match self {
416            BuiltinRunner::Bitwise(_) => INPUT_CELLS_PER_BITWISE,
417            BuiltinRunner::EcOp(_) => INPUT_CELLS_PER_EC_OP,
418            BuiltinRunner::Hash(_) => INPUT_CELLS_PER_HASH,
419            BuiltinRunner::RangeCheck(_) | BuiltinRunner::RangeCheck96(_) => CELLS_PER_RANGE_CHECK,
420            BuiltinRunner::Output(_) => 0,
421            BuiltinRunner::Keccak(_) => INPUT_CELLS_PER_KECCAK,
422            BuiltinRunner::Signature(_) => CELLS_PER_SIGNATURE,
423            BuiltinRunner::Poseidon(_) => INPUT_CELLS_PER_POSEIDON,
424            BuiltinRunner::SegmentArena(_) => ARENA_BUILTIN_SIZE,
425            BuiltinRunner::Mod(_) => CELLS_PER_MOD,
426        }
427    }
428
429    fn instances_per_component(&self) -> u32 {
430        match self {
431            BuiltinRunner::Keccak(_) => KECCAK_INSTANCES_PER_COMPONENT,
432            _ => BUILTIN_INSTANCES_PER_COMPONENT,
433        }
434    }
435
436    pub fn name(&self) -> BuiltinName {
437        match self {
438            BuiltinRunner::Bitwise(_) => BuiltinName::bitwise,
439            BuiltinRunner::EcOp(_) => BuiltinName::ec_op,
440            BuiltinRunner::Hash(_) => BuiltinName::pedersen,
441            BuiltinRunner::RangeCheck(_) => BuiltinName::range_check,
442            BuiltinRunner::RangeCheck96(_) => BuiltinName::range_check96,
443            BuiltinRunner::Output(_) => BuiltinName::output,
444            BuiltinRunner::Keccak(_) => BuiltinName::keccak,
445            BuiltinRunner::Signature(_) => BuiltinName::ecdsa,
446            BuiltinRunner::Poseidon(_) => BuiltinName::poseidon,
447            BuiltinRunner::SegmentArena(_) => BuiltinName::segment_arena,
448            BuiltinRunner::Mod(b) => b.name(),
449        }
450    }
451
452    pub fn run_security_checks(&self, vm: &VirtualMachine) -> Result<(), VirtualMachineError> {
453        if let BuiltinRunner::Output(_) | BuiltinRunner::SegmentArena(_) = self {
454            return Ok(());
455        }
456        if let BuiltinRunner::Mod(modulo) = self {
457            modulo.run_additional_security_checks(vm)?;
458        }
459        let cells_per_instance = self.cells_per_instance() as usize;
460        let n_input_cells = self.n_input_cells() as usize;
461        let builtin_segment_index = self.base();
462        // If the builtin's segment is empty, there are no security checks to run
463        let builtin_segment = match vm.segments.memory.data.get(builtin_segment_index) {
464            Some(segment) if !segment.is_empty() => segment,
465            _ => return Ok(()),
466        };
467        // The builtin segment's size - 1 is the maximum offset within the segment's addresses
468        // Assumption: The last element is not a None value
469        // It is safe to asume this for normal program execution
470        // If there are trailing None values at the end, the following security checks will fail
471        let offset_max = builtin_segment.len().saturating_sub(1);
472        // offset_len is the amount of non-None values in the segment
473        let offset_len = builtin_segment.iter().filter(|x| x.is_some()).count();
474        let n = match offset_len {
475            0 => 0,
476            _ => div_floor(offset_max, cells_per_instance) + 1,
477        };
478        // Verify that n is not too large to make sure the expected_offsets set that is constructed
479        // below is not too large.
480        if n > div_floor(offset_len, n_input_cells) {
481            return Err(MemoryError::MissingMemoryCells(Box::new(self.name())).into());
482        }
483        // Check that the two inputs (x and y) of each instance are set.
484        let mut missing_offsets = Vec::with_capacity(n);
485        // Check for missing expected offsets (either their address is no present, or their value is None)
486        for i in 0..n {
487            for j in 0..n_input_cells {
488                let offset = cells_per_instance * i + j;
489                if builtin_segment
490                    .get(offset)
491                    .filter(|x| x.is_some())
492                    .is_none()
493                {
494                    missing_offsets.push(offset)
495                }
496            }
497        }
498        if !missing_offsets.is_empty() {
499            return Err(MemoryError::MissingMemoryCellsWithOffsets(Box::new((
500                self.name(),
501                missing_offsets,
502            )))
503            .into());
504        }
505        // Verify auto deduction rules for the unasigned output cells
506        // Assigned output cells are checked as part of the call to verify_auto_deductions().
507        for i in 0..n {
508            for j in n_input_cells..cells_per_instance {
509                let offset = cells_per_instance * i + j;
510                if builtin_segment
511                    .get(offset)
512                    .filter(|x| x.is_some())
513                    .is_none()
514                {
515                    vm.verify_auto_deductions_for_addr(
516                        Relocatable::from((builtin_segment_index as isize, offset)),
517                        self,
518                    )?;
519                }
520            }
521        }
522        Ok(())
523    }
524
525    pub fn get_used_cells_and_allocated_size(
526        &self,
527        vm: &VirtualMachine,
528    ) -> Result<(usize, usize), MemoryError> {
529        match self {
530            BuiltinRunner::Output(_) | BuiltinRunner::SegmentArena(_) => {
531                let used = self.get_used_cells(&vm.segments)?;
532                Ok((used, used))
533            }
534            _ => {
535                let used_cells = self.get_used_cells(&vm.segments)?;
536                if vm.disable_trace_padding {
537                    // If trace padding is disabled, we pad the used cells to still ensure that the
538                    // number of instances is a power of 2.
539                    let num_instances = self.get_used_instances(&vm.segments)?;
540                    let padded_used_cells = if num_instances > 0 {
541                        num_instances.next_power_of_two() * self.cells_per_instance() as usize
542                    } else {
543                        0
544                    };
545                    Ok((used_cells, padded_used_cells))
546                } else {
547                    let size = self.get_allocated_memory_units(vm)?;
548                    if used_cells > size {
549                        return Err(InsufficientAllocatedCellsError::BuiltinCells(Box::new((
550                            self.name(),
551                            used_cells,
552                            size,
553                        )))
554                        .into());
555                    }
556                    Ok((used_cells, size))
557                }
558            }
559        }
560    }
561
562    /// Returns data stored internally by builtins needed to re-execute from a cairo pie
563    pub fn get_additional_data(&self) -> BuiltinAdditionalData {
564        match self {
565            BuiltinRunner::Hash(builtin) => builtin.get_additional_data(),
566            BuiltinRunner::Output(builtin) => builtin.get_additional_data(),
567            BuiltinRunner::Signature(builtin) => builtin.get_additional_data(),
568            _ => BuiltinAdditionalData::None,
569        }
570    }
571
572    /// Extends the builtin's internal data with the internal data obtained from a previous cairo execution
573    /// Used solely when running from a cairo pie
574    pub fn extend_additional_data(
575        &mut self,
576        additional_data: &BuiltinAdditionalData,
577    ) -> Result<(), RunnerError> {
578        match self {
579            BuiltinRunner::Hash(builtin) => builtin.extend_additional_data(additional_data),
580            BuiltinRunner::Output(builtin) => builtin.extend_additional_data(additional_data),
581            BuiltinRunner::Signature(builtin) => builtin.extend_additional_data(additional_data),
582            _ => Ok(()),
583        }
584    }
585
586    // Returns information about the builtin that should be added to the AIR private input.
587    pub fn air_private_input(&self, segments: &MemorySegmentManager) -> Vec<PrivateInput> {
588        match self {
589            BuiltinRunner::RangeCheck(builtin) => builtin.air_private_input(&segments.memory),
590            BuiltinRunner::RangeCheck96(builtin) => builtin.air_private_input(&segments.memory),
591            BuiltinRunner::Bitwise(builtin) => builtin.air_private_input(&segments.memory),
592            BuiltinRunner::Hash(builtin) => builtin.air_private_input(&segments.memory),
593            BuiltinRunner::EcOp(builtin) => builtin.air_private_input(&segments.memory),
594            BuiltinRunner::Poseidon(builtin) => builtin.air_private_input(&segments.memory),
595            BuiltinRunner::Signature(builtin) => builtin.air_private_input(&segments.memory),
596            BuiltinRunner::Keccak(builtin) => builtin.air_private_input(&segments.memory),
597            BuiltinRunner::Mod(builtin) => builtin.air_private_input(segments),
598            _ => vec![],
599        }
600    }
601
602    pub(crate) fn set_stop_ptr(&mut self, stop_ptr: usize) {
603        match self {
604            BuiltinRunner::Bitwise(ref mut bitwise) => bitwise.stop_ptr = Some(stop_ptr),
605            BuiltinRunner::EcOp(ref mut ec) => ec.stop_ptr = Some(stop_ptr),
606            BuiltinRunner::Hash(ref mut hash) => hash.stop_ptr = Some(stop_ptr),
607            BuiltinRunner::Output(ref mut output) => output.stop_ptr = Some(stop_ptr),
608            BuiltinRunner::RangeCheck(ref mut range_check) => range_check.stop_ptr = Some(stop_ptr),
609            BuiltinRunner::RangeCheck96(ref mut range_check) => {
610                range_check.stop_ptr = Some(stop_ptr)
611            }
612            BuiltinRunner::Keccak(ref mut keccak) => keccak.stop_ptr = Some(stop_ptr),
613            BuiltinRunner::Signature(ref mut signature) => signature.stop_ptr = Some(stop_ptr),
614            BuiltinRunner::Poseidon(ref mut poseidon) => poseidon.stop_ptr = Some(stop_ptr),
615            BuiltinRunner::SegmentArena(ref mut segment_arena) => {
616                segment_arena.stop_ptr = Some(stop_ptr)
617            }
618            BuiltinRunner::Mod(modulo) => modulo.stop_ptr = Some(stop_ptr),
619        }
620    }
621
622    pub(crate) fn stop_ptr(&self) -> Option<usize> {
623        match self {
624            BuiltinRunner::Bitwise(ref bitwise) => bitwise.stop_ptr,
625            BuiltinRunner::EcOp(ref ec) => ec.stop_ptr,
626            BuiltinRunner::Hash(ref hash) => hash.stop_ptr,
627            BuiltinRunner::Output(ref output) => output.stop_ptr,
628            BuiltinRunner::RangeCheck(ref range_check) => range_check.stop_ptr,
629            BuiltinRunner::RangeCheck96(ref range_check) => range_check.stop_ptr,
630            BuiltinRunner::Keccak(ref keccak) => keccak.stop_ptr,
631            BuiltinRunner::Signature(ref signature) => signature.stop_ptr,
632            BuiltinRunner::Poseidon(ref poseidon) => poseidon.stop_ptr,
633            BuiltinRunner::SegmentArena(ref segment_arena) => segment_arena.stop_ptr,
634            BuiltinRunner::Mod(ref modulo) => modulo.stop_ptr,
635        }
636    }
637}
638
639impl From<KeccakBuiltinRunner> for BuiltinRunner {
640    fn from(runner: KeccakBuiltinRunner) -> Self {
641        BuiltinRunner::Keccak(runner)
642    }
643}
644
645impl From<BitwiseBuiltinRunner> for BuiltinRunner {
646    fn from(runner: BitwiseBuiltinRunner) -> Self {
647        BuiltinRunner::Bitwise(runner)
648    }
649}
650
651impl From<EcOpBuiltinRunner> for BuiltinRunner {
652    fn from(runner: EcOpBuiltinRunner) -> Self {
653        BuiltinRunner::EcOp(runner)
654    }
655}
656
657impl From<HashBuiltinRunner> for BuiltinRunner {
658    fn from(runner: HashBuiltinRunner) -> Self {
659        BuiltinRunner::Hash(runner)
660    }
661}
662
663impl From<OutputBuiltinRunner> for BuiltinRunner {
664    fn from(runner: OutputBuiltinRunner) -> Self {
665        BuiltinRunner::Output(runner)
666    }
667}
668
669impl From<RangeCheckBuiltinRunner<RC_N_PARTS_STANDARD>> for BuiltinRunner {
670    fn from(runner: RangeCheckBuiltinRunner<RC_N_PARTS_STANDARD>) -> Self {
671        BuiltinRunner::RangeCheck(runner)
672    }
673}
674
675impl From<RangeCheckBuiltinRunner<RC_N_PARTS_96>> for BuiltinRunner {
676    fn from(runner: RangeCheckBuiltinRunner<RC_N_PARTS_96>) -> Self {
677        BuiltinRunner::RangeCheck96(runner)
678    }
679}
680
681impl From<SignatureBuiltinRunner> for BuiltinRunner {
682    fn from(runner: SignatureBuiltinRunner) -> Self {
683        BuiltinRunner::Signature(runner)
684    }
685}
686
687impl From<PoseidonBuiltinRunner> for BuiltinRunner {
688    fn from(runner: PoseidonBuiltinRunner) -> Self {
689        BuiltinRunner::Poseidon(runner)
690    }
691}
692
693impl From<SegmentArenaBuiltinRunner> for BuiltinRunner {
694    fn from(runner: SegmentArenaBuiltinRunner) -> Self {
695        BuiltinRunner::SegmentArena(runner)
696    }
697}
698
699impl From<ModBuiltinRunner> for BuiltinRunner {
700    fn from(runner: ModBuiltinRunner) -> Self {
701        BuiltinRunner::Mod(runner)
702    }
703}
704
705#[cfg(test)]
706mod tests {
707    use super::*;
708    use crate::cairo_run::{cairo_run, CairoRunConfig};
709    use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor;
710    use crate::relocatable;
711    use crate::types::builtin_name::BuiltinName;
712    use crate::types::instance_definitions::mod_instance_def::ModInstanceDef;
713    use crate::types::instance_definitions::LowRatio;
714    use crate::types::layout_name::LayoutName;
715    use crate::types::program::Program;
716    use crate::utils::test_utils::*;
717    use crate::vm::errors::memory_errors::InsufficientAllocatedCellsError;
718    use crate::vm::vm_memory::memory::MemoryCell;
719    use assert_matches::assert_matches;
720
721    #[cfg(target_arch = "wasm32")]
722    use wasm_bindgen_test::*;
723
724    #[test]
725    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
726    fn get_n_input_cells_bitwise() {
727        let bitwise = BitwiseBuiltinRunner::new(Some(10), true);
728        let builtin: BuiltinRunner = bitwise.clone().into();
729        assert_eq!(INPUT_CELLS_PER_BITWISE, builtin.n_input_cells())
730    }
731
732    #[test]
733    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
734    fn get_n_input_cells_hash() {
735        let hash = HashBuiltinRunner::new(Some(10), true);
736        let builtin: BuiltinRunner = hash.clone().into();
737        assert_eq!(INPUT_CELLS_PER_HASH, builtin.n_input_cells())
738    }
739
740    #[test]
741    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
742    fn get_n_input_cells_ec_op() {
743        let ec_op = EcOpBuiltinRunner::new(Some(256), true);
744        let builtin: BuiltinRunner = ec_op.clone().into();
745        assert_eq!(INPUT_CELLS_PER_EC_OP, builtin.n_input_cells())
746    }
747
748    #[test]
749    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
750    fn get_n_input_cells_ecdsa() {
751        let signature = SignatureBuiltinRunner::new(Some(10), true);
752        let builtin: BuiltinRunner = signature.clone().into();
753        assert_eq!(CELLS_PER_SIGNATURE, builtin.n_input_cells())
754    }
755
756    #[test]
757    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
758    fn get_n_input_cells_output() {
759        let output = OutputBuiltinRunner::new(true);
760        let builtin: BuiltinRunner = output.into();
761        assert_eq!(0, builtin.n_input_cells())
762    }
763
764    #[test]
765    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
766    fn get_cells_per_instance_bitwise() {
767        let bitwise = BitwiseBuiltinRunner::new(Some(10), true);
768        let builtin: BuiltinRunner = bitwise.clone().into();
769        assert_eq!(CELLS_PER_BITWISE, builtin.cells_per_instance())
770    }
771
772    #[test]
773    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
774    fn get_cells_per_instance_hash() {
775        let hash = HashBuiltinRunner::new(Some(10), true);
776        let builtin: BuiltinRunner = hash.clone().into();
777        assert_eq!(CELLS_PER_HASH, builtin.cells_per_instance())
778    }
779
780    #[test]
781    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
782    fn get_cells_per_instance_ec_op() {
783        let ec_op = EcOpBuiltinRunner::new(Some(256), true);
784        let builtin: BuiltinRunner = ec_op.clone().into();
785        assert_eq!(CELLS_PER_EC_OP, builtin.cells_per_instance())
786    }
787
788    #[test]
789    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
790    fn get_cells_per_instance_ecdsa() {
791        let signature = SignatureBuiltinRunner::new(Some(10), true);
792        let builtin: BuiltinRunner = signature.clone().into();
793        assert_eq!(CELLS_PER_SIGNATURE, builtin.cells_per_instance())
794    }
795
796    #[test]
797    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
798    fn get_cells_per_instance_output() {
799        let output = OutputBuiltinRunner::new(true);
800        let builtin: BuiltinRunner = output.into();
801        assert_eq!(0, builtin.cells_per_instance())
802    }
803
804    #[test]
805    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
806    fn get_name_bitwise() {
807        let bitwise = BitwiseBuiltinRunner::new(Some(10), true);
808        let builtin: BuiltinRunner = bitwise.into();
809        assert_eq!(BuiltinName::bitwise, builtin.name())
810    }
811
812    #[test]
813    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
814    fn get_name_hash() {
815        let hash = HashBuiltinRunner::new(Some(10), true);
816        let builtin: BuiltinRunner = hash.into();
817        assert_eq!(BuiltinName::pedersen, builtin.name())
818    }
819
820    #[test]
821    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
822    fn get_name_range_check() {
823        let range_check = RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(10), true);
824        let builtin: BuiltinRunner = range_check.into();
825        assert_eq!(BuiltinName::range_check, builtin.name())
826    }
827
828    #[test]
829    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
830    fn get_name_ec_op() {
831        let ec_op = EcOpBuiltinRunner::new(Some(256), true);
832        let builtin: BuiltinRunner = ec_op.into();
833        assert_eq!(BuiltinName::ec_op, builtin.name())
834    }
835
836    #[test]
837    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
838    fn get_name_ecdsa() {
839        let signature = SignatureBuiltinRunner::new(Some(10), true);
840        let builtin: BuiltinRunner = signature.into();
841        assert_eq!(BuiltinName::ecdsa, builtin.name())
842    }
843
844    #[test]
845    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
846    fn get_name_output() {
847        let output = OutputBuiltinRunner::new(true);
848        let builtin: BuiltinRunner = output.into();
849        assert_eq!(BuiltinName::output, builtin.name())
850    }
851
852    #[test]
853    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
854    fn get_allocated_memory_units_bitwise_with_items() {
855        let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(10), true));
856
857        let program = program!(
858            builtins = vec![BuiltinName::bitwise],
859            data = vec_data!(
860                (4612671182993129469_i64),
861                (5189976364521848832_i64),
862                (18446744073709551615_i128),
863                (5199546496550207487_i64),
864                (4612389712311386111_i64),
865                (5198983563776393216_i64),
866                (2),
867                (2345108766317314046_i64),
868                (5191102247248822272_i64),
869                (5189976364521848832_i64),
870                (7),
871                (1226245742482522112_i64),
872                ((
873                    "3618502788666131213697322783095070105623107215331596699973092056135872020470",
874                    10
875                )),
876                (2345108766317314046_i64)
877            ),
878            main = Some(8),
879        );
880
881        let mut cairo_runner = cairo_runner!(program);
882
883        let mut hint_processor = BuiltinHintProcessor::new_empty();
884
885        let address = cairo_runner.initialize(false).unwrap();
886
887        cairo_runner
888            .run_until_pc(address, &mut hint_processor)
889            .unwrap();
890
891        assert_eq!(builtin.get_allocated_memory_units(&cairo_runner.vm), Ok(5));
892    }
893
894    #[test]
895    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
896    fn compare_proof_mode_with_and_without_disable_trace_padding() {
897        const PEDERSEN_TEST: &[u8] =
898            include_bytes!("../../../../../cairo_programs/proof_programs/pedersen_test.json");
899        const BIGINT_TEST: &[u8] =
900            include_bytes!("../../../../../cairo_programs/proof_programs/bigint.json");
901        const POSEIDON_HASH_TEST: &[u8] =
902            include_bytes!("../../../../../cairo_programs/proof_programs/poseidon_hash.json");
903
904        let program_files = vec![PEDERSEN_TEST, BIGINT_TEST, POSEIDON_HASH_TEST];
905
906        for program_data in program_files {
907            let config_false = CairoRunConfig {
908                disable_trace_padding: false,
909                proof_mode: true,
910                layout: LayoutName::all_cairo,
911                ..Default::default()
912            };
913            let mut hint_processor_false = BuiltinHintProcessor::new_empty();
914            let runner_false =
915                cairo_run(program_data, &config_false, &mut hint_processor_false).unwrap();
916            let last_step_false = runner_false.vm.current_step;
917
918            assert!(last_step_false.is_power_of_two());
919
920            let config_true = CairoRunConfig {
921                disable_trace_padding: true,
922                proof_mode: true,
923                layout: LayoutName::all_cairo,
924                ..Default::default()
925            };
926            let mut hint_processor_true = BuiltinHintProcessor::new_empty();
927            let runner_true =
928                cairo_run(program_data, &config_true, &mut hint_processor_true).unwrap();
929            let last_step_true = runner_true.vm.current_step;
930
931            // Ensure the last step is not a power of two - true for this specific program, not always.
932            assert!(!last_step_true.is_power_of_two());
933
934            assert!(last_step_true < last_step_false);
935
936            let builtin_runners_false = &runner_false.vm.builtin_runners;
937            let builtin_runners_true = &runner_true.vm.builtin_runners;
938            assert_eq!(builtin_runners_false.len(), builtin_runners_true.len());
939            // Compare allocated instances for each pair of builtin runners.
940            for (builtin_runner_false, builtin_runner_true) in builtin_runners_false
941                .iter()
942                .zip(builtin_runners_true.iter())
943            {
944                assert_eq!(builtin_runner_false.name(), builtin_runner_true.name());
945                match builtin_runner_false {
946                    BuiltinRunner::Output(_) | BuiltinRunner::SegmentArena(_) => {
947                        continue;
948                    }
949                    _ => {}
950                }
951                let (_, allocated_size_false) = builtin_runner_false
952                    .get_used_cells_and_allocated_size(&runner_false.vm)
953                    .unwrap();
954                let (used_cells_true, allocated_size_true) = builtin_runner_true
955                    .get_used_cells_and_allocated_size(&runner_true.vm)
956                    .unwrap();
957                let n_allocated_instances_false = safe_div_usize(
958                    allocated_size_false,
959                    builtin_runner_false.cells_per_instance() as usize,
960                )
961                .unwrap();
962                let n_allocated_instances_true = safe_div_usize(
963                    allocated_size_true,
964                    builtin_runner_true.cells_per_instance() as usize,
965                )
966                .unwrap();
967                assert!(
968                    n_allocated_instances_false.is_power_of_two()
969                        || n_allocated_instances_false == 0
970                );
971                assert!(
972                    n_allocated_instances_true.is_power_of_two() || n_allocated_instances_true == 0
973                );
974                // Checks that the number of allocated instances is different when trace padding is
975                // enabled/disabled. Holds for this specific program, not always (that is, in other
976                // programs, padding may be of size 0, or the same).
977                assert!(
978                    n_allocated_instances_true == 0
979                        || n_allocated_instances_true != n_allocated_instances_false
980                );
981
982                // Since the last instance of the builtin isn't guaranteed to have a full output,
983                // the number of used_cells might not be a multiple of cells_per_instance, so we
984                // make sure that the discrepancy is up to the number of output cells.
985                // This is the same for both cases, so we only check one (true).
986                let n_output_cells = builtin_runner_true.cells_per_instance() as usize
987                    - builtin_runner_true.n_input_cells() as usize;
988                assert!(
989                    used_cells_true + n_output_cells
990                        >= (builtin_runner_true.cells_per_instance() as usize)
991                            * builtin_runner_true
992                                .get_used_instances(&runner_true.vm.segments)
993                                .unwrap()
994                );
995            }
996        }
997    }
998
999    #[test]
1000    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1001    fn get_allocated_memory_units_ec_op_with_items() {
1002        let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(10), true));
1003
1004        let program = program!(
1005            builtins = vec![BuiltinName::ec_op],
1006            data = vec_data!(
1007                (4612671182993129469_i64),
1008                (5189976364521848832_i64),
1009                (18446744073709551615_i128),
1010                (5199546496550207487_i64),
1011                (4612389712311386111_i64),
1012                (5198983563776393216_i64),
1013                (2),
1014                (2345108766317314046_i64),
1015                (5191102247248822272_i64),
1016                (5189976364521848832_i64),
1017                (7),
1018                (1226245742482522112_i64),
1019                ((
1020                    "3618502788666131213697322783095070105623107215331596699973092056135872020470",
1021                    10
1022                )),
1023                (2345108766317314046_i64)
1024            ),
1025            main = Some(8),
1026        );
1027
1028        let mut cairo_runner = cairo_runner!(program);
1029
1030        let mut hint_processor = BuiltinHintProcessor::new_empty();
1031
1032        let address = cairo_runner.initialize(false).unwrap();
1033
1034        cairo_runner
1035            .run_until_pc(address, &mut hint_processor)
1036            .unwrap();
1037
1038        assert_eq!(builtin.get_allocated_memory_units(&cairo_runner.vm), Ok(7));
1039    }
1040
1041    #[test]
1042    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1043    fn get_allocated_memory_units_hash_with_items() {
1044        let builtin = BuiltinRunner::Hash(HashBuiltinRunner::new(Some(10), true));
1045
1046        let program = program!(
1047            builtins = vec![BuiltinName::pedersen],
1048            data = vec_data!(
1049                (4612671182993129469_i64),
1050                (5189976364521848832_i64),
1051                (18446744073709551615_i128),
1052                (5199546496550207487_i64),
1053                (4612389712311386111_i64),
1054                (5198983563776393216_i64),
1055                (2),
1056                (2345108766317314046_i64),
1057                (5191102247248822272_i64),
1058                (5189976364521848832_i64),
1059                (7),
1060                (1226245742482522112_i64),
1061                ((
1062                    "3618502788666131213697322783095070105623107215331596699973092056135872020470",
1063                    10
1064                )),
1065                (2345108766317314046_i64)
1066            ),
1067            main = Some(8),
1068        );
1069
1070        let mut cairo_runner = cairo_runner!(program);
1071
1072        let mut hint_processor = BuiltinHintProcessor::new_empty();
1073
1074        let address = cairo_runner.initialize(false).unwrap();
1075
1076        cairo_runner
1077            .run_until_pc(address, &mut hint_processor)
1078            .unwrap();
1079
1080        assert_eq!(builtin.get_allocated_memory_units(&cairo_runner.vm), Ok(3));
1081    }
1082
1083    #[test]
1084    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1085    fn get_allocated_memory_units_range_check_with_items() {
1086        let builtin = BuiltinRunner::RangeCheck(
1087            RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(10), true),
1088        );
1089
1090        let program = program!(
1091            builtins = vec![BuiltinName::range_check],
1092            data = vec_data!(
1093                (4612671182993129469_i64),
1094                (5189976364521848832_i64),
1095                (18446744073709551615_i128),
1096                (5199546496550207487_i64),
1097                (4612389712311386111_i64),
1098                (5198983563776393216_i64),
1099                (2),
1100                (2345108766317314046_i64),
1101                (5191102247248822272_i64),
1102                (5189976364521848832_i64),
1103                (7),
1104                (1226245742482522112_i64),
1105                ((
1106                    "3618502788666131213697322783095070105623107215331596699973092056135872020470",
1107                    10
1108                )),
1109                (2345108766317314046_i64)
1110            ),
1111            main = Some(8),
1112        );
1113
1114        let mut cairo_runner = cairo_runner!(program);
1115
1116        let mut hint_processor = BuiltinHintProcessor::new_empty();
1117
1118        let address = cairo_runner.initialize(false).unwrap();
1119
1120        cairo_runner
1121            .run_until_pc(address, &mut hint_processor)
1122            .unwrap();
1123
1124        assert_eq!(builtin.get_allocated_memory_units(&cairo_runner.vm), Ok(1));
1125    }
1126
1127    #[test]
1128    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1129    fn get_allocated_memory_units_keccak_with_items() {
1130        let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(10), true));
1131
1132        let mut vm = vm!();
1133        vm.current_step = 160;
1134        assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(256));
1135    }
1136
1137    #[test]
1138    fn get_allocated_memory_units_keccak_min_steps_not_reached() {
1139        let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(10), true));
1140
1141        let mut vm = vm!();
1142        vm.current_step = 10;
1143        assert_eq!(
1144            builtin.get_allocated_memory_units(&vm),
1145            Err(MemoryError::InsufficientAllocatedCells(
1146                InsufficientAllocatedCellsError::MinStepNotReached(Box::new((
1147                    160,
1148                    BuiltinName::keccak
1149                )))
1150            ))
1151        );
1152    }
1153
1154    #[test]
1155    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1156    fn get_allocated_memory_units_output() {
1157        let builtin = BuiltinRunner::Output(OutputBuiltinRunner::new(true));
1158        let vm = vm!();
1159
1160        // In this case, the function always return Ok(0)
1161        assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(0));
1162    }
1163
1164    #[test]
1165    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1166    fn get_allocated_memory_units_range_check() {
1167        let builtin = BuiltinRunner::RangeCheck(
1168            RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true),
1169        );
1170        let mut vm = vm!();
1171        vm.current_step = 8;
1172        assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(1));
1173    }
1174
1175    #[test]
1176    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1177    fn get_allocated_memory_units_hash() {
1178        let builtin = BuiltinRunner::Hash(HashBuiltinRunner::new(Some(1), true));
1179        let mut vm = vm!();
1180        vm.current_step = 1;
1181        assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(3));
1182    }
1183
1184    #[test]
1185    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1186    fn get_allocated_memory_units_bitwise() {
1187        let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true));
1188        let mut vm = vm!();
1189        vm.current_step = 256;
1190        assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(5));
1191    }
1192
1193    #[test]
1194    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1195    fn get_allocated_memory_units_ec_op() {
1196        let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), true));
1197        let mut vm = vm!();
1198        vm.current_step = 256;
1199        assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(7));
1200    }
1201
1202    #[test]
1203    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1204    fn get_allocated_memory_units_keccak() {
1205        let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(2048), true));
1206        let mut vm = vm!();
1207        vm.current_step = 32768;
1208        assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(256));
1209    }
1210
1211    #[test]
1212    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1213    fn get_allocated_memory_units_zero_ratio() {
1214        let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(0), true));
1215        let vm = vm!();
1216        assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(0));
1217    }
1218
1219    #[test]
1220    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1221    fn get_allocated_memory_units_none_ratio() {
1222        let mut builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new(None, true));
1223        let mut vm = vm!();
1224
1225        builtin.initialize_segments(&mut vm.segments);
1226        vm.compute_segments_effective_sizes();
1227
1228        assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(0));
1229    }
1230
1231    #[test]
1232    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1233    fn get_range_check_usage_range_check() {
1234        let builtin = BuiltinRunner::RangeCheck(
1235            RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true),
1236        );
1237        let memory = memory![((0, 0), 1), ((0, 1), 2), ((0, 2), 3), ((0, 3), 4)];
1238        assert_eq!(builtin.get_range_check_usage(&memory), Some((0, 4)));
1239    }
1240
1241    #[test]
1242    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1243    fn get_range_check_usage_output() {
1244        let builtin = BuiltinRunner::Output(OutputBuiltinRunner::new(true));
1245        let memory = memory![((0, 0), 1), ((0, 1), 2), ((0, 2), 3), ((0, 3), 4)];
1246        assert_eq!(builtin.get_range_check_usage(&memory), None);
1247    }
1248
1249    #[test]
1250    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1251    fn get_range_check_usage_hash() {
1252        let builtin = BuiltinRunner::Hash(HashBuiltinRunner::new(Some(256), true));
1253        let memory = memory![((0, 0), 1), ((0, 1), 2), ((0, 2), 3), ((0, 3), 4)];
1254        assert_eq!(builtin.get_range_check_usage(&memory), None);
1255    }
1256
1257    #[test]
1258    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1259    fn get_range_check_usage_ec_op() {
1260        let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), true));
1261        let memory = memory![((0, 0), 1), ((0, 1), 2), ((0, 2), 3), ((0, 3), 4)];
1262        assert_eq!(builtin.get_range_check_usage(&memory), None);
1263    }
1264
1265    #[test]
1266    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1267    fn get_range_check_usage_bitwise() {
1268        let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true));
1269        let memory = memory![((0, 0), 1), ((0, 1), 2), ((0, 2), 3), ((0, 3), 4)];
1270        assert_eq!(builtin.get_range_check_usage(&memory), None);
1271    }
1272
1273    #[test]
1274    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1275    fn get_used_diluted_check_units_bitwise() {
1276        let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true));
1277        assert_eq!(builtin.get_used_diluted_check_units(270, 7), 1255);
1278    }
1279
1280    #[test]
1281    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1282    fn get_used_diluted_check_units_keccak_zero_case() {
1283        let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(2048), true));
1284        assert_eq!(builtin.get_used_diluted_check_units(270, 7), 0);
1285    }
1286
1287    #[test]
1288    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1289    fn get_used_diluted_check_units_keccak_non_zero_case() {
1290        let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(2048), true));
1291        assert_eq!(builtin.get_used_diluted_check_units(0, 8), 32768);
1292    }
1293
1294    #[test]
1295    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1296    fn get_used_diluted_check_units_ec_op() {
1297        let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(10), true));
1298        assert_eq!(builtin.get_used_diluted_check_units(270, 7), 0);
1299    }
1300
1301    #[test]
1302    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1303    fn get_used_diluted_check_units_hash() {
1304        let builtin = BuiltinRunner::Hash(HashBuiltinRunner::new(Some(1), true));
1305        assert_eq!(builtin.get_used_diluted_check_units(270, 7), 0);
1306    }
1307
1308    #[test]
1309    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1310    fn get_used_diluted_check_units_range_check() {
1311        let builtin = BuiltinRunner::RangeCheck(
1312            RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true),
1313        );
1314        assert_eq!(builtin.get_used_diluted_check_units(270, 7), 0);
1315    }
1316
1317    #[test]
1318    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1319    fn get_used_diluted_check_units_output() {
1320        let builtin = BuiltinRunner::Output(OutputBuiltinRunner::new(true));
1321        assert_eq!(builtin.get_used_diluted_check_units(270, 7), 0);
1322    }
1323
1324    #[test]
1325    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1326    fn get_memory_segment_addresses_test() {
1327        let bitwise_builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(256), true).into();
1328        assert_eq!(bitwise_builtin.get_memory_segment_addresses(), (0, None),);
1329        let ec_op_builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into();
1330        assert_eq!(ec_op_builtin.get_memory_segment_addresses(), (0, None),);
1331        let hash_builtin: BuiltinRunner = HashBuiltinRunner::new(Some(8), true).into();
1332        assert_eq!(hash_builtin.get_memory_segment_addresses(), (0, None),);
1333        let output_builtin: BuiltinRunner = OutputBuiltinRunner::new(true).into();
1334        assert_eq!(output_builtin.get_memory_segment_addresses(), (0, None),);
1335        let range_check_builtin: BuiltinRunner = BuiltinRunner::RangeCheck(
1336            RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true),
1337        );
1338        assert_eq!(
1339            range_check_builtin.get_memory_segment_addresses(),
1340            (0, None),
1341        );
1342    }
1343
1344    #[test]
1345    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1346    fn run_security_checks_for_output() {
1347        let builtin = BuiltinRunner::Output(OutputBuiltinRunner::new(true));
1348        let vm = vm!();
1349
1350        assert_matches!(builtin.run_security_checks(&vm), Ok(()));
1351    }
1352
1353    #[test]
1354    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1355    fn run_security_checks_empty_memory() {
1356        let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true));
1357        let vm = vm!();
1358        // Unused builtin shouldn't fail security checks
1359        assert_matches!(builtin.run_security_checks(&vm), Ok(()));
1360    }
1361
1362    #[test]
1363    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1364    fn run_security_checks_empty_offsets() {
1365        let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true));
1366        let mut vm = vm!();
1367
1368        vm.segments.memory.data = vec![vec![]];
1369
1370        assert_matches!(builtin.run_security_checks(&vm), Ok(()));
1371    }
1372
1373    #[test]
1374    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1375    fn run_security_checks_bitwise_missing_memory_cells_with_offsets() {
1376        let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true));
1377        let mut vm = vm!();
1378        vm.segments.memory = memory![
1379            ((0, 1), (0, 1)),
1380            ((0, 2), (0, 2)),
1381            ((0, 3), (0, 3)),
1382            ((0, 4), (0, 4))
1383        ];
1384
1385        assert_matches!(
1386            builtin.run_security_checks(&vm),
1387            Err(VirtualMachineError::Memory(
1388                MemoryError::MissingMemoryCellsWithOffsets(bx)
1389            )) if *bx == (BuiltinName::bitwise, vec![0])
1390        );
1391    }
1392
1393    #[test]
1394    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1395    fn run_security_checks_bitwise_missing_memory_cells() {
1396        let bitwise_builtin = BitwiseBuiltinRunner::new(Some(256), true);
1397
1398        let builtin: BuiltinRunner = bitwise_builtin.into();
1399
1400        let mut vm = vm!();
1401
1402        vm.segments.memory = memory![((0, 4), (0, 5))];
1403
1404        assert_matches!(
1405            builtin.run_security_checks(&vm),
1406            Err(VirtualMachineError::Memory(
1407                MemoryError::MissingMemoryCells(bx)
1408            )) if *bx == BuiltinName::bitwise
1409        );
1410    }
1411
1412    #[test]
1413    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1414    fn run_security_checks_hash_missing_memory_cells_with_offsets() {
1415        let builtin: BuiltinRunner = HashBuiltinRunner::new(Some(8), true).into();
1416        let mut vm = vm!();
1417
1418        vm.segments.memory = memory![
1419            ((0, 1), (0, 1)),
1420            ((0, 2), (0, 2)),
1421            ((0, 3), (0, 3)),
1422            ((0, 4), (0, 4)),
1423            ((0, 5), (0, 5))
1424        ];
1425        assert_matches!(
1426            builtin.run_security_checks(&vm),
1427            Err(VirtualMachineError::Memory(
1428                MemoryError::MissingMemoryCellsWithOffsets(bx)
1429            )) if *bx == (BuiltinName::pedersen, vec![0])
1430        );
1431    }
1432
1433    #[test]
1434    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1435    fn run_security_checks_hash_missing_memory_cells() {
1436        let hash_builtin = HashBuiltinRunner::new(Some(8), true);
1437
1438        let builtin: BuiltinRunner = hash_builtin.into();
1439
1440        let mut vm = vm!();
1441
1442        vm.segments.memory = memory![((0, 0), (0, 0))];
1443
1444        assert_matches!(
1445            builtin.run_security_checks(&vm),
1446            Err(VirtualMachineError::Memory(
1447                MemoryError::MissingMemoryCells(bx)
1448            )) if *bx == BuiltinName::pedersen
1449        );
1450    }
1451
1452    #[test]
1453    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1454    fn run_security_checks_range_check_missing_memory_cells_with_offsets() {
1455        let range_check_builtin =
1456            RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1457        let builtin: BuiltinRunner = range_check_builtin.into();
1458        let mut vm = vm!();
1459
1460        vm.segments.memory = memory![
1461            ((0, 1), 100),
1462            ((0, 2), 2),
1463            ((0, 3), 3),
1464            ((0, 5), 5),
1465            ((0, 6), 17),
1466            ((0, 7), 22)
1467        ];
1468
1469        assert_matches!(
1470            builtin.run_security_checks(&vm),
1471            Err(VirtualMachineError::Memory(
1472                MemoryError::MissingMemoryCells(bx)
1473            )) if *bx == BuiltinName::range_check
1474        );
1475    }
1476
1477    #[test]
1478    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1479    fn run_security_checks_range_check_missing_memory_cells() {
1480        let builtin: BuiltinRunner = BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::<
1481            RC_N_PARTS_STANDARD,
1482        >::new(Some(8), true));
1483        let mut vm = vm!();
1484
1485        vm.segments.memory = memory![((0, 1), 1)];
1486
1487        assert_matches!(
1488            builtin.run_security_checks(&vm),
1489            Err(VirtualMachineError::Memory(
1490                MemoryError::MissingMemoryCells(bx)
1491            )) if *bx == BuiltinName::range_check
1492        );
1493    }
1494
1495    #[test]
1496    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1497    fn run_security_checks_range_check_empty() {
1498        let range_check_builtin =
1499            RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1500
1501        let builtin: BuiltinRunner = range_check_builtin.into();
1502
1503        let mut vm = vm!();
1504
1505        vm.segments.memory.data = vec![vec![MemoryCell::NONE, MemoryCell::NONE, MemoryCell::NONE]];
1506
1507        assert_matches!(builtin.run_security_checks(&vm), Ok(()));
1508    }
1509
1510    #[test]
1511    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1512    fn run_security_checks_validate_auto_deductions() {
1513        let builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(256), true).into();
1514
1515        let mut vm = vm!();
1516        vm.segments
1517            .memory
1518            .validated_addresses
1519            .extend(&[relocatable!(0, 2)]);
1520
1521        vm.segments.memory = memory![
1522            ((0, 0), (0, 0)),
1523            ((0, 1), (0, 1)),
1524            ((0, 2), (0, 2)),
1525            ((0, 3), (0, 3)),
1526            ((0, 4), (0, 4))
1527        ];
1528
1529        assert_matches!(builtin.run_security_checks(&vm), Ok(()));
1530    }
1531
1532    #[test]
1533    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1534    fn run_security_ec_op_check_memory_empty() {
1535        let ec_op_builtin = EcOpBuiltinRunner::new(Some(256), true);
1536
1537        let builtin: BuiltinRunner = ec_op_builtin.into();
1538
1539        let mut vm = vm!();
1540        // The values stored in memory are not relevant for this test
1541        vm.segments.memory.data = vec![vec![]];
1542
1543        assert_matches!(builtin.run_security_checks(&vm), Ok(()));
1544    }
1545
1546    #[test]
1547    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1548    fn run_security_ec_op_check_memory_1_element() {
1549        let ec_op_builtin = EcOpBuiltinRunner::new(Some(256), true);
1550
1551        let builtin: BuiltinRunner = ec_op_builtin.into();
1552
1553        let mut vm = vm!();
1554        // The values stored in memory are not relevant for this test
1555        vm.segments.memory = memory![((0, 0), 0)];
1556        assert_matches!(
1557            builtin.run_security_checks(&vm),
1558            Err(VirtualMachineError::Memory(
1559                MemoryError::MissingMemoryCells(bx)
1560            )) if *bx == BuiltinName::ec_op
1561        );
1562    }
1563
1564    #[test]
1565    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1566    fn run_security_ec_op_check_memory_3_elements() {
1567        let ec_op_builtin = EcOpBuiltinRunner::new(Some(256), true);
1568
1569        let builtin: BuiltinRunner = ec_op_builtin.into();
1570
1571        let mut vm = vm!();
1572        // The values stored in memory are not relevant for this test
1573        vm.segments.memory = memory![((0, 0), 0), ((0, 1), 0), ((0, 2), 0)];
1574
1575        assert_matches!(
1576            builtin.run_security_checks(&vm),
1577            Err(VirtualMachineError::Memory(
1578                MemoryError::MissingMemoryCells(bx)
1579            )) if *bx == BuiltinName::ec_op
1580        );
1581    }
1582
1583    #[test]
1584    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1585    fn run_security_ec_op_missing_memory_cells_with_offsets() {
1586        let builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into();
1587        let mut vm = vm!();
1588        vm.segments.memory = memory![
1589            ((0, 1), (0, 1)),
1590            ((0, 2), (0, 2)),
1591            ((0, 3), (0, 3)),
1592            ((0, 4), (0, 4)),
1593            ((0, 5), (0, 5)),
1594            ((0, 6), (0, 6))
1595        ];
1596
1597        assert_matches!(
1598            builtin.run_security_checks(&vm),
1599            Err(VirtualMachineError::Memory(
1600                MemoryError::MissingMemoryCellsWithOffsets(bx)
1601            )) if *bx == (BuiltinName::ec_op, vec![0])
1602        );
1603    }
1604
1605    #[test]
1606    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1607    fn run_security_ec_op_check_memory_gap() {
1608        let ec_op_builtin = EcOpBuiltinRunner::new(Some(256), true);
1609
1610        let builtin: BuiltinRunner = ec_op_builtin.into();
1611
1612        let mut vm = vm!();
1613        // The values stored in memory are not relevant for this test
1614        vm.segments.memory = memory![
1615            ((0, 0), 0),
1616            ((0, 1), 1),
1617            ((0, 2), 2),
1618            ((0, 3), 3),
1619            ((0, 4), 4),
1620            ((0, 5), 5),
1621            ((0, 6), 6),
1622            ((0, 8), 8),
1623            ((0, 9), 9),
1624            ((0, 10), 10),
1625            ((0, 11), 11)
1626        ];
1627
1628        assert_matches!(
1629            builtin.run_security_checks(&vm),
1630            Err(VirtualMachineError::Memory(
1631                MemoryError::MissingMemoryCellsWithOffsets(bx)
1632            )) if *bx == (BuiltinName::ec_op, vec![7])
1633        );
1634    }
1635
1636    /// Test that get_used_perm_range_check_units() returns zero when the
1637    /// builtin is a BitwiseBuiltinRunner.
1638    #[test]
1639    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1640    fn get_used_perm_range_check_units_bitwise() {
1641        let builtin_runner: BuiltinRunner = BitwiseBuiltinRunner::new(Some(256), true).into();
1642        let mut vm = vm!();
1643
1644        vm.current_step = 8;
1645        vm.segments.segment_used_sizes = Some(vec![5]);
1646        assert_eq!(builtin_runner.get_used_perm_range_check_units(&vm), Ok(0));
1647    }
1648
1649    /// Test that get_used_perm_range_check_units() returns zero when the
1650    /// builtin is an EcOpBuiltinRunner.
1651    #[test]
1652    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1653    fn get_used_perm_range_check_units_ec_op() {
1654        let builtin_runner: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into();
1655        let mut vm = vm!();
1656
1657        vm.current_step = 8;
1658        vm.segments.segment_used_sizes = Some(vec![5]);
1659        assert_eq!(builtin_runner.get_used_perm_range_check_units(&vm), Ok(0));
1660    }
1661
1662    /// Test that get_used_perm_range_check_units() returns zero when the
1663    /// builtin is a HashBuiltinRunner.
1664    #[test]
1665    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1666    fn get_used_perm_range_check_units_hash() {
1667        let builtin_runner: BuiltinRunner = HashBuiltinRunner::new(Some(8), true).into();
1668        let mut vm = vm!();
1669
1670        vm.current_step = 8;
1671        vm.segments.segment_used_sizes = Some(vec![5]);
1672        assert_eq!(builtin_runner.get_used_perm_range_check_units(&vm), Ok(0));
1673    }
1674
1675    /// Test that get_used_perm_range_check_units() returns zero when the
1676    /// builtin is an OutputBuiltinRunner.
1677    #[test]
1678    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1679    fn get_used_perm_range_check_units_output() {
1680        let builtin_runner: BuiltinRunner = OutputBuiltinRunner::new(true).into();
1681        let mut vm = vm!();
1682
1683        vm.current_step = 8;
1684        vm.segments.segment_used_sizes = Some(vec![5]);
1685        assert_eq!(builtin_runner.get_used_perm_range_check_units(&vm), Ok(0));
1686    }
1687
1688    /// Test that get_used_perm_range_check_units() calls the corresponding
1689    /// method when the builtin is a RangeCheckBuiltinRunner.
1690    #[test]
1691    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1692    fn get_used_perm_range_check_units_range_check() {
1693        let builtin_runner: BuiltinRunner =
1694            RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true).into();
1695        let mut vm = vm!();
1696
1697        vm.current_step = 8;
1698        vm.segments.segment_used_sizes = Some(vec![1]);
1699        assert_eq!(builtin_runner.get_used_perm_range_check_units(&vm), Ok(8));
1700    }
1701
1702    #[test]
1703    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1704    fn get_ratio_tests() {
1705        let bitwise_builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(256), true).into();
1706        assert_eq!(bitwise_builtin.ratio(), (Some(256)),);
1707        let ec_op_builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into();
1708        assert_eq!(ec_op_builtin.ratio(), (Some(256)),);
1709        let hash_builtin: BuiltinRunner = HashBuiltinRunner::new(Some(8), true).into();
1710        assert_eq!(hash_builtin.ratio(), (Some(8)),);
1711        let output_builtin: BuiltinRunner = OutputBuiltinRunner::new(true).into();
1712        assert_eq!(output_builtin.ratio(), None,);
1713        let range_check_builtin: BuiltinRunner = BuiltinRunner::RangeCheck(
1714            RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true),
1715        );
1716        assert_eq!(range_check_builtin.ratio(), (Some(8)),);
1717        let keccak_builtin: BuiltinRunner = KeccakBuiltinRunner::new(Some(2048), true).into();
1718        assert_eq!(keccak_builtin.ratio(), (Some(2048)),);
1719    }
1720
1721    #[test]
1722    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1723    fn get_ratio_den_tests() {
1724        let rangecheck_builtin: BuiltinRunner =
1725            RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new_with_low_ratio(
1726                Some(LowRatio::new(1, 2)),
1727                true,
1728            )
1729            .into();
1730        assert_eq!(rangecheck_builtin.ratio_den(), (Some(2)),);
1731
1732        let rangecheck96_builtin: BuiltinRunner =
1733            RangeCheckBuiltinRunner::<RC_N_PARTS_96>::new_with_low_ratio(
1734                Some(LowRatio::new(1, 4)),
1735                true,
1736            )
1737            .into();
1738        assert_eq!(rangecheck96_builtin.ratio_den(), (Some(4)),);
1739
1740        let mod_builtin: BuiltinRunner =
1741            ModBuiltinRunner::new_add_mod(&ModInstanceDef::new(Some(5), 3, 3), true).into();
1742        assert_eq!(mod_builtin.ratio_den(), (Some(1)),);
1743    }
1744
1745    #[test]
1746    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1747    fn bitwise_get_used_instances_test() {
1748        let mut vm = vm!();
1749        vm.segments.segment_used_sizes = Some(vec![4]);
1750
1751        let bitwise_builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(256), true).into();
1752        assert_eq!(bitwise_builtin.get_used_instances(&vm.segments), Ok(1));
1753    }
1754
1755    #[test]
1756    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1757    fn ec_op_get_used_instances_test() {
1758        let mut vm = vm!();
1759        vm.segments.segment_used_sizes = Some(vec![4]);
1760
1761        let ec_op_builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into();
1762        assert_eq!(ec_op_builtin.get_used_instances(&vm.segments), Ok(1));
1763    }
1764
1765    #[test]
1766    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1767    fn hash_get_used_instances_test() {
1768        let mut vm = vm!();
1769        vm.segments.segment_used_sizes = Some(vec![4]);
1770
1771        let hash_builtin: BuiltinRunner = HashBuiltinRunner::new(Some(8), true).into();
1772        assert_eq!(hash_builtin.get_used_instances(&vm.segments), Ok(2));
1773    }
1774
1775    #[test]
1776    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1777    fn output_get_used_instances_test() {
1778        let mut vm = vm!();
1779        vm.segments.segment_used_sizes = Some(vec![4]);
1780
1781        let output_builtin: BuiltinRunner = OutputBuiltinRunner::new(true).into();
1782        assert_eq!(output_builtin.get_used_instances(&vm.segments), Ok(4));
1783    }
1784    #[test]
1785    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1786    fn range_check_get_used_instances_test() {
1787        let mut vm = vm!();
1788        vm.segments.segment_used_sizes = Some(vec![4]);
1789
1790        let range_check_builtin: BuiltinRunner = BuiltinRunner::RangeCheck(
1791            RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true),
1792        );
1793        assert_eq!(range_check_builtin.get_used_instances(&vm.segments), Ok(4));
1794    }
1795
1796    #[test]
1797    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1798    fn runners_final_stack() {
1799        let mut builtins = vec![
1800            BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), false)),
1801            BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), false)),
1802            BuiltinRunner::Hash(HashBuiltinRunner::new(Some(1), false)),
1803            BuiltinRunner::Output(OutputBuiltinRunner::new(false)),
1804            BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(
1805                Some(8),
1806                false,
1807            )),
1808            BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(2048), false)),
1809            BuiltinRunner::Signature(SignatureBuiltinRunner::new(Some(512), false)),
1810        ];
1811        let vm = vm!();
1812
1813        for br in builtins.iter_mut() {
1814            assert_eq!(br.final_stack(&vm.segments, vm.get_ap()), Ok(vm.get_ap()));
1815        }
1816    }
1817
1818    #[test]
1819    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1820    fn runners_set_stop_ptr() {
1821        let builtins = vec![
1822            BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), false)),
1823            BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), false)),
1824            BuiltinRunner::Hash(HashBuiltinRunner::new(Some(1), false)),
1825            BuiltinRunner::Output(OutputBuiltinRunner::new(false)),
1826            BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(
1827                Some(8),
1828                false,
1829            )),
1830            BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(2048), false)),
1831            BuiltinRunner::Signature(SignatureBuiltinRunner::new(Some(512), false)),
1832            BuiltinRunner::Poseidon(PoseidonBuiltinRunner::new(Some(32), false)),
1833            BuiltinRunner::SegmentArena(SegmentArenaBuiltinRunner::new(false)),
1834        ];
1835
1836        let ptr = 3;
1837
1838        for mut br in builtins {
1839            br.set_stop_ptr(ptr);
1840            let (_, stop_ptr) = br.get_memory_segment_addresses();
1841            assert_eq!(stop_ptr, Some(ptr));
1842        }
1843    }
1844
1845    #[test]
1846    fn get_additonal_data_none() {
1847        let builtin: BuiltinRunner = PoseidonBuiltinRunner::new(None, true).into();
1848        assert_eq!(builtin.get_additional_data(), BuiltinAdditionalData::None)
1849    }
1850}