Skip to main content

cairo_program_runner_lib/hints/
hint_processors.rs

1use std::any::Any;
2use std::rc::Rc;
3
4use cairo_lang_runner::CairoHintProcessor;
5use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::{
6    BuiltinHintProcessor, HintFunc, HintProcessorData,
7};
8use cairo_vm::hint_processor::hint_processor_definition::{HintExtension, HintProcessorLogic};
9use cairo_vm::types::exec_scope::ExecutionScopes;
10use cairo_vm::vm::errors::hint_errors::HintError;
11use cairo_vm::vm::runners::cairo_runner::ResourceTracker;
12use cairo_vm::vm::vm_core::VirtualMachine;
13
14use crate::hints::bootloader_hints::{
15    assert_is_composite_packed_output, assert_program_address,
16    compute_and_configure_fact_topologies, compute_and_configure_fact_topologies_simple,
17    enter_packed_output_scope, guess_pre_image_of_subtasks_output_hash,
18    import_packed_output_schemas, is_plain_packed_output, load_bootloader_config,
19    load_simple_bootloader_input, prepare_simple_bootloader_input,
20    prepare_simple_bootloader_output_segment, restore_bootloader_output, save_output_pointer,
21    save_packed_outputs, set_packed_output_to_subtasks,
22};
23use crate::hints::codes::*;
24use crate::hints::execute_task_hints::{
25    append_fact_topologies, bootloader_validate_hash, determine_use_prev_hash,
26    execute_task_exit_scope, load_program_hint, setup_subtask_for_execution, validate_hash,
27    write_return_builtins_hint,
28};
29use crate::hints::inner_select_builtins::select_builtin;
30use crate::hints::select_builtins::select_builtins_enter_scope;
31use crate::hints::simple_bootloader_hints::{
32    divide_num_by_2, program_hash_function_to_ap, set_ap_to_zero, set_current_task,
33    setup_run_simple_bootloader_before_task_execution,
34};
35use crate::hints::utils::output_builtin_set_pages_by_size_and_fact_topology;
36use crate::hints::verifier_hints::load_and_parse_proof;
37
38use super::applicative_bootloader_hints::{
39    finalize_fact_topologies_and_pages, prepare_aggregator_simple_bootloader_output_segment,
40    prepare_root_task_unpacker_bootloader_output_segment, restore_applicative_output_state,
41};
42use super::bootloader_hints::load_unpacker_bootloader_input;
43use super::builtin_usage_hints::{
44    builtin_usage_5_to_ap, builtin_usage_add_other_segment, builtin_usage_add_signature,
45    builtin_usage_set_pages_and_fact_topology, flexible_builtin_usage_from_input,
46};
47use super::concat_aggregator_hints::{
48    concat_aggregator_get_handle_task_output, concat_aggregator_parse_task,
49};
50use super::fibonacci_hints::{fibonacci_load_claim_idx, fibonacci_load_second_element};
51use super::fri_layer::divide_queries_ind_by_coset_size_to_fp_offset;
52use super::mock_cairo_verifier_hints::{
53    load_mock_cairo_verifier_input, mock_cairo_verifier_hash_to_fp,
54    mock_cairo_verifier_len_output_to_fp, mock_cairo_verifier_n_steps_to_ap,
55};
56use super::pedersen_merkle_hints::{
57    pedersen_merkle_idx_parity_to_ap, pedersen_merkle_load_input, pedersen_merkle_update,
58    pedersen_merkle_verify_auth_path_len,
59};
60use super::simple_bootloader_hints::{
61    simple_bootloader_simulate_ec_op, simple_bootloader_simulate_ecdsa,
62    simple_bootloader_simulate_keccak, simulate_ec_op_assert_false,
63    simulate_ec_op_fill_mem_with_bits_of_m, simulate_ecdsa_compute_w_wr_wz,
64    simulate_ecdsa_fill_mem_with_felt_96_bit_limbs, simulate_ecdsa_get_r_and_s,
65    simulate_keccak_calc_high_low, simulate_keccak_fill_mem_with_state,
66};
67use super::simple_output_hints::{len_output_to_ap, load_simple_output_input, write_simple_output};
68use super::vector_commitment::set_bit_from_index;
69
70/// A hint processor that can only execute the hints defined in this library.
71/// For large projects, you may want to compose a hint processor from multiple parts
72/// (ex: Starknet OS, bootloader and Cairo VM). This hint processor is as minimal as possible
73/// to enable this modularity.
74///
75/// However, this processor is not sufficient to execute the bootloader. For this,
76/// use `StandaloneBootloaderHintProcessor`.
77#[derive(Default)]
78pub struct MinimalBootloaderHintProcessor;
79
80impl MinimalBootloaderHintProcessor {
81    pub fn new() -> Self {
82        Self {}
83    }
84}
85
86impl HintProcessorLogic for MinimalBootloaderHintProcessor {
87    fn execute_hint(
88        &mut self,
89        vm: &mut VirtualMachine,
90        exec_scopes: &mut ExecutionScopes,
91        hint_data: &Box<dyn Any>,
92    ) -> Result<(), HintError> {
93        let hint_data = hint_data
94            .downcast_ref::<HintProcessorData>()
95            .ok_or(HintError::WrongHintData)?;
96
97        let ids_data = &hint_data.ids_data;
98        let ap_tracking = &hint_data.ap_tracking;
99        let constants = &hint_data.constants;
100
101        match hint_data.code.as_str() {
102            BOOTLOADER_RESTORE_BOOTLOADER_OUTPUT => restore_bootloader_output(vm, exec_scopes),
103            BOOTLOADER_PREPARE_SIMPLE_BOOTLOADER_INPUT => {
104                prepare_simple_bootloader_input(exec_scopes)
105            }
106            BOOTLOADER_READ_SIMPLE_BOOTLOADER_INPUT => load_simple_bootloader_input(exec_scopes),
107            BOOTLOADER_READ_UNPACKER_BOOTLOADER_INPUT => {
108                load_unpacker_bootloader_input(exec_scopes)
109            }
110            BOOTLOADER_LOAD_BOOTLOADER_CONFIG => {
111                load_bootloader_config(vm, exec_scopes, ids_data, ap_tracking)
112            }
113            BOOTLOADER_ENTER_PACKED_OUTPUT_SCOPE => {
114                enter_packed_output_scope(vm, exec_scopes, ids_data, ap_tracking)
115            }
116            BOOTLOADER_SAVE_OUTPUT_POINTER => {
117                save_output_pointer(vm, exec_scopes, ids_data, ap_tracking)
118            }
119            BOOTLOADER_SAVE_PACKED_OUTPUTS => save_packed_outputs(exec_scopes),
120            BOOTLOADER_GUESS_PRE_IMAGE_OF_SUBTASKS_OUTPUT_HASH => {
121                guess_pre_image_of_subtasks_output_hash(vm, exec_scopes, ids_data, ap_tracking)
122            }
123            BOOTLOADER_PREPARE_SIMPLE_BOOTLOADER_OUTPUT_SEGMENT => {
124                prepare_simple_bootloader_output_segment(vm, exec_scopes, ids_data, ap_tracking)
125            }
126            BOOTLOADER_COMPUTE_FACT_TOPOLOGIES => {
127                compute_and_configure_fact_topologies(vm, exec_scopes)
128            }
129            BOOTLOADER_SIMPLE_BOOTLOADER_COMPUTE_FACT_TOPOLOGIES => {
130                compute_and_configure_fact_topologies_simple(vm, exec_scopes)
131            }
132            BOOTLOADER_SET_PACKED_OUTPUT_TO_SUBTASKS => set_packed_output_to_subtasks(exec_scopes),
133            BOOTLOADER_IMPORT_PACKED_OUTPUT_SCHEMAS => import_packed_output_schemas(),
134            BOOTLOADER_IS_PLAIN_PACKED_OUTPUT => is_plain_packed_output(vm, exec_scopes),
135            BOOTLOADER_PROGRAM_HASH => program_hash_function_to_ap(vm, exec_scopes),
136            BOOTLOADER_VALIDATE_HASH => bootloader_validate_hash(
137                vm,
138                exec_scopes,
139                &hint_data.ids_data,
140                &hint_data.ap_tracking,
141            ),
142            BOOTLOADER_ASSERT_IS_COMPOSITE_PACKED_OUTPUT => {
143                assert_is_composite_packed_output(exec_scopes)
144            }
145            SETUP_RUN_SIMPLE_BOOTLOADER_BEFORE_TASK_EXECUTION => {
146                setup_run_simple_bootloader_before_task_execution(
147                    vm,
148                    exec_scopes,
149                    ids_data,
150                    ap_tracking,
151                )
152            }
153            SIMPLE_BOOTLOADER_DIVIDE_NUM_BY_2 => divide_num_by_2(vm, ids_data, ap_tracking),
154            SIMPLE_BOOTLOADER_SET_CURRENT_TASK => {
155                set_current_task(vm, exec_scopes, ids_data, ap_tracking)
156            }
157            DETERMINE_USE_PREV_HASH => {
158                determine_use_prev_hash(vm, exec_scopes, ids_data, ap_tracking)
159            }
160            SIMPLE_BOOTLOADER_ZERO => set_ap_to_zero(vm),
161            LOAD_PROGRAM_SEGMENT => load_program_hint(vm, exec_scopes, ids_data, ap_tracking),
162            EXECUTE_TASK_VALIDATE_HASH => validate_hash(vm, exec_scopes, ids_data, ap_tracking),
163            EXECUTE_TASK_ASSERT_PROGRAM_ADDRESS => {
164                assert_program_address(vm, exec_scopes, ids_data, ap_tracking)
165            }
166            EXECUTE_TASK_WRITE_RETURN_BUILTINS => {
167                write_return_builtins_hint(vm, exec_scopes, ids_data, ap_tracking)
168            }
169            EXECUTE_TASK_APPEND_FACT_TOPOLOGIES => {
170                append_fact_topologies(vm, exec_scopes, ids_data, ap_tracking)
171            }
172            SELECT_BUILTINS_ENTER_SCOPE => {
173                select_builtins_enter_scope(vm, exec_scopes, ids_data, ap_tracking)
174            }
175            INNER_SELECT_BUILTINS_SELECT_BUILTIN => {
176                select_builtin(vm, exec_scopes, ids_data, ap_tracking)
177            }
178            VERIFIER_LOAD_AND_PARSE_PROOF => {
179                load_and_parse_proof(vm, exec_scopes, ids_data, ap_tracking)
180            }
181            VERIFIER_GET_INDEX_LAST_BIT => set_bit_from_index(vm, ids_data, ap_tracking),
182            VERIFIER_DIVIDE_QUERIES_IND_BY_COSET_SIZE_TO_FP_OFFSET => {
183                divide_queries_ind_by_coset_size_to_fp_offset(vm, ids_data, ap_tracking)
184            }
185            APPLICATIVE_LOAD_INPUTS => prepare_aggregator_simple_bootloader_output_segment(
186                vm,
187                exec_scopes,
188                ids_data,
189                ap_tracking,
190            ),
191            APPLICATIVE_SET_UP_UNPACKER_INPUTS => {
192                prepare_root_task_unpacker_bootloader_output_segment(
193                    vm,
194                    exec_scopes,
195                    ids_data,
196                    ap_tracking,
197                )
198            }
199            APPLICATIVE_RESTORE_OUTPUT_BUILTIN_STATE => {
200                restore_applicative_output_state(vm, exec_scopes)
201            }
202            APPLICATIVE_FINALIZE_FACT_TOPOLOGIES_AND_PAGES => {
203                finalize_fact_topologies_and_pages(vm, exec_scopes, ids_data, ap_tracking)
204            }
205            SIMPLE_BOOTLOADER_SIMULATE_EC_OP => {
206                simple_bootloader_simulate_ec_op(vm, ids_data, ap_tracking)
207            }
208            SIMULATE_EC_OP_FILL_MEM_WITH_BITS_OF_M => {
209                simulate_ec_op_fill_mem_with_bits_of_m(vm, ids_data, ap_tracking, constants)
210            }
211            SIMULATE_EC_OP_ASSERT_FALSE => simulate_ec_op_assert_false(),
212            SIMPLE_BOOTLOADER_SIMULATE_KECCAK => {
213                simple_bootloader_simulate_keccak(vm, ids_data, ap_tracking)
214            }
215            SIMULATE_KECCAK_FILL_MEM_WITH_STATE => {
216                simulate_keccak_fill_mem_with_state(vm, ids_data, ap_tracking)
217            }
218            SIMULATE_KECCAK_CALC_HIGH3_LOW3 => {
219                simulate_keccak_calc_high_low(vm, ids_data, ap_tracking, 3)
220            }
221            SIMULATE_KECCAK_CALC_HIGH6_LOW6 => {
222                simulate_keccak_calc_high_low(vm, ids_data, ap_tracking, 6)
223            }
224            SIMULATE_KECCAK_CALC_HIGH9_LOW9 => {
225                simulate_keccak_calc_high_low(vm, ids_data, ap_tracking, 9)
226            }
227            SIMULATE_KECCAK_CALC_HIGH12_LOW12 => {
228                simulate_keccak_calc_high_low(vm, ids_data, ap_tracking, 12)
229            }
230            SIMULATE_KECCAK_CALC_HIGH15_LOW15 => {
231                simulate_keccak_calc_high_low(vm, ids_data, ap_tracking, 15)
232            }
233            SIMULATE_KECCAK_CALC_HIGH18_LOW18 => {
234                simulate_keccak_calc_high_low(vm, ids_data, ap_tracking, 18)
235            }
236            SIMULATE_KECCAK_CALC_HIGH21_LOW21 => {
237                simulate_keccak_calc_high_low(vm, ids_data, ap_tracking, 21)
238            }
239            SIMPLE_BOOTLOADER_SIMULATE_ECDSA => {
240                simple_bootloader_simulate_ecdsa(vm, ids_data, ap_tracking)
241            }
242            SIMULATE_ECDSA_GET_R_AND_S => simulate_ecdsa_get_r_and_s(vm, ids_data, ap_tracking),
243            SIMULATE_ECDSA_COMPUTE_W_WR_WZ => {
244                simulate_ecdsa_compute_w_wr_wz(vm, ids_data, ap_tracking, constants)
245            }
246            SIMULATE_ECDSA_FILL_MEM_WITH_FELT_96_BIT_LIMBS => {
247                simulate_ecdsa_fill_mem_with_felt_96_bit_limbs(vm, ids_data, ap_tracking)
248            }
249            unknown_hint_code => Err(HintError::UnknownHint(
250                unknown_hint_code.to_string().into_boxed_str(),
251            )),
252        }
253    }
254}
255
256impl ResourceTracker for MinimalBootloaderHintProcessor {}
257
258#[derive(Default)]
259pub struct MinimalTestProgramsHintProcessor;
260
261impl MinimalTestProgramsHintProcessor {
262    pub fn new() -> Self {
263        Self {}
264    }
265}
266
267impl HintProcessorLogic for MinimalTestProgramsHintProcessor {
268    fn execute_hint(
269        &mut self,
270        vm: &mut VirtualMachine,
271        exec_scopes: &mut ExecutionScopes,
272        hint_data: &Box<dyn Any>,
273    ) -> Result<(), HintError> {
274        let hint_data = hint_data
275            .downcast_ref::<HintProcessorData>()
276            .ok_or(HintError::WrongHintData)?;
277
278        let ids_data = &hint_data.ids_data;
279        let ap_tracking = &hint_data.ap_tracking;
280
281        match hint_data.code.as_str() {
282            SIMPLE_OUTPUT_LOAD_PROGRAM_INPUT => load_simple_output_input(exec_scopes),
283            SIMPLE_OUTPUT_WRITE_OUTPUT => {
284                write_simple_output(vm, exec_scopes, ids_data, ap_tracking)
285            }
286            SIMPLE_OUTPUT_LEN_OUTPUT_TO_AP => len_output_to_ap(vm, exec_scopes),
287            MOCK_CAIRO_VERIFIER_LOAD_INPUT => {
288                load_mock_cairo_verifier_input(vm, exec_scopes, ids_data, ap_tracking)
289            }
290            MOCK_CAIRO_VERIFIER_OUTPUT_LEN_TO_FP => {
291                mock_cairo_verifier_len_output_to_fp(vm, exec_scopes)
292            }
293            MOCK_CAIRO_VERIFIER_HASH_TO_FP => mock_cairo_verifier_hash_to_fp(vm, exec_scopes),
294            MOCK_CAIRO_VERIFIER_GET_N_STEPS => Ok(()),
295            MOCK_CAIRO_VERIFIER_N_STEPS_TO_AP => mock_cairo_verifier_n_steps_to_ap(vm, exec_scopes),
296            CONCAT_AGGREGATOR_PARSE_TASKS_OUTPUTS => {
297                concat_aggregator_parse_task(vm, exec_scopes, ids_data, ap_tracking)
298            }
299            CONCAT_AGGREGATOR_GET_TASK_OUTPUT_WITH_SIZE => {
300                concat_aggregator_get_handle_task_output(vm, exec_scopes, ids_data, ap_tracking, 1)
301            }
302            CONCAT_AGGREGATOR_GET_TASK_OUTPUT_WITHOUT_SIZE => {
303                concat_aggregator_get_handle_task_output(vm, exec_scopes, ids_data, ap_tracking, 0)
304            }
305            CONCAT_AGGREGATOR_SET_PAGES_AND_FACT_TOPOLOGY => {
306                output_builtin_set_pages_by_size_and_fact_topology(vm, ids_data, ap_tracking, 10)
307            }
308            BUILTIN_USAGE_SET_MAX_SIZE_PAGES_AND_FACT_TOPOLOGY => {
309                output_builtin_set_pages_by_size_and_fact_topology(vm, ids_data, ap_tracking, 3800)
310            }
311            BUILTIN_USAGE_ADD_OTHER_SEGMENT => {
312                builtin_usage_add_other_segment(vm, ids_data, ap_tracking, true)
313            }
314            BUILTIN_USAGE_ADD_OTHER_SEGMENT_FINALIZE => {
315                builtin_usage_add_other_segment(vm, ids_data, ap_tracking, true)
316            }
317            BUILTIN_USAGE_ADD_SIGNATURE
318            | BUILTIN_USAGE_ADD_SIGNATURE_FROM_SIGNATURE_BUILTIN_STRUCT => {
319                builtin_usage_add_signature(vm, ids_data, ap_tracking)
320            }
321            BUILTIN_USAGE_5_TO_AP => builtin_usage_5_to_ap(vm),
322            BUILTIN_USAGE_SET_PAGES_AND_FACT_TOPOLOGY => {
323                builtin_usage_set_pages_and_fact_topology(vm, ids_data, ap_tracking)
324            }
325            FLEXIBLE_BUILTIN_USAGE_FROM_INPUT => {
326                flexible_builtin_usage_from_input(vm, exec_scopes, ids_data, ap_tracking)
327            }
328            FIBONACCI_LOAD_SECOND_ELEMENT => fibonacci_load_second_element(vm, exec_scopes),
329            FIBONACCI_LOAD_CLAIM_IDX => fibonacci_load_claim_idx(vm, exec_scopes),
330            PEDERSEN_MERKLE_VERIFY_AUTH_PATH_LEN => {
331                pedersen_merkle_verify_auth_path_len(exec_scopes)
332            }
333            PEDERSEN_MERKLE_LOAD_INPUT => {
334                pedersen_merkle_load_input(vm, exec_scopes, ids_data, ap_tracking)
335            }
336            PEDERSEN_MERKLE_IDX_PARITY_TO_AP => {
337                pedersen_merkle_idx_parity_to_ap(vm, ids_data, ap_tracking)
338            }
339            PEDERSEN_MERKLE_UPDATE_LEFT => {
340                pedersen_merkle_update(vm, exec_scopes, ids_data, ap_tracking, true)
341            }
342            PEDERSEN_MERKLE_UPDATE_RIGHT => {
343                pedersen_merkle_update(vm, exec_scopes, ids_data, ap_tracking, false)
344            }
345            unknown_hint_code => Err(HintError::UnknownHint(
346                unknown_hint_code.to_string().into_boxed_str(),
347            )),
348        }
349    }
350}
351
352/// A hint processor for use cases where we only care about the bootloader hints.
353///
354/// When executing a hint, this hint processor will first check the hints defined in this library,
355/// then the ones defined in Cairo VM.
356pub struct BootloaderHintProcessor<'a> {
357    bootloader_hint_processor: MinimalBootloaderHintProcessor,
358    builtin_hint_processor: BuiltinHintProcessor,
359    test_programs_hint_processor: MinimalTestProgramsHintProcessor,
360    pub subtask_cairo1_hint_processor_stack: Vec<Option<CairoHintProcessor<'a>>>,
361}
362
363impl Default for BootloaderHintProcessor<'_> {
364    fn default() -> Self {
365        Self::new()
366    }
367}
368
369impl<'a> BootloaderHintProcessor<'a> {
370    pub fn new() -> Self {
371        Self {
372            bootloader_hint_processor: MinimalBootloaderHintProcessor::new(),
373            builtin_hint_processor: BuiltinHintProcessor::new_empty(),
374            subtask_cairo1_hint_processor_stack: Vec::new(),
375            test_programs_hint_processor: MinimalTestProgramsHintProcessor::new(),
376        }
377    }
378
379    pub fn add_hint(&mut self, hint_code: String, hint_func: Rc<HintFunc>) {
380        self.builtin_hint_processor
381            .extra_hints
382            .insert(hint_code, hint_func);
383    }
384
385    /// Push new subtask state onto the stacks.
386    /// Pass an an optional Cairo hint processor.
387    pub fn spawn_subtask(&mut self, cairo_hint_processor: Option<CairoHintProcessor<'a>>) {
388        self.subtask_cairo1_hint_processor_stack
389            .push(cairo_hint_processor);
390    }
391
392    /// Pop the current subtask state off the stacks.
393    pub fn despawn_subtask(&mut self) {
394        self.subtask_cairo1_hint_processor_stack.pop();
395    }
396}
397
398impl HintProcessorLogic for BootloaderHintProcessor<'_> {
399    fn execute_hint(
400        &mut self,
401        _vm: &mut VirtualMachine,
402        _exec_scopes: &mut ExecutionScopes,
403        hint_data: &Box<dyn Any>,
404    ) -> Result<(), HintError> {
405        // This method will never be called, but must be defined for `HintProcessorLogic`.
406
407        let hint_data = hint_data.downcast_ref::<HintProcessorData>().unwrap();
408        let hint_code = &hint_data.code;
409        Err(HintError::UnknownHint(hint_code.clone().into_boxed_str()))
410    }
411
412    fn execute_hint_extensive(
413        &mut self,
414        vm: &mut VirtualMachine,
415        exec_scopes: &mut ExecutionScopes,
416        hint_data: &Box<dyn Any>,
417    ) -> Result<HintExtension, HintError> {
418        // In case the subtask_cairo_hint_processor is a Some variant, we try matching the hint
419        // using it first, for efficiency, since it is assumed to only be Some if we're inside
420        // an execution of a cairo1 program subtask.
421        if let Some(Some(subtask_cairo_hint_processor)) =
422            self.subtask_cairo1_hint_processor_stack.last_mut()
423        {
424            match subtask_cairo_hint_processor.execute_hint_extensive(vm, exec_scopes, hint_data) {
425                Err(HintError::UnknownHint(_)) | Err(HintError::WrongHintData) => {}
426                result => {
427                    return result;
428                }
429            }
430        }
431
432        match self
433            .bootloader_hint_processor
434            .execute_hint_extensive(vm, exec_scopes, hint_data)
435        {
436            Err(HintError::UnknownHint(_)) => {}
437            result => {
438                return result;
439            }
440        }
441
442        let hint_data_dc = hint_data
443            .downcast_ref::<HintProcessorData>()
444            .ok_or(HintError::WrongHintData)?;
445        match hint_data_dc.code.as_str() {
446            EXECUTE_TASK_CALL_TASK => {
447                return setup_subtask_for_execution(
448                    self,
449                    vm,
450                    exec_scopes,
451                    &hint_data_dc.ids_data,
452                    &hint_data_dc.ap_tracking,
453                );
454            }
455            EXECUTE_TASK_EXIT_SCOPE => return execute_task_exit_scope(self, exec_scopes),
456            _ => {}
457        }
458
459        match self
460            .builtin_hint_processor
461            .execute_hint_extensive(vm, exec_scopes, hint_data)
462        {
463            Err(HintError::UnknownHint(_)) => {}
464            result => {
465                return result;
466            }
467        }
468
469        self.test_programs_hint_processor
470            .execute_hint_extensive(vm, exec_scopes, hint_data)
471    }
472}
473
474impl ResourceTracker for BootloaderHintProcessor<'_> {}