diff --git a/Cargo.lock b/Cargo.lock index 8f1cca0486..7406fd65e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,17 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.8.11" @@ -227,8 +238,8 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "zstd", - "zstd-safe", + "zstd 0.13.3", + "zstd-safe 7.2.3", ] [[package]] @@ -318,6 +329,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + [[package]] name = "bincode" version = "2.0.0-rc.3" @@ -445,6 +462,26 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "cairo-lang-casm" version = "2.10.0-rc.0" @@ -533,6 +570,31 @@ dependencies = [ "good_lp", ] +[[package]] +name = "cairo-lang-executable" +version = "2.10.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e1372cbef644001d7a73364581b9b1348add79aba5ec9f9e7a9ce0fe0980c4" +dependencies = [ + "anyhow", + "cairo-lang-casm", + "cairo-lang-compiler", + "cairo-lang-defs", + "cairo-lang-filesystem", + "cairo-lang-lowering", + "cairo-lang-plugins", + "cairo-lang-runnable-utils", + "cairo-lang-semantic", + "cairo-lang-sierra-generator", + "cairo-lang-sierra-to-casm", + "cairo-lang-syntax", + "cairo-lang-utils", + "cairo-vm 1.0.2", + "indoc", + "itertools 0.12.1", + "serde", +] + [[package]] name = "cairo-lang-filesystem" version = "2.10.0-rc.0" @@ -663,6 +725,24 @@ dependencies = [ "toml", ] +[[package]] +name = "cairo-lang-runnable-utils" +version = "2.10.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "951b72522c8a76e177119699bdcd3c4288bdc0bc784ac22dd7c0f80b2a7444d0" +dependencies = [ + "cairo-lang-casm", + "cairo-lang-sierra", + "cairo-lang-sierra-ap-change", + "cairo-lang-sierra-gas", + "cairo-lang-sierra-to-casm", + "cairo-lang-sierra-type-size", + "cairo-lang-utils", + "cairo-vm 1.0.2", + "itertools 0.12.1", + "thiserror 1.0.69", +] + [[package]] name = "cairo-lang-semantic" version = "2.10.0-rc.0" @@ -912,6 +992,37 @@ dependencies = [ "serde", ] +[[package]] +name = "cairo-vm" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fa8b4b56ee66cebcade4d85128e55b2bfdf046502187aeaa8c2768a427684dc" +dependencies = [ + "anyhow", + "bincode", + "bitvec", + "generic-array", + "hashbrown 0.14.5", + "hex", + "keccak", + "lazy_static", + "nom", + "num-bigint", + "num-integer", + "num-prime", + "num-traits", + "rand", + "rust_decimal", + "serde", + "serde_json", + "sha2", + "sha3", + "starknet-crypto 0.6.2", + "starknet-types-core", + "thiserror-no-std", + "zip", +] + [[package]] name = "cairo-vm" version = "2.0.1" @@ -924,6 +1035,7 @@ dependencies = [ "bincode", "bitvec", "cairo-lang-casm", + "cairo-lang-executable", "cairo-lang-starknet", "cairo-lang-starknet-classes", "clap", @@ -950,7 +1062,7 @@ dependencies = [ "serde_json", "sha2", "sha3", - "starknet-crypto", + "starknet-crypto 0.7.4", "starknet-types-core", "thiserror 2.0.12", "wasm-bindgen-test", @@ -963,7 +1075,7 @@ version = "2.0.1" dependencies = [ "assert_matches", "bincode", - "cairo-vm", + "cairo-vm 2.0.1", "cairo-vm-tracer", "clap", "mimalloc", @@ -977,7 +1089,7 @@ name = "cairo-vm-tracer" version = "2.0.1" dependencies = [ "axum", - "cairo-vm", + "cairo-vm 2.0.1", "include_dir", "mime_guess", "num-bigint", @@ -1006,7 +1118,7 @@ dependencies = [ "cairo-lang-sierra-type-size", "cairo-lang-starknet-classes", "cairo-lang-utils", - "cairo-vm", + "cairo-vm 2.0.1", "clap", "itertools 0.11.0", "mimalloc", @@ -1067,6 +1179,16 @@ dependencies = [ "half", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.5.31" @@ -1159,6 +1281,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "convert_case" version = "0.6.0" @@ -1274,6 +1402,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + [[package]] name = "derivative" version = "2.2.0" @@ -1677,7 +1814,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" name = "hint_accountant" version = "2.0.1" dependencies = [ - "cairo-vm", + "cairo-vm 2.0.1", "serde", "serde_json", ] @@ -1758,7 +1895,7 @@ dependencies = [ name = "hyper_threading" version = "2.0.1" dependencies = [ - "cairo-vm", + "cairo-vm 2.0.1", "rayon", "tracing", ] @@ -1855,6 +1992,15 @@ version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "iri-string" version = "0.7.7" @@ -2217,6 +2363,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.46" @@ -2340,6 +2492,17 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" @@ -2352,6 +2515,18 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2464,6 +2639,12 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -2924,6 +3105,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" @@ -3024,6 +3216,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "starknet-crypto" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e2c30c01e8eb0fc913c4ee3cf676389fffc1d1182bfe5bb9670e4e72e968064" +dependencies = [ + "crypto-bigint", + "hex", + "hmac", + "num-bigint", + "num-integer", + "num-traits", + "rfc6979", + "sha2", + "starknet-crypto-codegen", + "starknet-curve 0.4.2", + "starknet-ff", + "zeroize", +] + [[package]] name = "starknet-crypto" version = "0.7.4" @@ -3038,11 +3250,31 @@ dependencies = [ "num-traits", "rfc6979", "sha2", - "starknet-curve", + "starknet-curve 0.5.1", "starknet-types-core", "zeroize", ] +[[package]] +name = "starknet-crypto-codegen" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc159a1934c7be9761c237333a57febe060ace2bc9e3b337a59a37af206d19f" +dependencies = [ + "starknet-curve 0.4.2", + "starknet-ff", + "syn 2.0.98", +] + +[[package]] +name = "starknet-curve" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1c383518bb312751e4be80f53e8644034aa99a0afb29d7ac41b89a997db875b" +dependencies = [ + "starknet-ff", +] + [[package]] name = "starknet-curve" version = "0.5.1" @@ -3052,6 +3284,18 @@ dependencies = [ "starknet-types-core", ] +[[package]] +name = "starknet-ff" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abf1b44ec5b18d87c1ae5f54590ca9d0699ef4dd5b2ffa66fc97f24613ec585" +dependencies = [ + "ark-ff", + "crypto-bigint", + "getrandom 0.2.15", + "hex", +] + [[package]] name = "starknet-types-core" version = "0.1.7" @@ -3191,6 +3435,26 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "thiserror-impl-no-std" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58e6318948b519ba6dc2b442a6d0b904ebfb8d411a3ad3e07843615a72249758" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "thiserror-no-std" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ad459d94dd517257cc96add8a43190ee620011bb6e6cdc82dafd97dfafafea" +dependencies = [ + "thiserror-impl-no-std", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -3201,6 +3465,25 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -3640,7 +3923,7 @@ dependencies = [ name = "wasm-demo" version = "2.0.1" dependencies = [ - "cairo-vm", + "cairo-vm 2.0.1", "console_error_panic_hook", "serde_json", "wasm-bindgen", @@ -3865,10 +4148,27 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" dependencies = [ + "aes", "byteorder", + "bzip2", + "constant_time_eq", "crc32fast", "crossbeam-utils", "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", ] [[package]] @@ -3877,7 +4177,17 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ - "zstd-safe", + "zstd-safe 7.2.3", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 7744e5788d..ac2bf8a748 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,6 +72,7 @@ cairo-lang-sierra-to-casm = { version = "2.10.0-rc.0", default-features = false cairo-lang-sierra = { version = "2.10.0-rc.0", default-features = false } cairo-lang-runner = { version = "2.10.0-rc.0", default-features = false } cairo-lang-utils = { version = "=2.10.0-rc.0", default-features = false } +cairo-lang-executable = { version = "=2.10.0-rc.0", default-features = false } # TODO: check these dependencies for wasm compatibility ark-ff = { version = "0.4.2", default-features = false } diff --git a/cairo_programs/new_executable/empty.cairo b/cairo_programs/new_executable/empty.cairo new file mode 100644 index 0000000000..a53ef42c03 --- /dev/null +++ b/cairo_programs/new_executable/empty.cairo @@ -0,0 +1,2 @@ +#[executable] +fn main() {} diff --git a/vm/Cargo.toml b/vm/Cargo.toml index be960a993c..1fed7c98b7 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -31,6 +31,10 @@ tracer = [] mod_builtin = [] cairo-0-secp-hints = [] cairo-0-data-availability-hints = [] +cairo-runner-2 = [ + "dep:cairo-lang-casm", + "dep:cairo-lang-executable", +] # Note that these features are not retro-compatible with the cairo Python VM. test_utils = ["std", "dep:arbitrary", "starknet-types-core/arbitrary", "starknet-types-core/std"] # This feature will reference every test-oriented feature @@ -62,6 +66,10 @@ thiserror = { workspace = true } starknet-types-core = { version = "0.1.2", default-features = false, features = ["serde", "curve", "num-traits", "hash"] } rust_decimal = { version = "1.35.0", default-features = false } +# cairo-lang dependencies +cairo-lang-executable = { workspace = true, optional = true } +cairo-lang-casm = { workspace = true, optional = true } + # only for std num-prime = { version = "0.4.3", features = ["big-int"], optional = true } bitvec = { workspace = true } @@ -69,7 +77,6 @@ bitvec = { workspace = true } # Dependencies for cairo-1-hints feature cairo-lang-starknet = { workspace = true, optional = true } cairo-lang-starknet-classes = { workspace = true, optional = true } -cairo-lang-casm = { workspace = true, optional = true } # TODO: check these dependencies for wasm compatibility ark-ff = { workspace = true, optional = true } diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs new file mode 100644 index 0000000000..4978c56fc6 --- /dev/null +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -0,0 +1,460 @@ +#![cfg(feature = "cairo-runner-2")] + +use core::any::Any; + +use crate::{ + hint_processor::hint_processor_definition::{HintProcessor, HintReference}, + serde::deserialize_program::HintParams, + stdlib::{ + collections::{BTreeMap, HashMap, HashSet}, + prelude::*, + }, + types::{ + builtin_name::BuiltinName, + errors::program_errors::ProgramError, + exec_scope::ExecutionScopes, + layout::CairoLayout, + program::HintsCollection, + relocatable::{MaybeRelocatable, Relocatable}, + }, + utils::is_subsequence, + vm::{ + context::run_context::RunContext, + errors::{runner_errors::RunnerError, vm_errors::VirtualMachineError}, + runners::builtin_runner::{ + BitwiseBuiltinRunner, BuiltinRunner, EcOpBuiltinRunner, HashBuiltinRunner, + KeccakBuiltinRunner, ModBuiltinRunner, OutputBuiltinRunner, PoseidonBuiltinRunner, + RangeCheckBuiltinRunner, SignatureBuiltinRunner, RC_N_PARTS_96, RC_N_PARTS_STANDARD, + }, + vm_core::VirtualMachine, + vm_memory::{memory::Memory, memory_segments::MemorySegmentManager}, + }, + Felt252, +}; + +/// This type is originally defined in `cairo-lang-executable`. +/// We redefine it here to avoid a cyclic dependencies. +#[derive(Debug)] +pub struct ExecutableEntryPoint { + pub builtins: Vec, + pub offset: usize, + pub kind: EntryPointKind, +} + +/// This type is originally defined in `cairo-lang-executable`. +/// We redefine it here to avoid a cyclic dependencies. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum EntryPointKind { + Bootloader, + Standalone, +} + +pub struct Program2 { + pub bytecode: Vec, + pub hints_collection: HintsCollection, + pub entrypoint: ExecutableEntryPoint, + + pub reference_manager: Vec, + pub constants: HashMap, +} + +impl Program2 { + pub fn new( + bytecode: Vec, + hints: BTreeMap>, + entrypoint: ExecutableEntryPoint, + reference_manager: Vec, + constants: HashMap, + ) -> Result { + let hints_collection = HintsCollection::new(&hints, bytecode.len())?; + + Ok(Self { + bytecode, + hints_collection, + entrypoint, + reference_manager, + constants, + }) + } +} + +#[allow(dead_code)] +pub struct CairoRunner2 { + vm: VirtualMachine, + program_base: Relocatable, + execution_base: Relocatable, + final_pc: Relocatable, + execution_scopes: ExecutionScopes, + + // Configuration + program: Program2, + layout: CairoLayout, +} + +impl CairoRunner2 { + #[allow(clippy::too_many_arguments)] + pub fn new( + program: Program2, + layout: CairoLayout, + trace_enabled: bool, + ) -> Result { + let mut vm = VirtualMachine::new(trace_enabled, false); + + check_builtin_order(&(&program.entrypoint).builtins)?; + vm.builtin_runners = + initialize_builtin_runners(&layout, &program.entrypoint.builtins, true, true)?; + + let program_base = vm.add_memory_segment(); + let execution_base = vm.add_memory_segment(); + + initialize_builtin_runner_segments(&mut vm.builtin_runners, &mut vm.segments); + + load_program(&mut vm, program_base, &program.bytecode)?; + + let mut stack = Vec::new(); + + let initial_pc = (program_base + program.entrypoint.offset)?; + + let (initial_fp, final_pc) = match program.entrypoint.kind { + EntryPointKind::Bootloader => { + // On bootloader, we execute until control flow is returned. + // The stack is arranged as if we are at the start of a function call. + // Input arguments are set as input arguments to the the function. + // + // <-------- ARGUMENTS ---- + // ┌────┬────┬────┬────┬────────┬────────┬ ─ ─ ─ ─ ┐ + // ... │ │ │ │ │ RET FP │ RET PC │ + // └────┴────┴────┴────┴────────┴────────┴ ─ ─ ─ ─ ┘ + // INIT FP + // Note: The size of the cells is not relevant + // + // The initial fp variable points to the cell after the return pc. + + extend_stack_with_builtins( + &mut stack, + &program.entrypoint.builtins, + &vm.builtin_runners, + ); + + let return_fp = vm.add_memory_segment(); + let return_pc = vm.add_memory_segment(); + stack.push(MaybeRelocatable::RelocatableValue(return_fp)); + stack.push(MaybeRelocatable::RelocatableValue(return_pc)); + + let initial_fp = (execution_base + stack.len())?; + + (initial_fp, return_pc) + } + EntryPointKind::Standalone => { + // On standalone, we execute until a fixed address. + // Input arguments are set as local variables to the current frame. + // + // -------------- ARGUMENTS ------------------> + // ┌──────┬─────────┬────┬────┬────┬────┬────┬────┐ + // │ ZERO │ │ │ │ │ │ │ │ ... + // └──────┴─────────┴────┴────┴────┴────┴────┴────┘ + // INIT FP + // Note: The size of the cells is not relevant + // + // The initial fp variable points to the cell after the zero element. + // + // The zero element is necessary because the compiler asumes that `fp` + // is not pointing to the start of a segment - it fails otherwise. + + let stack_prefix = &[MaybeRelocatable::Int(Felt252::ZERO)]; + stack.extend_from_slice(stack_prefix); + extend_stack_with_builtins( + &mut stack, + &program.entrypoint.builtins, + &vm.builtin_runners, + ); + + let final_pc = (initial_pc + 4)?; + let initial_fp = (execution_base + stack_prefix.len())?; + + (initial_fp, final_pc) + } + }; + + let initial_ap = initial_fp; + let run_context = RunContext::new(initial_pc, initial_ap.offset, initial_fp.offset); + vm.set_run_context(run_context); + + load_stack(&mut vm, execution_base, &stack)?; + + add_builtin_validation_rules(&mut vm.segments.memory, &mut vm.builtin_runners)?; + + Ok(Self { + vm, + program_base, + execution_base, + final_pc, + execution_scopes: ExecutionScopes::new(), + program, + layout, + }) + } + + pub fn run( + &mut self, + hint_processor: &mut dyn HintProcessor, + ) -> Result<(), VirtualMachineError> { + #[cfg_attr(not(feature = "extensive_hints"), allow(unused_mut))] + let mut hint_data = get_hint_data( + &self.program.hints_collection, + &self.program.reference_manager, + hint_processor, + )?; + + #[cfg(feature = "extensive_hints")] + let mut hint_ranges = self.program.hints_collection.hints_ranges.clone(); + + while self.vm.get_pc() != self.final_pc && !hint_processor.consumed() { + #[cfg(feature = "extensive_hints")] + let hint_data = &mut hint_data; + #[cfg(not(feature = "extensive_hints"))] + let hint_data = self + .program + .hints_collection + .get_hint_range_for_pc(self.vm.get_pc().offset) + .and_then(|range| { + range.and_then(|(start, length)| hint_data.get(start..start + length.get())) + }) + .unwrap_or(&[]); + + self.vm.step( + hint_processor, + &mut self.execution_scopes, + hint_data, + #[cfg(feature = "extensive_hints")] + &mut hint_ranges, + &self.program.constants, + )?; + + hint_processor.consume_step(); + } + + if self.vm.get_pc() != self.final_pc { + return Err(VirtualMachineError::UnfinishedExecution); + } + + Ok(()) + } +} + +pub fn check_builtin_order(builtins: &[BuiltinName]) -> Result<(), RunnerError> { + let ordered_builtins = vec![ + BuiltinName::output, + BuiltinName::pedersen, + BuiltinName::range_check, + BuiltinName::ecdsa, + BuiltinName::bitwise, + BuiltinName::ec_op, + BuiltinName::keccak, + BuiltinName::poseidon, + BuiltinName::range_check96, + BuiltinName::add_mod, + BuiltinName::mul_mod, + ]; + if !is_subsequence(builtins, &ordered_builtins) { + return Err(RunnerError::DisorderedBuiltins); + }; + + Ok(()) +} + +pub fn initialize_builtin_runners( + layout: &CairoLayout, + builtins: &[BuiltinName], + allow_missing_builtins: bool, + create_all_builtins: bool, +) -> Result, RunnerError> { + let mut builtin_runners = Vec::new(); + + let mut builtins: HashSet = builtins.iter().map(ToOwned::to_owned).collect(); + + if layout.builtins.output { + let included = builtins.remove(&BuiltinName::output); + if included || create_all_builtins { + builtin_runners.push(OutputBuiltinRunner::new(included).into()); + } + } + + if let Some(instance_def) = layout.builtins.pedersen.as_ref() { + let included = builtins.remove(&BuiltinName::pedersen); + if included || create_all_builtins { + builtin_runners.push(HashBuiltinRunner::new(instance_def.ratio, included).into()); + } + } + + if let Some(instance_def) = layout.builtins.range_check.as_ref() { + let included = builtins.remove(&BuiltinName::range_check); + if included || create_all_builtins { + builtin_runners.push( + RangeCheckBuiltinRunner::::new_with_low_ratio( + instance_def.ratio, + included, + ) + .into(), + ); + } + } + + if let Some(instance_def) = layout.builtins.ecdsa.as_ref() { + let included = builtins.remove(&BuiltinName::ecdsa); + if included || create_all_builtins { + builtin_runners.push(SignatureBuiltinRunner::new(instance_def.ratio, included).into()); + } + } + + if let Some(instance_def) = layout.builtins.bitwise.as_ref() { + let included = builtins.remove(&BuiltinName::bitwise); + if included || create_all_builtins { + builtin_runners.push(BitwiseBuiltinRunner::new(instance_def.ratio, included).into()); + } + } + + if let Some(instance_def) = layout.builtins.ec_op.as_ref() { + let included = builtins.remove(&BuiltinName::ec_op); + if included || create_all_builtins { + builtin_runners.push(EcOpBuiltinRunner::new(instance_def.ratio, included).into()); + } + } + + if let Some(instance_def) = layout.builtins.keccak.as_ref() { + let included = builtins.remove(&BuiltinName::keccak); + if included || create_all_builtins { + builtin_runners.push(KeccakBuiltinRunner::new(instance_def.ratio, included).into()); + } + } + + if let Some(instance_def) = layout.builtins.poseidon.as_ref() { + let included = builtins.remove(&BuiltinName::poseidon); + if included || create_all_builtins { + builtin_runners.push(PoseidonBuiltinRunner::new(instance_def.ratio, included).into()); + } + } + + if let Some(instance_def) = layout.builtins.range_check96.as_ref() { + let included = builtins.remove(&BuiltinName::range_check96); + if included || create_all_builtins { + builtin_runners.push( + RangeCheckBuiltinRunner::::new_with_low_ratio( + instance_def.ratio, + included, + ) + .into(), + ); + } + } + if let Some(instance_def) = layout.builtins.add_mod.as_ref() { + let included = builtins.remove(&BuiltinName::add_mod); + if included || create_all_builtins { + builtin_runners.push(ModBuiltinRunner::new_add_mod(instance_def, included).into()); + } + } + if let Some(instance_def) = layout.builtins.mul_mod.as_ref() { + let included = builtins.remove(&BuiltinName::mul_mod); + if included || create_all_builtins { + builtin_runners.push(ModBuiltinRunner::new_mul_mod(instance_def, included).into()); + } + } + + if !builtins.is_empty() && !allow_missing_builtins { + return Err(RunnerError::NoBuiltinForInstance(Box::new(( + builtins, + layout.name, + )))); + } + + Ok(builtin_runners) +} + +fn initialize_builtin_runner_segments( + builtin_runners: &mut [BuiltinRunner], + segments: &mut MemorySegmentManager, +) { + for builtin_runner in builtin_runners.iter_mut() { + builtin_runner.initialize_segments(segments); + } + + for builtin_runner in builtin_runners.iter_mut() { + if let BuiltinRunner::Mod(mod_builtin_runner) = builtin_runner { + mod_builtin_runner.initialize_zero_segment(segments); + } + } +} + +fn extend_stack_with_builtins( + stack: &mut Vec, + builtins: &[BuiltinName], + runners: &[BuiltinRunner], +) { + let runner_map: HashMap = runners + .iter() + .map(|builtin_runner| (builtin_runner.name(), builtin_runner)) + .collect(); + for builtin in builtins { + if let Some(builtin_runner) = runner_map.get(builtin) { + stack.append(&mut builtin_runner.initial_stack()); + } else { + stack.push(Felt252::ZERO.into()) + } + } +} + +fn load_program( + vm: &mut VirtualMachine, + program_base: Relocatable, + bytecode: &[MaybeRelocatable], +) -> Result<(), RunnerError> { + vm.load_data(program_base, bytecode) + .map_err(RunnerError::MemoryInitializationError)?; + for i in 0..bytecode.len() { + vm.segments.memory.mark_as_accessed((program_base + i)?); + } + Ok(()) +} + +fn load_stack( + vm: &mut VirtualMachine, + execution_base: Relocatable, + stack: &[MaybeRelocatable], +) -> Result<(), RunnerError> { + vm.load_data(execution_base, stack) + .map_err(RunnerError::MemoryInitializationError)?; + Ok(()) +} + +fn add_builtin_validation_rules( + memory: &mut Memory, + runners: &mut [BuiltinRunner], +) -> Result<(), RunnerError> { + for runner in runners { + runner.add_validation_rule(memory) + } + memory + .validate_existing_memory() + .map_err(RunnerError::MemoryValidationError)?; + Ok(()) +} + +fn get_hint_data( + collection: &HintsCollection, + references: &[HintReference], + processor: &dyn HintProcessor, +) -> Result>, VirtualMachineError> { + collection + .iter_hints() + .map(|hint| { + processor + .compile_hint( + &hint.code, + &hint.flow_tracking_data.ap_tracking, + &hint.flow_tracking_data.reference_ids, + references, + ) + .map_err(|_| VirtualMachineError::CompileHintFail(hint.code.clone().into())) + }) + .collect() +} diff --git a/vm/src/vm/runners/mod.rs b/vm/src/vm/runners/mod.rs index ed5ecaa7dc..30b6dae47d 100644 --- a/vm/src/vm/runners/mod.rs +++ b/vm/src/vm/runners/mod.rs @@ -1,3 +1,4 @@ pub mod builtin_runner; pub mod cairo_pie; pub mod cairo_runner; +pub mod cairo_runner_2; diff --git a/vm/src/vm/vm_core.rs b/vm/src/vm/vm_core.rs index 1c0a59682e..0f32bbb589 100644 --- a/vm/src/vm/vm_core.rs +++ b/vm/src/vm/vm_core.rs @@ -1067,6 +1067,11 @@ impl VirtualMachine { self.run_context.set_pc(pc) } + #[doc(hidden)] + pub fn set_run_context(&mut self, run_context: RunContext) { + self.run_context = run_context; + } + pub fn get_segment_used_size(&self, index: usize) -> Option { self.segments.get_segment_used_size(index) }