diff --git a/crates/starknet-os/src/cairo_types/syscalls.rs b/crates/starknet-os/src/cairo_types/syscalls.rs index 7724c117a..7327c3cd2 100644 --- a/crates/starknet-os/src/cairo_types/syscalls.rs +++ b/crates/starknet-os/src/cairo_types/syscalls.rs @@ -289,3 +289,32 @@ pub struct GetTxSignature { #[allow(unused)] pub response: GetTxSignatureResponse, } + +#[allow(unused)] +#[derive(FieldOffsetGetters)] +pub struct SecpNewResponse { + #[allow(unused)] + pub not_on_curve: Felt252, + #[allow(unused)] + pub ec_point: Relocatable, +} + +#[allow(unused)] +#[derive(FieldOffsetGetters)] +pub struct EcPoint { + #[allow(unused)] + pub d0: Felt252, + #[allow(unused)] + pub d1: Felt252, + #[allow(unused)] + pub d3: Felt252, +} + +#[allow(unused)] +#[derive(FieldOffsetGetters)] +pub struct EcCoordinate { + #[allow(unused)] + pub x: EcPoint, + #[allow(unused)] + pub y: EcPoint, +} diff --git a/crates/starknet-os/src/execution/helper.rs b/crates/starknet-os/src/execution/helper.rs index cb37741db..38a95e01e 100644 --- a/crates/starknet-os/src/execution/helper.rs +++ b/crates/starknet-os/src/execution/helper.rs @@ -1,4 +1,3 @@ -use std::cell::OnceCell; use std::collections::HashMap; use std::ops::Deref; use std::rc::Rc; @@ -7,7 +6,6 @@ use std::vec::IntoIter; use blockifier::context::BlockContext; use blockifier::execution::call_info::CallInfo; use blockifier::execution::entry_point_execution::CallResult; -use blockifier::execution::syscalls::secp::SecpHintProcessor; use blockifier::transaction::objects::TransactionExecutionInfo; use cairo_vm::types::relocatable::Relocatable; use cairo_vm::vm::errors::hint_errors::HintError; @@ -15,6 +13,7 @@ use cairo_vm::Felt252; use starknet_api::deprecated_contract_class::EntryPointType; use tokio::sync::RwLock; +use super::secp_handler::SecpSyscallProcessor; use crate::config::STORED_BLOCK_HASH_BUFFER; use crate::starknet::starknet_storage::{CommitmentInfo, CommitmentInfoError, PerContractStorage}; use crate::storage::storage::StorageError; @@ -56,16 +55,9 @@ where pub storage_by_address: ContractStorageMap, // Secp syscall processors. - pub secp256k1_syscall_processor: SecpSyscallProcessor>, - pub secp256r1_syscall_processor: SecpSyscallProcessor>, + pub secp256k1_syscall_processor: SecpSyscallProcessor, + pub secp256r1_syscall_processor: SecpSyscallProcessor, } - -#[derive(Debug, Default)] -pub struct SecpSyscallProcessor

{ - pub processor: P, - pub segment: OnceCell, -} - /// ExecutionHelper is wrapped in Rc> in order /// to clone the refrence when entering and exiting vm scopes #[derive(Debug)] diff --git a/crates/starknet-os/src/execution/secp_handler.rs b/crates/starknet-os/src/execution/secp_handler.rs index 32d7d5a6a..1d48aadbf 100644 --- a/crates/starknet-os/src/execution/secp_handler.rs +++ b/crates/starknet-os/src/execution/secp_handler.rs @@ -1,3 +1,4 @@ +use std::cell::OnceCell; use std::marker::PhantomData; use ark_ec::short_weierstrass::SWCurveConfig; @@ -9,24 +10,31 @@ use cairo_vm::vm::vm_core::VirtualMachine; use cairo_vm::Felt252; use num_bigint::BigUint; -use super::helper::{ExecutionHelperWrapper, SecpSyscallProcessor}; +use super::helper::ExecutionHelperWrapper; use super::syscall_handler_utils::{ felt_from_ptr, write_maybe_relocatable, SyscallHandler, SyscallResult, WriteResponseResult, }; +use crate::cairo_types::syscalls::EcCoordinate; use crate::execution::helper::ExecutionHelper; use crate::execution::syscall_handler_utils::{write_felt, SyscallExecutionError}; use crate::starknet::starknet_storage::PerContractStorage; +#[derive(Debug, Default)] +pub struct SecpSyscallProcessor { + processor: SecpHintProcessor, + segment: OnceCell, +} + /// This trait is private and not callable outside this module. trait GetSecpSyscallHandler { - fn get_secp_handler(&mut self) -> &mut SecpSyscallProcessor>; + fn get_secp_handler(&mut self) -> &mut SecpSyscallProcessor; } impl GetSecpSyscallHandler for ExecutionHelper where PCS: PerContractStorage, { - fn get_secp_handler(&mut self) -> &mut SecpSyscallProcessor> { + fn get_secp_handler(&mut self) -> &mut SecpSyscallProcessor { &mut self.secp256k1_syscall_processor } } @@ -35,7 +43,7 @@ impl GetSecpSyscallHandler for ExecutionHelper where PCS: PerContractStorage, { - fn get_secp_handler(&mut self) -> &mut SecpSyscallProcessor> { + fn get_secp_handler(&mut self) -> &mut SecpSyscallProcessor { &mut self.secp256r1_syscall_processor } } @@ -92,7 +100,9 @@ where let res = secp_handler.processor.secp_new(request)?; if let Some(ec_point) = res.optional_ec_point_id { let segment = secp_handler.segment.get_or_init(|| vm.add_memory_segment()); - return Ok(SecpOptionalEcPointResponse { optional_ec_point_id: Some((*segment + ec_point * 6)?) }); + return Ok(SecpOptionalEcPointResponse { + optional_ec_point_id: Some((*segment + ec_point * EcCoordinate::cairo_size())?), + }); } Ok(SecpOptionalEcPointResponse { optional_ec_point_id: None }) @@ -155,7 +165,7 @@ where if let Some(ec_point) = res.optional_ec_point_id { let segment = secp_handler.segment.get_or_init(|| vm.add_memory_segment()); return Ok(SecpOptionalEcPointResponse { - optional_ec_point_id: Some((*segment + ec_point * 6)?), // multiply with size of EcPOINT? + optional_ec_point_id: Some((*segment + ec_point * EcCoordinate::cairo_size())?), }); } @@ -188,7 +198,7 @@ pub struct SecpMulRequest { } #[derive(Debug, Eq, PartialEq)] -pub struct SecpOpRespone { +pub struct SecpOpResponse { pub ec_point_id: Relocatable, } @@ -199,7 +209,7 @@ where { type Request = SecpMulRequest; - type Response = SecpOpRespone; + type Response = SecpOpResponse; fn read_request(vm: &VirtualMachine, ptr: &mut Relocatable) -> SyscallResult { let ec_point_id = vm.get_relocatable(*ptr)?; @@ -226,12 +236,12 @@ where let offset = request.ec_point_id; let segment = secp_handler.segment.get().unwrap(); let request = blockifier::execution::syscalls::secp::SecpMulRequest { - ec_point_id: (offset.offset / 6).into(), + ec_point_id: (offset.offset / EcCoordinate::cairo_size()).into(), multiplier: request.multiplier, }; let res = secp_handler.processor.secp_mul(request)?; - Ok(SecpOpRespone { ec_point_id: (*segment + res.ec_point_id * 6)? }) + Ok(SecpOpResponse { ec_point_id: (*segment + res.ec_point_id * EcCoordinate::cairo_size())? }) } fn write_response(response: Self::Response, vm: &mut VirtualMachine, ptr: &mut Relocatable) -> WriteResponseResult { @@ -257,7 +267,7 @@ where { type Request = SecpAddRequest; - type Response = SecpOpRespone; + type Response = SecpOpResponse; fn read_request(vm: &VirtualMachine, ptr: &mut Relocatable) -> SyscallResult { let lhs_id = vm.get_relocatable(*ptr)?; @@ -279,13 +289,13 @@ where let mut eh_ref = exec_wrapper.execution_helper.write().await; let secp_handler = &mut as GetSecpSyscallHandler>::get_secp_handler(&mut eh_ref); let request = blockifier::execution::syscalls::secp::SecpAddRequest { - lhs_id: (request.lhs_id.offset / 6).into(), - rhs_id: (request.rhs_id.offset / 6).into(), + lhs_id: (request.lhs_id.offset / EcCoordinate::cairo_size()).into(), + rhs_id: (request.rhs_id.offset / EcCoordinate::cairo_size()).into(), }; let res = secp_handler.processor.secp_add(request)?; let segment = secp_handler.segment.get().unwrap(); - Ok(SecpOpRespone { ec_point_id: (*segment + res.ec_point_id * 6)? }) + Ok(SecpOpResponse { ec_point_id: (*segment + res.ec_point_id * EcCoordinate::cairo_size())? }) } fn write_response(response: Self::Response, vm: &mut VirtualMachine, ptr: &mut Relocatable) -> WriteResponseResult { @@ -328,9 +338,11 @@ where let mut eh_ref = exec_wrapper.execution_helper.write().await; let secp_handler = &mut as GetSecpSyscallHandler>::get_secp_handler(&mut eh_ref); let offset = request.ec_point_id; - // let segment = secp_handler.segment.get().unwrap(); - let request = - blockifier::execution::syscalls::secp::SecpGetXyRequest { ec_point_id: (offset.offset / 6).into() }; + let _ = secp_handler.segment.get().unwrap(); + let request = blockifier::execution::syscalls::secp::SecpGetXyRequest { + ec_point_id: (offset.offset / EcCoordinate::cairo_size()).into(), + }; + let res = secp_handler.processor.secp_get_xy(request)?; Ok(res) } @@ -360,8 +372,6 @@ mod tests { use num_traits::{FromPrimitive, Num}; use rstest::rstest; - // use super::*; - fn parse_hex(hex_str: &str) -> BigUint { let trimmed_hex_str = hex_str.trim_start_matches("0x"); BigUint::from_str_radix(trimmed_hex_str, 16).unwrap() diff --git a/crates/starknet-os/src/hints/mod.rs b/crates/starknet-os/src/hints/mod.rs index 275ee8683..001e71176 100644 --- a/crates/starknet-os/src/hints/mod.rs +++ b/crates/starknet-os/src/hints/mod.rs @@ -39,6 +39,7 @@ mod execute_transactions; pub mod execution; mod output; mod patricia; +mod secp; pub mod state; pub mod syscalls; #[cfg(test)] @@ -235,7 +236,7 @@ fn hints() -> HashMap where hints.insert(transaction_hash::DATA_TO_HASH_NEW_SEGMENT.into(), transaction_hash::data_to_hash_new_segment); hints.insert(block_context::WRITE_USE_ZKG_DA_TO_MEM.into(), block_context::write_use_zkg_da_to_mem); hints.insert(compiled_class::SET_AP_TO_SEGMENT_HASH.into(), compiled_class::set_ap_to_segment_hash); - + hints.insert(secp::READ_EC_POINT_ADDRESS.into(), secp::read_ec_point_from_address); hints } diff --git a/crates/starknet-os/src/hints/secp.rs b/crates/starknet-os/src/hints/secp.rs new file mode 100644 index 000000000..6d9d7b67a --- /dev/null +++ b/crates/starknet-os/src/hints/secp.rs @@ -0,0 +1,34 @@ +use std::collections::HashMap; + +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_integer_from_var_name, get_ptr_from_var_name, insert_value_into_ap, +}; +use cairo_vm::hint_processor::hint_processor_definition::HintReference; +use cairo_vm::serde::deserialize_program::ApTracking; +use cairo_vm::types::exec_scope::ExecutionScopes; +use cairo_vm::vm::errors::hint_errors::HintError; +use cairo_vm::vm::vm_core::VirtualMachine; +use cairo_vm::Felt252; + +use crate::cairo_types::syscalls::SecpNewResponse; +use crate::hints::vars; + +pub const READ_EC_POINT_ADDRESS: &str = r#"memory[ap] = to_felt_or_relocatable(ids.response.ec_point.address_ if ids.not_on_curve == 0 else segments.add())"#; +pub fn read_ec_point_from_address( + vm: &mut VirtualMachine, + _exec_scopes: &mut ExecutionScopes, + ids_data: &HashMap, + _ap_tracking: &ApTracking, + _constants: &HashMap, +) -> Result<(), HintError> { + let not_on_curve = get_integer_from_var_name(vars::ids::NOT_ON_CURVE, vm, ids_data, _ap_tracking)?; + if not_on_curve == Felt252::ZERO { + let response = get_ptr_from_var_name(vars::ids::RESPONSE, vm, ids_data, _ap_tracking)?; + let ec_point = vm.get_relocatable((response + SecpNewResponse::ec_point_offset())?)?; + insert_value_into_ap(vm, ec_point)?; + } else { + let segment = vm.add_memory_segment(); + insert_value_into_ap(vm, segment)?; + } + Ok(()) +} diff --git a/crates/starknet-os/src/hints/unimplemented.rs b/crates/starknet-os/src/hints/unimplemented.rs index 936b70407..1f7c2351a 100644 --- a/crates/starknet-os/src/hints/unimplemented.rs +++ b/crates/starknet-os/src/hints/unimplemented.rs @@ -1,59 +1,10 @@ use indoc::indoc; -#[allow(unused)] -pub const CALCULATE_VALUE: &str = indoc! {r#" - from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1, pack - from starkware.python.math_utils import y_squared_from_x - - y_square_int = y_squared_from_x( - x=pack(ids.x, SECP256R1.prime), - alpha=SECP256R1.alpha, - beta=SECP256R1.beta, - field_prime=SECP256R1.prime, - ) - - # Note that (y_square_int ** ((SECP256R1.prime + 1) / 4)) ** 2 = - # = y_square_int ** ((SECP256R1.prime + 1) / 2) = - # = y_square_int ** ((SECP256R1.prime - 1) / 2 + 1) = - # = y_square_int * y_square_int ** ((SECP256R1.prime - 1) / 2) = y_square_int * {+/-}1. - y = pow(y_square_int, (SECP256R1.prime + 1) // 4, SECP256R1.prime) - - # We need to decide whether to take y or prime - y. - if ids.v % 2 == y % 2: - value = y - else: - value = (-y) % SECP256R1.prime"# -}; - #[allow(unused)] pub const SET_AP_TO_SEGMENT_HASH: &str = indoc! {r#" memory[ap] = to_felt_or_relocatable(bytecode_segment_structure.hash())"# }; -#[allow(unused)] -pub const COMPUTE_NEW_Y: &str = indoc! {r#" - value = new_y = (slope * (x - new_x) - y) % SECP256R1_P"# -}; - -#[allow(unused)] -pub const COMPUTE_VALUE_DIV_MOD: &str = indoc! {r#" - from starkware.python.math_utils import div_mod - - value = div_mod(1, x, SECP256R1_P)"# -}; - -#[allow(unused)] -pub const COMPUTE_IDS_HIGH_LOW: &str = indoc! {r#" - from starkware.cairo.common.math_utils import as_int - - # Correctness check. - value = as_int(ids.value, PRIME) % PRIME - assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**165).' - - # Calculation for the assertion. - ids.high, ids.low = divmod(ids.value, ids.SHIFT)"# -}; - #[allow(unused)] pub const WRITE_ZKG_COMMITMENT_ADDRESS: &str = indoc! {r#" execution_helper.store_da_segment( @@ -66,81 +17,3 @@ pub const WRITE_ZKG_COMMITMENT_ADDRESS: &str = indoc! {r#" ) )"# }; - -#[allow(unused)] -pub const WRITE_NIBBLES_TO_MEM: &str = indoc! {r#" - memory[fp + 0] = to_felt_or_relocatable(nibbles.pop())"# -}; - -#[allow(unused)] -pub const PACK_X_PRIME: &str = indoc! {r#" - from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P - from starkware.cairo.common.cairo_secp.secp_utils import pack - - x = pack(ids.x, PRIME) % SECP256R1_P"# -}; - -#[allow(unused)] -pub const MAYBE_WRITE_ADDRESS_TO_AP: &str = indoc! {r#" - memory[ap] = to_felt_or_relocatable(ids.response.ec_point.address_ if ids.not_on_curve == 0 else segments.add())"# -}; - -#[allow(unused)] -pub const GENERATE_NIBBLES: &str = indoc! {r#" - num = (ids.scalar.high << 128) + ids.scalar.low - nibbles = [(num >> i) & 0xf for i in range(0, 256, 4)] - ids.first_nibble = nibbles.pop() - ids.last_nibble = nibbles[0]"# -}; - -// TODO: looks nearly identical to crate::IS_ON_CURVE -#[allow(unused)] -pub const IS_ON_CURVE_2: &str = indoc! {r#" - ids.is_on_curve = (y * y) % SECP256R1.prime == y_square_int"# -}; - -// TODO: looks similar to PACK_X_PRIME (above) -#[allow(unused)] -pub const PACK_X_PRIME_2: &str = indoc! {r#" - from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P - from starkware.cairo.common.cairo_secp.secp_utils import pack - value = pack(ids.x, PRIME) % SECP256R1_P"# -}; - -#[allow(unused)] -pub const WRITE_DIVMOD_SEGMENT: &str = indoc! {r#" - from starkware.starknet.core.os.data_availability.bls_utils import BLS_PRIME, pack, split - - a = pack(ids.a, PRIME) - b = pack(ids.b, PRIME) - - q, r = divmod(a * b, BLS_PRIME) - - # By the assumption: |a|, |b| < 2**104 * ((2**86) ** 2 + 2**86 + 1) < 2**276.001. - # Therefore |q| <= |ab| / BLS_PRIME < 2**299. - # Hence the absolute value of the high limb of split(q) < 2**127. - segments.write_arg(ids.q.address_, split(q)) - segments.write_arg(ids.res.address_, split(r))"# -}; - -#[allow(unused)] -pub const CALCULATE_VALUE_2: &str = indoc! {r#" - from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P - from starkware.cairo.common.cairo_secp.secp_utils import pack - - slope = pack(ids.slope, SECP256R1_P) - x = pack(ids.point.x, SECP256R1_P) - y = pack(ids.point.y, SECP256R1_P) - - value = new_x = (pow(slope, 2, SECP256R1_P) - 2 * x) % SECP256R1_P"# -}; - -#[allow(unused)] -pub const COMPUTE_Q_MOD_PRIME: &str = indoc! {r#" - from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P - from starkware.cairo.common.cairo_secp.secp_utils import pack - - q, r = divmod(pack(ids.val, PRIME), SECP256R1_P) - assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." - ids.q = q % PRIME"# -}; diff --git a/crates/starknet-os/src/hints/vars.rs b/crates/starknet-os/src/hints/vars.rs index a8747b8bc..d635d8894 100644 --- a/crates/starknet-os/src/hints/vars.rs +++ b/crates/starknet-os/src/hints/vars.rs @@ -90,6 +90,7 @@ pub mod ids { pub const NEW_ROOT: &str = "new_root"; pub const NEW_STATE_ENTRY: &str = "new_state_entry"; pub const NODE: &str = "node"; + pub const NOT_ON_CURVE: &str = "not_on_curve"; pub const OLD_BLOCK_HASH: &str = "old_block_hash"; pub const OLD_BLOCK_NUMBER: &str = "old_block_number"; pub const OS_CONTEXT: &str = "os_context";