From 561d5c48068926cf6ac8bb22f6812ba4b1c51312 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 15:43:49 -0300 Subject: [PATCH 01/31] Add IdsManager.GetConst --- pkg/hints/hint_utils/ids_manager.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/pkg/hints/hint_utils/ids_manager.go b/pkg/hints/hint_utils/ids_manager.go index 06ed7d33..cab448df 100644 --- a/pkg/hints/hint_utils/ids_manager.go +++ b/pkg/hints/hint_utils/ids_manager.go @@ -12,8 +12,9 @@ import ( // Identifier Manager // Provides methods that allow hints to interact with cairo variables given their identifier name type IdsManager struct { - References map[string]HintReference - HintApTracking parser.ApTrackingData + References map[string]HintReference + HintApTracking parser.ApTrackingData + AccessibleScopes []string } func ErrIdsManager(err error) error { @@ -31,6 +32,17 @@ func NewIdsManager(references map[string]HintReference, hintApTracking parser.Ap } } +func (ids *IdsManager) GetConst(name string, constants *map[string]lambdaworks.Felt) (lambdaworks.Felt, error) { + // Accessible scopes are listed from outer to inner + for i := len(ids.AccessibleScopes) - 1; i >= 0; i-- { + constant, ok := (*constants)[ids.AccessibleScopes[i]+"."+name] + if ok { + return constant, nil + } + } + return lambdaworks.FeltZero(), nil +} + // Inserts value into memory given its identifier name func (ids *IdsManager) Insert(name string, value *MaybeRelocatable, vm *VirtualMachine) error { From e25c3f4999d69237333ab8f6c62ad02f50a94b8b Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 15:45:58 -0300 Subject: [PATCH 02/31] Integrate into logic --- pkg/hints/hint_processor.go | 2 +- pkg/hints/hint_utils/ids_manager.go | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index f31400f9..0041aa48 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -29,7 +29,7 @@ func (p *CairoVmHintProcessor) CompileHint(hintParams *parser.HintParams, refere name = split[len(split)-1] references[name] = ParseHintReference(referenceManager.References[n]) } - ids := NewIdsManager(references, hintParams.FlowTrackingData.APTracking) + ids := NewIdsManager(references, hintParams.FlowTrackingData.APTracking, AccesibleScopes: hintParams.AccessibleScopes) return HintData{Ids: ids, Code: hintParams.Code}, nil } diff --git a/pkg/hints/hint_utils/ids_manager.go b/pkg/hints/hint_utils/ids_manager.go index cab448df..0a5cdb48 100644 --- a/pkg/hints/hint_utils/ids_manager.go +++ b/pkg/hints/hint_utils/ids_manager.go @@ -25,10 +25,11 @@ func ErrUnknownIdentifier(name string) error { return ErrIdsManager(errors.Errorf("Unknow identifier %s", name)) } -func NewIdsManager(references map[string]HintReference, hintApTracking parser.ApTrackingData) IdsManager { +func NewIdsManager(references map[string]HintReference, hintApTracking parser.ApTrackingData, accessibleScopes []string) IdsManager { return IdsManager{ - References: references, - HintApTracking: hintApTracking, + References: references, + HintApTracking: hintApTracking, + AccessibleScopes: accessibleScopes, } } From 303b2b9c2ff5300bfd5c2ef2607e7eba72b93caf Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Mon, 18 Sep 2023 15:51:16 -0300 Subject: [PATCH 03/31] [WIP] Assert 250 Bits and SPLIT_FELT --- .../assert_250_bit_element_array.cairo | 31 ++++++++++ pkg/hints/hint_processor.go | 2 + pkg/hints/hint_utils/hint_utils.go | 23 ++++++++ pkg/hints/math_hint_codes.go | 2 + pkg/hints/math_hints.go | 56 +++++++++++++++++++ pkg/vm/cairo_run/cairo_run_test.go | 8 +++ pkg/vm/program.go | 2 +- pkg/vm/program_test.go | 4 +- 8 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 cairo_programs/assert_250_bit_element_array.cairo create mode 100644 pkg/hints/hint_utils/hint_utils.go diff --git a/cairo_programs/assert_250_bit_element_array.cairo b/cairo_programs/assert_250_bit_element_array.cairo new file mode 100644 index 00000000..b4307e26 --- /dev/null +++ b/cairo_programs/assert_250_bit_element_array.cairo @@ -0,0 +1,31 @@ +%builtins range_check + +from starkware.cairo.common.math import assert_250_bit +from starkware.cairo.common.alloc import alloc + +func assert_250_bit_element_array{range_check_ptr: felt}( + array: felt*, array_length: felt, iterator: felt +) { + if (iterator == array_length) { + return (); + } + assert_250_bit(array[iterator]); + return assert_250_bit_element_array(array, array_length, iterator + 1); +} + +func fill_array(array: felt*, base: felt, step: felt, array_length: felt, iterator: felt) { + if (iterator == array_length) { + return (); + } + assert array[iterator] = base + step * iterator; + return fill_array(array, base, step, array_length, iterator + 1); +} + +func main{range_check_ptr: felt}() { + alloc_locals; + tempvar array_length = 10; + let (array: felt*) = alloc(); + fill_array(array, 70000000000000000000, 300000000000000000, array_length, 0); + assert_250_bit_element_array(array, array_length, 0); + return (); +} diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index f31400f9..9ef4b5fe 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -69,6 +69,8 @@ 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 ASSERT_250_BITS: + return Assert250Bit(data.Ids, vm, constants) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/hint_utils/hint_utils.go b/pkg/hints/hint_utils/hint_utils.go new file mode 100644 index 00000000..41340eaf --- /dev/null +++ b/pkg/hints/hint_utils/hint_utils.go @@ -0,0 +1,23 @@ +package hint_utils + +import ( + "strings" + + . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + "github.com/pkg/errors" +) + +func GetConstantFromVarName(name string, constants *map[string]Felt) (Felt, error) { + if constants == nil { + return Felt{}, errors.Errorf("Caled GetConstantFromVarName with a nil constants map. Var Name: %s", name) + } + + for key, value := range *constants { + keySplit := strings.Split(key, ".") + if keySplit[len(keySplit)-1] == name { + return value, nil + } + } + + return Felt{}, errors.Errorf("Variable name not found in constants map. Var Name: %s", name) +} diff --git a/pkg/hints/math_hint_codes.go b/pkg/hints/math_hint_codes.go index 553bcde1..ab8c6b34 100644 --- a/pkg/hints/math_hint_codes.go +++ b/pkg/hints/math_hint_codes.go @@ -18,3 +18,5 @@ else: const ASSERT_NOT_EQUAL = "from starkware.cairo.lang.vm.relocatable import RelocatableValue\nboth_ints = isinstance(ids.a, int) and isinstance(ids.b, int)\nboth_relocatable = (\n isinstance(ids.a, RelocatableValue) and isinstance(ids.b, RelocatableValue) and\n ids.a.segment_index == ids.b.segment_index)\nassert both_ints or both_relocatable, \\\n f'assert_not_equal failed: non-comparable values: {ids.a}, {ids.b}.'\nassert (ids.a - ids.b) % PRIME != 0, f'assert_not_equal failed: {ids.a} = {ids.b}.'" const SQRT = "from starkware.python.math_utils import isqrt\nvalue = ids.value % PRIME\nassert value < 2 ** 250, f\"value={value} is outside of the range [0, 2**250).\"\nassert 2 ** 250 < PRIME\nids.root = isqrt(value)" + +const ASSERT_250_BITS = "from starkware.cairo.common.math_utils import as_int\n\n# Correctness check.\nvalue = as_int(ids.value, PRIME) % PRIME\nassert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**250).'\n\n# Calculation for the assertion.\nids.high, ids.low = divmod(ids.value, ids.SHIFT)" diff --git a/pkg/hints/math_hints.go b/pkg/hints/math_hints.go index c56c0a18..f492fa8f 100644 --- a/pkg/hints/math_hints.go +++ b/pkg/hints/math_hints.go @@ -151,3 +151,59 @@ func sqrt(ids IdsManager, vm *VirtualMachine) error { ids.Insert("root", NewMaybeRelocatableFelt(root_felt), vm) return nil } + +// Implements hint: +// +// from starkware.cairo.common.math_utils import as_int +// # Correctness check. +// value = as_int(ids.value, PRIME) % PRIME +// assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**250).' +// # Calculation for the assertion. +// ids.high, ids.low = divmod(ids.value, ids.SHIFT) +func Assert250Bit(ids IdsManager, vm *VirtualMachine, constants *map[string]Felt) error { + const UPPER_BOUND = "starkware.cairo.common.math.assert_250_bit.UPPER_BOUND" + const SHIFT = "starkware.cairo.common.math.assert_250_bit.SHIFT" + + if constants == nil { + return errors.New("Called Assert250Bit with a nil constants map") + } + + upperBound, ok := (*constants)[UPPER_BOUND] + + if !ok { + var err error + upperBound, err = GetConstantFromVarName(UPPER_BOUND, constants) + + if err != nil { + return err + } + } + + shift, ok := (*constants)[SHIFT] + + if !ok { + var err error + shift, err = GetConstantFromVarName(SHIFT, constants) + + if err != nil { + return err + } + } + + value, err := ids.GetFelt("value", vm) + + if err != nil { + return err + } + + if Felt.Cmp(value, upperBound) == 1 { + return errors.New("Value outside of 250 bit Range") + } + + high, low := value.DivRem(shift) + + ids.Insert("high", NewMaybeRelocatableFelt(high), vm) + ids.Insert("low", NewMaybeRelocatableFelt(low), vm) + + return nil +} diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index 3182e252..b6ce4ade 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -202,3 +202,11 @@ func TestSqrtHint(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) + if err != nil { + t.Errorf("Program execution failed with error: %s", err) + } +} diff --git a/pkg/vm/program.go b/pkg/vm/program.go index 125860fb..b72707ee 100644 --- a/pkg/vm/program.go +++ b/pkg/vm/program.go @@ -64,7 +64,7 @@ func DeserializeProgramJson(compiledProgram parser.CompiledJson) Program { func (p *Program) ExtractConstants() map[string]lambdaworks.Felt { constants := make(map[string]lambdaworks.Felt) for name, identifier := range p.Identifiers { - if identifier.Type == "constant" { + if identifier.Type == "const" { constants[name] = identifier.Value } } diff --git a/pkg/vm/program_test.go b/pkg/vm/program_test.go index 95371ce6..bf8d4fff 100644 --- a/pkg/vm/program_test.go +++ b/pkg/vm/program_test.go @@ -34,11 +34,11 @@ func TestExtractConstants(t *testing.T) { }, "A": { Value: lambdaworks.FeltFromUint64(7), - Type: "constant", + Type: "const", }, "B": { Value: lambdaworks.FeltFromUint64(17), - Type: "constant", + Type: "const", }, }, } From 8ad2c3ad248e22d7c7144d88e3b97576b91fad54 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 15:57:21 -0300 Subject: [PATCH 04/31] Add utils to help with fetching constants --- pkg/hints/hint_processor.go | 2 +- pkg/hints/hint_utils/ids_manager.go | 2 +- pkg/hints/hint_utils/ids_manager_test.go | 52 ++++++++++++++++++++++++ pkg/hints/hint_utils/testing_utils.go | 9 +++- 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 0041aa48..cf8181a6 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -29,7 +29,7 @@ func (p *CairoVmHintProcessor) CompileHint(hintParams *parser.HintParams, refere name = split[len(split)-1] references[name] = ParseHintReference(referenceManager.References[n]) } - ids := NewIdsManager(references, hintParams.FlowTrackingData.APTracking, AccesibleScopes: hintParams.AccessibleScopes) + ids := NewIdsManager(references, hintParams.FlowTrackingData.APTracking, hintParams.AccessibleScopes) return HintData{Ids: ids, Code: hintParams.Code}, nil } diff --git a/pkg/hints/hint_utils/ids_manager.go b/pkg/hints/hint_utils/ids_manager.go index 0a5cdb48..03748b1c 100644 --- a/pkg/hints/hint_utils/ids_manager.go +++ b/pkg/hints/hint_utils/ids_manager.go @@ -41,7 +41,7 @@ func (ids *IdsManager) GetConst(name string, constants *map[string]lambdaworks.F return constant, nil } } - return lambdaworks.FeltZero(), nil + return lambdaworks.FeltZero(), errors.Errorf("Missing constant %s", name) } // Inserts value into memory given its identifier name diff --git a/pkg/hints/hint_utils/ids_manager_test.go b/pkg/hints/hint_utils/ids_manager_test.go index 6fd3f234..5dc69b12 100644 --- a/pkg/hints/hint_utils/ids_manager_test.go +++ b/pkg/hints/hint_utils/ids_manager_test.go @@ -285,3 +285,55 @@ func TestIdsManagerGetStructFieldTest(t *testing.T) { t.Errorf("IdsManager.GetStructFieldFelt returned wrong values") } } + +func TestIdsManagerGetConst(t *testing.T) { + ids := IdsManager{ + AccessibleScopes: []string{ + "starkware.cairo.common.math", + "starkware.cairo.common.math.assert_250_bit", + }, + } + upperBound := lambdaworks.FeltFromUint64(250) + constants := map[string]lambdaworks.Felt{ + "starkware.cairo.common.math.assert_250_bit.UPPER_BOUND": upperBound, + } + constant, err := ids.GetConst("UPPER_BOUND", &constants) + if err != nil || constant != upperBound { + t.Errorf("IdsManager.GetConst returned wrong/no constant") + } +} + +func TestIdsManagerGetConstPrioritizeInnerModule(t *testing.T) { + ids := IdsManager{ + AccessibleScopes: []string{ + "starkware.cairo.common.math", + "starkware.cairo.common.math.assert_250_bit", + }, + } + upperBound := lambdaworks.FeltFromUint64(250) + constants := map[string]lambdaworks.Felt{ + "starkware.cairo.common.math.assert_250_bit.UPPER_BOUND": upperBound, + "starkware.cairo.common.math.UPPER_BOUND": lambdaworks.FeltZero(), + } + constant, err := ids.GetConst("UPPER_BOUND", &constants) + if err != nil || constant != upperBound { + t.Errorf("IdsManager.GetConst returned wrong/no constant") + } +} + +func TestIdsManagerGetConstNoMConst(t *testing.T) { + ids := IdsManager{ + AccessibleScopes: []string{ + "starkware.cairo.common.math", + "starkware.cairo.common.math.assert_250_bit", + }, + } + lowerBound := lambdaworks.FeltFromUint64(250) + constants := map[string]lambdaworks.Felt{ + "starkware.cairo.common.math.assert_250_bit.LOWER_BOUND": lowerBound, + } + _, err := ids.GetConst("UPPER_BOUND", &constants) + if err == nil { + t.Errorf("IdsManager.GetConst should have failed") + } +} diff --git a/pkg/hints/hint_utils/testing_utils.go b/pkg/hints/hint_utils/testing_utils.go index ab2470cd..547008b8 100644 --- a/pkg/hints/hint_utils/testing_utils.go +++ b/pkg/hints/hint_utils/testing_utils.go @@ -1,6 +1,7 @@ package hint_utils import ( + "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" "github.com/lambdaclass/cairo-vm.go/pkg/parser" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" @@ -17,7 +18,7 @@ import ( // All references will be FP-based, so please don't update the value of FP after calling this function, // and make sure that the memory at fp's segment is clear from its current offset onwards func SetupIdsForTest(ids map[string][]*memory.MaybeRelocatable, vm *VirtualMachine) IdsManager { - manager := NewIdsManager(make(map[string]HintReference), parser.ApTrackingData{}) + manager := NewIdsManager(make(map[string]HintReference), parser.ApTrackingData{}, []string{}) base_addr := vm.RunContext.Fp current_offset := 0 for name, elems := range ids { @@ -43,3 +44,9 @@ func SetupIdsForTest(ids map[string][]*memory.MaybeRelocatable, vm *VirtualMachi } return manager } + +func AddConstantForTest(name string, value lambdaworks.Felt, ids IdsManager, constants *map[string]lambdaworks.Felt) { + ids.AccessibleScopes = append(ids.AccessibleScopes, "path") + (*constants)["path."+name] = value + +} From 53e6b7639f60b2c75bca86a3adc98eb222a61b5e Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 16:05:10 -0300 Subject: [PATCH 05/31] Add SetupConstantsForTest --- pkg/hints/hint_utils/testing_utils.go | 9 ++++++--- pkg/hints/hint_utils/testing_utils_test.go | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/pkg/hints/hint_utils/testing_utils.go b/pkg/hints/hint_utils/testing_utils.go index 547008b8..9d9be754 100644 --- a/pkg/hints/hint_utils/testing_utils.go +++ b/pkg/hints/hint_utils/testing_utils.go @@ -45,8 +45,11 @@ func SetupIdsForTest(ids map[string][]*memory.MaybeRelocatable, vm *VirtualMachi return manager } -func AddConstantForTest(name string, value lambdaworks.Felt, ids IdsManager, constants *map[string]lambdaworks.Felt) { +func SetupConstantsForTest(new_constants map[string]lambdaworks.Felt, ids IdsManager) map[string]lambdaworks.Felt { + constants := make(map[string]lambdaworks.Felt) ids.AccessibleScopes = append(ids.AccessibleScopes, "path") - (*constants)["path."+name] = value - + for name, constant := range new_constants { + constants["path."+name] = constant + } + return constants } diff --git a/pkg/hints/hint_utils/testing_utils_test.go b/pkg/hints/hint_utils/testing_utils_test.go index a9c19945..34e94990 100644 --- a/pkg/hints/hint_utils/testing_utils_test.go +++ b/pkg/hints/hint_utils/testing_utils_test.go @@ -108,3 +108,24 @@ func TestSetupIdsForTestStructWithGap(t *testing.T) { t.Error("Failed to insert ids") } } + +func TestSetupConstantsForTest(t *testing.T) { + constA := FeltOne() + constB := FeltZero() + IdsManager := IdsManager{} + constants := SetupConstantsForTest(map[string]Felt{ + "A": constA, + "B": constB, + }, + IdsManager, + ) + // Check that we can fetch the constants + a, err := IdsManager.GetConst("A", &constants) + if err != nil || a != constA { + t.Error("SetupConstantsForTest wrong/no A") + } + b, err := IdsManager.GetConst("B", &constants) + if err != nil || b != constB { + t.Error("SetupConstantsForTest wrong/no B") + } +} From 34cc455db7b4a4810fef2c7c09e3ecee621c5b73 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 16:07:17 -0300 Subject: [PATCH 06/31] Add comments --- pkg/hints/hint_utils/ids_manager.go | 2 ++ pkg/hints/hint_utils/testing_utils.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/pkg/hints/hint_utils/ids_manager.go b/pkg/hints/hint_utils/ids_manager.go index 03748b1c..12f48387 100644 --- a/pkg/hints/hint_utils/ids_manager.go +++ b/pkg/hints/hint_utils/ids_manager.go @@ -33,6 +33,8 @@ func NewIdsManager(references map[string]HintReference, hintApTracking parser.Ap } } +// Fetches a constant used by the hint +// Searches inner modules first for name-matching constants func (ids *IdsManager) GetConst(name string, constants *map[string]lambdaworks.Felt) (lambdaworks.Felt, error) { // Accessible scopes are listed from outer to inner for i := len(ids.AccessibleScopes) - 1; i >= 0; i-- { diff --git a/pkg/hints/hint_utils/testing_utils.go b/pkg/hints/hint_utils/testing_utils.go index 9d9be754..cc5e86a2 100644 --- a/pkg/hints/hint_utils/testing_utils.go +++ b/pkg/hints/hint_utils/testing_utils.go @@ -45,6 +45,8 @@ func SetupIdsForTest(ids map[string][]*memory.MaybeRelocatable, vm *VirtualMachi return manager } +// Returns a constants map accoring to the new_constants map receives +// Adds a path to each constant and a matching path to the hint's accessible scopes func SetupConstantsForTest(new_constants map[string]lambdaworks.Felt, ids IdsManager) map[string]lambdaworks.Felt { constants := make(map[string]lambdaworks.Felt) ids.AccessibleScopes = append(ids.AccessibleScopes, "path") From 164820a534d4a6f9806878e3da7abbfd157a25c3 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 16:09:31 -0300 Subject: [PATCH 07/31] Guard error case --- pkg/hints/hint_utils/ids_manager.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pkg/hints/hint_utils/ids_manager.go b/pkg/hints/hint_utils/ids_manager.go index 12f48387..f883ac5c 100644 --- a/pkg/hints/hint_utils/ids_manager.go +++ b/pkg/hints/hint_utils/ids_manager.go @@ -36,11 +36,14 @@ func NewIdsManager(references map[string]HintReference, hintApTracking parser.Ap // Fetches a constant used by the hint // Searches inner modules first for name-matching constants func (ids *IdsManager) GetConst(name string, constants *map[string]lambdaworks.Felt) (lambdaworks.Felt, error) { - // Accessible scopes are listed from outer to inner - for i := len(ids.AccessibleScopes) - 1; i >= 0; i-- { - constant, ok := (*constants)[ids.AccessibleScopes[i]+"."+name] - if ok { - return constant, nil + // Hints should always have accessible scopes + if len(ids.AccessibleScopes) != 0 { + // Accessible scopes are listed from outer to inner + for i := len(ids.AccessibleScopes) - 1; i >= 0; i-- { + constant, ok := (*constants)[ids.AccessibleScopes[i]+"."+name] + if ok { + return constant, nil + } } } return lambdaworks.FeltZero(), errors.Errorf("Missing constant %s", name) From fc09cd540f80a7c34905f61b52434d77b11be63c Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Mon, 18 Sep 2023 16:13:35 -0300 Subject: [PATCH 08/31] Add tests for ASSERT_250_BIT --- pkg/hints/math_hints.go | 4 +- pkg/hints/math_hints_test.go | 75 ++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/pkg/hints/math_hints.go b/pkg/hints/math_hints.go index f492fa8f..2d5579ad 100644 --- a/pkg/hints/math_hints.go +++ b/pkg/hints/math_hints.go @@ -172,7 +172,7 @@ func Assert250Bit(ids IdsManager, vm *VirtualMachine, constants *map[string]Felt if !ok { var err error - upperBound, err = GetConstantFromVarName(UPPER_BOUND, constants) + upperBound, err = GetConstantFromVarName("UPPER_BOUND", constants) if err != nil { return err @@ -183,7 +183,7 @@ func Assert250Bit(ids IdsManager, vm *VirtualMachine, constants *map[string]Felt if !ok { var err error - shift, err = GetConstantFromVarName(SHIFT, constants) + shift, err = GetConstantFromVarName("SHIFT", constants) if err != nil { return err diff --git a/pkg/hints/math_hints_test.go b/pkg/hints/math_hints_test.go index 5dbd4e6a..ed0dc0e8 100644 --- a/pkg/hints/math_hints_test.go +++ b/pkg/hints/math_hints_test.go @@ -5,6 +5,7 @@ import ( . "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/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" @@ -316,3 +317,77 @@ func TestSqrtOk(t *testing.T) { t.Errorf("Expected sqrt(9) == 3. Got: %v", root) } } + +func TestAssert250BitHintSuccess(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "value": {NewMaybeRelocatableFelt(FeltFromUint64(3))}, + "high": {nil}, + "low": {nil}, + }, + vm, + ) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: ASSERT_250_BITS, + }) + + constants := make(map[string]Felt) + constants["UPPER_BOUND"] = lambdaworks.FeltFromUint64(10) + constants["SHIFT"] = lambdaworks.FeltFromUint64(1) + + err := hintProcessor.ExecuteHint(vm, &hintData, &constants, nil) + if err != nil { + t.Errorf("ASSERT_250_BIT hint failed with error %s", err) + } + + high, err := idsManager.GetFelt("high", vm) + if err != nil { + t.Errorf("failed to get high: %s", err) + } + + low, err := idsManager.GetFelt("low", vm) + if err != nil { + t.Errorf("failed to get low: %s", err) + } + + if high != FeltFromUint64(3) { + t.Errorf("Expected high == 3. Got: %v", high) + } + + if low != FeltFromUint64(0) { + t.Errorf("Expected low == 0. Got: %v", low) + } +} + +func TestAssert250BitHintFail(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "value": {NewMaybeRelocatableFelt(FeltFromUint64(20))}, + "high": {nil}, + "low": {nil}, + }, + vm, + ) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: ASSERT_250_BITS, + }) + + constants := make(map[string]Felt) + constants["UPPER_BOUND"] = lambdaworks.FeltFromUint64(10) + constants["SHIFT"] = lambdaworks.FeltFromUint64(1) + + err := hintProcessor.ExecuteHint(vm, &hintData, &constants, nil) + if err == nil { + t.Errorf("ASSERT_250_BIT hint should have failed with Value outside of 250 bit error") + } +} From e529897206b9eff175c221057e2b6dedc8065daa Mon Sep 17 00:00:00 2001 From: fmoletta <99273364+fmoletta@users.noreply.github.com> Date: Mon, 18 Sep 2023 16:16:13 -0300 Subject: [PATCH 09/31] Fix typo --- pkg/hints/hint_utils/testing_utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/hints/hint_utils/testing_utils.go b/pkg/hints/hint_utils/testing_utils.go index cc5e86a2..472fcc9c 100644 --- a/pkg/hints/hint_utils/testing_utils.go +++ b/pkg/hints/hint_utils/testing_utils.go @@ -45,7 +45,7 @@ func SetupIdsForTest(ids map[string][]*memory.MaybeRelocatable, vm *VirtualMachi return manager } -// Returns a constants map accoring to the new_constants map receives +// Returns a constants map accoring to the new_constants map received // Adds a path to each constant and a matching path to the hint's accessible scopes func SetupConstantsForTest(new_constants map[string]lambdaworks.Felt, ids IdsManager) map[string]lambdaworks.Felt { constants := make(map[string]lambdaworks.Felt) From 543962062361b320069de098c9abe11d209a7dc2 Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Mon, 18 Sep 2023 16:38:08 -0300 Subject: [PATCH 10/31] Implement SPLIT_FELT --- cairo_programs/split_felt.cairo | 42 +++++++++++++++ pkg/hints/hint_processor.go | 2 + pkg/hints/math_hint_codes.go | 2 + pkg/hints/math_hints.go | 63 +++++++++++++++++++++- pkg/lambdaworks/lib/lambdaworks/src/lib.rs | 2 +- pkg/vm/cairo_run/cairo_run_test.go | 8 +++ 6 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 cairo_programs/split_felt.cairo diff --git a/cairo_programs/split_felt.cairo b/cairo_programs/split_felt.cairo new file mode 100644 index 00000000..3790297d --- /dev/null +++ b/cairo_programs/split_felt.cairo @@ -0,0 +1,42 @@ +%builtins range_check + +from starkware.cairo.common.math import assert_le +from starkware.cairo.common.math import split_felt + +func split_felt_manual_implemetation{range_check_ptr}(value) -> (high: felt, low: felt) { + // Note: the following code works because PRIME - 1 is divisible by 2**128. + const MAX_HIGH = (-1) / 2 ** 128; + const MAX_LOW = 0; + + // Guess the low and high parts of the integer. + let low = [range_check_ptr]; + let high = [range_check_ptr + 1]; + let range_check_ptr = range_check_ptr + 2; + + %{ + from starkware.cairo.common.math_utils import assert_integer + assert ids.MAX_HIGH < 2**128 and ids.MAX_LOW < 2**128 + assert PRIME - 1 == ids.MAX_HIGH * 2**128 + ids.MAX_LOW + assert_integer(ids.value) + ids.low = ids.value & ((1 << 128) - 1) + ids.high = ids.value >> 128 + %} + + assert value = high * (2 ** 128) + low; + if (high == MAX_HIGH) { + assert_le(low, MAX_LOW); + } else { + assert_le(high, MAX_HIGH - 1); + } + return (high=high, low=low); +} + +func main{range_check_ptr: felt}() { + let (m, n) = split_felt_manual_implemetation(5784800237655953878877368326340059594760); + assert m = 17; + assert n = 8; + let (x, y) = split_felt(5784800237655953878877368326340059594760); + assert x = 17; + assert y = 8; + return (); +} diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 9ef4b5fe..62ec3a77 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -71,6 +71,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return vm_enter_scope(execScopes) case ASSERT_250_BITS: return Assert250Bit(data.Ids, vm, constants) + case SPLIT_FELT: + return SplitFelt(data.Ids, vm, constants) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/math_hint_codes.go b/pkg/hints/math_hint_codes.go index ab8c6b34..de36b808 100644 --- a/pkg/hints/math_hint_codes.go +++ b/pkg/hints/math_hint_codes.go @@ -20,3 +20,5 @@ const ASSERT_NOT_EQUAL = "from starkware.cairo.lang.vm.relocatable import Reloca const SQRT = "from starkware.python.math_utils import isqrt\nvalue = ids.value % PRIME\nassert value < 2 ** 250, f\"value={value} is outside of the range [0, 2**250).\"\nassert 2 ** 250 < PRIME\nids.root = isqrt(value)" const ASSERT_250_BITS = "from starkware.cairo.common.math_utils import as_int\n\n# Correctness check.\nvalue = as_int(ids.value, PRIME) % PRIME\nassert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**250).'\n\n# Calculation for the assertion.\nids.high, ids.low = divmod(ids.value, ids.SHIFT)" + +const SPLIT_FELT = "from starkware.cairo.common.math_utils import assert_integer\nassert ids.MAX_HIGH < 2**128 and ids.MAX_LOW < 2**128\nassert PRIME - 1 == ids.MAX_HIGH * 2**128 + ids.MAX_LOW\nassert_integer(ids.value)\nids.low = ids.value & ((1 << 128) - 1)\nids.high = ids.value >> 128" diff --git a/pkg/hints/math_hints.go b/pkg/hints/math_hints.go index 2d5579ad..fe124d2d 100644 --- a/pkg/hints/math_hints.go +++ b/pkg/hints/math_hints.go @@ -202,8 +202,67 @@ func Assert250Bit(ids IdsManager, vm *VirtualMachine, constants *map[string]Felt high, low := value.DivRem(shift) - ids.Insert("high", NewMaybeRelocatableFelt(high), vm) - ids.Insert("low", NewMaybeRelocatableFelt(low), vm) + err = ids.Insert("high", NewMaybeRelocatableFelt(high), vm) + if err != nil { + return err + } + + err = ids.Insert("low", NewMaybeRelocatableFelt(low), vm) + if err != nil { + return err + } + + return nil +} + + +// Implements hint: +// %{ +// from starkware.cairo.common.math_utils import assert_integer +// assert ids.MAX_HIGH < 2**128 and ids.MAX_LOW < 2**128 +// assert PRIME - 1 == ids.MAX_HIGH * 2**128 + ids.MAX_LOW +// assert_integer(ids.value) +// ids.low = ids.value & ((1 << 128) - 1) +// ids.high = ids.value >> 128 +// %} +func SplitFelt(ids IdsManager, vm *VirtualMachine, constants *map[string]Felt) error { + maxHigh, err := GetConstantFromVarName("MAX_HIGH", constants) + if err != nil { + return err + } + + maxLow, err := GetConstantFromVarName("MAX_LOW", constants) + if err != nil { + return err + } + + if maxHigh.Bits() > 128 || maxLow.Bits() > 128 { + return errors.New("Assertion Failed: assert ids.MAX_HIGH < 2**128 and ids.MAX_LOW < 2**128") + } + + + twoToTheOneTwentyEight := lambdaworks.FeltOne().Shl(128) + if lambdaworks.FeltFromDecString("-1") != maxHigh.Mul(twoToTheOneTwentyEight).Add(maxLow) { + return errors.New("Assertion Failed: assert PRIME - 1 == ids.MAX_HIGH * 2**128 + ids.MAX_LOW") + } + + value, err := ids.GetFelt("value", vm) + if err != nil { + return err + } + + low := value.And(twoToTheOneTwentyEight.Sub(lambdaworks.FeltOne())) + high := value.Shr(128) + + err = ids.Insert("high", NewMaybeRelocatableFelt(high), vm) + if err != nil { + return err + } + + err = ids.Insert("low", NewMaybeRelocatableFelt(low), vm) + if err != nil { + return err + } return nil } diff --git a/pkg/lambdaworks/lib/lambdaworks/src/lib.rs b/pkg/lambdaworks/lib/lambdaworks/src/lib.rs index 97c98c6e..b772d13d 100644 --- a/pkg/lambdaworks/lib/lambdaworks/src/lib.rs +++ b/pkg/lambdaworks/lib/lambdaworks/src/lib.rs @@ -257,7 +257,7 @@ pub unsafe extern "C" fn free_string(ptr: *mut c_char) { pub extern "C" fn felt_shr(a: Limbs, b: usize, result: Limbs) { let felt_a = limbs_to_felt(a).representative(); - let res = felt_a << b; + let res = felt_a >> b; felt_to_limbs(Felt::from(&res), result) } diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index b6ce4ade..c5985bc3 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -210,3 +210,11 @@ func TestAssert250BitHint(t *testing.T) { t.Errorf("Program execution failed with error: %s", err) } } + +func TestSplitFeltHint(t *testing.T) { + cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, Layout: "all_cairo", ProofMode: false} + _, err := cairo_run.CairoRun("../../../cairo_programs/split_felt.json", cairoRunConfig) + if err != nil { + t.Errorf("Program execution failed with error: %s", err) + } +} From 4b93d075087523ed1418aa7a0a4440f32c9ba67d Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 16:45:00 -0300 Subject: [PATCH 11/31] Fix util --- pkg/hints/hint_utils/testing_utils.go | 2 +- pkg/hints/hint_utils/testing_utils_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/hints/hint_utils/testing_utils.go b/pkg/hints/hint_utils/testing_utils.go index cc5e86a2..2d7d0a29 100644 --- a/pkg/hints/hint_utils/testing_utils.go +++ b/pkg/hints/hint_utils/testing_utils.go @@ -47,7 +47,7 @@ func SetupIdsForTest(ids map[string][]*memory.MaybeRelocatable, vm *VirtualMachi // Returns a constants map accoring to the new_constants map receives // Adds a path to each constant and a matching path to the hint's accessible scopes -func SetupConstantsForTest(new_constants map[string]lambdaworks.Felt, ids IdsManager) map[string]lambdaworks.Felt { +func SetupConstantsForTest(new_constants map[string]lambdaworks.Felt, ids *IdsManager) map[string]lambdaworks.Felt { constants := make(map[string]lambdaworks.Felt) ids.AccessibleScopes = append(ids.AccessibleScopes, "path") for name, constant := range new_constants { diff --git a/pkg/hints/hint_utils/testing_utils_test.go b/pkg/hints/hint_utils/testing_utils_test.go index 34e94990..4875a1a1 100644 --- a/pkg/hints/hint_utils/testing_utils_test.go +++ b/pkg/hints/hint_utils/testing_utils_test.go @@ -117,7 +117,7 @@ func TestSetupConstantsForTest(t *testing.T) { "A": constA, "B": constB, }, - IdsManager, + &IdsManager, ) // Check that we can fetch the constants a, err := IdsManager.GetConst("A", &constants) From 37c674a76cbedeff12bbf4238336b62ca89f1d66 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 16:49:10 -0300 Subject: [PATCH 12/31] Add hint code --- pkg/hints/math_hint_codes.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/hints/math_hint_codes.go b/pkg/hints/math_hint_codes.go index 553bcde1..2d93ebf9 100644 --- a/pkg/hints/math_hint_codes.go +++ b/pkg/hints/math_hint_codes.go @@ -18,3 +18,5 @@ else: const ASSERT_NOT_EQUAL = "from starkware.cairo.lang.vm.relocatable import RelocatableValue\nboth_ints = isinstance(ids.a, int) and isinstance(ids.b, int)\nboth_relocatable = (\n isinstance(ids.a, RelocatableValue) and isinstance(ids.b, RelocatableValue) and\n ids.a.segment_index == ids.b.segment_index)\nassert both_ints or both_relocatable, \\\n f'assert_not_equal failed: non-comparable values: {ids.a}, {ids.b}.'\nassert (ids.a - ids.b) % PRIME != 0, f'assert_not_equal failed: {ids.a} = {ids.b}.'" const SQRT = "from starkware.python.math_utils import isqrt\nvalue = ids.value % PRIME\nassert value < 2 ** 250, f\"value={value} is outside of the range [0, 2**250).\"\nassert 2 ** 250 < PRIME\nids.root = isqrt(value)" + +const ASSERT_LE_FELT = "import itertools\n\nfrom starkware.cairo.common.math_utils import assert_integer\nassert_integer(ids.a)\nassert_integer(ids.b)\na = ids.a % PRIME\nb = ids.b % PRIME\nassert a <= b, f'a = {a} is not less than or equal to b = {b}.'\n\n# Find an arc less than PRIME / 3, and another less than PRIME / 2.\nlengths_and_indices = [(a, 0), (b - a, 1), (PRIME - 1 - b, 2)]\nlengths_and_indices.sort()\nassert lengths_and_indices[0][0] <= PRIME // 3 and lengths_and_indices[1][0] <= PRIME // 2\nexcluded = lengths_and_indices[2][1]\n\nmemory[ids.range_check_ptr + 1], memory[ids.range_check_ptr + 0] = (\n divmod(lengths_and_indices[0][0], ids.PRIME_OVER_3_HIGH))\nmemory[ids.range_check_ptr + 3], memory[ids.range_check_ptr + 2] = (\n divmod(lengths_and_indices[1][0], ids.PRIME_OVER_2_HIGH))" From 9ddaeac237771b02a85cae579ec0622019ccf699 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 18:02:45 -0300 Subject: [PATCH 13/31] Implement FeltFromBigInt --- pkg/lambdaworks/lambdaworks.go | 8 ++++++++ pkg/lambdaworks/lambdaworks_test.go | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index e4ffd4b9..cd00deb8 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -283,6 +283,14 @@ func (f Felt) ToBigInt() *big.Int { return new(big.Int).SetBytes(f.ToBeBytes()[:32]) } +func FeltFromBigInt(n *big.Int) Felt { + bytes := n.Bytes() + println(bytes) + var bytes32 [32]byte + copy(bytes32[:], bytes) + return FeltFromLeBytes(&bytes32) +} + const CAIRO_PRIME_HEX = "0x800000000000011000000000000000000000000000000000000000000000001" const SIGNED_FELT_MAX_HEX = "0x400000000000008800000000000000000000000000000000000000000000000" diff --git a/pkg/lambdaworks/lambdaworks_test.go b/pkg/lambdaworks/lambdaworks_test.go index 8116378d..9b03f186 100644 --- a/pkg/lambdaworks/lambdaworks_test.go +++ b/pkg/lambdaworks/lambdaworks_test.go @@ -70,6 +70,14 @@ func TestToBigInt(t *testing.T) { } } +func TestFromBigInt(t *testing.T) { + expectedFelt := lambdaworks.FeltFromUint64(26) + bigInt := new(big.Int).SetUint64(26) + if !reflect.DeepEqual(lambdaworks.FeltFromBigInt(bigInt), expectedFelt) { + t.Errorf("TestToBigInt failed. Expected: %v, Got: %v", 26, lambdaworks.FeltFromBigInt(bigInt)) + } +} + func TestToSignedNegative(t *testing.T) { felt := lambdaworks.FeltFromDecString("-1") bigInt := felt.ToSigned() From 73703bcb811c921db8d5d63374fe456d02a6e03d Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 18:05:13 -0300 Subject: [PATCH 14/31] Implement ASSERT_LE_FELT hint --- pkg/hints/math_hints.go | 70 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/pkg/hints/math_hints.go b/pkg/hints/math_hints.go index c56c0a18..2c1461c0 100644 --- a/pkg/hints/math_hints.go +++ b/pkg/hints/math_hints.go @@ -1,11 +1,14 @@ package hints import ( + "math/big" + "github.com/lambdaclass/cairo-vm.go/pkg/builtins" . "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/math_utils" + . "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" @@ -151,3 +154,70 @@ func sqrt(ids IdsManager, vm *VirtualMachine) error { ids.Insert("root", NewMaybeRelocatableFelt(root_felt), vm) return nil } + +func assertLeFelt(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes, constants *map[string]Felt) error { + // Fetch constants + primeOver3HighFelt, err := ids.GetConst("PRIME_OVER_3_HIGH", constants) + if err != nil { + return err + } + primeOver3High := primeOver3HighFelt.ToBigInt() + primeOver2HighFelt, err := ids.GetConst("PRIME_OVER_2_HIGH", constants) + if err != nil { + return err + } + primeOver2High := primeOver2HighFelt.ToBigInt() + // Fetch ids variables + aFelt, err := ids.GetFelt("a", vm) + if err != nil { + return err + } + a := aFelt.ToBigInt() + bFelt, err := ids.GetFelt("b", vm) + if err != nil { + return err + } + b := bFelt.ToBigInt() + rangeCheckPtr, err := ids.GetRelocatable("range_check_ptr", vm) + if err != nil { + return err + } + cairoPrime, _ := new(big.Int).SetString(CAIRO_PRIME_HEX, 0) + halfPrime := new(big.Int).Div(cairoPrime, new(big.Int).SetUint64(2)) + thirdOfPrime := new(big.Int).Div(cairoPrime, new(big.Int).SetUint64(2)) + if a.Cmp(b) == 1 { + return errors.Errorf("Assertion failed, %v, is not less or equal to %v", a, b) + } + arc1 := new(big.Int).Sub(b, a) + arc2 := new(big.Int).Sub(new(big.Int).Sub(cairoPrime, (big.NewInt(1))), b) + + // Split lengthsAndIndices array into lenght & idxs array and mantain the same order between them + lengths := []*big.Int{a, arc1, arc2} + idxs := []int{0, 1, 2} + // Sort lengths & idxs by lengths + for i := 0; i < 3; i++ { + for j := i; j > 0 && lengths[j-1].Cmp(lengths[j]) == 1; j-- { + lengths[j], lengths[j-1] = lengths[j-1], lengths[j] + idxs[j], idxs[j-1] = idxs[j-1], idxs[j] + } + } + + if lengths[0].Cmp(thirdOfPrime) == 1 || lengths[1].Cmp(halfPrime) == 1 { + return errors.Errorf("Arc too big, %v must be <= %v and %v <= %v", lengths[0], thirdOfPrime, lengths[1], halfPrime) + } + excluded := idxs[2] + scopes.AssignOrUpdateVariable("excluded", excluded) + q_0, r_0 := new(big.Int).DivMod(lengths[0], primeOver3High, primeOver3High) + q_1, r_1 := new(big.Int).DivMod(lengths[1], primeOver2High, primeOver2High) + + // Insert values into range_check_ptr + data := []MaybeRelocatable{ + *NewMaybeRelocatableFelt(FeltFromBigInt(r_0)), + *NewMaybeRelocatableFelt(FeltFromBigInt(q_0)), + *NewMaybeRelocatableFelt(FeltFromBigInt(r_1)), + *NewMaybeRelocatableFelt(FeltFromBigInt(q_1)), + } + _, err = vm.Segments.LoadData(rangeCheckPtr, &data) + + return err +} From 6f7fe683c4a69a31e80b16b7a30aa4c96265ab67 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 18:07:51 -0300 Subject: [PATCH 15/31] Add comment --- pkg/hints/math_hints.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/hints/math_hints.go b/pkg/hints/math_hints.go index 2c1461c0..a377afd4 100644 --- a/pkg/hints/math_hints.go +++ b/pkg/hints/math_hints.go @@ -182,6 +182,7 @@ func assertLeFelt(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes, c if err != nil { return err } + // Hint Logic cairoPrime, _ := new(big.Int).SetString(CAIRO_PRIME_HEX, 0) halfPrime := new(big.Int).Div(cairoPrime, new(big.Int).SetUint64(2)) thirdOfPrime := new(big.Int).Div(cairoPrime, new(big.Int).SetUint64(2)) From a1c0625b24b9fe4f54fe33418d69e82a0707fbe9 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 18:17:37 -0300 Subject: [PATCH 16/31] Add test --- pkg/hints/hint_processor.go | 2 ++ pkg/hints/math_hints_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index cf8181a6..1cf69b58 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -69,6 +69,8 @@ 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 ASSERT_LE_FELT: + return assertLeFelt(data.Ids, vm, execScopes, constants) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/math_hints_test.go b/pkg/hints/math_hints_test.go index 5dbd4e6a..d8276b31 100644 --- a/pkg/hints/math_hints_test.go +++ b/pkg/hints/math_hints_test.go @@ -6,6 +6,7 @@ import ( . "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" ) @@ -316,3 +317,33 @@ func TestSqrtOk(t *testing.T) { t.Errorf("Expected sqrt(9) == 3. Got: %v", root) } } + +func TestAssertLeFeltOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + vm.Segments.AddSegment() + scopes := NewExecutionScopes() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "a": {NewMaybeRelocatableFelt(FeltOne())}, + "b": {NewMaybeRelocatableFelt(FeltFromUint64(2))}, + "range_check_ptr": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))}, + }, + vm, + ) + constants := SetupConstantsForTest(map[string]Felt{ + "PRIME_OVER_3_HIGH": FeltFromHex("4000000000000088000000000000001"), + "PRIME_OVER_2_HIGH": FeltFromHex("2AAAAAAAAAAAAB05555555555555556"), + }, + &idsManager, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: ASSERT_LE_FELT, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, &constants, scopes) + if err != nil { + t.Errorf("ASSERT_LE_FELT hint failed with error: %s", err) + } +} From a712b47651dea818986e373a4a2225566b7360b3 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 18:25:27 -0300 Subject: [PATCH 17/31] Add the 3 assert_le_felt_exclued hints --- pkg/hints/hint_processor.go | 6 +++++ pkg/hints/math_hint_codes.go | 6 +++++ pkg/hints/math_hints.go | 51 ++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 1cf69b58..9eff95b0 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -71,6 +71,12 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return vm_enter_scope(execScopes) case ASSERT_LE_FELT: return assertLeFelt(data.Ids, vm, execScopes, constants) + case ASSERT_LE_FELT_EXCLUDED_0: + return assertLeFeltExcluded0(vm, execScopes) + case ASSERT_LE_FELT_EXCLUDED_1: + return assertLeFeltExcluded1(vm, execScopes) + case ASSERT_LE_FELT_EXCLUDED_2: + return assertLeFeltExcluded2(vm, execScopes) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/math_hint_codes.go b/pkg/hints/math_hint_codes.go index 2d93ebf9..a3a47679 100644 --- a/pkg/hints/math_hint_codes.go +++ b/pkg/hints/math_hint_codes.go @@ -20,3 +20,9 @@ const ASSERT_NOT_EQUAL = "from starkware.cairo.lang.vm.relocatable import Reloca const SQRT = "from starkware.python.math_utils import isqrt\nvalue = ids.value % PRIME\nassert value < 2 ** 250, f\"value={value} is outside of the range [0, 2**250).\"\nassert 2 ** 250 < PRIME\nids.root = isqrt(value)" const ASSERT_LE_FELT = "import itertools\n\nfrom starkware.cairo.common.math_utils import assert_integer\nassert_integer(ids.a)\nassert_integer(ids.b)\na = ids.a % PRIME\nb = ids.b % PRIME\nassert a <= b, f'a = {a} is not less than or equal to b = {b}.'\n\n# Find an arc less than PRIME / 3, and another less than PRIME / 2.\nlengths_and_indices = [(a, 0), (b - a, 1), (PRIME - 1 - b, 2)]\nlengths_and_indices.sort()\nassert lengths_and_indices[0][0] <= PRIME // 3 and lengths_and_indices[1][0] <= PRIME // 2\nexcluded = lengths_and_indices[2][1]\n\nmemory[ids.range_check_ptr + 1], memory[ids.range_check_ptr + 0] = (\n divmod(lengths_and_indices[0][0], ids.PRIME_OVER_3_HIGH))\nmemory[ids.range_check_ptr + 3], memory[ids.range_check_ptr + 2] = (\n divmod(lengths_and_indices[1][0], ids.PRIME_OVER_2_HIGH))" + +const ASSERT_LE_FELT_EXCLUDED_0 = "memory[ap] = 1 if excluded != 0 else 0" + +const ASSERT_LE_FELT_EXCLUDED_1 = "memory[ap] = 1 if excluded != 1 else 0" + +const ASSERT_LE_FELT_EXCLUDED_2 = "assert excluded == 2" diff --git a/pkg/hints/math_hints.go b/pkg/hints/math_hints.go index a377afd4..ab731596 100644 --- a/pkg/hints/math_hints.go +++ b/pkg/hints/math_hints.go @@ -222,3 +222,54 @@ func assertLeFelt(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes, c return err } + +// "memory[ap] = 1 if excluded != 0 else 0" +func assertLeFeltExcluded0(vm *VirtualMachine, scopes *ExecutionScopes) error { + // Fetch scope var + excludedAny, err := scopes.Get("excluded") + if err != nil { + return err + } + excluded, ok := excludedAny.(int) + if !ok { + return errors.New("exluded not in scope") + } + if excluded == 0 { + return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltZero())) + } + return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltOne())) +} + +// "memory[ap] = 1 if excluded != 1 else 0" +func assertLeFeltExcluded1(vm *VirtualMachine, scopes *ExecutionScopes) error { + // Fetch scope var + excludedAny, err := scopes.Get("excluded") + if err != nil { + return err + } + excluded, ok := excludedAny.(int) + if !ok { + return errors.New("exluded not in scope") + } + if excluded == 1 { + return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltZero())) + } + return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltOne())) +} + +// "assert excluded == 2" +func assertLeFeltExcluded2(vm *VirtualMachine, scopes *ExecutionScopes) error { + // Fetch scope var + excludedAny, err := scopes.Get("excluded") + if err != nil { + return err + } + excluded, ok := excludedAny.(int) + if !ok { + return errors.New("exluded not in scope") + } + if excluded == 2 { + return errors.New("Assertion Failed: excluded == 2") + } + return nil +} From ad0cd1e64d44a33b4fec6ad95e1bd8c58f8e4860 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 18:35:23 -0300 Subject: [PATCH 18/31] Add tests --- pkg/hints/math_hints.go | 2 +- pkg/hints/math_hints_test.go | 110 +++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/pkg/hints/math_hints.go b/pkg/hints/math_hints.go index ab731596..c25b8d5a 100644 --- a/pkg/hints/math_hints.go +++ b/pkg/hints/math_hints.go @@ -268,7 +268,7 @@ func assertLeFeltExcluded2(vm *VirtualMachine, scopes *ExecutionScopes) error { if !ok { return errors.New("exluded not in scope") } - if excluded == 2 { + if excluded != 2 { return errors.New("Assertion Failed: excluded == 2") } return nil diff --git a/pkg/hints/math_hints_test.go b/pkg/hints/math_hints_test.go index d8276b31..d8d09c52 100644 --- a/pkg/hints/math_hints_test.go +++ b/pkg/hints/math_hints_test.go @@ -347,3 +347,113 @@ func TestAssertLeFeltOk(t *testing.T) { t.Errorf("ASSERT_LE_FELT hint failed with error: %s", err) } } + +func TestAssertLeFeltExcluded0Zero(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + scopes := NewExecutionScopes() + scopes.AssignOrUpdateVariable("excluded", int(0)) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Code: ASSERT_LE_FELT_EXCLUDED_0, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("ASSERT_LE_FELT_EXCLUDED_0 hint test failed with error %s", err) + } + // Check the value of memory[ap] + val, err := vm.Segments.Memory.GetFelt(vm.RunContext.Ap) + if err != nil || !val.IsZero() { + t.Error("Wrong/No value inserted into ap") + } +} + +func TestAssertLeFeltExcluded0One(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + scopes := NewExecutionScopes() + scopes.AssignOrUpdateVariable("excluded", int(1)) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Code: ASSERT_LE_FELT_EXCLUDED_0, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("ASSERT_LE_FELT_EXCLUDED_0 hint test failed with error %s", err) + } + // Check the value of memory[ap] + val, err := vm.Segments.Memory.GetFelt(vm.RunContext.Ap) + if err != nil || val != FeltOne() { + t.Error("Wrong/No value inserted into ap") + } +} + +func TestAssertLeFeltExcluded1Zero(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + scopes := NewExecutionScopes() + scopes.AssignOrUpdateVariable("excluded", int(1)) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Code: ASSERT_LE_FELT_EXCLUDED_1, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("ASSERT_LE_FELT_EXCLUDED_1 hint test failed with error %s", err) + } + // Check the value of memory[ap] + val, err := vm.Segments.Memory.GetFelt(vm.RunContext.Ap) + if err != nil || !val.IsZero() { + t.Error("Wrong/No value inserted into ap") + } +} + +func TestAssertLeFeltExcluded1One(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + scopes := NewExecutionScopes() + scopes.AssignOrUpdateVariable("excluded", int(0)) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Code: ASSERT_LE_FELT_EXCLUDED_1, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("ASSERT_LE_FELT_EXCLUDED_1 hint test failed with error %s", err) + } + // Check the value of memory[ap] + val, err := vm.Segments.Memory.GetFelt(vm.RunContext.Ap) + if err != nil || val != FeltOne() { + t.Error("Wrong/No value inserted into ap") + } +} + +func TestAssertLeFeltExcluded2Ok(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + scopes := NewExecutionScopes() + scopes.AssignOrUpdateVariable("excluded", int(2)) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Code: ASSERT_LE_FELT_EXCLUDED_2, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("ASSERT_LE_FELT_EXCLUDED_2 hint test failed with error %s", err) + } +} + +func TestAssertLeFeltExcluded2Err(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + scopes := NewExecutionScopes() + scopes.AssignOrUpdateVariable("excluded", int(0)) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Code: ASSERT_LE_FELT_EXCLUDED_2, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err == nil { + t.Errorf("ASSERT_LE_FELT_EXCLUDED_2 hint test should have failed") + } +} From df0ef467c9e46872c51aa6ab12a9046d8ee832a1 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 18:45:30 -0300 Subject: [PATCH 19/31] Fix identifier --- pkg/vm/program.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vm/program.go b/pkg/vm/program.go index 125860fb..b72707ee 100644 --- a/pkg/vm/program.go +++ b/pkg/vm/program.go @@ -64,7 +64,7 @@ func DeserializeProgramJson(compiledProgram parser.CompiledJson) Program { func (p *Program) ExtractConstants() map[string]lambdaworks.Felt { constants := make(map[string]lambdaworks.Felt) for name, identifier := range p.Identifiers { - if identifier.Type == "constant" { + if identifier.Type == "const" { constants[name] = identifier.Value } } From 1eabf940f324e7688eb5451c322e1a98b891dc10 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 18:46:46 -0300 Subject: [PATCH 20/31] Add integration test --- cairo_programs/assert_le_felt.cairo | 10 ++++++++++ pkg/vm/cairo_run/cairo_run_test.go | 8 ++++++++ 2 files changed, 18 insertions(+) create mode 100644 cairo_programs/assert_le_felt.cairo diff --git a/cairo_programs/assert_le_felt.cairo b/cairo_programs/assert_le_felt.cairo new file mode 100644 index 00000000..8282ac6f --- /dev/null +++ b/cairo_programs/assert_le_felt.cairo @@ -0,0 +1,10 @@ + +%builtins range_check +from starkware.cairo.common.math import assert_le_felt + +func main{range_check_ptr: felt}() { + assert_le_felt(1, 2); + assert_le_felt(-2, -1); + assert_le_felt(-1, 2); + return (); +} diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index 3182e252..35935c60 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -202,3 +202,11 @@ func TestSqrtHint(t *testing.T) { 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) + if err != nil { + t.Errorf("Program execution failed with error: %s", err) + } +} From 64b71649f846936279d192190bb6639947bb41ce Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 18:47:30 -0300 Subject: [PATCH 21/31] Fix type const in tests --- pkg/vm/program_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/vm/program_test.go b/pkg/vm/program_test.go index 95371ce6..bf8d4fff 100644 --- a/pkg/vm/program_test.go +++ b/pkg/vm/program_test.go @@ -34,11 +34,11 @@ func TestExtractConstants(t *testing.T) { }, "A": { Value: lambdaworks.FeltFromUint64(7), - Type: "constant", + Type: "const", }, "B": { Value: lambdaworks.FeltFromUint64(17), - Type: "constant", + Type: "const", }, }, } From a85c2c9c4a470b1ce05e3a405fd210932f005a4a Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 18:51:01 -0300 Subject: [PATCH 22/31] Fix typo --- pkg/hints/math_hints.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/hints/math_hints.go b/pkg/hints/math_hints.go index c25b8d5a..216b9ed5 100644 --- a/pkg/hints/math_hints.go +++ b/pkg/hints/math_hints.go @@ -232,7 +232,7 @@ func assertLeFeltExcluded0(vm *VirtualMachine, scopes *ExecutionScopes) error { } excluded, ok := excludedAny.(int) if !ok { - return errors.New("exluded not in scope") + return errors.New("excluded not in scope") } if excluded == 0 { return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltZero())) @@ -249,7 +249,7 @@ func assertLeFeltExcluded1(vm *VirtualMachine, scopes *ExecutionScopes) error { } excluded, ok := excludedAny.(int) if !ok { - return errors.New("exluded not in scope") + return errors.New("excluded not in scope") } if excluded == 1 { return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltZero())) @@ -266,7 +266,7 @@ func assertLeFeltExcluded2(vm *VirtualMachine, scopes *ExecutionScopes) error { } excluded, ok := excludedAny.(int) if !ok { - return errors.New("exluded not in scope") + return errors.New("excluded not in scope") } if excluded != 2 { return errors.New("Assertion Failed: excluded == 2") From f4a0cf25cea16f275039df73ebea7df8b8b00285 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 18:52:17 -0300 Subject: [PATCH 23/31] Fix test --- cairo_programs/assert_le_felt.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cairo_programs/assert_le_felt.cairo b/cairo_programs/assert_le_felt.cairo index 8282ac6f..df623734 100644 --- a/cairo_programs/assert_le_felt.cairo +++ b/cairo_programs/assert_le_felt.cairo @@ -5,6 +5,6 @@ from starkware.cairo.common.math import assert_le_felt func main{range_check_ptr: felt}() { assert_le_felt(1, 2); assert_le_felt(-2, -1); - assert_le_felt(-1, 2); + assert_le_felt(2, -1); return (); } From 03142ac788e6f172ddb559d282762debc1f66c76 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 18:53:08 -0300 Subject: [PATCH 24/31] Fix bug --- pkg/hints/math_hints.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/hints/math_hints.go b/pkg/hints/math_hints.go index 216b9ed5..2ab24bc4 100644 --- a/pkg/hints/math_hints.go +++ b/pkg/hints/math_hints.go @@ -185,7 +185,7 @@ func assertLeFelt(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes, c // Hint Logic cairoPrime, _ := new(big.Int).SetString(CAIRO_PRIME_HEX, 0) halfPrime := new(big.Int).Div(cairoPrime, new(big.Int).SetUint64(2)) - thirdOfPrime := new(big.Int).Div(cairoPrime, new(big.Int).SetUint64(2)) + thirdOfPrime := new(big.Int).Div(cairoPrime, new(big.Int).SetUint64(3)) if a.Cmp(b) == 1 { return errors.Errorf("Assertion failed, %v, is not less or equal to %v", a, b) } From 742d51e5aac183c4fd6e0be9e9d39c05ff5fa888 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 18:55:09 -0300 Subject: [PATCH 25/31] Remove debug print --- pkg/lambdaworks/lambdaworks.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index cd00deb8..f944eaeb 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -285,7 +285,6 @@ func (f Felt) ToBigInt() *big.Int { func FeltFromBigInt(n *big.Int) Felt { bytes := n.Bytes() - println(bytes) var bytes32 [32]byte copy(bytes32[:], bytes) return FeltFromLeBytes(&bytes32) From 8707c241949be9f44dfbd2cfc159e1f75e8cd512 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 19:03:46 -0300 Subject: [PATCH 26/31] Fix test name --- pkg/lambdaworks/lambdaworks.go | 5 +++++ pkg/lambdaworks/lambdaworks_test.go | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index f944eaeb..d66e7b24 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -284,6 +284,11 @@ func (f Felt) ToBigInt() *big.Int { } func FeltFromBigInt(n *big.Int) Felt { + // Perform modulo prime + prime, _ := new(big.Int).SetString(CAIRO_PRIME_HEX, 0) + if n.Cmp(prime) != -1 { + n = new(big.Int).Mod(n, prime) + } bytes := n.Bytes() var bytes32 [32]byte copy(bytes32[:], bytes) diff --git a/pkg/lambdaworks/lambdaworks_test.go b/pkg/lambdaworks/lambdaworks_test.go index 9b03f186..bffb7e7a 100644 --- a/pkg/lambdaworks/lambdaworks_test.go +++ b/pkg/lambdaworks/lambdaworks_test.go @@ -78,6 +78,14 @@ func TestFromBigInt(t *testing.T) { } } +func TestFromBigIntPrime(t *testing.T) { + expectedFelt := lambdaworks.FeltFromDecString("0") + bigInt, _ := new(big.Int).SetString(lambdaworks.CAIRO_PRIME_HEX, 0) + if !reflect.DeepEqual(lambdaworks.FeltFromBigInt(bigInt), expectedFelt) { + t.Errorf("TestToBigInt failed. Expected: PRIME, Got: %v", lambdaworks.FeltFromBigInt(bigInt)) + } +} + func TestToSignedNegative(t *testing.T) { felt := lambdaworks.FeltFromDecString("-1") bigInt := felt.ToSigned() From 789fce2bed2be8e9b24e644cf6462dab703c1bff Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 19 Sep 2023 11:08:56 -0300 Subject: [PATCH 27/31] Add hint + unit tests --- pkg/hints/hint_processor.go | 2 ++ pkg/hints/math_hint_codes.go | 2 ++ pkg/hints/math_hints.go | 16 ++++++++++++++ pkg/hints/math_hints_test.go | 42 ++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+) diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 9eff95b0..2b222969 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -77,6 +77,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return assertLeFeltExcluded1(vm, execScopes) case ASSERT_LE_FELT_EXCLUDED_2: return assertLeFeltExcluded2(vm, execScopes) + case ASSERT_LT_FELT: + return assertLtFelt(data.Ids, vm) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/math_hint_codes.go b/pkg/hints/math_hint_codes.go index a3a47679..623a8e90 100644 --- a/pkg/hints/math_hint_codes.go +++ b/pkg/hints/math_hint_codes.go @@ -26,3 +26,5 @@ const ASSERT_LE_FELT_EXCLUDED_0 = "memory[ap] = 1 if excluded != 0 else 0" const ASSERT_LE_FELT_EXCLUDED_1 = "memory[ap] = 1 if excluded != 1 else 0" const ASSERT_LE_FELT_EXCLUDED_2 = "assert excluded == 2" + +const ASSERT_LT_FELT = "from starkware.cairo.common.math_utils import assert_integer\nassert_integer(ids.a)\nassert_integer(ids.b)\nassert (ids.a % PRIME) < (ids.b % PRIME), \\\n f'a = {ids.a % PRIME} is not less than b = {ids.b % PRIME}.'" diff --git a/pkg/hints/math_hints.go b/pkg/hints/math_hints.go index 2ab24bc4..f2fb2450 100644 --- a/pkg/hints/math_hints.go +++ b/pkg/hints/math_hints.go @@ -273,3 +273,19 @@ func assertLeFeltExcluded2(vm *VirtualMachine, scopes *ExecutionScopes) error { } return nil } + +func assertLtFelt(ids IdsManager, vm *VirtualMachine) error { + // Fetch ids variables + a, err := ids.GetFelt("a", vm) + if err != nil { + return err + } + b, err := ids.GetFelt("b", vm) + if err != nil { + return err + } + if a.Cmp(b) != -1 { + return errors.Errorf("Assertion failed, a = %s %% PRIME is not less than b = %s %% PRIME", a.ToHexString(), b.ToHexString()) + } + return nil +} diff --git a/pkg/hints/math_hints_test.go b/pkg/hints/math_hints_test.go index d8d09c52..43aa090d 100644 --- a/pkg/hints/math_hints_test.go +++ b/pkg/hints/math_hints_test.go @@ -457,3 +457,45 @@ func TestAssertLeFeltExcluded2Err(t *testing.T) { t.Errorf("ASSERT_LE_FELT_EXCLUDED_2 hint test should have failed") } } + +func TestAssertLeFeltHintOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "a": {NewMaybeRelocatableFelt(FeltFromUint64(17))}, + "b": {NewMaybeRelocatableFelt(FeltFromUint64(18))}, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: ASSERT_LT_FELT, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("ASSERT_LT_FELT hint test failed with error %s", err) + } +} + +func TestAssertLeFeltHintErr(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "a": {NewMaybeRelocatableFelt(FeltFromUint64(17))}, + "b": {NewMaybeRelocatableFelt(FeltFromUint64(16))}, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: ASSERT_LT_FELT, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("ASSERT_LT_FELT hint test should have failed") + } +} From c10798a60930ef8aa34aaadf57db3179c8a4fccb Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 19 Sep 2023 11:15:01 -0300 Subject: [PATCH 28/31] Fix test --- pkg/hints/math_hints_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/hints/math_hints_test.go b/pkg/hints/math_hints_test.go index 43aa090d..50e8d47b 100644 --- a/pkg/hints/math_hints_test.go +++ b/pkg/hints/math_hints_test.go @@ -495,7 +495,7 @@ func TestAssertLeFeltHintErr(t *testing.T) { Code: ASSERT_LT_FELT, }) err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) - if err != nil { + if err == nil { t.Errorf("ASSERT_LT_FELT hint test should have failed") } } From e086b60e2ad1e76399fbb0cfa24331ab96667222 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 19 Sep 2023 11:18:01 -0300 Subject: [PATCH 29/31] Add integration test --- cairo_programs/assert_lt_felt.cairo | 49 +++++++++++++++++++++++++++++ pkg/vm/cairo_run/cairo_run_test.go | 8 +++++ 2 files changed, 57 insertions(+) create mode 100644 cairo_programs/assert_lt_felt.cairo diff --git a/cairo_programs/assert_lt_felt.cairo b/cairo_programs/assert_lt_felt.cairo new file mode 100644 index 00000000..0b56ee55 --- /dev/null +++ b/cairo_programs/assert_lt_felt.cairo @@ -0,0 +1,49 @@ +%builtins range_check + +from starkware.cairo.common.math import assert_lt +from starkware.cairo.common.math import split_felt +from starkware.cairo.common.math import assert_lt_felt + +func assert_lt_felt_manual_implementation{range_check_ptr}(a, b) { + %{ + from starkware.cairo.common.math_utils import assert_integer + assert_integer(ids.a) + assert_integer(ids.b) + assert (ids.a % PRIME) < (ids.b % PRIME), \ + f'a = {ids.a % PRIME} is not less than b = {ids.b % PRIME}.' + %} + alloc_locals; + let (local a_high, local a_low) = split_felt(a); + let (b_high, b_low) = split_felt(b); + + if (a_high == b_high) { + assert_lt(a_low, b_low); + return (); + } + assert_lt(a_high, b_high); + return (); +} + +func main{range_check_ptr: felt}() { + let x = 5; + let y = 6; + + tempvar m = 7; + tempvar n = 7 * 7; + + assert_lt_felt(1, 2); + assert_lt_felt(-2, -1); + assert_lt_felt(1, -1); + assert_lt_felt(0, 1); + assert_lt_felt(x, y); + assert_lt_felt(m, n); + + assert_lt_felt_manual_implementation(1, 2); + assert_lt_felt_manual_implementation(-2, -1); + assert_lt_felt_manual_implementation(1, -1); + assert_lt_felt_manual_implementation(0, 1); + assert_lt_felt_manual_implementation(x, y); + assert_lt_felt_manual_implementation(m, n); + + return (); +} \ No newline at end of file diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index 35935c60..b4c1bda5 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -210,3 +210,11 @@ func TestAssertLeFelt(t *testing.T) { t.Errorf("Program execution failed with error: %s", err) } } + +func TestAssertLtFelt(t *testing.T) { + cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, Layout: "all_cairo", ProofMode: false} + _, err := cairo_run.CairoRun("../../../cairo_programs/assert_lt_felt.json", cairoRunConfig) + if err != nil { + t.Errorf("Program execution failed with error: %s", err) + } +} From cb72b52cba1e8c468c5266dcb33630bd9bb4c485 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 19 Sep 2023 11:24:27 -0300 Subject: [PATCH 30/31] Add newline at eof --- cairo_programs/assert_lt_felt.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cairo_programs/assert_lt_felt.cairo b/cairo_programs/assert_lt_felt.cairo index 0b56ee55..7e1ee2d3 100644 --- a/cairo_programs/assert_lt_felt.cairo +++ b/cairo_programs/assert_lt_felt.cairo @@ -46,4 +46,4 @@ func main{range_check_ptr: felt}() { assert_lt_felt_manual_implementation(m, n); return (); -} \ No newline at end of file +} From 87240d3c74b4335a45fb2e8fb54d0101697ad557 Mon Sep 17 00:00:00 2001 From: Federica Date: Wed, 20 Sep 2023 10:49:46 -0300 Subject: [PATCH 31/31] Remove file --- pkg/hints/hint_utils/hint_utils.go | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 pkg/hints/hint_utils/hint_utils.go diff --git a/pkg/hints/hint_utils/hint_utils.go b/pkg/hints/hint_utils/hint_utils.go deleted file mode 100644 index 41340eaf..00000000 --- a/pkg/hints/hint_utils/hint_utils.go +++ /dev/null @@ -1,23 +0,0 @@ -package hint_utils - -import ( - "strings" - - . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" - "github.com/pkg/errors" -) - -func GetConstantFromVarName(name string, constants *map[string]Felt) (Felt, error) { - if constants == nil { - return Felt{}, errors.Errorf("Caled GetConstantFromVarName with a nil constants map. Var Name: %s", name) - } - - for key, value := range *constants { - keySplit := strings.Split(key, ".") - if keySplit[len(keySplit)-1] == name { - return value, nil - } - } - - return Felt{}, errors.Errorf("Variable name not found in constants map. Var Name: %s", name) -}