diff --git a/pkg/hints/dict_hints_test.go b/pkg/hints/dict_hints_test.go index 76e5de9d..b70b47dc 100644 --- a/pkg/hints/dict_hints_test.go +++ b/pkg/hints/dict_hints_test.go @@ -5,6 +5,7 @@ import ( . "github.com/lambdaclass/cairo-vm.go/pkg/hints" "github.com/lambdaclass/cairo-vm.go/pkg/hints/dict_manager" + . "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/ec_hint.go b/pkg/hints/ec_hint.go new file mode 100644 index 00000000..8c83ff07 --- /dev/null +++ b/pkg/hints/ec_hint.go @@ -0,0 +1,116 @@ +package hints + +import ( + "errors" + "math/big" + + "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" +) + +type BigInt3 struct { + Limbs []lambdaworks.Felt +} + +type EcPoint struct { + X BigInt3 + Y BigInt3 +} + +func (val *BigInt3) Pack86() big.Int { + sum := big.NewInt(0) + for i := 0; i < 3; i++ { + felt := val.Limbs[i] + signed := felt.ToSigned() + shifed := new(big.Int).Lsh(signed, uint(i*86)) + sum.Add(sum, shifed) + } + return *sum +} + +func BigInt3FromBaseAddr(addr memory.Relocatable, virtual_machine vm.VirtualMachine) (BigInt3, error) { + limbs := make([]lambdaworks.Felt, 0) + for i := 0; i < 3; i++ { + felt, err := virtual_machine.Segments.Memory.GetFelt(addr.AddUint(uint(i))) + if err == nil { + limbs = append(limbs, felt) + } else { + return BigInt3{}, errors.New("Identifier has no member") + } + } + return BigInt3{Limbs: limbs}, nil +} + +func BigInt3FromVarName(name string, virtual_machine vm.VirtualMachine, ids_data hint_utils.IdsManager) (EcPoint, error) { + point_addr, err := ids_data.GetAddr(name, &virtual_machine) + if err != nil { + return EcPoint{}, err + } + + x, err := BigInt3FromBaseAddr(point_addr, virtual_machine) + if err != nil { + return EcPoint{}, err + } + + y, err := BigInt3FromBaseAddr(point_addr.AddUint(3), virtual_machine) + if err != nil { + return EcPoint{}, err + } + + return EcPoint{X: x, Y: y}, nil +} + +/* +Implements main logic for `EC_NEGATE` and `EC_NEGATE_EMBEDDED_SECP` hints +*/ +func ecNegate(virtual_machine vm.VirtualMachine, exec_scopes types.ExecutionScopes, ids_data hint_utils.IdsManager, secp_p big.Int) error { + point, err := ids_data.GetRelocatable("point", &virtual_machine) + if err != nil { + return err + } + + point_y, err := point.AddInt(3) + if err != nil { + return err + } + + y_bigint3, err := BigInt3FromBaseAddr(point_y, virtual_machine) + if err != nil { + return err + } + + y := y_bigint3.Pack86() + value := new(big.Int).Neg(&y) + value.Mod(value, &secp_p) + + exec_scopes.AssignOrUpdateVariable("value", value) + exec_scopes.AssignOrUpdateVariable("SECP_P", secp_p) + return nil +} + +func ecNegateImportSecpP(virtual_machine vm.VirtualMachine, exec_scopes types.ExecutionScopes, ids_data hint_utils.IdsManager) error { + secp_p, _ := new(big.Int).SetString("115792089237316195423570985008687907853269984665640564039457584007908834671663", 10) + return ecNegate(virtual_machine, exec_scopes, ids_data, *secp_p) +} + +/* +Implements hint: +%{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + SECP_P = 2**255-19 + + y = pack(ids.point.y, PRIME) % SECP_P + # The modulo operation in python always returns a nonnegative number. + value = (-y) % SECP_P +%} +*/ + +func ecNegateEmbeddedSecpP(virtual_machine vm.VirtualMachine, exec_scopes types.ExecutionScopes, ids_data hint_utils.IdsManager) error { + secp_p := big.NewInt(1) + secp_p.Lsh(secp_p, 255) + secp_p.Sub(secp_p, big.NewInt(19)) + return ecNegate(virtual_machine, exec_scopes, ids_data, *secp_p) +} diff --git a/pkg/hints/ec_hint_test.go b/pkg/hints/ec_hint_test.go new file mode 100644 index 00000000..bed5fbe3 --- /dev/null +++ b/pkg/hints/ec_hint_test.go @@ -0,0 +1,134 @@ +package hints_test + +import ( + "fmt" + "math/big" + "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" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" +) + +func TestBigInt3Pack86(t *testing.T) { + limbs1 := []Felt{FeltFromUint64(10), FeltFromUint64(10), FeltFromUint64(10)} + bigint := BigInt3{Limbs: limbs1} + pack1 := bigint.Pack86() + + expected, _ := new(big.Int).SetString("59863107065073783529622931521771477038469668772249610", 10) + + if pack1.Cmp(expected) != 0 { + t.Errorf("Different pack from expected") + } + + limbs2 := []Felt{FeltFromDecString("773712524553362"), FeltFromDecString("57408430697461422066401280"), FeltFromDecString("1292469707114105")} + bigint2 := BigInt3{Limbs: limbs2} + pack2 := bigint2.Pack86() + + expected2, _ := new(big.Int).SetString("7737125245533626718119526477371252455336267181195264773712524553362", 10) + + if pack2.Cmp(expected2) != 0 { + t.Errorf("Different pack from expected2") + } +} + +func TestRunEcNegateOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + vm.Segments.AddSegment() + vm.Segments.Memory.Insert(NewRelocatable(1, 3), NewMaybeRelocatableFelt(FeltFromUint64(2645))) + vm.Segments.Memory.Insert(NewRelocatable(1, 4), NewMaybeRelocatableFelt(FeltFromUint64(454))) + vm.Segments.Memory.Insert(NewRelocatable(1, 5), NewMaybeRelocatableFelt(FeltFromUint64(206))) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "point": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))}, + "ec_negative": {nil}, + }, + vm, + ) + + point, _ := idsManager.Get("point", vm) + fmt.Println("Ids manager: ", point) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: EC_NEGATE, + }) + exec_scopes := types.NewExecutionScopes() + err := hintProcessor.ExecuteHint(vm, &hintData, nil, exec_scopes) + if err != nil { + t.Errorf("Ec Negative hint test failed with error %s", err) + } else { + // Check ids.is_positive + value, err := exec_scopes.Get("value") + val := value.(*big.Int) + expected, _ := new(big.Int).SetString("115792089237316195423569751828682367333329274433232027476421668138471189901786", 10) + + if err != nil || expected.Cmp(val) != 0 { + t.Errorf("Ec Negative hint test incorrect value for exec_scopes.value") + } + } +} + +func TestRunEcEmbeddedSecpOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + vm.Segments.AddSegment() + vm.Segments.Memory.Insert(NewRelocatable(1, 3), NewMaybeRelocatableFelt(FeltFromUint64(2645))) + vm.Segments.Memory.Insert(NewRelocatable(1, 4), NewMaybeRelocatableFelt(FeltFromUint64(454))) + vm.Segments.Memory.Insert(NewRelocatable(1, 5), NewMaybeRelocatableFelt(FeltFromUint64(206))) + + y2 := big.NewInt(206) + y2.Lsh(y2, 86*2) + + y1 := big.NewInt(454) + y1.Lsh(y1, 86) + + y0 := big.NewInt(2645) + + y := new(big.Int) + y.Add(y, y2) + y.Add(y, y1) + y.Add(y, y0) + + vm.RunContext.Fp = NewRelocatable(1, 1) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "point": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))}, + "ec_negative": {nil}, + }, + vm, + ) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: EC_NEGATE_EMBEDDED_SECP, + }) + exec_scopes := types.NewExecutionScopes() + err := hintProcessor.ExecuteHint(vm, &hintData, nil, exec_scopes) + if err != nil { + t.Errorf("Ec Negative Embedded Sec hint test failed with error %s", err) + } else { + // Check ids.is_positive + value, err := exec_scopes.Get("value") + val := value.(*big.Int) + + // expected value + minus_y := big.NewInt(1) + minus_y.Lsh(minus_y, 255) + minus_y.Sub(minus_y, big.NewInt(19)) + minus_y.Sub(minus_y, y) + + if err != nil || minus_y.Cmp(val) != 0 { + t.Errorf("Ec Negative hint test incorrect value for exec_scopes.value") + } + } + +} diff --git a/pkg/hints/dict_hint_codes.go b/pkg/hints/hint_codes/dict_hint_codes.go similarity index 98% rename from pkg/hints/dict_hint_codes.go rename to pkg/hints/hint_codes/dict_hint_codes.go index 88445b9a..b8942a2f 100644 --- a/pkg/hints/dict_hint_codes.go +++ b/pkg/hints/hint_codes/dict_hint_codes.go @@ -1,4 +1,4 @@ -package hints +package hint_codes const DEFAULT_DICT_NEW = "if '__dict_manager' not in globals():\n from starkware.cairo.common.dict import DictManager\n __dict_manager = DictManager()\n\nmemory[ap] = __dict_manager.new_default_dict(segments, ids.default_value)" diff --git a/pkg/hints/hint_codes/ec_op_hints.go b/pkg/hints/hint_codes/ec_op_hints.go new file mode 100644 index 00000000..c2092a7f --- /dev/null +++ b/pkg/hints/hint_codes/ec_op_hints.go @@ -0,0 +1,4 @@ +package hint_codes + +const EC_NEGATE = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\n\ny = pack(ids.point.y, PRIME) % SECP_P\n# The modulo operation in python always returns a nonnegative number.\nvalue = (-y) % SECP_P" +const EC_NEGATE_EMBEDDED_SECP = "from starkware.cairo.common.cairo_secp.secp_utils import pack\nSECP_P = 2**255-19\n\ny = pack(ids.point.y, PRIME) % SECP_P\n# The modulo operation in python always returns a nonnegative number.\nvalue = (-y) % SECP_P" diff --git a/pkg/hints/math_hint_codes.go b/pkg/hints/hint_codes/math_hint_codes.go similarity index 98% rename from pkg/hints/math_hint_codes.go rename to pkg/hints/hint_codes/math_hint_codes.go index 553bcde1..0919825e 100644 --- a/pkg/hints/math_hint_codes.go +++ b/pkg/hints/hint_codes/math_hint_codes.go @@ -1,4 +1,4 @@ -package hints +package hint_codes const ASSERT_NN = "from starkware.cairo.common.math_utils import assert_integer\nassert_integer(ids.a)\nassert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.'" diff --git a/pkg/hints/memcpy_hint_codes.go b/pkg/hints/hint_codes/memcpy_hint_codes.go similarity index 91% rename from pkg/hints/memcpy_hint_codes.go rename to pkg/hints/hint_codes/memcpy_hint_codes.go index e2e52ffe..16966595 100644 --- a/pkg/hints/memcpy_hint_codes.go +++ b/pkg/hints/hint_codes/memcpy_hint_codes.go @@ -1,4 +1,4 @@ -package hints +package hint_codes const ADD_SEGMENT = "memory[ap] = segments.add()" const VM_EXIT_SCOPE = "vm_exit_scope()" diff --git a/pkg/hints/pow_hint_codes.go b/pkg/hints/hint_codes/pow_hint_codes.go similarity index 76% rename from pkg/hints/pow_hint_codes.go rename to pkg/hints/hint_codes/pow_hint_codes.go index 523a4356..ae7bd962 100644 --- a/pkg/hints/pow_hint_codes.go +++ b/pkg/hints/hint_codes/pow_hint_codes.go @@ -1,3 +1,3 @@ -package hints +package hint_codes const POW = "ids.locs.bit = (ids.prev_locs.exp % PRIME) & 1" diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index cf8181a6..ccc26810 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -3,6 +3,7 @@ package hints import ( "strings" + . "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/parser" @@ -61,6 +62,10 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return vm_exit_scope(execScopes) case ASSERT_NOT_EQUAL: return assert_not_equal(data.Ids, vm) + case EC_NEGATE: + return ecNegateImportSecpP(*vm, *execScopes, data.Ids) + case EC_NEGATE_EMBEDDED_SECP: + return ecNegateEmbeddedSecpP(*vm, *execScopes, data.Ids) case POW: return pow(data.Ids, vm) case SQRT: diff --git a/pkg/hints/math_hints_test.go b/pkg/hints/math_hints_test.go index 5dbd4e6a..54672499 100644 --- a/pkg/hints/math_hints_test.go +++ b/pkg/hints/math_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" diff --git a/pkg/hints/memcpy_hints_test.go b/pkg/hints/memcpy_hints_test.go index 0fd7cb0f..1e5beae1 100644 --- a/pkg/hints/memcpy_hints_test.go +++ b/pkg/hints/memcpy_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/lambdaworks" diff --git a/pkg/hints/pow_hints_test.go b/pkg/hints/pow_hints_test.go index 13ce6285..9a652e0c 100644 --- a/pkg/hints/pow_hints_test.go +++ b/pkg/hints/pow_hints_test.go @@ -2,6 +2,7 @@ package hints_test import ( . "github.com/lambdaclass/cairo-vm.go/pkg/hints" + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/vm"