From d7f401e018aea72d13c99e74f63912608e068c59 Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Mon, 18 Sep 2023 16:56:18 -0300 Subject: [PATCH 01/13] Add set_add hint --- cairo_programs/set_add.cairo | 43 +++++++++++++++++++ pkg/hints/hint_processor.go | 6 +++ pkg/hints/memcpy_hint_codes.go | 2 + pkg/hints/memcpy_hints.go | 32 ++++++++++++++ pkg/hints/set_hint_codes.go | 3 ++ pkg/hints/set_hints.go | 67 ++++++++++++++++++++++++++++++ pkg/vm/cairo_run/cairo_run_test.go | 8 ++++ pkg/vm/memory/memory.go | 9 ++++ 8 files changed, 170 insertions(+) create mode 100644 cairo_programs/set_add.cairo create mode 100644 pkg/hints/set_hint_codes.go create mode 100644 pkg/hints/set_hints.go diff --git a/cairo_programs/set_add.cairo b/cairo_programs/set_add.cairo new file mode 100644 index 00000000..8a765e25 --- /dev/null +++ b/cairo_programs/set_add.cairo @@ -0,0 +1,43 @@ +%builtins range_check + +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.set import set_add + +struct MyStruct { + a: felt, + b: felt, +} + +func main{range_check_ptr}() { + alloc_locals; + + // An array containing two structs. + let (local my_list: MyStruct*) = alloc(); + assert my_list[0] = MyStruct(a=1, b=3); + assert my_list[1] = MyStruct(a=5, b=7); + + // Suppose that we want to add the element + // MyStruct(a=2, b=3) to my_list, but only if it is not already + // present (for the purpose of the example the contents of the + // array are known, but this doesn't have to be the case) + let list_end: felt* = &my_list[2]; + let (new_elm: MyStruct*) = alloc(); + assert new_elm[0] = MyStruct(a=2, b=3); + + set_add{set_end_ptr=list_end}(set_ptr=my_list, elm_size=MyStruct.SIZE, elm_ptr=new_elm); + assert my_list[2] = MyStruct(a=2, b=3); + + // Now let's try to add MyStruct(a=1, b=3) to my_list, + // Since this element is already present in my_list, + // set_add won't add any element to the my_list + + let list_end: felt* = &my_list[3]; + assert new_elm[1] = MyStruct(a=1, b=3); + + set_add{set_end_ptr=list_end}(set_ptr=my_list, elm_size=MyStruct.SIZE, elm_ptr=new_elm); + + // Since my_list[3] = None, we can insert a MyStruct + assert my_list[3] = MyStruct(a=0, b=0); + + return (); +} diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 47da4dfb..209fccaf 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -63,6 +63,12 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return memcpy_enter_scope(data.Ids, vm, execScopes) case VM_ENTER_SCOPE: return vm_enter_scope(execScopes) + case MEMCPY_CONTINUE_COPYING: + return memcpy_continue_id(data.Ids, vm, execScopes, "continue_copying") + case MEMCPY_CONTINUE_LOOP: + return memcpy_continue_id(data.Ids, vm, execScopes, "continue_loop") + case SET_ADD: + return set_add(data.Ids, vm) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/memcpy_hint_codes.go b/pkg/hints/memcpy_hint_codes.go index e2e52ffe..6d15799a 100644 --- a/pkg/hints/memcpy_hint_codes.go +++ b/pkg/hints/memcpy_hint_codes.go @@ -4,3 +4,5 @@ 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" +const MEMCPY_CONTINUE_LOOP = "n -= 1\nids.continue_loop = 1 if n > 0 else 0" diff --git a/pkg/hints/memcpy_hints.go b/pkg/hints/memcpy_hints.go index 1c65f102..8931358b 100644 --- a/pkg/hints/memcpy_hints.go +++ b/pkg/hints/memcpy_hints.go @@ -2,6 +2,7 @@ package hints import ( . "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/vm/memory" @@ -36,3 +37,34 @@ func vm_enter_scope(executionScopes *types.ExecutionScopes) error { executionScopes.EnterScope(make(map[string]interface{})) return nil } + +/* + Implements hint: + + %{ + n -= 1 + ids.`i_name` = 1 if n > 0 else 0 + +%} +*/ +func memcpy_continue_id(ids IdsManager, vm *VirtualMachine, execScopes *types.ExecutionScopes, id string) error { + n, err := execScopes.Get("n") + if err != nil { + return err + } + n_felt := (n).(Felt).Sub(FeltOne()) + execScopes.AssignOrUpdateVariable("n", n_felt.Sub(FeltOne())) + if n_felt.IsZero() { + err := ids.Insert(id, NewMaybeRelocatableFelt(FeltZero()), vm) + if err != nil { + return err + } + } else { + err := ids.Insert(id, NewMaybeRelocatableFelt(FeltOne()), vm) + if err != nil { + return err + } + } + + return nil +} diff --git a/pkg/hints/set_hint_codes.go b/pkg/hints/set_hint_codes.go new file mode 100644 index 00000000..402e5dc2 --- /dev/null +++ b/pkg/hints/set_hint_codes.go @@ -0,0 +1,3 @@ +package hints + +const SET_ADD = "assert ids.elm_size > 0\nassert ids.set_ptr <= ids.set_end_ptr\nelm_list = memory.get_range(ids.elm_ptr, ids.elm_size)\nfor i in range(0, ids.set_end_ptr - ids.set_ptr, ids.elm_size):\n if memory.get_range(ids.set_ptr + i, ids.elm_size) == elm_list:\n ids.index = i // ids.elm_size\n ids.is_elm_in_set = 1\n break\nelse:\n ids.is_elm_in_set = 0" diff --git a/pkg/hints/set_hints.go b/pkg/hints/set_hints.go new file mode 100644 index 00000000..ed6dcef8 --- /dev/null +++ b/pkg/hints/set_hints.go @@ -0,0 +1,67 @@ +package hints + +import ( + . "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/vm" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" + "github.com/pkg/errors" +) + +/* + Implements hint: + + assert ids.elm_size > 0 + assert ids.set_ptr <= ids.set_end_ptr + elm_list = memory.get_range(ids.elm_ptr, ids.elm_size) + for i in range(0, ids.set_end_ptr - ids.set_ptr, ids.elm_size): + if memory.get_range(ids.set_ptr + i, ids.elm_size) == elm_list: + ids.index = i // ids.elm_size + ids.is_elm_in_set = 1 + break + else: + ids.is_elm_in_set = 0 +*/ +func set_add(ids IdsManager, vm *VirtualMachine) error { + set_ptr, err := ids.GetRelocatable("set_ptr", vm) + if err != nil { + return err + } + elm_size_felt, err := ids.GetFelt("elm_size", vm) + if err != nil { + return err + } + elm_ptr, err := ids.GetRelocatable("elm_ptr", vm) + if err != nil { + return err + } + set_end_ptr, err := ids.GetRelocatable("set_end_ptr", vm) + if err != nil { + return err + } + + if elm_size_felt.IsZero() { + return errors.Errorf("assert ids.elm_size > 0") + } + + elm_size, err := elm_size_felt.ToU64() + + if err != nil { + return err + } + + if set_ptr.Offset > set_end_ptr.Offset { + return errors.Errorf("expected set_ptr: %v <= set_end_ptr: %v", set_ptr, set_end_ptr) + } + + elem := vm.Segments.Memory.GetRange(elm_ptr, uint(elm_size)) + + for i := uint(0); i < set_end_ptr.Offset-set_ptr.Offset; i += uint(elm_size) { + other_elm := vm.Segments.Memory.GetRange(set_ptr.AddUint(i), uint(elm_size)) + if &elem == &other_elm { + return ids.Insert("is_elm_in_set", NewMaybeRelocatableFelt(FeltOne()), vm) + } + } + + return ids.Insert("is_elm_in_set", NewMaybeRelocatableFelt(FeltZero()), vm) +} diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index 2a250ef5..d7b0c0b4 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -170,3 +170,11 @@ func TestAssertNotEqualHint(t *testing.T) { t.Errorf("Program execution failed with error: %s", err) } } + +func TestSetAddHint(t *testing.T) { + cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, Layout: "all_cairo", ProofMode: false} + _, err := cairo_run.CairoRun("../../../cairo_programs/set_add.json", cairoRunConfig) + if err != nil { + t.Errorf("Program execution failed with error: %s", err) + } +} diff --git a/pkg/vm/memory/memory.go b/pkg/vm/memory/memory.go index 4c7f2bac..d42e6d9c 100644 --- a/pkg/vm/memory/memory.go +++ b/pkg/vm/memory/memory.go @@ -138,6 +138,15 @@ func (m *Memory) GetFelt(addr Relocatable) (lambdaworks.Felt, error) { return lambdaworks.FeltZero(), err } +// Get a range of memory from the starting relocatable to the starting relocatable + size +func (m *Memory) GetRange(start Relocatable, size uint) []MaybeRelocatable { + var res []MaybeRelocatable + for i := uint(0); i <= size; i++ { + res = append(res, m.Data[start.AddUint(i)]) + } + return res +} + // Adds a validation rule for a given segment func (m *Memory) AddValidationRule(SegmentIndex uint, rule ValidationRule) { m.validationRules[SegmentIndex] = rule From ae6e40655b6d19c57ceb091ce5b47397e957c56e Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Mon, 18 Sep 2023 17:03:53 -0300 Subject: [PATCH 02/13] Add error to get range --- pkg/hints/set_hints.go | 10 ++++++++-- pkg/vm/memory/memory.go | 9 +++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/pkg/hints/set_hints.go b/pkg/hints/set_hints.go index ed6dcef8..97a7e0df 100644 --- a/pkg/hints/set_hints.go +++ b/pkg/hints/set_hints.go @@ -54,10 +54,16 @@ func set_add(ids IdsManager, vm *VirtualMachine) error { return errors.Errorf("expected set_ptr: %v <= set_end_ptr: %v", set_ptr, set_end_ptr) } - elem := vm.Segments.Memory.GetRange(elm_ptr, uint(elm_size)) + elem, err := vm.Segments.Memory.GetRange(elm_ptr, uint(elm_size)) + if err != nil { + return err + } for i := uint(0); i < set_end_ptr.Offset-set_ptr.Offset; i += uint(elm_size) { - other_elm := vm.Segments.Memory.GetRange(set_ptr.AddUint(i), uint(elm_size)) + other_elm, err := vm.Segments.Memory.GetRange(set_ptr.AddUint(i), uint(elm_size)) + if err != nil { + return err + } if &elem == &other_elm { return ids.Insert("is_elm_in_set", NewMaybeRelocatableFelt(FeltOne()), vm) } diff --git a/pkg/vm/memory/memory.go b/pkg/vm/memory/memory.go index d42e6d9c..35aa56e0 100644 --- a/pkg/vm/memory/memory.go +++ b/pkg/vm/memory/memory.go @@ -139,12 +139,17 @@ func (m *Memory) GetFelt(addr Relocatable) (lambdaworks.Felt, error) { } // Get a range of memory from the starting relocatable to the starting relocatable + size -func (m *Memory) GetRange(start Relocatable, size uint) []MaybeRelocatable { +func (m *Memory) GetRange(start Relocatable, size uint) ([]MaybeRelocatable, error) { + _, is_in_dict := m.Data[start.AddUint(size - 1)] + if !is_in_dict { + return nil, errors.Errorf("Memory GetRange: range end (%v) not present in memory", start.AddUint(size - 1)) + } + var res []MaybeRelocatable for i := uint(0); i <= size; i++ { res = append(res, m.Data[start.AddUint(i)]) } - return res + return res, nil } // Adds a validation rule for a given segment From 06d20d9c63d9843d5e2d4fefbef59a46b5b6fe61 Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Tue, 19 Sep 2023 09:41:20 -0300 Subject: [PATCH 03/13] Revert memcpy changes --- pkg/hints/memcpy_hint_codes.go | 2 -- pkg/hints/memcpy_hints.go | 32 -------------------------------- 2 files changed, 34 deletions(-) diff --git a/pkg/hints/memcpy_hint_codes.go b/pkg/hints/memcpy_hint_codes.go index 6d15799a..e2e52ffe 100644 --- a/pkg/hints/memcpy_hint_codes.go +++ b/pkg/hints/memcpy_hint_codes.go @@ -4,5 +4,3 @@ 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" -const MEMCPY_CONTINUE_LOOP = "n -= 1\nids.continue_loop = 1 if n > 0 else 0" diff --git a/pkg/hints/memcpy_hints.go b/pkg/hints/memcpy_hints.go index 8931358b..1c65f102 100644 --- a/pkg/hints/memcpy_hints.go +++ b/pkg/hints/memcpy_hints.go @@ -2,7 +2,6 @@ package hints import ( . "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/vm/memory" @@ -37,34 +36,3 @@ func vm_enter_scope(executionScopes *types.ExecutionScopes) error { executionScopes.EnterScope(make(map[string]interface{})) return nil } - -/* - Implements hint: - - %{ - n -= 1 - ids.`i_name` = 1 if n > 0 else 0 - -%} -*/ -func memcpy_continue_id(ids IdsManager, vm *VirtualMachine, execScopes *types.ExecutionScopes, id string) error { - n, err := execScopes.Get("n") - if err != nil { - return err - } - n_felt := (n).(Felt).Sub(FeltOne()) - execScopes.AssignOrUpdateVariable("n", n_felt.Sub(FeltOne())) - if n_felt.IsZero() { - err := ids.Insert(id, NewMaybeRelocatableFelt(FeltZero()), vm) - if err != nil { - return err - } - } else { - err := ids.Insert(id, NewMaybeRelocatableFelt(FeltOne()), vm) - if err != nil { - return err - } - } - - return nil -} From 20b8c539b36ad202db23babd64eae427bee9601a Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Tue, 19 Sep 2023 10:21:11 -0300 Subject: [PATCH 04/13] Revert more changes --- pkg/hints/hint_processor.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index c84f6e00..d69dc9ea 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -69,10 +69,6 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return memcpy_enter_scope(data.Ids, vm, execScopes) case VM_ENTER_SCOPE: return vm_enter_scope(execScopes) - case MEMCPY_CONTINUE_COPYING: - return memcpy_continue_id(data.Ids, vm, execScopes, "continue_copying") - case MEMCPY_CONTINUE_LOOP: - return memcpy_continue_id(data.Ids, vm, execScopes, "continue_loop") case SET_ADD: return set_add(data.Ids, vm) default: From 63c3d827f6de046c052f66b354a75eb8d2bd69aa Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Wed, 20 Sep 2023 11:09:02 -0300 Subject: [PATCH 05/13] Add basic find element hint impl --- cairo_programs/find_element.cairo | 27 ++++++++++++++++ pkg/hints/find_element_hint_codes.go | 3 ++ pkg/hints/find_element_hints.go | 34 ++++++++++++++++++++ pkg/hints/hint_processor.go | 2 ++ pkg/hints/set_hints.go | 37 ++++++++++++---------- pkg/lambdaworks/lambdaworks.go | 17 +++++++++- pkg/lambdaworks/lib/lambdaworks.h | 4 +++ pkg/lambdaworks/lib/lambdaworks/src/lib.rs | 5 +++ pkg/vm/cairo_run/cairo_run_test.go | 8 +++++ pkg/vm/memory/memory.go | 8 ++--- 10 files changed, 123 insertions(+), 22 deletions(-) create mode 100644 cairo_programs/find_element.cairo create mode 100644 pkg/hints/find_element_hint_codes.go create mode 100644 pkg/hints/find_element_hints.go diff --git a/cairo_programs/find_element.cairo b/cairo_programs/find_element.cairo new file mode 100644 index 00000000..f609f32a --- /dev/null +++ b/cairo_programs/find_element.cairo @@ -0,0 +1,27 @@ +%builtins range_check +from starkware.cairo.common.find_element import find_element +from starkware.cairo.common.alloc import alloc + +struct MyStruct { + a: felt, + b: felt, +} + +func main{range_check_ptr}() -> () { + // Create an array with MyStruct elements (1,2), (3,4), (5,6). + alloc_locals; + let (local array_ptr: MyStruct*) = alloc(); + assert array_ptr[0] = MyStruct(a=1, b=2); + assert array_ptr[1] = MyStruct(a=3, b=4); + assert array_ptr[2] = MyStruct(a=5, b=6); + + // Find any element with key '5'. + let (element_ptr: MyStruct*) = find_element( + array_ptr=array_ptr, elm_size=MyStruct.SIZE, n_elms=3, key=5 + ); + // A pointer to the element with index 2 is returned. + assert element_ptr.a = 5; + assert element_ptr.b = 6; + + return (); +} diff --git a/pkg/hints/find_element_hint_codes.go b/pkg/hints/find_element_hint_codes.go new file mode 100644 index 00000000..aff73664 --- /dev/null +++ b/pkg/hints/find_element_hint_codes.go @@ -0,0 +1,3 @@ +package hints + +const FIND_ELEMENT = "array_ptr = ids.array_ptr\nelm_size = ids.elm_size\nassert isinstance(elm_size, int) and elm_size > 0, \\n f'Invalid value for elm_size. Got: {elm_size}.'\nkey = ids.key\n\nif '__find_element_index' in globals():\n ids.index = __find_element_index\n found_key = memory[array_ptr + elm_size * __find_element_index]\n assert found_key == key, \\n f'Invalid index found in __find_element_index. index: {__find_element_index}, ' \\n f'expected key {key}, found key: {found_key}.'\n # Delete __find_element_index to make sure it's not used for the next calls.\n del __find_element_index\nelse:\n n_elms = ids.n_elms\n assert isinstance(n_elms, int) and n_elms >= 0, \\n f'Invalid value for n_elms. Got: {n_elms}.'\n if '__find_element_max_size' in globals():\n assert n_elms <= __find_element_max_size, \\n f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \\n f'Got: n_elms={n_elms}.'\n\n for i in range(n_elms):\n if memory[array_ptr + elm_size * i] == key:\n ids.index = i\n break\n else:\n raise ValueError(f'Key {key} was not found.')" diff --git a/pkg/hints/find_element_hints.go b/pkg/hints/find_element_hints.go new file mode 100644 index 00000000..a456ed08 --- /dev/null +++ b/pkg/hints/find_element_hints.go @@ -0,0 +1,34 @@ +package hints + +import ( + . "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/vm" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" + "github.com/pkg/errors" +) + +func find_element(ids IdsManager, vm *VirtualMachine) error { + key, err := ids.GetFelt("key", vm) + if err != nil { + return err + } + n_elms, err := ids.GetFelt("n_elms", vm) + if err != nil { + return err + } + n_elms_iter, err := n_elms.ToUint() + if err != nil { + return err + } + for i := uint(0); i < n_elms_iter; i++ { + iter_key, err := ids.GetStructFieldFelt("array_start", i, vm) + if err != nil { + return err + } + if iter_key == key { + return ids.Insert("index", NewMaybeRelocatableFelt(FeltFromUint(i)), vm) + } + } + return errors.Errorf("Key: %v was not found", key) +} diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 1e74d8a8..a81e4e68 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -76,6 +76,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return vm_enter_scope(execScopes) case SET_ADD: return set_add(data.Ids, vm) + case FIND_ELEMENT: + return find_element(data.Ids, vm) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/set_hints.go b/pkg/hints/set_hints.go index 97a7e0df..123d9cca 100644 --- a/pkg/hints/set_hints.go +++ b/pkg/hints/set_hints.go @@ -9,18 +9,21 @@ import ( ) /* - Implements hint: +Implements hint: - assert ids.elm_size > 0 - assert ids.set_ptr <= ids.set_end_ptr - elm_list = memory.get_range(ids.elm_ptr, ids.elm_size) - for i in range(0, ids.set_end_ptr - ids.set_ptr, ids.elm_size): - if memory.get_range(ids.set_ptr + i, ids.elm_size) == elm_list: - ids.index = i // ids.elm_size - ids.is_elm_in_set = 1 - break - else: - ids.is_elm_in_set = 0 +assert ids.elm_size > 0 +assert ids.set_ptr <= ids.set_end_ptr +elm_list = memory.get_range(ids.elm_ptr, ids.elm_size) +for i in range(0, ids.set_end_ptr - ids.set_ptr, ids.elm_size): + + if memory.get_range(ids.set_ptr + i, ids.elm_size) == elm_list: + ids.index = i // ids.elm_size + ids.is_elm_in_set = 1 + break + +else: + + ids.is_elm_in_set = 0 */ func set_add(ids IdsManager, vm *VirtualMachine) error { set_ptr, err := ids.GetRelocatable("set_ptr", vm) @@ -55,15 +58,15 @@ func set_add(ids IdsManager, vm *VirtualMachine) error { } elem, err := vm.Segments.Memory.GetRange(elm_ptr, uint(elm_size)) - if err != nil { - return err - } + if err != nil { + return err + } for i := uint(0); i < set_end_ptr.Offset-set_ptr.Offset; i += uint(elm_size) { other_elm, err := vm.Segments.Memory.GetRange(set_ptr.AddUint(i), uint(elm_size)) - if err != nil { - return err - } + if err != nil { + return err + } if &elem == &other_elm { return ids.Insert("is_elm_in_set", NewMaybeRelocatableFelt(FeltOne()), vm) } diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index e4ffd4b9..5cbe454f 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -58,6 +58,12 @@ func FeltFromUint64(value uint64) Felt { return fromC(result) } +func FeltFromUint(value uint) Felt { + var result C.felt_t + C.from_uint(&result[0], C.uint_t(value)) + return fromC(result) +} + func FeltFromHex(value string) Felt { cs := C.CString(value) defer C.free(unsafe.Pointer(cs)) @@ -76,7 +82,7 @@ func FeltFromDecString(value string) Felt { return fromC(result) } -// turns a felt to usize +// turns a felt to u64 func (felt Felt) ToU64() (uint64, error) { if felt.limbs[0] == 0 && felt.limbs[1] == 0 && felt.limbs[2] == 0 { return uint64(felt.limbs[3]), nil @@ -85,6 +91,15 @@ func (felt Felt) ToU64() (uint64, error) { } } +// turns a felt to usize +func (felt Felt) ToUint() (uint, error) { + if felt.limbs[0] == 0 && felt.limbs[1] == 0 && felt.limbs[2] == 0 { + return uint(felt.limbs[3]), nil + } else { + return 0, ConversionError(felt, "uint") + } +} + func (felt Felt) ToLeBytes() *[32]byte { var result_c [32]C.uint8_t var value C.felt_t = felt.toC() diff --git a/pkg/lambdaworks/lib/lambdaworks.h b/pkg/lambdaworks/lib/lambdaworks.h index 573a8825..71ff7097 100644 --- a/pkg/lambdaworks/lib/lambdaworks.h +++ b/pkg/lambdaworks/lib/lambdaworks.h @@ -3,6 +3,7 @@ #include typedef uint64_t limb_t; +typedef unsigned int uint_t; /* A 256 bit prime field element (felt), represented as four limbs (integers). */ @@ -11,6 +12,9 @@ typedef limb_t felt_t[4]; /* Gets a felt_t representing the "value" number, in montgomery format. */ void from(felt_t result, uint64_t value); +/* Gets a felt_t representing the "value" number, in montgomery format. */ +void from_uint(felt_t result, uint_t value); + /*Gets a felt_t representing the "value" hexadecimal string, in montgomery * format. */ void from_hex(felt_t result, char *value); diff --git a/pkg/lambdaworks/lib/lambdaworks/src/lib.rs b/pkg/lambdaworks/lib/lambdaworks/src/lib.rs index b772d13d..14e27392 100644 --- a/pkg/lambdaworks/lib/lambdaworks/src/lib.rs +++ b/pkg/lambdaworks/lib/lambdaworks/src/lib.rs @@ -60,6 +60,11 @@ pub extern "C" fn from(result: Limbs, value: u64) { felt_to_limbs(Felt::from(value), result); } +#[no_mangle] +pub extern "C" fn from_uint(result: Limbs, value: usize) { + felt_to_limbs(Felt::from(value as u64), result); +} + #[no_mangle] pub extern "C" fn from_hex(result: Limbs, value: *const libc::c_char) { let val_cstr = unsafe { core::ffi::CStr::from_ptr(value) }; diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index ba056e24..a572efa8 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -210,3 +210,11 @@ func TestSetAddHint(t *testing.T) { t.Errorf("Program execution failed with error: %s", err) } } + +func TestFindElementHint(t *testing.T) { + cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, Layout: "all_cairo", ProofMode: false} + _, err := cairo_run.CairoRun("../../../cairo_programs/find_element.json", cairoRunConfig) + if err != nil { + t.Errorf("Program execution failed with error: %s", err) + } +} diff --git a/pkg/vm/memory/memory.go b/pkg/vm/memory/memory.go index 35aa56e0..0e372e59 100644 --- a/pkg/vm/memory/memory.go +++ b/pkg/vm/memory/memory.go @@ -140,10 +140,10 @@ func (m *Memory) GetFelt(addr Relocatable) (lambdaworks.Felt, error) { // Get a range of memory from the starting relocatable to the starting relocatable + size func (m *Memory) GetRange(start Relocatable, size uint) ([]MaybeRelocatable, error) { - _, is_in_dict := m.Data[start.AddUint(size - 1)] - if !is_in_dict { - return nil, errors.Errorf("Memory GetRange: range end (%v) not present in memory", start.AddUint(size - 1)) - } + _, is_in_dict := m.Data[start.AddUint(size-1)] + if !is_in_dict { + return nil, errors.Errorf("Memory GetRange: range end (%v) not present in memory", start.AddUint(size-1)) + } var res []MaybeRelocatable for i := uint(0); i <= size; i++ { From 6b596fc1c21e28d5c3ab32d8e69ca8ea5b33f41e Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Wed, 20 Sep 2023 15:03:23 -0300 Subject: [PATCH 06/13] Add search sorted lower and some tests --- cairo_programs/search_sorted_lower.cairo | 23 +++ pkg/hints/find_element_hint_codes.go | 50 ++++++- pkg/hints/find_element_hints.go | 121 +++++++++++++++- pkg/hints/find_element_hints_test.go | 170 +++++++++++++++++++++++ pkg/hints/hint_processor.go | 4 +- pkg/lambdaworks/lambdaworks_test.go | 35 +++++ pkg/vm/cairo_run/cairo_run_test.go | 8 ++ 7 files changed, 407 insertions(+), 4 deletions(-) create mode 100644 cairo_programs/search_sorted_lower.cairo create mode 100644 pkg/hints/find_element_hints_test.go diff --git a/cairo_programs/search_sorted_lower.cairo b/cairo_programs/search_sorted_lower.cairo new file mode 100644 index 00000000..0ef26bef --- /dev/null +++ b/cairo_programs/search_sorted_lower.cairo @@ -0,0 +1,23 @@ +%builtins range_check +from starkware.cairo.common.find_element import search_sorted_lower +from starkware.cairo.common.alloc import alloc + +struct MyStruct { + a: felt, + b: felt, +} + +func main{range_check_ptr}() -> () { + // Create an array with MyStruct elements (1,2), (3,4), (5,6). + alloc_locals; + let (local array_ptr: MyStruct*) = alloc(); + assert array_ptr[0] = MyStruct(a=1, b=2); + assert array_ptr[1] = MyStruct(a=3, b=4); + assert array_ptr[2] = MyStruct(a=5, b=6); + let (smallest_ptr: MyStruct*) = search_sorted_lower( + array_ptr=array_ptr, elm_size=2, n_elms=3, key=2 + ); + assert smallest_ptr.a = 3; + assert smallest_ptr.b = 4; + return (); +} diff --git a/pkg/hints/find_element_hint_codes.go b/pkg/hints/find_element_hint_codes.go index aff73664..eaff417d 100644 --- a/pkg/hints/find_element_hint_codes.go +++ b/pkg/hints/find_element_hint_codes.go @@ -1,3 +1,51 @@ package hints -const FIND_ELEMENT = "array_ptr = ids.array_ptr\nelm_size = ids.elm_size\nassert isinstance(elm_size, int) and elm_size > 0, \\n f'Invalid value for elm_size. Got: {elm_size}.'\nkey = ids.key\n\nif '__find_element_index' in globals():\n ids.index = __find_element_index\n found_key = memory[array_ptr + elm_size * __find_element_index]\n assert found_key == key, \\n f'Invalid index found in __find_element_index. index: {__find_element_index}, ' \\n f'expected key {key}, found key: {found_key}.'\n # Delete __find_element_index to make sure it's not used for the next calls.\n del __find_element_index\nelse:\n n_elms = ids.n_elms\n assert isinstance(n_elms, int) and n_elms >= 0, \\n f'Invalid value for n_elms. Got: {n_elms}.'\n if '__find_element_max_size' in globals():\n assert n_elms <= __find_element_max_size, \\n f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \\n f'Got: n_elms={n_elms}.'\n\n for i in range(n_elms):\n if memory[array_ptr + elm_size * i] == key:\n ids.index = i\n break\n else:\n raise ValueError(f'Key {key} was not found.')" +const FIND_ELEMENT = `array_ptr = ids.array_ptr +elm_size = ids.elm_size +assert isinstance(elm_size, int) and elm_size > 0, \ + f'Invalid value for elm_size. Got: {elm_size}.' +key = ids.key + +if '__find_element_index' in globals(): + ids.index = __find_element_index + found_key = memory[array_ptr + elm_size * __find_element_index] + assert found_key == key, \ + f'Invalid index found in __find_element_index. index: {__find_element_index}, ' \ + f'expected key {key}, found key: {found_key}.' + # Delete __find_element_index to make sure it's not used for the next calls. + del __find_element_index +else: + n_elms = ids.n_elms + assert isinstance(n_elms, int) and n_elms >= 0, \ + f'Invalid value for n_elms. Got: {n_elms}.' + if '__find_element_max_size' in globals(): + assert n_elms <= __find_element_max_size, \ + f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \ + f'Got: n_elms={n_elms}.' + + for i in range(n_elms): + if memory[array_ptr + elm_size * i] == key: + ids.index = i + break + else: + raise ValueError(f'Key {key} was not found.')` + +const SEARCH_SORTED_LOWER = `array_ptr = ids.array_ptr +elm_size = ids.elm_size +assert isinstance(elm_size, int) and elm_size > 0, \ + f'Invalid value for elm_size. Got: {elm_size}.' + +n_elms = ids.n_elms +assert isinstance(n_elms, int) and n_elms >= 0, \ + f'Invalid value for n_elms. Got: {n_elms}.' +if '__find_element_max_size' in globals(): + assert n_elms <= __find_element_max_size, \ + f'find_element() can only be used with n_elms<={__find_element_max_size}. ' \ + f'Got: n_elms={n_elms}.' + +for i in range(n_elms): + if memory[array_ptr + elm_size * i] >= ids.key: + ids.index = i + break +else: + ids.index = n_elms` diff --git a/pkg/hints/find_element_hints.go b/pkg/hints/find_element_hints.go index a456ed08..9e661db5 100644 --- a/pkg/hints/find_element_hints.go +++ b/pkg/hints/find_element_hints.go @@ -3,16 +3,32 @@ package hints import ( . "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/vm/memory" "github.com/pkg/errors" ) -func find_element(ids IdsManager, vm *VirtualMachine) error { +func find_element(ids IdsManager, vm *VirtualMachine, execScopes ExecutionScopes) error { + array_ptr, err := ids.GetRelocatable("array_ptr", vm) + if err != nil { + return err + } + key, err := ids.GetFelt("key", vm) if err != nil { return err } + + elm_size_felt, err := ids.GetFelt("elm_size", vm) + if err != nil { + return err + } + elm_size, err := elm_size_felt.ToUint() + if err != nil { + return err + } + n_elms, err := ids.GetFelt("n_elms", vm) if err != nil { return err @@ -21,8 +37,51 @@ func find_element(ids IdsManager, vm *VirtualMachine) error { if err != nil { return err } + + find_element_index_uncast, err := execScopes.Get("find_element_index") + if err == nil { + find_element_index, ok := find_element_index_uncast.(Felt) + if !ok { + return ConversionError(find_element_index, "felt") + } + position, err := array_ptr.AddFelt(find_element_index.Mul(elm_size_felt)) + if err != nil { + return err + } + + found_key, err := vm.Segments.Memory.GetFelt(position) + if err != nil { + return err + } + if found_key != key { + return errors.Errorf( + "Invalid index found in find_element_index. Index: %s.\nExpected key: %s, found_key %s", + find_element_index.ToSignedFeltString(), + key.ToSignedFeltString(), + found_key.ToSignedFeltString(), + ) + } + execScopes.DeleteVariable("find_element_index") + return ids.Insert("index", NewMaybeRelocatableFelt(find_element_index), vm) + } + + find_element_max_size_uncast, err := execScopes.Get("find_element_max_size") + if err == nil { + find_element_max_size, ok := find_element_max_size_uncast.(Felt) + if !ok { + return ConversionError(find_element_max_size, "felt") + } + if n_elms.Cmp(find_element_max_size) == 1 { + return errors.Errorf( + "find_element() can only be used with n_elms <= %s.\nGot: n_elms = %s", + find_element_max_size.ToSignedFeltString(), + n_elms.ToSignedFeltString(), + ) + } + } + for i := uint(0); i < n_elms_iter; i++ { - iter_key, err := ids.GetStructFieldFelt("array_start", i, vm) + iter_key, err := vm.Segments.Memory.GetFelt(array_ptr.AddUint(i * elm_size)) if err != nil { return err } @@ -30,5 +89,63 @@ func find_element(ids IdsManager, vm *VirtualMachine) error { return ids.Insert("index", NewMaybeRelocatableFelt(FeltFromUint(i)), vm) } } + + return errors.Errorf("Key: %v was not found", key) +} + +func search_sorted_lower(ids IdsManager, vm *VirtualMachine, execScopes ExecutionScopes) error { + array_ptr, err := ids.GetRelocatable("array_ptr", vm) + if err != nil { + return err + } + + key, err := ids.GetFelt("key", vm) + if err != nil { + return err + } + + elm_size_felt, err := ids.GetFelt("elm_size", vm) + if err != nil { + return err + } + elm_size, err := elm_size_felt.ToUint() + if err != nil { + return err + } + + n_elms, err := ids.GetFelt("n_elms", vm) + if err != nil { + return err + } + n_elms_iter, err := n_elms.ToUint() + if err != nil { + return err + } + + find_element_max_size_uncast, err := execScopes.Get("find_element_max_size") + if err == nil { + find_element_max_size, ok := find_element_max_size_uncast.(Felt) + if !ok { + return ConversionError(find_element_max_size, "felt") + } + if n_elms.Cmp(find_element_max_size) == 1 { + return errors.Errorf( + "find_element() can only be used with n_elms <= %s.\nGot: n_elms = %s", + find_element_max_size.ToSignedFeltString(), + n_elms.ToSignedFeltString(), + ) + } + } + + for i := uint(0); i < n_elms_iter; i++ { + iter_key, err := vm.Segments.Memory.GetFelt(array_ptr.AddUint(i * elm_size)) + if err != nil { + return err + } + if iter_key == key || iter_key.Cmp(key) == 1 { + return ids.Insert("index", NewMaybeRelocatableFelt(FeltFromUint(i)), vm) + } + } + return errors.Errorf("Key: %v was not found", key) } diff --git a/pkg/hints/find_element_hints_test.go b/pkg/hints/find_element_hints_test.go new file mode 100644 index 00000000..d8c69b78 --- /dev/null +++ b/pkg/hints/find_element_hints_test.go @@ -0,0 +1,170 @@ +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/vm/memory" +) + +func TestFindElementHintOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + vm.Segments.AddSegment() + vm.Segments.Memory.Insert(NewRelocatable(1, 0), NewMaybeRelocatableFelt(FeltFromUint64(1))) + vm.Segments.Memory.Insert(NewRelocatable(1, 1), NewMaybeRelocatableFelt(FeltFromUint64(2))) + vm.Segments.Memory.Insert(NewRelocatable(1, 2), NewMaybeRelocatableFelt(FeltFromUint64(3))) + vm.Segments.Memory.Insert(NewRelocatable(1, 3), NewMaybeRelocatableFelt(FeltFromUint64(4))) + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "array_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))}, + "elm_size": {NewMaybeRelocatableFelt(FeltFromUint64(2))}, + "n_elms": {NewMaybeRelocatableFelt(FeltFromUint64(2))}, + "key": {NewMaybeRelocatableFelt(FeltFromUint64(3))}, + "index": {nil}, + }, + vm, + ) + + execScopes := NewExecutionScopes() + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: FIND_ELEMENT, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, execScopes) + if err != nil { + t.Errorf("FIND_ELEMENT hint test failed with error: %s", err) + } + index, err := idsManager.GetFelt("index", vm) + if err != nil { + t.Errorf("%s", err) + } + if index.Cmp(FeltFromUint64(1)) != 0 { + t.Errorf("Index was expected to be 1, got %s", index.ToSignedFeltString()) + } +} + +func TestFindElementWithFindElementIndex(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + vm.Segments.AddSegment() + vm.Segments.Memory.Insert(NewRelocatable(1, 0), NewMaybeRelocatableFelt(FeltFromUint64(1))) + vm.Segments.Memory.Insert(NewRelocatable(1, 1), NewMaybeRelocatableFelt(FeltFromUint64(2))) + vm.Segments.Memory.Insert(NewRelocatable(1, 2), NewMaybeRelocatableFelt(FeltFromUint64(3))) + vm.Segments.Memory.Insert(NewRelocatable(1, 3), NewMaybeRelocatableFelt(FeltFromUint64(4))) + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "array_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))}, + "elm_size": {NewMaybeRelocatableFelt(FeltFromUint64(2))}, + "n_elms": {NewMaybeRelocatableFelt(FeltFromUint64(2))}, + "key": {NewMaybeRelocatableFelt(FeltFromUint64(3))}, + "index": {nil}, + }, + vm, + ) + + execScopes := NewExecutionScopes() + scope := make(map[string]interface{}) + scope["find_element_index"] = FeltOne() + execScopes.EnterScope(scope) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: FIND_ELEMENT, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, execScopes) + if err != nil { + t.Errorf("FIND_ELEMENT hint test failed with error: %s", err) + } + index, err := idsManager.GetFelt("index", vm) + if err != nil { + t.Errorf("%s", err) + } + if index.Cmp(FeltFromUint64(1)) != 0 { + t.Errorf("Index was expected to be 1, got %s", index.ToSignedFeltString()) + } +} + +func TestFindElementFindElementMaxSizeOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + vm.Segments.AddSegment() + vm.Segments.Memory.Insert(NewRelocatable(1, 0), NewMaybeRelocatableFelt(FeltFromUint64(1))) + vm.Segments.Memory.Insert(NewRelocatable(1, 1), NewMaybeRelocatableFelt(FeltFromUint64(2))) + vm.Segments.Memory.Insert(NewRelocatable(1, 2), NewMaybeRelocatableFelt(FeltFromUint64(3))) + vm.Segments.Memory.Insert(NewRelocatable(1, 3), NewMaybeRelocatableFelt(FeltFromUint64(4))) + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "array_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))}, + "elm_size": {NewMaybeRelocatableFelt(FeltFromUint64(2))}, + "n_elms": {NewMaybeRelocatableFelt(FeltFromUint64(2))}, + "key": {NewMaybeRelocatableFelt(FeltFromUint64(3))}, + "index": {nil}, + }, + vm, + ) + + execScopes := NewExecutionScopes() + scope := make(map[string]interface{}) + scope["find_element_max_size"] = FeltFromUint64(2) + execScopes.EnterScope(scope) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: FIND_ELEMENT, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, execScopes) + if err != nil { + t.Errorf("FIND_ELEMENT hint test failed with error: %s", err) + } + index, err := idsManager.GetFelt("index", vm) + if err != nil { + t.Errorf("%s", err) + } + if index.Cmp(FeltFromUint64(1)) != 0 { + t.Errorf("Index was expected to be 1, got %s", index.ToSignedFeltString()) + } +} + +func TestFindElementFindElementMaxSizeLessThanNeeded(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + vm.Segments.AddSegment() + vm.Segments.Memory.Insert(NewRelocatable(1, 0), NewMaybeRelocatableFelt(FeltFromUint64(1))) + vm.Segments.Memory.Insert(NewRelocatable(1, 1), NewMaybeRelocatableFelt(FeltFromUint64(2))) + vm.Segments.Memory.Insert(NewRelocatable(1, 2), NewMaybeRelocatableFelt(FeltFromUint64(3))) + vm.Segments.Memory.Insert(NewRelocatable(1, 3), NewMaybeRelocatableFelt(FeltFromUint64(4))) + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "array_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))}, + "elm_size": {NewMaybeRelocatableFelt(FeltFromUint64(2))}, + "n_elms": {NewMaybeRelocatableFelt(FeltFromUint64(2))}, + "key": {NewMaybeRelocatableFelt(FeltFromUint64(3))}, + "index": {nil}, + }, + vm, + ) + + execScopes := NewExecutionScopes() + scope := make(map[string]interface{}) + scope["find_element_max_size"] = FeltOne() + execScopes.EnterScope(scope) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: FIND_ELEMENT, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, execScopes) + if err == nil { + t.Errorf("FIND_ELEMENT hint expected to fail with find_element_max_size < n_elms") + } +} diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index a81e4e68..1b707005 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -77,7 +77,9 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, case SET_ADD: return set_add(data.Ids, vm) case FIND_ELEMENT: - return find_element(data.Ids, vm) + return find_element(data.Ids, vm, *execScopes) + case SEARCH_SORTED_LOWER: + return search_sorted_lower(data.Ids, vm, *execScopes) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/lambdaworks/lambdaworks_test.go b/pkg/lambdaworks/lambdaworks_test.go index 8116378d..34275815 100644 --- a/pkg/lambdaworks/lambdaworks_test.go +++ b/pkg/lambdaworks/lambdaworks_test.go @@ -410,6 +410,41 @@ func TestToU64Fail(t *testing.T) { t.Errorf("Conversion test should fail with error: %v", expected_err) } } + +func TestToUint1(t *testing.T) { + felt := lambdaworks.FeltOne() + result, err := felt.ToUint() + + var expected uint = 1 + + if expected != result { + t.Errorf("Error in conversion expected: %v, got %v with err: %v", expected, result, err) + } + +} + +func TestToUint10230(t *testing.T) { + felt := lambdaworks.FeltFromUint(10230) + result, err := felt.ToUint() + + var expected uint = 10230 + + if expected != result { + t.Errorf("Error in conversion expected: %v, got %v with err: %v", expected, result, err) + } +} + +func TestToUintFail(t *testing.T) { + felt := lambdaworks.FeltFromDecString("9999999999999999999999999") + + _, err := felt.ToUint() + expected_err := lambdaworks.ConversionError(felt, "uint") + + if err.Error() != expected_err.Error() { + t.Errorf("Conversion test should fail with error: %v", expected_err) + } +} + func TestFeltIsZero(t *testing.T) { f_zero := lambdaworks.FeltZero() diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index a572efa8..0d35c61a 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -218,3 +218,11 @@ func TestFindElementHint(t *testing.T) { t.Errorf("Program execution failed with error: %s", err) } } + +func TestSearchSortedLowerHint(t *testing.T) { + cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, Layout: "all_cairo", ProofMode: false} + _, err := cairo_run.CairoRun("../../../cairo_programs/search_sorted_lower.json", cairoRunConfig) + if err != nil { + t.Errorf("Program execution failed with error: %s", err) + } +} From 6c61272aa4a74f223c81f97cf9c79e44994255c2 Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Thu, 21 Sep 2023 09:26:34 -0300 Subject: [PATCH 07/13] Run format --- pkg/hints/set_hints.go | 15 +++++++-------- pkg/vm/cairo_run/cairo_run_test.go | 8 ++++---- pkg/vm/vm_core.go | 16 ++++++++-------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/pkg/hints/set_hints.go b/pkg/hints/set_hints.go index 7eedcb18..14d9bf38 100644 --- a/pkg/hints/set_hints.go +++ b/pkg/hints/set_hints.go @@ -6,7 +6,7 @@ import ( . "github.com/lambdaclass/cairo-vm.go/pkg/vm" . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" "github.com/pkg/errors" - "reflect" + "reflect" ) /* @@ -63,20 +63,19 @@ func set_add(ids IdsManager, vm *VirtualMachine) error { return err } - for i := uint(0); i < set_end_ptr.Offset - set_ptr.Offset; i++ { - other_elm, err := vm.Segments.Memory.GetRange(set_ptr.AddUint(i * elm_size), elm_size) + for i := uint(0); i < set_end_ptr.Offset-set_ptr.Offset; i++ { + other_elm, err := vm.Segments.Memory.GetRange(set_ptr.AddUint(i*elm_size), elm_size) if err != nil { return err } if reflect.DeepEqual(elem, other_elm) { - err := ids.Insert("index", NewMaybeRelocatableFelt(FeltFromUint(i)), vm) - if err != nil { - return err - } + err := ids.Insert("index", NewMaybeRelocatableFelt(FeltFromUint(i)), vm) + if err != nil { + return err + } return ids.Insert("is_elm_in_set", NewMaybeRelocatableFelt(FeltOne()), vm) } } return ids.Insert("is_elm_in_set", NewMaybeRelocatableFelt(FeltZero()), vm) } - diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index 065b6d54..33fc265f 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -148,7 +148,7 @@ func TestUnsignedDivRemHint(t *testing.T) { } func TestSetAddHint(t *testing.T) { - testProgram("set_add", t) + testProgram("set_add", t) } func TestMemcpyHint(t *testing.T) { @@ -175,15 +175,15 @@ func TestSquashDict(t *testing.T) { } func TestSignedDivRemHint(t *testing.T) { - testProgram("signed_div_rem", t) + testProgram("signed_div_rem", t) } func TestFindElementHint(t *testing.T) { - testProgram("find_element", t) + testProgram("find_element", t) } func TestSearchSortedLowerHint(t *testing.T) { - testProgram("search_sorted_lower", t) + testProgram("search_sorted_lower", t) } func TestAssert250BitHint(t *testing.T) { diff --git a/pkg/vm/vm_core.go b/pkg/vm/vm_core.go index e267aa21..7f5aec40 100644 --- a/pkg/vm/vm_core.go +++ b/pkg/vm/vm_core.go @@ -324,14 +324,14 @@ func (vm *VirtualMachine) DeduceOp1(instruction *Instruction, dst *memory.MaybeR return &dst_rel, dst, nil } case ResMul: - if op0 != nil && dst != nil { - dst_felt, dst_is_felt := dst.GetFelt() - op0_felt, op0_is_felt := op0.GetFelt() - if dst_is_felt && op0_is_felt && !op0_felt.IsZero() { - res := memory.NewMaybeRelocatableFelt(dst_felt.Div(op0_felt)) - return res, dst, nil - } - } + if op0 != nil && dst != nil { + dst_felt, dst_is_felt := dst.GetFelt() + op0_felt, op0_is_felt := op0.GetFelt() + if dst_is_felt && op0_is_felt && !op0_felt.IsZero() { + res := memory.NewMaybeRelocatableFelt(dst_felt.Div(op0_felt)) + return res, dst, nil + } + } } } return nil, nil, nil From 57d6dc797c4d98a578f020446d50633575bdc61a Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Thu, 21 Sep 2023 09:51:20 -0300 Subject: [PATCH 08/13] Add set_hints_test --- pkg/hints/set_hints.go | 10 +--- pkg/hints/set_hints_test.go | 103 ++++++++++++++++++++++++++++++++++++ pkg/vm/memory/memory.go | 4 +- 3 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 pkg/hints/set_hints_test.go diff --git a/pkg/hints/set_hints.go b/pkg/hints/set_hints.go index 14d9bf38..17569565 100644 --- a/pkg/hints/set_hints.go +++ b/pkg/hints/set_hints.go @@ -58,16 +58,10 @@ func set_add(ids IdsManager, vm *VirtualMachine) error { return errors.Errorf("expected set_ptr: %v <= set_end_ptr: %v", set_ptr, set_end_ptr) } - elem, err := vm.Segments.Memory.GetRange(elm_ptr, elm_size) - if err != nil { - return err - } + elem := vm.Segments.Memory.GetRange(elm_ptr, elm_size) for i := uint(0); i < set_end_ptr.Offset-set_ptr.Offset; i++ { - other_elm, err := vm.Segments.Memory.GetRange(set_ptr.AddUint(i*elm_size), elm_size) - if err != nil { - return err - } + other_elm := vm.Segments.Memory.GetRange(set_ptr.AddUint(i*elm_size), elm_size) if reflect.DeepEqual(elem, other_elm) { err := ids.Insert("index", NewMaybeRelocatableFelt(FeltFromUint(i)), vm) if err != nil { diff --git a/pkg/hints/set_hints_test.go b/pkg/hints/set_hints_test.go new file mode 100644 index 00000000..81640fde --- /dev/null +++ b/pkg/hints/set_hints_test.go @@ -0,0 +1,103 @@ +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/vm" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" +) + +func TestSetAddElmInSet(t *testing.T) { + vm := NewVirtualMachine() + // Initialize segments + vm.Segments.AddSegment() + vm.Segments.AddSegment() + // element to insert + vm.Segments.Memory.Insert(NewRelocatable(1, 0), NewMaybeRelocatableFelt(FeltFromUint64(2))) + // set + vm.Segments.Memory.Insert(NewRelocatable(1, 1), NewMaybeRelocatableFelt(FeltFromUint64(1))) + vm.Segments.Memory.Insert(NewRelocatable(1, 2), NewMaybeRelocatableFelt(FeltFromUint64(2))) + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "elm_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))}, + "set_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 1))}, + "set_end_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 3))}, + "elm_size": {NewMaybeRelocatableFelt(FeltFromUint64(1))}, + "index": {nil}, + "is_elm_in_set": {nil}, + }, + vm, + ) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: SET_ADD, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("SET_ADD failed with error: %s", err) + } + + is_elm_in_set, err := idsManager.GetFelt("is_elm_in_set", vm) + if err != nil { + t.Errorf("SET_ADD couldn't get is_elm_in_set: %s", err) + } + + if !is_elm_in_set.IsOne() { + t.Errorf("Expected is_elm_in_set to be 1, got: %s", is_elm_in_set.ToSignedFeltString()) + } + + index, err := idsManager.GetFelt("index", vm) + if err != nil { + t.Errorf("SET_ADD couldn't get index: %s", err) + } + if !index.IsOne() { + t.Errorf("Expected element to be found at 1, got index: %s", index.ToSignedFeltString()) + } +} + +func TestSetAddElmNotInSet(t *testing.T) { + vm := NewVirtualMachine() + // Initialize segments + vm.Segments.AddSegment() + vm.Segments.AddSegment() + // element to insert + vm.Segments.Memory.Insert(NewRelocatable(1, 0), NewMaybeRelocatableFelt(FeltFromUint64(3))) + // set + vm.Segments.Memory.Insert(NewRelocatable(1, 1), NewMaybeRelocatableFelt(FeltFromUint64(1))) + vm.Segments.Memory.Insert(NewRelocatable(1, 2), NewMaybeRelocatableFelt(FeltFromUint64(2))) + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "elm_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))}, + "set_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 1))}, + "set_end_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 3))}, + "elm_size": {NewMaybeRelocatableFelt(FeltFromUint64(1))}, + "index": {nil}, + "is_elm_in_set": {nil}, + }, + vm, + ) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: SET_ADD, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("SET_ADD failed with error: %s", err) + } + + is_elm_in_set, err := idsManager.GetFelt("is_elm_in_set", vm) + if err != nil { + t.Errorf("SET_ADD couldn't get is_elm_in_set: %s", err) + } + + if !is_elm_in_set.IsZero() { + t.Errorf("Expected is_elm_in_set to be 1, got: %s", is_elm_in_set.ToSignedFeltString()) + } +} diff --git a/pkg/vm/memory/memory.go b/pkg/vm/memory/memory.go index ccee0a1d..7ce7d77a 100644 --- a/pkg/vm/memory/memory.go +++ b/pkg/vm/memory/memory.go @@ -151,12 +151,12 @@ func (m *Memory) GetFelt(addr Relocatable) (lambdaworks.Felt, error) { } // Get a range of memory from the starting relocatable to the starting relocatable + size -func (m *Memory) GetRange(start Relocatable, size uint) ([]MaybeRelocatable, error) { +func (m *Memory) GetRange(start Relocatable, size uint) []MaybeRelocatable { var res []MaybeRelocatable for i := uint(0); i < size; i++ { res = append(res, m.Data[start.AddUint(i)]) } - return res, nil + return res } // Adds a validation rule for a given segment From 22c3df1ba52ba746f9f35199e4df688826b3fefe Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Thu, 21 Sep 2023 11:10:01 -0300 Subject: [PATCH 09/13] Add error to GetRange --- cairo_programs/set_add.cairo | 13 ------------- pkg/hints/set_hints.go | 12 +++++++++--- pkg/hints/set_hints_test.go | 2 +- pkg/lambdaworks/lambdaworks.go | 6 +++--- pkg/vm/memory/memory.go | 8 ++++++-- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/cairo_programs/set_add.cairo b/cairo_programs/set_add.cairo index 8a765e25..4113901d 100644 --- a/cairo_programs/set_add.cairo +++ b/cairo_programs/set_add.cairo @@ -26,18 +26,5 @@ func main{range_check_ptr}() { set_add{set_end_ptr=list_end}(set_ptr=my_list, elm_size=MyStruct.SIZE, elm_ptr=new_elm); assert my_list[2] = MyStruct(a=2, b=3); - - // Now let's try to add MyStruct(a=1, b=3) to my_list, - // Since this element is already present in my_list, - // set_add won't add any element to the my_list - - let list_end: felt* = &my_list[3]; - assert new_elm[1] = MyStruct(a=1, b=3); - - set_add{set_end_ptr=list_end}(set_ptr=my_list, elm_size=MyStruct.SIZE, elm_ptr=new_elm); - - // Since my_list[3] = None, we can insert a MyStruct - assert my_list[3] = MyStruct(a=0, b=0); - return (); } diff --git a/pkg/hints/set_hints.go b/pkg/hints/set_hints.go index 17569565..b3f7cf78 100644 --- a/pkg/hints/set_hints.go +++ b/pkg/hints/set_hints.go @@ -58,10 +58,16 @@ func set_add(ids IdsManager, vm *VirtualMachine) error { return errors.Errorf("expected set_ptr: %v <= set_end_ptr: %v", set_ptr, set_end_ptr) } - elem := vm.Segments.Memory.GetRange(elm_ptr, elm_size) + elem, err := vm.Segments.Memory.GetRange(elm_ptr, elm_size) + if err != nil { + return err + } - for i := uint(0); i < set_end_ptr.Offset-set_ptr.Offset; i++ { - other_elm := vm.Segments.Memory.GetRange(set_ptr.AddUint(i*elm_size), elm_size) + for i := uint(0); i < set_end_ptr.Offset-set_ptr.Offset-elm_size; i++ { + other_elm, err := vm.Segments.Memory.GetRange(set_ptr.AddUint(i*elm_size), elm_size) + if err != nil { + return err + } if reflect.DeepEqual(elem, other_elm) { err := ids.Insert("index", NewMaybeRelocatableFelt(FeltFromUint(i)), vm) if err != nil { diff --git a/pkg/hints/set_hints_test.go b/pkg/hints/set_hints_test.go index 81640fde..92681399 100644 --- a/pkg/hints/set_hints_test.go +++ b/pkg/hints/set_hints_test.go @@ -24,7 +24,7 @@ func TestSetAddElmInSet(t *testing.T) { map[string][]*MaybeRelocatable{ "elm_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))}, "set_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 1))}, - "set_end_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 3))}, + "set_end_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 4))}, "elm_size": {NewMaybeRelocatableFelt(FeltFromUint64(1))}, "index": {nil}, "is_elm_in_set": {nil}, diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index 89877617..59f3a477 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -94,11 +94,11 @@ func (felt Felt) ToU64() (uint64, error) { // turns a felt to usize func (felt Felt) ToUint() (uint, error) { - if felt.limbs[0] == 0 && felt.limbs[1] == 0 && felt.limbs[2] == 0 { - return uint(felt.limbs[3]), nil - } else { + felt_u64, err := felt.ToU64() + if err != nil { return 0, ConversionError(felt, "uint") } + return uint(felt_u64), nil } func (felt Felt) ToLeBytes() *[32]byte { diff --git a/pkg/vm/memory/memory.go b/pkg/vm/memory/memory.go index 7ce7d77a..e1a00780 100644 --- a/pkg/vm/memory/memory.go +++ b/pkg/vm/memory/memory.go @@ -151,12 +151,16 @@ func (m *Memory) GetFelt(addr Relocatable) (lambdaworks.Felt, error) { } // Get a range of memory from the starting relocatable to the starting relocatable + size -func (m *Memory) GetRange(start Relocatable, size uint) []MaybeRelocatable { +func (m *Memory) GetRange(start Relocatable, size uint) ([]MaybeRelocatable, error) { + _, ok := m.Data[start.AddUint(size-1)] + if !ok { + return nil, errors.Errorf("Range out of bounds, cell %v is not present in Memory", start.AddUint(size-1)) + } var res []MaybeRelocatable for i := uint(0); i < size; i++ { res = append(res, m.Data[start.AddUint(i)]) } - return res + return res, nil } // Adds a validation rule for a given segment From f2ed685608922bf6434fcfc2d0cc1de4ce717009 Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Thu, 21 Sep 2023 11:44:47 -0300 Subject: [PATCH 10/13] Move hint codes --- pkg/hints/find_element_hints_test.go | 1 + pkg/hints/{ => hint_codes}/find_element_hint_codes.go | 2 +- pkg/hints/{ => hint_codes}/set_hint_codes.go | 2 +- pkg/hints/set_hints_test.go | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) rename pkg/hints/{ => hint_codes}/find_element_hint_codes.go (98%) rename pkg/hints/{ => hint_codes}/set_hint_codes.go (95%) diff --git a/pkg/hints/find_element_hints_test.go b/pkg/hints/find_element_hints_test.go index e113c8a9..a9e74eda 100644 --- a/pkg/hints/find_element_hints_test.go +++ b/pkg/hints/find_element_hints_test.go @@ -4,6 +4,7 @@ import ( "testing" . "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/types" diff --git a/pkg/hints/find_element_hint_codes.go b/pkg/hints/hint_codes/find_element_hint_codes.go similarity index 98% rename from pkg/hints/find_element_hint_codes.go rename to pkg/hints/hint_codes/find_element_hint_codes.go index eaff417d..30bea4d2 100644 --- a/pkg/hints/find_element_hint_codes.go +++ b/pkg/hints/hint_codes/find_element_hint_codes.go @@ -1,4 +1,4 @@ -package hints +package hint_codes const FIND_ELEMENT = `array_ptr = ids.array_ptr elm_size = ids.elm_size diff --git a/pkg/hints/set_hint_codes.go b/pkg/hints/hint_codes/set_hint_codes.go similarity index 95% rename from pkg/hints/set_hint_codes.go rename to pkg/hints/hint_codes/set_hint_codes.go index 402e5dc2..53354ac4 100644 --- a/pkg/hints/set_hint_codes.go +++ b/pkg/hints/hint_codes/set_hint_codes.go @@ -1,3 +1,3 @@ -package hints +package hint_codes const SET_ADD = "assert ids.elm_size > 0\nassert ids.set_ptr <= ids.set_end_ptr\nelm_list = memory.get_range(ids.elm_ptr, ids.elm_size)\nfor i in range(0, ids.set_end_ptr - ids.set_ptr, ids.elm_size):\n if memory.get_range(ids.set_ptr + i, ids.elm_size) == elm_list:\n ids.index = i // ids.elm_size\n ids.is_elm_in_set = 1\n break\nelse:\n ids.is_elm_in_set = 0" diff --git a/pkg/hints/set_hints_test.go b/pkg/hints/set_hints_test.go index 92681399..bc5ad98a 100644 --- a/pkg/hints/set_hints_test.go +++ b/pkg/hints/set_hints_test.go @@ -4,6 +4,7 @@ import ( "testing" . "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/vm" From 67a34851ac08e02fa7c8583fd09fa32eefe50c64 Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Thu, 21 Sep 2023 11:50:08 -0300 Subject: [PATCH 11/13] Make cell presence check more thorough --- pkg/vm/memory/memory.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/vm/memory/memory.go b/pkg/vm/memory/memory.go index e1a00780..a4b3659e 100644 --- a/pkg/vm/memory/memory.go +++ b/pkg/vm/memory/memory.go @@ -152,13 +152,13 @@ func (m *Memory) GetFelt(addr Relocatable) (lambdaworks.Felt, error) { // Get a range of memory from the starting relocatable to the starting relocatable + size func (m *Memory) GetRange(start Relocatable, size uint) ([]MaybeRelocatable, error) { - _, ok := m.Data[start.AddUint(size-1)] - if !ok { - return nil, errors.Errorf("Range out of bounds, cell %v is not present in Memory", start.AddUint(size-1)) - } var res []MaybeRelocatable for i := uint(0); i < size; i++ { - res = append(res, m.Data[start.AddUint(i)]) + val, ok := m.Data[start.AddUint(i)] + if !ok { + return nil, errors.Errorf("GetRange: cell %v is not present in Memory", start.AddUint(i)) + } + res = append(res, val) } return res, nil } From 1475d36a933098f17c63947c8e3ba48e1de41b25 Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Thu, 21 Sep 2023 12:05:17 -0300 Subject: [PATCH 12/13] Use camel case --- pkg/hints/find_element_hints.go | 78 ++++++++++++++++----------------- pkg/hints/hint_processor.go | 6 +-- pkg/hints/set_hints.go | 26 +++++------ pkg/hints/set_hints_test.go | 12 ++--- 4 files changed, 61 insertions(+), 61 deletions(-) diff --git a/pkg/hints/find_element_hints.go b/pkg/hints/find_element_hints.go index 9e661db5..303003a1 100644 --- a/pkg/hints/find_element_hints.go +++ b/pkg/hints/find_element_hints.go @@ -9,8 +9,8 @@ import ( "github.com/pkg/errors" ) -func find_element(ids IdsManager, vm *VirtualMachine, execScopes ExecutionScopes) error { - array_ptr, err := ids.GetRelocatable("array_ptr", vm) +func findElement(ids IdsManager, vm *VirtualMachine, execScopes ExecutionScopes) error { + arrayPtr, err := ids.GetRelocatable("array_ptr", vm) if err != nil { return err } @@ -20,72 +20,72 @@ func find_element(ids IdsManager, vm *VirtualMachine, execScopes ExecutionScopes return err } - elm_size_felt, err := ids.GetFelt("elm_size", vm) + elmSizeFelt, err := ids.GetFelt("elm_size", vm) if err != nil { return err } - elm_size, err := elm_size_felt.ToUint() + elmSize, err := elmSizeFelt.ToUint() if err != nil { return err } - n_elms, err := ids.GetFelt("n_elms", vm) + nElms, err := ids.GetFelt("n_elms", vm) if err != nil { return err } - n_elms_iter, err := n_elms.ToUint() + nElmsIter, err := nElms.ToUint() if err != nil { return err } - find_element_index_uncast, err := execScopes.Get("find_element_index") + findElementIndexUncast, err := execScopes.Get("find_element_index") if err == nil { - find_element_index, ok := find_element_index_uncast.(Felt) + findElementIndex, ok := findElementIndexUncast.(Felt) if !ok { - return ConversionError(find_element_index, "felt") + return ConversionError(findElementIndex, "felt") } - position, err := array_ptr.AddFelt(find_element_index.Mul(elm_size_felt)) + position, err := arrayPtr.AddFelt(findElementIndex.Mul(elmSizeFelt)) if err != nil { return err } - found_key, err := vm.Segments.Memory.GetFelt(position) + foundKey, err := vm.Segments.Memory.GetFelt(position) if err != nil { return err } - if found_key != key { + if foundKey != key { return errors.Errorf( "Invalid index found in find_element_index. Index: %s.\nExpected key: %s, found_key %s", - find_element_index.ToSignedFeltString(), + findElementIndex.ToSignedFeltString(), key.ToSignedFeltString(), - found_key.ToSignedFeltString(), + foundKey.ToSignedFeltString(), ) } execScopes.DeleteVariable("find_element_index") - return ids.Insert("index", NewMaybeRelocatableFelt(find_element_index), vm) + return ids.Insert("index", NewMaybeRelocatableFelt(findElementIndex), vm) } - find_element_max_size_uncast, err := execScopes.Get("find_element_max_size") + findElementMaxSizeUncast, err := execScopes.Get("find_element_max_size") if err == nil { - find_element_max_size, ok := find_element_max_size_uncast.(Felt) + findElementMaxSize, ok := findElementMaxSizeUncast.(Felt) if !ok { - return ConversionError(find_element_max_size, "felt") + return ConversionError(findElementMaxSize, "felt") } - if n_elms.Cmp(find_element_max_size) == 1 { + if nElms.Cmp(findElementMaxSize) == 1 { return errors.Errorf( "find_element() can only be used with n_elms <= %s.\nGot: n_elms = %s", - find_element_max_size.ToSignedFeltString(), - n_elms.ToSignedFeltString(), + findElementMaxSize.ToSignedFeltString(), + nElms.ToSignedFeltString(), ) } } - for i := uint(0); i < n_elms_iter; i++ { - iter_key, err := vm.Segments.Memory.GetFelt(array_ptr.AddUint(i * elm_size)) + for i := uint(0); i < nElmsIter; i++ { + iterKey, err := vm.Segments.Memory.GetFelt(arrayPtr.AddUint(i * elmSize)) if err != nil { return err } - if iter_key == key { + if iterKey == key { return ids.Insert("index", NewMaybeRelocatableFelt(FeltFromUint(i)), vm) } } @@ -93,8 +93,8 @@ func find_element(ids IdsManager, vm *VirtualMachine, execScopes ExecutionScopes return errors.Errorf("Key: %v was not found", key) } -func search_sorted_lower(ids IdsManager, vm *VirtualMachine, execScopes ExecutionScopes) error { - array_ptr, err := ids.GetRelocatable("array_ptr", vm) +func searchSortedLower(ids IdsManager, vm *VirtualMachine, execScopes ExecutionScopes) error { + arrayPtr, err := ids.GetRelocatable("array_ptr", vm) if err != nil { return err } @@ -104,45 +104,45 @@ func search_sorted_lower(ids IdsManager, vm *VirtualMachine, execScopes Executio return err } - elm_size_felt, err := ids.GetFelt("elm_size", vm) + elmSizeFelt, err := ids.GetFelt("elm_size", vm) if err != nil { return err } - elm_size, err := elm_size_felt.ToUint() + elmSize, err := elmSizeFelt.ToUint() if err != nil { return err } - n_elms, err := ids.GetFelt("n_elms", vm) + nElms, err := ids.GetFelt("n_elms", vm) if err != nil { return err } - n_elms_iter, err := n_elms.ToUint() + nElmsIter, err := nElms.ToUint() if err != nil { return err } - find_element_max_size_uncast, err := execScopes.Get("find_element_max_size") + findElementMaxSizeUncast, err := execScopes.Get("find_element_max_size") if err == nil { - find_element_max_size, ok := find_element_max_size_uncast.(Felt) + findElementMaxSize, ok := findElementMaxSizeUncast.(Felt) if !ok { - return ConversionError(find_element_max_size, "felt") + return ConversionError(findElementMaxSize, "felt") } - if n_elms.Cmp(find_element_max_size) == 1 { + if nElms.Cmp(findElementMaxSize) == 1 { return errors.Errorf( "find_element() can only be used with n_elms <= %s.\nGot: n_elms = %s", - find_element_max_size.ToSignedFeltString(), - n_elms.ToSignedFeltString(), + findElementMaxSize.ToSignedFeltString(), + nElms.ToSignedFeltString(), ) } } - for i := uint(0); i < n_elms_iter; i++ { - iter_key, err := vm.Segments.Memory.GetFelt(array_ptr.AddUint(i * elm_size)) + for i := uint(0); i < nElmsIter; i++ { + iterKey, err := vm.Segments.Memory.GetFelt(arrayPtr.AddUint(i * elmSize)) if err != nil { return err } - if iter_key == key || iter_key.Cmp(key) == 1 { + if iterKey == key || iterKey.Cmp(key) == 1 { return ids.Insert("index", NewMaybeRelocatableFelt(FeltFromUint(i)), vm) } } diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 5e7d1c06..c53321bc 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -107,11 +107,11 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, case VM_ENTER_SCOPE: return vm_enter_scope(execScopes) case SET_ADD: - return set_add(data.Ids, vm) + return setAdd(data.Ids, vm) case FIND_ELEMENT: - return find_element(data.Ids, vm, *execScopes) + return findElement(data.Ids, vm, *execScopes) case SEARCH_SORTED_LOWER: - return search_sorted_lower(data.Ids, vm, *execScopes) + return searchSortedLower(data.Ids, vm, *execScopes) case UNSAFE_KECCAK: return unsafeKeccak(data.Ids, vm, *execScopes) case UNSAFE_KECCAK_FINALIZE: diff --git a/pkg/hints/set_hints.go b/pkg/hints/set_hints.go index b3f7cf78..2435aa02 100644 --- a/pkg/hints/set_hints.go +++ b/pkg/hints/set_hints.go @@ -26,49 +26,49 @@ else: ids.is_elm_in_set = 0 */ -func set_add(ids IdsManager, vm *VirtualMachine) error { - set_ptr, err := ids.GetRelocatable("set_ptr", vm) +func setAdd(ids IdsManager, vm *VirtualMachine) error { + setPtr, err := ids.GetRelocatable("set_ptr", vm) if err != nil { return err } - elm_size_felt, err := ids.GetFelt("elm_size", vm) + elmSizeFelt, err := ids.GetFelt("elm_size", vm) if err != nil { return err } - elm_ptr, err := ids.GetRelocatable("elm_ptr", vm) + elmPtr, err := ids.GetRelocatable("elm_ptr", vm) if err != nil { return err } - set_end_ptr, err := ids.GetRelocatable("set_end_ptr", vm) + setEndPtr, err := ids.GetRelocatable("set_end_ptr", vm) if err != nil { return err } - if elm_size_felt.IsZero() { + if elmSizeFelt.IsZero() { return errors.Errorf("assert ids.elm_size > 0") } - elm_size, err := elm_size_felt.ToUint() + elmSize, err := elmSizeFelt.ToUint() if err != nil { return err } - if set_ptr.Offset > set_end_ptr.Offset { - return errors.Errorf("expected set_ptr: %v <= set_end_ptr: %v", set_ptr, set_end_ptr) + if setPtr.Offset > setEndPtr.Offset { + return errors.Errorf("expected set_ptr: %v <= set_end_ptr: %v", setPtr, setEndPtr) } - elem, err := vm.Segments.Memory.GetRange(elm_ptr, elm_size) + elem, err := vm.Segments.Memory.GetRange(elmPtr, elmSize) if err != nil { return err } - for i := uint(0); i < set_end_ptr.Offset-set_ptr.Offset-elm_size; i++ { - other_elm, err := vm.Segments.Memory.GetRange(set_ptr.AddUint(i*elm_size), elm_size) + for i := uint(0); i < setEndPtr.Offset-setPtr.Offset-elmSize; i++ { + otherElm, err := vm.Segments.Memory.GetRange(setPtr.AddUint(i*elmSize), elmSize) if err != nil { return err } - if reflect.DeepEqual(elem, other_elm) { + if reflect.DeepEqual(elem, otherElm) { err := ids.Insert("index", NewMaybeRelocatableFelt(FeltFromUint(i)), vm) if err != nil { return err diff --git a/pkg/hints/set_hints_test.go b/pkg/hints/set_hints_test.go index bc5ad98a..a7bbd9fa 100644 --- a/pkg/hints/set_hints_test.go +++ b/pkg/hints/set_hints_test.go @@ -43,13 +43,13 @@ func TestSetAddElmInSet(t *testing.T) { t.Errorf("SET_ADD failed with error: %s", err) } - is_elm_in_set, err := idsManager.GetFelt("is_elm_in_set", vm) + isElmInSet, err := idsManager.GetFelt("is_elm_in_set", vm) if err != nil { t.Errorf("SET_ADD couldn't get is_elm_in_set: %s", err) } - if !is_elm_in_set.IsOne() { - t.Errorf("Expected is_elm_in_set to be 1, got: %s", is_elm_in_set.ToSignedFeltString()) + if !isElmInSet.IsOne() { + t.Errorf("Expected is_elm_in_set to be 1, got: %s", isElmInSet.ToSignedFeltString()) } index, err := idsManager.GetFelt("index", vm) @@ -93,12 +93,12 @@ func TestSetAddElmNotInSet(t *testing.T) { t.Errorf("SET_ADD failed with error: %s", err) } - is_elm_in_set, err := idsManager.GetFelt("is_elm_in_set", vm) + isElmInSet, err := idsManager.GetFelt("is_elm_in_set", vm) if err != nil { t.Errorf("SET_ADD couldn't get is_elm_in_set: %s", err) } - if !is_elm_in_set.IsZero() { - t.Errorf("Expected is_elm_in_set to be 1, got: %s", is_elm_in_set.ToSignedFeltString()) + if !isElmInSet.IsZero() { + t.Errorf("Expected is_elm_in_set to be 1, got: %s", isElmInSet.ToSignedFeltString()) } } From 65d35d124238697d5d83f8043628a149413b7edf Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Fri, 22 Sep 2023 10:39:13 -0300 Subject: [PATCH 13/13] Use get in memory GetRange --- pkg/vm/memory/memory.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/vm/memory/memory.go b/pkg/vm/memory/memory.go index a4b3659e..4939a8a0 100644 --- a/pkg/vm/memory/memory.go +++ b/pkg/vm/memory/memory.go @@ -154,11 +154,11 @@ func (m *Memory) GetFelt(addr Relocatable) (lambdaworks.Felt, error) { func (m *Memory) GetRange(start Relocatable, size uint) ([]MaybeRelocatable, error) { var res []MaybeRelocatable for i := uint(0); i < size; i++ { - val, ok := m.Data[start.AddUint(i)] - if !ok { - return nil, errors.Errorf("GetRange: cell %v is not present in Memory", start.AddUint(i)) + val, err := m.Get(start.AddUint(i)) + if err != nil { + return nil, err } - res = append(res, val) + res = append(res, *val) } return res, nil }