diff --git a/src/debug.rs b/src/debug.rs index 93c0555..8d14588 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,37 +1,44 @@ -use cairo_lang_sierra::extensions::{ - array::ArrayConcreteLibfunc, - boolean::BoolConcreteLibfunc, - bounded_int::BoundedIntConcreteLibfunc, - boxing::BoxConcreteLibfunc, - bytes31::Bytes31ConcreteLibfunc, - casts::CastConcreteLibfunc, - circuit::CircuitConcreteLibfunc, - const_type::ConstConcreteLibfunc, - core::CoreConcreteLibfunc, - coupon::CouponConcreteLibfunc, - debug::DebugConcreteLibfunc, - ec::EcConcreteLibfunc, - enm::EnumConcreteLibfunc, - felt252::{Felt252BinaryOperationConcrete, Felt252BinaryOperator, Felt252Concrete}, - felt252_dict::{Felt252DictConcreteLibfunc, Felt252DictEntryConcreteLibfunc}, - gas::GasConcreteLibfunc, - int::{ - signed::SintConcrete, signed128::Sint128Concrete, unsigned::UintConcrete, - unsigned128::Uint128Concrete, unsigned256::Uint256Concrete, unsigned512::Uint512Concrete, - IntOperator, +use cairo_lang_sierra::{ + extensions::{ + array::ArrayConcreteLibfunc, + boolean::BoolConcreteLibfunc, + bounded_int::BoundedIntConcreteLibfunc, + boxing::BoxConcreteLibfunc, + bytes31::Bytes31ConcreteLibfunc, + casts::CastConcreteLibfunc, + circuit::{CircuitConcreteLibfunc, CircuitTypeConcrete}, + const_type::ConstConcreteLibfunc, + core::{CoreConcreteLibfunc, CoreLibfunc, CoreType, CoreTypeConcrete}, + coupon::CouponConcreteLibfunc, + debug::DebugConcreteLibfunc, + ec::EcConcreteLibfunc, + enm::EnumConcreteLibfunc, + felt252::{Felt252BinaryOperationConcrete, Felt252BinaryOperator, Felt252Concrete}, + felt252_dict::{Felt252DictConcreteLibfunc, Felt252DictEntryConcreteLibfunc}, + gas::GasConcreteLibfunc, + int::{ + signed::SintConcrete, signed128::Sint128Concrete, unsigned::UintConcrete, + unsigned128::Uint128Concrete, unsigned256::Uint256Concrete, + unsigned512::Uint512Concrete, IntOperator, + }, + lib_func::{BranchSignature, ParamSignature}, + mem::MemConcreteLibfunc, + nullable::NullableConcreteLibfunc, + pedersen::PedersenConcreteLibfunc, + poseidon::PoseidonConcreteLibfunc, + starknet::{ + secp256::{Secp256ConcreteLibfunc, Secp256OpConcreteLibfunc}, + testing::TestingConcreteLibfunc, + StarkNetConcreteLibfunc, StarkNetTypeConcrete, + }, + structure::StructConcreteLibfunc, }, - mem::MemConcreteLibfunc, - nullable::NullableConcreteLibfunc, - pedersen::PedersenConcreteLibfunc, - poseidon::PoseidonConcreteLibfunc, - starknet::{ - secp256::{Secp256ConcreteLibfunc, Secp256OpConcreteLibfunc}, - testing::TestingConcreteLibfunc, - StarkNetConcreteLibfunc, - }, - structure::StructConcreteLibfunc, + ids::ConcreteTypeId, + program_registry::ProgramRegistry, }; +use crate::Value; + pub fn libfunc_to_name(value: &CoreConcreteLibfunc) -> &'static str { match value { CoreConcreteLibfunc::ApTracking(value) => match value { @@ -409,3 +416,153 @@ pub fn libfunc_to_name(value: &CoreConcreteLibfunc) -> &'static str { }, } } + +pub fn type_to_name( + ty_id: &ConcreteTypeId, + registry: &ProgramRegistry, +) -> String { + let ty = registry.get_type(ty_id).unwrap(); + match ty { + CoreTypeConcrete::Array(info) => { + format!("Array<{}>", type_to_name(&info.ty, registry)) + } + CoreTypeConcrete::Box(info) => { + format!("Box<{}>", type_to_name(&info.ty, registry)) + } + CoreTypeConcrete::Uninitialized(info) => { + format!("Uninitialized<{}>", type_to_name(&info.ty, registry)) + } + CoreTypeConcrete::NonZero(info) => { + format!("NonZero<{}>", type_to_name(&info.ty, registry)) + } + CoreTypeConcrete::Nullable(info) => { + format!("Nullable<{}>", type_to_name(&info.ty, registry)) + } + CoreTypeConcrete::Span(info) => { + format!("Span<{}>", type_to_name(&info.ty, registry)) + } + CoreTypeConcrete::Snapshot(info) => { + format!("Snapshot<{}>", type_to_name(&info.ty, registry)) + } + CoreTypeConcrete::Struct(info) => { + let fields = info + .members + .iter() + .map(|ty_id| type_to_name(ty_id, registry)) + .collect::>(); + let fields = fields.join(", "); + + format!("Struct<{}>", fields) + } + CoreTypeConcrete::Enum(info) => { + let fields = info + .variants + .iter() + .map(|ty_id| type_to_name(ty_id, registry)) + .collect::>(); + let fields = fields.join(", "); + + format!("Enum<{}>", fields) + } + CoreTypeConcrete::Felt252Dict(_) => String::from("Felt252Dict"), + CoreTypeConcrete::Felt252DictEntry(_) => String::from("Felt252DictEntry"), + CoreTypeConcrete::SquashedFelt252Dict(_) => String::from("SquashedFelt252Dict"), + CoreTypeConcrete::StarkNet(selector) => match selector { + StarkNetTypeConcrete::ClassHash(_) => String::from("Starknet::ClassHash"), + StarkNetTypeConcrete::ContractAddress(_) => String::from("Starknet::ContractAddress"), + StarkNetTypeConcrete::StorageBaseAddress(_) => { + String::from("Starknet::StorageBaseAddress") + } + StarkNetTypeConcrete::StorageAddress(_) => String::from("Starknet::StorageAddress"), + StarkNetTypeConcrete::System(_) => String::from("Starknet::System"), + StarkNetTypeConcrete::Secp256Point(_) => String::from("Starknet::Secp256Point"), + StarkNetTypeConcrete::Sha256StateHandle(_) => { + String::from("Starknet::Sha256StateHandle") + } + }, + + CoreTypeConcrete::Bitwise(_) => String::from("Bitwise"), + CoreTypeConcrete::Circuit(selector) => match selector { + CircuitTypeConcrete::AddMod(_) => String::from("AddMod"), + CircuitTypeConcrete::MulMod(_) => String::from("MulMod"), + CircuitTypeConcrete::AddModGate(_) => String::from("AddModGate"), + CircuitTypeConcrete::Circuit(_) => String::from("Circuit"), + CircuitTypeConcrete::CircuitData(_) => String::from("CircuitData"), + CircuitTypeConcrete::CircuitOutputs(_) => String::from("CircuitOutputs"), + CircuitTypeConcrete::CircuitPartialOutputs(_) => String::from("CircuitPartialOutputs"), + CircuitTypeConcrete::CircuitDescriptor(_) => String::from("CircuitDescriptor"), + CircuitTypeConcrete::CircuitFailureGuarantee(_) => { + String::from("CircuitFailureGuarantee") + } + CircuitTypeConcrete::CircuitInput(_) => String::from("CircuitInput"), + CircuitTypeConcrete::CircuitInputAccumulator(_) => { + String::from("CircuitInputAccumulator") + } + CircuitTypeConcrete::CircuitModulus(_) => String::from("CircuitModulus"), + CircuitTypeConcrete::InverseGate(_) => String::from("InverseGate"), + CircuitTypeConcrete::MulModGate(_) => String::from("MulModGate"), + CircuitTypeConcrete::SubModGate(_) => String::from("SubModGate"), + CircuitTypeConcrete::U96Guarantee(_) => String::from("U96Guarantee"), + CircuitTypeConcrete::U96LimbsLessThanGuarantee(_) => { + String::from("U96LimbsLessThanGuarantee") + } + }, + CoreTypeConcrete::Const(_) => String::from("Const"), + CoreTypeConcrete::Coupon(_) => String::from("Coupon"), + CoreTypeConcrete::EcOp(_) => String::from("EcOp"), + CoreTypeConcrete::EcPoint(_) => String::from("EcPoint"), + CoreTypeConcrete::EcState(_) => String::from("EcState"), + CoreTypeConcrete::Felt252(_) => String::from("Felt252"), + CoreTypeConcrete::GasBuiltin(_) => String::from("GasBuiltin"), + CoreTypeConcrete::BuiltinCosts(_) => String::from("BuiltinCosts"), + CoreTypeConcrete::Uint8(_) => String::from("Uint8"), + CoreTypeConcrete::Uint16(_) => String::from("Uint16"), + CoreTypeConcrete::Uint32(_) => String::from("Uint32"), + CoreTypeConcrete::Uint64(_) => String::from("Uint64"), + CoreTypeConcrete::Uint128(_) => String::from("Uint128"), + CoreTypeConcrete::Uint128MulGuarantee(_) => String::from("Uint128MulGuarantee"), + CoreTypeConcrete::Sint8(_) => String::from("Sint8"), + CoreTypeConcrete::Sint16(_) => String::from("Sint16"), + CoreTypeConcrete::Sint32(_) => String::from("Sint32"), + CoreTypeConcrete::Sint64(_) => String::from("Sint64"), + CoreTypeConcrete::Sint128(_) => String::from("Sint128"), + CoreTypeConcrete::RangeCheck(_) => String::from("RangeCheck"), + CoreTypeConcrete::RangeCheck96(_) => String::from("RangeCheck96"), + CoreTypeConcrete::Pedersen(_) => String::from("Pedersen"), + CoreTypeConcrete::Poseidon(_) => String::from("Poseidon"), + CoreTypeConcrete::SegmentArena(_) => String::from("SegmentArena"), + CoreTypeConcrete::Bytes31(_) => String::from("Bytes31"), + CoreTypeConcrete::BoundedInt(_) => String::from("BoundedInt"), + } +} + +/// prints all the signature information, used while debugging to learn +/// how to implement a certain libfunc. +#[allow(dead_code)] +pub fn debug_signature( + registry: &ProgramRegistry, + params: &[ParamSignature], + branches: &[BranchSignature], + args: &[Value], +) { + println!( + "Params: {:#?}", + params + .iter() + .map(|p| type_to_name(&p.ty, registry)) + .collect::>() + ); + println!( + "Branches: {:#?}", + branches + .iter() + .map(|b| { + b.vars + .iter() + .map(|vars| type_to_name(&vars.ty, registry)) + .collect::>() + }) + .collect::>() + ); + println!("Args: {:#?}", args); +} diff --git a/src/lib.rs b/src/lib.rs index de8ec91..88893fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,9 @@ -use cairo_lang_sierra::program::{GenFunction, Program, StatementIdx}; +use cairo_lang_sierra::{ + extensions::core::{CoreLibfunc, CoreType}, + ids::ConcreteTypeId, + program::{GenFunction, Program, StatementIdx}, + program_registry::ProgramRegistry, +}; pub use self::{dump::*, value::*, vm::VirtualMachine}; @@ -29,3 +34,27 @@ pub fn find_entry_point_by_name<'a>( .iter() .find(|x| x.id.debug_name.as_ref().map(|x| x.as_str()) == Some(name)) } + +// If type is invisible to sierra (i.e. a single element container), +// finds it's actual concrete type recursively. +// If not, returns the current type +pub fn find_real_type( + registry: &ProgramRegistry, + ty: &ConcreteTypeId, +) -> ConcreteTypeId { + match registry.get_type(ty).unwrap() { + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Box(info) => { + find_real_type(registry, &info.ty) + } + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Uninitialized(info) => { + find_real_type(registry, &info.ty) + } + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Span(info) => { + find_real_type(registry, &info.ty) + } + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Snapshot(info) => { + find_real_type(registry, &info.ty) + } + _ => ty.clone(), + } +} diff --git a/src/starknet/secp256k1_point.rs b/src/starknet/secp256k1_point.rs index 4e3a8a8..0c4844b 100644 --- a/src/starknet/secp256k1_point.rs +++ b/src/starknet/secp256k1_point.rs @@ -15,4 +15,13 @@ impl Secp256k1Point { Value::Struct(vec![Value::U128(self.y.lo), Value::U128(self.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)); + + Self { x, y } + } } diff --git a/src/starknet/secp256r1_point.rs b/src/starknet/secp256r1_point.rs index a51ecde..5036f78 100644 --- a/src/starknet/secp256r1_point.rs +++ b/src/starknet/secp256r1_point.rs @@ -15,4 +15,13 @@ impl Secp256r1Point { Value::Struct(vec![Value::U128(self.y.lo), Value::U128(self.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)); + + Self { x, y } + } } diff --git a/src/starknet/u256.rs b/src/starknet/u256.rs index da9c75e..43b6803 100644 --- a/src/starknet/u256.rs +++ b/src/starknet/u256.rs @@ -11,4 +11,12 @@ impl U256 { 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/src/value.rs b/src/value.rs index 6b76db8..c8729e4 100644 --- a/src/value.rs +++ b/src/value.rs @@ -13,6 +13,8 @@ use serde::Serialize; use starknet_types_core::felt::Felt; use std::{collections::HashMap, fmt::Debug, ops::Range}; +use crate::debug::type_to_name; + #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum Value { Array { @@ -128,8 +130,7 @@ impl Value { } CoreTypeConcrete::Uint8(_) => matches!(self, Self::U8(_)), CoreTypeConcrete::Uint32(_) => matches!(self, Self::U32(_)), - CoreTypeConcrete::Uint128(_) - | CoreTypeConcrete::Circuit(CircuitTypeConcrete::U96Guarantee(_)) => { + CoreTypeConcrete::Uint128(_) => { matches!(self, Self::U128(_)) } @@ -137,9 +138,6 @@ impl Value { CoreTypeConcrete::RangeCheck(_) | CoreTypeConcrete::SegmentArena(_) | CoreTypeConcrete::RangeCheck96(_) - | CoreTypeConcrete::Circuit( - CircuitTypeConcrete::AddMod(_) | CircuitTypeConcrete::MulMod(_), - ) | CoreTypeConcrete::StarkNet(StarkNetTypeConcrete::System(_)) => { matches!(self, Self::Unit) } @@ -148,7 +146,29 @@ impl Value { CoreTypeConcrete::Coupon(_) => todo!(), CoreTypeConcrete::Bitwise(_) => matches!(self, Self::Unit), CoreTypeConcrete::Box(info) => self.is(registry, &info.ty), - CoreTypeConcrete::Circuit(_) => todo!(), + + // Circuit related types + CoreTypeConcrete::Circuit(selector) => match selector { + CircuitTypeConcrete::Circuit(_) => matches!(self, Self::Circuit(_)), + CircuitTypeConcrete::CircuitData(_) => matches!(self, Self::Circuit(_)), + CircuitTypeConcrete::CircuitOutputs(_) => matches!(self, Self::CircuitOutputs(_)), + CircuitTypeConcrete::CircuitInput(_) => matches!(self, Self::Unit), + CircuitTypeConcrete::CircuitInputAccumulator(_) => matches!(self, Self::Circuit(_)), + CircuitTypeConcrete::CircuitModulus(_) => matches!(self, Self::CircuitModulus(_)), + CircuitTypeConcrete::U96Guarantee(_) => matches!(self, Self::U128(_)), + CircuitTypeConcrete::CircuitDescriptor(_) + | CircuitTypeConcrete::CircuitFailureGuarantee(_) + | CircuitTypeConcrete::AddMod(_) + | CircuitTypeConcrete::MulMod(_) + | CircuitTypeConcrete::AddModGate(_) + | CircuitTypeConcrete::CircuitPartialOutputs(_) + | CircuitTypeConcrete::InverseGate(_) + | CircuitTypeConcrete::MulModGate(_) + | CircuitTypeConcrete::SubModGate(_) + | CircuitTypeConcrete::U96LimbsLessThanGuarantee(_) => { + matches!(self, Self::Unit) + } + }, CoreTypeConcrete::Const(_) => todo!(), CoreTypeConcrete::EcOp(_) => matches!(self, Self::Unit), CoreTypeConcrete::EcPoint(_) => matches!(self, Self::EcPoint { .. }), @@ -160,7 +180,7 @@ impl Value { CoreTypeConcrete::Sint16(_) => todo!(), CoreTypeConcrete::Sint64(_) => todo!(), CoreTypeConcrete::Nullable(info) => self.is(registry, &info.ty), - CoreTypeConcrete::Uninitialized(_) => todo!(), + CoreTypeConcrete::Uninitialized(_) => matches!(self, Self::Uninitialized { .. }), CoreTypeConcrete::Felt252DictEntry(_) => todo!(), CoreTypeConcrete::SquashedFelt252Dict(_) => todo!(), CoreTypeConcrete::Pedersen(_) => matches!(self, Self::Unit), @@ -172,13 +192,18 @@ impl Value { | StarkNetTypeConcrete::StorageBaseAddress(_) | StarkNetTypeConcrete::StorageAddress(_) => matches!(self, Self::Felt(_)), StarkNetTypeConcrete::System(_) => matches!(self, Self::Unit), - StarkNetTypeConcrete::Secp256Point(_) => todo!(), + StarkNetTypeConcrete::Secp256Point(_) => matches!(self, Self::Struct(_)), StarkNetTypeConcrete::Sha256StateHandle(_) => matches!(self, Self::Struct { .. }), }, }; if !res { - dbg!("value is mismatch", ty.info(), self); + dbg!( + "value is mismatch", + ty.info(), + self, + type_to_name(type_id, registry) + ); } res diff --git a/src/vm.rs b/src/vm.rs index bede656..422ac47 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -10,7 +10,7 @@ use cairo_lang_sierra::{ circuit::CircuitTypeConcrete, core::{CoreConcreteLibfunc, CoreLibfunc, CoreType, CoreTypeConcrete}, starknet::StarkNetTypeConcrete, - ConcreteType, + ConcreteLibfunc, ConcreteType, }, ids::{ConcreteLibfuncId, FunctionId, VarId}, program::{GenFunction, GenStatement, Invocation, Program, StatementIdx}, @@ -221,6 +221,24 @@ impl VirtualMachine { "invocation of {invocation} returned the wrong number of values" ); + assert!( + results + .iter() + .zip( + &self + .registry + .get_libfunc(&invocation.libfunc_id) + .unwrap() + .branch_signatures()[branch_idx] + .vars + ) + .all(|(value, ret)| value.is(&self.registry, &ret.ty)), + "invocation of {} returned an invalid argument", + libfunc_to_name( + self.registry.get_libfunc(&invocation.libfunc_id).unwrap() + ) + ); + frame.pc = frame.pc.next(&invocation.branches[branch_idx].target); frame.state.set( edit_state::put_results( diff --git a/src/vm/array.rs b/src/vm/array.rs index e4814e1..4f45f56 100644 --- a/src/vm/array.rs +++ b/src/vm/array.rs @@ -1,10 +1,11 @@ use super::EvalAction; -use crate::Value; +use crate::{find_real_type, Value}; use cairo_lang_sierra::{ extensions::{ array::ArrayConcreteLibfunc, core::{CoreLibfunc, CoreType, CoreTypeConcrete}, lib_func::{SignatureAndTypeConcreteLibfunc, SignatureOnlyConcreteLibfunc}, + ConcreteLibfunc, }, program_registry::ProgramRegistry, }; @@ -17,7 +18,7 @@ pub fn eval( ) -> EvalAction { match selector { ArrayConcreteLibfunc::New(info) => eval_new(registry, info, args), - ArrayConcreteLibfunc::SpanFromTuple(_) => todo!(), + ArrayConcreteLibfunc::SpanFromTuple(info) => eval_span_from_tuple(registry, info, args), ArrayConcreteLibfunc::TupleFromSpan(_) => todo!(), ArrayConcreteLibfunc::Append(info) => eval_append(registry, info, args), ArrayConcreteLibfunc::PopFront(info) => eval_pop_front(registry, info, args), @@ -36,6 +37,30 @@ pub fn eval( } } +fn eval_span_from_tuple( + registry: &ProgramRegistry, + info: &SignatureAndTypeConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::Struct(data)]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + let ty = &info.branch_signatures()[0].vars[0].ty; + let ty = find_real_type(registry, ty); + + let CoreTypeConcrete::Array(info) = registry.get_type(&ty).unwrap() else { + panic!() + }; + + let value = Value::Array { + ty: info.ty.clone(), + data, + }; + + return EvalAction::NormalBranch(0, smallvec![value]); +} + pub fn eval_new( registry: &ProgramRegistry, info: &SignatureOnlyConcreteLibfunc, diff --git a/src/vm/circuit.rs b/src/vm/circuit.rs index 5764a35..1716614 100644 --- a/src/vm/circuit.rs +++ b/src/vm/circuit.rs @@ -235,7 +235,7 @@ pub fn eval_u96_single_limb_less_than_guarantee_verify( _info: &SignatureOnlyConcreteLibfunc, _args: Vec, ) -> EvalAction { - EvalAction::NormalBranch(0, smallvec![Value::Unit]) + EvalAction::NormalBranch(0, smallvec![Value::U128(0)]) } pub fn eval_u96_guarantee_verify( diff --git a/src/vm/const.rs b/src/vm/const.rs index a9a805b..8f52d98 100644 --- a/src/vm/const.rs +++ b/src/vm/const.rs @@ -82,7 +82,13 @@ fn inner( [GenericArg::Value(value)] => Value::Felt(value.into()), _ => unreachable!(), }, - CoreTypeConcrete::NonZero(info) => inner(registry, &info.ty, inner_data), + CoreTypeConcrete::NonZero(_) => match inner_data { + [GenericArg::Type(type_id)] => match registry.get_type(type_id).unwrap() { + CoreTypeConcrete::Const(info) => inner(registry, &info.inner_ty, &info.inner_data), + _ => unreachable!(), + }, + _ => unreachable!(), + }, CoreTypeConcrete::Sint128(_) => match inner_data { [GenericArg::Value(value)] => Value::I128(value.try_into().unwrap()), _ => unreachable!(), @@ -113,6 +119,10 @@ fn inner( }, CoreTypeConcrete::Uint128(_) => match inner_data { [GenericArg::Value(value)] => Value::U128(value.try_into().unwrap()), + [GenericArg::Type(type_id)] => match registry.get_type(type_id).unwrap() { + CoreTypeConcrete::Const(info) => inner(registry, &info.inner_ty, &info.inner_data), + _ => unreachable!(), + }, _ => unreachable!(), }, CoreTypeConcrete::Struct(_) => { diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index 7ef0779..6a30346 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -1,5 +1,8 @@ use super::EvalAction; -use crate::{starknet::StarknetSyscallHandler, Value}; +use crate::{ + starknet::{Secp256r1Point, StarknetSyscallHandler, U256}, + Value, +}; use cairo_lang_sierra::{ extensions::{ consts::SignatureAndConstConcreteLibfunc, @@ -10,6 +13,7 @@ use cairo_lang_sierra::{ }, program_registry::ProgramRegistry, }; +use num_traits::One; use smallvec::smallvec; use starknet_types_core::felt::Felt; @@ -98,7 +102,247 @@ pub fn eval( eval_send_message_to_l1(registry, info, args, syscall_handler) } StarkNetConcreteLibfunc::Testing(_info) => todo!(), - StarkNetConcreteLibfunc::Secp256(_info) => todo!(), + StarkNetConcreteLibfunc::Secp256(info) => match info { + cairo_lang_sierra::extensions::starknet::secp256::Secp256ConcreteLibfunc::K1(info) => { + match info { + cairo_lang_sierra::extensions::starknet::secp256::Secp256OpConcreteLibfunc::New(_) => todo!(), + cairo_lang_sierra::extensions::starknet::secp256::Secp256OpConcreteLibfunc::Add(_) => todo!(), + cairo_lang_sierra::extensions::starknet::secp256::Secp256OpConcreteLibfunc::Mul(_) => todo!(), + cairo_lang_sierra::extensions::starknet::secp256::Secp256OpConcreteLibfunc::GetPointFromX(_) => todo!(), + cairo_lang_sierra::extensions::starknet::secp256::Secp256OpConcreteLibfunc::GetXy(_) => todo!(), + } + } + cairo_lang_sierra::extensions::starknet::secp256::Secp256ConcreteLibfunc::R1(info) => { + match info { + cairo_lang_sierra::extensions::starknet::secp256::Secp256OpConcreteLibfunc::New(info) => eval_secp_r_new(registry, info, args, syscall_handler), + cairo_lang_sierra::extensions::starknet::secp256::Secp256OpConcreteLibfunc::Add(info) => eval_secp_r_add(registry, info, args, syscall_handler), + cairo_lang_sierra::extensions::starknet::secp256::Secp256OpConcreteLibfunc::Mul(info) => eval_secp_r_mul(registry, info, args, syscall_handler), + cairo_lang_sierra::extensions::starknet::secp256::Secp256OpConcreteLibfunc::GetPointFromX(info) => eval_secp_r_get_point_from_x(registry, info, args, syscall_handler), + cairo_lang_sierra::extensions::starknet::secp256::Secp256OpConcreteLibfunc::GetXy(info) => secp_r_get_xy(registry, info, args, syscall_handler), + } + } + }, + } +} + +fn eval_secp_r_add( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, +) -> EvalAction { + let [Value::U128(mut gas), system @ Value::Unit, x, y]: [Value; 4] = args.try_into().unwrap() + else { + panic!() + }; + + let x = Secp256r1Point::from_value(x); + let y = Secp256r1Point::from_value(y); + + match syscall_handler.secp256r1_add(x, y, &mut gas) { + Ok(x) => EvalAction::NormalBranch(0, smallvec![Value::U128(gas), system, x.into_value()]), + Err(r) => { + let r = Value::Struct(r.into_iter().map(Value::Felt).collect::>()); + EvalAction::NormalBranch(1, smallvec![Value::U128(gas), system, r]) + } + } +} + +fn eval_secp_r_mul( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, +) -> EvalAction { + let [Value::U128(mut gas), system @ Value::Unit, x, n]: [Value; 4] = args.try_into().unwrap() + else { + panic!() + }; + + let x = Secp256r1Point::from_value(x); + let n = U256::from_value(n); + + match syscall_handler.secp256r1_mul(x, n, &mut gas) { + Ok(x) => EvalAction::NormalBranch(0, smallvec![Value::U128(gas), system, x.into_value()]), + Err(r) => { + let r = Value::Struct(r.into_iter().map(Value::Felt).collect::>()); + EvalAction::NormalBranch(1, smallvec![Value::U128(gas), system, r]) + } + } +} + +fn eval_secp_r_new( + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, +) -> EvalAction { + let [Value::U128(mut gas), system @ Value::Unit, Value::Struct(x), Value::Struct(y)]: [Value; + 4] = args.try_into().unwrap() + else { + panic!() + }; + + let Value::U128(x_lo) = x[0] else { panic!() }; + let Value::U128(x_hi) = x[1] else { panic!() }; + let x = U256 { lo: x_lo, hi: x_hi }; + let Value::U128(y_lo) = y[0] else { panic!() }; + let Value::U128(y_hi) = y[1] else { panic!() }; + let y = U256 { lo: y_lo, hi: y_hi }; + + match syscall_handler.secp256r1_new(x, y, &mut gas) { + Ok(p) => { + let enum_ty = &info.branch_signatures()[0].vars[2].ty; + let value = match p { + Some(p) => Value::Enum { + self_ty: enum_ty.clone(), + index: 0, + payload: Box::new(p.into_value()), + }, + None => Value::Enum { + self_ty: enum_ty.clone(), + index: 1, + payload: Box::new(Value::Unit), + }, + }; + + EvalAction::NormalBranch(0, smallvec![Value::U128(gas), system, value]) + } + Err(payload) => { + // get felt type from the error branch array + let felt_ty = { + match registry + .get_type(&info.branch_signatures()[1].vars[2].ty) + .unwrap() + { + CoreTypeConcrete::Array(info) => info.ty.clone(), + _ => unreachable!(), + } + }; + + let value = payload.into_iter().map(Value::Felt).collect::>(); + EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: felt_ty, + data: value + } + ], + ) + } + } +} + +fn eval_secp_r_get_point_from_x( + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, +) -> EvalAction { + let [Value::U128(mut gas), system @ Value::Unit, Value::Struct(x), Value::Enum { + index: y_parity, .. + }]: [Value; 4] = args.try_into().unwrap() + else { + panic!() + }; + + let Value::U128(x_lo) = x[0] else { panic!() }; + let Value::U128(x_hi) = x[1] else { panic!() }; + let x = U256 { lo: x_lo, hi: x_hi }; + let y_parity = y_parity.is_one(); + + match syscall_handler.secp256r1_get_point_from_x(x, y_parity, &mut gas) { + Ok(p) => { + let enum_ty = &info.branch_signatures()[0].vars[2].ty; + let value = match p { + Some(p) => Value::Enum { + self_ty: enum_ty.clone(), + index: 0, + payload: Box::new(p.into_value()), + }, + None => Value::Enum { + self_ty: enum_ty.clone(), + index: 1, + payload: Box::new(Value::Unit), + }, + }; + + EvalAction::NormalBranch(0, smallvec![Value::U128(gas), system, value]) + } + Err(payload) => { + // get felt type from the error branch array + let felt_ty = { + match registry + .get_type(&info.branch_signatures()[1].vars[2].ty) + .unwrap() + { + CoreTypeConcrete::Array(info) => info.ty.clone(), + _ => unreachable!(), + } + }; + + let value = payload.into_iter().map(Value::Felt).collect::>(); + EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: felt_ty, + data: value + } + ], + ) + } + } +} + +fn secp_r_get_xy( + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, +) -> EvalAction { + let [Value::U128(mut gas), system @ Value::Unit, secp_value]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let secp_value = Secp256r1Point::from_value(secp_value); + + match syscall_handler.secp256r1_get_xy(secp_value, &mut gas) { + Ok(payload) => { + let (x, y) = (payload.0.into_value(), payload.1.into_value()); + EvalAction::NormalBranch(0, smallvec![Value::U128(gas), system, x, y]) + } + Err(payload) => { + let felt_ty = { + match registry + .get_type(&info.branch_signatures()[1].vars[2].ty) + .unwrap() + { + CoreTypeConcrete::Array(info) => info.ty.clone(), + _ => unreachable!(), + } + }; + + let payload = payload.into_iter().map(Value::Felt).collect::>(); + EvalAction::NormalBranch( + 0, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: felt_ty, + data: payload + } + ], + ) + } } } diff --git a/src/vm/uint252.rs b/src/vm/uint252.rs index d57682e..5131715 100644 --- a/src/vm/uint252.rs +++ b/src/vm/uint252.rs @@ -20,7 +20,50 @@ pub fn eval( Uint256Concrete::IsZero(info) => eval_is_zero(registry, info, args), Uint256Concrete::Divmod(info) => eval_divmod(registry, info, args), Uint256Concrete::SquareRoot(_) => todo!(), - Uint256Concrete::InvModN(_) => todo!(), + Uint256Concrete::InvModN(info) => eval_inv_mod_n(registry, info, args), + } +} + +fn eval_inv_mod_n( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::Struct(x), Value::Struct(modulo)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let [Value::U128(x_lo), Value::U128(x_hi)]: [Value; 2] = x.clone().try_into().unwrap() else { + panic!() + }; + + let [Value::U128(mod_lo), Value::U128(mod_hi)]: [Value; 2] = modulo.clone().try_into().unwrap() + else { + panic!() + }; + + let x = u256_to_biguint(x_lo, x_hi); + let modulo = u256_to_biguint(mod_lo, mod_hi); + + match x.modinv(&modulo) { + Some(r) => EvalAction::NormalBranch( + 0, + smallvec![ + range_check, + u256_to_value(r), + Value::Unit, + Value::Unit, + Value::Unit, + Value::Unit, + Value::Unit, + Value::Unit, + Value::Unit, + Value::Unit + ], + ), + None => EvalAction::NormalBranch(1, smallvec![range_check, Value::Unit, Value::Unit]), } }