From faa207d945104cc4e4a6714cf3c2f63584c2728c Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 13 Aug 2024 16:53:33 +0200 Subject: [PATCH 01/40] progress --- src/value.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/value.rs b/src/value.rs index 244caca..6105749 100644 --- a/src/value.rs +++ b/src/value.rs @@ -99,29 +99,29 @@ impl Value { // To do: CoreTypeConcrete::Coupon(_) => todo!(), - CoreTypeConcrete::Bitwise(_) => todo!(), - CoreTypeConcrete::Box(_) => todo!(), + CoreTypeConcrete::Bitwise(_) => matches!(self, Self::Unit), + CoreTypeConcrete::Box(info) => self.is(registry, &info.ty), CoreTypeConcrete::Circuit(_) => todo!(), CoreTypeConcrete::Const(_) => todo!(), CoreTypeConcrete::EcOp(_) => todo!(), CoreTypeConcrete::EcPoint(_) => todo!(), CoreTypeConcrete::EcState(_) => todo!(), - CoreTypeConcrete::BuiltinCosts(_) => todo!(), + CoreTypeConcrete::BuiltinCosts(_) => matches!(self, Self::Unit), CoreTypeConcrete::Uint16(_) => todo!(), CoreTypeConcrete::Uint64(_) => todo!(), CoreTypeConcrete::Uint128(_) => todo!(), - CoreTypeConcrete::Uint128MulGuarantee(_) => todo!(), + CoreTypeConcrete::Uint128MulGuarantee(_) => matches!(self, Self::Unit), CoreTypeConcrete::Sint16(_) => todo!(), CoreTypeConcrete::Sint32(_) => todo!(), CoreTypeConcrete::Sint64(_) => todo!(), CoreTypeConcrete::Sint128(_) => todo!(), - CoreTypeConcrete::Nullable(_) => todo!(), - CoreTypeConcrete::RangeCheck96(_) => todo!(), + CoreTypeConcrete::Nullable(info) => self.is(registry, &info.ty), + CoreTypeConcrete::RangeCheck96(_) => matches!(self, Self::Unit), CoreTypeConcrete::Uninitialized(_) => todo!(), CoreTypeConcrete::Felt252DictEntry(_) => todo!(), CoreTypeConcrete::SquashedFelt252Dict(_) => todo!(), - CoreTypeConcrete::Pedersen(_) => todo!(), - CoreTypeConcrete::Poseidon(_) => todo!(), + CoreTypeConcrete::Pedersen(_) => matches!(self, Self::Unit), + CoreTypeConcrete::Poseidon(_) => matches!(self, Self::Unit), CoreTypeConcrete::Span(_) => todo!(), CoreTypeConcrete::StarkNet(inner) => match inner { StarkNetTypeConcrete::ClassHash(_) From bb9da64961fe8373f3e04d45a02f9ed78ed70a84 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 14 Aug 2024 14:22:46 +0200 Subject: [PATCH 02/40] implement more libfuncs --- src/vm/felt252.rs | 15 +++++++++++++-- src/vm/starknet.rs | 29 ++++++++++++++++++++++++++++- src/vm/struct.rs | 34 +++++++++++++++++++++++++++++++++- src/vm/uint32.rs | 15 +++++++++++++-- src/vm/uint8.rs | 15 +++++++++++++-- 5 files changed, 100 insertions(+), 8 deletions(-) diff --git a/src/vm/felt252.rs b/src/vm/felt252.rs index 8e8c163..e6d10c0 100644 --- a/src/vm/felt252.rs +++ b/src/vm/felt252.rs @@ -3,7 +3,10 @@ use crate::Value; use cairo_lang_sierra::{ extensions::{ core::{CoreLibfunc, CoreType}, - felt252::{Felt252BinaryOperationConcrete, Felt252BinaryOperator, Felt252Concrete}, + felt252::{ + Felt252BinaryOperationConcrete, Felt252BinaryOperator, Felt252Concrete, + Felt252ConstConcreteLibfunc, + }, }, program_registry::ProgramRegistry, }; @@ -16,7 +19,7 @@ pub fn eval( ) -> EvalAction { match selector { Felt252Concrete::BinaryOperation(info) => eval_squash(registry, info, args), - Felt252Concrete::Const(_) => todo!(), + Felt252Concrete::Const(info) => eval_const(registry, info, args), Felt252Concrete::IsZero(_) => todo!(), } } @@ -44,3 +47,11 @@ pub fn eval_squash( EvalAction::NormalBranch(0, smallvec![Value::Felt(res)]) } + +pub fn eval_const( + _registry: &ProgramRegistry, + info: &Felt252ConstConcreteLibfunc, + _args: Vec, +) -> EvalAction { + EvalAction::NormalBranch(0, smallvec![Value::Felt(info.c.clone().into())]) +} diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index 3e62691..e6245d9 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -11,6 +11,7 @@ use cairo_lang_sierra::{ program_registry::ProgramRegistry, }; use smallvec::smallvec; +use starknet_types_core::felt::Felt; pub fn eval( registry: &ProgramRegistry, @@ -28,7 +29,9 @@ pub fn eval( StarkNetConcreteLibfunc::ClassHashTryFromFelt252(_) => todo!(), StarkNetConcreteLibfunc::ClassHashToFelt252(_) => todo!(), StarkNetConcreteLibfunc::ContractAddressConst(_) => todo!(), - StarkNetConcreteLibfunc::ContractAddressTryFromFelt252(_) => todo!(), + StarkNetConcreteLibfunc::ContractAddressTryFromFelt252(info) => { + eval_contract_address_try_from_felt(registry, info, args) + } StarkNetConcreteLibfunc::ContractAddressToFelt252(_) => todo!(), StarkNetConcreteLibfunc::StorageRead(info) => { eval_storage_read(registry, info, args, syscall_handler) @@ -85,6 +88,30 @@ fn eval_storage_base_address_const( EvalAction::NormalBranch(0, smallvec![Value::Felt(info.c.clone().into())]) } +fn eval_contract_address_try_from_felt( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + // 2 ** 251 = 3618502788666131106986593281521497120414687020801267626233049500247285301248 + + let [range_check @ Value::Unit, Value::Felt(value)]: [Value; 2] = args.try_into().unwrap() + else { + panic!() + }; + + if value + < Felt::from_dec_str( + "3618502788666131106986593281521497120414687020801267626233049500247285301248", + ) + .unwrap() + { + EvalAction::NormalBranch(0, smallvec![range_check, Value::Felt(value)]) + } else { + EvalAction::NormalBranch(1, smallvec![range_check]) + } +} + fn eval_storage_address_from_base( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, diff --git a/src/vm/struct.rs b/src/vm/struct.rs index 609944e..1e84436 100644 --- a/src/vm/struct.rs +++ b/src/vm/struct.rs @@ -18,7 +18,9 @@ pub fn eval( match selector { StructConcreteLibfunc::Construct(info) => eval_construct(registry, info, args), StructConcreteLibfunc::Deconstruct(info) => eval_deconstruct(registry, info, args), - StructConcreteLibfunc::SnapshotDeconstruct(_) => todo!(), + StructConcreteLibfunc::SnapshotDeconstruct(info) => { + eval_snapshot_deconstruct(registry, info, args) + } } } @@ -65,3 +67,33 @@ pub fn eval_deconstruct( EvalAction::NormalBranch(0, values.into()) } + +pub fn eval_snapshot_deconstruct( + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::Struct(values)]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + let CoreTypeConcrete::Snapshot(snapshot_ty) = registry + .get_type(&info.signature.param_signatures[0].ty) + .unwrap() + else { + panic!() + }; + + let CoreTypeConcrete::Struct(StructConcreteType { members, .. }) = + registry.get_type(&snapshot_ty.ty).unwrap() + else { + panic!() + }; + assert_eq!(values.len(), members.len()); + assert!(values + .iter() + .zip(members) + .all(|(value, ty)| value.is(registry, ty))); + + EvalAction::NormalBranch(0, values.into()) +} diff --git a/src/vm/uint32.rs b/src/vm/uint32.rs index 82ff35e..ba9ee66 100644 --- a/src/vm/uint32.rs +++ b/src/vm/uint32.rs @@ -3,7 +3,10 @@ use crate::Value; use cairo_lang_sierra::{ extensions::{ core::{CoreLibfunc, CoreType}, - int::{unsigned::Uint32Concrete, IntOperationConcreteLibfunc, IntOperator}, + int::{ + unsigned::{Uint32Concrete, Uint32Traits}, + IntConstConcreteLibfunc, IntOperationConcreteLibfunc, IntOperator, + }, lib_func::SignatureOnlyConcreteLibfunc, }, program_registry::ProgramRegistry, @@ -16,7 +19,7 @@ pub fn eval( args: Vec, ) -> EvalAction { match selector { - Uint32Concrete::Const(_) => todo!(), + Uint32Concrete::Const(info) => eval_const(registry, info, args), Uint32Concrete::Operation(info) => eval_operation(registry, info, args), Uint32Concrete::SquareRoot(_) => todo!(), Uint32Concrete::Equal(_) => todo!(), @@ -62,3 +65,11 @@ pub fn eval_to_felt252( EvalAction::NormalBranch(0, smallvec![Value::Felt(value.into())]) } + +pub fn eval_const( + _registry: &ProgramRegistry, + info: &IntConstConcreteLibfunc, + _args: Vec, +) -> EvalAction { + EvalAction::NormalBranch(0, smallvec![Value::U32(info.c)]) +} diff --git a/src/vm/uint8.rs b/src/vm/uint8.rs index 5e29e49..f70d551 100644 --- a/src/vm/uint8.rs +++ b/src/vm/uint8.rs @@ -3,7 +3,10 @@ use crate::Value; use cairo_lang_sierra::{ extensions::{ core::{CoreLibfunc, CoreType}, - int::unsigned::Uint8Concrete, + int::{ + unsigned::{Uint8Concrete, Uint8Traits}, + IntConstConcreteLibfunc, + }, lib_func::SignatureOnlyConcreteLibfunc, }, program_registry::ProgramRegistry, @@ -16,7 +19,7 @@ pub fn eval( args: Vec, ) -> EvalAction { match selector { - Uint8Concrete::Const(_) => todo!(), + Uint8Concrete::Const(info) => eval_const(registry, info, args), Uint8Concrete::Operation(_) => todo!(), Uint8Concrete::SquareRoot(_) => todo!(), Uint8Concrete::Equal(info) => eval_equal(registry, info, args), @@ -40,3 +43,11 @@ pub fn eval_equal( EvalAction::NormalBranch((lhs != rhs) as usize, smallvec![]) } + +pub fn eval_const( + _registry: &ProgramRegistry, + info: &IntConstConcreteLibfunc, + _args: Vec, +) -> EvalAction { + EvalAction::NormalBranch(0, smallvec![Value::U8(info.c)]) +} From 2ed025dbb9c5b5a58552dff97ba49ada56dd6c2f Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 14 Aug 2024 14:42:49 +0200 Subject: [PATCH 03/40] progress --- src/value.rs | 3 +- src/vm.rs | 3 +- src/vm/felt252.rs | 4 +- src/vm/uint32.rs | 48 +++++++++++++++++-- src/vm/uint64.rs | 117 ++++++++++++++++++++++++++++++++++++++++++++++ src/vm/uint8.rs | 60 ++++++++++++++++++++++-- 6 files changed, 224 insertions(+), 11 deletions(-) create mode 100644 src/vm/uint64.rs diff --git a/src/value.rs b/src/value.rs index 6105749..f94d5df 100644 --- a/src/value.rs +++ b/src/value.rs @@ -40,6 +40,7 @@ pub enum Value { Struct(Vec), U128(u128), U256(u128, u128), + U16(u16), U32(u32), U64(u64), U8(u8), @@ -108,7 +109,7 @@ impl Value { CoreTypeConcrete::EcState(_) => todo!(), CoreTypeConcrete::BuiltinCosts(_) => matches!(self, Self::Unit), CoreTypeConcrete::Uint16(_) => todo!(), - CoreTypeConcrete::Uint64(_) => todo!(), + CoreTypeConcrete::Uint64(_) => matches!(self, Self::U64(_)), CoreTypeConcrete::Uint128(_) => todo!(), CoreTypeConcrete::Uint128MulGuarantee(_) => matches!(self, Self::Unit), CoreTypeConcrete::Sint16(_) => todo!(), diff --git a/src/vm.rs b/src/vm.rs index b8b655c..04f49f3 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -39,6 +39,7 @@ mod snapshot_take; mod starknet; mod r#struct; mod uint32; +mod uint64; mod uint8; pub struct VirtualMachine { @@ -314,7 +315,7 @@ fn eval<'a>( CoreConcreteLibfunc::Uint256(_) => todo!(), CoreConcreteLibfunc::Uint32(selector) => self::uint32::eval(registry, selector, args), CoreConcreteLibfunc::Uint512(_) => todo!(), - CoreConcreteLibfunc::Uint64(_) => todo!(), + CoreConcreteLibfunc::Uint64(selector) => self::uint64::eval(registry, selector, args), CoreConcreteLibfunc::Uint8(selector) => self::uint8::eval(registry, selector, args), CoreConcreteLibfunc::UnconditionalJump(info) => self::jump::eval(registry, info, args), CoreConcreteLibfunc::UnwrapNonZero(_) => todo!(), diff --git a/src/vm/felt252.rs b/src/vm/felt252.rs index e6d10c0..8d21599 100644 --- a/src/vm/felt252.rs +++ b/src/vm/felt252.rs @@ -18,13 +18,13 @@ pub fn eval( args: Vec, ) -> EvalAction { match selector { - Felt252Concrete::BinaryOperation(info) => eval_squash(registry, info, args), + Felt252Concrete::BinaryOperation(info) => eval_operation(registry, info, args), Felt252Concrete::Const(info) => eval_const(registry, info, args), Felt252Concrete::IsZero(_) => todo!(), } } -pub fn eval_squash( +pub fn eval_operation( _registry: &ProgramRegistry, info: &Felt252BinaryOperationConcrete, args: Vec, diff --git a/src/vm/uint32.rs b/src/vm/uint32.rs index ba9ee66..a960d37 100644 --- a/src/vm/uint32.rs +++ b/src/vm/uint32.rs @@ -22,12 +22,12 @@ pub fn eval( Uint32Concrete::Const(info) => eval_const(registry, info, args), Uint32Concrete::Operation(info) => eval_operation(registry, info, args), Uint32Concrete::SquareRoot(_) => todo!(), - Uint32Concrete::Equal(_) => todo!(), + Uint32Concrete::Equal(info) => eval_equal(registry, info, args), Uint32Concrete::ToFelt252(info) => eval_to_felt252(registry, info, args), Uint32Concrete::FromFelt252(_) => todo!(), - Uint32Concrete::IsZero(_) => todo!(), + Uint32Concrete::IsZero(info) => eval_is_zero(registry, info, args), Uint32Concrete::Divmod(_) => todo!(), - Uint32Concrete::WideMul(_) => todo!(), + Uint32Concrete::WideMul(info) => eval_widemul(registry, info, args), Uint32Concrete::Bitwise(_) => todo!(), } } @@ -54,6 +54,34 @@ pub fn eval_operation( ) } +pub fn eval_equal( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::U32(lhs), Value::U32(rhs)]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + + EvalAction::NormalBranch((lhs != rhs) as usize, smallvec![]) +} + +pub fn eval_is_zero( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [vm_value @ Value::U32(value)]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + if value == 0 { + EvalAction::NormalBranch(0, smallvec![]) + } else { + EvalAction::NormalBranch(1, smallvec![vm_value]) + } +} + pub fn eval_to_felt252( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, @@ -73,3 +101,17 @@ pub fn eval_const( ) -> EvalAction { EvalAction::NormalBranch(0, smallvec![Value::U32(info.c)]) } + +pub fn eval_widemul( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::U32(lhs), Value::U32(rhs)]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + + let result = (lhs as u64) * (rhs as u64); + + EvalAction::NormalBranch(0, smallvec![Value::U64(result)]) +} diff --git a/src/vm/uint64.rs b/src/vm/uint64.rs new file mode 100644 index 0000000..5989875 --- /dev/null +++ b/src/vm/uint64.rs @@ -0,0 +1,117 @@ +use super::EvalAction; +use crate::Value; +use cairo_lang_sierra::{ + extensions::{ + core::{CoreLibfunc, CoreType}, + int::{ + unsigned::{Uint64Concrete, Uint64Traits}, + IntConstConcreteLibfunc, IntOperationConcreteLibfunc, IntOperator, + }, + lib_func::SignatureOnlyConcreteLibfunc, + }, + program_registry::ProgramRegistry, +}; +use smallvec::smallvec; + +pub fn eval( + registry: &ProgramRegistry, + selector: &Uint64Concrete, + args: Vec, +) -> EvalAction { + match selector { + Uint64Concrete::Const(info) => eval_const(registry, info, args), + Uint64Concrete::Operation(info) => eval_operation(registry, info, args), + Uint64Concrete::SquareRoot(_) => todo!(), + Uint64Concrete::Equal(info) => eval_equal(registry, info, args), + Uint64Concrete::ToFelt252(info) => eval_to_felt252(registry, info, args), + Uint64Concrete::FromFelt252(_) => todo!(), + Uint64Concrete::IsZero(info) => eval_is_zero(registry, info, args), + Uint64Concrete::Divmod(_) => todo!(), + Uint64Concrete::WideMul(info) => eval_widemul(registry, info, args), + Uint64Concrete::Bitwise(_) => todo!(), + } +} + +pub fn eval_operation( + _registry: &ProgramRegistry, + info: &IntOperationConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::U64(lhs), Value::U64(rhs)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let (result, has_overflow) = match info.operator { + IntOperator::OverflowingAdd => lhs.overflowing_add(rhs), + IntOperator::OverflowingSub => lhs.overflowing_sub(rhs), + }; + + EvalAction::NormalBranch( + has_overflow as usize, + smallvec![range_check, Value::U64(result)], + ) +} + +pub fn eval_equal( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::U64(lhs), Value::U64(rhs)]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + + EvalAction::NormalBranch((lhs != rhs) as usize, smallvec![]) +} + +pub fn eval_is_zero( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [vm_value @ Value::U64(value)]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + if value == 0 { + EvalAction::NormalBranch(0, smallvec![]) + } else { + EvalAction::NormalBranch(1, smallvec![vm_value]) + } +} + +pub fn eval_to_felt252( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::U64(value)]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + EvalAction::NormalBranch(0, smallvec![Value::Felt(value.into())]) +} + +pub fn eval_const( + _registry: &ProgramRegistry, + info: &IntConstConcreteLibfunc, + _args: Vec, +) -> EvalAction { + EvalAction::NormalBranch(0, smallvec![Value::U64(info.c)]) +} + +pub fn eval_widemul( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::U64(lhs), Value::U64(rhs)]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + + let result = (lhs as u128) * (rhs as u128); + + EvalAction::NormalBranch(0, smallvec![Value::U128(result)]) +} diff --git a/src/vm/uint8.rs b/src/vm/uint8.rs index f70d551..b4dc540 100644 --- a/src/vm/uint8.rs +++ b/src/vm/uint8.rs @@ -5,7 +5,7 @@ use cairo_lang_sierra::{ core::{CoreLibfunc, CoreType}, int::{ unsigned::{Uint8Concrete, Uint8Traits}, - IntConstConcreteLibfunc, + IntConstConcreteLibfunc, IntOperationConcreteLibfunc, IntOperator, }, lib_func::SignatureOnlyConcreteLibfunc, }, @@ -20,18 +20,40 @@ pub fn eval( ) -> EvalAction { match selector { Uint8Concrete::Const(info) => eval_const(registry, info, args), - Uint8Concrete::Operation(_) => todo!(), + Uint8Concrete::Operation(info) => eval_operation(registry, info, args), Uint8Concrete::SquareRoot(_) => todo!(), Uint8Concrete::Equal(info) => eval_equal(registry, info, args), Uint8Concrete::ToFelt252(_) => todo!(), Uint8Concrete::FromFelt252(_) => todo!(), - Uint8Concrete::IsZero(_) => todo!(), + Uint8Concrete::IsZero(info) => eval_is_zero(registry, info, args), Uint8Concrete::Divmod(_) => todo!(), - Uint8Concrete::WideMul(_) => todo!(), + Uint8Concrete::WideMul(info) => eval_widemul(registry, info, args), Uint8Concrete::Bitwise(_) => todo!(), } } +pub fn eval_operation( + _registry: &ProgramRegistry, + info: &IntOperationConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::U8(lhs), Value::U8(rhs)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let (result, has_overflow) = match info.operator { + IntOperator::OverflowingAdd => lhs.overflowing_add(rhs), + IntOperator::OverflowingSub => lhs.overflowing_sub(rhs), + }; + + EvalAction::NormalBranch( + has_overflow as usize, + smallvec![range_check, Value::U8(result)], + ) +} + pub fn eval_equal( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, @@ -44,6 +66,22 @@ pub fn eval_equal( EvalAction::NormalBranch((lhs != rhs) as usize, smallvec![]) } +pub fn eval_is_zero( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [vm_value @ Value::U8(value)]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + if value == 0 { + EvalAction::NormalBranch(0, smallvec![]) + } else { + EvalAction::NormalBranch(1, smallvec![vm_value]) + } +} + pub fn eval_const( _registry: &ProgramRegistry, info: &IntConstConcreteLibfunc, @@ -51,3 +89,17 @@ pub fn eval_const( ) -> EvalAction { EvalAction::NormalBranch(0, smallvec![Value::U8(info.c)]) } + +pub fn eval_widemul( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::U8(lhs), Value::U8(rhs)]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + + let result = (lhs as u16) * (rhs as u16); + + EvalAction::NormalBranch(0, smallvec![Value::U16(result)]) +} From 7697fadb2414327696f026cb854338636068b75a Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 14 Aug 2024 14:46:13 +0200 Subject: [PATCH 04/40] progress --- src/vm/cast.rs | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/vm/cast.rs b/src/vm/cast.rs index 112d168..5fff9ed 100644 --- a/src/vm/cast.rs +++ b/src/vm/cast.rs @@ -8,6 +8,7 @@ use cairo_lang_sierra::{ }, program_registry::ProgramRegistry, }; +use num_bigint::BigInt; use smallvec::smallvec; pub fn eval( @@ -32,6 +33,11 @@ pub fn eval_downcast( let value = match value { Value::BoundedInt { value, .. } => value, + Value::U128(value) => BigInt::from(value), + Value::U64(value) => BigInt::from(value), + Value::U32(value) => BigInt::from(value), + Value::U16(value) => BigInt::from(value), + Value::U8(value) => BigInt::from(value), _ => todo!(), }; @@ -43,6 +49,11 @@ pub fn eval_downcast( range_check, match registry.get_type(&info.to_ty).unwrap() { CoreTypeConcrete::Sint8(_) => Value::I8(value.try_into().unwrap()), + CoreTypeConcrete::Uint8(_) => Value::U8(value.try_into().unwrap()), + CoreTypeConcrete::Uint16(_) => Value::U16(value.try_into().unwrap()), + CoreTypeConcrete::Uint32(_) => Value::U32(value.try_into().unwrap()), + CoreTypeConcrete::Uint64(_) => Value::U64(value.try_into().unwrap()), + CoreTypeConcrete::Uint128(_) => Value::U128(value.try_into().unwrap()), _ => todo!(), } ], @@ -57,24 +68,15 @@ pub fn eval_upcast( info: &SignatureOnlyConcreteLibfunc, args: Vec, ) -> EvalAction { - dbg!(info - .signature - .param_signatures - .iter() - .map(|x| x.ty.to_string()) - .collect::>()); - dbg!(info - .signature - .branch_signatures - .iter() - .map(|x| x.vars.iter().map(|x| x.ty.to_string()).collect::>()) - .collect::>()); - dbg!(&args); - let [value] = args.try_into().unwrap(); let value = match value { Value::BoundedInt { value, .. } => value, + Value::U128(value) => BigInt::from(value), + Value::U64(value) => BigInt::from(value), + Value::U32(value) => BigInt::from(value), + Value::U16(value) => BigInt::from(value), + Value::U8(value) => BigInt::from(value), _ => todo!(), }; @@ -85,6 +87,11 @@ pub fn eval_upcast( .unwrap() { CoreTypeConcrete::Sint8(_) => Value::I8(value.try_into().unwrap()), + CoreTypeConcrete::Uint8(_) => Value::U8(value.try_into().unwrap()), + CoreTypeConcrete::Uint16(_) => Value::U16(value.try_into().unwrap()), + CoreTypeConcrete::Uint32(_) => Value::U32(value.try_into().unwrap()), + CoreTypeConcrete::Uint64(_) => Value::U64(value.try_into().unwrap()), + CoreTypeConcrete::Uint128(_) => Value::U128(value.try_into().unwrap()), _ => todo!(), }], ) From dd21f95ed984930d66f79f3322890896239403de Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 14 Aug 2024 15:07:35 +0200 Subject: [PATCH 05/40] more libfuncs --- Cargo.toml | 1 + src/vm.rs | 6 ++++-- src/vm/pedersen.rs | 40 ++++++++++++++++++++++++++++++++++++ src/vm/poseidon.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++ src/vm/starknet.rs | 13 +++++++++++- 5 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 src/vm/pedersen.rs create mode 100644 src/vm/poseidon.rs diff --git a/Cargo.toml b/Cargo.toml index 118869d..38038ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ serde = { version = "1.0.204", features = ["derive"] } serde_json = "1.0.121" sha2 = { version = "0.10.8", features = ["compress"] } smallvec = "1.13.2" +starknet-crypto = "0.7.1" starknet-types-core = "0.1.2" tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } diff --git a/src/vm.rs b/src/vm.rs index 04f49f3..550603d 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -35,6 +35,8 @@ mod function_call; mod gas; mod jump; mod mem; +mod pedersen; +mod poseidon; mod snapshot_take; mod starknet; mod r#struct; @@ -298,8 +300,8 @@ fn eval<'a>( CoreConcreteLibfunc::Gas(selector) => self::gas::eval(registry, selector, args), CoreConcreteLibfunc::Mem(selector) => self::mem::eval(registry, selector, args), CoreConcreteLibfunc::Nullable(_) => todo!(), - CoreConcreteLibfunc::Pedersen(_) => todo!(), - CoreConcreteLibfunc::Poseidon(_) => todo!(), + CoreConcreteLibfunc::Pedersen(selector) => self::pedersen::eval(registry, selector, args), + CoreConcreteLibfunc::Poseidon(selector) => self::poseidon::eval(registry, selector, args), CoreConcreteLibfunc::Sint128(_) => todo!(), CoreConcreteLibfunc::Sint16(_) => todo!(), CoreConcreteLibfunc::Sint32(_) => todo!(), diff --git a/src/vm/pedersen.rs b/src/vm/pedersen.rs new file mode 100644 index 0000000..1b920c7 --- /dev/null +++ b/src/vm/pedersen.rs @@ -0,0 +1,40 @@ +use cairo_lang_sierra::{ + extensions::{ + core::{CoreLibfunc, CoreType}, + lib_func::SignatureOnlyConcreteLibfunc, + pedersen::PedersenConcreteLibfunc, + poseidon::PoseidonConcreteLibfunc, + }, + program_registry::ProgramRegistry, +}; +use smallvec::smallvec; + +use crate::Value; + +use super::EvalAction; + +pub fn eval( + registry: &ProgramRegistry, + selector: &PedersenConcreteLibfunc, + args: Vec, +) -> EvalAction { + match selector { + PedersenConcreteLibfunc::PedersenHash(info) => eval_pedersen_hash(registry, info, args), + } +} + +fn eval_pedersen_hash( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [pedersen @ Value::Unit, Value::Felt(lhs), Value::Felt(rhs)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let res = starknet_crypto::pedersen_hash(&lhs, &rhs); + + EvalAction::NormalBranch(0, smallvec![pedersen, Value::Felt(res),]) +} diff --git a/src/vm/poseidon.rs b/src/vm/poseidon.rs new file mode 100644 index 0000000..d1a2048 --- /dev/null +++ b/src/vm/poseidon.rs @@ -0,0 +1,51 @@ +use cairo_lang_sierra::{ + extensions::{ + core::{CoreLibfunc, CoreType}, + lib_func::SignatureOnlyConcreteLibfunc, + poseidon::PoseidonConcreteLibfunc, + }, + program_registry::ProgramRegistry, +}; +use smallvec::smallvec; + +use crate::Value; + +use super::EvalAction; + +pub fn eval( + registry: &ProgramRegistry, + selector: &PoseidonConcreteLibfunc, + args: Vec, +) -> EvalAction { + match selector { + PoseidonConcreteLibfunc::HadesPermutation(info) => { + eval_hades_permutation(registry, info, args) + } + } +} + +fn eval_hades_permutation( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [poseidon @ Value::Unit, Value::Felt(p1), Value::Felt(p2), Value::Felt(p3)]: [Value; 4] = + args.try_into().unwrap() + else { + panic!() + }; + + let mut state = [p1, p2, p3]; + + starknet_crypto::poseidon_permute_comp(&mut state); + + EvalAction::NormalBranch( + 0, + smallvec![ + poseidon, + Value::Felt(state[0]), + Value::Felt(state[1]), + Value::Felt(state[2]) + ], + ) +} diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index e6245d9..3be90a3 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -47,7 +47,9 @@ pub fn eval( eval_storage_address_from_base(registry, info, args) } StarkNetConcreteLibfunc::StorageAddressFromBaseAndOffset(_) => todo!(), - StarkNetConcreteLibfunc::StorageAddressToFelt252(_) => todo!(), + StarkNetConcreteLibfunc::StorageAddressToFelt252(info) => { + eval_storage_address_to_felt(registry, info, args) + } StarkNetConcreteLibfunc::StorageAddressTryFromFelt252(_) => todo!(), StarkNetConcreteLibfunc::EmitEvent(info) => eval_emit_event(registry, info, args), StarkNetConcreteLibfunc::GetBlockHash(info) => eval_get_block_hash(registry, info, args), @@ -112,6 +114,15 @@ fn eval_contract_address_try_from_felt( } } +fn eval_storage_address_to_felt( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [value] = args.try_into().unwrap(); + EvalAction::NormalBranch(0, smallvec![value]) +} + fn eval_storage_address_from_base( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, From b378a542b3871a83205dfba63cd4f898b0e9cabb Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Fri, 16 Aug 2024 11:39:16 +0200 Subject: [PATCH 06/40] progress --- src/vm/pedersen.rs | 1 - src/vm/starknet.rs | 95 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 89 insertions(+), 7 deletions(-) diff --git a/src/vm/pedersen.rs b/src/vm/pedersen.rs index 1b920c7..04da05a 100644 --- a/src/vm/pedersen.rs +++ b/src/vm/pedersen.rs @@ -3,7 +3,6 @@ use cairo_lang_sierra::{ core::{CoreLibfunc, CoreType}, lib_func::SignatureOnlyConcreteLibfunc, pedersen::PedersenConcreteLibfunc, - poseidon::PoseidonConcreteLibfunc, }, program_registry::ProgramRegistry, }; diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index 3be90a3..e799665 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -26,13 +26,21 @@ pub fn eval( StarkNetConcreteLibfunc::ClassHashConst(info) => { eval_class_hash_const(registry, info, args) } - StarkNetConcreteLibfunc::ClassHashTryFromFelt252(_) => todo!(), - StarkNetConcreteLibfunc::ClassHashToFelt252(_) => todo!(), - StarkNetConcreteLibfunc::ContractAddressConst(_) => todo!(), + StarkNetConcreteLibfunc::ClassHashTryFromFelt252(info) => { + eval_class_hash_try_from_felt(registry, info, args) + } + StarkNetConcreteLibfunc::ClassHashToFelt252(info) => { + eval_class_hash_to_felt(registry, info, args) + } + StarkNetConcreteLibfunc::ContractAddressConst(info) => { + eval_contract_address_const(registry, info, args) + } StarkNetConcreteLibfunc::ContractAddressTryFromFelt252(info) => { eval_contract_address_try_from_felt(registry, info, args) } - StarkNetConcreteLibfunc::ContractAddressToFelt252(_) => todo!(), + StarkNetConcreteLibfunc::ContractAddressToFelt252(info) => { + eval_contract_address_to_felt(registry, info, args) + } StarkNetConcreteLibfunc::StorageRead(info) => { eval_storage_read(registry, info, args, syscall_handler) } @@ -42,11 +50,15 @@ pub fn eval( StarkNetConcreteLibfunc::StorageBaseAddressConst(info) => { eval_storage_base_address_const(registry, info, args) } - StarkNetConcreteLibfunc::StorageBaseAddressFromFelt252(_) => todo!(), + StarkNetConcreteLibfunc::StorageBaseAddressFromFelt252(info) => { + eval_storage_base_address_from_felt(registry, info, args) + } StarkNetConcreteLibfunc::StorageAddressFromBase(info) => { eval_storage_address_from_base(registry, info, args) } - StarkNetConcreteLibfunc::StorageAddressFromBaseAndOffset(_) => todo!(), + StarkNetConcreteLibfunc::StorageAddressFromBaseAndOffset(info) => { + eval_storage_address_from_base_and_offset(registry, info, args) + } StarkNetConcreteLibfunc::StorageAddressToFelt252(info) => { eval_storage_address_to_felt(registry, info, args) } @@ -90,6 +102,38 @@ fn eval_storage_base_address_const( EvalAction::NormalBranch(0, smallvec![Value::Felt(info.c.clone().into())]) } +fn eval_contract_address_const( + _registry: &ProgramRegistry, + info: &SignatureAndConstConcreteLibfunc, + _args: Vec, +) -> EvalAction { + EvalAction::NormalBranch(0, smallvec![Value::Felt(info.c.clone().into())]) +} + +fn eval_class_hash_try_from_felt( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + // 2 ** 251 = 3618502788666131106986593281521497120414687020801267626233049500247285301248 + + let [range_check @ Value::Unit, Value::Felt(value)]: [Value; 2] = args.try_into().unwrap() + else { + panic!() + }; + + if value + < Felt::from_dec_str( + "3618502788666131106986593281521497120414687020801267626233049500247285301248", + ) + .unwrap() + { + EvalAction::NormalBranch(0, smallvec![range_check, Value::Felt(value)]) + } else { + EvalAction::NormalBranch(1, smallvec![range_check]) + } +} + fn eval_contract_address_try_from_felt( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, @@ -114,6 +158,15 @@ fn eval_contract_address_try_from_felt( } } +fn eval_storage_base_address_from_felt( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check, value] = args.try_into().unwrap(); + EvalAction::NormalBranch(0, smallvec![range_check, value]) +} + fn eval_storage_address_to_felt( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, @@ -123,6 +176,24 @@ fn eval_storage_address_to_felt( EvalAction::NormalBranch(0, smallvec![value]) } +fn eval_contract_address_to_felt( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [value] = args.try_into().unwrap(); + EvalAction::NormalBranch(0, smallvec![value]) +} + +fn eval_class_hash_to_felt( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [value] = args.try_into().unwrap(); + EvalAction::NormalBranch(0, smallvec![value]) +} + fn eval_storage_address_from_base( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, @@ -132,6 +203,18 @@ fn eval_storage_address_from_base( EvalAction::NormalBranch(0, smallvec![value]) } +fn eval_storage_address_from_base_and_offset( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::Felt(value), Value::U8(offset)]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + + EvalAction::NormalBranch(0, smallvec![Value::Felt(value + Felt::from(offset))]) +} + fn eval_call_contract( registry: &ProgramRegistry, info: &SignatureOnlyConcreteLibfunc, From b46061470f64852265bc6a9ae20030ec3e85337a Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Fri, 16 Aug 2024 11:59:06 +0200 Subject: [PATCH 07/40] progress --- src/vm/starknet.rs | 279 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 224 insertions(+), 55 deletions(-) diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index e799665..9e2ed56 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -62,14 +62,20 @@ pub fn eval( StarkNetConcreteLibfunc::StorageAddressToFelt252(info) => { eval_storage_address_to_felt(registry, info, args) } - StarkNetConcreteLibfunc::StorageAddressTryFromFelt252(_) => todo!(), - StarkNetConcreteLibfunc::EmitEvent(info) => eval_emit_event(registry, info, args), - StarkNetConcreteLibfunc::GetBlockHash(info) => eval_get_block_hash(registry, info, args), + StarkNetConcreteLibfunc::StorageAddressTryFromFelt252(info) => { + eval_storage_address_try_from_felt(registry, info, args) + } + StarkNetConcreteLibfunc::EmitEvent(info) => { + eval_emit_event(registry, info, args, syscall_handler) + } + StarkNetConcreteLibfunc::GetBlockHash(info) => { + eval_get_block_hash(registry, info, args, syscall_handler) + } StarkNetConcreteLibfunc::GetExecutionInfo(info) => { - eval_get_execution_info(registry, info, args) + eval_get_execution_info(registry, info, args, syscall_handler) } StarkNetConcreteLibfunc::GetExecutionInfoV2(info) => { - eval_get_execution_info_v2(registry, info, args) + eval_get_execution_info_v2(registry, info, args, syscall_handler) } StarkNetConcreteLibfunc::Deploy(info) => eval_deploy(registry, info, args), StarkNetConcreteLibfunc::Keccak(info) => eval_keccak(registry, info, args), @@ -158,6 +164,30 @@ fn eval_contract_address_try_from_felt( } } +fn eval_storage_address_try_from_felt( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + // 2 ** 251 = 3618502788666131106986593281521497120414687020801267626233049500247285301248 + + let [range_check @ Value::Unit, Value::Felt(value)]: [Value; 2] = args.try_into().unwrap() + else { + panic!() + }; + + if value + < Felt::from_dec_str( + "3618502788666131106986593281521497120414687020801267626233049500247285301248", + ) + .unwrap() + { + EvalAction::NormalBranch(0, smallvec![range_check, Value::Felt(value)]) + } else { + EvalAction::NormalBranch(1, smallvec![range_check]) + } +} + fn eval_storage_base_address_from_felt( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, @@ -229,7 +259,9 @@ fn eval_storage_read( args: Vec, syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - let args: [Value; 4] = args.try_into().unwrap(); + let [Value::U128(mut gas), system, Value::U32(address_domain), Value::Felt(storage_key)]: [Value; 4] = args.try_into().unwrap() else { + panic!() + }; let error_felt_ty = { match registry .get_type(&info.branch_signatures()[1].vars[2].ty) @@ -240,29 +272,23 @@ fn eval_storage_read( } }; - match args { - [Value::U128(mut gas), system, Value::U32(address_domain), Value::Felt(storage_key)] => { - let result = syscall_handler.storage_read(address_domain, storage_key, &mut gas); - - match result { - Ok(value) => EvalAction::NormalBranch( - 0, - smallvec![Value::U128(gas), system, Value::Felt(value)], - ), - Err(e) => EvalAction::NormalBranch( - 1, - smallvec![ - Value::U128(gas), - system, - Value::Array { - ty: error_felt_ty, - data: e.into_iter().map(Value::Felt).collect::>(), - } - ], - ), - } + let result = syscall_handler.storage_read(address_domain, storage_key, &mut gas); + + match result { + Ok(value) => { + EvalAction::NormalBranch(0, smallvec![Value::U128(gas), system, Value::Felt(value)]) } - _ => panic!(), + Err(e) => EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: error_felt_ty, + data: e.into_iter().map(Value::Felt).collect::>(), + } + ], + ), } } @@ -272,7 +298,9 @@ fn eval_storage_write( args: Vec, syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - let args: [Value; 5] = args.try_into().unwrap(); + let [Value::U128(mut gas), system, Value::U32(address_domain), Value::Felt(storage_key), Value::Felt(value)]: [Value; 5] = args.try_into().unwrap() else { + panic!() + }; let error_felt_ty = { match registry .get_type(&info.branch_signatures()[1].vars[2].ty) @@ -283,28 +311,21 @@ fn eval_storage_write( } }; - match args { - [Value::U128(mut gas), system, Value::U32(address_domain), Value::Felt(storage_key), Value::Felt(value)] => - { - let result = - syscall_handler.storage_write(address_domain, storage_key, value, &mut gas); - - match result { - Ok(_) => EvalAction::NormalBranch(0, smallvec![Value::U128(gas), system]), - Err(e) => EvalAction::NormalBranch( - 1, - smallvec![ - Value::U128(gas), - system, - Value::Array { - ty: error_felt_ty, - data: e.into_iter().map(Value::Felt).collect::>(), - } - ], - ), - } - } - _ => panic!(), + let result = syscall_handler.storage_write(address_domain, storage_key, value, &mut gas); + + match result { + Ok(_) => EvalAction::NormalBranch(0, smallvec![Value::U128(gas), system]), + Err(e) => EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: error_felt_ty, + data: e.into_iter().map(Value::Felt).collect::>(), + } + ], + ), } } @@ -312,32 +333,180 @@ fn eval_emit_event( registry: &ProgramRegistry, info: &SignatureOnlyConcreteLibfunc, args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - todo!() + let [Value::U128(mut gas), system, Value::Array { ty: _, data: keys }, Value::Array { ty: _, data }]: [Value; 4] = args.try_into().unwrap() else { + panic!() + }; + + let error_felt_ty = { + match registry + .get_type(&info.branch_signatures()[1].vars[2].ty) + .unwrap() + { + CoreTypeConcrete::Array(info) => info.ty.clone(), + _ => unreachable!(), + } + }; + + let keys = keys + .into_iter() + .map(|x| match x { + Value::Felt(x) => x, + _ => unreachable!(), + }) + .collect(); + let data = data + .into_iter() + .map(|x| match x { + Value::Felt(x) => x, + _ => unreachable!(), + }) + .collect(); + + let result = syscall_handler.emit_event(keys, data, &mut gas); + + match result { + Ok(_) => EvalAction::NormalBranch(0, smallvec![Value::U128(gas), system]), + Err(e) => EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: error_felt_ty, + data: e.into_iter().map(Value::Felt).collect::>(), + } + ], + ), + } } fn eval_get_block_hash( registry: &ProgramRegistry, info: &SignatureOnlyConcreteLibfunc, args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - todo!() + let [Value::U128(mut gas), system, Value::U64(block_number)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + let error_felt_ty = { + match registry + .get_type(&info.branch_signatures()[1].vars[2].ty) + .unwrap() + { + CoreTypeConcrete::Array(info) => info.ty.clone(), + _ => unreachable!(), + } + }; + + let result = syscall_handler.get_block_hash(block_number, &mut gas); + + match result { + Ok(res) => { + EvalAction::NormalBranch(0, smallvec![Value::U128(gas), system, Value::Felt(res)]) + } + Err(e) => EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: error_felt_ty, + data: e.into_iter().map(Value::Felt).collect::>(), + } + ], + ), + } } fn eval_get_execution_info( registry: &ProgramRegistry, info: &SignatureOnlyConcreteLibfunc, args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - todo!() + let [Value::U128(mut gas), system]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + // 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 result = syscall_handler.get_execution_info(&mut gas); + + match result { + Ok(res) => EvalAction::NormalBranch( + 0, + smallvec![Value::U128(gas), system, res.into_value(felt_ty)], + ), + Err(e) => EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: felt_ty, + data: e.into_iter().map(Value::Felt).collect::>(), + } + ], + ), + } } fn eval_get_execution_info_v2( registry: &ProgramRegistry, info: &SignatureOnlyConcreteLibfunc, args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - todo!() + let [Value::U128(mut gas), system]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + // 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 result = syscall_handler.get_execution_info_v2(&mut gas); + + let out_ty = registry + .get_type(&info.branch_signatures()[0].vars[2].ty) + .unwrap(); + + match result { + Ok(res) => EvalAction::NormalBranch( + 0, + smallvec![Value::U128(gas), system, res.into_value(felt_ty)], + ), + Err(e) => EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: felt_ty, + data: e.into_iter().map(Value::Felt).collect::>(), + } + ], + ), + } } fn eval_deploy( From 257fc8f2fd794a8b8e6747a08539f2413f440d2e Mon Sep 17 00:00:00 2001 From: Edgar Date: Fri, 16 Aug 2024 15:42:32 +0200 Subject: [PATCH 08/40] temp progress --- src/vm/starknet.rs | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index 9e2ed56..b11e6f7 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -335,7 +335,18 @@ fn eval_emit_event( args: Vec, syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - let [Value::U128(mut gas), system, Value::Array { ty: _, data: keys }, Value::Array { ty: _, data }]: [Value; 4] = args.try_into().unwrap() else { + dbg!(&args); + let [Value::U128(mut gas), system, Value::Struct(key_arr), Value::Struct(data_arr)]: [Value; + 4] = args.try_into().unwrap() + else { + panic!() + }; + + let [Value::Array { ty: _, data: keys }]: [Value; 1] = key_arr.try_into().unwrap() else { + panic!() + }; + + let [Value::Array { ty: _, data }]: [Value; 1] = data_arr.try_into().unwrap() else { panic!() }; @@ -490,10 +501,24 @@ fn eval_get_execution_info_v2( .get_type(&info.branch_signatures()[0].vars[2].ty) .unwrap(); + let out_ty = if let CoreTypeConcrete::Struct(inner) = out_ty { + let out_ty = registry.get_type(&inner.members[1]).unwrap(); + + if let CoreTypeConcrete::Struct(inner) = out_ty { + let out_ty = registry.get_type(&inner.members[7]).unwrap(); + dbg!(inner.members[7].debug_name.as_ref()); + inner.members[7].clone() + } else { + panic!() + } + } else { + panic!() + }; + match result { Ok(res) => EvalAction::NormalBranch( 0, - smallvec![Value::U128(gas), system, res.into_value(felt_ty)], + smallvec![Value::U128(gas), system, res.into_value(felt_ty, out_ty)], ), Err(e) => EvalAction::NormalBranch( 1, From 7ccfcb6bf24cdcc91556d8ec458e5fb795f0f71d Mon Sep 17 00:00:00 2001 From: Edgar Date: Fri, 16 Aug 2024 15:52:12 +0200 Subject: [PATCH 09/40] progress --- src/value.rs | 4 +- src/vm.rs | 3 +- src/vm/felt252.rs | 20 ++++++++- src/vm/u128.rs | 105 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 src/vm/u128.rs diff --git a/src/value.rs b/src/value.rs index f94d5df..5c4fb21 100644 --- a/src/value.rs +++ b/src/value.rs @@ -108,9 +108,9 @@ impl Value { CoreTypeConcrete::EcPoint(_) => todo!(), CoreTypeConcrete::EcState(_) => todo!(), CoreTypeConcrete::BuiltinCosts(_) => matches!(self, Self::Unit), - CoreTypeConcrete::Uint16(_) => todo!(), + CoreTypeConcrete::Uint16(_) => matches!(self, Self::U16(_)), CoreTypeConcrete::Uint64(_) => matches!(self, Self::U64(_)), - CoreTypeConcrete::Uint128(_) => todo!(), + CoreTypeConcrete::Uint128(_) => matches!(self, Self::U128(_)), CoreTypeConcrete::Uint128MulGuarantee(_) => matches!(self, Self::Unit), CoreTypeConcrete::Sint16(_) => todo!(), CoreTypeConcrete::Sint32(_) => todo!(), diff --git a/src/vm.rs b/src/vm.rs index 550603d..baa3484 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -40,6 +40,7 @@ mod poseidon; mod snapshot_take; mod starknet; mod r#struct; +mod u128; mod uint32; mod uint64; mod uint8; @@ -312,7 +313,7 @@ fn eval<'a>( self::starknet::eval(registry, selector, args, syscall_handler) } CoreConcreteLibfunc::Struct(selector) => self::r#struct::eval(registry, selector, args), - CoreConcreteLibfunc::Uint128(_) => todo!(), + CoreConcreteLibfunc::Uint128(selector) => self::u128::eval(registry, selector, args), CoreConcreteLibfunc::Uint16(_) => todo!(), CoreConcreteLibfunc::Uint256(_) => todo!(), CoreConcreteLibfunc::Uint32(selector) => self::uint32::eval(registry, selector, args), diff --git a/src/vm/felt252.rs b/src/vm/felt252.rs index 8d21599..00c0c84 100644 --- a/src/vm/felt252.rs +++ b/src/vm/felt252.rs @@ -7,10 +7,12 @@ use cairo_lang_sierra::{ Felt252BinaryOperationConcrete, Felt252BinaryOperator, Felt252Concrete, Felt252ConstConcreteLibfunc, }, + lib_func::SignatureOnlyConcreteLibfunc, }, program_registry::ProgramRegistry, }; use smallvec::smallvec; +use starknet_crypto::Felt; pub fn eval( registry: &ProgramRegistry, @@ -20,7 +22,7 @@ pub fn eval( match selector { Felt252Concrete::BinaryOperation(info) => eval_operation(registry, info, args), Felt252Concrete::Const(info) => eval_const(registry, info, args), - Felt252Concrete::IsZero(_) => todo!(), + Felt252Concrete::IsZero(info) => eval_felt_is_zero(registry, info, args), } } @@ -55,3 +57,19 @@ pub fn eval_const( ) -> EvalAction { EvalAction::NormalBranch(0, smallvec![Value::Felt(info.c.clone().into())]) } + +pub fn eval_felt_is_zero( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::Felt(value)]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + if value == Felt::ZERO { + EvalAction::NormalBranch(0, smallvec![]) + } else { + EvalAction::NormalBranch(1, smallvec![Value::Felt(value)]) + } +} diff --git a/src/vm/u128.rs b/src/vm/u128.rs new file mode 100644 index 0000000..f648a23 --- /dev/null +++ b/src/vm/u128.rs @@ -0,0 +1,105 @@ +use super::EvalAction; +use crate::Value; +use cairo_lang_sierra::{ + extensions::{ + core::{CoreLibfunc, CoreType}, + int::{ + unsigned128::{Uint128Concrete, Uint128Traits}, + IntConstConcreteLibfunc, IntOperationConcreteLibfunc, IntOperator, + }, + lib_func::SignatureOnlyConcreteLibfunc, + }, + program_registry::ProgramRegistry, +}; +use smallvec::smallvec; + +pub fn eval( + registry: &ProgramRegistry, + selector: &Uint128Concrete, + args: Vec, +) -> EvalAction { + match selector { + Uint128Concrete::Const(info) => eval_const(registry, info, args), + Uint128Concrete::Operation(info) => eval_operation(registry, info, args), + Uint128Concrete::SquareRoot(_) => todo!(), + Uint128Concrete::Equal(info) => eval_equal(registry, info, args), + Uint128Concrete::ToFelt252(info) => eval_to_felt(registry, info, args), + Uint128Concrete::FromFelt252(_) => todo!(), + Uint128Concrete::IsZero(info) => eval_is_zero(registry, info, args), + Uint128Concrete::Divmod(_) => todo!(), + Uint128Concrete::Bitwise(_) => todo!(), + Uint128Concrete::GuaranteeMul(_) => todo!(), + Uint128Concrete::MulGuaranteeVerify(_) => todo!(), + Uint128Concrete::ByteReverse(_) => todo!(), + } +} + +pub fn eval_operation( + _registry: &ProgramRegistry, + info: &IntOperationConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::U128(lhs), Value::U128(rhs)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let (result, has_overflow) = match info.operator { + IntOperator::OverflowingAdd => lhs.overflowing_add(rhs), + IntOperator::OverflowingSub => lhs.overflowing_sub(rhs), + }; + + EvalAction::NormalBranch( + has_overflow as usize, + smallvec![range_check, Value::U128(result)], + ) +} + +pub fn eval_equal( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::U128(lhs), Value::U128(rhs)]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + + EvalAction::NormalBranch((lhs != rhs) as usize, smallvec![]) +} + +pub fn eval_is_zero( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [vm_value @ Value::U128(value)]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + if value == 0 { + EvalAction::NormalBranch(0, smallvec![]) + } else { + EvalAction::NormalBranch(1, smallvec![vm_value]) + } +} + +pub fn eval_const( + _registry: &ProgramRegistry, + info: &IntConstConcreteLibfunc, + _args: Vec, +) -> EvalAction { + EvalAction::NormalBranch(0, smallvec![Value::U128(info.c)]) +} + +pub fn eval_to_felt( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::U128(value)]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + EvalAction::NormalBranch(0, smallvec![Value::Felt(value.into())]) +} From e3182e6685fe78a5f73496daa62a3f475064129d Mon Sep 17 00:00:00 2001 From: Edgar Date: Fri, 16 Aug 2024 16:05:22 +0200 Subject: [PATCH 10/40] progress --- src/vm.rs | 3 ++- src/vm/bool.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++ src/vm/starknet.rs | 1 - 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 src/vm/bool.rs diff --git a/src/vm.rs b/src/vm.rs index baa3484..d09bcaf 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -20,6 +20,7 @@ use tracing::debug; mod ap_tracking; mod array; +mod bool; mod bounded_int; mod r#box; mod branch_align; @@ -273,7 +274,7 @@ fn eval<'a>( self::ap_tracking::eval(registry, selector, args) } CoreConcreteLibfunc::Array(selector) => self::array::eval(registry, selector, args), - CoreConcreteLibfunc::Bool(_) => todo!(), + CoreConcreteLibfunc::Bool(selector) => self::bool::eval(registry, selector, args), CoreConcreteLibfunc::BoundedInt(selector) => { self::bounded_int::eval(registry, selector, args) } diff --git a/src/vm/bool.rs b/src/vm/bool.rs new file mode 100644 index 0000000..b37e289 --- /dev/null +++ b/src/vm/bool.rs @@ -0,0 +1,54 @@ +use super::EvalAction; +use crate::Value; +use cairo_lang_sierra::{ + extensions::{ + boolean::BoolConcreteLibfunc, + core::{CoreLibfunc, CoreType}, + lib_func::{SignatureAndTypeConcreteLibfunc, SignatureOnlyConcreteLibfunc}, + }, + program_registry::ProgramRegistry, +}; +use smallvec::smallvec; + +pub fn eval( + registry: &ProgramRegistry, + selector: &BoolConcreteLibfunc, + args: Vec, +) -> EvalAction { + match selector { + BoolConcreteLibfunc::And(info) => eval_and(registry, info, args), + BoolConcreteLibfunc::Not(_) => todo!(), + BoolConcreteLibfunc::Xor(_) => todo!(), + BoolConcreteLibfunc::Or(_) => todo!(), + BoolConcreteLibfunc::ToFelt252(_) => todo!(), + } +} + +pub fn eval_and( + _registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + dbg!(&args); + let [Value::Enum { + self_ty, + index: lhs, + payload, + }, Value::Enum { + self_ty: _, + index: rhs, + payload: _, + }]: [Value; 2] = args.try_into().unwrap() + else { + panic!() + }; + + EvalAction::NormalBranch( + 0, + smallvec![Value::Enum { + self_ty, + index: lhs & rhs, + payload + }], + ) +} diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index b11e6f7..74f5ae6 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -335,7 +335,6 @@ fn eval_emit_event( args: Vec, syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - dbg!(&args); let [Value::U128(mut gas), system, Value::Struct(key_arr), Value::Struct(data_arr)]: [Value; 4] = args.try_into().unwrap() else { From c2f7da55a4db1756bc32f4e9c991594436559910 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 19 Aug 2024 08:35:44 +0200 Subject: [PATCH 11/40] add makefile --- .gitignore | 6 +++ Makefile | 63 ++++++++++++++++++++++++++++++++ scripts/check-corelib-version.sh | 10 +++++ src/main.rs | 4 +- 4 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 Makefile create mode 100755 scripts/check-corelib-version.sh diff --git a/.gitignore b/.gitignore index 389159a..9ad5fc0 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,9 @@ Cargo.lock *.pdb # End of https://www.toptal.com/developers/gitignore/api/rust + +cairo2/ + +corelib + +*.tar diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cbad790 --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +.PHONY: deps build needs-cairo2 deps-macos build-cairo-2-compiler-macos decompress-cairo install-scarb clean + +UNAME := $(shell uname) + +CAIRO_2_VERSION=2.7.0 +SCARB_VERSION = 2.7.0 + +needs-cairo2: +ifeq ($(wildcard ./cairo2/.),) + $(error You are missing the Starknet Cairo 1 compiler, please run 'make deps' to install the necessary dependencies.) +endif + ./scripts/check-corelib-version.sh $(CAIRO_2_VERSION) + +build: + cargo build --release --all-features + +test: needs-cairo2 + cargo test --all-features + +clean: + cargo clean + +deps: +ifeq ($(UNAME), Linux) +deps: build-cairo-2-compiler install-scarb +endif +ifeq ($(UNAME), Darwin) +deps: deps-macos +endif + -rm -rf corelib + -ln -s cairo2/corelib corelib + +deps-macos: build-cairo-2-compiler-macos install-scarb-macos + +cairo-repo-2-dir = cairo2 +cairo-repo-2-dir-macos = cairo2-macos + +build-cairo-2-compiler-macos: | $(cairo-repo-2-dir-macos) + +$(cairo-repo-2-dir-macos): cairo-${CAIRO_2_VERSION}-macos.tar + $(MAKE) decompress-cairo SOURCE=$< TARGET=cairo2/ + +build-cairo-2-compiler: | $(cairo-repo-2-dir) + +$(cairo-repo-2-dir): cairo-${CAIRO_2_VERSION}.tar + $(MAKE) decompress-cairo SOURCE=$< TARGET=cairo2/ + +decompress-cairo: + rm -rf $(TARGET) \ + && tar -xzvf $(SOURCE) \ + && mv cairo/ $(TARGET) + +cairo-%-macos.tar: + curl -L -o "$@" "https://github.com/starkware-libs/cairo/releases/download/v$*/release-aarch64-apple-darwin.tar" + +cairo-%.tar: + curl -L -o "$@" "https://github.com/starkware-libs/cairo/releases/download/v$*/release-x86_64-unknown-linux-musl.tar.gz" + +install-scarb: + curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh| sh -s -- --no-modify-path --version $(SCARB_VERSION) + +install-scarb-macos: + curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh| sh -s -- --version $(SCARB_VERSION) diff --git a/scripts/check-corelib-version.sh b/scripts/check-corelib-version.sh new file mode 100755 index 0000000..2458d67 --- /dev/null +++ b/scripts/check-corelib-version.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +# Script to check the corelib version matches. + +_result=$(grep "version = \"$1\"" corelib/Scarb.toml) + +if [ $? -ne 0 ]; then + echo "corelib version mismatch, please re-run 'make deps'" + exit 1 +fi diff --git a/src/main.rs b/src/main.rs index 1b751c8..7c1c21f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -171,8 +171,8 @@ mod test { trace.push(StateDump::new(statement_idx, state)); } - // let trace_str = serde_json::to_string_pretty(&trace).unwrap(); - // std::fs::write("contract_trace.json", trace_str).unwrap(); + let trace_str = serde_json::to_string_pretty(&trace).unwrap(); + std::fs::write("contract_trace.json", trace_str).unwrap(); } pub fn find_entry_point_by_idx( From 18b4fcdb29e72ac332207a85df2f2489616ba69c Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 19 Aug 2024 08:37:17 +0200 Subject: [PATCH 12/40] improve makefile --- Makefile | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cbad790..d55a67a 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: deps build needs-cairo2 deps-macos build-cairo-2-compiler-macos decompress-cairo install-scarb clean +.PHONY: usage deps build check needs-cairo2 deps-macos build-cairo-2-compiler-macos decompress-cairo install-scarb clean UNAME := $(shell uname) @@ -11,9 +11,21 @@ ifeq ($(wildcard ./cairo2/.),) endif ./scripts/check-corelib-version.sh $(CAIRO_2_VERSION) +usage: + @echo "Usage:" + @echo " deps: Installs the necesarry dependencies." + @echo " build: Builds the cairo-native library and binaries." + @echo " check: Checks format and lints." + @echo " test: Runs all tests." + @echo " clean: Cleans the built artifacts." + build: cargo build --release --all-features +check: check-llvm + cargo fmt --all -- --check + cargo clippy --all-targets --all-features -- -D warnings + test: needs-cairo2 cargo test --all-features From fce18dacaf64c7ea7e29ef9b7bce7cda6590f550 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 19 Aug 2024 08:38:26 +0200 Subject: [PATCH 13/40] gitignore json --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 9ad5fc0..041d014 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ cairo2/ corelib *.tar + +*.json From adaa8fdbf8cb25af4374c2952487251e6fce40db Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 19 Aug 2024 08:40:42 +0200 Subject: [PATCH 14/40] basic ci --- .github/workflows/ci.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2b88dcd --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,24 @@ +name: Test + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Retreive cached dependecies + uses: Swatinem/rust-cache@v2 + - name: Build + run: cargo build --all-features --verbose + - name: Run tests + run: cargo test --all-features --verbose From 8e4589c516091a1cee854257c0d9c52218d6479d Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 19 Aug 2024 09:05:26 +0200 Subject: [PATCH 15/40] implement bool libfuncs --- src/vm/bool.rs | 108 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 6 deletions(-) diff --git a/src/vm/bool.rs b/src/vm/bool.rs index b37e289..ffb5d73 100644 --- a/src/vm/bool.rs +++ b/src/vm/bool.rs @@ -17,19 +17,18 @@ pub fn eval( ) -> EvalAction { match selector { BoolConcreteLibfunc::And(info) => eval_and(registry, info, args), - BoolConcreteLibfunc::Not(_) => todo!(), - BoolConcreteLibfunc::Xor(_) => todo!(), - BoolConcreteLibfunc::Or(_) => todo!(), - BoolConcreteLibfunc::ToFelt252(_) => todo!(), + BoolConcreteLibfunc::Not(info) => eval_not(registry, info, args), + BoolConcreteLibfunc::Xor(info) => eval_xor(registry, info, args), + BoolConcreteLibfunc::Or(info) => eval_or(registry, info, args), + BoolConcreteLibfunc::ToFelt252(info) => eval_to_felt252(registry, info, args), } } pub fn eval_and( _registry: &ProgramRegistry, - info: &SignatureOnlyConcreteLibfunc, + _info: &SignatureOnlyConcreteLibfunc, args: Vec, ) -> EvalAction { - dbg!(&args); let [Value::Enum { self_ty, index: lhs, @@ -52,3 +51,100 @@ pub fn eval_and( }], ) } + +pub fn eval_not( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::Enum { + self_ty, + index: lhs, + payload, + }]: [Value; 1] = args.try_into().unwrap() + else { + panic!() + }; + + EvalAction::NormalBranch( + 0, + smallvec![Value::Enum { + self_ty, + index: !lhs, + payload + }], + ) +} + +pub fn eval_xor( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::Enum { + self_ty, + index: lhs, + payload, + }, Value::Enum { + self_ty: _, + index: rhs, + payload: _, + }]: [Value; 2] = args.try_into().unwrap() + else { + panic!() + }; + + EvalAction::NormalBranch( + 0, + smallvec![Value::Enum { + self_ty, + index: lhs ^ rhs, + payload + }], + ) +} + +pub fn eval_or( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::Enum { + self_ty, + index: lhs, + payload, + }, Value::Enum { + self_ty: _, + index: rhs, + payload: _, + }]: [Value; 2] = args.try_into().unwrap() + else { + panic!() + }; + + EvalAction::NormalBranch( + 0, + smallvec![Value::Enum { + self_ty, + index: lhs | rhs, + payload + }], + ) +} + +pub fn eval_to_felt252( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::Enum { + self_ty: _, + index: lhs, + payload: _, + }]: [Value; 1] = args.try_into().unwrap() + else { + panic!() + }; + + EvalAction::NormalBranch(0, smallvec![Value::Felt(lhs.into())]) +} From 9bad2a748b7c3e862bcc1193eec9e9d10440a4c8 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 19 Aug 2024 09:06:07 +0200 Subject: [PATCH 16/40] fix ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2b88dcd..76e5db7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,4 +21,4 @@ jobs: - name: Build run: cargo build --all-features --verbose - name: Run tests - run: cargo test --all-features --verbose + run: make test From 9ff8001f23cdce84f6b95ae76758ad63843609b4 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 19 Aug 2024 09:31:30 +0200 Subject: [PATCH 17/40] fix bool libfuncs --- src/vm/bool.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/vm/bool.rs b/src/vm/bool.rs index ffb5d73..d98fa8a 100644 --- a/src/vm/bool.rs +++ b/src/vm/bool.rs @@ -42,11 +42,14 @@ pub fn eval_and( panic!() }; + let lhs = lhs != 0; + let rhs = rhs != 0; + EvalAction::NormalBranch( 0, smallvec![Value::Enum { self_ty, - index: lhs & rhs, + index: (lhs && rhs) as usize, payload }], ) @@ -70,7 +73,7 @@ pub fn eval_not( 0, smallvec![Value::Enum { self_ty, - index: !lhs, + index: (lhs == 0) as usize, payload }], ) @@ -94,11 +97,14 @@ pub fn eval_xor( panic!() }; + let lhs = lhs != 0; + let rhs = rhs != 0; + EvalAction::NormalBranch( 0, smallvec![Value::Enum { self_ty, - index: lhs ^ rhs, + index: (lhs ^ rhs) as usize, payload }], ) @@ -122,11 +128,14 @@ pub fn eval_or( panic!() }; + let lhs = lhs != 0; + let rhs = rhs != 0; + EvalAction::NormalBranch( 0, smallvec![Value::Enum { self_ty, - index: lhs | rhs, + index: (lhs || rhs) as usize, payload }], ) From 3363eb153330a23db9291f65684abbcc50509f60 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 19 Aug 2024 09:32:18 +0200 Subject: [PATCH 18/40] fix ci again --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76e5db7..f070cbe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,6 +18,8 @@ jobs: - uses: actions/checkout@v4 - name: Retreive cached dependecies uses: Swatinem/rust-cache@v2 + - name: Deps + run: make deps - name: Build run: cargo build --all-features --verbose - name: Run tests From f5358b51137a6225b246ff333c0803f5ea47e638 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 19 Aug 2024 09:40:57 +0200 Subject: [PATCH 19/40] u128 from felt --- src/vm/u128.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/vm/u128.rs b/src/vm/u128.rs index f648a23..ca618df 100644 --- a/src/vm/u128.rs +++ b/src/vm/u128.rs @@ -12,6 +12,7 @@ use cairo_lang_sierra::{ program_registry::ProgramRegistry, }; use smallvec::smallvec; +use starknet_crypto::Felt; pub fn eval( registry: &ProgramRegistry, @@ -24,7 +25,7 @@ pub fn eval( Uint128Concrete::SquareRoot(_) => todo!(), Uint128Concrete::Equal(info) => eval_equal(registry, info, args), Uint128Concrete::ToFelt252(info) => eval_to_felt(registry, info, args), - Uint128Concrete::FromFelt252(_) => todo!(), + Uint128Concrete::FromFelt252(info) => eval_from_felt(registry, info, args), Uint128Concrete::IsZero(info) => eval_is_zero(registry, info, args), Uint128Concrete::Divmod(_) => todo!(), Uint128Concrete::Bitwise(_) => todo!(), @@ -103,3 +104,28 @@ pub fn eval_to_felt( EvalAction::NormalBranch(0, smallvec![Value::Felt(value.into())]) } + +pub fn eval_from_felt( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::Felt(value)]: [Value; 2] = args.try_into().unwrap() + else { + panic!() + }; + + let max = Felt::from(u128::MAX); + + if value <= max { + let value: u128 = value.to_biguint().try_into().unwrap(); + EvalAction::NormalBranch(0, smallvec![range_check, Value::U128(value)]) + } else { + let overflow: u128 = (value - max).to_biguint().try_into().unwrap(); + let value: u128 = max.to_biguint().try_into().unwrap(); + EvalAction::NormalBranch( + 1, + smallvec![range_check, Value::U128(value), Value::U128(overflow)], + ) + } +} From d9c410addbe56ec72195c1639504e059e8eb6fc5 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 19 Aug 2024 09:53:25 +0200 Subject: [PATCH 20/40] fixes --- Makefile | 2 +- src/main.rs | 6 +++-- src/starknet/secp256k1_point.rs | 1 + src/starknet/secp256r1_point.rs | 1 + src/starknet/u256.rs | 1 + src/vm.rs | 2 +- src/vm/bool.rs | 2 +- src/vm/starknet.rs | 43 ++++++++++++++++----------------- 8 files changed, 31 insertions(+), 27 deletions(-) diff --git a/Makefile b/Makefile index d55a67a..8ffeb61 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ usage: build: cargo build --release --all-features -check: check-llvm +check: cargo fmt --all -- --check cargo clippy --all-targets --all-features -- -D warnings diff --git a/src/main.rs b/src/main.rs index 7c1c21f..38976f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -171,8 +171,10 @@ mod test { trace.push(StateDump::new(statement_idx, state)); } - let trace_str = serde_json::to_string_pretty(&trace).unwrap(); - std::fs::write("contract_trace.json", trace_str).unwrap(); + assert!(!vm.syscall_handler.storage.is_empty()); + + // let trace_str = serde_json::to_string_pretty(&trace).unwrap(); + // std::fs::write("contract_trace.json", trace_str).unwrap(); } pub fn find_entry_point_by_idx( diff --git a/src/starknet/secp256k1_point.rs b/src/starknet/secp256k1_point.rs index ad0183e..bbac4df 100644 --- a/src/starknet/secp256k1_point.rs +++ b/src/starknet/secp256k1_point.rs @@ -8,6 +8,7 @@ pub struct Secp256k1Point { } impl Secp256k1Point { + #[allow(unused)] pub(crate) fn into_value(self) -> Value { Value::Struct(vec![ Value::U256(self.x.lo, self.x.hi), diff --git a/src/starknet/secp256r1_point.rs b/src/starknet/secp256r1_point.rs index d5a5761..8548ef0 100644 --- a/src/starknet/secp256r1_point.rs +++ b/src/starknet/secp256r1_point.rs @@ -8,6 +8,7 @@ pub struct Secp256r1Point { } impl Secp256r1Point { + #[allow(unused)] pub(crate) fn into_value(self) -> Value { Value::Struct(vec![ Value::U256(self.x.lo, self.x.hi), diff --git a/src/starknet/u256.rs b/src/starknet/u256.rs index 5758ee7..da9c75e 100644 --- a/src/starknet/u256.rs +++ b/src/starknet/u256.rs @@ -7,6 +7,7 @@ pub struct U256 { } impl U256 { + #[allow(unused)] pub(crate) fn into_value(self) -> Value { Value::Struct(vec![Value::U128(self.lo), Value::U128(self.hi)]) } diff --git a/src/vm.rs b/src/vm.rs index d09bcaf..225c448 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -49,7 +49,7 @@ mod uint8; pub struct VirtualMachine { program: Arc, registry: ProgramRegistry, - syscall_handler: S, + pub syscall_handler: S, frames: Vec, } diff --git a/src/vm/bool.rs b/src/vm/bool.rs index d98fa8a..8d63295 100644 --- a/src/vm/bool.rs +++ b/src/vm/bool.rs @@ -4,7 +4,7 @@ use cairo_lang_sierra::{ extensions::{ boolean::BoolConcreteLibfunc, core::{CoreLibfunc, CoreType}, - lib_func::{SignatureAndTypeConcreteLibfunc, SignatureOnlyConcreteLibfunc}, + lib_func::SignatureOnlyConcreteLibfunc, }, program_registry::ProgramRegistry, }; diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index 74f5ae6..2b1febe 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -87,8 +87,8 @@ pub fn eval( StarkNetConcreteLibfunc::SendMessageToL1(info) => { eval_send_message_to_l1(registry, info, args) } - StarkNetConcreteLibfunc::Testing(info) => todo!(), - StarkNetConcreteLibfunc::Secp256(info) => todo!(), + StarkNetConcreteLibfunc::Testing(_info) => todo!(), + StarkNetConcreteLibfunc::Secp256(_info) => todo!(), } } @@ -246,9 +246,9 @@ fn eval_storage_address_from_base_and_offset( } fn eval_call_contract( - registry: &ProgramRegistry, - info: &SignatureOnlyConcreteLibfunc, - args: Vec, + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + _args: Vec, ) -> EvalAction { todo!() } @@ -504,8 +504,7 @@ fn eval_get_execution_info_v2( let out_ty = registry.get_type(&inner.members[1]).unwrap(); if let CoreTypeConcrete::Struct(inner) = out_ty { - let out_ty = registry.get_type(&inner.members[7]).unwrap(); - dbg!(inner.members[7].debug_name.as_ref()); + // should be resourcebound ty inner.members[7].clone() } else { panic!() @@ -534,41 +533,41 @@ fn eval_get_execution_info_v2( } fn eval_deploy( - registry: &ProgramRegistry, - info: &SignatureOnlyConcreteLibfunc, - args: Vec, + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + _args: Vec, ) -> EvalAction { todo!() } fn eval_keccak( - registry: &ProgramRegistry, - info: &SignatureOnlyConcreteLibfunc, - args: Vec, + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + _args: Vec, ) -> EvalAction { todo!() } fn eval_library_call( - registry: &ProgramRegistry, - info: &SignatureOnlyConcreteLibfunc, - args: Vec, + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + _args: Vec, ) -> EvalAction { todo!() } fn eval_replace_class( - registry: &ProgramRegistry, - info: &SignatureOnlyConcreteLibfunc, - args: Vec, + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + _args: Vec, ) -> EvalAction { todo!() } fn eval_send_message_to_l1( - registry: &ProgramRegistry, - info: &SignatureOnlyConcreteLibfunc, - args: Vec, + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + _args: Vec, ) -> EvalAction { todo!() } From c23c8838a0bd6d53378949cec89ad0a05bc113f0 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 19 Aug 2024 10:10:09 +0200 Subject: [PATCH 21/40] add contract execution result --- src/dump.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 7 +++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/dump.rs b/src/dump.rs index e65fe3a..be028a7 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -2,6 +2,7 @@ use crate::value::Value; use cairo_lang_sierra::{ids::VarId, program::StatementIdx}; use cairo_lang_utils::ordered_hash_map::OrderedHashMap; use serde::{ser::SerializeMap, Serialize}; +use starknet_crypto::Felt; use std::collections::BTreeMap; #[derive(Clone, Debug, Default, Serialize)] @@ -51,3 +52,73 @@ impl Serialize for StateDump { s.end() } } + +#[derive(Debug, Clone)] +pub struct ContractExecutionResult { + pub remaining_gas: u128, + pub failure_flag: bool, + pub return_values: Vec, + pub error_msg: Option, +} + +impl ContractExecutionResult { + pub fn from_trace(trace: &ProgramTrace) -> Option { + let last = trace.states.last()?; + + let mut remaining_gas = None; + let mut error_msg = None; + let mut failure_flag = false; + let mut return_values = Vec::new(); + + for value in last.items.values() { + match value { + Value::U128(gas) => remaining_gas = Some(*gas), + Value::Enum { + self_ty: _, + index, + payload, + } => { + failure_flag = (*index) != 0; + + if let Value::Struct(inner) = &**payload { + if !failure_flag { + if let Value::Struct(inner) = &inner[0] { + if let Value::Array { ty: _, data } = &inner[0] { + for value in data.iter() { + if let Value::Felt(x) = value { + return_values.push(*x); + } + } + } + } + } else if let Value::Array { ty: _, data } = &inner[1] { + let mut error_felt_vec = Vec::new(); + for value in data.iter() { + if let Value::Felt(x) = value { + error_felt_vec.push(*x); + } + } + let bytes_err: Vec<_> = error_felt_vec + .iter() + .flat_map(|felt| felt.to_bytes_be().to_vec()) + // remove null chars + .filter(|b| *b != 0) + .collect(); + let str_error = String::from_utf8(bytes_err).unwrap().to_owned(); + error_msg = Some(str_error); + } + } + } + Value::Unit => {} + _ => None?, + } + } + + Some(Self { + remaining_gas: remaining_gas.unwrap_or(0), + return_values, + error_msg, + failure_flag, + }) + } +} diff --git a/src/main.rs b/src/main.rs index 38976f9..ab010b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,7 +101,7 @@ mod test { use cairo_lang_compiler::CompilerConfig; use cairo_lang_sierra::program::{GenFunction, Program, StatementIdx}; use cairo_lang_starknet::compile::compile_path; - use sierra_emu::{ProgramTrace, StateDump, VirtualMachine}; + use sierra_emu::{ContractExecutionResult, ProgramTrace, StateDump, VirtualMachine}; #[test] fn test_contract() { @@ -173,6 +173,11 @@ mod test { assert!(!vm.syscall_handler.storage.is_empty()); + let result = ContractExecutionResult::from_trace(&trace).unwrap(); + assert!(!result.failure_flag); + assert_eq!(result.return_values.len(), 0); + assert_eq!(result.error_msg, None); + // let trace_str = serde_json::to_string_pretty(&trace).unwrap(); // std::fs::write("contract_trace.json", trace_str).unwrap(); } From 21abd64daf9751e833818089a2d7c9200f612eb4 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Tue, 20 Aug 2024 10:03:57 +0200 Subject: [PATCH 22/40] temp --- src/starknet/tx_v2_info.rs | 8 +++---- src/vm/enum.rs | 2 ++ src/vm/starknet.rs | 46 ++++++++++++++++++++++++++++---------- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/starknet/tx_v2_info.rs b/src/starknet/tx_v2_info.rs index 0495a30..4086365 100644 --- a/src/starknet/tx_v2_info.rs +++ b/src/starknet/tx_v2_info.rs @@ -38,19 +38,19 @@ impl TxV2Info { Value::Felt(self.transaction_hash), Value::Felt(self.chain_id), Value::Felt(self.nonce), - Value::Array { + 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::Array { + 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::Array { diff --git a/src/vm/enum.rs b/src/vm/enum.rs index a76e51b..63fcecb 100644 --- a/src/vm/enum.rs +++ b/src/vm/enum.rs @@ -38,6 +38,8 @@ pub fn eval_init( }; assert_eq!(info.n_variants, variants.len()); assert!(info.index < info.n_variants); + dbg!(&value); + dbg!(&variants[info.index]); assert!(value.is(registry, &variants[info.index])); EvalAction::NormalBranch( diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index 2b1febe..3770532 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -496,27 +496,49 @@ fn eval_get_execution_info_v2( let result = syscall_handler.get_execution_info_v2(&mut gas); - let out_ty = registry + let mut out_ty = registry .get_type(&info.branch_signatures()[0].vars[2].ty) .unwrap(); + let mut out_ty_id = &info.branch_signatures()[0].vars[2].ty; - let out_ty = if let CoreTypeConcrete::Struct(inner) = out_ty { - let out_ty = registry.get_type(&inner.members[1]).unwrap(); + if let CoreTypeConcrete::Box(inner) = out_ty { + out_ty_id = &inner.ty; + out_ty = registry.get_type(&inner.ty).unwrap(); + }; - if let CoreTypeConcrete::Struct(inner) = out_ty { - // should be resourcebound ty - inner.members[7].clone() - } else { - panic!() - } - } else { - panic!() + if let CoreTypeConcrete::Struct(inner) = out_ty { + out_ty_id = &inner.members[1]; + out_ty = registry.get_type(&inner.members[1]).unwrap(); + }; + + if let CoreTypeConcrete::Box(inner) = out_ty { + out_ty_id = &inner.ty; + out_ty = registry.get_type(&inner.ty).unwrap(); + }; + + if let CoreTypeConcrete::Struct(inner) = out_ty { + out_ty_id = &inner.members[7]; + out_ty = registry.get_type(&inner.members[7]).unwrap(); + }; + + if let CoreTypeConcrete::Struct(inner) = out_ty { + out_ty_id = &inner.members[0]; + out_ty = registry.get_type(&inner.members[0]).unwrap(); + }; + if let CoreTypeConcrete::Snapshot(inner) = out_ty { + out_ty_id = &inner.ty; + out_ty = registry.get_type(&inner.ty).unwrap(); + }; + if let CoreTypeConcrete::Array(inner) = out_ty { + out_ty_id = &inner.ty; + out_ty = registry.get_type(&inner.ty).unwrap(); }; + dbg!(&out_ty_id); match result { Ok(res) => EvalAction::NormalBranch( 0, - smallvec![Value::U128(gas), system, res.into_value(felt_ty, out_ty)], + smallvec![Value::U128(gas), system, res.into_value(felt_ty, out_ty_id.clone())], ), Err(e) => EvalAction::NormalBranch( 1, From 8e85c06f207da2a22282653a3d8c329ff2c536c6 Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 20 Aug 2024 12:35:07 +0200 Subject: [PATCH 23/40] add failing test --- Cargo.toml | 10 ++-- programs/syscalls.cairo | 114 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 22 ++++++++ src/main.rs | 14 ++--- src/vm/starknet.rs | 6 ++- tests/syscalls.rs | 62 ++++++++++++++++++++++ 6 files changed, 211 insertions(+), 17 deletions(-) create mode 100644 programs/syscalls.cairo create mode 100644 tests/syscalls.rs diff --git a/Cargo.toml b/Cargo.toml index 38038ac..ee85895 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,16 +4,16 @@ version = "0.1.0" edition = "2021" [dependencies] -cairo-lang-sierra = "2.7.0" -cairo-lang-utils = "2.7.0" -clap = { version = "4.5.11", features = ["derive"] } +cairo-lang-sierra = "2.7.1" +cairo-lang-utils = "2.7.1" +clap = { version = "4.5.16", features = ["derive"] } k256 = "0.13.3" keccak = "0.1.5" num-bigint = "0.4.6" p256 = "0.13.2" sec1 = { version = "0.7.3", features = ["std"] } -serde = { version = "1.0.204", features = ["derive"] } -serde_json = "1.0.121" +serde = { version = "1.0.208", features = ["derive"] } +serde_json = "1.0.125" sha2 = { version = "0.10.8", features = ["compress"] } smallvec = "1.13.2" starknet-crypto = "0.7.1" diff --git a/programs/syscalls.cairo b/programs/syscalls.cairo new file mode 100644 index 0000000..3328400 --- /dev/null +++ b/programs/syscalls.cairo @@ -0,0 +1,114 @@ +use core::starknet::{ + call_contract_syscall, class_hash_const, contract_address_const, ContractAddress, + deploy_syscall, emit_event_syscall, ExecutionInfo, get_block_hash_syscall, + keccak_syscall, + library_call_syscall, replace_class_syscall, send_message_to_l1_syscall, + storage_address_try_from_felt252, storage_read_syscall, storage_write_syscall, SyscallResult, + testing::cheatcode, +}; +use core::starknet::syscalls::get_execution_info_syscall; +use core::starknet::syscalls::get_execution_info_v2_syscall; + +fn get_block_hash() -> SyscallResult { + get_block_hash_syscall(0) +} + +fn get_execution_info() -> SyscallResult> { + get_execution_info_syscall() +} + +fn get_execution_info_v2() -> SyscallResult> { + get_execution_info_v2_syscall() +} + +fn deploy() -> SyscallResult<(ContractAddress, Span)> { + deploy_syscall(class_hash_const::<0>(), 0, array![].span(), false) +} + +fn replace_class() -> SyscallResult<()> { + replace_class_syscall(class_hash_const::<0>()) +} + +fn library_call() -> SyscallResult> { + library_call_syscall(class_hash_const::<0>(), 0, array![].span()) +} + +fn call_contract() -> SyscallResult> { + call_contract_syscall(contract_address_const::<0>(), 0, array![].span()) +} + +fn storage_read() -> felt252 { + storage_read_syscall(0, storage_address_try_from_felt252(0).unwrap()).unwrap() +} + +fn storage_write() { + storage_write_syscall(0, storage_address_try_from_felt252(0).unwrap(), 0).unwrap() +} + +fn emit_event() -> SyscallResult<()> { + emit_event_syscall(array![].span(), array![].span()) +} + +fn send_message_to_l1() -> SyscallResult<()> { + send_message_to_l1_syscall(3, array![2].span()) +} + +fn keccak() -> SyscallResult { + keccak_syscall(array![].span()) +} + +fn set_sequencer_address(address: felt252) -> Span { + return cheatcode::<'set_sequencer_address'>(array![address].span()); +} + +fn set_account_contract_address(address: felt252) -> Span { + return cheatcode::<'set_account_contract_address'>(array![address].span()); +} + +fn set_block_number(number: felt252) -> Span { + return cheatcode::<'set_block_number'>(array![number].span()); +} + +fn set_block_timestamp(timestamp: felt252) -> Span { + return cheatcode::<'set_block_timestamp'>(array![timestamp].span()); +} + +fn set_caller_address(address: felt252) -> Span { + return cheatcode::<'set_caller_address'>(array![address].span()); +} + +fn set_chain_id(id: felt252) -> Span { + return cheatcode::<'set_chain_id'>(array![id].span()); +} + +fn set_contract_address(address: felt252) -> Span { + return cheatcode::<'set_contract_address'>(array![address].span()); +} + +fn set_max_fee(fee: felt252) -> Span { + return cheatcode::<'set_max_fee'>(array![fee].span()); +} + +fn set_nonce(nonce: felt252) -> Span { + return cheatcode::<'set_nonce'>(array![nonce].span()); +} + +fn set_signature(signature: Array) -> Span { + return cheatcode::<'set_signature'>(signature.span()); +} + +fn set_transaction_hash(hash: felt252) -> Span { + return cheatcode::<'set_transaction_hash'>(array![hash].span()); +} + +fn set_version(version: felt252) -> Span { + return cheatcode::<'set_version'>(array![version].span()); +} + +fn pop_log(log: felt252) -> Span { + return cheatcode::<'pop_log'>(array![log].span()); +} + +fn pop_l2_to_l1_message(message: felt252) -> Span { + return cheatcode::<'pop_l2_to_l1_message'>(array![message].span()); +} diff --git a/src/lib.rs b/src/lib.rs index 5004c05..fd94664 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,28 @@ +use cairo_lang_sierra::program::{GenFunction, Program, StatementIdx}; + pub use self::{dump::*, value::*, vm::VirtualMachine}; mod dump; pub mod starknet; mod value; mod vm; + +pub fn find_entry_point_by_idx( + program: &Program, + entry_point_idx: usize, +) -> Option<&GenFunction> { + program + .funcs + .iter() + .find(|x| x.id.id == entry_point_idx as u64) +} + +pub fn find_entry_point_by_name<'a>( + program: &'a Program, + name: &str, +) -> Option<&'a GenFunction> { + program + .funcs + .iter() + .find(|x| x.id.debug_name.as_ref().map(|x| x.as_str()) == Some(name)) +} diff --git a/src/main.rs b/src/main.rs index ab010b0..89d1cc2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,7 +101,9 @@ mod test { use cairo_lang_compiler::CompilerConfig; use cairo_lang_sierra::program::{GenFunction, Program, StatementIdx}; use cairo_lang_starknet::compile::compile_path; - use sierra_emu::{ContractExecutionResult, ProgramTrace, StateDump, VirtualMachine}; + use sierra_emu::{ + find_entry_point_by_idx, ContractExecutionResult, ProgramTrace, StateDump, VirtualMachine, + }; #[test] fn test_contract() { @@ -181,14 +183,4 @@ mod test { // let trace_str = serde_json::to_string_pretty(&trace).unwrap(); // std::fs::write("contract_trace.json", trace_str).unwrap(); } - - pub fn find_entry_point_by_idx( - program: &Program, - entry_point_idx: usize, - ) -> Option<&GenFunction> { - program - .funcs - .iter() - .find(|x| x.id.id == entry_point_idx as u64) - } } diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index 3770532..e27b659 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -538,7 +538,11 @@ fn eval_get_execution_info_v2( match result { Ok(res) => EvalAction::NormalBranch( 0, - smallvec![Value::U128(gas), system, res.into_value(felt_ty, out_ty_id.clone())], + smallvec![ + Value::U128(gas), + system, + res.into_value(felt_ty, out_ty_id.clone()) + ], ), Err(e) => EvalAction::NormalBranch( 1, diff --git a/tests/syscalls.rs b/tests/syscalls.rs new file mode 100644 index 0000000..12b0a1d --- /dev/null +++ b/tests/syscalls.rs @@ -0,0 +1,62 @@ +use std::{path::Path, sync::Arc}; + +use cairo_lang_compiler::{compile_cairo_project_at_path, CompilerConfig}; +use cairo_lang_sierra::program::{GenFunction, Program, StatementIdx}; +use sierra_emu::{ProgramTrace, StateDump, VirtualMachine}; + +fn run_syscall(func_name: &str) -> ProgramTrace { + let path = Path::new("programs/syscalls.cairo"); + + let sierra_program = Arc::new( + compile_cairo_project_at_path( + path, + CompilerConfig { + replace_ids: true, + ..Default::default() + }, + ) + .unwrap(), + ); + + let function = find_entry_point_by_name(&sierra_program, func_name).unwrap(); + + let mut vm = VirtualMachine::new(sierra_program.clone()); + + let calldata = []; + let initial_gas = 1000000; + + vm.call_contract(function, initial_gas, calldata); + + let mut trace = ProgramTrace::new(); + + while let Some((statement_idx, state)) = vm.step() { + trace.push(StateDump::new(statement_idx, state)); + } + + trace +} + +#[test] +fn test_contract_constructor() { + let mut trace = run_syscall("syscalls::syscalls::get_execution_info_v2"); +} + +pub fn find_entry_point_by_idx( + program: &Program, + entry_point_idx: usize, +) -> Option<&GenFunction> { + program + .funcs + .iter() + .find(|x| x.id.id == entry_point_idx as u64) +} + +pub fn find_entry_point_by_name<'a>( + program: &'a Program, + name: &str, +) -> Option<&'a GenFunction> { + program + .funcs + .iter() + .find(|x| x.id.debug_name.as_ref().map(|x| x.as_str()) == Some(name)) +} From 1abf41d125bb01d9905af3410120543659420802 Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 20 Aug 2024 13:06:31 +0200 Subject: [PATCH 24/40] fix --- Cargo.toml | 4 ++++ src/starknet/tx_info.rs | 4 ++-- src/starknet/tx_v2_info.rs | 8 ++++---- src/vm/enum.rs | 2 -- src/vm/starknet.rs | 1 - tests/syscalls.rs | 2 +- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ee85895..9793193 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,3 +24,7 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } [dev-dependencies] cairo-lang-compiler = "2.7.0" cairo-lang-starknet = "2.7.0" + +# On dev optimize dependencies a bit so it's not as slow. +[profile.dev.package."*"] +opt-level = 1 diff --git a/src/starknet/tx_info.rs b/src/starknet/tx_info.rs index f44cb4e..ac9206d 100644 --- a/src/starknet/tx_info.rs +++ b/src/starknet/tx_info.rs @@ -19,10 +19,10 @@ impl TxInfo { Value::Felt(self.version), Value::Felt(self.account_contract_address), Value::U128(self.max_fee), - Value::Array { + 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/src/starknet/tx_v2_info.rs b/src/starknet/tx_v2_info.rs index 4086365..77083de 100644 --- a/src/starknet/tx_v2_info.rs +++ b/src/starknet/tx_v2_info.rs @@ -31,10 +31,10 @@ impl TxV2Info { Value::Felt(self.version), Value::Felt(self.account_contract_address), Value::U128(self.max_fee), - Value::Array { + 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), @@ -53,14 +53,14 @@ impl TxV2Info { }]), Value::U32(self.nonce_data_availability_mode), Value::U32(self.fee_data_availability_mode), - Value::Array { + Value::Struct(vec![Value::Array { ty: felt252_ty, data: self .account_deployment_data .into_iter() .map(Value::Felt) .collect(), - }, + }]), ]) } } diff --git a/src/vm/enum.rs b/src/vm/enum.rs index 63fcecb..a76e51b 100644 --- a/src/vm/enum.rs +++ b/src/vm/enum.rs @@ -38,8 +38,6 @@ pub fn eval_init( }; assert_eq!(info.n_variants, variants.len()); assert!(info.index < info.n_variants); - dbg!(&value); - dbg!(&variants[info.index]); assert!(value.is(registry, &variants[info.index])); EvalAction::NormalBranch( diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index e27b659..6ac4a5b 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -533,7 +533,6 @@ fn eval_get_execution_info_v2( out_ty_id = &inner.ty; out_ty = registry.get_type(&inner.ty).unwrap(); }; - dbg!(&out_ty_id); match result { Ok(res) => EvalAction::NormalBranch( diff --git a/tests/syscalls.rs b/tests/syscalls.rs index 12b0a1d..9121091 100644 --- a/tests/syscalls.rs +++ b/tests/syscalls.rs @@ -38,7 +38,7 @@ fn run_syscall(func_name: &str) -> ProgramTrace { #[test] fn test_contract_constructor() { - let mut trace = run_syscall("syscalls::syscalls::get_execution_info_v2"); + run_syscall("syscalls::syscalls::get_execution_info_v2"); } pub fn find_entry_point_by_idx( From ead1a1598c0570d640c6834f7d70a44d923e6db6 Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 20 Aug 2024 14:04:30 +0200 Subject: [PATCH 25/40] implement more syscalls --- src/vm/starknet.rs | 196 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 178 insertions(+), 18 deletions(-) diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index 6ac4a5b..a9c8170 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -77,15 +77,19 @@ pub fn eval( StarkNetConcreteLibfunc::GetExecutionInfoV2(info) => { eval_get_execution_info_v2(registry, info, args, syscall_handler) } - StarkNetConcreteLibfunc::Deploy(info) => eval_deploy(registry, info, args), - StarkNetConcreteLibfunc::Keccak(info) => eval_keccak(registry, info, args), + StarkNetConcreteLibfunc::Deploy(info) => eval_deploy(registry, info, args, syscall_handler), + StarkNetConcreteLibfunc::Keccak(info) => eval_keccak(registry, info, args, syscall_handler), StarkNetConcreteLibfunc::Sha256ProcessBlock(_) => todo!(), StarkNetConcreteLibfunc::Sha256StateHandleInit(_) => todo!(), StarkNetConcreteLibfunc::Sha256StateHandleDigest(_) => todo!(), - StarkNetConcreteLibfunc::LibraryCall(info) => eval_library_call(registry, info, args), - StarkNetConcreteLibfunc::ReplaceClass(info) => eval_replace_class(registry, info, args), + StarkNetConcreteLibfunc::LibraryCall(info) => { + eval_library_call(registry, info, args, syscall_handler) + } + StarkNetConcreteLibfunc::ReplaceClass(info) => { + eval_replace_class(registry, info, args, syscall_handler) + } StarkNetConcreteLibfunc::SendMessageToL1(info) => { - eval_send_message_to_l1(registry, info, args) + eval_send_message_to_l1(registry, info, args, syscall_handler) } StarkNetConcreteLibfunc::Testing(_info) => todo!(), StarkNetConcreteLibfunc::Secp256(_info) => todo!(), @@ -531,7 +535,6 @@ fn eval_get_execution_info_v2( }; if let CoreTypeConcrete::Array(inner) = out_ty { out_ty_id = &inner.ty; - out_ty = registry.get_type(&inner.ty).unwrap(); }; match result { @@ -558,17 +561,92 @@ fn eval_get_execution_info_v2( } fn eval_deploy( - _registry: &ProgramRegistry, - _info: &SignatureOnlyConcreteLibfunc, - _args: Vec, + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - todo!() + let [Value::U128(mut gas), system, Value::Felt(class_hash), Value::Felt(contract_address_salt), Value::Struct(calldata), Value::Enum { + self_ty: _, + index: deploy_from_zero, + payload: _, + }]: [Value; 6] = args.try_into().unwrap() + else { + panic!() + }; + + let deploy_from_zero = deploy_from_zero != 0; + + let [Value::Array { + ty: _, + data: calldata, + }]: [Value; 1] = calldata.try_into().unwrap() + else { + panic!() + }; + + let calldata = calldata + .into_iter() + .map(|x| match x { + Value::Felt(x) => x, + _ => unreachable!(), + }) + .collect(); + + // 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 result = syscall_handler.deploy( + class_hash, + contract_address_salt, + calldata, + deploy_from_zero, + &mut gas, + ); + + match result { + Ok((contract_address, return_values)) => EvalAction::NormalBranch( + 0, + smallvec![ + Value::U128(gas), + system, + Value::Felt(contract_address), + Value::Array { + ty: felt_ty, + data: return_values + .into_iter() + .map(Value::Felt) + .collect::>(), + } + ], + ), + Err(e) => EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: felt_ty, + data: e.into_iter().map(Value::Felt).collect::>(), + } + ], + ), + } } fn eval_keccak( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, _args: Vec, + _syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { todo!() } @@ -577,22 +655,104 @@ fn eval_library_call( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, _args: Vec, + _syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { todo!() } fn eval_replace_class( - _registry: &ProgramRegistry, - _info: &SignatureOnlyConcreteLibfunc, - _args: Vec, + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - todo!() + let [Value::U128(mut gas), system, Value::Felt(class_hash)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + // 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 result = syscall_handler.replace_class(class_hash, &mut gas); + + match result { + Ok(()) => EvalAction::NormalBranch(0, smallvec![Value::U128(gas), system]), + Err(e) => EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: felt_ty, + data: e.into_iter().map(Value::Felt).collect::>(), + } + ], + ), + } } fn eval_send_message_to_l1( - _registry: &ProgramRegistry, - _info: &SignatureOnlyConcreteLibfunc, - _args: Vec, + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - todo!() + let [Value::U128(mut gas), system, Value::Felt(address), Value::Struct(payload)]: [Value; 4] = + args.try_into().unwrap() + else { + panic!() + }; + + let [Value::Array { + ty: _, + data: payload, + }]: [Value; 1] = payload.try_into().unwrap() + else { + panic!() + }; + + let payload = payload + .into_iter() + .map(|x| match x { + Value::Felt(x) => x, + _ => unreachable!(), + }) + .collect(); + + // 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 result = syscall_handler.send_message_to_l1(address, payload, &mut gas); + + match result { + Ok(()) => EvalAction::NormalBranch(0, smallvec![Value::U128(gas), system]), + Err(e) => EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: felt_ty, + data: e.into_iter().map(Value::Felt).collect::>(), + } + ], + ), + } } From 7166e938cb68ad4853efdc67b70797dfa83c8077 Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 20 Aug 2024 14:19:54 +0200 Subject: [PATCH 26/40] implement more syscalls --- src/vm/starknet.rs | 130 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 118 insertions(+), 12 deletions(-) diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index a9c8170..c373762 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -619,13 +619,13 @@ fn eval_deploy( Value::U128(gas), system, Value::Felt(contract_address), - Value::Array { + Value::Struct(vec![Value::Array { ty: felt_ty, data: return_values .into_iter() .map(Value::Felt) .collect::>(), - } + }]) ], ), Err(e) => EvalAction::NormalBranch( @@ -643,21 +643,127 @@ fn eval_deploy( } fn eval_keccak( - _registry: &ProgramRegistry, - _info: &SignatureOnlyConcreteLibfunc, - _args: Vec, - _syscall_handler: &mut impl StarknetSyscallHandler, + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - todo!() + let [Value::U128(mut gas), system, Value::Struct(input)]: [Value; 3] = args.try_into().unwrap() + else { + panic!() + }; + + let [Value::Array { ty: _, data: input }]: [Value; 1] = input.try_into().unwrap() else { + panic!() + }; + + let input = input + .into_iter() + .map(|x| match x { + Value::U64(x) => x, + _ => unreachable!(), + }) + .collect(); + + let result = syscall_handler.keccak(input, &mut gas); + + // 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!(), + } + }; + + match result { + Ok(res) => { + EvalAction::NormalBranch(0, smallvec![Value::U128(gas), system, res.into_value()]) + } + Err(e) => EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: felt_ty, + data: e.into_iter().map(Value::Felt).collect::>(), + } + ], + ), + } } fn eval_library_call( - _registry: &ProgramRegistry, - _info: &SignatureOnlyConcreteLibfunc, - _args: Vec, - _syscall_handler: &mut impl StarknetSyscallHandler, + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - todo!() + let [Value::U128(mut gas), system, Value::Felt(class_hash), Value::Felt(function_selector), Value::Struct(calldata)]: [Value; 5] = + args.try_into().unwrap() + else { + panic!() + }; + + let [Value::Array { + ty: _, + data: calldata, + }]: [Value; 1] = calldata.try_into().unwrap() + else { + panic!() + }; + + let calldata = calldata + .into_iter() + .map(|x| match x { + Value::Felt(x) => x, + _ => unreachable!(), + }) + .collect(); + + // 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 result = syscall_handler.library_call(class_hash, function_selector, calldata, &mut gas); + + match result { + Ok(return_values) => EvalAction::NormalBranch( + 0, + smallvec![ + Value::U128(gas), + system, + Value::Struct(vec![Value::Array { + ty: felt_ty, + data: return_values + .into_iter() + .map(Value::Felt) + .collect::>(), + }]) + ], + ), + Err(e) => EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: felt_ty, + data: e.into_iter().map(Value::Felt).collect::>(), + } + ], + ), + } } fn eval_replace_class( From 76f18bc009045312b8a7d2018737e178813002ea Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 20 Aug 2024 14:20:19 +0200 Subject: [PATCH 27/40] fix warns --- src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 89d1cc2..37bbec5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -99,7 +99,6 @@ mod test { use std::path::Path; use cairo_lang_compiler::CompilerConfig; - use cairo_lang_sierra::program::{GenFunction, Program, StatementIdx}; use cairo_lang_starknet::compile::compile_path; use sierra_emu::{ find_entry_point_by_idx, ContractExecutionResult, ProgramTrace, StateDump, VirtualMachine, From a44627d9481a66bbe220076904938f3fcf75250d Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 20 Aug 2024 14:42:32 +0200 Subject: [PATCH 28/40] more libfuncs --- src/vm.rs | 4 ++-- src/vm/{u128.rs => uint128.rs} | 0 src/vm/uint32.rs | 42 ++++++++++++++++++++++++++++++++-- src/vm/uint64.rs | 42 ++++++++++++++++++++++++++++++++-- src/vm/uint8.rs | 37 ++++++++++++++++++++++++++++-- 5 files changed, 117 insertions(+), 8 deletions(-) rename src/vm/{u128.rs => uint128.rs} (100%) diff --git a/src/vm.rs b/src/vm.rs index 225c448..0c422a9 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -41,7 +41,7 @@ mod poseidon; mod snapshot_take; mod starknet; mod r#struct; -mod u128; +mod uint128; mod uint32; mod uint64; mod uint8; @@ -314,7 +314,7 @@ fn eval<'a>( self::starknet::eval(registry, selector, args, syscall_handler) } CoreConcreteLibfunc::Struct(selector) => self::r#struct::eval(registry, selector, args), - CoreConcreteLibfunc::Uint128(selector) => self::u128::eval(registry, selector, args), + CoreConcreteLibfunc::Uint128(selector) => self::uint128::eval(registry, selector, args), CoreConcreteLibfunc::Uint16(_) => todo!(), CoreConcreteLibfunc::Uint256(_) => todo!(), CoreConcreteLibfunc::Uint32(selector) => self::uint32::eval(registry, selector, args), diff --git a/src/vm/u128.rs b/src/vm/uint128.rs similarity index 100% rename from src/vm/u128.rs rename to src/vm/uint128.rs diff --git a/src/vm/uint32.rs b/src/vm/uint32.rs index a960d37..577d38c 100644 --- a/src/vm/uint32.rs +++ b/src/vm/uint32.rs @@ -12,6 +12,7 @@ use cairo_lang_sierra::{ program_registry::ProgramRegistry, }; use smallvec::smallvec; +use starknet_crypto::Felt; pub fn eval( registry: &ProgramRegistry, @@ -24,14 +25,31 @@ pub fn eval( Uint32Concrete::SquareRoot(_) => todo!(), Uint32Concrete::Equal(info) => eval_equal(registry, info, args), Uint32Concrete::ToFelt252(info) => eval_to_felt252(registry, info, args), - Uint32Concrete::FromFelt252(_) => todo!(), + Uint32Concrete::FromFelt252(info) => eval_from_felt(registry, info, args), Uint32Concrete::IsZero(info) => eval_is_zero(registry, info, args), - Uint32Concrete::Divmod(_) => todo!(), + Uint32Concrete::Divmod(info) => eval_divmod(registry, info, args), Uint32Concrete::WideMul(info) => eval_widemul(registry, info, args), Uint32Concrete::Bitwise(_) => todo!(), } } +pub fn eval_divmod( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::U32(x), Value::U32(y)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let val = Value::U32(x / y); + let rem = Value::U32(x % y); + + EvalAction::NormalBranch(0, smallvec![range_check, val, rem]) +} + pub fn eval_operation( _registry: &ProgramRegistry, info: &IntOperationConcreteLibfunc, @@ -54,6 +72,26 @@ pub fn eval_operation( ) } +pub fn eval_from_felt( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::Felt(value)]: [Value; 2] = args.try_into().unwrap() + else { + panic!() + }; + + let max = Felt::from(u32::MAX); + + if value <= max { + let value: u32 = value.to_biguint().try_into().unwrap(); + EvalAction::NormalBranch(0, smallvec![range_check, Value::U32(value)]) + } else { + EvalAction::NormalBranch(1, smallvec![range_check]) + } +} + pub fn eval_equal( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, diff --git a/src/vm/uint64.rs b/src/vm/uint64.rs index 5989875..3e952e1 100644 --- a/src/vm/uint64.rs +++ b/src/vm/uint64.rs @@ -12,6 +12,7 @@ use cairo_lang_sierra::{ program_registry::ProgramRegistry, }; use smallvec::smallvec; +use starknet_crypto::Felt; pub fn eval( registry: &ProgramRegistry, @@ -24,14 +25,51 @@ pub fn eval( Uint64Concrete::SquareRoot(_) => todo!(), Uint64Concrete::Equal(info) => eval_equal(registry, info, args), Uint64Concrete::ToFelt252(info) => eval_to_felt252(registry, info, args), - Uint64Concrete::FromFelt252(_) => todo!(), + Uint64Concrete::FromFelt252(info) => eval_from_felt(registry, info, args), Uint64Concrete::IsZero(info) => eval_is_zero(registry, info, args), - Uint64Concrete::Divmod(_) => todo!(), + Uint64Concrete::Divmod(info) => eval_divmod(registry, info, args), Uint64Concrete::WideMul(info) => eval_widemul(registry, info, args), Uint64Concrete::Bitwise(_) => todo!(), } } +pub fn eval_divmod( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::U64(x), Value::U64(y)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let val = Value::U64(x / y); + let rem = Value::U64(x % y); + + EvalAction::NormalBranch(0, smallvec![range_check, val, rem]) +} + +pub fn eval_from_felt( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::Felt(value)]: [Value; 2] = args.try_into().unwrap() + else { + panic!() + }; + + let max = Felt::from(u64::MAX); + + if value <= max { + let value: u64 = value.to_biguint().try_into().unwrap(); + EvalAction::NormalBranch(0, smallvec![range_check, Value::U64(value)]) + } else { + EvalAction::NormalBranch(1, smallvec![range_check]) + } +} + pub fn eval_operation( _registry: &ProgramRegistry, info: &IntOperationConcreteLibfunc, diff --git a/src/vm/uint8.rs b/src/vm/uint8.rs index b4dc540..36ac3a9 100644 --- a/src/vm/uint8.rs +++ b/src/vm/uint8.rs @@ -12,6 +12,7 @@ use cairo_lang_sierra::{ program_registry::ProgramRegistry, }; use smallvec::smallvec; +use starknet_crypto::Felt; pub fn eval( registry: &ProgramRegistry, @@ -23,8 +24,8 @@ pub fn eval( Uint8Concrete::Operation(info) => eval_operation(registry, info, args), Uint8Concrete::SquareRoot(_) => todo!(), Uint8Concrete::Equal(info) => eval_equal(registry, info, args), - Uint8Concrete::ToFelt252(_) => todo!(), - Uint8Concrete::FromFelt252(_) => todo!(), + Uint8Concrete::ToFelt252(info) => eval_to_felt252(registry, info, args), + Uint8Concrete::FromFelt252(info) => eval_from_felt(registry, info, args), Uint8Concrete::IsZero(info) => eval_is_zero(registry, info, args), Uint8Concrete::Divmod(_) => todo!(), Uint8Concrete::WideMul(info) => eval_widemul(registry, info, args), @@ -32,6 +33,18 @@ pub fn eval( } } +pub fn eval_to_felt252( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::U8(value)]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + EvalAction::NormalBranch(0, smallvec![Value::Felt(value.into())]) +} + pub fn eval_operation( _registry: &ProgramRegistry, info: &IntOperationConcreteLibfunc, @@ -54,6 +67,26 @@ pub fn eval_operation( ) } +pub fn eval_from_felt( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::Felt(value)]: [Value; 2] = args.try_into().unwrap() + else { + panic!() + }; + + let max = Felt::from(u8::MAX); + + if value <= max { + let value: u8 = value.to_biguint().try_into().unwrap(); + EvalAction::NormalBranch(0, smallvec![range_check, Value::U8(value)]) + } else { + EvalAction::NormalBranch(1, smallvec![range_check]) + } +} + pub fn eval_equal( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, From 839a92e36e372756046b1d04155faba2fedc2e9d Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 20 Aug 2024 15:08:03 +0200 Subject: [PATCH 29/40] bytes31 --- src/vm.rs | 3 +- src/vm/bytes31.rs | 99 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/vm/bytes31.rs diff --git a/src/vm.rs b/src/vm.rs index 0c422a9..e79fc37 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -24,6 +24,7 @@ mod bool; mod bounded_int; mod r#box; mod branch_align; +mod bytes31; mod cast; mod r#const; mod drop; @@ -280,7 +281,7 @@ fn eval<'a>( } CoreConcreteLibfunc::Box(selector) => self::r#box::eval(registry, selector, args), CoreConcreteLibfunc::BranchAlign(info) => self::branch_align::eval(registry, info, args), - CoreConcreteLibfunc::Bytes31(_) => todo!(), + CoreConcreteLibfunc::Bytes31(selector) => self::bytes31::eval(registry, selector, args), CoreConcreteLibfunc::Cast(selector) => self::cast::eval(registry, selector, args), CoreConcreteLibfunc::Circuit(_) => todo!(), CoreConcreteLibfunc::Const(selector) => self::r#const::eval(registry, selector, args), diff --git a/src/vm/bytes31.rs b/src/vm/bytes31.rs new file mode 100644 index 0000000..d2ff9cf --- /dev/null +++ b/src/vm/bytes31.rs @@ -0,0 +1,99 @@ +use std::ops::Range; + +use super::EvalAction; +use crate::Value; +use cairo_lang_sierra::{ + extensions::{ + bytes31::Bytes31ConcreteLibfunc, + consts::SignatureAndConstConcreteLibfunc, + core::{CoreLibfunc, CoreType, CoreTypeConcrete}, + lib_func::SignatureOnlyConcreteLibfunc, + ConcreteLibfunc, + }, + program_registry::ProgramRegistry, +}; +use smallvec::smallvec; + +pub fn eval( + registry: &ProgramRegistry, + selector: &Bytes31ConcreteLibfunc, + args: Vec, +) -> EvalAction { + match selector { + Bytes31ConcreteLibfunc::Const(info) => eval_const(registry, info, args), + Bytes31ConcreteLibfunc::ToFelt252(info) => eval_to_felt252(registry, info, args), + Bytes31ConcreteLibfunc::TryFromFelt252(info) => eval_from_felt(registry, info, args), + } +} + +pub fn eval_const( + registry: &ProgramRegistry, + info: &SignatureAndConstConcreteLibfunc, + _args: Vec, +) -> EvalAction { + let out_ty = registry + .get_type(&info.branch_signatures()[0].vars[0].ty) + .unwrap(); + + if let CoreTypeConcrete::BoundedInt(bounded_info) = out_ty { + let range = bounded_info.range.clone(); + let value = Value::BoundedInt { + range: Range { + start: range.lower, + end: range.upper, + }, + value: info.c.clone(), + }; + EvalAction::NormalBranch(0, smallvec![value]) + } else { + panic!() + } +} + +pub fn eval_from_felt( + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::Felt(value)]: [Value; 2] = args.try_into().unwrap() + else { + panic!() + }; + + let out_ty = registry + .get_type(&info.branch_signatures()[0].vars[1].ty) + .unwrap(); + + if let CoreTypeConcrete::BoundedInt(info) = out_ty { + let range = info.range.clone(); + + if range.is_full_felt252_range() + || (value < range.upper.clone().into() && value >= range.lower.clone().into()) + { + let value = Value::BoundedInt { + range: Range { + start: range.lower, + end: range.upper, + }, + value: value.to_bigint(), + }; + EvalAction::NormalBranch(0, smallvec![range_check, value]) + } else { + EvalAction::NormalBranch(1, smallvec![range_check]) + } + } else { + panic!() + } +} + +pub fn eval_to_felt252( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::BoundedInt { range: _, value }]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + EvalAction::NormalBranch(0, smallvec![Value::Felt(value.into())]) +} From c5dfb21fffcc274a3757a2484aa486911c3232b6 Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 20 Aug 2024 17:29:12 +0200 Subject: [PATCH 30/40] const libfuncs --- src/value.rs | 5 ++-- src/vm/bytes31.rs | 60 ++++++++++------------------------------------- src/vm/const.rs | 27 +++++++++++++++++++++ 3 files changed, 43 insertions(+), 49 deletions(-) diff --git a/src/value.rs b/src/value.rs index 5c4fb21..0083219 100644 --- a/src/value.rs +++ b/src/value.rs @@ -27,6 +27,7 @@ pub enum Value { payload: Box, }, Felt(Felt), + Bytes31(Felt), FeltDict { ty: ConcreteTypeId, data: HashMap, @@ -74,6 +75,7 @@ impl Value { matches!(self, Self::Enum { self_ty, .. } if self_ty == type_id) } CoreTypeConcrete::Felt252(_) => matches!(self, Self::Felt(_)), + CoreTypeConcrete::Bytes31(_) => matches!(self, Self::Bytes31(_)), CoreTypeConcrete::Felt252Dict(info) => { matches!(self, Self::FeltDict { ty, .. } if *ty == info.ty) } @@ -133,8 +135,7 @@ impl Value { StarkNetTypeConcrete::Secp256Point(_) => todo!(), StarkNetTypeConcrete::Sha256StateHandle(_) => todo!(), }, - CoreTypeConcrete::Bytes31(_) => todo!(), - CoreTypeConcrete::BoundedInt(_) => todo!(), + CoreTypeConcrete::BoundedInt(_) => matches!(self, Self::BoundedInt { .. }), } } diff --git a/src/vm/bytes31.rs b/src/vm/bytes31.rs index d2ff9cf..5d37259 100644 --- a/src/vm/bytes31.rs +++ b/src/vm/bytes31.rs @@ -1,18 +1,17 @@ -use std::ops::Range; - use super::EvalAction; use crate::Value; use cairo_lang_sierra::{ extensions::{ bytes31::Bytes31ConcreteLibfunc, consts::SignatureAndConstConcreteLibfunc, - core::{CoreLibfunc, CoreType, CoreTypeConcrete}, + core::{CoreLibfunc, CoreType}, lib_func::SignatureOnlyConcreteLibfunc, - ConcreteLibfunc, }, program_registry::ProgramRegistry, }; +use num_bigint::BigInt; use smallvec::smallvec; +use starknet_crypto::Felt; pub fn eval( registry: &ProgramRegistry, @@ -27,32 +26,16 @@ pub fn eval( } pub fn eval_const( - registry: &ProgramRegistry, + _registry: &ProgramRegistry, info: &SignatureAndConstConcreteLibfunc, _args: Vec, ) -> EvalAction { - let out_ty = registry - .get_type(&info.branch_signatures()[0].vars[0].ty) - .unwrap(); - - if let CoreTypeConcrete::BoundedInt(bounded_info) = out_ty { - let range = bounded_info.range.clone(); - let value = Value::BoundedInt { - range: Range { - start: range.lower, - end: range.upper, - }, - value: info.c.clone(), - }; - EvalAction::NormalBranch(0, smallvec![value]) - } else { - panic!() - } + EvalAction::NormalBranch(0, smallvec![Value::Bytes31(info.c.clone().into())]) } pub fn eval_from_felt( - registry: &ProgramRegistry, - info: &SignatureOnlyConcreteLibfunc, + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, args: Vec, ) -> EvalAction { let [range_check @ Value::Unit, Value::Felt(value)]: [Value; 2] = args.try_into().unwrap() @@ -60,29 +43,12 @@ pub fn eval_from_felt( panic!() }; - let out_ty = registry - .get_type(&info.branch_signatures()[0].vars[1].ty) - .unwrap(); - - if let CoreTypeConcrete::BoundedInt(info) = out_ty { - let range = info.range.clone(); + let max = Felt::from(BigInt::from(2).pow(248) - 1); - if range.is_full_felt252_range() - || (value < range.upper.clone().into() && value >= range.lower.clone().into()) - { - let value = Value::BoundedInt { - range: Range { - start: range.lower, - end: range.upper, - }, - value: value.to_bigint(), - }; - EvalAction::NormalBranch(0, smallvec![range_check, value]) - } else { - EvalAction::NormalBranch(1, smallvec![range_check]) - } + if value <= max { + EvalAction::NormalBranch(0, smallvec![range_check, Value::Bytes31(value)]) } else { - panic!() + EvalAction::NormalBranch(1, smallvec![range_check]) } } @@ -91,9 +57,9 @@ pub fn eval_to_felt252( _info: &SignatureOnlyConcreteLibfunc, args: Vec, ) -> EvalAction { - let [Value::BoundedInt { range: _, value }]: [Value; 1] = args.try_into().unwrap() else { + let [Value::Bytes31(value)]: [Value; 1] = args.try_into().unwrap() else { panic!() }; - EvalAction::NormalBranch(0, smallvec![Value::Felt(value.into())]) + EvalAction::NormalBranch(0, smallvec![Value::Felt(value)]) } diff --git a/src/vm/const.rs b/src/vm/const.rs index 54f3a03..77e3f20 100644 --- a/src/vm/const.rs +++ b/src/vm/const.rs @@ -68,6 +68,33 @@ pub fn eval_as_immediate( [GenericArg::Value(value)] => Value::U8(value.try_into().unwrap()), _ => unreachable!(), }, + CoreTypeConcrete::Uint128(_) => match inner_data { + [GenericArg::Value(value)] => Value::U128(value.try_into().unwrap()), + _ => unreachable!(), + }, + CoreTypeConcrete::Struct(_) => { + let mut fields = Vec::new(); + + for field in inner_data { + match field { + GenericArg::Type(const_field_ty) => { + let field_type = registry.get_type(const_field_ty).unwrap(); + + match &field_type { + CoreTypeConcrete::Const(const_ty) => { + let field_value = + inner(registry, &const_ty.inner_ty, &const_ty.inner_data); + fields.push(field_value); + } + _ => unreachable!(), + }; + } + _ => unreachable!(), + } + } + + Value::Struct(fields) + } _ => todo!("{:?}", type_id), } } From c4706f290a38670e0aae3830fedcce9cb24579c7 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 21 Aug 2024 14:55:54 +0200 Subject: [PATCH 31/40] fixes --- src/dump.rs | 6 +- src/vm.rs | 4 +- src/vm/uint128.rs | 2 +- src/vm/uint32.rs | 2 +- src/vm/uint64.rs | 2 +- src/vm/uint8.rs | 2 +- tests/libfuncs.rs | 133 +++++++++++++++++++++++++++++++++++++ tests/tests/test_u32.cairo | 3 + 8 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 tests/libfuncs.rs create mode 100644 tests/tests/test_u32.cairo diff --git a/src/dump.rs b/src/dump.rs index be028a7..ab625c1 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -7,7 +7,7 @@ use std::collections::BTreeMap; #[derive(Clone, Debug, Default, Serialize)] pub struct ProgramTrace { - states: Vec, + pub states: Vec, // TODO: Syscall data. } @@ -23,8 +23,8 @@ impl ProgramTrace { #[derive(Clone, Debug)] pub struct StateDump { - statement_idx: StatementIdx, - items: BTreeMap, + pub statement_idx: StatementIdx, + pub items: BTreeMap, } impl StateDump { diff --git a/src/vm.rs b/src/vm.rs index e79fc37..9d2e42a 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -172,8 +172,8 @@ impl VirtualMachine { let state_snapshot = frame.state.get_mut().clone(); debug!( - "Evaluating statement {} ({})", - frame.pc.0, &self.program.statements[frame.pc.0] + "Evaluating statement {} ({}) (values: \n{:#?}\n)", + frame.pc.0, &self.program.statements[frame.pc.0], state_snapshot ); match &self.program.statements[frame.pc.0] { GenStatement::Invocation(invocation) => { diff --git a/src/vm/uint128.rs b/src/vm/uint128.rs index ca618df..dcaa6c9 100644 --- a/src/vm/uint128.rs +++ b/src/vm/uint128.rs @@ -66,7 +66,7 @@ pub fn eval_equal( panic!() }; - EvalAction::NormalBranch((lhs != rhs) as usize, smallvec![]) + EvalAction::NormalBranch((lhs == rhs) as usize, smallvec![]) } pub fn eval_is_zero( diff --git a/src/vm/uint32.rs b/src/vm/uint32.rs index 577d38c..b229310 100644 --- a/src/vm/uint32.rs +++ b/src/vm/uint32.rs @@ -101,7 +101,7 @@ pub fn eval_equal( panic!() }; - EvalAction::NormalBranch((lhs != rhs) as usize, smallvec![]) + EvalAction::NormalBranch((lhs == rhs) as usize, smallvec![]) } pub fn eval_is_zero( diff --git a/src/vm/uint64.rs b/src/vm/uint64.rs index 3e952e1..9760b0d 100644 --- a/src/vm/uint64.rs +++ b/src/vm/uint64.rs @@ -101,7 +101,7 @@ pub fn eval_equal( panic!() }; - EvalAction::NormalBranch((lhs != rhs) as usize, smallvec![]) + EvalAction::NormalBranch((lhs == rhs) as usize, smallvec![]) } pub fn eval_is_zero( diff --git a/src/vm/uint8.rs b/src/vm/uint8.rs index 36ac3a9..ef839ab 100644 --- a/src/vm/uint8.rs +++ b/src/vm/uint8.rs @@ -96,7 +96,7 @@ pub fn eval_equal( panic!() }; - EvalAction::NormalBranch((lhs != rhs) as usize, smallvec![]) + EvalAction::NormalBranch((lhs == rhs) as usize, smallvec![]) } pub fn eval_is_zero( diff --git a/tests/libfuncs.rs b/tests/libfuncs.rs new file mode 100644 index 0000000..5fcf124 --- /dev/null +++ b/tests/libfuncs.rs @@ -0,0 +1,133 @@ +use std::{path::Path, sync::Arc}; + +use cairo_lang_compiler::{compile_cairo_project_at_path, CompilerConfig}; +use cairo_lang_sierra::{ + extensions::{core::CoreTypeConcrete, starknet::StarkNetTypeConcrete}, + program::{GenFunction, Program, StatementIdx}, +}; +use sierra_emu::{ProgramTrace, StateDump, Value, VirtualMachine}; + +fn run_program(path: &str, func_name: &str, args: &[Value]) -> Vec { + let path = Path::new(path); + + let sierra_program = Arc::new( + compile_cairo_project_at_path( + path, + CompilerConfig { + replace_ids: true, + ..Default::default() + }, + ) + .unwrap(), + ); + + let function = find_entry_point_by_name(&sierra_program, func_name).unwrap(); + + let mut vm = VirtualMachine::new(sierra_program.clone()); + + let mut args = args.iter().cloned(); + let initial_gas = 1000000; + + vm.push_frame( + function.id.clone(), + function + .signature + .param_types + .iter() + .map(|type_id| { + let type_info = vm.registry().get_type(type_id).unwrap(); + match type_info { + CoreTypeConcrete::GasBuiltin(_) => Value::U128(initial_gas), + CoreTypeConcrete::StarkNet(StarkNetTypeConcrete::System(_)) => Value::Unit, + CoreTypeConcrete::RangeCheck(_) + | CoreTypeConcrete::Pedersen(_) + | CoreTypeConcrete::Poseidon(_) + | CoreTypeConcrete::Bitwise(_) + | CoreTypeConcrete::BuiltinCosts(_) + | CoreTypeConcrete::SegmentArena(_) => Value::Unit, + _ => args.next().unwrap(), + } + }) + .collect::>(), + ); + + let mut trace = ProgramTrace::new(); + + while let Some((statement_idx, state)) = vm.step() { + trace.push(StateDump::new(statement_idx, state)); + } + + trace + .states + .last() + .unwrap() + .items + .values() + .cloned() + .collect() +} + +#[test] +fn test_u32_overflow() { + let r = run_program( + "tests/tests/test_u32.cairo", + "test_u32::test_u32::run_test", + &[Value::U32(2), Value::U32(2)], + ); + assert!(matches!( + r[1], + Value::Enum { + self_ty: _, + index: 0, + payload: _ + } + )); + + let r = run_program( + "tests/tests/test_u32.cairo", + "test_u32::test_u32::run_test", + &[Value::U32(2), Value::U32(3)], + ); + assert!(matches!( + r[1], + Value::Enum { + self_ty: _, + index: 1, + payload: _ + } + )); + + let r = run_program( + "tests/tests/test_u32.cairo", + "test_u32::test_u32::run_test", + &[Value::U32(0), Value::U32(0)], + ); + assert!(matches!( + r[1], + Value::Enum { + self_ty: _, + index: 0, + payload: _ + } + )); +} + +pub fn find_entry_point_by_idx( + program: &Program, + entry_point_idx: usize, +) -> Option<&GenFunction> { + program + .funcs + .iter() + .find(|x| x.id.id == entry_point_idx as u64) +} + +pub fn find_entry_point_by_name<'a>( + program: &'a Program, + name: &str, +) -> Option<&'a GenFunction> { + program + .funcs + .iter() + .find(|x| x.id.debug_name.as_ref().map(|x| x.as_str()) == Some(name)) +} diff --git a/tests/tests/test_u32.cairo b/tests/tests/test_u32.cairo new file mode 100644 index 0000000..1aa78c3 --- /dev/null +++ b/tests/tests/test_u32.cairo @@ -0,0 +1,3 @@ +fn run_test(lhs: u32, rhs: u32) -> u32 { + lhs - rhs +} From b671b14504cf70a74347936e7a0b0afc68dd0384 Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 22 Aug 2024 17:52:10 +0200 Subject: [PATCH 32/40] progress --- Cargo.toml | 2 + src/value.rs | 16 +++++-- src/vm.rs | 17 +++++-- src/vm/ec.rs | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 7 deletions(-) create mode 100644 src/vm/ec.rs diff --git a/Cargo.toml b/Cargo.toml index 9793193..6906aed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ clap = { version = "4.5.16", features = ["derive"] } k256 = "0.13.3" keccak = "0.1.5" num-bigint = "0.4.6" +num-traits = "0.2.19" p256 = "0.13.2" sec1 = { version = "0.7.3", features = ["std"] } serde = { version = "1.0.208", features = ["derive"] } @@ -17,6 +18,7 @@ serde_json = "1.0.125" sha2 = { version = "0.10.8", features = ["compress"] } smallvec = "1.13.2" starknet-crypto = "0.7.1" +starknet-curve = "0.5.0" starknet-types-core = "0.1.2" tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } diff --git a/src/value.rs b/src/value.rs index 0083219..03376fe 100644 --- a/src/value.rs +++ b/src/value.rs @@ -37,6 +37,16 @@ pub enum Value { data: HashMap, key: Felt, }, + EcPoint { + x: Felt, + y: Felt, + }, + EcState { + x0: Felt, + y0: Felt, + x1: Felt, + y1: Felt, + }, I8(i8), Struct(Vec), U128(u128), @@ -106,9 +116,9 @@ impl Value { CoreTypeConcrete::Box(info) => self.is(registry, &info.ty), CoreTypeConcrete::Circuit(_) => todo!(), CoreTypeConcrete::Const(_) => todo!(), - CoreTypeConcrete::EcOp(_) => todo!(), - CoreTypeConcrete::EcPoint(_) => todo!(), - CoreTypeConcrete::EcState(_) => todo!(), + CoreTypeConcrete::EcOp(_) => matches!(self, Self::Unit), + CoreTypeConcrete::EcPoint(_) => matches!(self, Self::EcPoint { .. }), + CoreTypeConcrete::EcState(_) => matches!(self, Self::EcState { .. }), CoreTypeConcrete::BuiltinCosts(_) => matches!(self, Self::Unit), CoreTypeConcrete::Uint16(_) => matches!(self, Self::U16(_)), CoreTypeConcrete::Uint64(_) => matches!(self, Self::U64(_)), diff --git a/src/vm.rs b/src/vm.rs index 9d2e42a..bbf62b7 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -7,13 +7,14 @@ use cairo_lang_sierra::{ extensions::{ core::{CoreConcreteLibfunc, CoreLibfunc, CoreType, CoreTypeConcrete}, starknet::StarkNetTypeConcrete, + ConcreteType, }, ids::{ConcreteLibfuncId, FunctionId, VarId}, program::{GenFunction, GenStatement, Invocation, Program, StatementIdx}, program_registry::ProgramRegistry, }; use cairo_lang_utils::ordered_hash_map::OrderedHashMap; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use starknet_types_core::felt::Felt; use std::{cell::Cell, sync::Arc}; use tracing::debug; @@ -29,6 +30,7 @@ mod cast; mod r#const; mod drop; mod dup; +mod ec; mod r#enum; mod felt252; mod felt252_dict; @@ -129,8 +131,11 @@ impl VirtualMachine { | CoreTypeConcrete::Poseidon(_) | CoreTypeConcrete::Bitwise(_) | CoreTypeConcrete::BuiltinCosts(_) + | CoreTypeConcrete::EcOp(_) | CoreTypeConcrete::SegmentArena(_) => Value::Unit, - _ => unreachable!(), + x => { + todo!("{:?}", x.info()) + } } }) .collect::>(), @@ -290,7 +295,7 @@ fn eval<'a>( CoreConcreteLibfunc::Debug(_) => todo!(), CoreConcreteLibfunc::Drop(info) => self::drop::eval(registry, info, args), CoreConcreteLibfunc::Dup(info) => self::dup::eval(registry, info, args), - CoreConcreteLibfunc::Ec(_) => todo!(), + CoreConcreteLibfunc::Ec(selector) => self::ec::eval(registry, selector, args), CoreConcreteLibfunc::Enum(selector) => self::r#enum::eval(registry, selector, args), CoreConcreteLibfunc::Felt252(selector) => self::felt252::eval(registry, selector, args), CoreConcreteLibfunc::Felt252Dict(selector) => { @@ -323,6 +328,10 @@ fn eval<'a>( CoreConcreteLibfunc::Uint64(selector) => self::uint64::eval(registry, selector, args), CoreConcreteLibfunc::Uint8(selector) => self::uint8::eval(registry, selector, args), CoreConcreteLibfunc::UnconditionalJump(info) => self::jump::eval(registry, info, args), - CoreConcreteLibfunc::UnwrapNonZero(_) => todo!(), + CoreConcreteLibfunc::UnwrapNonZero(_info) => { + let [value] = args.try_into().unwrap(); + + EvalAction::NormalBranch(0, smallvec![value]) + } } } diff --git a/src/vm/ec.rs b/src/vm/ec.rs new file mode 100644 index 0000000..40ae7ac --- /dev/null +++ b/src/vm/ec.rs @@ -0,0 +1,131 @@ +use super::EvalAction; +use crate::Value; +use cairo_lang_sierra::{ + extensions::{ + core::{CoreLibfunc, CoreType}, + ec::EcConcreteLibfunc, + lib_func::SignatureOnlyConcreteLibfunc, + }, + program_registry::ProgramRegistry, +}; +use num_traits::identities::Zero; +use smallvec::smallvec; +use starknet_crypto::Felt; +use starknet_curve::curve_params::BETA; +use starknet_types_core::curve::{AffinePoint, ProjectivePoint}; + +// todo: verify these are correct. + +pub fn eval( + registry: &ProgramRegistry, + selector: &EcConcreteLibfunc, + args: Vec, +) -> EvalAction { + match selector { + EcConcreteLibfunc::IsZero(info) => eval_is_zero(registry, info, args), + EcConcreteLibfunc::Neg(_) => todo!(), + EcConcreteLibfunc::StateAdd(info) => eval_state_add(registry, info, args), + EcConcreteLibfunc::TryNew(info) => eval_new(registry, info, args), + EcConcreteLibfunc::StateFinalize(_) => todo!(), + EcConcreteLibfunc::StateInit(_) => todo!(), + EcConcreteLibfunc::StateAddMul(_) => todo!(), + EcConcreteLibfunc::PointFromX(info) => eval_point_from_x(registry, info, args), + EcConcreteLibfunc::UnwrapPoint(_) => todo!(), + EcConcreteLibfunc::Zero(_) => todo!(), + } +} + +pub fn eval_is_zero( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [value @ Value::EcPoint { x, y }]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + if x.is_zero() && y.is_zero() { + EvalAction::NormalBranch(0, smallvec![]) + } else { + EvalAction::NormalBranch(1, smallvec![value]) + } +} + +pub fn eval_new( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::Felt(x), Value::Felt(y)]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + + match AffinePoint::new(x, y) { + Ok(point) => EvalAction::NormalBranch( + 0, + smallvec![Value::EcPoint { + x: point.x(), + y: point.y(), + }], + ), + Err(_) => EvalAction::NormalBranch(1, smallvec![]), + } +} + +pub fn eval_state_add( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::EcState { x0, y0, x1, y1 }, Value::EcPoint { x, y }]: [Value; 2] = + args.try_into().unwrap() + else { + panic!() + }; + + let mut state = ProjectivePoint::from_affine(x0, y0).unwrap(); + let point = AffinePoint::new(x, y).unwrap(); + + state += &point; + + EvalAction::NormalBranch( + 0, + smallvec![Value::EcState { + x0: state.x(), + y0: state.y(), + x1, + y1 + }], + ) +} + +pub fn eval_point_from_x( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::Felt(x)]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + + // https://github.com/starkware-libs/cairo/blob/aaad921bba52e729dc24ece07fab2edf09ccfa15/crates/cairo-lang-sierra-to-casm/src/invocations/ec.rs#L63 + let x2 = x * x; + let x3 = x2 * x; + let alpha_x_plus_beta = x + BETA; + let rhs = x3 + alpha_x_plus_beta; + let y = rhs.sqrt().unwrap_or_else(|| Felt::from(3) * rhs); + + match AffinePoint::new(x, y) { + Ok(point) => EvalAction::NormalBranch( + 0, + smallvec![ + range_check, + Value::EcPoint { + x: point.x(), + y: point.y(), + } + ], + ), + Err(_) => EvalAction::NormalBranch(1, smallvec![range_check]), + } +} From d69c6dcfe2f5682f8ee44555d0613fc6b4ccb35c Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Fri, 23 Aug 2024 13:34:54 +0200 Subject: [PATCH 33/40] impl ec libfuncs --- Cargo.toml | 1 + src/vm/ec.rs | 131 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 125 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6906aed..97a85fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ keccak = "0.1.5" num-bigint = "0.4.6" num-traits = "0.2.19" p256 = "0.13.2" +rand = "0.8.5" sec1 = { version = "0.7.3", features = ["std"] } serde = { version = "1.0.208", features = ["derive"] } serde_json = "1.0.125" diff --git a/src/vm/ec.rs b/src/vm/ec.rs index 40ae7ac..8f570eb 100644 --- a/src/vm/ec.rs +++ b/src/vm/ec.rs @@ -9,10 +9,13 @@ use cairo_lang_sierra::{ program_registry::ProgramRegistry, }; use num_traits::identities::Zero; +use rand::Rng; use smallvec::smallvec; use starknet_crypto::Felt; use starknet_curve::curve_params::BETA; use starknet_types_core::curve::{AffinePoint, ProjectivePoint}; +use std::ops::Mul; +use std::ops::Neg; // todo: verify these are correct. @@ -23,12 +26,12 @@ pub fn eval( ) -> EvalAction { match selector { EcConcreteLibfunc::IsZero(info) => eval_is_zero(registry, info, args), - EcConcreteLibfunc::Neg(_) => todo!(), + EcConcreteLibfunc::Neg(info) => eval_neg(registry, info, args), EcConcreteLibfunc::StateAdd(info) => eval_state_add(registry, info, args), EcConcreteLibfunc::TryNew(info) => eval_new(registry, info, args), - EcConcreteLibfunc::StateFinalize(_) => todo!(), - EcConcreteLibfunc::StateInit(_) => todo!(), - EcConcreteLibfunc::StateAddMul(_) => todo!(), + EcConcreteLibfunc::StateFinalize(info) => eval_state_finalize(registry, info, args), + EcConcreteLibfunc::StateInit(info) => eval_state_init(registry, info, args), + EcConcreteLibfunc::StateAddMul(info) => eval_state_add_mul(registry, info, args), EcConcreteLibfunc::PointFromX(info) => eval_point_from_x(registry, info, args), EcConcreteLibfunc::UnwrapPoint(_) => todo!(), EcConcreteLibfunc::Zero(_) => todo!(), @@ -40,17 +43,38 @@ pub fn eval_is_zero( _info: &SignatureOnlyConcreteLibfunc, args: Vec, ) -> EvalAction { - let [value @ Value::EcPoint { x, y }]: [Value; 1] = args.try_into().unwrap() else { + let [value @ Value::EcPoint { x: _, y }]: [Value; 1] = args.try_into().unwrap() else { panic!() }; - - if x.is_zero() && y.is_zero() { + // To check whether `(x, y) = (0, 0)` (the zero point), it is enough to check + // whether `y = 0`, since there is no point on the curve with y = 0. + if y.is_zero() { EvalAction::NormalBranch(0, smallvec![]) } else { EvalAction::NormalBranch(1, smallvec![value]) } } +pub fn eval_neg( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::EcPoint { x, y }]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + let point = AffinePoint::new(x, y).unwrap().neg(); + + EvalAction::NormalBranch( + 0, + smallvec![Value::EcPoint { + x: point.x(), + y: point.y(), + }], + ) +} + pub fn eval_new( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, @@ -72,6 +96,24 @@ pub fn eval_new( } } +pub fn eval_state_init( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + _args: Vec, +) -> EvalAction { + let state = random_ec_point(); + + EvalAction::NormalBranch( + 0, + smallvec![Value::EcState { + x0: state.x(), + y0: state.y(), + x1: state.x(), + y1: state.y(), + }], + ) +} + pub fn eval_state_add( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, @@ -87,6 +129,7 @@ pub fn eval_state_add( let point = AffinePoint::new(x, y).unwrap(); state += &point; + let state = state.to_affine().unwrap(); EvalAction::NormalBranch( 0, @@ -99,6 +142,63 @@ pub fn eval_state_add( ) } +pub fn eval_state_add_mul( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [ec @ Value::Unit, Value::EcState { x0, y0, x1, y1 }, Value::Felt(scalar), Value::EcPoint { x, y }]: [Value; 4] = + args.try_into().unwrap() + else { + panic!() + }; + + let mut state = ProjectivePoint::from_affine(x0, y0).unwrap(); + let point = ProjectivePoint::from_affine(x, y).unwrap(); + + state += &point.mul(scalar); + let state = state.to_affine().unwrap(); + + EvalAction::NormalBranch( + 0, + smallvec![ + ec, + Value::EcState { + x0: state.x(), + y0: state.y(), + x1, + y1 + } + ], + ) +} + +pub fn eval_state_finalize( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::EcState { x0, y0, x1, y1 }]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + let state = ProjectivePoint::from_affine(x0, y0).unwrap(); + let random_point = ProjectivePoint::from_affine(x1, y1).unwrap(); + + if state.x() == random_point.x() && state.y() == random_point.y() { + EvalAction::NormalBranch(1, smallvec![]) + } else { + let point = &state - &random_point; + EvalAction::NormalBranch( + 0, + smallvec![Value::EcPoint { + x: point.x(), + y: point.y(), + }], + ) + } +} + pub fn eval_point_from_x( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, @@ -109,6 +209,7 @@ pub fn eval_point_from_x( }; // https://github.com/starkware-libs/cairo/blob/aaad921bba52e729dc24ece07fab2edf09ccfa15/crates/cairo-lang-sierra-to-casm/src/invocations/ec.rs#L63 + let x2 = x * x; let x3 = x2 * x; let alpha_x_plus_beta = x + BETA; @@ -129,3 +230,19 @@ pub fn eval_point_from_x( Err(_) => EvalAction::NormalBranch(1, smallvec![range_check]), } } + +fn random_ec_point() -> AffinePoint { + // https://github.com/starkware-libs/cairo/blob/aaad921bba52e729dc24ece07fab2edf09ccfa15/crates/cairo-lang-runner/src/casm_run/mod.rs#L1802 + let mut rng = rand::thread_rng(); + let (random_x, random_y) = loop { + // Randominzing 31 bytes to make sure is in range. + let x_bytes: [u8; 31] = rng.gen(); + let random_x = Felt::from_bytes_be_slice(&x_bytes); + let random_y_squared = random_x * random_x * random_x + random_x + BETA; + if let Some(random_y) = random_y_squared.sqrt() { + break (random_x, random_y); + } + }; + + AffinePoint::new(random_x, random_y).unwrap() +} From f4bf651a65f20f89be53b70916eef293b66545a3 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Fri, 23 Aug 2024 13:57:43 +0200 Subject: [PATCH 34/40] ec progress --- src/vm/ec.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/vm/ec.rs b/src/vm/ec.rs index 8f570eb..6ff9444 100644 --- a/src/vm/ec.rs +++ b/src/vm/ec.rs @@ -33,7 +33,7 @@ pub fn eval( EcConcreteLibfunc::StateInit(info) => eval_state_init(registry, info, args), EcConcreteLibfunc::StateAddMul(info) => eval_state_add_mul(registry, info, args), EcConcreteLibfunc::PointFromX(info) => eval_point_from_x(registry, info, args), - EcConcreteLibfunc::UnwrapPoint(_) => todo!(), + EcConcreteLibfunc::UnwrapPoint(info) => eval_unwrap_point(registry, info, args), EcConcreteLibfunc::Zero(_) => todo!(), } } @@ -55,6 +55,17 @@ pub fn eval_is_zero( } } +pub fn eval_unwrap_point( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::EcPoint { x, y }]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + EvalAction::NormalBranch(0, smallvec![Value::Felt(x), Value::Felt(y)]) +} + pub fn eval_neg( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, From ecae0eb4e1a3e294cff3083d8092e7720e277b50 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Fri, 23 Aug 2024 15:56:19 +0200 Subject: [PATCH 35/40] fix ec --- src/vm/ec.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vm/ec.rs b/src/vm/ec.rs index 6ff9444..64ab982 100644 --- a/src/vm/ec.rs +++ b/src/vm/ec.rs @@ -200,6 +200,7 @@ pub fn eval_state_finalize( EvalAction::NormalBranch(1, smallvec![]) } else { let point = &state - &random_point; + let point = point.to_affine().unwrap(); EvalAction::NormalBranch( 0, smallvec![Value::EcPoint { From e0547444cc2288c53211dd6f8703c5c6db1e095b Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Fri, 23 Aug 2024 17:02:57 +0200 Subject: [PATCH 36/40] impl call contract --- src/vm/starknet.rs | 72 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/src/vm/starknet.rs b/src/vm/starknet.rs index c373762..75fee73 100644 --- a/src/vm/starknet.rs +++ b/src/vm/starknet.rs @@ -21,7 +21,7 @@ pub fn eval( ) -> EvalAction { match selector { StarkNetConcreteLibfunc::CallContract(info) => { - self::eval_call_contract(registry, info, args) + self::eval_call_contract(registry, info, args, syscall_handler) } StarkNetConcreteLibfunc::ClassHashConst(info) => { eval_class_hash_const(registry, info, args) @@ -250,11 +250,73 @@ fn eval_storage_address_from_base_and_offset( } fn eval_call_contract( - _registry: &ProgramRegistry, - _info: &SignatureOnlyConcreteLibfunc, - _args: Vec, + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, + syscall_handler: &mut impl StarknetSyscallHandler, ) -> EvalAction { - todo!() + let [Value::U128(mut gas), system, Value::Felt(address), Value::Felt(entry_point_selector), Value::Struct(calldata)]: [Value; 5] = + args.try_into().unwrap() + else { + panic!() + }; + + let [Value::Array { + ty: _, + data: calldata, + }]: [Value; 1] = calldata.try_into().unwrap() + else { + panic!() + }; + + let calldata = calldata + .into_iter() + .map(|x| match x { + Value::Felt(x) => x, + _ => unreachable!(), + }) + .collect(); + + // 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 result = syscall_handler.call_contract(address, entry_point_selector, calldata, &mut gas); + + match result { + Ok(return_values) => EvalAction::NormalBranch( + 0, + smallvec![ + Value::U128(gas), + system, + Value::Struct(vec![Value::Array { + ty: felt_ty, + data: return_values + .into_iter() + .map(Value::Felt) + .collect::>(), + }]) + ], + ), + Err(e) => EvalAction::NormalBranch( + 1, + smallvec![ + Value::U128(gas), + system, + Value::Array { + ty: felt_ty, + data: e.into_iter().map(Value::Felt).collect::>(), + } + ], + ), + } } fn eval_storage_read( From f3ecce8045580833a055dfeb89335698ee861b9b Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 26 Aug 2024 12:48:47 +0200 Subject: [PATCH 37/40] bitwise --- src/vm/uint128.rs | 23 ++++++++++++++++++++++- src/vm/uint32.rs | 23 ++++++++++++++++++++++- src/vm/uint64.rs | 23 ++++++++++++++++++++++- src/vm/uint8.rs | 42 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 106 insertions(+), 5 deletions(-) diff --git a/src/vm/uint128.rs b/src/vm/uint128.rs index dcaa6c9..08e9956 100644 --- a/src/vm/uint128.rs +++ b/src/vm/uint128.rs @@ -28,7 +28,7 @@ pub fn eval( Uint128Concrete::FromFelt252(info) => eval_from_felt(registry, info, args), Uint128Concrete::IsZero(info) => eval_is_zero(registry, info, args), Uint128Concrete::Divmod(_) => todo!(), - Uint128Concrete::Bitwise(_) => todo!(), + Uint128Concrete::Bitwise(info) => eval_bitwise(registry, info, args), Uint128Concrete::GuaranteeMul(_) => todo!(), Uint128Concrete::MulGuaranteeVerify(_) => todo!(), Uint128Concrete::ByteReverse(_) => todo!(), @@ -85,6 +85,27 @@ pub fn eval_is_zero( } } +pub fn eval_bitwise( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [bitwise @ Value::Unit, Value::U128(lhs), Value::U128(rhs)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let and = lhs & rhs; + let or = lhs | rhs; + let xor = lhs ^ rhs; + + EvalAction::NormalBranch( + 0, + smallvec![bitwise, Value::U128(and), Value::U128(or), Value::U128(xor)], + ) +} + pub fn eval_const( _registry: &ProgramRegistry, info: &IntConstConcreteLibfunc, diff --git a/src/vm/uint32.rs b/src/vm/uint32.rs index b229310..b1daf1d 100644 --- a/src/vm/uint32.rs +++ b/src/vm/uint32.rs @@ -29,7 +29,7 @@ pub fn eval( Uint32Concrete::IsZero(info) => eval_is_zero(registry, info, args), Uint32Concrete::Divmod(info) => eval_divmod(registry, info, args), Uint32Concrete::WideMul(info) => eval_widemul(registry, info, args), - Uint32Concrete::Bitwise(_) => todo!(), + Uint32Concrete::Bitwise(info) => eval_bitwise(registry, info, args), } } @@ -104,6 +104,27 @@ pub fn eval_equal( EvalAction::NormalBranch((lhs == rhs) as usize, smallvec![]) } +pub fn eval_bitwise( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [bitwise @ Value::Unit, Value::U32(lhs), Value::U32(rhs)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let and = lhs & rhs; + let or = lhs | rhs; + let xor = lhs ^ rhs; + + EvalAction::NormalBranch( + 0, + smallvec![bitwise, Value::U32(and), Value::U32(or), Value::U32(xor)], + ) +} + pub fn eval_is_zero( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, diff --git a/src/vm/uint64.rs b/src/vm/uint64.rs index 9760b0d..224dcba 100644 --- a/src/vm/uint64.rs +++ b/src/vm/uint64.rs @@ -29,7 +29,7 @@ pub fn eval( Uint64Concrete::IsZero(info) => eval_is_zero(registry, info, args), Uint64Concrete::Divmod(info) => eval_divmod(registry, info, args), Uint64Concrete::WideMul(info) => eval_widemul(registry, info, args), - Uint64Concrete::Bitwise(_) => todo!(), + Uint64Concrete::Bitwise(info) => eval_bitwise(registry, info, args), } } @@ -104,6 +104,27 @@ pub fn eval_equal( EvalAction::NormalBranch((lhs == rhs) as usize, smallvec![]) } +pub fn eval_bitwise( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [bitwise @ Value::Unit, Value::U64(lhs), Value::U64(rhs)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let and = lhs & rhs; + let or = lhs | rhs; + let xor = lhs ^ rhs; + + EvalAction::NormalBranch( + 0, + smallvec![bitwise, Value::U64(and), Value::U64(or), Value::U64(xor)], + ) +} + pub fn eval_is_zero( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, diff --git a/src/vm/uint8.rs b/src/vm/uint8.rs index ef839ab..24d18ee 100644 --- a/src/vm/uint8.rs +++ b/src/vm/uint8.rs @@ -27,12 +27,29 @@ pub fn eval( Uint8Concrete::ToFelt252(info) => eval_to_felt252(registry, info, args), Uint8Concrete::FromFelt252(info) => eval_from_felt(registry, info, args), Uint8Concrete::IsZero(info) => eval_is_zero(registry, info, args), - Uint8Concrete::Divmod(_) => todo!(), + Uint8Concrete::Divmod(info) => eval_divmod(registry, info, args), Uint8Concrete::WideMul(info) => eval_widemul(registry, info, args), - Uint8Concrete::Bitwise(_) => todo!(), + Uint8Concrete::Bitwise(info) => eval_bitwise(registry, info, args), } } +pub fn eval_divmod( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::U8(x), Value::U8(y)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let val = Value::U8(x / y); + let rem = Value::U8(x % y); + + EvalAction::NormalBranch(0, smallvec![range_check, val, rem]) +} + pub fn eval_to_felt252( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, @@ -99,6 +116,27 @@ pub fn eval_equal( EvalAction::NormalBranch((lhs == rhs) as usize, smallvec![]) } +pub fn eval_bitwise( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [bitwise @ Value::Unit, Value::U8(lhs), Value::U8(rhs)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let and = lhs & rhs; + let or = lhs | rhs; + let xor = lhs ^ rhs; + + EvalAction::NormalBranch( + 0, + smallvec![bitwise, Value::U8(and), Value::U8(or), Value::U8(xor)], + ) +} + pub fn eval_is_zero( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, From d4cce3edd1c85b13bac881eef9a668fc6a71e60c Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 26 Aug 2024 12:52:24 +0200 Subject: [PATCH 38/40] u16 --- src/vm.rs | 6 +- src/vm/uint16.rs | 176 ++++++++++++++++++++++++++++++++++++++++++++++ src/vm/uint252.rs | 25 +++++++ 3 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 src/vm/uint16.rs create mode 100644 src/vm/uint252.rs diff --git a/src/vm.rs b/src/vm.rs index bbf62b7..3f51a0d 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -45,6 +45,8 @@ mod snapshot_take; mod starknet; mod r#struct; mod uint128; +mod uint16; +mod uint252; mod uint32; mod uint64; mod uint8; @@ -321,8 +323,8 @@ fn eval<'a>( } CoreConcreteLibfunc::Struct(selector) => self::r#struct::eval(registry, selector, args), CoreConcreteLibfunc::Uint128(selector) => self::uint128::eval(registry, selector, args), - CoreConcreteLibfunc::Uint16(_) => todo!(), - CoreConcreteLibfunc::Uint256(_) => todo!(), + CoreConcreteLibfunc::Uint16(selector) => self::uint16::eval(registry, selector, args), + CoreConcreteLibfunc::Uint256(selector) => self::uint252::eval(registry, selector, args), CoreConcreteLibfunc::Uint32(selector) => self::uint32::eval(registry, selector, args), CoreConcreteLibfunc::Uint512(_) => todo!(), CoreConcreteLibfunc::Uint64(selector) => self::uint64::eval(registry, selector, args), diff --git a/src/vm/uint16.rs b/src/vm/uint16.rs new file mode 100644 index 0000000..b394c96 --- /dev/null +++ b/src/vm/uint16.rs @@ -0,0 +1,176 @@ +use super::EvalAction; +use crate::Value; +use cairo_lang_sierra::{ + extensions::{ + core::{CoreLibfunc, CoreType}, + int::{ + unsigned::{Uint16Concrete, Uint16Traits}, + IntConstConcreteLibfunc, IntOperationConcreteLibfunc, IntOperator, + }, + lib_func::SignatureOnlyConcreteLibfunc, + }, + program_registry::ProgramRegistry, +}; +use smallvec::smallvec; +use starknet_crypto::Felt; + +pub fn eval( + registry: &ProgramRegistry, + selector: &Uint16Concrete, + args: Vec, +) -> EvalAction { + match selector { + Uint16Concrete::Const(info) => eval_const(registry, info, args), + Uint16Concrete::Operation(info) => eval_operation(registry, info, args), + Uint16Concrete::SquareRoot(_) => todo!(), + Uint16Concrete::Equal(info) => eval_equal(registry, info, args), + Uint16Concrete::ToFelt252(info) => eval_to_felt252(registry, info, args), + Uint16Concrete::FromFelt252(info) => eval_from_felt(registry, info, args), + Uint16Concrete::IsZero(info) => eval_is_zero(registry, info, args), + Uint16Concrete::Divmod(info) => eval_divmod(registry, info, args), + Uint16Concrete::WideMul(info) => eval_widemul(registry, info, args), + Uint16Concrete::Bitwise(info) => eval_bitwise(registry, info, args), + } +} + +pub fn eval_divmod( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::U16(x), Value::U16(y)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let val = Value::U16(x / y); + let rem = Value::U16(x % y); + + EvalAction::NormalBranch(0, smallvec![range_check, val, rem]) +} + +pub fn eval_operation( + _registry: &ProgramRegistry, + info: &IntOperationConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::U16(lhs), Value::U16(rhs)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let (result, has_overflow) = match info.operator { + IntOperator::OverflowingAdd => lhs.overflowing_add(rhs), + IntOperator::OverflowingSub => lhs.overflowing_sub(rhs), + }; + + EvalAction::NormalBranch( + has_overflow as usize, + smallvec![range_check, Value::U16(result)], + ) +} + +pub fn eval_from_felt( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::Felt(value)]: [Value; 2] = args.try_into().unwrap() + else { + panic!() + }; + + let max = Felt::from(u16::MAX); + + if value <= max { + let value: u16 = value.to_biguint().try_into().unwrap(); + EvalAction::NormalBranch(0, smallvec![range_check, Value::U16(value)]) + } else { + EvalAction::NormalBranch(1, smallvec![range_check]) + } +} + +pub fn eval_equal( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::U16(lhs), Value::U16(rhs)]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + + EvalAction::NormalBranch((lhs == rhs) as usize, smallvec![]) +} + +pub fn eval_bitwise( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [bitwise @ Value::Unit, Value::U16(lhs), Value::U16(rhs)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let and = lhs & rhs; + let or = lhs | rhs; + let xor = lhs ^ rhs; + + EvalAction::NormalBranch( + 0, + smallvec![bitwise, Value::U16(and), Value::U16(or), Value::U16(xor)], + ) +} + +pub fn eval_is_zero( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [vm_value @ Value::U16(value)]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + if value == 0 { + EvalAction::NormalBranch(0, smallvec![]) + } else { + EvalAction::NormalBranch(1, smallvec![vm_value]) + } +} + +pub fn eval_to_felt252( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::U16(value)]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + EvalAction::NormalBranch(0, smallvec![Value::Felt(value.into())]) +} + +pub fn eval_const( + _registry: &ProgramRegistry, + info: &IntConstConcreteLibfunc, + _args: Vec, +) -> EvalAction { + EvalAction::NormalBranch(0, smallvec![Value::U16(info.c)]) +} + +pub fn eval_widemul( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::U16(lhs), Value::U16(rhs)]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + + let result = (lhs as u32) * (rhs as u32); + + EvalAction::NormalBranch(0, smallvec![Value::U32(result)]) +} diff --git a/src/vm/uint252.rs b/src/vm/uint252.rs new file mode 100644 index 0000000..8e35144 --- /dev/null +++ b/src/vm/uint252.rs @@ -0,0 +1,25 @@ +use super::EvalAction; +use crate::Value; +use cairo_lang_sierra::{ + extensions::{ + core::{CoreLibfunc, CoreType}, + int::unsigned256::Uint256Concrete, + lib_func::SignatureOnlyConcreteLibfunc, + }, + program_registry::ProgramRegistry, +}; +use smallvec::smallvec; +use starknet_crypto::Felt; + +pub fn eval( + registry: &ProgramRegistry, + selector: &Uint256Concrete, + args: Vec, +) -> EvalAction { + match selector { + Uint256Concrete::IsZero(_) => todo!(), + Uint256Concrete::Divmod(_) => todo!(), + Uint256Concrete::SquareRoot(_) => todo!(), + Uint256Concrete::InvModN(_) => todo!(), + } +} From f10b211fa6b59b6e0b08eec928e62f70c8dc84ee Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 26 Aug 2024 16:29:25 +0200 Subject: [PATCH 39/40] progress --- src/starknet/secp256k1_point.rs | 4 +- src/starknet/secp256r1_point.rs | 4 +- src/value.rs | 1 - src/vm/uint128.rs | 50 ++++++++++++++++++--- src/vm/uint252.rs | 77 +++++++++++++++++++++++++++++++-- 5 files changed, 121 insertions(+), 15 deletions(-) diff --git a/src/starknet/secp256k1_point.rs b/src/starknet/secp256k1_point.rs index bbac4df..767b5f1 100644 --- a/src/starknet/secp256k1_point.rs +++ b/src/starknet/secp256k1_point.rs @@ -11,8 +11,8 @@ impl Secp256k1Point { #[allow(unused)] pub(crate) fn into_value(self) -> Value { Value::Struct(vec![ - Value::U256(self.x.lo, self.x.hi), - Value::U256(self.y.lo, self.y.hi), + Value::Struct(vec![Value::U128(self.x.lo), Value::U128(self.x.hi)]), + Value::Struct(vec![Value::U128(self.y.lo), Value::U128(self.y.hi)]), ]) } } diff --git a/src/starknet/secp256r1_point.rs b/src/starknet/secp256r1_point.rs index 8548ef0..b3137ac 100644 --- a/src/starknet/secp256r1_point.rs +++ b/src/starknet/secp256r1_point.rs @@ -11,8 +11,8 @@ impl Secp256r1Point { #[allow(unused)] pub(crate) fn into_value(self) -> Value { Value::Struct(vec![ - Value::U256(self.x.lo, self.x.hi), - Value::U256(self.y.lo, self.y.hi), + Value::Struct(vec![Value::U128(self.x.lo), Value::U128(self.x.hi)]), + Value::Struct(vec![Value::U128(self.y.lo), Value::U128(self.y.hi)]), ]) } } diff --git a/src/value.rs b/src/value.rs index 03376fe..b49a72d 100644 --- a/src/value.rs +++ b/src/value.rs @@ -50,7 +50,6 @@ pub enum Value { I8(i8), Struct(Vec), U128(u128), - U256(u128, u128), U16(u16), U32(u32), U64(u64), diff --git a/src/vm/uint128.rs b/src/vm/uint128.rs index 08e9956..965bce0 100644 --- a/src/vm/uint128.rs +++ b/src/vm/uint128.rs @@ -1,3 +1,5 @@ +use std::u128; + use super::EvalAction; use crate::Value; use cairo_lang_sierra::{ @@ -11,8 +13,10 @@ use cairo_lang_sierra::{ }, program_registry::ProgramRegistry, }; +use num_bigint::BigUint; use smallvec::smallvec; use starknet_crypto::Felt; +use starknet_types_core::felt::NonZeroFelt; pub fn eval( registry: &ProgramRegistry, @@ -27,14 +31,44 @@ pub fn eval( Uint128Concrete::ToFelt252(info) => eval_to_felt(registry, info, args), Uint128Concrete::FromFelt252(info) => eval_from_felt(registry, info, args), Uint128Concrete::IsZero(info) => eval_is_zero(registry, info, args), - Uint128Concrete::Divmod(_) => todo!(), + Uint128Concrete::Divmod(info) => eval_divmod(registry, info, args), Uint128Concrete::Bitwise(info) => eval_bitwise(registry, info, args), Uint128Concrete::GuaranteeMul(_) => todo!(), - Uint128Concrete::MulGuaranteeVerify(_) => todo!(), + Uint128Concrete::MulGuaranteeVerify(info) => eval_guarantee_verify(registry, info, args), Uint128Concrete::ByteReverse(_) => todo!(), } } +pub fn eval_guarantee_verify( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, _verify @ Value::Unit]: [Value; 2] = args.try_into().unwrap() + else { + panic!() + }; + + EvalAction::NormalBranch(0, smallvec![range_check]) +} + +pub fn eval_divmod( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::U128(x), Value::U128(y)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let val = Value::U128(x / y); + let rem = Value::U128(x % y); + + EvalAction::NormalBranch(0, smallvec![range_check, val, rem]) +} + pub fn eval_operation( _registry: &ProgramRegistry, info: &IntOperationConcreteLibfunc, @@ -136,17 +170,19 @@ pub fn eval_from_felt( panic!() }; - let max = Felt::from(u128::MAX); + let bound = Felt::from(u128::MAX) + 1; - if value <= max { + if value < bound { let value: u128 = value.to_biguint().try_into().unwrap(); EvalAction::NormalBranch(0, smallvec![range_check, Value::U128(value)]) } else { - let overflow: u128 = (value - max).to_biguint().try_into().unwrap(); - let value: u128 = max.to_biguint().try_into().unwrap(); + let (new_value, overflow) = value.div_rem(&NonZeroFelt::try_from(bound).unwrap()); + + let overflow: u128 = overflow.to_biguint().try_into().unwrap(); + let new_value: u128 = new_value.to_biguint().try_into().unwrap(); EvalAction::NormalBranch( 1, - smallvec![range_check, Value::U128(value), Value::U128(overflow)], + smallvec![range_check, Value::U128(new_value), Value::U128(overflow)], ) } } diff --git a/src/vm/uint252.rs b/src/vm/uint252.rs index 8e35144..98e8aab 100644 --- a/src/vm/uint252.rs +++ b/src/vm/uint252.rs @@ -1,3 +1,5 @@ +use std::u128; + use super::EvalAction; use crate::Value; use cairo_lang_sierra::{ @@ -8,8 +10,8 @@ use cairo_lang_sierra::{ }, program_registry::ProgramRegistry, }; +use num_bigint::BigUint; use smallvec::smallvec; -use starknet_crypto::Felt; pub fn eval( registry: &ProgramRegistry, @@ -17,9 +19,78 @@ pub fn eval( args: Vec, ) -> EvalAction { match selector { - Uint256Concrete::IsZero(_) => todo!(), - Uint256Concrete::Divmod(_) => todo!(), + Uint256Concrete::IsZero(info) => eval_is_zero(registry, info, args), + Uint256Concrete::Divmod(info) => eval_divmod(registry, info, args), Uint256Concrete::SquareRoot(_) => todo!(), Uint256Concrete::InvModN(_) => todo!(), } } + +pub fn eval_is_zero( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::Struct(fields)]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + let [Value::U128(lo), Value::U128(hi)]: [Value; 2] = fields.clone().try_into().unwrap() else { + panic!() + }; + + if lo == 0 && hi == 0 { + EvalAction::NormalBranch(0, smallvec![]) + } else { + EvalAction::NormalBranch(1, smallvec![Value::Struct(fields)]) + } +} + +#[inline] +pub fn u256_to_biguint(lo: u128, hi: u128) -> BigUint { + BigUint::from(lo) + (BigUint::from(hi) << 128) +} + +#[inline] +pub fn u256_to_value(value: BigUint) -> Value { + let hi: u128 = (&value >> 128u32).try_into().unwrap(); + let lo: u128 = (value & BigUint::from(u128::MAX)).try_into().unwrap(); + Value::Struct(vec![Value::U128(lo), Value::U128(hi)]) +} + +pub fn eval_divmod( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::Struct(lhs), Value::Struct(rhs)]: [Value; 3] = + args.try_into().unwrap() + else { + panic!() + }; + + let [Value::U128(lhs_lo), Value::U128(lhs_hi)]: [Value; 2] = lhs.try_into().unwrap() else { + panic!() + }; + + let lhs = u256_to_biguint(lhs_lo, lhs_hi); + + let [Value::U128(rhs_lo), Value::U128(rhs_hi)]: [Value; 2] = rhs.try_into().unwrap() else { + panic!() + }; + + let rhs = u256_to_biguint(rhs_lo, rhs_hi); + + let div = &lhs / &rhs; + let modulo = lhs % rhs; + + EvalAction::NormalBranch( + 0, + smallvec![ + range_check, + u256_to_value(div), + u256_to_value(modulo), + Value::Unit + ], + ) +} From 89fb58741122bf036303e516ba8774b471610120 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 26 Aug 2024 17:51:31 +0200 Subject: [PATCH 40/40] uint128 libfuncs --- src/value.rs | 10 +++++++++- src/vm/uint128.rs | 19 ++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/value.rs b/src/value.rs index b49a72d..f72ac05 100644 --- a/src/value.rs +++ b/src/value.rs @@ -2,6 +2,7 @@ use cairo_lang_sierra::{ extensions::{ core::{CoreLibfunc, CoreType, CoreTypeConcrete}, starknet::StarkNetTypeConcrete, + ConcreteType, }, ids::ConcreteTypeId, program_registry::ProgramRegistry, @@ -76,7 +77,8 @@ impl Value { registry: &ProgramRegistry, type_id: &ConcreteTypeId, ) -> bool { - match registry.get_type(type_id).unwrap() { + let ty = registry.get_type(type_id).unwrap(); + let res = match ty { CoreTypeConcrete::Array(info) => { matches!(self, Self::Array { ty, .. } if *ty == info.ty) } @@ -145,7 +147,13 @@ impl Value { StarkNetTypeConcrete::Sha256StateHandle(_) => todo!(), }, CoreTypeConcrete::BoundedInt(_) => matches!(self, Self::BoundedInt { .. }), + }; + + if !res { + dbg!("value is mismatch", ty.info(), self); } + + res } #[doc(hidden)] diff --git a/src/vm/uint128.rs b/src/vm/uint128.rs index 965bce0..6ffc2cd 100644 --- a/src/vm/uint128.rs +++ b/src/vm/uint128.rs @@ -33,12 +33,29 @@ pub fn eval( Uint128Concrete::IsZero(info) => eval_is_zero(registry, info, args), Uint128Concrete::Divmod(info) => eval_divmod(registry, info, args), Uint128Concrete::Bitwise(info) => eval_bitwise(registry, info, args), - Uint128Concrete::GuaranteeMul(_) => todo!(), + Uint128Concrete::GuaranteeMul(info) => eval_guarantee_mul(registry, info, args), Uint128Concrete::MulGuaranteeVerify(info) => eval_guarantee_verify(registry, info, args), Uint128Concrete::ByteReverse(_) => todo!(), } } +pub fn eval_guarantee_mul( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::U128(lhs), Value::U128(rhs)]: [Value; 2] = args.try_into().unwrap() else { + panic!() + }; + + let mask128 = BigUint::from(u128::MAX); + let result = BigUint::from(lhs) * BigUint::from(rhs); + let high = Value::U128((&result >> 128u32).try_into().unwrap()); + let low = Value::U128((result & mask128).try_into().unwrap()); + + EvalAction::NormalBranch(0, smallvec![high, low, Value::Unit]) +} + pub fn eval_guarantee_verify( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc,