diff --git a/cairo_programs/memcpy_test.cairo b/cairo_programs/memcpy_test.cairo new file mode 100644 index 00000000..cca8d6e4 --- /dev/null +++ b/cairo_programs/memcpy_test.cairo @@ -0,0 +1,21 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.registers import get_fp_and_pc + +func main() { + alloc_locals; + + let (__fp__, _) = get_fp_and_pc(); + + local numbers: (felt, felt, felt) = (1, 2, 3); + + let dest: felt* = alloc(); + + memcpy(dst=dest, src=&numbers, len=3); + + assert numbers[0] = dest[0]; + assert numbers[1] = dest[1]; + assert numbers[2] = dest[2]; + + return (); +} diff --git a/cairo_programs/memset.cairo b/cairo_programs/memset.cairo new file mode 100644 index 00000000..6f0b3341 --- /dev/null +++ b/cairo_programs/memset.cairo @@ -0,0 +1,30 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.memset import memset +from starkware.cairo.common.bool import TRUE, FALSE + +func check_array(array: felt*, value: felt, array_length: felt, iterator: felt) -> (r: felt) { + if (iterator == array_length) { + return (TRUE,); + } + if (array[iterator] != value) { + return (FALSE,); + } + return check_array(array, value, array_length, iterator + 1); +} + +func main() { + alloc_locals; + let (local strings: felt*) = alloc(); + memset(strings, 'Lambda', 20); + let check_string: felt = check_array(strings, 'Lambda', 20, 0); + assert check_string = TRUE; + assert strings[20] = 'can insert new value'; + + let numbers: felt* = alloc(); + memset(numbers, 10, 100); + let check_string: felt = check_array(numbers, 10, 100, 0); + assert check_string = TRUE; + assert numbers[100] = 11; + + return (); +} diff --git a/pkg/hints/hint_codes/memcpy_hint_codes.go b/pkg/hints/hint_codes/memcpy_hint_codes.go index 16966595..d6b671c4 100644 --- a/pkg/hints/hint_codes/memcpy_hint_codes.go +++ b/pkg/hints/hint_codes/memcpy_hint_codes.go @@ -4,3 +4,4 @@ const ADD_SEGMENT = "memory[ap] = segments.add()" const VM_EXIT_SCOPE = "vm_exit_scope()" const VM_ENTER_SCOPE = "vm_enter_scope()" const MEMCPY_ENTER_SCOPE = "vm_enter_scope({'n': ids.len})" +const MEMCPY_CONTINUE_COPYING = "n -= 1\nids.continue_copying = 1 if n > 0 else 0" diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index b877bd1f..12b581c9 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -98,6 +98,12 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return sqrt(data.Ids, vm) case MEMCPY_ENTER_SCOPE: return memcpy_enter_scope(data.Ids, vm, execScopes) + case MEMSET_ENTER_SCOPE: + return memset_enter_scope(data.Ids, vm, execScopes) + case MEMCPY_CONTINUE_COPYING: + return memset_step_loop(data.Ids, vm, execScopes, "continue_copying") + case MEMSET_CONTINUE_LOOP: + return memset_step_loop(data.Ids, vm, execScopes, "continue_loop") case VM_ENTER_SCOPE: return vm_enter_scope(execScopes) case ASSERT_LE_FELT: diff --git a/pkg/hints/hint_utils/ids_manager.go b/pkg/hints/hint_utils/ids_manager.go index f883ac5c..48affa6a 100644 --- a/pkg/hints/hint_utils/ids_manager.go +++ b/pkg/hints/hint_utils/ids_manager.go @@ -25,6 +25,10 @@ func ErrUnknownIdentifier(name string) error { return ErrIdsManager(errors.Errorf("Unknow identifier %s", name)) } +func ErrIdentifierNotFelt(name string) error { + return ErrIdsManager(errors.Errorf("Identifier %s is not a Felt", name)) +} + func NewIdsManager(references map[string]HintReference, hintApTracking parser.ApTrackingData, accessibleScopes []string) IdsManager { return IdsManager{ References: references, @@ -67,7 +71,7 @@ func (ids *IdsManager) GetFelt(name string, vm *VirtualMachine) (lambdaworks.Fel } felt, is_felt := val.GetFelt() if !is_felt { - return lambdaworks.Felt{}, errors.Errorf("Identifier %s is not a Felt", name) + return lambdaworks.Felt{}, ErrIdentifierNotFelt(name) } return felt, nil } diff --git a/pkg/hints/memcpy_hints.go b/pkg/hints/memcpy_hints.go index 1c65f102..8b7cb7b1 100644 --- a/pkg/hints/memcpy_hints.go +++ b/pkg/hints/memcpy_hints.go @@ -2,7 +2,8 @@ package hints import ( . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" - "github.com/lambdaclass/cairo-vm.go/pkg/types" + . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + . "github.com/lambdaclass/cairo-vm.go/pkg/types" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" ) @@ -15,13 +16,13 @@ func add_segment(vm *VirtualMachine) error { // Implements hint: // %{ vm_exit_scope() %} -func vm_exit_scope(executionScopes *types.ExecutionScopes) error { +func vm_exit_scope(executionScopes *ExecutionScopes) error { return executionScopes.ExitScope() } // Implements hint: // %{ vm_enter_scope({'n': ids.len}) %} -func memcpy_enter_scope(ids IdsManager, vm *VirtualMachine, execScopes *types.ExecutionScopes) error { +func memcpy_enter_scope(ids IdsManager, vm *VirtualMachine, execScopes *ExecutionScopes) error { len, err := ids.GetFelt("len", vm) if err != nil { return err @@ -31,8 +32,42 @@ func memcpy_enter_scope(ids IdsManager, vm *VirtualMachine, execScopes *types.Ex return nil } +/* + Implements hint: + + %{ + n -= 1 + ids.`i_name` = 1 if n > 0 else 0 + +%} +*/ +func memset_step_loop(ids IdsManager, vm *VirtualMachine, execScoes *ExecutionScopes, i_name string) error { + // get `n` variable from vm scope + n, err := execScoes.Get("n") + if err != nil { + return err + } + // this variable will hold the value of `n - 1` + newN, ok := n.(Felt) + if !ok { + return ConversionError(n, "felt") + } + newN = newN.Sub(FeltOne()) + execScoes.AssignOrUpdateVariable("n", newN) + + // if `newN` is positive, insert 1 in the address of `continue_loop` + // else, insert 0 + var flag *MaybeRelocatable + if newN.IsPositive() { + flag = NewMaybeRelocatableFelt(FeltOne()) + } else { + flag = NewMaybeRelocatableFelt(FeltZero()) + } + return ids.Insert(i_name, flag, vm) +} + // Implements hint: vm_enter_scope() -func vm_enter_scope(executionScopes *types.ExecutionScopes) error { +func vm_enter_scope(executionScopes *ExecutionScopes) error { executionScopes.EnterScope(make(map[string]interface{})) return nil } diff --git a/pkg/hints/memcpy_hints_test.go b/pkg/hints/memcpy_hints_test.go index 1e5beae1..457fb574 100644 --- a/pkg/hints/memcpy_hints_test.go +++ b/pkg/hints/memcpy_hints_test.go @@ -6,14 +6,14 @@ import ( . "github.com/lambdaclass/cairo-vm.go/pkg/hints" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" - "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/types" + . "github.com/lambdaclass/cairo-vm.go/pkg/utils" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" ) -func AddSegmentHintOk(t *testing.T) { +func TestAddSegmentHintOk(t *testing.T) { vm := NewVirtualMachine() initial_segments := vm.Segments.Memory.NumSegments() hintProcessor := CairoVmHintProcessor{} @@ -51,7 +51,7 @@ func TestExitScopeHintValid(t *testing.T) { err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) if err != nil { - t.Errorf("TestExitScopeHintValid failed with error %s", err) + t.Errorf("failed with error %s", err) } } @@ -77,7 +77,7 @@ func TestExitScopeHintInvalid(t *testing.T) { err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) if err.Error() != ErrCannotExitMainScop.Error() { - t.Errorf("TestExitScopeHintInvalid should fail with error %s", ErrCannotExitMainScop) + t.Errorf("should fail with error %s", ErrCannotExitMainScop) } } @@ -101,14 +101,14 @@ func TestMemcpyEnterScopeHintValid(t *testing.T) { executionScopes := NewExecutionScopes() err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) if err != nil { - t.Errorf("TestMemcpyEnterScopeHintValid failed with error %s", err) + t.Errorf("failed with error %s", err) } res, err := executionScopes.Get("n") if err != nil { - t.Errorf("TestMemcpyEnterScopeHintValid failed with error %s", err) + t.Errorf("failed with error %s", err) } - if res.(lambdaworks.Felt) != lambdaworks.FeltFromDecString("45") { - t.Errorf("TestMemcpyEnterScopeHintValid failed, expected len: %d, got: %d", lambdaworks.FeltFromDecString("45"), res.(lambdaworks.Felt)) + if res.(Felt) != FeltFromDecString("45") { + t.Errorf("failed, expected len: %d, got: %d", FeltFromDecString("45"), res.(Felt)) } } @@ -130,7 +130,7 @@ func TestMemcpyEnterScopeHintInvalid(t *testing.T) { executionScopes := NewExecutionScopes() err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) if err.Error() != ErrUnknownIdentifier("len").Error() { - t.Errorf("TestMemcpyEnterScopeHintInvalid should fail with error %s", ErrUnknownIdentifier("len")) + t.Errorf("should fail with error %s", ErrUnknownIdentifier("len")) } } @@ -153,6 +153,124 @@ func TestEnterScope(t *testing.T) { err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) if err != nil { - t.Errorf("TestEnterScopeHint failed with error %s", err) + t.Errorf("failed with error %s", err) + } +} + +func TestMemcpyContinueCopyingValid1(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments = AddNSegments(vm.Segments, 2) + vm.RunContext.Fp = NewRelocatable(1, 2) + executionScopes := NewExecutionScopesWithInitValue("n", FeltOne()) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "continue_copying": nil, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: MEMCPY_CONTINUE_COPYING, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) + if err != nil { + t.Errorf("failed with error %s", err) + } + + val, err := idsManager.GetFelt("continue_copying", vm) + if err != nil { + t.Errorf("failed with error %s", err) + } + if val != FeltZero() { + t.Errorf("failed, expected val: %d, got: %d", FeltZero(), val) + } +} + +func TestMemcpyContinueCopyingValidNeg1(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments = AddNSegments(vm.Segments, 2) + vm.RunContext.Fp = NewRelocatable(1, 2) + executionScopes := NewExecutionScopesWithInitValue("n", FeltFromDecString("-1")) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "continue_copying": nil, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: MEMCPY_CONTINUE_COPYING, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) + if err != nil { + t.Errorf("failed with error %s", err) + } + + val, err := idsManager.GetFelt("continue_copying", vm) + if err != nil { + t.Errorf("failed with error %s", err) + } + if val != FeltOne() { + t.Errorf("failed, expected val: %d, got: %d", FeltOne(), val) + } +} + +func TestMemcpyContinueCopyingVarNotInScope(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + vm.RunContext.Fp = NewRelocatable(3, 0) + vm.Segments.Memory.Insert(NewRelocatable(0, 2), NewMaybeRelocatableFelt(FeltFromUint64(5))) + + executionScopes := NewExecutionScopes() + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "continue_copying": nil, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: MEMCPY_CONTINUE_COPYING, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) + if err.Error() != ErrVariableNotInScope("n").Error() { + t.Errorf("should fail with error %s", ErrVariableNotInScope("n")) + } +} + +func TestMemcpyContinueCopyingInsertError(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments = AddNSegments(vm.Segments, 2) + executionScopes := NewExecutionScopes() + + scope := make(map[string]interface{}) + scope["n"] = FeltOne() + executionScopes.EnterScope(scope) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "continue_copying": {NewMaybeRelocatableFelt(FeltFromUint64(5))}, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: MEMCPY_CONTINUE_COPYING, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) + expected := ErrMemoryWriteOnce(NewRelocatable(0, 0), *NewMaybeRelocatableFeltFromUint64(5), *NewMaybeRelocatableFeltFromUint64(0)) + if err.Error() != expected.Error() { + t.Errorf("should fail with error %s", expected) } } diff --git a/pkg/hints/memset_hint_codes.go b/pkg/hints/memset_hint_codes.go new file mode 100644 index 00000000..2425ad41 --- /dev/null +++ b/pkg/hints/memset_hint_codes.go @@ -0,0 +1,4 @@ +package hints + +const MEMSET_ENTER_SCOPE = "vm_enter_scope({'n': ids.n})" +const MEMSET_CONTINUE_LOOP = "n -= 1\nids.continue_loop = 1 if n > 0 else 0" diff --git a/pkg/hints/memset_hints.go b/pkg/hints/memset_hints.go new file mode 100644 index 00000000..19a2c39a --- /dev/null +++ b/pkg/hints/memset_hints.go @@ -0,0 +1,18 @@ +package hints + +import ( + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + . "github.com/lambdaclass/cairo-vm.go/pkg/types" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" +) + +// Implements hint: +// %{ vm_enter_scope({'n': ids.n}) %} +func memset_enter_scope(ids IdsManager, vm *VirtualMachine, execScopes *ExecutionScopes) error { + n, err := ids.GetFelt("n", vm) + if err != nil { + return err + } + execScopes.EnterScope(map[string]interface{}{"n": n}) + return nil +} diff --git a/pkg/hints/memset_hints_test.go b/pkg/hints/memset_hints_test.go new file mode 100644 index 00000000..7e6e585e --- /dev/null +++ b/pkg/hints/memset_hints_test.go @@ -0,0 +1,183 @@ +package hints_test + +import ( + "testing" + + . "github.com/lambdaclass/cairo-vm.go/pkg/hints" + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + + . "github.com/lambdaclass/cairo-vm.go/pkg/types" + + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" + + . "github.com/lambdaclass/cairo-vm.go/pkg/utils" + + . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" +) + +func TestMemsetEnterScopeValid(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments = AddNSegments(vm.Segments, 2) + vm.RunContext.Fp = NewRelocatable(1, 2) + vm.Segments.Memory.Insert(NewRelocatable(1, 1), NewMaybeRelocatableFeltFromUint64(5)) + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "n": {NewMaybeRelocatableFeltFromUint64(4)}, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: MEMSET_ENTER_SCOPE, + }) + + executionScopes := NewExecutionScopes() + err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) + if err != nil { + t.Errorf("failed with error %s", err) + } + val, err := executionScopes.Get("n") + if err != nil { + t.Errorf("failed with error %s", err) + } + + if val.(Felt) != FeltFromUint64(4) { + t.Errorf("failed, expected value: %s, got: %s", FeltFromUint64(4).ToSignedFeltString(), val.(Felt).ToSignedFeltString()) + + } +} + +func TestMemsetEnterScopeInvalid(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments = AddNSegments(vm.Segments, 2) + vm.RunContext.Fp = NewRelocatable(1, 1) + // insert a relocatable value in the address of ids.len so that it raises an error. + vm.Segments.Memory.Insert(NewRelocatable(1, 1), NewMaybeRelocatableRelocatableParams(1, 0)) + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "n": {NewMaybeRelocatableRelocatableParams(3, 4)}, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: MEMSET_ENTER_SCOPE, + }) + + executionScopes := NewExecutionScopes() + err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) + if err.Error() != ErrIdentifierNotFelt("n").Error() { + t.Errorf("should fail with: %s", ErrIdentifierNotFelt("n").Error()) + } + +} + +func TestMemsetContinueLoopValidEqual1Hint(t *testing.T) { + vm := NewVirtualMachine() + vm.RunContext.Fp = NewRelocatable(1, 0) + vm.Segments = AddNSegments(vm.Segments, 2) + executionScopes := NewExecutionScopesWithInitValue("n", FeltFromUint64(1)) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "continue_loop": {NewMaybeRelocatableFeltFromUint64(0)}, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: MEMSET_CONTINUE_LOOP, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) + if err != nil { + t.Errorf("failed with error %s", err) + } + val, err := vm.Segments.Memory.GetFelt(NewRelocatable(1, 0)) + if err != nil { + t.Errorf("failed with error %s", err) + } + if val != FeltZero() { + t.Errorf("failed, expected %d, got: %d", FeltZero(), val) + } +} + +func TestMemsetContinueLoopValidEqual5Hint(t *testing.T) { + vm := NewVirtualMachine() + vm.RunContext.Fp = NewRelocatable(1, 0) + vm.Segments = AddNSegments(vm.Segments, 2) + executionScopes := NewExecutionScopesWithInitValue("n", FeltFromUint64(5)) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "continue_loop": {NewMaybeRelocatableFeltFromUint64(1)}, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: MEMSET_CONTINUE_LOOP, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) + if err != nil { + t.Errorf("failed with error %s", err) + } + val, err := vm.Segments.Memory.GetFelt(NewRelocatable(1, 0)) + if err != nil { + t.Errorf("failed with error %s", err) + } + if val != FeltOne() { + t.Errorf("failed, expected %d, got: %d", FeltOne(), val) + } +} + +func TestMemsetContinueLoopVarNotInScope(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + executionScopes := NewExecutionScopes() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "continue_loop": {NewMaybeRelocatableFeltFromUint64(1)}, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: MEMSET_CONTINUE_LOOP, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) + if err.Error() != ErrVariableNotInScope("n").Error() { + t.Errorf("should fail with error %s", ErrVariableNotInScope("n")) + } +} + +func TestMemsetContinueLoopInsertError(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments = AddNSegments(vm.Segments, 2) + executionScopes := NewExecutionScopesWithInitValue("n", FeltOne()) + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "continue_loop": {NewMaybeRelocatableFelt(FeltFromUint64(5))}, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: MEMSET_CONTINUE_LOOP, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, executionScopes) + expected := ErrMemoryWriteOnce(NewRelocatable(0, 0), *NewMaybeRelocatableFeltFromUint64(5), *NewMaybeRelocatableFeltFromUint64(0)) + if err.Error() != expected.Error() { + t.Errorf("should fail with error %s", expected) + } +} diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index d66e7b24..77f8ec56 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -9,6 +9,7 @@ import "C" import ( "math/big" + "reflect" "strings" "unsafe" @@ -29,8 +30,8 @@ func LambdaworksError(err error) error { return errors.Wrapf(err, "Lambdaworks Error") } -func ConversionError(felt Felt, targetType string) error { - return LambdaworksError(errors.Errorf("Cannot convert felt: %d to %s", felt, targetType)) +func ConversionError(val interface{}, targetType string) error { + return LambdaworksError(errors.Errorf("Cannot convert %s: %d to %s", reflect.TypeOf(val), val, targetType)) } // Converts a Go Felt to a C felt_t. @@ -155,6 +156,10 @@ func (f Felt) IsZero() bool { return f == FeltZero() } +func (f Felt) IsPositive() bool { + return !f.IsZero() +} + func (f Felt) IsOne() bool { return f == FeltOne() } diff --git a/pkg/types/exec_scope_test.go b/pkg/types/exec_scope_test.go index 1ee54fd9..119f266d 100644 --- a/pkg/types/exec_scope_test.go +++ b/pkg/types/exec_scope_test.go @@ -26,26 +26,6 @@ func TestGetLocalVariables(t *testing.T) { } } -func TestGetRefLocalVariables(t *testing.T) { - scope := make(map[string]interface{}) - scope["k"] = lambdaworks.FeltOne() - - scopes := types.NewExecutionScopes() - scopes.EnterScope(scope) - - result, err := scopes.GetRef("k") - if err != nil { - t.Errorf("TestGetRefLocalVariables failed with error: %s", err) - - } - f_one := lambdaworks.FeltOne() - f_res := (*result).(lambdaworks.Felt) - expected := &f_one - if *expected != f_res { - t.Errorf("TestGetRefLocalVariables failed, expected: %d, got: %d", expected, &f_res) - } -} - func TestEnterNewScope(t *testing.T) { scope := make(map[string]interface{}) scope["a"] = lambdaworks.FeltOne() diff --git a/pkg/types/exec_scope_utils.go b/pkg/types/exec_scope_utils.go new file mode 100644 index 00000000..4a6cab69 --- /dev/null +++ b/pkg/types/exec_scope_utils.go @@ -0,0 +1,7 @@ +package types + +func NewExecutionScopesWithInitValue(key string, val interface{}) *ExecutionScopes { + scopes := NewExecutionScopes() + scopes.EnterScope(map[string]interface{}{key: val}) + return scopes +} diff --git a/pkg/types/exec_scopes.go b/pkg/types/exec_scopes.go index 50f15213..357a1cec 100644 --- a/pkg/types/exec_scopes.go +++ b/pkg/types/exec_scopes.go @@ -82,11 +82,3 @@ func (es *ExecutionScopes) Get(varName string) (interface{}, error) { } return val, nil } - -func (es *ExecutionScopes) GetRef(varName string) (*interface{}, error) { - val, err := es.Get(varName) - if err != nil { - return nil, err - } - return &val, err -} diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 6e7ee63a..52a114e2 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -1,6 +1,9 @@ package utils import ( + . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" + "github.com/pkg/errors" ) @@ -38,3 +41,19 @@ func CheckBuiltinsSubsequence(programBuiltins []string) error { } return nil } + +// Creates a new MaybeRelocatable from a uint64 value +func NewMaybeRelocatableFeltFromUint64(val uint64) *MaybeRelocatable { + return NewMaybeRelocatableFelt(FeltFromUint64(val)) +} + +func NewMaybeRelocatableRelocatableParams(segment_idx int, offset uint) *MaybeRelocatable { + return NewMaybeRelocatableRelocatable(NewRelocatable(segment_idx, offset)) +} + +func AddNSegments(segments MemorySegmentManager, nSegments int) MemorySegmentManager { + for i := 0; i < nSegments; i++ { + segments.AddSegment() + } + return segments +} diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index 12fabd3e..ee124565 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -210,6 +210,13 @@ func TestSqrtHint(t *testing.T) { } } +func TestMemcpyHint(t *testing.T) { + cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, Layout: "all_cairo", ProofMode: false} + _, err := cairo_run.CairoRun("../../../cairo_programs/memcpy_test.json", cairoRunConfig) + if err != nil { + t.Errorf("Program execution failed with error: %s", err) + } +} func TestAssertLeFelt(t *testing.T) { cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, Layout: "all_cairo", ProofMode: false} _, err := cairo_run.CairoRun("../../../cairo_programs/assert_le_felt.json", cairoRunConfig) @@ -217,6 +224,13 @@ func TestAssertLeFelt(t *testing.T) { t.Errorf("Program execution failed with error: %s", err) } } +func TestMemsetHint(t *testing.T) { + cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, Layout: "all_cairo", ProofMode: false} + _, err := cairo_run.CairoRun("../../../cairo_programs/memset.json", cairoRunConfig) + if err != nil { + t.Errorf("Program execution failed with error: %s", err) + } +} func TestMathCmp(t *testing.T) { cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, Layout: "all_cairo", ProofMode: false} @@ -225,7 +239,6 @@ func TestMathCmp(t *testing.T) { t.Errorf("Program execution failed with error: %s", err) } } - func TestSquashDict(t *testing.T) { cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, Layout: "small", ProofMode: false} _, err := cairo_run.CairoRun("../../../cairo_programs/squash_dict.json", cairoRunConfig) @@ -233,7 +246,6 @@ func TestSquashDict(t *testing.T) { t.Errorf("Program execution failed with error: %s", err) } } - func TestAssert250BitHint(t *testing.T) { cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, Layout: "all_cairo", ProofMode: false} _, err := cairo_run.CairoRun("../../../cairo_programs/assert_250_bit_element_array.json", cairoRunConfig) diff --git a/pkg/vm/memory/memory.go b/pkg/vm/memory/memory.go index 4c7f2bac..9985bc44 100644 --- a/pkg/vm/memory/memory.go +++ b/pkg/vm/memory/memory.go @@ -10,6 +10,18 @@ import ( // A Set to store Relocatable values type AddressSet map[Relocatable]bool +func MemoryError(err error) error { + return errors.Wrapf(err, "Memory error") +} + +func ErrMemoryWriteOnce(addr Relocatable, prevVal MaybeRelocatable, newVal MaybeRelocatable) error { + addrStr := addr.ToString() + prevValStr := prevVal.ToString() + newValStr := newVal.ToString() + + return MemoryError(errors.Errorf("Memory is write-once, cannot overwrite memory value in %s. %s != %s", addrStr, prevValStr, newValStr)) +} + func NewAddressSet() AddressSet { return make(map[Relocatable]bool) } @@ -76,13 +88,13 @@ func (m *Memory) Insert(addr Relocatable, val *MaybeRelocatable) error { // Check that insertions are preformed within the memory bounds if addr.SegmentIndex >= int(m.numSegments) { - return errors.New("Error: Inserting into a non allocated segment") + return errors.Errorf("Error: Inserting into a non allocated segment %s", addr.ToString()) } // Check for possible overwrites prev_elem, ok := m.Data[addr] if ok && prev_elem != *val { - return errors.New("Memory is write-once, cannot overwrite memory value") + return ErrMemoryWriteOnce(addr, prev_elem, *val) } m.Data[addr] = *val return m.validateAddress(addr)