diff --git a/pkg/hintrunner/utils/math_utils.go b/pkg/hintrunner/utils/math_utils.go index 34b1f06d3..fa4eee43d 100644 --- a/pkg/hintrunner/utils/math_utils.go +++ b/pkg/hintrunner/utils/math_utils.go @@ -1,13 +1,34 @@ package utils import ( + "errors" "fmt" "math/big" "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" ) +func EcDoubleSlope(pointX, pointY, alpha, prime *big.Int) (big.Int, error) { + // https://github.com/starkware-libs/cairo-lang/blob/efa9648f57568aad8f8a13fbf027d2de7c63c2c0/src/starkware/python/math_utils.py#L151 + + if new(big.Int).Mod(pointY, prime).Cmp(big.NewInt(0)) == 0 { + return *big.NewInt(0), errors.New("point[1] % p == 0") + } + + n := big.NewInt(3) + n.Mul(n, pointX) + n.Mul(n, pointX) + n.Add(n, alpha) + + m := big.NewInt(2) + m.Mul(m, pointY) + + return divmod(n, m, prime) +} + func AsInt(valueFelt *fp.Element) big.Int { + // https://github.com/starkware-libs/cairo-lang/blob/efa9648f57568aad8f8a13fbf027d2de7c63c2c0/src/starkware/cairo/common/math_utils.py#L8 + var valueBig big.Int valueFelt.BigInt(&valueBig) return AsIntBig(&valueBig) @@ -23,6 +44,71 @@ func AsIntBig(value *big.Int) big.Int { return *new(big.Int).Sub(value, fp.Modulus()) } +func divmod(n, m, p *big.Int) (big.Int, error) { + // https://github.com/starkware-libs/cairo-lang/blob/efa9648f57568aad8f8a13fbf027d2de7c63c2c0/src/starkware/python/math_utils.py#L26 + + a, _, c := igcdex(m, p) + if c.Cmp(big.NewInt(1)) != 0 { + return *big.NewInt(0), errors.New("no solution exists (gcd(m, p) != 1)") + } + res := new(big.Int) + res.Mul(n, &a) + res.Mod(res, p) + return *res, nil +} + +func igcdex(a, b *big.Int) (big.Int, big.Int, big.Int) { + // https://github.com/sympy/sympy/blob/d91b8ad6d36a59a879cc70e5f4b379da5fdd46ce/sympy/core/intfunc.py#L362 + + if a.Cmp(big.NewInt(0)) == 0 && b.Cmp(big.NewInt(0)) == 0 { + return *big.NewInt(0), *big.NewInt(1), *big.NewInt(0) + } + g, x, y := gcdext(a, b) + return x, y, g +} + +func gcdext(a, b *big.Int) (big.Int, big.Int, big.Int) { + // https://github.com/sympy/sympy/blob/d91b8ad6d36a59a879cc70e5f4b379da5fdd46ce/sympy/external/ntheory.py#L125 + + if a.Cmp(big.NewInt(0)) == 0 || b.Cmp(big.NewInt(0)) == 0 { + g := new(big.Int) + if a.Cmp(big.NewInt(0)) == 0 { + g.Abs(b) + } else { + g.Abs(a) + } + + if g.Cmp(big.NewInt(0)) == 0 { + return *big.NewInt(0), *big.NewInt(0), *big.NewInt(0) + } + return *g, *new(big.Int).Div(a, g), *new(big.Int).Div(b, g) + } + + xSign, aSigned := sign(a) + ySign, bSigned := sign(b) + x, r := big.NewInt(1), big.NewInt(0) + y, s := big.NewInt(0), big.NewInt(1) + + for bSigned.Sign() != 0 { + q, c := new(big.Int).DivMod(&aSigned, &bSigned, new(big.Int)) + aSigned = bSigned + bSigned = *c + x, r = r, new(big.Int).Sub(x, new(big.Int).Mul(q, r)) + y, s = s, new(big.Int).Sub(y, new(big.Int).Mul(q, s)) + } + + return aSigned, *new(big.Int).Mul(x, big.NewInt(int64(xSign))), *new(big.Int).Mul(y, big.NewInt(int64(ySign))) +} + +func sign(n *big.Int) (int, big.Int) { + // https://github.com/sympy/sympy/blob/d91b8ad6d36a59a879cc70e5f4b379da5fdd46ce/sympy/external/ntheory.py#L119 + + if n.Sign() < 0 { + return -1, *new(big.Int).Abs(n) + } + return 1, *new(big.Int).Set(n) +} + func SafeDiv(x, y *big.Int) (big.Int, error) { if y.Cmp(big.NewInt(0)) == 0 { return *big.NewInt(0), fmt.Errorf("Division by zero.") diff --git a/pkg/hintrunner/utils/math_utils_test.go b/pkg/hintrunner/utils/math_utils_test.go new file mode 100644 index 000000000..dae76dc5c --- /dev/null +++ b/pkg/hintrunner/utils/math_utils_test.go @@ -0,0 +1,114 @@ +package utils + +import ( + "math/big" + "testing" +) + +func TestDivMod(t *testing.T) { + // https://github.com/starkware-libs/cairo-lang/blob/efa9648f57568aad8f8a13fbf027d2de7c63c2c0/src/starkware/python/math_utils_test.py#L108 + tests := []struct { + name string + n, m, p *big.Int + expected *big.Int + expectedErrMsg string + }{ + { + name: "Basic case", + n: big.NewInt(2), + m: big.NewInt(3), + p: big.NewInt(5), + expected: big.NewInt(4), + }, + { + name: "Error case", + n: big.NewInt(8), + m: big.NewInt(10), + p: big.NewInt(5), + expectedErrMsg: "no solution exists (gcd(m, p) != 1)", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual, err := divmod(tt.n, tt.m, tt.p) + + if err != nil { + if err.Error() != tt.expectedErrMsg { + t.Errorf("got error: %v, want: %v", err, tt.expectedErrMsg) + } + return + } + + if actual.Cmp(tt.expected) != 0 { + t.Errorf("got quotient: %v, want: %v", actual, tt.expected) + } + }) + } +} + +func TestIgcdex(t *testing.T) { + // https://github.com/sympy/sympy/blob/e7fb2714f17b30b83e424448aad0da9e94a4b577/sympy/core/tests/test_numbers.py#L278 + tests := []struct { + name string + a, b *big.Int + expectedX, expectedY, expectedG *big.Int + }{ + { + name: "Case 1", + a: big.NewInt(2), + b: big.NewInt(3), + expectedX: big.NewInt(-1), + expectedY: big.NewInt(1), + expectedG: big.NewInt(1), + }, + { + name: "Case 2", + a: big.NewInt(10), + b: big.NewInt(12), + expectedX: big.NewInt(-1), + expectedY: big.NewInt(1), + expectedG: big.NewInt(2), + }, + { + name: "Case 3", + a: big.NewInt(100), + b: big.NewInt(2004), + expectedX: big.NewInt(-20), + expectedY: big.NewInt(1), + expectedG: big.NewInt(4), + }, + { + name: "Case 4", + a: big.NewInt(0), + b: big.NewInt(0), + expectedX: big.NewInt(0), + expectedY: big.NewInt(1), + expectedG: big.NewInt(0), + }, + { + name: "Case 5", + a: big.NewInt(1), + b: big.NewInt(0), + expectedX: big.NewInt(1), + expectedY: big.NewInt(0), + expectedG: big.NewInt(1), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actualX, actualY, actualG := igcdex(tt.a, tt.b) + + if actualX.Cmp(tt.expectedX) != 0 { + t.Errorf("got x: %v, want: %v", actualX, tt.expectedX) + } + if actualY.Cmp(tt.expectedY) != 0 { + t.Errorf("got x: %v, want: %v", actualY, tt.expectedY) + } + if actualG.Cmp(tt.expectedG) != 0 { + t.Errorf("got x: %v, want: %v", actualG, tt.expectedG) + } + }) + } +} diff --git a/pkg/hintrunner/utils/secp_utils.go b/pkg/hintrunner/utils/secp_utils.go index e07f39a27..b1db73f52 100644 --- a/pkg/hintrunner/utils/secp_utils.go +++ b/pkg/hintrunner/utils/secp_utils.go @@ -8,33 +8,35 @@ import ( "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" ) -func getBaseBig() (*big.Int, bool) { +func getBaseBig() (big.Int, bool) { // 2**86 - return new(big.Int).SetString("77371252455336267181195264", 10) + base, ok := new(big.Int).SetString("77371252455336267181195264", 10) + return *base, ok } -func GetSecPBig() (*big.Int, bool) { +func GetSecPBig() (big.Int, bool) { // 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 - 1 - return new(big.Int).SetString("115792089237316195423570985008687907853269984665640564039457584007908834671663", 10) + secP, ok := new(big.Int).SetString("115792089237316195423570985008687907853269984665640564039457584007908834671663", 10) + return *secP, ok } -func SecPPacked(limbs [3]*fp.Element) (*big.Int, error) { +func SecPPacked(limbs [3]*fp.Element) (big.Int, error) { // https://github.com/starkware-libs/cairo-lang/blob/efa9648f57568aad8f8a13fbf027d2de7c63c2c0/src/starkware/cairo/common/cairo_secp/secp_utils.py#L28 baseBig, ok := getBaseBig() if !ok { - return nil, fmt.Errorf("getBaseBig failed") + return *big.NewInt(0), fmt.Errorf("getBaseBig failed") } packedBig := new(big.Int) for idx, limb := range limbs { limbBig := AsInt(limb) - valueToAddBig := new(big.Int).Exp(baseBig, big.NewInt(int64(idx)), nil) + valueToAddBig := new(big.Int).Exp(&baseBig, big.NewInt(int64(idx)), nil) valueToAddBig.Mul(valueToAddBig, &limbBig) packedBig.Add(packedBig, valueToAddBig) } - return packedBig, nil + return *packedBig, nil } func GetBetaBig() big.Int { @@ -48,10 +50,10 @@ func GetNBig() big.Int { return *NBig } -func SecPSplit(num *big.Int) ([]*big.Int, error) { +func SecPSplit(num *big.Int) ([]big.Int, error) { // https://github.com/starkware-libs/cairo-lang/blob/efa9648f57568aad8f8a13fbf027d2de7c63c2c0/src/starkware/cairo/common/cairo_secp/secp_utils.py#L14 - split := make([]*big.Int, 3) + split := make([]big.Int, 3) baseBig, ok := getBaseBig() if !ok { @@ -60,8 +62,9 @@ func SecPSplit(num *big.Int) ([]*big.Int, error) { var residue big.Int for i := 0; i < 3; i++ { - num.DivMod(num, baseBig, &residue) - split[i] = new(big.Int).Set(&residue) + num.DivMod(num, &baseBig, &residue) + splitVal := new(big.Int).Set(&residue) + split[i] = *splitVal } if num.Cmp(big.NewInt(0)) != 0 { @@ -73,6 +76,6 @@ func SecPSplit(num *big.Int) ([]*big.Int, error) { func GetSecp256R1_P() (big.Int, bool) { // 2**256 - 2**224 + 2**192 + 2**96 - 1 - secp256r1_p, ok := new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10) - return *secp256r1_p, ok + secp256R1_P, ok := new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10) + return *secp256R1_P, ok } diff --git a/pkg/hintrunner/zero/hintcode.go b/pkg/hintrunner/zero/hintcode.go index 92a4c470b..c25fddfe6 100644 --- a/pkg/hintrunner/zero/hintcode.go +++ b/pkg/hintrunner/zero/hintcode.go @@ -63,6 +63,7 @@ const ( 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" fastEcAddAssignNewXCode string = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\n\nslope = pack(ids.slope, PRIME)\nx0 = pack(ids.point0.x, PRIME)\nx1 = pack(ids.point1.x, PRIME)\ny0 = pack(ids.point0.y, PRIME)\n\nvalue = new_x = (pow(slope, 2, SECP_P) - x0 - x1) % SECP_P" + ecDoubleSlopeV1Code string = "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)" // ------ Signature hints related code ------ verifyECDSASignatureCode string = "ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))" diff --git a/pkg/hintrunner/zero/zerohint.go b/pkg/hintrunner/zero/zerohint.go index dc9a8b145..b67f7f986 100644 --- a/pkg/hintrunner/zero/zerohint.go +++ b/pkg/hintrunner/zero/zerohint.go @@ -127,6 +127,8 @@ func GetHintFromCode(program *zero.ZeroProgram, rawHint zero.Hint, hintPC uint64 return createFastEcAddAssignNewYHinter() case fastEcAddAssignNewXCode: return createFastEcAddAssignNewXHinter(resolver) + case ecDoubleSlopeV1Code: + return createEcDoubleSlopeV1Hinter(resolver) // 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 d4bc8ed8a..5b99063d7 100644 --- a/pkg/hintrunner/zero/zerohint_ec.go +++ b/pkg/hintrunner/zero/zerohint_ec.go @@ -51,13 +51,13 @@ func newEcNegateHint(point hinter.ResOperander) hinter.Hinter { if err != nil { return err } - yBig.Mod(yBig, secPBig) + yBig.Mod(&yBig, &secPBig) //> value = (-y) % SECP_P - yBig.Neg(yBig) - yBig.Mod(yBig, secPBig) + yBig.Neg(&yBig) + yBig.Mod(&yBig, &secPBig) - return ctx.ScopeManager.AssignVariables(map[string]any{"value": yBig, "SECP_P": secPBig}) + return ctx.ScopeManager.AssignVariables(map[string]any{"value": &yBig, "SECP_P": &secPBig}) }, } } @@ -101,7 +101,7 @@ func newNondetBigint3V1Hint(res hinter.ResOperander) hinter.Hinter { return err } - valueFelt := new(fp.Element).SetBigInt(values[i]) + valueFelt := new(fp.Element).SetBigInt(&values[i]) valueMv := mem.MemoryValueFromFieldElement(valueFelt) err = vm.Memory.WriteToAddress(&valueAddr, &valueMv) @@ -277,15 +277,15 @@ func newFastEcAddAssignNewXHint(slope, point0, point1 hinter.ResOperander) hinte } new_xBig := new(big.Int) - new_xBig.Exp(slopeBig, big.NewInt(2), secPBig) - new_xBig.Sub(new_xBig, x0Big) - new_xBig.Sub(new_xBig, x1Big) - new_xBig.Mod(new_xBig, secPBig) + new_xBig.Exp(&slopeBig, big.NewInt(2), &secPBig) + new_xBig.Sub(new_xBig, &x0Big) + new_xBig.Sub(new_xBig, &x1Big) + new_xBig.Mod(new_xBig, &secPBig) valueBig := new(big.Int) valueBig.Set(new_xBig) - return ctx.ScopeManager.AssignVariables(map[string]any{"slope": slopeBig, "x0": x0Big, "x1": x1Big, "y0": y0Big, "new_x": new_xBig, "value": valueBig}) + return ctx.ScopeManager.AssignVariables(map[string]any{"slope": &slopeBig, "x0": &x0Big, "x1": &x1Big, "y0": &y0Big, "new_x": new_xBig, "value": valueBig}) }, } } @@ -306,3 +306,83 @@ func createFastEcAddAssignNewXHinter(resolver hintReferenceResolver) (hinter.Hin return newFastEcAddAssignNewXHint(slope, point0, point1), nil } + +func newEcDoubleSlopeV1Hint(point hinter.ResOperander) hinter.Hinter { + return &GenericZeroHinter{ + Name: "EcDoubleSlopeV1", + Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { + //> from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack + //> from starkware.python.math_utils import ec_double_slope + // + //> # Compute the slope. + //> x = pack(ids.point.x, PRIME) + //> y = pack(ids.point.y, PRIME) + //> value = slope = ec_double_slope(point=(x, y), alpha=0, p=SECP_P) + + pointAddr, err := point.GetAddress(vm) + if err != nil { + return err + } + pointMemoryValues, err := hinter.GetConsecutiveValues(vm, pointAddr, int16(6)) + if err != nil { + return err + } + + // [x.d0, x.d1, x.d2] + var pointXValues [3]*fp.Element + // [y.d0, y.d1, y.d2] + var pointYValues [3]*fp.Element + + for i := 0; i < 3; i++ { + pointValue, err := pointMemoryValues[i].FieldElement() + if err != nil { + return err + } + pointXValues[i] = pointValue + } + for i := 3; i < 6; i++ { + pointValue, err := pointMemoryValues[i].FieldElement() + if err != nil { + return err + } + pointYValues[i-3] = pointValue + } + + //> x = pack(ids.point.x, PRIME) + xBig, err := secp_utils.SecPPacked(pointXValues) + if err != nil { + return err + } + + //> y = pack(ids.point.y, PRIME) + yBig, err := secp_utils.SecPPacked(pointYValues) + if err != nil { + return err + } + + secPBig, ok := secp_utils.GetSecPBig() + if !ok { + return fmt.Errorf("GetSecPBig failed") + } + + //> value = slope = ec_double_slope(point=(x, y), alpha=0, p=SECP_P) + valueBig, err := secp_utils.EcDoubleSlope(&xBig, &yBig, big.NewInt(0), &secPBig) + if err != nil { + return err + } + + slopeBig := new(big.Int).Set(&valueBig) + + return ctx.ScopeManager.AssignVariables(map[string]any{"x": &xBig, "y": &yBig, "value": &valueBig, "slope": slopeBig}) + }, + } +} + +func createEcDoubleSlopeV1Hinter(resolver hintReferenceResolver) (hinter.Hinter, error) { + point, err := resolver.GetResOperander("point") + if err != nil { + return nil, err + } + + return newEcDoubleSlopeV1Hint(point), nil +} diff --git a/pkg/hintrunner/zero/zerohint_ec_test.go b/pkg/hintrunner/zero/zerohint_ec_test.go index b3884bca0..e229e6794 100644 --- a/pkg/hintrunner/zero/zerohint_ec_test.go +++ b/pkg/hintrunner/zero/zerohint_ec_test.go @@ -352,7 +352,7 @@ func TestZeroHintEc(t *testing.T) { 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}) + 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() @@ -371,7 +371,7 @@ func TestZeroHintEc(t *testing.T) { 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}) + 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() @@ -391,7 +391,7 @@ func TestZeroHintEc(t *testing.T) { 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}) + 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() @@ -409,18 +409,18 @@ func TestZeroHintEc(t *testing.T) { {Name: "slope.d0", Kind: apRelative, Value: feltString("64081873649130491683833713")}, {Name: "slope.d1", Kind: apRelative, Value: feltString("34843994309543177837008178")}, {Name: "slope.d2", Kind: apRelative, Value: feltString("16548672716077616016846383")}, - {Name: "point0.x.d0", Kind: apRelative, Value: feltString("51215")}, - {Name: "point0.x.d1", Kind: apRelative, Value: feltString("36848548548458")}, - {Name: "point0.x.d2", Kind: apRelative, Value: feltString("634734734")}, - {Name: "point0.y.d0", Kind: apRelative, Value: feltString("26362")}, - {Name: "point0.y.d1", Kind: apRelative, Value: feltString("263724839599")}, - {Name: "point0.y.d2", Kind: apRelative, Value: feltString("901297012")}, - {Name: "point1.x.d0", Kind: apRelative, Value: feltString("45789")}, - {Name: "point1.x.d1", Kind: apRelative, Value: feltString("45612238789798")}, - {Name: "point1.x.d2", Kind: apRelative, Value: feltString("214455666")}, - {Name: "point1.y.d0", Kind: apRelative, Value: feltString("12457")}, - {Name: "point1.y.d1", Kind: apRelative, Value: feltString("895645646464")}, - {Name: "point1.y.d2", Kind: apRelative, Value: feltString("211245645")}, + {Name: "point0.x.d0", Kind: apRelative, Value: feltUint64(51215)}, + {Name: "point0.x.d1", Kind: apRelative, Value: feltUint64(36848548548458)}, + {Name: "point0.x.d2", Kind: apRelative, Value: feltUint64(634734734)}, + {Name: "point0.y.d0", Kind: apRelative, Value: feltUint64(26362)}, + {Name: "point0.y.d1", Kind: apRelative, Value: feltUint64(263724839599)}, + {Name: "point0.y.d2", Kind: apRelative, Value: feltUint64(901297012)}, + {Name: "point1.x.d0", Kind: apRelative, Value: feltUint64(45789)}, + {Name: "point1.x.d1", Kind: apRelative, Value: feltUint64(45612238789798)}, + {Name: "point1.x.d2", Kind: apRelative, Value: feltUint64(214455666)}, + {Name: "point1.y.d0", Kind: apRelative, Value: feltUint64(12457)}, + {Name: "point1.y.d1", Kind: apRelative, Value: feltUint64(895645646464)}, + {Name: "point1.y.d2", Kind: apRelative, Value: feltUint64(211245645)}, }, ctxInit: func(ctx *hinter.HintRunnerContext) { ctx.ScopeManager.EnterScope(map[string]any{}) @@ -505,5 +505,93 @@ func TestZeroHintEc(t *testing.T) { }), }, }, + "EcDoubleSlopeV1": { + { + operanders: []*hintOperander{ + {Name: "point.x.d0", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "point.x.d1", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "point.x.d2", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "point.y.d0", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "point.y.d1", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "point.y.d2", Kind: apRelative, Value: &utils.FeltZero}, + }, + ctxInit: func(ctx *hinter.HintRunnerContext) { + hinter.InitializeScopeManager(ctx, map[string]any{}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newEcDoubleSlopeV1Hint(ctx.operanders["point.x.d0"]) + }, + errCheck: errorTextContains("point[1] % p == 0"), + }, + { + operanders: []*hintOperander{ + // values are random + {Name: "point.x.d0", Kind: apRelative, Value: feltUint64(51215)}, + {Name: "point.x.d1", Kind: apRelative, Value: feltUint64(368485485484584)}, + {Name: "point.x.d2", Kind: apRelative, Value: feltUint64(4564564687987)}, + {Name: "point.y.d0", Kind: apRelative, Value: feltUint64(26362)}, + {Name: "point.y.d1", Kind: apRelative, Value: feltUint64(263724839599)}, + {Name: "point.y.d2", Kind: apRelative, Value: feltString("1321654896123789784652346")}, + }, + ctxInit: func(ctx *hinter.HintRunnerContext) { + hinter.InitializeScopeManager(ctx, map[string]any{}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newEcDoubleSlopeV1Hint(ctx.operanders["point.x.d0"]) + }, + check: allVarValueInScopeEquals(map[string]any{ + "x": bigIntString("27324902462242089002202715756360945650502697953428275540292323343", 10), + "y": bigIntString("7911836854973739773537612350570845963794165335703809150610926758199350552314", 10), + "value": bigIntString("8532480558268366897328020348259450788170980412191993744326748439943456131995", 10), + "slope": bigIntString("8532480558268366897328020348259450788170980412191993744326748439943456131995", 10), + }), + }, + { + operanders: []*hintOperander{ + // 2**80 + {Name: "point.x.d0", Kind: apRelative, Value: feltString("1208925819614629174706176")}, + {Name: "point.x.d1", Kind: apRelative, Value: feltString("1208925819614629174706176")}, + {Name: "point.x.d2", Kind: apRelative, Value: feltString("1208925819614629174706176")}, + // 2**40 + {Name: "point.y.d0", Kind: apRelative, Value: feltUint64(1099511627776)}, + {Name: "point.y.d1", Kind: apRelative, Value: feltUint64(1099511627776)}, + {Name: "point.y.d2", Kind: apRelative, Value: feltUint64(1099511627776)}, + }, + ctxInit: func(ctx *hinter.HintRunnerContext) { + hinter.InitializeScopeManager(ctx, map[string]any{}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newEcDoubleSlopeV1Hint(ctx.operanders["point.x.d0"]) + }, + check: allVarValueInScopeEquals(map[string]any{ + "x": bigIntString("7237005577332262213973186656579099030007160806638365755234031873103428059136", 10), + "y": bigIntString("6582018229284824168619876815299993750165559328377972410848116736", 10), + "value": bigIntString("154266052248863066452028362858593603519505739480817180031844352", 10), + "slope": bigIntString("154266052248863066452028362858593603519505739480817180031844352", 10), + }), + }, + { + operanders: []*hintOperander{ + {Name: "point.x.d0", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "point.x.d1", Kind: apRelative, Value: &utils.FeltOne}, + {Name: "point.x.d2", Kind: apRelative, Value: feltUint64(2)}, + {Name: "point.y.d0", Kind: apRelative, Value: feltUint64(3)}, + {Name: "point.y.d1", Kind: apRelative, Value: feltUint64(4)}, + {Name: "point.y.d2", Kind: apRelative, Value: feltUint64(5)}, + }, + ctxInit: func(ctx *hinter.HintRunnerContext) { + hinter.InitializeScopeManager(ctx, map[string]any{}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newEcDoubleSlopeV1Hint(ctx.operanders["point.x.d0"]) + }, + check: allVarValueInScopeEquals(map[string]any{ + "x": bigIntString("11972621413014756705924586226983042952357666573254656", 10), + "y": bigIntString("29931553532536891764811465683514486063898567204929539", 10), + "value": bigIntString("35023503208535022533116513151423452638642669107476233313413226008091253006355", 10), + "slope": bigIntString("35023503208535022533116513151423452638642669107476233313413226008091253006355", 10), + }), + }, + }, }) } diff --git a/pkg/hintrunner/zero/zerohint_signature.go b/pkg/hintrunner/zero/zerohint_signature.go index 0e3a9c4b7..1d9f86dab 100644 --- a/pkg/hintrunner/zero/zerohint_signature.go +++ b/pkg/hintrunner/zero/zerohint_signature.go @@ -7,6 +7,7 @@ import ( "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter" secp_utils "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/utils" VM "github.com/NethermindEth/cairo-vm-go/pkg/vm" + "github.com/NethermindEth/cairo-vm-go/pkg/vm/builtins" "github.com/NethermindEth/cairo-vm-go/pkg/vm/memory" "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" ) @@ -53,7 +54,7 @@ func newVerifyZeroHint(val, q hinter.ResOperander) hinter.Hinter { return err } qBig, rBig := new(big.Int), new(big.Int) - qBig.DivMod(packedValue, secPBig, rBig) + qBig.DivMod(&packedValue, &secPBig, rBig) //> assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." if rBig.Cmp(big.NewInt(0)) != 0 { @@ -85,3 +86,185 @@ func createVerifyZeroHinter(resolver hintReferenceResolver) (hinter.Hinter, erro return newVerifyZeroHint(val, q), nil } + +func newVerifyECDSASignatureHinter(ecdsaPtr, signature_r, signature_s hinter.ResOperander) hinter.Hinter { + return &GenericZeroHinter{ + Name: "VerifyECDSASignature", + Op: func(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error { + //> ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s)) + ecdsaPtrAddr, err := hinter.ResolveAsAddress(vm, ecdsaPtr) + if err != nil { + return err + } + signature_rFelt, err := hinter.ResolveAsFelt(vm, signature_r) + if err != nil { + return err + } + signature_sFelt, err := hinter.ResolveAsFelt(vm, signature_s) + if err != nil { + return err + } + ECDSA_segment, ok := vm.Memory.FindSegmentWithBuiltin(builtins.ECDSAName) + if !ok { + return fmt.Errorf("ECDSA segment not found") + } + ECDSA_builtinRunner := (ECDSA_segment.BuiltinRunner).(*builtins.ECDSA) + return ECDSA_builtinRunner.AddSignature(ecdsaPtrAddr.Offset, signature_rFelt, signature_sFelt) + }, + } +} + +func createVerifyECDSASignatureHinter(resolver hintReferenceResolver) (hinter.Hinter, error) { + ecdsaPtr, err := resolver.GetResOperander("ecdsa_ptr") + if err != nil { + return nil, err + } + signature_r, err := resolver.GetResOperander("signature_r") + if err != nil { + return nil, err + } + signature_s, err := resolver.GetResOperander("signature_s") + if err != nil { + return nil, err + } + return newVerifyECDSASignatureHinter(ecdsaPtr, signature_r, signature_s), nil +} + +func newGetPointFromXHinter(xCube, v hinter.ResOperander) hinter.Hinter { + return &GenericZeroHinter{ + Name: "VerifyECDSASignature", + Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { + //> from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack + //> x_cube_int = pack(ids.x_cube, PRIME) % SECP_P + //> y_square_int = (x_cube_int + ids.BETA) % SECP_P + //> y = pow(y_square_int, (SECP_P + 1) // 4, SECP_P) + //> if ids.v % 2 == y % 2: + //> value = y + //> else: + //> value = (-y) % SECP_P + xCubeAddr, err := xCube.GetAddress(vm) + if err != nil { + return err + } + + xCubeMemoryValues, err := hinter.GetConsecutiveValues(vm, xCubeAddr, 3) + if err != nil { + return err + } + v, err := hinter.ResolveAsFelt(vm, v) + if err != nil { + return err + } + + //> from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack + secpBig, _ := secp_utils.GetSecPBig() + + //> x_cube_int = pack(ids.x_cube, PRIME) % SECP_P + var xCubeValues [3]*fp.Element + for i := 0; i < 3; i++ { + xCubeValues[i], err = xCubeMemoryValues[i].FieldElement() + if err != nil { + return err + } + } + xCubeIntBig, err := secp_utils.SecPPacked(xCubeValues) + if err != nil { + return err + } + xCubeIntBig.Mod(&xCubeIntBig, &secpBig) + + //> y_square_int = (x_cube_int + ids.BETA) % SECP_P + betaBig := secp_utils.GetBetaBig() + ySquareIntBig := new(big.Int).Add(&xCubeIntBig, &betaBig) + ySquareIntBig.Mod(ySquareIntBig, &secpBig) + + //> y = pow(y_square_int, (SECP_P + 1) // 4, SECP_P) + exponent := new(big.Int).Div(new(big.Int).Add(&secpBig, big.NewInt(1)), big.NewInt(4)) + y := new(big.Int).Exp(ySquareIntBig, exponent, &secpBig) + vBig := v.BigInt(new(big.Int)) + + //> if ids.v % 2 == y % 2: + //> value = y + //> else: + //> value = (-y) % SECP_P + value := new(big.Int) + if vBig.Bit(0) == y.Bit(0) { + value.Set(y) + } else { + value.Mod(value.Neg(y), &secpBig) + } + return ctx.ScopeManager.AssignVariable("value", value) + }, + } +} + +func createGetPointFromXHinter(resolver hintReferenceResolver) (hinter.Hinter, error) { + xCube, err := resolver.GetResOperander("x_cube") + if err != nil { + return nil, err + } + v, err := resolver.GetResOperander("v") + if err != nil { + return nil, err + } + return newGetPointFromXHinter(xCube, v), nil +} + +func newImportSecp256R1PHinter() hinter.Hinter { + return &GenericZeroHinter{ + Name: "Secp256R1", + Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { + //> from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P + SECP256R1_PBig, ok := secp_utils.GetSecp256R1_P() + if !ok { + return fmt.Errorf("SECP256R1_P failed.") + } + return ctx.ScopeManager.AssignVariable("SECP_P", &SECP256R1_PBig) + }, + } +} + +func createImportSecp256R1PHinter() (hinter.Hinter, error) { + return newImportSecp256R1PHinter(), nil +} + +func newDivModSafeDivHinter() hinter.Hinter { + return &GenericZeroHinter{ + Name: "DivModSafeDivHinter", + Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { + //> value = k = safe_div(res * b - a, N) + + res, err := ctx.ScopeManager.GetVariableValueAsBigInt("res") + if err != nil { + return err + } + a, err := ctx.ScopeManager.GetVariableValueAsBigInt("a") + if err != nil { + return err + } + b, err := ctx.ScopeManager.GetVariableValueAsBigInt("b") + if err != nil { + return err + } + N, err := ctx.ScopeManager.GetVariableValueAsBigInt("N") + if err != nil { + return err + } + divisor := new(big.Int).Sub(new(big.Int).Mul(res, b), a) + value, err := secp_utils.SafeDiv(divisor, N) + if err != nil { + return err + } + k := new(big.Int).Set(&value) + err = ctx.ScopeManager.AssignVariable("k", k) + if err != nil { + return err + } + return ctx.ScopeManager.AssignVariable("value", &value) + }, + } +} + +func createDivModSafeDivHinter() (hinter.Hinter, error) { + return newDivModSafeDivHinter(), nil +} diff --git a/pkg/hintrunner/zero/zerohint_signature_test.go b/pkg/hintrunner/zero/zerohint_signature_test.go index a29c02dee..7be3c77fa 100644 --- a/pkg/hintrunner/zero/zerohint_signature_test.go +++ b/pkg/hintrunner/zero/zerohint_signature_test.go @@ -4,7 +4,9 @@ import ( "testing" "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter" + "github.com/NethermindEth/cairo-vm-go/pkg/parsers/starknet" "github.com/NethermindEth/cairo-vm-go/pkg/utils" + "github.com/stretchr/testify/require" ) func TestVerifyZeroHint(t *testing.T) { @@ -48,5 +50,154 @@ func TestVerifyZeroHint(t *testing.T) { check: varValueEquals("q", feltInt64(1)), }, }, + "VerifyECDSASignature": { + { + operanders: []*hintOperander{ + {Name: "ecdsaPtr", Kind: reference, Value: addrBuiltin(starknet.ECDSA, 0)}, + {Name: "signature_r", Kind: apRelative, Value: feltString("3086480810278599376317923499561306189851900463386393948998357832163236918254")}, + {Name: "signature_s", Kind: apRelative, Value: feltString("598673427589502599949712887611119751108407514580626464031881322743364689811")}, + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + ecdsaPtr := ctx.operanders["ecdsaPtr"].(*hinter.DoubleDeref).Deref + return newVerifyECDSASignatureHinter(ecdsaPtr, ctx.operanders["signature_r"], ctx.operanders["signature_s"]) + }, + errCheck: func(t *testing.T, ctx *hintTestContext, err error) { + require.NoError(t, err) + }, + }, + }, + "GetPointFromX": { + { + //> if v % 2 == y % 2 + operanders: []*hintOperander{ + {Name: "xCube.d0", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "xCube.d1", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "xCube.d2", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "v", Kind: apRelative, Value: &utils.FeltZero}, + }, + ctxInit: func(ctx *hinter.HintRunnerContext) { + ctx.ScopeManager.EnterScope(map[string]any{}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newGetPointFromXHinter(ctx.operanders["xCube.d0"], ctx.operanders["v"]) + }, + check: varValueInScopeEquals("value", bigIntString("64828261740814840065360381756190772627110652128289340260788836867053167272156", 10)), + }, + // if v % 2 != y % 2: + { + operanders: []*hintOperander{ + {Name: "xCube.d0", Kind: apRelative, Value: &utils.FeltOne}, + {Name: "xCube.d1", Kind: apRelative, Value: &utils.FeltOne}, + {Name: "xCube.d2", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "v", Kind: apRelative, Value: &utils.FeltZero}, + }, + ctxInit: func(ctx *hinter.HintRunnerContext) { + ctx.ScopeManager.EnterScope(map[string]any{}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newGetPointFromXHinter(ctx.operanders["xCube.d0"], ctx.operanders["v"]) + }, + check: varValueInScopeEquals("value", bigIntString("3754707778961574900176639079436749683878498834289427635045629810524611907876", 10)), + }, + // values are 2**86 BASE + { + operanders: []*hintOperander{ + {Name: "xCube.d0", Kind: apRelative, Value: feltString("77371252455336267181195264")}, + {Name: "xCube.d1", Kind: apRelative, Value: feltString("77371252455336267181195264")}, + {Name: "xCube.d2", Kind: apRelative, Value: feltString("77371252455336267181195264")}, + {Name: "v", Kind: apRelative, Value: feltString("77371252455336267181195264")}, + }, + ctxInit: func(ctx *hinter.HintRunnerContext) { + ctx.ScopeManager.EnterScope(map[string]any{}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newGetPointFromXHinter(ctx.operanders["xCube.d0"], ctx.operanders["v"]) + }, + check: varValueInScopeEquals("value", bigIntString("64330220386510520462271671435567806262107470356169873352512014089172394266548", 10)), + }, + }, + "ImportSecp256R1P": { + { + operanders: []*hintOperander{}, + ctxInit: func(ctx *hinter.HintRunnerContext) { + hinter.InitializeScopeManager(ctx, map[string]any{}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newImportSecp256R1PHinter() + }, + check: varValueInScopeEquals("SECP_P", bigIntString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)), + }, + }, + "DivModNSafeDivHint": { + { + // zero quotient + operanders: []*hintOperander{}, + ctxInit: func(ctx *hinter.HintRunnerContext) { + ctx.ScopeManager.EnterScope(map[string]any{}) + err := ctx.ScopeManager.AssignVariables(map[string]any{ + "res": bigIntString("0", 10), + "a": bigIntString("0", 10), + "b": bigIntString("0", 10), + "N": bigIntString("1", 10), + }) + if err != nil { + t.Fatal(err) + } + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newDivModSafeDivHinter() + }, + check: varListInScopeEquals(map[string]any{ + "value": bigIntString("0", 10), + "k": bigIntString("0", 10), + }), + }, + { + // negative quotient + operanders: []*hintOperander{}, + ctxInit: func(ctx *hinter.HintRunnerContext) { + ctx.ScopeManager.EnterScope(map[string]any{}) + err := ctx.ScopeManager.AssignVariables(map[string]any{ + "res": bigIntString("1", 10), + "a": bigIntString("2", 10), + "b": bigIntString("1", 10), + "N": bigIntString("1", 10), + }) + if err != nil { + t.Fatal(err) + } + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newDivModSafeDivHinter() + }, + check: varListInScopeEquals(map[string]any{ + "value": bigIntString("-1", 10), + "k": bigIntString("-1", 10), + }), + }, + { + // positive quotient + operanders: []*hintOperander{}, + ctxInit: func(ctx *hinter.HintRunnerContext) { + ctx.ScopeManager.EnterScope(map[string]any{}) + err := ctx.ScopeManager.AssignVariables(map[string]any{ + "res": bigIntString("10", 10), + "a": bigIntString("20", 10), + "b": bigIntString("30", 10), + "N": bigIntString("2", 10), + }) + if err != nil { + t.Fatal(err) + } + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newDivModSafeDivHinter() + }, + check: varListInScopeEquals(map[string]any{ + "value": bigIntString("140", 10), + "k": bigIntString("140", 10), + }), + }, + }, }) } diff --git a/pkg/hintrunner/zero/zerohint_signatures.go b/pkg/hintrunner/zero/zerohint_signatures.go deleted file mode 100644 index f17beb55d..000000000 --- a/pkg/hintrunner/zero/zerohint_signatures.go +++ /dev/null @@ -1,194 +0,0 @@ -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" - VM "github.com/NethermindEth/cairo-vm-go/pkg/vm" - "github.com/NethermindEth/cairo-vm-go/pkg/vm/builtins" - "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" -) - -func newVerifyECDSASignatureHinter(ecdsaPtr, signature_r, signature_s hinter.ResOperander) hinter.Hinter { - return &GenericZeroHinter{ - Name: "VerifyECDSASignature", - Op: func(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error { - //> ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s)) - ecdsaPtrAddr, err := hinter.ResolveAsAddress(vm, ecdsaPtr) - if err != nil { - return err - } - signature_rFelt, err := hinter.ResolveAsFelt(vm, signature_r) - if err != nil { - return err - } - signature_sFelt, err := hinter.ResolveAsFelt(vm, signature_s) - if err != nil { - return err - } - ECDSA_segment, ok := vm.Memory.FindSegmentWithBuiltin(builtins.ECDSAName) - if !ok { - return fmt.Errorf("ECDSA segment not found") - } - ECDSA_builtinRunner := (ECDSA_segment.BuiltinRunner).(*builtins.ECDSA) - return ECDSA_builtinRunner.AddSignature(ecdsaPtrAddr.Offset, signature_rFelt, signature_sFelt) - }, - } -} - -func createVerifyECDSASignatureHinter(resolver hintReferenceResolver) (hinter.Hinter, error) { - ecdsaPtr, err := resolver.GetResOperander("ecdsa_ptr") - if err != nil { - return nil, err - } - signature_r, err := resolver.GetResOperander("signature_r") - if err != nil { - return nil, err - } - signature_s, err := resolver.GetResOperander("signature_s") - if err != nil { - return nil, err - } - return newVerifyECDSASignatureHinter(ecdsaPtr, signature_r, signature_s), nil -} - -func newGetPointFromXHinter(xCube, v hinter.ResOperander) hinter.Hinter { - return &GenericZeroHinter{ - Name: "VerifyECDSASignature", - Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { - //> from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack - //> x_cube_int = pack(ids.x_cube, PRIME) % SECP_P - //> y_square_int = (x_cube_int + ids.BETA) % SECP_P - //> y = pow(y_square_int, (SECP_P + 1) // 4, SECP_P) - //> if ids.v % 2 == y % 2: - //> value = y - //> else: - //> value = (-y) % SECP_P - xCubeAddr, err := xCube.GetAddress(vm) - if err != nil { - return err - } - - xCubeMemoryValues, err := hinter.GetConsecutiveValues(vm, xCubeAddr, 3) - if err != nil { - return err - } - v, err := hinter.ResolveAsFelt(vm, v) - if err != nil { - return err - } - - //> from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack - secpBig, _ := secp_utils.GetSecPBig() - - //> x_cube_int = pack(ids.x_cube, PRIME) % SECP_P - var xCubeValues [3]*fp.Element - for i := 0; i < 3; i++ { - xCubeValues[i], err = xCubeMemoryValues[i].FieldElement() - if err != nil { - return err - } - } - xCubeIntBig, err := secp_utils.SecPPacked(xCubeValues) - if err != nil { - return err - } - xCubeIntBig.Mod(xCubeIntBig, secpBig) - - //> y_square_int = (x_cube_int + ids.BETA) % SECP_P - betaBig := secp_utils.GetBetaBig() - ySquareIntBig := new(big.Int).Add(xCubeIntBig, &betaBig) - ySquareIntBig.Mod(ySquareIntBig, secpBig) - - //> y = pow(y_square_int, (SECP_P + 1) // 4, SECP_P) - exponent := new(big.Int).Div(new(big.Int).Add(secpBig, big.NewInt(1)), big.NewInt(4)) - y := new(big.Int).Exp(ySquareIntBig, exponent, secpBig) - vBig := v.BigInt(new(big.Int)) - - //> if ids.v % 2 == y % 2: - //> value = y - //> else: - //> value = (-y) % SECP_P - value := new(big.Int) - if vBig.Bit(0) == y.Bit(0) { - value.Set(y) - } else { - value.Mod(value.Neg(y), secpBig) - } - return ctx.ScopeManager.AssignVariable("value", value) - }, - } -} - -func createGetPointFromXHinter(resolver hintReferenceResolver) (hinter.Hinter, error) { - xCube, err := resolver.GetResOperander("x_cube") - if err != nil { - return nil, err - } - v, err := resolver.GetResOperander("v") - if err != nil { - return nil, err - } - return newGetPointFromXHinter(xCube, v), nil -} - -func newDivModSafeDivHinter() hinter.Hinter { - return &GenericZeroHinter{ - Name: "DivModSafeDivHinter", - Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { - //> value = k = safe_div(res * b - a, N) - - res, err := ctx.ScopeManager.GetVariableValueAsBigInt("res") - if err != nil { - return err - } - a, err := ctx.ScopeManager.GetVariableValueAsBigInt("a") - if err != nil { - return err - } - b, err := ctx.ScopeManager.GetVariableValueAsBigInt("b") - if err != nil { - return err - } - N, err := ctx.ScopeManager.GetVariableValueAsBigInt("N") - if err != nil { - return err - } - divisor := new(big.Int).Sub(new(big.Int).Mul(res, b), a) - value, err := secp_utils.SafeDiv(divisor, N) - if err != nil { - return err - } - k := new(big.Int).Set(&value) - err = ctx.ScopeManager.AssignVariable("k", k) - if err != nil { - return err - } - return ctx.ScopeManager.AssignVariable("value", &value) - }, - } -} - -func createDivModSafeDivHinter() (hinter.Hinter, error) { - return newDivModSafeDivHinter(), nil -} - -func newImportSecp256R1PHinter() hinter.Hinter { - return &GenericZeroHinter{ - Name: "Secp256R1", - Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { - //> from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P - SECP256R1_PBig, ok := secp_utils.GetSecp256R1_P() - if !ok { - return fmt.Errorf("SECP256R1_P failed.") - } - return ctx.ScopeManager.AssignVariable("SECP_P", &SECP256R1_PBig) - }, - } -} - -func createImportSecp256R1PHinter() (hinter.Hinter, error) { - return newImportSecp256R1PHinter(), nil -} diff --git a/pkg/hintrunner/zero/zerohint_signatures_test.go b/pkg/hintrunner/zero/zerohint_signatures_test.go deleted file mode 100644 index e91c30707..000000000 --- a/pkg/hintrunner/zero/zerohint_signatures_test.go +++ /dev/null @@ -1,165 +0,0 @@ -package zero - -import ( - "testing" - - "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter" - "github.com/NethermindEth/cairo-vm-go/pkg/parsers/starknet" - "github.com/NethermindEth/cairo-vm-go/pkg/utils" - - "github.com/stretchr/testify/require" -) - -func TestSignatures(t *testing.T) { - runHinterTests(t, map[string][]hintTestCase{ - "VerifyECDSASignature": { - { - operanders: []*hintOperander{ - {Name: "ecdsaPtr", Kind: reference, Value: addrBuiltin(starknet.ECDSA, 0)}, - {Name: "signature_r", Kind: apRelative, Value: feltString("3086480810278599376317923499561306189851900463386393948998357832163236918254")}, - {Name: "signature_s", Kind: apRelative, Value: feltString("598673427589502599949712887611119751108407514580626464031881322743364689811")}, - }, - makeHinter: func(ctx *hintTestContext) hinter.Hinter { - ecdsaPtr := ctx.operanders["ecdsaPtr"].(*hinter.DoubleDeref).Deref - return newVerifyECDSASignatureHinter(ecdsaPtr, ctx.operanders["signature_r"], ctx.operanders["signature_s"]) - }, - errCheck: func(t *testing.T, ctx *hintTestContext, err error) { - require.NoError(t, err) - }, - }, - }, - "GetPointFromX": { - { - //> if v % 2 == y % 2 - operanders: []*hintOperander{ - {Name: "xCube.d0", Kind: apRelative, Value: &utils.FeltZero}, - {Name: "xCube.d1", Kind: apRelative, Value: &utils.FeltZero}, - {Name: "xCube.d2", Kind: apRelative, Value: &utils.FeltZero}, - {Name: "v", Kind: apRelative, Value: &utils.FeltZero}, - }, - ctxInit: func(ctx *hinter.HintRunnerContext) { - ctx.ScopeManager.EnterScope(map[string]any{}) - }, - makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newGetPointFromXHinter(ctx.operanders["xCube.d0"], ctx.operanders["v"]) - }, - check: varValueInScopeEquals("value", bigIntString("64828261740814840065360381756190772627110652128289340260788836867053167272156", 10)), - }, - { - // if v % 2 != y % 2: - operanders: []*hintOperander{ - {Name: "xCube.d0", Kind: apRelative, Value: &utils.FeltOne}, - {Name: "xCube.d1", Kind: apRelative, Value: &utils.FeltOne}, - {Name: "xCube.d2", Kind: apRelative, Value: &utils.FeltZero}, - {Name: "v", Kind: apRelative, Value: &utils.FeltZero}, - }, - ctxInit: func(ctx *hinter.HintRunnerContext) { - ctx.ScopeManager.EnterScope(map[string]any{}) - }, - makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newGetPointFromXHinter(ctx.operanders["xCube.d0"], ctx.operanders["v"]) - }, - check: varValueInScopeEquals("value", bigIntString("3754707778961574900176639079436749683878498834289427635045629810524611907876", 10)), - }, - { - // values are 2**86 BASE - operanders: []*hintOperander{ - {Name: "xCube.d0", Kind: apRelative, Value: feltString("77371252455336267181195264")}, - {Name: "xCube.d1", Kind: apRelative, Value: feltString("77371252455336267181195264")}, - {Name: "xCube.d2", Kind: apRelative, Value: feltString("77371252455336267181195264")}, - {Name: "v", Kind: apRelative, Value: feltString("77371252455336267181195264")}, - }, - ctxInit: func(ctx *hinter.HintRunnerContext) { - ctx.ScopeManager.EnterScope(map[string]any{}) - }, - makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newGetPointFromXHinter(ctx.operanders["xCube.d0"], ctx.operanders["v"]) - }, - check: varValueInScopeEquals("value", bigIntString("64330220386510520462271671435567806262107470356169873352512014089172394266548", 10)), - }, - }, - "DivModNSafeDivHint": { - { - // zero quotient - operanders: []*hintOperander{}, - ctxInit: func(ctx *hinter.HintRunnerContext) { - ctx.ScopeManager.EnterScope(map[string]any{}) - err := ctx.ScopeManager.AssignVariables(map[string]any{ - "res": bigIntString("0", 10), - "a": bigIntString("0", 10), - "b": bigIntString("0", 10), - "N": bigIntString("1", 10), - }) - if err != nil { - t.Fatal(err) - } - }, - makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newDivModSafeDivHinter() - }, - check: varListInScopeEquals(map[string]any{ - "value": bigIntString("0", 10), - "k": bigIntString("0", 10), - }), - }, - { - // negative quotient - operanders: []*hintOperander{}, - ctxInit: func(ctx *hinter.HintRunnerContext) { - ctx.ScopeManager.EnterScope(map[string]any{}) - err := ctx.ScopeManager.AssignVariables(map[string]any{ - "res": bigIntString("1", 10), - "a": bigIntString("2", 10), - "b": bigIntString("1", 10), - "N": bigIntString("1", 10), - }) - if err != nil { - t.Fatal(err) - } - }, - makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newDivModSafeDivHinter() - }, - check: varListInScopeEquals(map[string]any{ - "value": bigIntString("-1", 10), - "k": bigIntString("-1", 10), - }), - }, - { - // positive quotient - operanders: []*hintOperander{}, - ctxInit: func(ctx *hinter.HintRunnerContext) { - ctx.ScopeManager.EnterScope(map[string]any{}) - err := ctx.ScopeManager.AssignVariables(map[string]any{ - "res": bigIntString("10", 10), - "a": bigIntString("20", 10), - "b": bigIntString("30", 10), - "N": bigIntString("2", 10), - }) - if err != nil { - t.Fatal(err) - } - }, - makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newDivModSafeDivHinter() - }, - check: varListInScopeEquals(map[string]any{ - "value": bigIntString("140", 10), - "k": bigIntString("140", 10), - }), - }, - }, - "ImportSecp256R1P": { - { - operanders: []*hintOperander{}, - ctxInit: func(ctx *hinter.HintRunnerContext) { - hinter.InitializeScopeManager(ctx, map[string]any{}) - }, - makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newImportSecp256R1PHinter() - }, - check: varValueInScopeEquals("SECP_P", bigIntString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)), - }, - }, - }) -}