diff --git a/pkg/hintrunner/utils/math_utils.go b/pkg/hintrunner/utils/math_utils.go index fa4eee43..70fe0f79 100644 --- a/pkg/hintrunner/utils/math_utils.go +++ b/pkg/hintrunner/utils/math_utils.go @@ -23,7 +23,7 @@ func EcDoubleSlope(pointX, pointY, alpha, prime *big.Int) (big.Int, error) { m := big.NewInt(2) m.Mul(m, pointY) - return divmod(n, m, prime) + return Divmod(n, m, prime) } func AsInt(valueFelt *fp.Element) big.Int { @@ -44,7 +44,7 @@ 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) { +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) diff --git a/pkg/hintrunner/utils/math_utils_test.go b/pkg/hintrunner/utils/math_utils_test.go index dae76dc5..8ad73cac 100644 --- a/pkg/hintrunner/utils/math_utils_test.go +++ b/pkg/hintrunner/utils/math_utils_test.go @@ -31,7 +31,7 @@ func TestDivMod(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - actual, err := divmod(tt.n, tt.m, tt.p) + actual, err := Divmod(tt.n, tt.m, tt.p) if err != nil { if err.Error() != tt.expectedErrMsg { diff --git a/pkg/hintrunner/utils/secp_utils.go b/pkg/hintrunner/utils/secp_utils.go index b1db73f5..4e5e57dc 100644 --- a/pkg/hintrunner/utils/secp_utils.go +++ b/pkg/hintrunner/utils/secp_utils.go @@ -20,6 +20,12 @@ func GetSecPBig() (big.Int, bool) { return *secP, ok } +func GetN() (big.Int, bool) { + // 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 + n, ok := new(big.Int).SetString("115792089237316195423570985008687907852837564279074904382605163141518161494337", 10) + return *n, ok +} + 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 @@ -43,13 +49,6 @@ func GetBetaBig() big.Int { return *big.NewInt(7) } -func GetNBig() big.Int { - // https://github.com/starkware-libs/cairo-lang/blob/efa9648f57568aad8f8a13fbf027d2de7c63c2c0/src/starkware/cairo/common/cairo_secp/secp_utils.py#L9 - - NBig, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16) - return *NBig -} - 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 @@ -57,7 +56,7 @@ func SecPSplit(num *big.Int) ([]big.Int, error) { baseBig, ok := getBaseBig() if !ok { - return nil, fmt.Errorf("getBaseBig failed") + return nil, fmt.Errorf("GetBaseBig failed") } var residue big.Int diff --git a/pkg/hintrunner/zero/hintcode.go b/pkg/hintrunner/zero/hintcode.go index f7a05b01..71a6fca2 100644 --- a/pkg/hintrunner/zero/hintcode.go +++ b/pkg/hintrunner/zero/hintcode.go @@ -66,11 +66,12 @@ const ( 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))" - getPointFromXCode string = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\nx_cube_int = pack(ids.x_cube, PRIME) % SECP_P\ny_square_int = (x_cube_int + ids.BETA) % SECP_P\ny = pow(y_square_int, (SECP_P + 1) // 4, SECP_P)\nif ids.v % 2 == y % 2:\nvalue = y\nelse:\nvalue = (-y) % SECP_P" - divModNSafeDivCode string = "value = k = safe_div(res * b - a, N)" - importSecp256R1PCode string = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P" - verifyZeroCode string = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\n\nq, r = divmod(pack(ids.val, PRIME), SECP_P)\nassert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"\nids.q = q % PRIME" + verifyECDSASignatureCode string = "ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))" + getPointFromXCode string = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\nx_cube_int = pack(ids.x_cube, PRIME) % SECP_P\ny_square_int = (x_cube_int + ids.BETA) % SECP_P\ny = pow(y_square_int, (SECP_P + 1) // 4, SECP_P)\nif ids.v % 2 == y % 2:\nvalue = y\nelse:\nvalue = (-y) % SECP_P" + divModNSafeDivCode string = "value = k = safe_div(res * b - a, N)" + importSecp256R1PCode string = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P" + verifyZeroCode string = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\n\nq, r = divmod(pack(ids.val, PRIME), SECP_P)\nassert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"\nids.q = q % PRIME" + divModNPackedDivmodV1Code string = "from starkware.cairo.common.cairo_secp.secp_utils import N, pack\nfrom starkware.python.math_utils import div_mod, safe_div\n\na = pack(ids.a, PRIME)\nb = pack(ids.b, PRIME)\nvalue = res = div_mod(a, b, N)" // ------ Blake Hash hints related code ------ blake2sAddUint256BigendCode string = "B = 32\nMASK = 2 ** 32 - 1\nsegments.write_arg(ids.data, [(ids.high >> (B * (3 - i))) & MASK for i in range(4)])\nsegments.write_arg(ids.data + 4, [(ids.low >> (B * (3 - i))) & MASK for i in range(4)])" diff --git a/pkg/hintrunner/zero/zerohint.go b/pkg/hintrunner/zero/zerohint.go index 3d817f07..35ebdd7d 100644 --- a/pkg/hintrunner/zero/zerohint.go +++ b/pkg/hintrunner/zero/zerohint.go @@ -118,6 +118,8 @@ func GetHintFromCode(program *zero.ZeroProgram, rawHint zero.Hint, hintPC uint64 return createImportSecp256R1PHinter() case verifyZeroCode: return createVerifyZeroHinter(resolver) + case divModNPackedDivmodV1Code: + return createDivModNPackedDivmodV1Hinter(resolver) // EC hints case ecNegateCode: return createEcNegateHinter(resolver) diff --git a/pkg/hintrunner/zero/zerohint_signature.go b/pkg/hintrunner/zero/zerohint_signature.go index 1d9f86da..107d07ac 100644 --- a/pkg/hintrunner/zero/zerohint_signature.go +++ b/pkg/hintrunner/zero/zerohint_signature.go @@ -268,3 +268,90 @@ func newDivModSafeDivHinter() hinter.Hinter { func createDivModSafeDivHinter() (hinter.Hinter, error) { return newDivModSafeDivHinter(), nil } + +func newDivModNPackedDivmodV1Hint(a, b hinter.ResOperander) hinter.Hinter { + return &GenericZeroHinter{ + Name: "DivModNPackedDivmodV1", + Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { + //> from starkware.cairo.common.cairo_secp.secp_utils import N, pack + //> from starkware.python.math_utils import div_mod, safe_div + //> a = pack(ids.a, PRIME) + //> b = pack(ids.b, PRIME) + //> value = res = div_mod(a, b, N) + + aAddr, err := a.GetAddress(vm) + if err != nil { + return err + } + aMemoryValues, err := hinter.GetConsecutiveValues(vm, aAddr, int16(3)) + if err != nil { + return err + } + + bAddr, err := b.GetAddress(vm) + if err != nil { + return err + } + bMemoryValues, err := hinter.GetConsecutiveValues(vm, bAddr, int16(3)) + if err != nil { + return err + } + + var aValues [3]*fp.Element + var bValues [3]*fp.Element + + for i := 0; i < 3; i++ { + aValue, err := aMemoryValues[i].FieldElement() + if err != nil { + return err + } + aValues[i] = aValue + + bValue, err := bMemoryValues[i].FieldElement() + if err != nil { + return err + } + bValues[i] = bValue + } + + //> a = pack(ids.a, PRIME) + aPackedBig, err := secp_utils.SecPPacked(aValues) + if err != nil { + return err + } + + //> b = pack(ids.b, PRIME) + bPackedBig, err := secp_utils.SecPPacked(bValues) + if err != nil { + return err + } + + nBig, ok := secp_utils.GetN() + if !ok { + return fmt.Errorf("GetN failed") + } + + //> value = res = div_mod(a, b, N) + resBig, err := secp_utils.Divmod(&aPackedBig, &bPackedBig, &nBig) + if err != nil { + return err + } + valueBig := new(big.Int).Set(&resBig) + + return ctx.ScopeManager.AssignVariables(map[string]any{"res": &resBig, "value": valueBig}) + }, + } +} + +func createDivModNPackedDivmodV1Hinter(resolver hintReferenceResolver) (hinter.Hinter, error) { + a, err := resolver.GetResOperander("a") + if err != nil { + return nil, err + } + b, err := resolver.GetResOperander("b") + if err != nil { + return nil, err + } + + return newDivModNPackedDivmodV1Hint(a, b), nil +} diff --git a/pkg/hintrunner/zero/zerohint_signature_test.go b/pkg/hintrunner/zero/zerohint_signature_test.go index 7be3c77f..38ff4be1 100644 --- a/pkg/hintrunner/zero/zerohint_signature_test.go +++ b/pkg/hintrunner/zero/zerohint_signature_test.go @@ -1,6 +1,7 @@ package zero import ( + "math/big" "testing" "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter" @@ -199,5 +200,86 @@ func TestVerifyZeroHint(t *testing.T) { }), }, }, + "DivModNPackedDivmodV1": { + { + operanders: []*hintOperander{ + {Name: "a.d0", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "a.d1", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "a.d2", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "b.d0", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "b.d1", Kind: apRelative, Value: &utils.FeltZero}, + {Name: "b.d2", Kind: apRelative, Value: &utils.FeltZero}, + }, + ctxInit: func(ctx *hinter.HintRunnerContext) { + hinter.InitializeScopeManager(ctx, map[string]any{}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newDivModNPackedDivmodV1Hint(ctx.operanders["a.d0"], ctx.operanders["b.d0"]) + }, + errCheck: errorTextContains("no solution exists (gcd(m, p) != 1)"), + }, + { + operanders: []*hintOperander{ + {Name: "a.d0", Kind: apRelative, Value: &utils.FeltOne}, + {Name: "a.d1", Kind: apRelative, Value: &utils.FeltOne}, + {Name: "a.d2", Kind: apRelative, Value: &utils.FeltOne}, + {Name: "b.d0", Kind: apRelative, Value: &utils.FeltOne}, + {Name: "b.d1", Kind: apRelative, Value: &utils.FeltOne}, + {Name: "b.d2", Kind: apRelative, Value: &utils.FeltOne}, + }, + ctxInit: func(ctx *hinter.HintRunnerContext) { + hinter.InitializeScopeManager(ctx, map[string]any{}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newDivModNPackedDivmodV1Hint(ctx.operanders["a.d0"], ctx.operanders["b.d0"]) + }, + check: allVarValueInScopeEquals(map[string]any{ + "res": big.NewInt(1), + "value": big.NewInt(1), + }), + }, + { + operanders: []*hintOperander{ + // values are the 3 results of split(SEC_P) + {Name: "a.d0", Kind: apRelative, Value: feltString("77371252455336262886226991")}, + {Name: "a.d1", Kind: apRelative, Value: feltString("77371252455336267181195263")}, + {Name: "a.d2", Kind: apRelative, Value: feltString("19342813113834066795298815")}, + {Name: "b.d0", Kind: apRelative, Value: feltString("77371252455336262886226991")}, + {Name: "b.d1", Kind: apRelative, Value: feltString("77371252455336267181195263")}, + {Name: "b.d2", Kind: apRelative, Value: feltString("19342813113834066795298815")}, + }, + ctxInit: func(ctx *hinter.HintRunnerContext) { + hinter.InitializeScopeManager(ctx, map[string]any{}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newDivModNPackedDivmodV1Hint(ctx.operanders["a.d0"], ctx.operanders["b.d0"]) + }, + check: allVarValueInScopeEquals(map[string]any{ + "res": big.NewInt(1), + "value": big.NewInt(1), + }), + }, + { + operanders: []*hintOperander{ + // random values + {Name: "a.d0", Kind: apRelative, Value: feltString("124")}, + {Name: "a.d1", Kind: apRelative, Value: feltString("668")}, + {Name: "a.d2", Kind: apRelative, Value: feltString("979")}, + {Name: "b.d0", Kind: apRelative, Value: feltString("741")}, + {Name: "b.d1", Kind: apRelative, Value: feltString("17")}, + {Name: "b.d2", Kind: apRelative, Value: feltString("670")}, + }, + ctxInit: func(ctx *hinter.HintRunnerContext) { + hinter.InitializeScopeManager(ctx, map[string]any{}) + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newDivModNPackedDivmodV1Hint(ctx.operanders["a.d0"], ctx.operanders["b.d0"]) + }, + check: allVarValueInScopeEquals(map[string]any{ + "res": bigIntString("62733347149736974538461843763852691885676254208529184638286052021917647089374", 10), + "value": bigIntString("62733347149736974538461843763852691885676254208529184638286052021917647089374", 10), + }), + }, + }, }) }