diff --git a/Cargo.lock b/Cargo.lock index 39b9eac5fb..2c40305a08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1064,6 +1064,7 @@ dependencies = [ "cairo-lang-starknet", "cairo-lang-starknet-classes", "cairo-lang-utils", + "cairo-starknet-syscalls", "criterion", "educe 0.5.11", "itertools 0.14.0", @@ -1211,6 +1212,14 @@ dependencies = [ "serde_json", ] +[[package]] +name = "cairo-starknet-syscalls" +version = "0.9.0-rc.7" +dependencies = [ + "serde", + "starknet-types-core", +] + [[package]] name = "cairo-vm" version = "3.2.0" @@ -3721,6 +3730,7 @@ dependencies = [ "cairo-lang-starknet-classes", "cairo-lang-test-plugin", "cairo-lang-utils", + "cairo-starknet-syscalls", "clap", "generic-array", "k256", diff --git a/Cargo.toml b/Cargo.toml index 4d13bfaf77..51cd72d9d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ exclude = [ "debug_utils/casm-data-flow", ] members = [ + "cairo-starknet-syscalls", "debug_utils", "debug_utils/sierra-emu", "debug_utils/cairo-native-stress", @@ -53,6 +54,7 @@ cairo-lang-test-runner = "~2.19.0-rc.1" cairo-lang-utils = "~2.19.0-rc.1" cairo-native-bin-utils.path = "binaries/cairo-native-bin-utils" cairo-native = { path = ".", version = "0.9.0-rc.7" } +cairo-starknet-syscalls = { path = "cairo-starknet-syscalls", version = "0.9.0-rc.7" } clap = "4.5.23" colored = "2.1.0" criterion = "0.5.1" @@ -135,6 +137,7 @@ testing = ["dep:cairo-lang-compiler", "dep:cairo-lang-filesystem"] [dependencies] aquamarine.workspace = true bumpalo.workspace = true +cairo-starknet-syscalls.workspace = true cairo-lang-compiler = { workspace = true, optional = true } cairo-lang-filesystem = { workspace = true, optional = true } cairo-lang-lowering.workspace = true diff --git a/cairo-starknet-syscalls/Cargo.toml b/cairo-starknet-syscalls/Cargo.toml new file mode 100644 index 0000000000..69daee9c24 --- /dev/null +++ b/cairo-starknet-syscalls/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "cairo-starknet-syscalls" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +description = "Shared StarknetSyscallHandler trait and supporting types for cairo-native and sierra-emu" + +[dependencies] +serde = { workspace = true, features = ["derive"] } +starknet-types-core = { workspace = true, features = ["std", "serde", "num-traits"] } diff --git a/cairo-starknet-syscalls/src/lib.rs b/cairo-starknet-syscalls/src/lib.rs new file mode 100644 index 0000000000..04b1694c15 --- /dev/null +++ b/cairo-starknet-syscalls/src/lib.rs @@ -0,0 +1,391 @@ +//! Shared `StarknetSyscallHandler` trait and supporting types for cairo-native +//! and sierra-emu. +//! +//! Both crates re-export from here so a single syscall-handler impl can drive +//! both the cairo-native AOT executor and the sierra-emu interpreter. + +#![deny(unused_must_use)] + +use serde::{Deserialize, Serialize}; +use starknet_types_core::felt::Felt; + +pub type SyscallResult = std::result::Result>; + +/// Binary representation of a `u256` (in MLIR). +#[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + serde::Serialize, + serde::Deserialize, + Default, +)] +#[repr(C, align(16))] +pub struct U256 { + pub lo: u128, + pub hi: u128, +} + +#[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Default, + serde::Serialize, + serde::Deserialize, +)] +pub struct ExecutionInfo { + pub block_info: BlockInfo, + pub tx_info: TxInfo, + pub caller_address: Felt, + pub contract_address: Felt, + pub entry_point_selector: Felt, +} + +#[derive( + Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, +)] +pub struct ExecutionInfoV2 { + pub block_info: BlockInfo, + pub tx_info: TxV2Info, + pub caller_address: Felt, + pub contract_address: Felt, + pub entry_point_selector: Felt, +} + +#[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Default, + serde::Serialize, + serde::Deserialize, +)] +pub struct TxV2Info { + pub version: Felt, + pub account_contract_address: Felt, + pub max_fee: u128, + pub signature: Vec, + pub transaction_hash: Felt, + pub chain_id: Felt, + pub nonce: Felt, + pub resource_bounds: Vec, + pub tip: u128, + pub paymaster_data: Vec, + pub nonce_data_availability_mode: u32, + pub fee_data_availability_mode: u32, + pub account_deployment_data: Vec, +} + +#[derive( + Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, +)] +pub struct ExecutionInfoV3 { + pub block_info: BlockInfo, + pub tx_info: TxV3Info, + pub caller_address: Felt, + pub contract_address: Felt, + pub entry_point_selector: Felt, +} + +#[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Default, + serde::Serialize, + serde::Deserialize, +)] +pub struct TxV3Info { + pub version: Felt, + pub account_contract_address: Felt, + pub max_fee: u128, + pub signature: Vec, + pub transaction_hash: Felt, + pub chain_id: Felt, + pub nonce: Felt, + pub resource_bounds: Vec, + pub tip: u128, + pub paymaster_data: Vec, + pub nonce_data_availability_mode: u32, + pub fee_data_availability_mode: u32, + pub account_deployment_data: Vec, + pub proof_facts: Vec, +} + +#[derive( + Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, +)] +pub struct ResourceBounds { + pub resource: Felt, + pub max_amount: u64, + pub max_price_per_unit: u128, +} + +#[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Default, + serde::Serialize, + serde::Deserialize, +)] +pub struct BlockInfo { + pub block_number: u64, + pub block_timestamp: u64, + pub sequencer_address: Felt, +} + +#[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Default, + serde::Serialize, + serde::Deserialize, +)] +pub struct TxInfo { + pub version: Felt, + pub account_contract_address: Felt, + pub max_fee: u128, + pub signature: Vec, + pub transaction_hash: Felt, + pub chain_id: Felt, + pub nonce: Felt, +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Deserialize, Serialize, Default)] +#[repr(C, align(16))] +pub struct Secp256k1Point { + pub x: U256, + pub y: U256, + pub is_infinity: bool, +} + +impl Secp256k1Point { + pub const fn new(x_lo: u128, x_hi: u128, y_lo: u128, y_hi: u128, is_infinity: bool) -> Self { + Self { + x: U256 { lo: x_lo, hi: x_hi }, + y: U256 { lo: y_lo, hi: y_hi }, + is_infinity, + } + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Deserialize, Serialize, Default)] +#[repr(C, align(16))] +pub struct Secp256r1Point { + pub x: U256, + pub y: U256, + pub is_infinity: bool, +} + +impl Secp256r1Point { + pub const fn new(x_lo: u128, x_hi: u128, y_lo: u128, y_hi: u128, is_infinity: bool) -> Self { + Self { + x: U256 { lo: x_lo, hi: x_hi }, + y: U256 { lo: y_lo, hi: y_hi }, + is_infinity, + } + } +} + +pub trait StarknetSyscallHandler { + fn get_block_hash(&mut self, block_number: u64, remaining_gas: &mut u64) + -> SyscallResult; + + fn get_execution_info(&mut self, remaining_gas: &mut u64) -> SyscallResult; + + fn get_execution_info_v2(&mut self, remaining_gas: &mut u64) -> SyscallResult; + + fn get_execution_info_v3(&mut self, remaining_gas: &mut u64) -> SyscallResult; + + fn deploy( + &mut self, + class_hash: Felt, + contract_address_salt: Felt, + calldata: &[Felt], + deploy_from_zero: bool, + remaining_gas: &mut u64, + ) -> SyscallResult<(Felt, Vec)>; + + fn replace_class(&mut self, class_hash: Felt, remaining_gas: &mut u64) -> SyscallResult<()>; + + fn library_call( + &mut self, + class_hash: Felt, + function_selector: Felt, + calldata: &[Felt], + remaining_gas: &mut u64, + ) -> SyscallResult>; + + fn call_contract( + &mut self, + address: Felt, + entry_point_selector: Felt, + calldata: &[Felt], + remaining_gas: &mut u64, + ) -> SyscallResult>; + + fn storage_read( + &mut self, + address_domain: u32, + address: Felt, + remaining_gas: &mut u64, + ) -> SyscallResult; + + fn storage_write( + &mut self, + address_domain: u32, + address: Felt, + value: Felt, + remaining_gas: &mut u64, + ) -> SyscallResult<()>; + + fn emit_event( + &mut self, + keys: &[Felt], + data: &[Felt], + remaining_gas: &mut u64, + ) -> SyscallResult<()>; + + fn send_message_to_l1( + &mut self, + to_address: Felt, + payload: &[Felt], + remaining_gas: &mut u64, + ) -> SyscallResult<()>; + + fn keccak(&mut self, input: &[u64], remaining_gas: &mut u64) -> SyscallResult; + + fn secp256k1_new( + &mut self, + x: U256, + y: U256, + remaining_gas: &mut u64, + ) -> SyscallResult>; + + fn secp256k1_add( + &mut self, + p0: Secp256k1Point, + p1: Secp256k1Point, + remaining_gas: &mut u64, + ) -> SyscallResult; + + fn secp256k1_mul( + &mut self, + p: Secp256k1Point, + m: U256, + remaining_gas: &mut u64, + ) -> SyscallResult; + + fn secp256k1_get_point_from_x( + &mut self, + x: U256, + y_parity: bool, + remaining_gas: &mut u64, + ) -> SyscallResult>; + + fn secp256k1_get_xy( + &mut self, + p: Secp256k1Point, + remaining_gas: &mut u64, + ) -> SyscallResult<(U256, U256)>; + + fn secp256r1_new( + &mut self, + x: U256, + y: U256, + remaining_gas: &mut u64, + ) -> SyscallResult>; + + fn secp256r1_add( + &mut self, + p0: Secp256r1Point, + p1: Secp256r1Point, + remaining_gas: &mut u64, + ) -> SyscallResult; + + fn secp256r1_mul( + &mut self, + p: Secp256r1Point, + m: U256, + remaining_gas: &mut u64, + ) -> SyscallResult; + + fn secp256r1_get_point_from_x( + &mut self, + x: U256, + y_parity: bool, + remaining_gas: &mut u64, + ) -> SyscallResult>; + + fn secp256r1_get_xy( + &mut self, + p: Secp256r1Point, + remaining_gas: &mut u64, + ) -> SyscallResult<(U256, U256)>; + + fn sha256_process_block( + &mut self, + state: &mut [u32; 8], + block: &[u32; 16], + remaining_gas: &mut u64, + ) -> SyscallResult<()>; + + fn sha512_process_block( + &mut self, + state: &mut [u64; 8], + block: &[u64; 16], + remaining_gas: &mut u64, + ) -> SyscallResult<()>; + + fn get_class_hash_at( + &mut self, + contract_address: Felt, + remaining_gas: &mut u64, + ) -> SyscallResult; + + fn meta_tx_v0( + &mut self, + address: Felt, + entry_point_selector: Felt, + calldata: &[Felt], + signature: &[Felt], + remaining_gas: &mut u64, + ) -> SyscallResult>; + + /// Test-only Starknet syscall. Production handlers don't implement it; the default + /// returns a single error felt rather than panicking, so a malicious contract that + /// invokes `cheatcode` against a handler that didn't override the method can't crash + /// the host. Test handlers should override. + fn cheatcode(&mut self, _selector: Felt, _input: &[Felt]) -> Vec { + vec![Felt::from_bytes_be_slice(b"cheatcode unsupported")] + } +} diff --git a/debug_utils/sierra-emu/Cargo.toml b/debug_utils/sierra-emu/Cargo.toml index 96290517db..f5e5387fc4 100644 --- a/debug_utils/sierra-emu/Cargo.toml +++ b/debug_utils/sierra-emu/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true repository.workspace = true [dependencies] +cairo-starknet-syscalls.workspace = true cairo-lang-lowering.workspace = true cairo-lang-compiler.workspace = true cairo-lang-filesystem.workspace = true diff --git a/debug_utils/sierra-emu/src/starknet.rs b/debug_utils/sierra-emu/src/starknet.rs index 288dd7bfac..547d015af6 100644 --- a/debug_utils/sierra-emu/src/starknet.rs +++ b/debug_utils/sierra-emu/src/starknet.rs @@ -3,11 +3,9 @@ use std::{ iter::once, }; -pub use self::{ - block_info::BlockInfo, execution_info::ExecutionInfo, execution_info_v2::ExecutionInfoV2, - execution_info_v3::ExecutionInfoV3, resource_bounds::ResourceBounds, - secp256k1_point::Secp256k1Point, secp256r1_point::Secp256r1Point, tx_info::TxInfo, - tx_v2_info::TxV2Info, tx_v3_info::TxV3Info, u256::U256, +pub use cairo_starknet_syscalls::{ + BlockInfo, ExecutionInfo, ExecutionInfoV2, ExecutionInfoV3, ResourceBounds, Secp256k1Point, + Secp256r1Point, StarknetSyscallHandler, SyscallResult, TxInfo, TxV2Info, TxV3Info, U256, }; use k256::elliptic_curve::{ generic_array::GenericArray, @@ -17,202 +15,16 @@ use sec1::point::Coordinates; use serde::Serialize; use starknet_types_core::felt::Felt; -mod block_info; -mod execution_info; -mod execution_info_v2; -mod execution_info_v3; -mod resource_bounds; -mod secp256k1_point; -mod secp256r1_point; -mod tx_info; -mod tx_v2_info; -mod tx_v3_info; -mod u256; +pub mod value_conv; -pub type SyscallResult = Result>; - -pub trait StarknetSyscallHandler { - fn get_block_hash(&mut self, block_number: u64, remaining_gas: &mut u64) - -> SyscallResult; - - fn get_execution_info(&mut self, remaining_gas: &mut u64) -> SyscallResult; - - fn get_execution_info_v2(&mut self, remaining_gas: &mut u64) -> SyscallResult; - - fn get_execution_info_v3( - &mut self, - _remaining_gas: &mut u64, - ) -> SyscallResult { - unimplemented!() - } - - fn deploy( - &mut self, - class_hash: Felt, - contract_address_salt: Felt, - calldata: &[Felt], - deploy_from_zero: bool, - remaining_gas: &mut u64, - ) -> SyscallResult<(Felt, Vec)>; - - fn replace_class(&mut self, class_hash: Felt, remaining_gas: &mut u64) -> SyscallResult<()>; - - fn library_call( - &mut self, - class_hash: Felt, - function_selector: Felt, - calldata: &[Felt], - remaining_gas: &mut u64, - ) -> SyscallResult>; - - fn call_contract( - &mut self, - address: Felt, - entry_point_selector: Felt, - calldata: &[Felt], - remaining_gas: &mut u64, - ) -> SyscallResult>; - - fn storage_read( - &mut self, - address_domain: u32, - address: Felt, - remaining_gas: &mut u64, - ) -> SyscallResult; - - fn storage_write( - &mut self, - address_domain: u32, - address: Felt, - value: Felt, - remaining_gas: &mut u64, - ) -> SyscallResult<()>; - - fn emit_event( - &mut self, - keys: &[Felt], - data: &[Felt], - remaining_gas: &mut u64, - ) -> SyscallResult<()>; - - fn send_message_to_l1( - &mut self, - to_address: Felt, - payload: &[Felt], - remaining_gas: &mut u64, - ) -> SyscallResult<()>; - - fn keccak(&mut self, input: &[u64], remaining_gas: &mut u64) -> SyscallResult; - - fn secp256k1_new( - &mut self, - x: U256, - y: U256, - remaining_gas: &mut u64, - ) -> SyscallResult>; - - fn secp256k1_add( - &mut self, - p0: Secp256k1Point, - p1: Secp256k1Point, - remaining_gas: &mut u64, - ) -> SyscallResult; - - fn secp256k1_mul( - &mut self, - p: Secp256k1Point, - m: U256, - remaining_gas: &mut u64, - ) -> SyscallResult; - - fn secp256k1_get_point_from_x( - &mut self, - x: U256, - y_parity: bool, - remaining_gas: &mut u64, - ) -> SyscallResult>; - - fn secp256k1_get_xy( - &mut self, - p: Secp256k1Point, - remaining_gas: &mut u64, - ) -> SyscallResult<(U256, U256)>; - - fn secp256r1_new( - &mut self, - x: U256, - y: U256, - remaining_gas: &mut u64, - ) -> SyscallResult>; - - fn secp256r1_add( - &mut self, - p0: Secp256r1Point, - p1: Secp256r1Point, - remaining_gas: &mut u64, - ) -> SyscallResult; - - fn secp256r1_mul( - &mut self, - p: Secp256r1Point, - m: U256, - remaining_gas: &mut u64, - ) -> SyscallResult; - - fn secp256r1_get_point_from_x( - &mut self, - x: U256, - y_parity: bool, - remaining_gas: &mut u64, - ) -> SyscallResult>; - - fn secp256r1_get_xy( - &mut self, - p: Secp256r1Point, - remaining_gas: &mut u64, - ) -> SyscallResult<(U256, U256)>; - - fn sha256_process_block( - &mut self, - prev_state: &mut [u32; 8], - current_block: &[u32; 16], - remaining_gas: &mut u64, - ) -> SyscallResult<()>; - - fn sha512_process_block( - &mut self, - prev_state: [u64; 8], - current_block: [u64; 16], - remaining_gas: &mut u64, - ) -> SyscallResult<[u64; 8]>; - - fn meta_tx_v0( - &mut self, - _address: Felt, - _entry_point_selector: Felt, - _calldata: &[Felt], - _signature: &[Felt], - _remaining_gas: &mut u64, - ) -> SyscallResult> { - unimplemented!(); - } - - fn get_class_hash_at( - &mut self, - _contract_address: Felt, - _remaining_gas: &mut u64, - ) -> SyscallResult { - unimplemented!() - } - - fn cheatcode(&mut self, _selector: Felt, _input: &[Felt]) -> Vec { - unimplemented!() - } -} - -/// A (somewhat) usable implementation of the starknet syscall handler trait. +/// A minimal in-memory implementation of [`StarknetSyscallHandler`] for tests and +/// debug-runner harnesses. Storage / events / execution info are modeled; syscalls +/// that would require contract-class lookups, deployment, cross-call routing, or +/// L1 message dispatch panic via `unimplemented!()`. Tests that need those should +/// drive sierra-emu through a richer handler (e.g. blockifier's +/// `NativeSyscallHandler`). /// -/// Currently gas is not deducted. +/// Gas is not deducted by this stub. #[derive(Debug, PartialEq, Eq, Clone, Serialize)] pub struct StubSyscallHandler { pub storage: BTreeMap<(u32, Felt), Felt>, @@ -305,6 +117,36 @@ impl StarknetSyscallHandler for StubSyscallHandler { Ok(self.execution_info.clone()) } + fn get_execution_info_v3( + &mut self, + _remaining_gas: &mut u64, + ) -> SyscallResult { + // The stub holds an `ExecutionInfoV2`; v3 adds proof_facts which we don't model. + // Mirrors the VM-side soft-fail in eval_get_execution_info_v3. + unimplemented!() + } + + fn get_class_hash_at( + &mut self, + _contract_address: Felt, + _remaining_gas: &mut u64, + ) -> SyscallResult { + // No class-registry lookup -- the stub doesn't track contract classes. + unimplemented!() + } + + fn meta_tx_v0( + &mut self, + _address: Felt, + _entry_point_selector: Felt, + _calldata: &[Felt], + _signature: &[Felt], + _remaining_gas: &mut u64, + ) -> SyscallResult> { + // Meta-tx routing re-enters `call_contract`, which the stub doesn't model. + unimplemented!() + } + fn deploy( &mut self, _class_hash: Felt, @@ -313,10 +155,12 @@ impl StarknetSyscallHandler for StubSyscallHandler { _deploy_from_zero: bool, _remaining_gas: &mut u64, ) -> SyscallResult<(Felt, Vec)> { + // Deployment requires constructor execution, which the stub doesn't model. unimplemented!() } fn replace_class(&mut self, _class_hash: Felt, _remaining_gas: &mut u64) -> SyscallResult<()> { + // Class replacement updates a registry the stub doesn't track. unimplemented!() } @@ -327,6 +171,7 @@ impl StarknetSyscallHandler for StubSyscallHandler { _calldata: &[Felt], _remaining_gas: &mut u64, ) -> SyscallResult> { + // Resolving the target function requires class-hash lookup the stub doesn't model. unimplemented!() } @@ -337,6 +182,7 @@ impl StarknetSyscallHandler for StubSyscallHandler { _calldata: &[Felt], _remaining_gas: &mut u64, ) -> SyscallResult> { + // Cross-contract calls require address -> class-hash -> function resolution. unimplemented!() } @@ -383,6 +229,7 @@ impl StarknetSyscallHandler for StubSyscallHandler { _payload: &[Felt], _remaining_gas: &mut u64, ) -> SyscallResult<()> { + // L1 message queue isn't modeled -- extend ContractLogs if a test needs it. unimplemented!() } @@ -930,16 +777,15 @@ impl StarknetSyscallHandler for StubSyscallHandler { fn sha512_process_block( &mut self, - prev_state: [u64; 8], - current_block: [u64; 16], + prev_state: &mut [u64; 8], + current_block: &[u64; 16], _remaining_gas: &mut u64, - ) -> SyscallResult<[u64; 8]> { - let mut state = prev_state; + ) -> SyscallResult<()> { let data_as_bytes = sha2::digest::generic_array::GenericArray::from_exact_iter( current_block.iter().flat_map(|x| x.to_be_bytes()), ) .unwrap(); - sha2::compress512(&mut state, &[data_as_bytes]); - Ok(state) + sha2::compress512(prev_state, &[data_as_bytes]); + Ok(()) } } diff --git a/debug_utils/sierra-emu/src/starknet/block_info.rs b/debug_utils/sierra-emu/src/starknet/block_info.rs deleted file mode 100644 index 4896acbcc4..0000000000 --- a/debug_utils/sierra-emu/src/starknet/block_info.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::Value; -use serde::Serialize; -use starknet_types_core::felt::Felt; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] -pub struct BlockInfo { - pub block_number: u64, - pub block_timestamp: u64, - pub sequencer_address: Felt, -} - -impl BlockInfo { - pub(crate) fn into_value(self) -> Value { - Value::Struct(vec![ - Value::U64(self.block_number), - Value::U64(self.block_timestamp), - Value::Felt(self.sequencer_address), - ]) - } -} diff --git a/debug_utils/sierra-emu/src/starknet/execution_info.rs b/debug_utils/sierra-emu/src/starknet/execution_info.rs deleted file mode 100644 index aceb072bc4..0000000000 --- a/debug_utils/sierra-emu/src/starknet/execution_info.rs +++ /dev/null @@ -1,25 +0,0 @@ -use super::{BlockInfo, TxInfo}; -use crate::Value; -use cairo_lang_sierra::ids::ConcreteTypeId; -use starknet_types_core::felt::Felt; - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ExecutionInfo { - pub block_info: BlockInfo, - pub tx_info: TxInfo, - pub caller_address: Felt, - pub contract_address: Felt, - pub entry_point_selector: Felt, -} - -impl ExecutionInfo { - pub(crate) fn into_value(self, felt252_ty: ConcreteTypeId) -> Value { - Value::Struct(vec![ - self.block_info.into_value(), - self.tx_info.into_value(felt252_ty), - Value::Felt(self.caller_address), - Value::Felt(self.contract_address), - Value::Felt(self.entry_point_selector), - ]) - } -} diff --git a/debug_utils/sierra-emu/src/starknet/execution_info_v2.rs b/debug_utils/sierra-emu/src/starknet/execution_info_v2.rs deleted file mode 100644 index 0ce8c9f7b7..0000000000 --- a/debug_utils/sierra-emu/src/starknet/execution_info_v2.rs +++ /dev/null @@ -1,30 +0,0 @@ -use super::{BlockInfo, TxV2Info}; -use crate::Value; -use cairo_lang_sierra::ids::ConcreteTypeId; -use serde::Serialize; -use starknet_types_core::felt::Felt; - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] -pub struct ExecutionInfoV2 { - pub block_info: BlockInfo, - pub tx_info: TxV2Info, - pub caller_address: Felt, - pub contract_address: Felt, - pub entry_point_selector: Felt, -} - -impl ExecutionInfoV2 { - pub(crate) fn into_value( - self, - felt252_ty: ConcreteTypeId, - resource_bounds_ty: ConcreteTypeId, - ) -> Value { - Value::Struct(vec![ - self.block_info.into_value(), - self.tx_info.into_value(felt252_ty, resource_bounds_ty), - Value::Felt(self.caller_address), - Value::Felt(self.contract_address), - Value::Felt(self.entry_point_selector), - ]) - } -} diff --git a/debug_utils/sierra-emu/src/starknet/execution_info_v3.rs b/debug_utils/sierra-emu/src/starknet/execution_info_v3.rs deleted file mode 100644 index 01a2f798bc..0000000000 --- a/debug_utils/sierra-emu/src/starknet/execution_info_v3.rs +++ /dev/null @@ -1,12 +0,0 @@ -use super::{BlockInfo, TxV3Info}; -use serde::Serialize; -use starknet_types_core::felt::Felt; - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] -pub struct ExecutionInfoV3 { - pub block_info: BlockInfo, - pub tx_info: TxV3Info, - pub caller_address: Felt, - pub contract_address: Felt, - pub entry_point_selector: Felt, -} diff --git a/debug_utils/sierra-emu/src/starknet/resource_bounds.rs b/debug_utils/sierra-emu/src/starknet/resource_bounds.rs deleted file mode 100644 index c9a17cc97e..0000000000 --- a/debug_utils/sierra-emu/src/starknet/resource_bounds.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::Value; -use serde::Serialize; -use starknet_types_core::felt::Felt; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] -pub struct ResourceBounds { - pub resource: Felt, - pub max_amount: u64, - pub max_price_per_unit: u128, -} - -impl ResourceBounds { - pub(crate) fn into_value(self) -> Value { - Value::Struct(vec![ - Value::Felt(self.resource), - Value::U64(self.max_amount), - Value::U128(self.max_price_per_unit), - ]) - } -} diff --git a/debug_utils/sierra-emu/src/starknet/secp256k1_point.rs b/debug_utils/sierra-emu/src/starknet/secp256k1_point.rs deleted file mode 100644 index cee80a608a..0000000000 --- a/debug_utils/sierra-emu/src/starknet/secp256k1_point.rs +++ /dev/null @@ -1,39 +0,0 @@ -use super::U256; -use crate::Value; - -#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] -pub struct Secp256k1Point { - pub x: U256, - pub y: U256, - pub is_infinity: bool, -} - -impl Secp256k1Point { - #[allow(unused)] - pub fn into_value(self) -> Value { - // Sierra has no slot for `is_infinity`; encode the identity element as the - // canonical (0, 0) sentinel so `from_value` can recover the flag losslessly. - // (0, 0) is not on the curve, so this aliasing is unambiguous. - let (x, y) = if self.is_infinity { - (U256 { lo: 0, hi: 0 }, U256 { lo: 0, hi: 0 }) - } else { - (self.x, self.y) - }; - Value::Struct(vec![ - Value::Struct(vec![Value::U128(x.lo), Value::U128(x.hi)]), - Value::Struct(vec![Value::U128(y.lo), Value::U128(y.hi)]), - ]) - } - - pub fn from_value(v: Value) -> Self { - let Value::Struct(mut v) = v else { panic!() }; - - let y = U256::from_value(v.remove(1)); - let x = U256::from_value(v.remove(0)); - - // Recover the flag from the (0, 0) sentinel — see `into_value`. - let is_infinity = x.lo == 0 && x.hi == 0 && y.lo == 0 && y.hi == 0; - - Self { x, y, is_infinity } - } -} diff --git a/debug_utils/sierra-emu/src/starknet/secp256r1_point.rs b/debug_utils/sierra-emu/src/starknet/secp256r1_point.rs deleted file mode 100644 index 770a8763d0..0000000000 --- a/debug_utils/sierra-emu/src/starknet/secp256r1_point.rs +++ /dev/null @@ -1,39 +0,0 @@ -use super::U256; -use crate::Value; - -#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] -pub struct Secp256r1Point { - pub x: U256, - pub y: U256, - pub is_infinity: bool, -} - -impl Secp256r1Point { - #[allow(unused)] - pub fn into_value(self) -> Value { - // Sierra has no slot for `is_infinity`; encode the identity element as the - // canonical (0, 0) sentinel so `from_value` can recover the flag losslessly. - // (0, 0) is not on the curve, so this aliasing is unambiguous. - let (x, y) = if self.is_infinity { - (U256 { lo: 0, hi: 0 }, U256 { lo: 0, hi: 0 }) - } else { - (self.x, self.y) - }; - Value::Struct(vec![ - Value::Struct(vec![Value::U128(x.lo), Value::U128(x.hi)]), - Value::Struct(vec![Value::U128(y.lo), Value::U128(y.hi)]), - ]) - } - - pub fn from_value(v: Value) -> Self { - let Value::Struct(mut v) = v else { panic!() }; - - let y = U256::from_value(v.remove(1)); - let x = U256::from_value(v.remove(0)); - - // Recover the flag from the (0, 0) sentinel — see `into_value`. - let is_infinity = x.lo == 0 && x.hi == 0 && y.lo == 0 && y.hi == 0; - - Self { x, y, is_infinity } - } -} diff --git a/debug_utils/sierra-emu/src/starknet/tx_info.rs b/debug_utils/sierra-emu/src/starknet/tx_info.rs deleted file mode 100644 index ac9206d821..0000000000 --- a/debug_utils/sierra-emu/src/starknet/tx_info.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::Value; -use cairo_lang_sierra::ids::ConcreteTypeId; -use starknet_types_core::felt::Felt; - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct TxInfo { - pub version: Felt, - pub account_contract_address: Felt, - pub max_fee: u128, - pub signature: Vec, - pub transaction_hash: Felt, - pub chain_id: Felt, - pub nonce: Felt, -} - -impl TxInfo { - pub(crate) fn into_value(self, felt252_ty: ConcreteTypeId) -> Value { - Value::Struct(vec![ - Value::Felt(self.version), - Value::Felt(self.account_contract_address), - Value::U128(self.max_fee), - Value::Struct(vec![Value::Array { - ty: felt252_ty, - data: self.signature.into_iter().map(Value::Felt).collect(), - }]), - Value::Felt(self.transaction_hash), - Value::Felt(self.chain_id), - Value::Felt(self.nonce), - ]) - } -} diff --git a/debug_utils/sierra-emu/src/starknet/tx_v2_info.rs b/debug_utils/sierra-emu/src/starknet/tx_v2_info.rs deleted file mode 100644 index 77083dec76..0000000000 --- a/debug_utils/sierra-emu/src/starknet/tx_v2_info.rs +++ /dev/null @@ -1,66 +0,0 @@ -use super::ResourceBounds; -use crate::Value; -use cairo_lang_sierra::ids::ConcreteTypeId; -use serde::Serialize; -use starknet_types_core::felt::Felt; - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] -pub struct TxV2Info { - pub version: Felt, - pub account_contract_address: Felt, - pub max_fee: u128, - pub signature: Vec, - pub transaction_hash: Felt, - pub chain_id: Felt, - pub nonce: Felt, - pub resource_bounds: Vec, - pub tip: u128, - pub paymaster_data: Vec, - pub nonce_data_availability_mode: u32, - pub fee_data_availability_mode: u32, - pub account_deployment_data: Vec, -} - -impl TxV2Info { - pub(crate) fn into_value( - self, - felt252_ty: ConcreteTypeId, - resource_bounds_ty: ConcreteTypeId, - ) -> Value { - Value::Struct(vec![ - Value::Felt(self.version), - Value::Felt(self.account_contract_address), - Value::U128(self.max_fee), - Value::Struct(vec![Value::Array { - ty: felt252_ty.clone(), - data: self.signature.into_iter().map(Value::Felt).collect(), - }]), - Value::Felt(self.transaction_hash), - Value::Felt(self.chain_id), - Value::Felt(self.nonce), - Value::Struct(vec![Value::Array { - ty: resource_bounds_ty, - data: self - .resource_bounds - .into_iter() - .map(ResourceBounds::into_value) - .collect(), - }]), - Value::U128(self.tip), - Value::Struct(vec![Value::Array { - ty: felt252_ty.clone(), - data: self.paymaster_data.into_iter().map(Value::Felt).collect(), - }]), - Value::U32(self.nonce_data_availability_mode), - Value::U32(self.fee_data_availability_mode), - Value::Struct(vec![Value::Array { - ty: felt252_ty, - data: self - .account_deployment_data - .into_iter() - .map(Value::Felt) - .collect(), - }]), - ]) - } -} diff --git a/debug_utils/sierra-emu/src/starknet/tx_v3_info.rs b/debug_utils/sierra-emu/src/starknet/tx_v3_info.rs deleted file mode 100644 index 25431ef518..0000000000 --- a/debug_utils/sierra-emu/src/starknet/tx_v3_info.rs +++ /dev/null @@ -1,21 +0,0 @@ -use super::ResourceBounds; -use serde::Serialize; -use starknet_types_core::felt::Felt; - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] -pub struct TxV3Info { - pub version: Felt, - pub account_contract_address: Felt, - pub max_fee: u128, - pub signature: Vec, - pub transaction_hash: Felt, - pub chain_id: Felt, - pub nonce: Felt, - pub resource_bounds: Vec, - pub tip: u128, - pub paymaster_data: Vec, - pub nonce_data_availability_mode: u32, - pub fee_data_availability_mode: u32, - pub account_deployment_data: Vec, - pub proof_facts: Vec, -} diff --git a/debug_utils/sierra-emu/src/starknet/u256.rs b/debug_utils/sierra-emu/src/starknet/u256.rs deleted file mode 100644 index 43b68030ce..0000000000 --- a/debug_utils/sierra-emu/src/starknet/u256.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::Value; - -#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct U256 { - pub lo: u128, - pub hi: u128, -} - -impl U256 { - #[allow(unused)] - pub(crate) fn into_value(self) -> Value { - Value::Struct(vec![Value::U128(self.lo), Value::U128(self.hi)]) - } - - pub fn from_value(v: Value) -> Self { - let Value::Struct(v) = v else { panic!() }; - let Value::U128(lo) = v[0] else { panic!() }; - let Value::U128(hi) = v[1] else { panic!() }; - - Self { lo, hi } - } -} diff --git a/debug_utils/sierra-emu/src/starknet/value_conv.rs b/debug_utils/sierra-emu/src/starknet/value_conv.rs new file mode 100644 index 0000000000..87d4339814 --- /dev/null +++ b/debug_utils/sierra-emu/src/starknet/value_conv.rs @@ -0,0 +1,206 @@ +//! Conversions between sierra-emu's `Value` representation and the syscall +//! types exported from `cairo-starknet-syscalls`. +//! +//! These helpers translate between the explicit Rust structs used by the syscall +//! handler trait (e.g. [`U256`], [`Secp256k1Point`], [`ExecutionInfoV2`]) and the +//! generic [`Value`] tree the sierra-emu VM stores variables in. Each +//! `*_into_value` lowers a struct to the Sierra wire shape; each `*_from_value` +//! inverts the lowering. +//! +//! The conversions are intentionally manual (rather than a generic derive) so the +//! field order and Sierra-level encoding remain explicit at call sites -- the +//! Sierra ABI is the source of truth here, not the Rust struct layout. + +use cairo_lang_sierra::ids::ConcreteTypeId; +use cairo_starknet_syscalls::{ + BlockInfo, ExecutionInfo, ExecutionInfoV2, ResourceBounds, Secp256k1Point, Secp256r1Point, + TxInfo, TxV2Info, U256, +}; + +use crate::Value; + +/// Encode a [`U256`] as the Sierra-level `(lo: u128, hi: u128)` struct value. +pub fn u256_into_value(x: U256) -> Value { + Value::Struct(vec![Value::U128(x.lo), Value::U128(x.hi)]) +} + +/// Decode a Sierra-level `(lo: u128, hi: u128)` struct value as a [`U256`]. +/// +/// Panics on a malformed `Value` -- the VM only produces these via the secp256 +/// libfunc evaluators, which always emit the right shape. +pub fn u256_from_value(v: Value) -> U256 { + let Value::Struct(v) = v else { panic!() }; + let Value::U128(lo) = v[0] else { panic!() }; + let Value::U128(hi) = v[1] else { panic!() }; + U256 { lo, hi } +} + +/// Encode a [`Secp256k1Point`] as the Sierra-level `(x: U256, y: U256)` pair. +/// +/// Sierra has no slot for `is_infinity`; the identity element is encoded as the +/// canonical `(0, 0)` sentinel so [`secp256k1_point_from_value`] can recover the +/// flag losslessly. `(0, 0)` is not on the secp256k1 curve, so this aliasing is +/// unambiguous. +pub fn secp256k1_point_into_value(p: Secp256k1Point) -> Value { + let (x, y) = if p.is_infinity { + (U256 { lo: 0, hi: 0 }, U256 { lo: 0, hi: 0 }) + } else { + (p.x, p.y) + }; + Value::Struct(vec![ + Value::Struct(vec![Value::U128(x.lo), Value::U128(x.hi)]), + Value::Struct(vec![Value::U128(y.lo), Value::U128(y.hi)]), + ]) +} + +/// Decode a Sierra-level `(x: U256, y: U256)` pair as a [`Secp256k1Point`]. +/// +/// Recovers `is_infinity` from the `(0, 0)` sentinel -- see +/// [`secp256k1_point_into_value`]. +pub fn secp256k1_point_from_value(v: Value) -> Secp256k1Point { + let Value::Struct(mut v) = v else { panic!() }; + let y = u256_from_value(v.remove(1)); + let x = u256_from_value(v.remove(0)); + let is_infinity = x.lo == 0 && x.hi == 0 && y.lo == 0 && y.hi == 0; + Secp256k1Point { x, y, is_infinity } +} + +/// Encode a [`Secp256r1Point`] as the Sierra-level `(x: U256, y: U256)` pair. +/// Identity-element handling mirrors [`secp256k1_point_into_value`]. +pub fn secp256r1_point_into_value(p: Secp256r1Point) -> Value { + let (x, y) = if p.is_infinity { + (U256 { lo: 0, hi: 0 }, U256 { lo: 0, hi: 0 }) + } else { + (p.x, p.y) + }; + Value::Struct(vec![ + Value::Struct(vec![Value::U128(x.lo), Value::U128(x.hi)]), + Value::Struct(vec![Value::U128(y.lo), Value::U128(y.hi)]), + ]) +} + +/// Decode a Sierra-level `(x: U256, y: U256)` pair as a [`Secp256r1Point`]. +/// `is_infinity` recovery mirrors [`secp256k1_point_from_value`]. +pub fn secp256r1_point_from_value(v: Value) -> Secp256r1Point { + let Value::Struct(mut v) = v else { panic!() }; + let y = u256_from_value(v.remove(1)); + let x = u256_from_value(v.remove(0)); + let is_infinity = x.lo == 0 && x.hi == 0 && y.lo == 0 && y.hi == 0; + Secp256r1Point { x, y, is_infinity } +} + +/// Encode a [`BlockInfo`] as the Sierra-level +/// `(block_number: u64, block_timestamp: u64, sequencer_address: felt252)` struct. +pub fn block_info_into_value(b: BlockInfo) -> Value { + Value::Struct(vec![ + Value::U64(b.block_number), + Value::U64(b.block_timestamp), + Value::Felt(b.sequencer_address), + ]) +} + +/// Encode a [`ResourceBounds`] as the Sierra-level +/// `(resource: felt252, max_amount: u64, max_price_per_unit: u128)` struct. +pub fn resource_bounds_into_value(r: ResourceBounds) -> Value { + Value::Struct(vec![ + Value::Felt(r.resource), + Value::U64(r.max_amount), + Value::U128(r.max_price_per_unit), + ]) +} + +/// Encode a [`TxInfo`] (the v1 transaction info) as its Sierra-level struct. +/// +/// `felt252_ty` is the concrete type id used for the inner `Array` +/// holding the signature. +pub fn tx_info_into_value(info: TxInfo, felt252_ty: ConcreteTypeId) -> Value { + Value::Struct(vec![ + Value::Felt(info.version), + Value::Felt(info.account_contract_address), + Value::U128(info.max_fee), + Value::Struct(vec![Value::Array { + ty: felt252_ty, + data: info.signature.into_iter().map(Value::Felt).collect(), + }]), + Value::Felt(info.transaction_hash), + Value::Felt(info.chain_id), + Value::Felt(info.nonce), + ]) +} + +/// Encode a [`TxV2Info`] (the v2 transaction info, including resource bounds and +/// paymaster data) as its Sierra-level struct. +/// +/// `felt252_ty` is the concrete type id for `Array` (used by signature, +/// paymaster_data, account_deployment_data). `resource_bounds_ty` is the type id +/// for `Array`. Both must be looked up from the Sierra program's +/// registry by the caller. +pub fn tx_v2_info_into_value( + info: TxV2Info, + felt252_ty: ConcreteTypeId, + resource_bounds_ty: ConcreteTypeId, +) -> Value { + Value::Struct(vec![ + Value::Felt(info.version), + Value::Felt(info.account_contract_address), + Value::U128(info.max_fee), + Value::Struct(vec![Value::Array { + ty: felt252_ty.clone(), + data: info.signature.into_iter().map(Value::Felt).collect(), + }]), + Value::Felt(info.transaction_hash), + Value::Felt(info.chain_id), + Value::Felt(info.nonce), + Value::Struct(vec![Value::Array { + ty: resource_bounds_ty, + data: info + .resource_bounds + .into_iter() + .map(resource_bounds_into_value) + .collect(), + }]), + Value::U128(info.tip), + Value::Struct(vec![Value::Array { + ty: felt252_ty.clone(), + data: info.paymaster_data.into_iter().map(Value::Felt).collect(), + }]), + Value::U32(info.nonce_data_availability_mode), + Value::U32(info.fee_data_availability_mode), + Value::Struct(vec![Value::Array { + ty: felt252_ty, + data: info + .account_deployment_data + .into_iter() + .map(Value::Felt) + .collect(), + }]), + ]) +} + +/// Encode an [`ExecutionInfo`] (the v1 execution info) as its Sierra-level struct. +/// See [`tx_info_into_value`] for the `felt252_ty` parameter. +pub fn execution_info_into_value(info: ExecutionInfo, felt252_ty: ConcreteTypeId) -> Value { + Value::Struct(vec![ + block_info_into_value(info.block_info), + tx_info_into_value(info.tx_info, felt252_ty), + Value::Felt(info.caller_address), + Value::Felt(info.contract_address), + Value::Felt(info.entry_point_selector), + ]) +} + +/// Encode an [`ExecutionInfoV2`] as its Sierra-level struct. +/// See [`tx_v2_info_into_value`] for the type-id parameters. +pub fn execution_info_v2_into_value( + info: ExecutionInfoV2, + felt252_ty: ConcreteTypeId, + resource_bounds_ty: ConcreteTypeId, +) -> Value { + Value::Struct(vec![ + block_info_into_value(info.block_info), + tx_v2_info_into_value(info.tx_info, felt252_ty, resource_bounds_ty), + Value::Felt(info.caller_address), + Value::Felt(info.contract_address), + Value::Felt(info.entry_point_selector), + ]) +} diff --git a/debug_utils/sierra-emu/src/vm/starknet.rs b/debug_utils/sierra-emu/src/vm/starknet.rs index 058f487106..8c9a883490 100644 --- a/debug_utils/sierra-emu/src/vm/starknet.rs +++ b/debug_utils/sierra-emu/src/vm/starknet.rs @@ -1,6 +1,13 @@ use super::EvalAction; use crate::{ - starknet::{Secp256k1Point, Secp256r1Point, StarknetSyscallHandler, U256}, + starknet::{ + value_conv::{ + execution_info_into_value, execution_info_v2_into_value, secp256k1_point_from_value, + secp256k1_point_into_value, secp256r1_point_from_value, secp256r1_point_into_value, + u256_from_value, u256_into_value, + }, + StarknetSyscallHandler, U256, + }, Value, }; use cairo_lang_sierra::{ @@ -203,10 +210,10 @@ fn eval_secp256_new( let syscall_result = match secp_type { SecpPointType::K1 => syscall_handler .secp256k1_new(x, y, &mut gas) - .map(|res| res.map(|op| op.into_value())), + .map(|res| res.map(secp256k1_point_into_value)), SecpPointType::R1 => syscall_handler .secp256r1_new(x, y, &mut gas) - .map(|res| res.map(|op| op.into_value())), + .map(|res| res.map(secp256r1_point_into_value)), }; match syscall_result { @@ -269,20 +276,20 @@ fn eval_secp256_add( let syscall_result = match secp_type { SecpPointType::K1 => { - let x = Secp256k1Point::from_value(x); - let y = Secp256k1Point::from_value(y); + let x = secp256k1_point_from_value(x); + let y = secp256k1_point_from_value(y); syscall_handler .secp256k1_add(x, y, &mut gas) - .map(|res| res.into_value()) + .map(secp256k1_point_into_value) } SecpPointType::R1 => { - let x = Secp256r1Point::from_value(x); - let y = Secp256r1Point::from_value(y); + let x = secp256r1_point_from_value(x); + let y = secp256r1_point_from_value(y); syscall_handler .secp256r1_add(x, y, &mut gas) - .map(|res| res.into_value()) + .map(secp256r1_point_into_value) } }; @@ -307,22 +314,22 @@ fn eval_secp256_mul( panic!() }; - let n = U256::from_value(n); + let n = u256_from_value(n); let syscall_result = match secp_type { SecpPointType::K1 => { - let x = Secp256k1Point::from_value(x); + let x = secp256k1_point_from_value(x); syscall_handler .secp256k1_mul(x, n, &mut gas) - .map(|res| res.into_value()) + .map(secp256k1_point_into_value) } SecpPointType::R1 => { - let x = Secp256r1Point::from_value(x); + let x = secp256r1_point_from_value(x); syscall_handler .secp256r1_mul(x, n, &mut gas) - .map(|res| res.into_value()) + .map(secp256r1_point_into_value) } }; @@ -357,10 +364,10 @@ fn eval_secp256_get_point_from_x( let syscall_result = match secp_type { SecpPointType::K1 => syscall_handler .secp256k1_get_point_from_x(x, y_parity, &mut gas) - .map(|res| res.map(|op| op.into_value())), + .map(|res| res.map(secp256k1_point_into_value)), SecpPointType::R1 => syscall_handler .secp256r1_get_point_from_x(x, y_parity, &mut gas) - .map(|res| res.map(|op| op.into_value())), + .map(|res| res.map(secp256r1_point_into_value)), }; match syscall_result { @@ -425,14 +432,14 @@ fn eval_secp256_get_xy( let syscall_result = match secp_type { SecpPointType::K1 => { - let secp_value = Secp256k1Point::from_value(secp_value); + let secp_value = secp256k1_point_from_value(secp_value); syscall_handler .secp256k1_get_xy(secp_value, &mut gas) .map(|res| (res.0, res.1)) } SecpPointType::R1 => { - let secp_value = Secp256r1Point::from_value(secp_value); + let secp_value = secp256r1_point_from_value(secp_value); syscall_handler .secp256r1_get_xy(secp_value, &mut gas) @@ -442,7 +449,7 @@ fn eval_secp256_get_xy( match syscall_result { Ok(payload) => { - let (x, y) = (payload.0.into_value(), payload.1.into_value()); + let (x, y) = (u256_into_value(payload.0), u256_into_value(payload.1)); EvalAction::NormalBranch(0, smallvec![Value::U64(gas), system, x, y]) } Err(payload) => { @@ -903,7 +910,11 @@ fn eval_get_execution_info( match result { Ok(res) => EvalAction::NormalBranch( 0, - smallvec![Value::U64(gas), system, res.into_value(felt_ty)], + smallvec![ + Value::U64(gas), + system, + execution_info_into_value(res, felt_ty) + ], ), Err(e) => EvalAction::NormalBranch( 1, @@ -984,7 +995,7 @@ fn eval_get_execution_info_v2( smallvec![ Value::U64(gas), system, - res.into_value(felt_ty, out_ty_id.clone()) + execution_info_v2_into_value(res, felt_ty, out_ty_id.clone()) ], ), Err(e) => EvalAction::NormalBranch( @@ -1121,7 +1132,7 @@ fn eval_keccak( match result { Ok(res) => { - EvalAction::NormalBranch(0, smallvec![Value::U64(gas), system, res.into_value()]) + EvalAction::NormalBranch(0, smallvec![Value::U64(gas), system, u256_into_value(res)]) } Err(e) => EvalAction::NormalBranch( 1, @@ -1420,7 +1431,7 @@ fn eval_sha512_process_block( panic!() }; - let prev_state: [u64; 8] = prev_state + let mut prev_state: [u64; 8] = prev_state .into_iter() .map(|v| { let Value::U64(v) = v else { panic!() }; @@ -1450,9 +1461,9 @@ fn eval_sha512_process_block( } }; - match syscall_handler.sha512_process_block(prev_state, current_block, &mut gas) { - Ok(payload) => { - let payload = payload.into_iter().map(Value::U64).collect::>(); + match syscall_handler.sha512_process_block(&mut prev_state, ¤t_block, &mut gas) { + Ok(()) => { + let payload = prev_state.into_iter().map(Value::U64).collect::>(); EvalAction::NormalBranch( 0, smallvec![Value::U64(gas), system, Value::Struct(payload)], diff --git a/src/metadata/trace_dump.rs b/src/metadata/trace_dump.rs index b7b3104ba8..e05e6aa2a8 100644 --- a/src/metadata/trace_dump.rs +++ b/src/metadata/trace_dump.rs @@ -210,6 +210,7 @@ pub mod trace_dump_runtime { use num_traits::One; use sierra_emu::{ starknet::{ + value_conv::{secp256k1_point_into_value, secp256r1_point_into_value}, Secp256k1Point as EmuSecp256k1Point, Secp256r1Point as EmuSecp256r1Point, U256 as EmuU256, }, @@ -775,7 +776,7 @@ pub mod trace_dump_runtime { }, is_infinity: point.is_infinity, }; - emu_point.into_value() + secp256k1_point_into_value(emu_point) } Secp256PointTypeConcrete::R1(_) => { let point: Secp256Point = value_ptr.cast().read(); @@ -790,7 +791,7 @@ pub mod trace_dump_runtime { }, is_infinity: point.is_infinity, }; - emu_point.into_value() + secp256r1_point_into_value(emu_point) } }, StarknetTypeConcrete::Sha256StateHandle(_) => { diff --git a/src/starknet.rs b/src/starknet.rs index 5a394f67d2..0a6051195f 100644 --- a/src/starknet.rs +++ b/src/starknet.rs @@ -1,9 +1,11 @@ //! Starknet related code for `cairo_native` -use serde::{Deserialize, Serialize}; use starknet_types_core::felt::Felt; -pub type SyscallResult = std::result::Result>; +pub use cairo_starknet_syscalls::{ + BlockInfo, ExecutionInfo, ExecutionInfoV2, ExecutionInfoV3, ResourceBounds, Secp256k1Point, + Secp256r1Point, StarknetSyscallHandler, SyscallResult, TxInfo, TxV2Info, TxV3Info, U256, +}; #[repr(C)] #[derive(Debug)] @@ -52,380 +54,6 @@ impl From<&Felt252Abi> for Felt { } } -/// Binary representation of a `u256` (in MLIR). -#[derive( - Debug, - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - serde::Serialize, - serde::Deserialize, - Default, -)] -#[repr(C, align(16))] -pub struct U256 { - pub lo: u128, - pub hi: u128, -} - -#[derive( - Debug, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Default, - serde::Serialize, - serde::Deserialize, -)] -pub struct ExecutionInfo { - pub block_info: BlockInfo, - pub tx_info: TxInfo, - pub caller_address: Felt, - pub contract_address: Felt, - pub entry_point_selector: Felt, -} - -#[derive( - Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, -)] -pub struct ExecutionInfoV2 { - pub block_info: BlockInfo, - pub tx_info: TxV2Info, - pub caller_address: Felt, - pub contract_address: Felt, - pub entry_point_selector: Felt, -} - -#[derive( - Debug, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Default, - serde::Serialize, - serde::Deserialize, -)] -pub struct TxV2Info { - pub version: Felt, - pub account_contract_address: Felt, - pub max_fee: u128, - pub signature: Vec, - pub transaction_hash: Felt, - pub chain_id: Felt, - pub nonce: Felt, - pub resource_bounds: Vec, - pub tip: u128, - pub paymaster_data: Vec, - pub nonce_data_availability_mode: u32, - pub fee_data_availability_mode: u32, - pub account_deployment_data: Vec, -} - -#[derive( - Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, -)] -pub struct ExecutionInfoV3 { - pub block_info: BlockInfo, - pub tx_info: TxV3Info, - pub caller_address: Felt, - pub contract_address: Felt, - pub entry_point_selector: Felt, -} - -#[derive( - Debug, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - serde::Serialize, - serde::Deserialize, - Default, -)] -pub struct TxV3Info { - pub version: Felt, - pub account_contract_address: Felt, - pub max_fee: u128, - pub signature: Vec, - pub transaction_hash: Felt, - pub chain_id: Felt, - pub nonce: Felt, - pub resource_bounds: Vec, - pub tip: u128, - pub paymaster_data: Vec, - pub nonce_data_availability_mode: u32, - pub fee_data_availability_mode: u32, - pub account_deployment_data: Vec, - pub proof_facts: Vec, -} - -#[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, -)] -pub struct ResourceBounds { - pub resource: Felt, - pub max_amount: u64, - pub max_price_per_unit: u128, -} - -#[derive( - Debug, - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Default, - serde::Serialize, - serde::Deserialize, -)] -pub struct BlockInfo { - pub block_number: u64, - pub block_timestamp: u64, - pub sequencer_address: Felt, -} - -#[derive( - Debug, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Default, - serde::Serialize, - serde::Deserialize, -)] -pub struct TxInfo { - pub version: Felt, - pub account_contract_address: Felt, - pub max_fee: u128, - pub signature: Vec, - pub transaction_hash: Felt, - pub chain_id: Felt, - pub nonce: Felt, -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Deserialize, Serialize, Default)] -#[repr(C, align(16))] -pub struct Secp256k1Point { - pub x: U256, - pub y: U256, - pub is_infinity: bool, -} - -impl Secp256k1Point { - pub const fn new(x_lo: u128, x_hi: u128, y_lo: u128, y_hi: u128, is_infinity: bool) -> Self { - Self { - x: U256 { lo: x_lo, hi: x_hi }, - y: U256 { lo: y_lo, hi: y_hi }, - is_infinity, - } - } -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Deserialize, Serialize, Default)] -#[repr(C, align(16))] -pub struct Secp256r1Point { - pub x: U256, - pub y: U256, - pub is_infinity: bool, -} - -impl Secp256r1Point { - pub const fn new(x_lo: u128, x_hi: u128, y_lo: u128, y_hi: u128, is_infinity: bool) -> Self { - Self { - x: U256 { lo: x_lo, hi: x_hi }, - y: U256 { lo: y_lo, hi: y_hi }, - is_infinity, - } - } -} - -pub trait StarknetSyscallHandler { - fn get_block_hash(&mut self, block_number: u64, remaining_gas: &mut u64) - -> SyscallResult; - - fn get_execution_info(&mut self, remaining_gas: &mut u64) -> SyscallResult; - - fn get_execution_info_v2(&mut self, remaining_gas: &mut u64) -> SyscallResult; - - fn get_execution_info_v3(&mut self, remaining_gas: &mut u64) -> SyscallResult; - - fn deploy( - &mut self, - class_hash: Felt, - contract_address_salt: Felt, - calldata: &[Felt], - deploy_from_zero: bool, - remaining_gas: &mut u64, - ) -> SyscallResult<(Felt, Vec)>; - fn replace_class(&mut self, class_hash: Felt, remaining_gas: &mut u64) -> SyscallResult<()>; - - fn library_call( - &mut self, - class_hash: Felt, - function_selector: Felt, - calldata: &[Felt], - remaining_gas: &mut u64, - ) -> SyscallResult>; - - fn call_contract( - &mut self, - address: Felt, - entry_point_selector: Felt, - calldata: &[Felt], - remaining_gas: &mut u64, - ) -> SyscallResult>; - - fn storage_read( - &mut self, - address_domain: u32, - address: Felt, - remaining_gas: &mut u64, - ) -> SyscallResult; - - fn storage_write( - &mut self, - address_domain: u32, - address: Felt, - value: Felt, - remaining_gas: &mut u64, - ) -> SyscallResult<()>; - - fn emit_event( - &mut self, - keys: &[Felt], - data: &[Felt], - remaining_gas: &mut u64, - ) -> SyscallResult<()>; - - fn send_message_to_l1( - &mut self, - to_address: Felt, - payload: &[Felt], - remaining_gas: &mut u64, - ) -> SyscallResult<()>; - - fn keccak(&mut self, input: &[u64], remaining_gas: &mut u64) -> SyscallResult; - - fn secp256k1_new( - &mut self, - x: U256, - y: U256, - remaining_gas: &mut u64, - ) -> SyscallResult>; - - fn secp256k1_add( - &mut self, - p0: Secp256k1Point, - p1: Secp256k1Point, - remaining_gas: &mut u64, - ) -> SyscallResult; - - fn secp256k1_mul( - &mut self, - p: Secp256k1Point, - m: U256, - remaining_gas: &mut u64, - ) -> SyscallResult; - - fn secp256k1_get_point_from_x( - &mut self, - x: U256, - y_parity: bool, - remaining_gas: &mut u64, - ) -> SyscallResult>; - - fn secp256k1_get_xy( - &mut self, - p: Secp256k1Point, - remaining_gas: &mut u64, - ) -> SyscallResult<(U256, U256)>; - - fn secp256r1_new( - &mut self, - x: U256, - y: U256, - remaining_gas: &mut u64, - ) -> SyscallResult>; - - fn secp256r1_add( - &mut self, - p0: Secp256r1Point, - p1: Secp256r1Point, - remaining_gas: &mut u64, - ) -> SyscallResult; - - fn secp256r1_mul( - &mut self, - p: Secp256r1Point, - m: U256, - remaining_gas: &mut u64, - ) -> SyscallResult; - - fn secp256r1_get_point_from_x( - &mut self, - x: U256, - y_parity: bool, - remaining_gas: &mut u64, - ) -> SyscallResult>; - - fn secp256r1_get_xy( - &mut self, - p: Secp256r1Point, - remaining_gas: &mut u64, - ) -> SyscallResult<(U256, U256)>; - - fn sha256_process_block( - &mut self, - state: &mut [u32; 8], - block: &[u32; 16], - remaining_gas: &mut u64, - ) -> SyscallResult<()>; - - fn sha512_process_block( - &mut self, - state: &mut [u64; 8], - block: &[u64; 16], - remaining_gas: &mut u64, - ) -> SyscallResult<()>; - - fn get_class_hash_at( - &mut self, - contract_address: Felt, - remaining_gas: &mut u64, - ) -> SyscallResult; - - fn meta_tx_v0( - &mut self, - address: Felt, - entry_point_selector: Felt, - calldata: &[Felt], - signature: &[Felt], - remaining_gas: &mut u64, - ) -> SyscallResult>; - - fn cheatcode(&mut self, _selector: Felt, _input: &[Felt]) -> Vec { - unimplemented!(); - } -} - pub struct DummySyscallHandler; impl StarknetSyscallHandler for DummySyscallHandler {