Skip to content

Commit c42f95a

Browse files
JulianGCalderonDiegoCivigabrielbosio
authored
Add test for simulated builtins (#2167)
* Add get_simulated_builtin_base hint for testing purposes * Add simulated_builtins.cairo example * Document simulated builtins field * Add a test for simulated builtins * Add documentation * Fix typos Co-authored-by: DiegoC <[email protected]> --------- Co-authored-by: DiegoC <[email protected]> Co-authored-by: Gabriel Bosio <[email protected]>
1 parent cfe117c commit c42f95a

File tree

6 files changed

+147
-0
lines changed

6 files changed

+147
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
%builtins ec_op
2+
3+
from starkware.cairo.common.cairo_builtins import EcOpBuiltin
4+
from starkware.cairo.common.ec_point import EcPoint
5+
from starkware.cairo.common.ec import ec_op
6+
7+
func main{ec_op_ptr: EcOpBuiltin*}() {
8+
alloc_locals;
9+
let (local ec_op_ptr) = init_ec_op(ec_op_ptr=ec_op_ptr);
10+
11+
let p = EcPoint(
12+
0x6a4beaef5a93425b973179cdba0c9d42f30e01a5f1e2db73da0884b8d6756fc,
13+
0x72565ec81bc09ff53fbfad99324a92aa5b39fb58267e395e8abe36290ebf24f,
14+
);
15+
let m = 34;
16+
let q = EcPoint(
17+
0x654fd7e67a123dd13868093b3b7777f1ffef596c2e324f25ceaf9146698482c,
18+
0x4fad269cbf860980e38768fe9cb6b0b9ab03ee3fe84cfde2eccce597c874fd8,
19+
);
20+
let (r) = ec_op(p, m, q);
21+
assert r.x = 108925483682366235368969256555281508851459278989259552980345066351008608800;
22+
assert r.y = 1592365885972480102953613056006596671718206128324372995731808913669237079419;
23+
return ();
24+
}
25+
26+
// Initializes the ec_op builtin pointer if not initialized.
27+
//
28+
// If the builtin is included in the layout, the ec_op_ptr will be valid, and
29+
// this function will do nothing. If the builtin is not included in the layout,
30+
// then it will obtain the pointer of the ec_op simulated builtin and return
31+
// it. For this to work properly, the runner must have the ec_op simulated
32+
// builtin runner at index 0.
33+
func init_ec_op(ec_op_ptr: EcOpBuiltin*) -> (ec_op_ptr: EcOpBuiltin*) {
34+
if (ec_op_ptr != 0) {
35+
return (ec_op_ptr=ec_op_ptr);
36+
}
37+
38+
alloc_locals;
39+
local builtin_idx = 0;
40+
local new_ptr;
41+
42+
// This hint is not defined in the original VM,
43+
// and its declared for testing purposes only.
44+
%{ ids.new_ptr = get_simulated_builtin_base(ids.builtin_idx) %}
45+
46+
return (ec_op_ptr=cast(new_ptr, EcOpBuiltin*));
47+
}

vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,16 @@ impl HintProcessorLogic for BuiltinHintProcessor {
10171017
&hint_data.ap_tracking,
10181018
constants,
10191019
),
1020+
#[cfg(feature = "test_utils")]
1021+
super::simulated_builtins::GET_SIMULATED_BUILTIN_BASE => {
1022+
super::simulated_builtins::get_simulated_builtin_base(
1023+
vm,
1024+
exec_scopes,
1025+
&hint_data.ids_data,
1026+
&hint_data.ap_tracking,
1027+
constants,
1028+
)
1029+
}
10201030

10211031
code => Err(HintError::UnknownHint(code.to_string().into_boxed_str())),
10221032
}

vm/src/hint_processor/builtin_hint_processor/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ pub mod sha256_utils;
3030
pub mod signature;
3131
#[cfg(feature = "test_utils")]
3232
#[cfg_attr(docsrs, doc(cfg(feature = "test_utils")))]
33+
pub mod simulated_builtins;
34+
#[cfg(feature = "test_utils")]
35+
#[cfg_attr(docsrs, doc(cfg(feature = "test_utils")))]
3336
pub mod skip_next_instruction;
3437
pub mod squash_dict_utils;
3538
pub mod uint256_utils;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use crate::hint_processor::hint_processor_definition::HintReference;
2+
use crate::stdlib::collections::HashMap;
3+
use crate::types::relocatable::Relocatable;
4+
use crate::Felt252;
5+
use crate::{
6+
serde::deserialize_program::ApTracking,
7+
types::exec_scope::ExecutionScopes,
8+
vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
9+
};
10+
use num_traits::ToPrimitive;
11+
12+
use super::hint_utils::{get_integer_from_var_name, insert_value_from_var_name};
13+
14+
pub const GET_SIMULATED_BUILTIN_BASE: &str =
15+
"ids.new_ptr = get_simulated_builtin_base(ids.builtin_idx)";
16+
17+
/// Obtains the simulated builtin runner base, at the given index. The simulated
18+
/// builtin runner must be initialized before the execution.
19+
///
20+
/// This hint is not defined in the original VM, and its declared for testing
21+
/// purposes only.
22+
pub fn get_simulated_builtin_base(
23+
vm: &mut VirtualMachine,
24+
_exec_scopes: &mut ExecutionScopes,
25+
ids_data: &HashMap<String, HintReference>,
26+
ap_tracking: &ApTracking,
27+
_constants: &HashMap<String, Felt252>,
28+
) -> Result<(), HintError> {
29+
// Obtain the simulated builtin runner from the builtin_idx variable.
30+
let builtin_idx = get_integer_from_var_name("builtin_idx", vm, ids_data, ap_tracking)?
31+
.to_usize()
32+
.ok_or(HintError::BigintToUsizeFail)?;
33+
let builtin_runner = &vm.simulated_builtin_runners[builtin_idx];
34+
35+
// Set new_ptr with the value of the builtin runner base.
36+
insert_value_from_var_name(
37+
"new_ptr",
38+
Relocatable {
39+
segment_index: builtin_runner.base() as isize,
40+
offset: 0,
41+
},
42+
vm,
43+
ids_data,
44+
ap_tracking,
45+
)
46+
}

vm/src/vm/runners/cairo_runner.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5731,4 +5731,35 @@ mod tests {
57315731
let builtin_segments = cairo_runner.get_builtin_segments();
57325732
assert!(builtin_segments.get(&9) == Some(&BuiltinName::poseidon));
57335733
}
5734+
5735+
#[test]
5736+
#[cfg(feature = "test_utils")]
5737+
fn test_simulated_builtins() {
5738+
let program_bytes = include_bytes!("../../../../cairo_programs/simulated_builtins.json");
5739+
let program =
5740+
Program::from_bytes(program_bytes, Some("main")).expect("failed to read program");
5741+
5742+
let program: &Program = &program;
5743+
let mut cairo_runner =
5744+
CairoRunner::new(program, LayoutName::plain, None, false, false, false)
5745+
.expect("failed to create runner");
5746+
5747+
// We allow missing builtins, as we will simulate them later.
5748+
let end = cairo_runner
5749+
.initialize(true)
5750+
.expect("failed to initialize builtins");
5751+
5752+
// Initialize the ec_op simulated builtin runner.
5753+
let mut builtin_runner = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(None, true));
5754+
builtin_runner.initialize_segments(&mut cairo_runner.vm.segments);
5755+
cairo_runner
5756+
.vm
5757+
.simulated_builtin_runners
5758+
.push(builtin_runner);
5759+
5760+
let hint_processor: &mut dyn HintProcessor = &mut BuiltinHintProcessor::new_empty();
5761+
cairo_runner
5762+
.run_until_pc(end, hint_processor)
5763+
.expect("failed to run program");
5764+
}
57345765
}

vm/src/vm/vm_core.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ impl DeducedOperands {
8989
pub struct VirtualMachine {
9090
pub(crate) run_context: RunContext,
9191
pub builtin_runners: Vec<BuiltinRunner>,
92+
/// A simulated builtin is being verified in the executed Cairo
93+
/// code (so proving them only involves proving cairo steps), rather
94+
/// than being outputted as their own segment and proven later using
95+
/// dedicated AIRs.
96+
///
97+
/// These builtins won't be included in the layout, hence the builtin
98+
/// segment pointer won't be passed as argument to the program. The program
99+
/// needs a mechanism for obtaining the segment pointer. See example
100+
/// implementation of this mechanism in `simulated_builtins.cairo`, or
101+
/// cairo-lang's `simple_bootloader.cairo`.
92102
pub simulated_builtin_runners: Vec<BuiltinRunner>,
93103
pub segments: MemorySegmentManager,
94104
pub(crate) trace: Option<Vec<TraceEntry>>,

0 commit comments

Comments
 (0)