diff --git a/cairo_programs/ec_mul_inner.cairo b/cairo_programs/ec_mul_inner.cairo new file mode 100644 index 00000000..5a65e3f8 --- /dev/null +++ b/cairo_programs/ec_mul_inner.cairo @@ -0,0 +1,23 @@ +%builtins range_check + +from starkware.cairo.common.cairo_secp.ec import ( + EcPoint, + ec_mul_inner, +) +from starkware.cairo.common.cairo_secp.bigint import BigInt3 + +func main{range_check_ptr: felt}() { + // ec_mul_inner + let (pow2, res) = ec_mul_inner( + EcPoint( + BigInt3(65162296, 359657, 04862662171381), BigInt3(-5166641367474701, -63029418, 793) + ), + 123, + 298, + ); + assert pow2 = EcPoint( + BigInt3(30016796425722798916160189, 75045389156830800234717485, 13862403786096360935413684), + BigInt3(43820690643633544357415586, 29808113745001228006676979, 15112469502208690731782390), + ); + return (); +} diff --git a/pkg/hints/ec_hint.go b/pkg/hints/ec_hint.go index 4b0a8ce2..6abb144f 100644 --- a/pkg/hints/ec_hint.go +++ b/pkg/hints/ec_hint.go @@ -7,10 +7,12 @@ import ( "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/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/types" "github.com/lambdaclass/cairo-vm.go/pkg/vm" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" + "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" ) type EcPoint struct { @@ -90,6 +92,23 @@ func ecNegateEmbeddedSecpP(virtual_machine *vm.VirtualMachine, exec_scopes types return ecNegate(virtual_machine, exec_scopes, ids_data, *secp_p) } +/* +Implements hint: +%{ memory[ap] = (ids.scalar % PRIME) % 2 %} +*/ +func ecMulInner(virtualMachine *vm.VirtualMachine, ids hint_utils.IdsManager) error { + scalar, err := ids.GetFelt("scalar", virtualMachine) + + if err != nil { + return err + } + + result := scalar.And(lambdaworks.FeltOne()) + virtualMachine.Segments.Memory.Insert(virtualMachine.RunContext.Ap, memory.NewMaybeRelocatableFelt(result)) + + return nil +} + /* Implements hint: diff --git a/pkg/hints/ec_hint_test.go b/pkg/hints/ec_hint_test.go index 5e74cef9..b52d37d7 100644 --- a/pkg/hints/ec_hint_test.go +++ b/pkg/hints/ec_hint_test.go @@ -129,6 +129,84 @@ func TestRunEcEmbeddedSecpOk(t *testing.T) { } +func TestEcMulInnerSuccessEven(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + vm.Segments.AddSegment() + + scalar := NewMaybeRelocatableFelt(FeltFromUint64(89712)) + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "scalar": {scalar}, + }, + vm, + ) + + hintProcessor := CairoVmHintProcessor{} + + hintData := any(HintData{ + Ids: idsManager, + Code: EC_MUL_INNER, + }) + + vm.RunContext.Ap = NewRelocatable(1, 1) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + result, err := vm.Segments.Memory.Get(NewRelocatable(1, 1)) + + if err != nil { + t.Errorf("EC_MUL_INNER hint failed with error %s", err) + } + + resultFelt, ok := result.GetFelt() + if !ok { + t.Errorf("EC_MUL_INNER hint expected Felt value as result") + } + + if !resultFelt.IsZero() { + t.Errorf("EC_MUL_INNER should have returned 0 but got %v", resultFelt) + } +} + +func TestEcMulInnerSuccessOdd(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + vm.Segments.AddSegment() + + scalar := NewMaybeRelocatableFelt(FeltFromUint64(89711)) + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "scalar": {scalar}, + }, + vm, + ) + + hintProcessor := CairoVmHintProcessor{} + + hintData := any(HintData{ + Ids: idsManager, + Code: EC_MUL_INNER, + }) + + vm.RunContext.Ap = NewRelocatable(1, 1) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + result, err := vm.Segments.Memory.Get(NewRelocatable(1, 1)) + + if err != nil { + t.Errorf("EC_MUL_INNER hint failed with error %s", err) + } + + resultFelt, ok := result.GetFelt() + if !ok { + t.Errorf("EC_MUL_INNER hint expected Felt value as result") + } + + if resultFelt.Cmp(FeltOne()) != 0 { + t.Errorf("EC_MUL_INNER should have returned 1 but got %v", resultFelt) + } +} + func TestComputeDoublingSlopeOk(t *testing.T) { vm := NewVirtualMachine() vm.Segments.AddSegment() diff --git a/pkg/hints/hint_codes/ec_op_hints.go b/pkg/hints/hint_codes/ec_op_hints.go index fabd0531..a7c8600f 100644 --- a/pkg/hints/hint_codes/ec_op_hints.go +++ b/pkg/hints/hint_codes/ec_op_hints.go @@ -2,6 +2,7 @@ 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" +const EC_MUL_INNER = "memory[ap] = (ids.scalar % PRIME) % 2" const EC_DOUBLE_SLOPE_V1 = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\nfrom starkware.python.math_utils import ec_double_slope\n\n# Compute the slope.\nx = pack(ids.point.x, PRIME)\ny = pack(ids.point.y, PRIME)\nvalue = slope = ec_double_slope(point=(x, y), alpha=0, p=SECP_P)" const COMPUTE_SLOPE_V1 = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\nfrom starkware.python.math_utils import line_slope\n\n# Compute the slope.\nx0 = pack(ids.point0.x, PRIME)\ny0 = pack(ids.point0.y, PRIME)\nx1 = pack(ids.point1.x, PRIME)\ny1 = pack(ids.point1.y, PRIME)\nvalue = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)" const EC_DOUBLE_SLOPE_EXTERNAL_CONSTS = "from starkware.cairo.common.cairo_secp.secp_utils import pack\nfrom starkware.python.math_utils import ec_double_slope\n\n# Compute the slope.\nx = pack(ids.point.x, PRIME)\ny = pack(ids.point.y, PRIME)\nvalue = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P)" diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 32cab3b2..b0c5165a 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -170,6 +170,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return splitInt(data.Ids, vm) case SPLIT_INT_ASSERT_RANGE: return splitIntAssertRange(data.Ids, vm) + case EC_MUL_INNER: + return ecMulInner(vm, data.Ids) case VERIFY_ZERO_EXTERNAL_SECP: return verifyZeroWithExternalConst(*vm, *execScopes, data.Ids) case FAST_EC_ADD_ASSIGN_NEW_X: diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index 47fb4e24..5cae0a81 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -335,3 +335,7 @@ func TestCairoKeccak(t *testing.T) { func TestKeccakAddUint256(t *testing.T) { testProgram("keccak_add_uint256", t) } + +func TestEcMulInner(t *testing.T) { + testProgram("ec_mul_inner", t) +}