From 48c8947807ce114dee533563c3121c4aaaaf9674 Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 27 Aug 2024 15:28:25 +0200 Subject: [PATCH 01/15] u516 --- Cargo.toml | 8 +++--- Makefile | 4 +-- src/vm.rs | 3 ++- src/vm/uint252.rs | 17 +++++++++++-- src/vm/uint512.rs | 63 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 src/vm/uint512.rs diff --git a/Cargo.toml b/Cargo.toml index 97a85fa..30f8e51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,8 +14,8 @@ 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" +serde = { version = "1.0.209", features = ["derive"] } +serde_json = "1.0.127" sha2 = { version = "0.10.8", features = ["compress"] } smallvec = "1.13.2" starknet-crypto = "0.7.1" @@ -25,8 +25,8 @@ tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } [dev-dependencies] -cairo-lang-compiler = "2.7.0" -cairo-lang-starknet = "2.7.0" +cairo-lang-compiler = "2.7.1" +cairo-lang-starknet = "2.7.1" # On dev optimize dependencies a bit so it's not as slow. [profile.dev.package."*"] diff --git a/Makefile b/Makefile index 8ffeb61..50c3209 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,8 @@ UNAME := $(shell uname) -CAIRO_2_VERSION=2.7.0 -SCARB_VERSION = 2.7.0 +CAIRO_2_VERSION=2.7.1 +SCARB_VERSION = 2.7.1 needs-cairo2: ifeq ($(wildcard ./cairo2/.),) diff --git a/src/vm.rs b/src/vm.rs index 3f51a0d..c6e982f 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -50,6 +50,7 @@ mod uint252; mod uint32; mod uint64; mod uint8; +mod uint512; pub struct VirtualMachine { program: Arc, @@ -326,7 +327,7 @@ fn eval<'a>( 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::Uint512(selector) => self::uint512::eval(registry, selector, args), 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), diff --git a/src/vm/uint252.rs b/src/vm/uint252.rs index 98e8aab..d57682e 100644 --- a/src/vm/uint252.rs +++ b/src/vm/uint252.rs @@ -1,5 +1,3 @@ -use std::u128; - use super::EvalAction; use crate::Value; use cairo_lang_sierra::{ @@ -58,6 +56,21 @@ pub fn u256_to_value(value: BigUint) -> Value { Value::Struct(vec![Value::U128(lo), Value::U128(hi)]) } +#[inline] +pub fn u516_to_value(value: BigUint) -> Value { + let upper_u256: BigUint = &value >> 256u32; + let hi1: u128 = (&upper_u256 >> 128u32).try_into().unwrap(); + let lo1: u128 = (upper_u256 & BigUint::from(u128::MAX)).try_into().unwrap(); + 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), + Value::U128(lo1), + Value::U128(hi1), + ]) +} + pub fn eval_divmod( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, diff --git a/src/vm/uint512.rs b/src/vm/uint512.rs new file mode 100644 index 0000000..6468d21 --- /dev/null +++ b/src/vm/uint512.rs @@ -0,0 +1,63 @@ +use super::EvalAction; +use crate::{vm::uint252::{u256_to_biguint, u256_to_value, u516_to_value}, Value}; +use cairo_lang_sierra::{ + extensions::{ + core::{CoreLibfunc, CoreType}, + int::{unsigned256::Uint256Concrete, unsigned512::Uint512Concrete}, + lib_func::SignatureOnlyConcreteLibfunc, + }, + program_registry::ProgramRegistry, +}; +use num_bigint::BigUint; +use smallvec::smallvec; + +pub fn eval( + registry: &ProgramRegistry, + selector: &Uint512Concrete, + args: Vec, +) -> EvalAction { + match selector { + Uint512Concrete::DivModU256(info) => eval_divmod(registry, info, args), + } +} + +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(div_0), Value::U128(div_1), Value::U128(div_2), Value::U128(div_3)]: [Value; 4] = lhs.try_into().unwrap() else { + panic!() + }; + + let lhs = u256_to_biguint(div_0, div_1) | (u256_to_biguint(div_2, div_3) << 256); + + let [Value::U128(divisor_0), Value::U128(divisor_1)]: [Value; 2] = rhs.try_into().unwrap() else { + panic!() + }; + + let rhs = u256_to_biguint(divisor_0, divisor_1); + + let div = &lhs / &rhs; + let modulo = lhs % rhs; + + EvalAction::NormalBranch( + 0, + smallvec![ + range_check, + u516_to_value(div), + u256_to_value(modulo), + Value::Unit, + Value::Unit, + Value::Unit, + Value::Unit, + Value::Unit, + ], + ) +} From 5b4bf0ba1566805234f976064df2f6479cddaa3c Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 27 Aug 2024 17:19:17 +0200 Subject: [PATCH 02/15] impl slice --- src/vm.rs | 2 +- src/vm/array.rs | 28 +++++++++++++++++++++++++++- src/vm/uint512.rs | 12 +++++++++--- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/vm.rs b/src/vm.rs index c6e982f..4e0ad23 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -48,9 +48,9 @@ mod uint128; mod uint16; mod uint252; mod uint32; +mod uint512; mod uint64; mod uint8; -mod uint512; pub struct VirtualMachine { program: Arc, diff --git a/src/vm/array.rs b/src/vm/array.rs index a6bb54c..c44c82d 100644 --- a/src/vm/array.rs +++ b/src/vm/array.rs @@ -23,7 +23,7 @@ pub fn eval( ArrayConcreteLibfunc::PopFront(info) => eval_pop_front(registry, info, args), ArrayConcreteLibfunc::PopFrontConsume(_) => todo!(), ArrayConcreteLibfunc::Get(info) => eval_get(registry, info, args), - ArrayConcreteLibfunc::Slice(_) => todo!(), + ArrayConcreteLibfunc::Slice(info) => eval_slice(registry, info, args), ArrayConcreteLibfunc::Len(info) => eval_len(registry, info, args), ArrayConcreteLibfunc::SnapshotPopFront(info) => { eval_snapshot_pop_front(registry, info, args) @@ -91,6 +91,32 @@ pub fn eval_get( } } +pub fn eval_slice( + _registry: &ProgramRegistry, + _info: &SignatureAndTypeConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [range_check @ Value::Unit, Value::Array { data, ty }, Value::U32(start), Value::U32(len)]: [Value; 4] = + args.try_into().unwrap() + else { + panic!() + }; + + match data.get(start as usize..(start + len) as usize) { + Some(value) => EvalAction::NormalBranch( + 0, + smallvec![ + range_check, + Value::Array { + data: value.to_vec(), + ty + } + ], + ), + None => EvalAction::NormalBranch(1, smallvec![range_check]), + } +} + pub fn eval_len( _registry: &ProgramRegistry, _info: &SignatureAndTypeConcreteLibfunc, diff --git a/src/vm/uint512.rs b/src/vm/uint512.rs index 6468d21..baf3e50 100644 --- a/src/vm/uint512.rs +++ b/src/vm/uint512.rs @@ -1,5 +1,8 @@ use super::EvalAction; -use crate::{vm::uint252::{u256_to_biguint, u256_to_value, u516_to_value}, Value}; +use crate::{ + vm::uint252::{u256_to_biguint, u256_to_value, u516_to_value}, + Value, +}; use cairo_lang_sierra::{ extensions::{ core::{CoreLibfunc, CoreType}, @@ -32,13 +35,16 @@ pub fn eval_divmod( panic!() }; - let [Value::U128(div_0), Value::U128(div_1), Value::U128(div_2), Value::U128(div_3)]: [Value; 4] = lhs.try_into().unwrap() else { + let [Value::U128(div_0), Value::U128(div_1), Value::U128(div_2), Value::U128(div_3)]: [Value; + 4] = lhs.try_into().unwrap() + else { panic!() }; let lhs = u256_to_biguint(div_0, div_1) | (u256_to_biguint(div_2, div_3) << 256); - let [Value::U128(divisor_0), Value::U128(divisor_1)]: [Value; 2] = rhs.try_into().unwrap() else { + let [Value::U128(divisor_0), Value::U128(divisor_1)]: [Value; 2] = rhs.try_into().unwrap() + else { panic!() }; From 834dc64a797b18e87849fcadf2c0aa0dac0d8e07 Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 27 Aug 2024 17:39:33 +0200 Subject: [PATCH 03/15] cast bounded int --- src/vm/cast.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vm/cast.rs b/src/vm/cast.rs index 5fff9ed..22688d9 100644 --- a/src/vm/cast.rs +++ b/src/vm/cast.rs @@ -4,7 +4,7 @@ use cairo_lang_sierra::{ extensions::{ casts::{CastConcreteLibfunc, DowncastConcreteLibfunc}, core::{CoreLibfunc, CoreType, CoreTypeConcrete}, - lib_func::SignatureOnlyConcreteLibfunc, + lib_func::SignatureOnlyConcreteLibfunc, ConcreteType, }, program_registry::ProgramRegistry, }; @@ -54,7 +54,8 @@ pub fn eval_downcast( 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!(), + CoreTypeConcrete::BoundedInt(_) => Value::BoundedInt{ range, value }, + x => todo!("{:?}", x.info()), } ], ) From c883b6de32a874b8b200563201008c909ad3e801 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 28 Aug 2024 10:49:12 +0200 Subject: [PATCH 04/15] upd rust2 --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index ff6d7a9..4fdc48f 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.80.0" +channel = "1.80.1" components = ["rustfmt", "clippy"] profile = "minimal" From 9a23176df7ef80ca2da8acacfdc13bdbd876acdf Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 28 Aug 2024 12:00:21 +0200 Subject: [PATCH 05/15] fix warnings --- src/value.rs | 3 --- src/vm/cast.rs | 5 +++-- src/vm/circuit.rs | 5 +---- src/vm/uint128.rs | 2 -- src/vm/uint512.rs | 3 +-- 5 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/value.rs b/src/value.rs index 898444a..2f04b62 100644 --- a/src/value.rs +++ b/src/value.rs @@ -147,14 +147,12 @@ impl Value { CoreTypeConcrete::BuiltinCosts(_) => matches!(self, Self::Unit), CoreTypeConcrete::Uint16(_) => matches!(self, Self::U16(_)), CoreTypeConcrete::Uint64(_) => matches!(self, Self::U64(_)), - CoreTypeConcrete::Uint128(_) => matches!(self, Self::U128(_)), CoreTypeConcrete::Uint128MulGuarantee(_) => matches!(self, Self::Unit), CoreTypeConcrete::Sint16(_) => todo!(), CoreTypeConcrete::Sint32(_) => todo!(), CoreTypeConcrete::Sint64(_) => todo!(), CoreTypeConcrete::Sint128(_) => todo!(), CoreTypeConcrete::Nullable(info) => self.is(registry, &info.ty), - CoreTypeConcrete::RangeCheck96(_) => matches!(self, Self::Unit), CoreTypeConcrete::Uninitialized(_) => todo!(), CoreTypeConcrete::Felt252DictEntry(_) => todo!(), CoreTypeConcrete::SquashedFelt252Dict(_) => todo!(), @@ -170,7 +168,6 @@ impl Value { StarkNetTypeConcrete::Secp256Point(_) => todo!(), StarkNetTypeConcrete::Sha256StateHandle(_) => todo!(), }, - CoreTypeConcrete::BoundedInt(_) => matches!(self, Self::BoundedInt { .. }), }; if !res { diff --git a/src/vm/cast.rs b/src/vm/cast.rs index 22688d9..c442c9e 100644 --- a/src/vm/cast.rs +++ b/src/vm/cast.rs @@ -4,7 +4,8 @@ use cairo_lang_sierra::{ extensions::{ casts::{CastConcreteLibfunc, DowncastConcreteLibfunc}, core::{CoreLibfunc, CoreType, CoreTypeConcrete}, - lib_func::SignatureOnlyConcreteLibfunc, ConcreteType, + lib_func::SignatureOnlyConcreteLibfunc, + ConcreteType, }, program_registry::ProgramRegistry, }; @@ -54,7 +55,7 @@ pub fn eval_downcast( CoreTypeConcrete::Uint32(_) => Value::U32(value.try_into().unwrap()), CoreTypeConcrete::Uint64(_) => Value::U64(value.try_into().unwrap()), CoreTypeConcrete::Uint128(_) => Value::U128(value.try_into().unwrap()), - CoreTypeConcrete::BoundedInt(_) => Value::BoundedInt{ range, value }, + CoreTypeConcrete::BoundedInt(_) => Value::BoundedInt { range, value }, x => todo!("{:?}", x.info()), } ], diff --git a/src/vm/circuit.rs b/src/vm/circuit.rs index b9593a4..5764a35 100644 --- a/src/vm/circuit.rs +++ b/src/vm/circuit.rs @@ -1,5 +1,3 @@ -use std::u8; - use super::EvalAction; use crate::Value; use cairo_lang_sierra::{ @@ -15,7 +13,6 @@ use cairo_lang_sierra::{ }; use num_bigint::{BigInt, BigUint, Sign, ToBigInt}; use smallvec::smallvec; -use starknet_types_core::felt::Felt; pub fn eval( registry: &ProgramRegistry, @@ -193,7 +190,7 @@ pub fn eval_get_output( CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(info)) => &info.circuit_info, _ => todo!(), }; - let gate_offset = circuit_info.values.get(&_info.output_ty).unwrap().clone(); + let gate_offset = *circuit_info.values.get(&_info.output_ty).unwrap(); let output_idx = gate_offset - 1 - circuit_info.n_inputs; let output = outputs[output_idx].to_owned(); let output_big = output.to_bigint().unwrap(); diff --git a/src/vm/uint128.rs b/src/vm/uint128.rs index 6ffc2cd..72975b9 100644 --- a/src/vm/uint128.rs +++ b/src/vm/uint128.rs @@ -1,5 +1,3 @@ -use std::u128; - use super::EvalAction; use crate::Value; use cairo_lang_sierra::{ diff --git a/src/vm/uint512.rs b/src/vm/uint512.rs index baf3e50..03a6268 100644 --- a/src/vm/uint512.rs +++ b/src/vm/uint512.rs @@ -6,12 +6,11 @@ use crate::{ use cairo_lang_sierra::{ extensions::{ core::{CoreLibfunc, CoreType}, - int::{unsigned256::Uint256Concrete, unsigned512::Uint512Concrete}, + int::unsigned512::Uint512Concrete, lib_func::SignatureOnlyConcreteLibfunc, }, program_registry::ProgramRegistry, }; -use num_bigint::BigUint; use smallvec::smallvec; pub fn eval( From 6131e94b752beda0e56babe82a23ebf7cfd6b2ea Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 28 Aug 2024 12:56:26 +0200 Subject: [PATCH 06/15] enum from bounded --- src/vm/enum.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/vm/enum.rs b/src/vm/enum.rs index a76e51b..3ecd6eb 100644 --- a/src/vm/enum.rs +++ b/src/vm/enum.rs @@ -3,8 +3,12 @@ use crate::Value; use cairo_lang_sierra::{ extensions::{ core::{CoreLibfunc, CoreType, CoreTypeConcrete}, - enm::{EnumConcreteLibfunc, EnumConcreteType, EnumInitConcreteLibfunc}, + enm::{ + EnumConcreteLibfunc, EnumConcreteType, EnumFromBoundedIntConcreteLibfunc, + EnumInitConcreteLibfunc, + }, lib_func::SignatureOnlyConcreteLibfunc, + ConcreteLibfunc, }, program_registry::ProgramRegistry, }; @@ -17,7 +21,7 @@ pub fn eval( ) -> EvalAction { match selector { EnumConcreteLibfunc::Init(info) => eval_init(registry, info, args), - EnumConcreteLibfunc::FromBoundedInt(_) => todo!(), + EnumConcreteLibfunc::FromBoundedInt(info) => eval_from_bounded_int(registry, info, args), EnumConcreteLibfunc::Match(info) => eval_match(registry, info, args), EnumConcreteLibfunc::SnapshotMatch(_) => todo!(), } @@ -50,6 +54,24 @@ pub fn eval_init( ) } +pub fn eval_from_bounded_int( + _registry: &ProgramRegistry, + info: &EnumFromBoundedIntConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::BoundedInt { range: _, value }]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + let enm = Value::Enum { + self_ty: info.branch_signatures()[0].vars[0].ty.clone(), + index: value.try_into().unwrap(), + payload: Box::new(Value::Struct(vec![])), + }; + + EvalAction::NormalBranch(0, smallvec![enm]) +} + pub fn eval_match( registry: &ProgramRegistry, info: &SignatureOnlyConcreteLibfunc, From e8c761b9b35005bb3cd9476269b5a7bfed5e2253 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 28 Aug 2024 14:16:01 +0200 Subject: [PATCH 07/15] fixes --- src/debug.rs | 411 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/vm.rs | 13 +- src/vm/array.rs | 4 +- 4 files changed, 424 insertions(+), 5 deletions(-) create mode 100644 src/debug.rs diff --git a/src/debug.rs b/src/debug.rs new file mode 100644 index 0000000..93c0555 --- /dev/null +++ b/src/debug.rs @@ -0,0 +1,411 @@ +use cairo_lang_sierra::extensions::{ + array::ArrayConcreteLibfunc, + boolean::BoolConcreteLibfunc, + bounded_int::BoundedIntConcreteLibfunc, + boxing::BoxConcreteLibfunc, + bytes31::Bytes31ConcreteLibfunc, + casts::CastConcreteLibfunc, + circuit::CircuitConcreteLibfunc, + const_type::ConstConcreteLibfunc, + core::CoreConcreteLibfunc, + coupon::CouponConcreteLibfunc, + debug::DebugConcreteLibfunc, + ec::EcConcreteLibfunc, + enm::EnumConcreteLibfunc, + felt252::{Felt252BinaryOperationConcrete, Felt252BinaryOperator, Felt252Concrete}, + felt252_dict::{Felt252DictConcreteLibfunc, Felt252DictEntryConcreteLibfunc}, + gas::GasConcreteLibfunc, + int::{ + signed::SintConcrete, signed128::Sint128Concrete, unsigned::UintConcrete, + unsigned128::Uint128Concrete, unsigned256::Uint256Concrete, unsigned512::Uint512Concrete, + IntOperator, + }, + mem::MemConcreteLibfunc, + nullable::NullableConcreteLibfunc, + pedersen::PedersenConcreteLibfunc, + poseidon::PoseidonConcreteLibfunc, + starknet::{ + secp256::{Secp256ConcreteLibfunc, Secp256OpConcreteLibfunc}, + testing::TestingConcreteLibfunc, + StarkNetConcreteLibfunc, + }, + structure::StructConcreteLibfunc, +}; + +pub fn libfunc_to_name(value: &CoreConcreteLibfunc) -> &'static str { + match value { + CoreConcreteLibfunc::ApTracking(value) => match value { + cairo_lang_sierra::extensions::ap_tracking::ApTrackingConcreteLibfunc::Revoke(_) => { + "revoke_ap_tracking" + } + cairo_lang_sierra::extensions::ap_tracking::ApTrackingConcreteLibfunc::Enable(_) => { + "enable_ap_tracking" + } + cairo_lang_sierra::extensions::ap_tracking::ApTrackingConcreteLibfunc::Disable(_) => { + "disable_ap_tracking" + } + }, + CoreConcreteLibfunc::Array(value) => match value { + ArrayConcreteLibfunc::New(_) => "array_new", + ArrayConcreteLibfunc::SpanFromTuple(_) => "span_from_tuple", + ArrayConcreteLibfunc::Append(_) => "array_append", + ArrayConcreteLibfunc::PopFront(_) => "array_pop_front", + ArrayConcreteLibfunc::PopFrontConsume(_) => "array_pop_front_consume", + ArrayConcreteLibfunc::Get(_) => "array_get", + ArrayConcreteLibfunc::Slice(_) => "array_slice", + ArrayConcreteLibfunc::Len(_) => "array_len", + ArrayConcreteLibfunc::SnapshotPopFront(_) => "array_snapshot_pop_front", + ArrayConcreteLibfunc::SnapshotPopBack(_) => "array_snapshot_pop_back", + ArrayConcreteLibfunc::TupleFromSpan(_) => "array_tuple_from_span", + ArrayConcreteLibfunc::SnapshotMultiPopFront(_) => "array_snapshot_multi_pop_front", + ArrayConcreteLibfunc::SnapshotMultiPopBack(_) => "array_snapshot_multi_pop_back", + }, + CoreConcreteLibfunc::BranchAlign(_) => "branch_align", + CoreConcreteLibfunc::Bool(value) => match value { + BoolConcreteLibfunc::And(_) => "bool_and", + BoolConcreteLibfunc::Not(_) => "bool_not", + BoolConcreteLibfunc::Xor(_) => "bool_xor", + BoolConcreteLibfunc::Or(_) => "bool_or", + BoolConcreteLibfunc::ToFelt252(_) => "bool_to_felt252", + }, + CoreConcreteLibfunc::Box(value) => match value { + BoxConcreteLibfunc::Into(_) => "box_into", + BoxConcreteLibfunc::Unbox(_) => "box_unbox", + BoxConcreteLibfunc::ForwardSnapshot(_) => "box_forward_snapshot", + }, + CoreConcreteLibfunc::Cast(value) => match value { + CastConcreteLibfunc::Downcast(_) => "downcast", + CastConcreteLibfunc::Upcast(_) => "upcast", + }, + CoreConcreteLibfunc::Coupon(value) => match value { + CouponConcreteLibfunc::Buy(_) => "coupon_buy", + CouponConcreteLibfunc::Refund(_) => "coupon_refund", + }, + CoreConcreteLibfunc::CouponCall(_) => "coupon_call", + CoreConcreteLibfunc::Drop(_) => "drop", + CoreConcreteLibfunc::Dup(_) => "dup", + CoreConcreteLibfunc::Ec(value) => match value { + EcConcreteLibfunc::IsZero(_) => "ec_is_zero", + EcConcreteLibfunc::Neg(_) => "ec_neg", + EcConcreteLibfunc::StateAdd(_) => "ec_state_add", + EcConcreteLibfunc::TryNew(_) => "ec_try_new", + EcConcreteLibfunc::StateFinalize(_) => "ec_state_finalize", + EcConcreteLibfunc::StateInit(_) => "ec_state_init", + EcConcreteLibfunc::StateAddMul(_) => "ec_state_add_mul", + EcConcreteLibfunc::PointFromX(_) => "ec_point_from_x", + EcConcreteLibfunc::UnwrapPoint(_) => "ec_unwrap_point", + EcConcreteLibfunc::Zero(_) => "ec_zero", + }, + CoreConcreteLibfunc::Felt252(value) => match value { + Felt252Concrete::BinaryOperation(op) => match op { + Felt252BinaryOperationConcrete::WithVar(op) => match &op.operator { + Felt252BinaryOperator::Add => "felt252_add", + Felt252BinaryOperator::Sub => "felt252_sub", + Felt252BinaryOperator::Mul => "felt252_mul", + Felt252BinaryOperator::Div => "felt252_div", + }, + Felt252BinaryOperationConcrete::WithConst(op) => match &op.operator { + Felt252BinaryOperator::Add => "felt252_const_add", + Felt252BinaryOperator::Sub => "felt252_const_sub", + Felt252BinaryOperator::Mul => "felt252_const_mul", + Felt252BinaryOperator::Div => "felt252_const_div", + }, + }, + Felt252Concrete::Const(_) => "felt252_const", + Felt252Concrete::IsZero(_) => "felt252_is_zero", + }, + CoreConcreteLibfunc::Const(value) => match value { + ConstConcreteLibfunc::AsBox(_) => "const_as_box", + ConstConcreteLibfunc::AsImmediate(_) => "const_as_immediate", + }, + CoreConcreteLibfunc::FunctionCall(_) => "function_call", + CoreConcreteLibfunc::Gas(value) => match value { + GasConcreteLibfunc::WithdrawGas(_) => "withdraw_gas", + GasConcreteLibfunc::RedepositGas(_) => "redeposit_gas", + GasConcreteLibfunc::GetAvailableGas(_) => "get_available_gas", + GasConcreteLibfunc::BuiltinWithdrawGas(_) => "builtin_withdraw_gas", + GasConcreteLibfunc::GetBuiltinCosts(_) => "get_builtin_costs", + }, + CoreConcreteLibfunc::Uint8(value) => match value { + UintConcrete::Const(_) => "u8_const", + UintConcrete::Operation(op) => match &op.operator { + IntOperator::OverflowingAdd => "u8_overflowing_add", + IntOperator::OverflowingSub => "u8_overflowing_sub", + }, + UintConcrete::SquareRoot(_) => "u8_sqrt", + UintConcrete::Equal(_) => "u8_eq", + UintConcrete::ToFelt252(_) => "u8_to_felt252", + UintConcrete::FromFelt252(_) => "u8_from_felt252", + UintConcrete::IsZero(_) => "u8_is_zero", + UintConcrete::Divmod(_) => "u8_divmod", + UintConcrete::WideMul(_) => "u8_wide_mul", + UintConcrete::Bitwise(_) => "u8_bitwise", + }, + CoreConcreteLibfunc::Uint16(value) => match value { + UintConcrete::Const(_) => "u16_const", + UintConcrete::Operation(op) => match &op.operator { + IntOperator::OverflowingAdd => "u16_overflowing_add", + IntOperator::OverflowingSub => "u16_overflowing_sub", + }, + UintConcrete::SquareRoot(_) => "u16_sqrt", + UintConcrete::Equal(_) => "u16_eq", + UintConcrete::ToFelt252(_) => "u16_to_felt252", + UintConcrete::FromFelt252(_) => "u16_from_felt252", + UintConcrete::IsZero(_) => "u16_is_zero", + UintConcrete::Divmod(_) => "u16_divmod", + UintConcrete::WideMul(_) => "u16_wide_mul", + UintConcrete::Bitwise(_) => "u16_bitwise", + }, + CoreConcreteLibfunc::Uint32(value) => match value { + UintConcrete::Const(_) => "u32_const", + UintConcrete::Operation(op) => match &op.operator { + IntOperator::OverflowingAdd => "u32_overflowing_add", + IntOperator::OverflowingSub => "u32_overflowing_sub", + }, + UintConcrete::SquareRoot(_) => "u32_sqrt", + UintConcrete::Equal(_) => "u32_eq", + UintConcrete::ToFelt252(_) => "u32_to_felt252", + UintConcrete::FromFelt252(_) => "u32_from_felt252", + UintConcrete::IsZero(_) => "u32_is_zero", + UintConcrete::Divmod(_) => "u32_divmod", + UintConcrete::WideMul(_) => "u32_wide_mul", + UintConcrete::Bitwise(_) => "u32_bitwise", + }, + CoreConcreteLibfunc::Uint64(value) => match value { + UintConcrete::Const(_) => "u64_const", + UintConcrete::Operation(op) => match &op.operator { + IntOperator::OverflowingAdd => "u64_overflowing_add", + IntOperator::OverflowingSub => "u64_overflowing_sub", + }, + UintConcrete::SquareRoot(_) => "u64_sqrt", + UintConcrete::Equal(_) => "u64_eq", + UintConcrete::ToFelt252(_) => "u64_to_felt252", + UintConcrete::FromFelt252(_) => "u64_from_felt252", + UintConcrete::IsZero(_) => "u64_is_zero", + UintConcrete::Divmod(_) => "u64_divmod", + UintConcrete::WideMul(_) => "u64_wide_mul", + UintConcrete::Bitwise(_) => "u64_bitwise", + }, + CoreConcreteLibfunc::Uint128(value) => match value { + Uint128Concrete::Operation(op) => match &op.operator { + IntOperator::OverflowingAdd => "u128_overflowing_add", + IntOperator::OverflowingSub => "u128_overflowing_sub", + }, + Uint128Concrete::Divmod(_) => "u128_divmod", + Uint128Concrete::GuaranteeMul(_) => "u128_guarantee_mul", + Uint128Concrete::MulGuaranteeVerify(_) => "u128_mul_guarantee_verify", + Uint128Concrete::Equal(_) => "u128_equal", + Uint128Concrete::SquareRoot(_) => "u128_sqrt", + Uint128Concrete::Const(_) => "u128_const", + Uint128Concrete::FromFelt252(_) => "u128_from_felt", + Uint128Concrete::ToFelt252(_) => "u128_to_felt252", + Uint128Concrete::IsZero(_) => "u128_is_zero", + Uint128Concrete::Bitwise(_) => "u128_bitwise", + Uint128Concrete::ByteReverse(_) => "u128_byte_reverse", + }, + CoreConcreteLibfunc::Uint256(value) => match value { + Uint256Concrete::IsZero(_) => "u256_is_zero", + Uint256Concrete::Divmod(_) => "u256_divmod", + Uint256Concrete::SquareRoot(_) => "u256_sqrt", + Uint256Concrete::InvModN(_) => "u256_inv_mod_n", + }, + CoreConcreteLibfunc::Uint512(value) => match value { + Uint512Concrete::DivModU256(_) => "u512_divmod_u256", + }, + CoreConcreteLibfunc::Sint8(value) => match value { + SintConcrete::Const(_) => "i8_const", + SintConcrete::Equal(_) => "i8_eq", + SintConcrete::ToFelt252(_) => "i8_to_felt252", + SintConcrete::FromFelt252(_) => "i8_from_felt252", + SintConcrete::Operation(op) => match &op.operator { + IntOperator::OverflowingAdd => "i8_overflowing_add", + IntOperator::OverflowingSub => "i8_overflowing_sub", + }, + SintConcrete::Diff(_) => "i8_diff", + SintConcrete::IsZero(_) => "i8_is_zero", + SintConcrete::WideMul(_) => "i8_wide_mul", + }, + CoreConcreteLibfunc::Sint16(value) => match value { + SintConcrete::Const(_) => "i16_const", + SintConcrete::Equal(_) => "i16_eq", + SintConcrete::ToFelt252(_) => "i16_to_felt252", + SintConcrete::FromFelt252(_) => "i16_from_felt252", + SintConcrete::Operation(op) => match &op.operator { + IntOperator::OverflowingAdd => "i16_overflowing_add", + IntOperator::OverflowingSub => "i16_overflowing_sub", + }, + SintConcrete::Diff(_) => "i16_diff", + SintConcrete::IsZero(_) => "i16_is_zero", + SintConcrete::WideMul(_) => "i16_wide_mul", + }, + CoreConcreteLibfunc::Sint32(value) => match value { + SintConcrete::Const(_) => "i32_const", + SintConcrete::Equal(_) => "i32_eq", + SintConcrete::ToFelt252(_) => "i32_to_felt252", + SintConcrete::FromFelt252(_) => "i32_from_felt252", + SintConcrete::Operation(op) => match &op.operator { + IntOperator::OverflowingAdd => "i32_overflowing_add", + IntOperator::OverflowingSub => "i32_overflowing_sub", + }, + SintConcrete::Diff(_) => "i32_diff", + SintConcrete::IsZero(_) => "i32_is_zero", + SintConcrete::WideMul(_) => "i32_wide_mul", + }, + CoreConcreteLibfunc::Sint64(value) => match value { + SintConcrete::Const(_) => "i64_const", + SintConcrete::Equal(_) => "i64_eq", + SintConcrete::ToFelt252(_) => "i64_to_felt252", + SintConcrete::FromFelt252(_) => "i64_from_felt252", + SintConcrete::Operation(op) => match &op.operator { + IntOperator::OverflowingAdd => "i64_overflowing_add", + IntOperator::OverflowingSub => "i64_overflowing_sub", + }, + SintConcrete::Diff(_) => "i64_diff", + SintConcrete::IsZero(_) => "i64_is_zero", + SintConcrete::WideMul(_) => "i64_wide_mul", + }, + CoreConcreteLibfunc::Sint128(value) => match value { + Sint128Concrete::Const(_) => "i128_const", + Sint128Concrete::Equal(_) => "i128_eq", + Sint128Concrete::ToFelt252(_) => "i128_to_felt252", + Sint128Concrete::FromFelt252(_) => "i128_from_felt252", + Sint128Concrete::Operation(op) => match &op.operator { + IntOperator::OverflowingAdd => "i128_overflowing_add", + IntOperator::OverflowingSub => "i128_overflowing_sub", + }, + Sint128Concrete::Diff(_) => "i128_diff", + Sint128Concrete::IsZero(_) => "i128_is_zero", + }, + CoreConcreteLibfunc::Mem(value) => match value { + MemConcreteLibfunc::StoreTemp(_) => "store_temp", + MemConcreteLibfunc::StoreLocal(_) => "store_local", + MemConcreteLibfunc::FinalizeLocals(_) => "finalize_locals", + MemConcreteLibfunc::AllocLocal(_) => "alloc_local", + MemConcreteLibfunc::Rename(_) => "rename", + }, + CoreConcreteLibfunc::Nullable(value) => match value { + NullableConcreteLibfunc::Null(_) => "nullable_null", + NullableConcreteLibfunc::NullableFromBox(_) => "nullable_from_box", + NullableConcreteLibfunc::MatchNullable(_) => "match_nullable", + NullableConcreteLibfunc::ForwardSnapshot(_) => "nullable_forward_snapshot", + }, + CoreConcreteLibfunc::UnwrapNonZero(_) => "unwrap_non_zero", + CoreConcreteLibfunc::UnconditionalJump(_) => "jump", + CoreConcreteLibfunc::Enum(value) => match value { + EnumConcreteLibfunc::Init(_) => "enum_init", + EnumConcreteLibfunc::FromBoundedInt(_) => "enum_from_bounded_int", + EnumConcreteLibfunc::Match(_) => "enum_match", + EnumConcreteLibfunc::SnapshotMatch(_) => "enum_snapshot_match", + }, + CoreConcreteLibfunc::Struct(value) => match value { + StructConcreteLibfunc::Construct(_) => "struct_construct", + StructConcreteLibfunc::Deconstruct(_) => "struct_deconstruct", + StructConcreteLibfunc::SnapshotDeconstruct(_) => "struct_snapshot_deconstruct", + }, + CoreConcreteLibfunc::Felt252Dict(value) => match value { + Felt252DictConcreteLibfunc::New(_) => "felt252dict_new", + Felt252DictConcreteLibfunc::Squash(_) => "felt252dict_squash", + }, + CoreConcreteLibfunc::Felt252DictEntry(value) => match value { + Felt252DictEntryConcreteLibfunc::Get(_) => "felt252dict_get", + Felt252DictEntryConcreteLibfunc::Finalize(_) => "felt252dict_finalize", + }, + CoreConcreteLibfunc::Pedersen(value) => match value { + PedersenConcreteLibfunc::PedersenHash(_) => "pedersen_hash", + }, + CoreConcreteLibfunc::Poseidon(value) => match value { + PoseidonConcreteLibfunc::HadesPermutation(_) => "hades_permutation", + }, + CoreConcreteLibfunc::StarkNet(value) => match value { + StarkNetConcreteLibfunc::CallContract(_) => "call_contract", + StarkNetConcreteLibfunc::ClassHashConst(_) => "class_hash_const", + StarkNetConcreteLibfunc::ClassHashTryFromFelt252(_) => "class_hash_try_from_felt252", + StarkNetConcreteLibfunc::ClassHashToFelt252(_) => "class_hash_to_felt252", + StarkNetConcreteLibfunc::ContractAddressConst(_) => "contract_address_const", + StarkNetConcreteLibfunc::ContractAddressTryFromFelt252(_) => { + "contract_address_try_from_felt252" + } + StarkNetConcreteLibfunc::ContractAddressToFelt252(_) => "contract_address_to_felt252", + StarkNetConcreteLibfunc::StorageRead(_) => "storage_read", + StarkNetConcreteLibfunc::StorageWrite(_) => "storage_write", + StarkNetConcreteLibfunc::StorageBaseAddressConst(_) => "storage_base_address_const", + StarkNetConcreteLibfunc::StorageBaseAddressFromFelt252(_) => { + "storage_base_address_from_felt252" + } + StarkNetConcreteLibfunc::StorageAddressFromBase(_) => "storage_address_from_base", + StarkNetConcreteLibfunc::StorageAddressFromBaseAndOffset(_) => { + "storage_address_from_base_and_offset" + } + StarkNetConcreteLibfunc::StorageAddressToFelt252(_) => "storage_address_to_felt252", + StarkNetConcreteLibfunc::StorageAddressTryFromFelt252(_) => { + "storage_address_try_from_felt252" + } + StarkNetConcreteLibfunc::EmitEvent(_) => "emit_event", + StarkNetConcreteLibfunc::GetBlockHash(_) => "get_block_hash", + StarkNetConcreteLibfunc::GetExecutionInfo(_) => "get_exec_info_v1", + StarkNetConcreteLibfunc::GetExecutionInfoV2(_) => "get_exec_info_v2", + StarkNetConcreteLibfunc::Deploy(_) => "deploy", + StarkNetConcreteLibfunc::Keccak(_) => "keccak", + StarkNetConcreteLibfunc::LibraryCall(_) => "library_call", + StarkNetConcreteLibfunc::ReplaceClass(_) => "replace_class", + StarkNetConcreteLibfunc::SendMessageToL1(_) => "send_message_to_l1", + StarkNetConcreteLibfunc::Testing(value) => match value { + TestingConcreteLibfunc::Cheatcode(_) => "cheatcode", + }, + StarkNetConcreteLibfunc::Secp256(value) => match value { + Secp256ConcreteLibfunc::K1(value) => match value { + Secp256OpConcreteLibfunc::New(_) => "secp256k1_new", + Secp256OpConcreteLibfunc::Add(_) => "secp256k1_add", + Secp256OpConcreteLibfunc::Mul(_) => "secp256k1_mul", + Secp256OpConcreteLibfunc::GetPointFromX(_) => "secp256k1_get_point_from_x", + Secp256OpConcreteLibfunc::GetXy(_) => "secp256k1_get_xy", + }, + Secp256ConcreteLibfunc::R1(value) => match value { + Secp256OpConcreteLibfunc::New(_) => "secp256r1_new", + Secp256OpConcreteLibfunc::Add(_) => "secp256r1_add", + Secp256OpConcreteLibfunc::Mul(_) => "secp256r1_mul", + Secp256OpConcreteLibfunc::GetPointFromX(_) => "secp256r1_get_point_from_x", + Secp256OpConcreteLibfunc::GetXy(_) => "secp256r1_get_xy", + }, + }, + StarkNetConcreteLibfunc::Sha256ProcessBlock(_) => "sha256_process_block", + StarkNetConcreteLibfunc::Sha256StateHandleInit(_) => "sha256_state_handle_init", + StarkNetConcreteLibfunc::Sha256StateHandleDigest(_) => "sha256_state_handle_digest", + }, + CoreConcreteLibfunc::Debug(value) => match value { + DebugConcreteLibfunc::Print(_) => "debug_print", + }, + CoreConcreteLibfunc::SnapshotTake(_) => "snapshot_take", + CoreConcreteLibfunc::Bytes31(value) => match value { + Bytes31ConcreteLibfunc::Const(_) => "bytes31_const", + Bytes31ConcreteLibfunc::ToFelt252(_) => "bytes31_to_felt252", + Bytes31ConcreteLibfunc::TryFromFelt252(_) => "bytes31_try_from_felt252", + }, + CoreConcreteLibfunc::Circuit(selector) => match selector { + CircuitConcreteLibfunc::AddInput(_) => "circuit_add_input", + CircuitConcreteLibfunc::Eval(_) => "circuit_eval", + CircuitConcreteLibfunc::GetDescriptor(_) => "circuit_get_descriptor", + CircuitConcreteLibfunc::InitCircuitData(_) => "circuit_init_circuit_data", + CircuitConcreteLibfunc::GetOutput(_) => "circuit_get_output", + CircuitConcreteLibfunc::TryIntoCircuitModulus(_) => "circuit_try_into_circuit_modulus", + CircuitConcreteLibfunc::FailureGuaranteeVerify(_) => "circuit_failure_guarantee_verify", + CircuitConcreteLibfunc::IntoU96Guarantee(_) => "circuit_into_u96_guarantee", + CircuitConcreteLibfunc::U96GuaranteeVerify(_) => "circuit_u96_guarantee_verify", + CircuitConcreteLibfunc::U96LimbsLessThanGuaranteeVerify(_) => { + "circuit_u96_limbs_less_than_guarantee_verify" + } + CircuitConcreteLibfunc::U96SingleLimbLessThanGuaranteeVerify(_) => { + "circuit_u96_single_limb_less_than_guarantee_verify" + } + }, + CoreConcreteLibfunc::BoundedInt(selector) => match selector { + BoundedIntConcreteLibfunc::Add(_) => "bounded_int_add", + BoundedIntConcreteLibfunc::Sub(_) => "bounded_int_sub", + BoundedIntConcreteLibfunc::Mul(_) => "bounded_int_mul", + BoundedIntConcreteLibfunc::DivRem(_) => "bounded_int_div_rem", + BoundedIntConcreteLibfunc::Constrain(_) => "bounded_int_constrain", + BoundedIntConcreteLibfunc::IsZero(_) => "bounded_int_is_zero", + BoundedIntConcreteLibfunc::WrapNonZero(_) => "bounded_int_wrap_non_zero", + }, + } +} diff --git a/src/lib.rs b/src/lib.rs index fd94664..fb720db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ use cairo_lang_sierra::program::{GenFunction, Program, StatementIdx}; pub use self::{dump::*, value::*, vm::VirtualMachine}; +mod debug; mod dump; pub mod starknet; mod value; diff --git a/src/vm.rs b/src/vm.rs index a99a916..9814d38 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,4 +1,5 @@ use crate::{ + debug::libfunc_to_name, starknet::{StarknetSyscallHandler, StubSyscallHandler}, Value, }; @@ -17,7 +18,7 @@ use cairo_lang_utils::ordered_hash_map::OrderedHashMap; use smallvec::{smallvec, SmallVec}; use starknet_types_core::felt::Felt; use std::{cell::Cell, sync::Arc}; -use tracing::debug; +use tracing::{debug, trace}; mod ap_tracking; mod array; @@ -181,11 +182,17 @@ impl VirtualMachine { let state_snapshot = frame.state.get_mut().clone(); debug!( - "Evaluating statement {} ({}) (values: \n{:#?}\n)", - frame.pc.0, &self.program.statements[frame.pc.0], state_snapshot + "Evaluating statement {} ({})", + frame.pc.0, &self.program.statements[frame.pc.0], ); + trace!("values: \n{:#?}\n", state_snapshot); match &self.program.statements[frame.pc.0] { GenStatement::Invocation(invocation) => { + let libfunc = self.registry.get_libfunc(&invocation.libfunc_id).unwrap(); + debug!( + "Executing invocation of libfunc: {}", + libfunc_to_name(libfunc) + ); let (state, values) = edit_state::take_args(frame.state.take(), invocation.args.iter()).unwrap(); diff --git a/src/vm/array.rs b/src/vm/array.rs index c44c82d..10d0472 100644 --- a/src/vm/array.rs +++ b/src/vm/array.rs @@ -87,7 +87,7 @@ pub fn eval_get( match data.get(index as usize).cloned() { Some(value) => EvalAction::NormalBranch(0, smallvec![range_check, value]), - None => EvalAction::NormalBranch(0, smallvec![range_check]), + None => EvalAction::NormalBranch(1, smallvec![range_check]), } } @@ -144,7 +144,7 @@ pub fn eval_pop_front( let value = data[0].clone(); EvalAction::NormalBranch(0, smallvec![Value::Array { data: new_data, ty }, value]) } else { - EvalAction::NormalBranch(1, smallvec![]) + EvalAction::NormalBranch(1, smallvec![Value::Array { data, ty }]) } } From c72405801d566b02ec3cad9a8fd9b7f2a8336198 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 28 Aug 2024 16:36:50 +0200 Subject: [PATCH 08/15] snapshot match --- src/vm/enum.rs | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/vm/enum.rs b/src/vm/enum.rs index 3ecd6eb..5fce56b 100644 --- a/src/vm/enum.rs +++ b/src/vm/enum.rs @@ -23,7 +23,7 @@ pub fn eval( EnumConcreteLibfunc::Init(info) => eval_init(registry, info, args), EnumConcreteLibfunc::FromBoundedInt(info) => eval_from_bounded_int(registry, info, args), EnumConcreteLibfunc::Match(info) => eval_match(registry, info, args), - EnumConcreteLibfunc::SnapshotMatch(_) => todo!(), + EnumConcreteLibfunc::SnapshotMatch(info) => eval_snapshot_match(registry, info, args), } } @@ -93,3 +93,35 @@ pub fn eval_match( EvalAction::NormalBranch(index, smallvec![*payload]) } + +pub fn eval_snapshot_match( + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::Enum { + self_ty, + index, + payload, + }]: [Value; 1] = args.try_into().unwrap() + else { + panic!() + }; + + let ty = registry + .get_type(&info.signature.param_signatures[0].ty) + .unwrap(); + + if let CoreTypeConcrete::Snapshot(inner) = ty { + assert_eq!(inner.ty, self_ty); + } else { + panic!("expected snapshot type") + } + + assert!(payload.is( + registry, + &info.signature.branch_signatures[index].vars[0].ty + )); + + EvalAction::NormalBranch(index, smallvec![*payload]) +} From 34ea6a8fb409421788759b8fa25367824b99a329 Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 29 Aug 2024 12:35:05 +0200 Subject: [PATCH 09/15] add gas --- Cargo.toml | 3 + src/gas.rs | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/value.rs | 7 +- src/vm.rs | 16 +++- src/vm/gas.rs | 43 ++++++++-- 6 files changed, 274 insertions(+), 11 deletions(-) create mode 100644 src/gas.rs diff --git a/Cargo.toml b/Cargo.toml index e1d33a9..07a4555 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,8 @@ edition = "2021" [dependencies] cairo-lang-sierra = "^2.7.1" +cairo-lang-sierra-ap-change = "^2.7.1" +cairo-lang-sierra-gas = "^2.7.1" cairo-lang-utils = "^2.7.1" clap = { version = "4.5.16", features = ["derive"] } k256 = "0.13.3" @@ -21,6 +23,7 @@ smallvec = "1.13.2" starknet-crypto = "0.7.1" starknet-curve = "0.5.0" starknet-types-core = "0.1.2" +thiserror = "1.0.63" tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } diff --git a/src/gas.rs b/src/gas.rs new file mode 100644 index 0000000..4792983 --- /dev/null +++ b/src/gas.rs @@ -0,0 +1,215 @@ +use cairo_lang_sierra::{ + extensions::gas::CostTokenType, + ids::FunctionId, + program::{Program, StatementIdx}, +}; +use cairo_lang_sierra_ap_change::{ + ap_change_info::ApChangeInfo, calc_ap_changes, + compute::calc_ap_changes as linear_calc_ap_changes, ApChangeError, +}; +use cairo_lang_sierra_gas::{ + compute_postcost_info, compute_precost_info, gas_info::GasInfo, CostError, +}; +use cairo_lang_utils::{casts::IntoOrPanic, ordered_hash_map::OrderedHashMap}; + +/// Holds global gas info. +#[derive(Debug, Default, PartialEq, Eq)] +pub struct GasMetadata { + pub ap_change_info: ApChangeInfo, + pub gas_info: GasInfo, +} + +/// Configuration for metadata computation. +#[derive(Debug, Clone)] +pub struct MetadataComputationConfig { + pub function_set_costs: OrderedHashMap>, + // ignored, its always used + pub linear_gas_solver: bool, + pub linear_ap_change_solver: bool, +} + +impl Default for MetadataComputationConfig { + fn default() -> Self { + Self { + function_set_costs: Default::default(), + linear_gas_solver: true, + linear_ap_change_solver: true, + } + } +} + +/// Error for metadata calculations. +#[derive(Debug, thiserror::Error, Eq, PartialEq)] +pub enum GasMetadataError { + #[error(transparent)] + ApChangeError(#[from] ApChangeError), + #[error(transparent)] + CostError(#[from] CostError), + #[error("Not enough gas to run the operation. Required: {:?}, Available: {:?}.", gas.0, gas.1)] + NotEnoughGas { gas: Box<(u128, u128)> }, +} + +impl GasMetadata { + pub fn new( + sierra_program: &Program, + config: Option, + ) -> Result { + if let Some(metadata_config) = config { + calc_metadata(sierra_program, metadata_config) + } else { + calc_metadata_ap_change_only(sierra_program) + } + } + + /// Returns the initial value for the gas counter. + /// If `available_gas` is None returns 0. + pub fn get_initial_available_gas( + &self, + func: &FunctionId, + available_gas: Option, + ) -> Result { + let Some(available_gas) = available_gas else { + return Ok(0); + }; + + // In case we don't have any costs - it means no gas equations were solved (and we are in + // the case of no gas checking enabled) - so the gas builtin is irrelevant, and we + // can return any value. + let Some(required_gas) = self.initial_required_gas(func) else { + return Ok(0); + }; + + available_gas + .checked_sub(required_gas) + .ok_or(GasMetadataError::NotEnoughGas { + gas: Box::new((required_gas, available_gas)), + }) + } + + pub fn initial_required_gas(&self, func: &FunctionId) -> Option { + if self.gas_info.function_costs.is_empty() { + return None; + } + Some( + self.gas_info.function_costs[func] + .iter() + .map(|(token_type, val)| val.into_or_panic::() * token_gas_cost(*token_type)) + .sum::() as u128, + ) + } + + pub fn get_gas_cost_for_statement(&self, idx: StatementIdx) -> Option { + let mut cost = None; + for cost_type in CostTokenType::iter_casm_tokens() { + if let Some(amount) = + self.get_gas_cost_for_statement_and_cost_token_type(idx, *cost_type) + { + *cost.get_or_insert(0) += amount * token_gas_cost(*cost_type) as u128; + } + } + cost + } + + pub fn get_gas_cost_for_statement_and_cost_token_type( + &self, + idx: StatementIdx, + cost_type: CostTokenType, + ) -> Option { + self.gas_info + .variable_values + .get(&(idx, cost_type)) + .copied() + .map(|x| { + x.try_into() + .expect("gas cost couldn't be converted to u128, should never happen") + }) + } +} + +impl Clone for GasMetadata { + fn clone(&self) -> Self { + Self { + ap_change_info: ApChangeInfo { + variable_values: self.ap_change_info.variable_values.clone(), + function_ap_change: self.ap_change_info.function_ap_change.clone(), + }, + gas_info: GasInfo { + variable_values: self.gas_info.variable_values.clone(), + function_costs: self.gas_info.function_costs.clone(), + }, + } + } +} + +/// Methods from https://github.com/starkware-libs/cairo/blob/fbdbbe4c42a6808eccbff8436078f73d0710c772/crates/cairo-lang-sierra-to-casm/src/metadata.rs#L71 + +/// Calculates the metadata for a Sierra program, with ap change info only. +fn calc_metadata_ap_change_only(program: &Program) -> Result { + Ok(GasMetadata { + ap_change_info: calc_ap_changes(program, |_, _| 0)?, + gas_info: GasInfo { + variable_values: Default::default(), + function_costs: Default::default(), + }, + }) +} + +/// Calculates the metadata for a Sierra program. +/// +/// `no_eq_solver` uses a linear-time algorithm for calculating the gas, instead of solving +/// equations. +fn calc_metadata( + program: &Program, + config: MetadataComputationConfig, +) -> Result { + let pre_gas_info = compute_precost_info(program)?; + + let ap_change_info = if config.linear_ap_change_solver { + linear_calc_ap_changes + } else { + calc_ap_changes + }(program, |idx, token_type| { + pre_gas_info.variable_values[&(idx, token_type)] as usize + })?; + + let enforced_function_costs: OrderedHashMap = config + .function_set_costs + .iter() + .map(|(func, costs)| (func.clone(), costs[&CostTokenType::Const])) + .collect(); + let post_gas_info = compute_postcost_info( + program, + &|idx| { + ap_change_info + .variable_values + .get(idx) + .copied() + .unwrap_or_default() + }, + &pre_gas_info, + &enforced_function_costs, + )?; + + Ok(GasMetadata { + ap_change_info, + gas_info: pre_gas_info.combine(post_gas_info), + }) +} + +pub fn token_gas_cost(token_type: CostTokenType) -> usize { + match token_type { + CostTokenType::Const => 1, + CostTokenType::Step + | CostTokenType::Hole + | CostTokenType::RangeCheck + | CostTokenType::RangeCheck96 => { + panic!("Token type {:?} has no gas cost.", token_type) + } + CostTokenType::Pedersen => 4130, + CostTokenType::Poseidon => 500, + CostTokenType::Bitwise => 594, + CostTokenType::EcOp => 4166, + CostTokenType::AddMod => 234, + CostTokenType::MulMod => 616, + } +} diff --git a/src/lib.rs b/src/lib.rs index fb720db..beb9a56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ pub use self::{dump::*, value::*, vm::VirtualMachine}; mod debug; mod dump; +mod gas; pub mod starknet; mod value; mod vm; diff --git a/src/value.rs b/src/value.rs index 2f04b62..79ad98a 100644 --- a/src/value.rs +++ b/src/value.rs @@ -72,8 +72,13 @@ impl Value { type_id: &ConcreteTypeId, ) -> Self { match registry.get_type(type_id).unwrap() { + CoreTypeConcrete::Uint8(_) => Value::U8(0), CoreTypeConcrete::Uint32(_) => Value::U32(0), - _ => panic!("type {type_id} has no default value implementation"), + CoreTypeConcrete::Uint64(_) => Value::U64(0), + CoreTypeConcrete::Uint16(_) => Value::U16(0), + CoreTypeConcrete::Uint128(_) => Value::U128(0), + CoreTypeConcrete::Felt252(_) => Value::Felt(0.into()), + x => panic!("type {:?} has no default value implementation", x.info()), } } diff --git a/src/vm.rs b/src/vm.rs index 9814d38..ac1327d 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,5 +1,6 @@ use crate::{ debug::libfunc_to_name, + gas::{GasMetadata, MetadataComputationConfig}, starknet::{StarknetSyscallHandler, StubSyscallHandler}, Value, }; @@ -55,16 +56,18 @@ mod uint64; mod uint8; pub struct VirtualMachine { - program: Arc, - registry: ProgramRegistry, + pub program: Arc, + pub registry: ProgramRegistry, pub syscall_handler: S, frames: Vec, + pub gas: GasMetadata, } impl VirtualMachine { pub fn new(program: Arc) -> Self { let registry = ProgramRegistry::new(&program).unwrap(); Self { + gas: GasMetadata::new(&program, Some(MetadataComputationConfig::default())).unwrap(), program, registry, syscall_handler: StubSyscallHandler::default(), @@ -77,6 +80,7 @@ impl VirtualMachine { pub fn new_starknet(program: Arc, syscall_handler: S) -> Self { let registry = ProgramRegistry::new(&program).unwrap(); Self { + gas: GasMetadata::new(&program, Some(MetadataComputationConfig::default())).unwrap(), program, registry, syscall_handler, @@ -201,6 +205,8 @@ impl VirtualMachine { &invocation.libfunc_id, values, &mut self.syscall_handler, + &self.gas, + &frame.pc, ) { EvalAction::NormalBranch(branch_idx, results) => { assert_eq!( @@ -285,6 +291,8 @@ fn eval<'a>( id: &'a ConcreteLibfuncId, args: Vec, syscall_handler: &mut impl StarknetSyscallHandler, + gas: &GasMetadata, + statement_idx: &StatementIdx, ) -> EvalAction { match registry.get_libfunc(id).unwrap() { CoreConcreteLibfunc::ApTracking(selector) => { @@ -316,7 +324,9 @@ fn eval<'a>( self::felt252_dict_entry::eval(registry, selector, args) } CoreConcreteLibfunc::FunctionCall(info) => self::function_call::eval(registry, info, args), - CoreConcreteLibfunc::Gas(selector) => self::gas::eval(registry, selector, args), + CoreConcreteLibfunc::Gas(selector) => { + self::gas::eval(registry, selector, args, gas, *statement_idx) + } CoreConcreteLibfunc::Mem(selector) => self::mem::eval(registry, selector, args), CoreConcreteLibfunc::Nullable(_) => todo!(), CoreConcreteLibfunc::Pedersen(selector) => self::pedersen::eval(registry, selector, args), diff --git a/src/vm/gas.rs b/src/vm/gas.rs index 96fa1f5..2bfda50 100644 --- a/src/vm/gas.rs +++ b/src/vm/gas.rs @@ -1,11 +1,12 @@ use super::EvalAction; -use crate::Value; +use crate::{gas::GasMetadata, Value}; use cairo_lang_sierra::{ extensions::{ core::{CoreLibfunc, CoreType}, gas::GasConcreteLibfunc, lib_func::SignatureOnlyConcreteLibfunc, }, + program::StatementIdx, program_registry::ProgramRegistry, }; use smallvec::smallvec; @@ -14,13 +15,17 @@ pub fn eval( registry: &ProgramRegistry, selector: &GasConcreteLibfunc, args: Vec, + gas: &GasMetadata, + statement_idx: StatementIdx, ) -> EvalAction { match selector { - GasConcreteLibfunc::WithdrawGas(info) => eval_withdraw_gas(registry, info, args), + GasConcreteLibfunc::WithdrawGas(info) => { + eval_withdraw_gas(registry, info, args, gas, statement_idx) + } GasConcreteLibfunc::RedepositGas(_) => todo!(), GasConcreteLibfunc::GetAvailableGas(_) => todo!(), GasConcreteLibfunc::BuiltinWithdrawGas(info) => { - eval_builtin_withdraw_gas(registry, info, args) + eval_builtin_withdraw_gas(registry, info, args, gas, statement_idx) } GasConcreteLibfunc::GetBuiltinCosts(info) => eval_get_builtin_costs(registry, info, args), } @@ -30,6 +35,8 @@ pub fn eval_builtin_withdraw_gas( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, args: Vec, + gas_meta: &GasMetadata, + statement_idx: StatementIdx, ) -> EvalAction { let [range_check @ Value::Unit, Value::U128(gas), _builtin_costs @ Value::Unit]: [Value; 3] = args.try_into().unwrap() @@ -37,21 +44,43 @@ pub fn eval_builtin_withdraw_gas( panic!() }; - // TODO: Implement properly. - EvalAction::NormalBranch(0, smallvec![range_check, Value::U128(gas)]) + let gas_cost = gas_meta.get_gas_cost_for_statement(statement_idx); + + if let Some(gas_cost) = gas_cost { + let new_gas = gas.saturating_sub(gas_cost); + if gas >= gas_cost { + EvalAction::NormalBranch(0, smallvec![range_check, Value::U128(new_gas)]) + } else { + EvalAction::NormalBranch(1, smallvec![range_check, Value::U128(new_gas)]) + } + } else { + EvalAction::NormalBranch(1, smallvec![range_check, Value::U128(gas)]) + } } pub fn eval_withdraw_gas( _registry: &ProgramRegistry, _info: &SignatureOnlyConcreteLibfunc, args: Vec, + gas_meta: &GasMetadata, + statement_idx: StatementIdx, ) -> EvalAction { let [range_check @ Value::Unit, Value::U128(gas)]: [Value; 2] = args.try_into().unwrap() else { panic!() }; - // TODO: Implement properly. - EvalAction::NormalBranch(0, smallvec![range_check, Value::U128(gas)]) + let gas_cost = gas_meta.get_gas_cost_for_statement(statement_idx); + + if let Some(gas_cost) = gas_cost { + let new_gas = gas.saturating_sub(gas_cost); + if gas >= gas_cost { + EvalAction::NormalBranch(0, smallvec![range_check, Value::U128(new_gas)]) + } else { + EvalAction::NormalBranch(1, smallvec![range_check, Value::U128(new_gas)]) + } + } else { + EvalAction::NormalBranch(1, smallvec![range_check, Value::U128(gas)]) + } } pub fn eval_get_builtin_costs( From 74a4cd100c721d0955629370880c6dba9a3c319a Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 29 Aug 2024 15:47:03 +0200 Subject: [PATCH 10/15] fix bitwise --- Cargo.toml | 12 ++++++------ src/vm/uint128.rs | 2 +- src/vm/uint16.rs | 2 +- src/vm/uint32.rs | 2 +- src/vm/uint64.rs | 2 +- src/vm/uint8.rs | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 07a4555..4b7482f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,10 +4,10 @@ version = "0.1.0" edition = "2021" [dependencies] -cairo-lang-sierra = "^2.7.1" -cairo-lang-sierra-ap-change = "^2.7.1" -cairo-lang-sierra-gas = "^2.7.1" -cairo-lang-utils = "^2.7.1" +cairo-lang-sierra = "~2.7.1" +cairo-lang-sierra-ap-change = "~2.7.1" +cairo-lang-sierra-gas = "~2.7.1" +cairo-lang-utils = "~2.7.1" clap = { version = "4.5.16", features = ["derive"] } k256 = "0.13.3" keccak = "0.1.5" @@ -28,8 +28,8 @@ tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } [dev-dependencies] -cairo-lang-compiler = "^2.7.1" -cairo-lang-starknet = "^2.7.1" +cairo-lang-compiler = "~2.7.1" +cairo-lang-starknet = "~2.7.1" # On dev optimize dependencies a bit so it's not as slow. [profile.dev.package."*"] diff --git a/src/vm/uint128.rs b/src/vm/uint128.rs index 72975b9..d36e932 100644 --- a/src/vm/uint128.rs +++ b/src/vm/uint128.rs @@ -151,7 +151,7 @@ pub fn eval_bitwise( EvalAction::NormalBranch( 0, - smallvec![bitwise, Value::U128(and), Value::U128(or), Value::U128(xor)], + smallvec![bitwise, Value::U128(and), Value::U128(xor), Value::U128(or)], ) } diff --git a/src/vm/uint16.rs b/src/vm/uint16.rs index b394c96..29d9269 100644 --- a/src/vm/uint16.rs +++ b/src/vm/uint16.rs @@ -121,7 +121,7 @@ pub fn eval_bitwise( EvalAction::NormalBranch( 0, - smallvec![bitwise, Value::U16(and), Value::U16(or), Value::U16(xor)], + smallvec![bitwise, Value::U16(and), Value::U16(xor), Value::U16(or)], ) } diff --git a/src/vm/uint32.rs b/src/vm/uint32.rs index b1daf1d..6c9e2c3 100644 --- a/src/vm/uint32.rs +++ b/src/vm/uint32.rs @@ -121,7 +121,7 @@ pub fn eval_bitwise( EvalAction::NormalBranch( 0, - smallvec![bitwise, Value::U32(and), Value::U32(or), Value::U32(xor)], + smallvec![bitwise, Value::U32(and), Value::U32(xor), Value::U32(or)], ) } diff --git a/src/vm/uint64.rs b/src/vm/uint64.rs index 224dcba..8162269 100644 --- a/src/vm/uint64.rs +++ b/src/vm/uint64.rs @@ -121,7 +121,7 @@ pub fn eval_bitwise( EvalAction::NormalBranch( 0, - smallvec![bitwise, Value::U64(and), Value::U64(or), Value::U64(xor)], + smallvec![bitwise, Value::U64(and), Value::U64(xor), Value::U64(or)], ) } diff --git a/src/vm/uint8.rs b/src/vm/uint8.rs index 24d18ee..b4c06fb 100644 --- a/src/vm/uint8.rs +++ b/src/vm/uint8.rs @@ -133,7 +133,7 @@ pub fn eval_bitwise( EvalAction::NormalBranch( 0, - smallvec![bitwise, Value::U8(and), Value::U8(or), Value::U8(xor)], + smallvec![bitwise, Value::U8(and), Value::U8(xor), Value::U8(or)], ) } From 1ecf37981f66dc4e1cfef593a1feea7a7c8aa89c Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 2 Sep 2024 13:27:43 +0100 Subject: [PATCH 11/15] 2.8.0 --- Cargo.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4b7482f..2b4d952 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,10 +4,10 @@ version = "0.1.0" edition = "2021" [dependencies] -cairo-lang-sierra = "~2.7.1" -cairo-lang-sierra-ap-change = "~2.7.1" -cairo-lang-sierra-gas = "~2.7.1" -cairo-lang-utils = "~2.7.1" +cairo-lang-sierra = "2.8.0" +cairo-lang-sierra-ap-change = "2.8.0" +cairo-lang-sierra-gas = "2.8.0" +cairo-lang-utils = "2.8.0" clap = { version = "4.5.16", features = ["derive"] } k256 = "0.13.3" keccak = "0.1.5" @@ -28,8 +28,8 @@ tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } [dev-dependencies] -cairo-lang-compiler = "~2.7.1" -cairo-lang-starknet = "~2.7.1" +cairo-lang-compiler = "2.8.0" +cairo-lang-starknet = "2.8.0" # On dev optimize dependencies a bit so it's not as slow. [profile.dev.package."*"] From 40655269eb4f3d309994ab82ab45690c7573c43a Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Tue, 3 Sep 2024 11:35:28 +0100 Subject: [PATCH 12/15] upd makefile --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 50c3209..82e3043 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,8 @@ UNAME := $(shell uname) -CAIRO_2_VERSION=2.7.1 -SCARB_VERSION = 2.7.1 +CAIRO_2_VERSION=2.8.0 +SCARB_VERSION = 2.8.0 needs-cairo2: ifeq ($(wildcard ./cairo2/.),) From a388abc024efd1a9a0a29b9a581a41a63144400a Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Tue, 3 Sep 2024 11:48:58 +0100 Subject: [PATCH 13/15] impl pop back --- src/vm/array.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/vm/array.rs b/src/vm/array.rs index 10d0472..fbee0f2 100644 --- a/src/vm/array.rs +++ b/src/vm/array.rs @@ -28,7 +28,7 @@ pub fn eval( ArrayConcreteLibfunc::SnapshotPopFront(info) => { eval_snapshot_pop_front(registry, info, args) } - ArrayConcreteLibfunc::SnapshotPopBack(_) => todo!(), + ArrayConcreteLibfunc::SnapshotPopBack(info) => eval_snapshot_pop_back(registry, info, args), ArrayConcreteLibfunc::SnapshotMultiPopFront(_) => todo!(), ArrayConcreteLibfunc::SnapshotMultiPopBack(_) => todo!(), } @@ -166,3 +166,22 @@ pub fn eval_snapshot_pop_front( EvalAction::NormalBranch(1, smallvec![Value::Array { data, ty }]) } } + +pub fn eval_snapshot_pop_back( + registry: &ProgramRegistry, + info: &SignatureAndTypeConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::Array { mut data, ty }]: [Value; 1] = args.try_into().unwrap() else { + panic!() + }; + + if !data.is_empty() { + let new_data = data.split_off(data.len() - 1); + let value = new_data[0].clone(); + assert!(value.is(registry, &info.ty)); + EvalAction::NormalBranch(0, smallvec![Value::Array { data, ty }, value]) + } else { + EvalAction::NormalBranch(1, smallvec![Value::Array { data, ty }]) + } +} From e4ddb7235bac30f6b92b6268c92953de6e0ba1b6 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Tue, 3 Sep 2024 11:51:01 +0100 Subject: [PATCH 14/15] box libfuncs --- src/vm/box.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/vm/box.rs b/src/vm/box.rs index ac80dd2..4504365 100644 --- a/src/vm/box.rs +++ b/src/vm/box.rs @@ -16,9 +16,9 @@ pub fn eval( args: Vec, ) -> EvalAction { match selector { - BoxConcreteLibfunc::Into(_) => todo!(), + BoxConcreteLibfunc::Into(info) => eval_into_box(registry, info, args), BoxConcreteLibfunc::Unbox(info) => eval_unbox(registry, info, args), - BoxConcreteLibfunc::ForwardSnapshot(_) => todo!(), + BoxConcreteLibfunc::ForwardSnapshot(info) => eval_forward_snapshot(registry, info, args), } } @@ -31,3 +31,23 @@ pub fn eval_unbox( EvalAction::NormalBranch(0, smallvec![value]) } + +pub fn eval_into_box( + _registry: &ProgramRegistry, + _info: &SignatureAndTypeConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [value] = args.try_into().unwrap(); + + EvalAction::NormalBranch(0, smallvec![value]) +} + +pub fn eval_forward_snapshot( + _registry: &ProgramRegistry, + _info: &SignatureAndTypeConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [value] = args.try_into().unwrap(); + + EvalAction::NormalBranch(0, smallvec![value]) +} From 14a2c1876fde482044976258368289ef2f948353 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Tue, 3 Sep 2024 11:55:50 +0100 Subject: [PATCH 15/15] bounded --- src/vm/bounded_int.rs | 82 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/src/vm/bounded_int.rs b/src/vm/bounded_int.rs index ed06273..0fdc939 100644 --- a/src/vm/bounded_int.rs +++ b/src/vm/bounded_int.rs @@ -20,16 +20,82 @@ pub fn eval( args: Vec, ) -> EvalAction { match selector { - BoundedIntConcreteLibfunc::Add(_) => todo!(), - BoundedIntConcreteLibfunc::Sub(_) => todo!(), + BoundedIntConcreteLibfunc::Add(info) => eval_add(registry, info, args), + BoundedIntConcreteLibfunc::Sub(info) => eval_sub(registry, info, args), BoundedIntConcreteLibfunc::Mul(info) => eval_mul(registry, info, args), BoundedIntConcreteLibfunc::DivRem(info) => eval_div_rem(registry, info, args), BoundedIntConcreteLibfunc::Constrain(info) => eval_constrain(registry, info, args), BoundedIntConcreteLibfunc::IsZero(info) => eval_is_zero(registry, info, args), - BoundedIntConcreteLibfunc::WrapNonZero(_) => todo!(), + BoundedIntConcreteLibfunc::WrapNonZero(info) => eval_wrap_non_zero(registry, info, args), } } +pub fn eval_add( + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::BoundedInt { value: lhs, .. }, Value::BoundedInt { value: rhs, .. }]: [Value; 2] = + args.try_into().unwrap() + else { + panic!() + }; + + let range = match registry + .get_type(&info.signature.branch_signatures[0].vars[0].ty) + .unwrap() + { + CoreTypeConcrete::BoundedInt(info) => info.range.lower.clone()..info.range.upper.clone(), + CoreTypeConcrete::NonZero(info) => match registry.get_type(&info.ty).unwrap() { + CoreTypeConcrete::BoundedInt(info) => { + info.range.lower.clone()..info.range.upper.clone() + } + _ => unreachable!(), + }, + _ => unreachable!(), + }; + EvalAction::NormalBranch( + 0, + smallvec![Value::BoundedInt { + range, + value: lhs + rhs, + }], + ) +} + +pub fn eval_sub( + registry: &ProgramRegistry, + info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [Value::BoundedInt { value: lhs, .. }, Value::BoundedInt { value: rhs, .. }]: [Value; 2] = + args.try_into().unwrap() + else { + panic!() + }; + + let range = match registry + .get_type(&info.signature.branch_signatures[0].vars[0].ty) + .unwrap() + { + CoreTypeConcrete::BoundedInt(info) => info.range.lower.clone()..info.range.upper.clone(), + CoreTypeConcrete::NonZero(info) => match registry.get_type(&info.ty).unwrap() { + CoreTypeConcrete::BoundedInt(info) => { + info.range.lower.clone()..info.range.upper.clone() + } + _ => unreachable!(), + }, + _ => unreachable!(), + }; + EvalAction::NormalBranch( + 0, + smallvec![Value::BoundedInt { + range, + value: lhs - rhs, + }], + ) +} + pub fn eval_mul( registry: &ProgramRegistry, info: &SignatureOnlyConcreteLibfunc, @@ -195,3 +261,13 @@ pub fn eval_is_zero( EvalAction::NormalBranch(1, smallvec![value]) } } + +pub fn eval_wrap_non_zero( + _registry: &ProgramRegistry, + _info: &SignatureOnlyConcreteLibfunc, + args: Vec, +) -> EvalAction { + let [value] = args.try_into().unwrap(); + + EvalAction::NormalBranch(0, smallvec![value]) +}