From bba16b0279c0354c203e85b0a0009f70f1aaebbe Mon Sep 17 00:00:00 2001 From: Harikrishnan Shaji Date: Mon, 8 Apr 2024 17:50:26 +0530 Subject: [PATCH] Implement FastEcAddAssignNewY hint (#334) * Implement EcNegate hint * Implement NondetBigint3V1 hint * Fix context usage + add some functions to return constants * Add scope check test utils + usage * More comments and tests * More tests * Clean up some code * Implement FastEcAddAssignNewY hint * Use FeltZero/FeltOne in tests * Use FeltZero in tests * Add secp util functions to clean up hint * Make function private * Moving comments around * Fix import * Make return simpler * Comment test values * Comment test values * Simpler context init in tests * Add GetVariableValueAsBigInt method to scope manager * Simpler tests * Remove duplicate test check * Clean up scope usage * Fetch SECP_P from scope in FastEcAddAssignNewY --------- Co-authored-by: Carmen Cabrera --- pkg/hintrunner/hinter/scope.go | 10 ++++ pkg/hintrunner/zero/hintcode.go | 5 +- pkg/hintrunner/zero/zerohint.go | 2 + pkg/hintrunner/zero/zerohint_ec.go | 53 ++++++++++++++++++- pkg/hintrunner/zero/zerohint_ec_test.go | 61 ++++++++++++++++++++++ pkg/hintrunner/zero/zerohint_utils_test.go | 8 +++ 6 files changed, 136 insertions(+), 3 deletions(-) diff --git a/pkg/hintrunner/hinter/scope.go b/pkg/hintrunner/hinter/scope.go index 71165f577..4c2c1be26 100644 --- a/pkg/hintrunner/hinter/scope.go +++ b/pkg/hintrunner/hinter/scope.go @@ -55,6 +55,16 @@ func (sm *ScopeManager) AssignVariable(name string, value any) error { return nil } +func (sm *ScopeManager) AssignVariables(values map[string]any) error { + for name, value := range values { + err := sm.AssignVariable(name, value) + if err != nil { + return err + } + } + return nil +} + func (sm *ScopeManager) GetVariableValue(name string) (any, error) { scope, err := sm.getCurrentScope() if err != nil { diff --git a/pkg/hintrunner/zero/hintcode.go b/pkg/hintrunner/zero/hintcode.go index fddef67c2..b3a3d9c1f 100644 --- a/pkg/hintrunner/zero/hintcode.go +++ b/pkg/hintrunner/zero/hintcode.go @@ -58,8 +58,9 @@ const ( // ------ Usort hints related code ------ // ------ Elliptic Curve hints related code ------ - ecNegateCode string = "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" - nondetBigint3V1Code string = "from starkware.cairo.common.cairo_secp.secp_utils import split\n\nsegments.write_arg(ids.res.address_, split(value))" + ecNegateCode string = "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" + nondetBigint3V1Code string = "from starkware.cairo.common.cairo_secp.secp_utils import split\n\nsegments.write_arg(ids.res.address_, split(value))" + fastEcAddAssignNewYCode string = "value = new_y = (slope * (x0 - new_x) - y0) % SECP_P" // ------ Signature hints related code ------ diff --git a/pkg/hintrunner/zero/zerohint.go b/pkg/hintrunner/zero/zerohint.go index 135a89cc5..337a4ae0f 100644 --- a/pkg/hintrunner/zero/zerohint.go +++ b/pkg/hintrunner/zero/zerohint.go @@ -112,6 +112,8 @@ func GetHintFromCode(program *zero.ZeroProgram, rawHint zero.Hint, hintPC uint64 return createEcNegateHinter(resolver) case nondetBigint3V1Code: return createNondetBigint3V1Hinter(resolver) + case fastEcAddAssignNewYCode: + return createFastEcAddAssignNewYHinter() // Blake hints case blake2sAddUint256BigendCode: return createBlake2sAddUint256Hinter(resolver, true) diff --git a/pkg/hintrunner/zero/zerohint_ec.go b/pkg/hintrunner/zero/zerohint_ec.go index ac99931fa..33d0e7e5f 100644 --- a/pkg/hintrunner/zero/zerohint_ec.go +++ b/pkg/hintrunner/zero/zerohint_ec.go @@ -2,6 +2,7 @@ package zero import ( "fmt" + "math/big" "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter" secp_utils "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/utils" @@ -56,7 +57,7 @@ func newEcNegateHint(point hinter.ResOperander) hinter.Hinter { yBig.Neg(yBig) yBig.Mod(yBig, secPBig) - return ctx.ScopeManager.AssignVariable("value", yBig) + return ctx.ScopeManager.AssignVariables(map[string]any{"value": yBig, "SECP_P": secPBig}) }, } } @@ -122,3 +123,53 @@ func createNondetBigint3V1Hinter(resolver hintReferenceResolver) (hinter.Hinter, return newNondetBigint3V1Hint(res), nil } + +func newFastEcAddAssignNewYHint() hinter.Hinter { + return &GenericZeroHinter{ + Name: "FastEcAddAssignNewY", + Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { + //> value = new_y = (slope * (x0 - new_x) - y0) % SECP_P + + slopeBig, err := ctx.ScopeManager.GetVariableValueAsBigInt("slope") + if err != nil { + return err + } + x0Big, err := ctx.ScopeManager.GetVariableValueAsBigInt("x0") + if err != nil { + return err + } + new_xBig, err := ctx.ScopeManager.GetVariableValueAsBigInt("new_x") + if err != nil { + return err + } + y0Big, err := ctx.ScopeManager.GetVariableValueAsBigInt("y0") + if err != nil { + return err + } + secPBig, err := ctx.ScopeManager.GetVariableValueAsBigInt("SECP_P") + if err != nil { + return err + } + + new_yBig := new(big.Int) + new_yBig.Sub(x0Big, new_xBig) + new_yBig.Mul(new_yBig, slopeBig) + new_yBig.Sub(new_yBig, y0Big) + new_yBig.Mod(new_yBig, secPBig) + + valueBig := new(big.Int) + valueBig.Set(new_yBig) + + err = ctx.ScopeManager.AssignVariable("new_y", new_yBig) + if err != nil { + return err + } + + return ctx.ScopeManager.AssignVariable("value", valueBig) + }, + } +} + +func createFastEcAddAssignNewYHinter() (hinter.Hinter, error) { + return newFastEcAddAssignNewYHint(), nil +} diff --git a/pkg/hintrunner/zero/zerohint_ec_test.go b/pkg/hintrunner/zero/zerohint_ec_test.go index 283d4c7f3..ed65b0c9b 100644 --- a/pkg/hintrunner/zero/zerohint_ec_test.go +++ b/pkg/hintrunner/zero/zerohint_ec_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter" + secp_utils "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/utils" "github.com/NethermindEth/cairo-vm-go/pkg/utils" "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" ) @@ -341,5 +342,65 @@ func TestZeroHintEc(t *testing.T) { check: consecutiveVarValueEquals("res", []*fp.Element{feltString("2"), feltString("2"), &utils.FeltZero}), }, }, + "FastEcAddAssignNewY": { + { + operanders: []*hintOperander{}, + ctxInit: func(ctx *hinter.HintRunnerContext) { + slopeBig := big.NewInt(100) + x0Big := big.NewInt(20) + new_xBig := big.NewInt(10) + y0Big := big.NewInt(10) + secPBig, _ := secp_utils.GetSecPBig() + + ctx.ScopeManager.EnterScope(map[string]any{"slope": slopeBig, "x0": x0Big, "new_x": new_xBig, "y0": y0Big, "SECP_P": secPBig}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newFastEcAddAssignNewYHint() + }, + check: allVarValueInScopeEquals(map[string]any{ + "new_y": big.NewInt(990), + "value": big.NewInt(990), + }), + }, + { + operanders: []*hintOperander{}, + ctxInit: func(ctx *hinter.HintRunnerContext) { + slopeBig := big.NewInt(0) + x0Big := big.NewInt(20) + new_xBig := big.NewInt(10) + y0Big := big.NewInt(10) + secPBig, _ := secp_utils.GetSecPBig() + + ctx.ScopeManager.EnterScope(map[string]any{"slope": slopeBig, "x0": x0Big, "new_x": new_xBig, "y0": y0Big, "SECP_P": secPBig}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newFastEcAddAssignNewYHint() + }, + check: allVarValueInScopeEquals(map[string]any{ + "new_y": bigIntString("115792089237316195423570985008687907853269984665640564039457584007908834671653", 10), + "value": bigIntString("115792089237316195423570985008687907853269984665640564039457584007908834671653", 10), + }), + }, + { + operanders: []*hintOperander{}, + ctxInit: func(ctx *hinter.HintRunnerContext) { + // GetSecPBig() + 20 + slopeBig := bigIntString("115792089237316195423570985008687907853269984665640564039457584007908834671683", 10) + x0Big := big.NewInt(200) + new_xBig := big.NewInt(199) + y0Big := big.NewInt(20) + secPBig, _ := secp_utils.GetSecPBig() + + ctx.ScopeManager.EnterScope(map[string]any{"slope": slopeBig, "x0": x0Big, "new_x": new_xBig, "y0": y0Big, "SECP_P": secPBig}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newFastEcAddAssignNewYHint() + }, + check: allVarValueInScopeEquals(map[string]any{ + "new_y": big.NewInt(0), + "value": big.NewInt(0), + }), + }, + }, }) } diff --git a/pkg/hintrunner/zero/zerohint_utils_test.go b/pkg/hintrunner/zero/zerohint_utils_test.go index c1b7d1857..105464562 100644 --- a/pkg/hintrunner/zero/zerohint_utils_test.go +++ b/pkg/hintrunner/zero/zerohint_utils_test.go @@ -180,6 +180,14 @@ func varValueInScopeEquals(varName string, expected any) func(t *testing.T, ctx } } +func allVarValueInScopeEquals(expectedValues map[string]any) func(t *testing.T, ctx *hintTestContext) { + return func(t *testing.T, ctx *hintTestContext) { + for varName, expected := range expectedValues { + varValueInScopeEquals(varName, expected)(t, ctx) + } + } +} + func errorTextContains(s string) func(t *testing.T, ctx *hintTestContext, err error) { return func(t *testing.T, ctx *hintTestContext, err error) { if err == nil {