Skip to content

Commit

Permalink
Implement Divmodnpackeddivmodv1 hint (#343)
Browse files Browse the repository at this point in the history
* 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

* Implement FastEcAddAssignNewX hint

* Make hint code less verbose

* Add more tests

* Fix comment formatting

* Clean up EcNegate using new util functions

* Implement EcDoubleSlopeV1 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

* Change zero compare

* Make return simpler

* Cleaner return

* Add more tests

* Comment test values

* Comment test values

* Comment test values

* Comment test values

* Update comment

* Simpler context init in tests

* Add GetVariableValueAsBigInt method to scope manager

* Simpler tests

* Remove duplicate test check

* Clean up scope usage

* Use existing constant

* Simpler loop

* Add AssignVariables method to scope manager + use it

* Use AssignVariables in FastEcAddAssignNewY

* Use util methods to make code simpler

* Use feltUint64 when applicable

* Change argument to accept slice

* Add tests for div_mod and igcdex

* Fetch SECP_P from scope in FastEcAddAssignNewY

* Implement DivModNPackedDivmodV1 hint

* Remove unnecessary space

* Use InitializeScopeManager

* Return big.Int instead of *big.Int

* More return big.Int instead of *big.Int

* Rename to divmod

* Change signature of EcDoubleSlope

* More return big.Int instead of *big.Int

* Remove redundant tests

---------

Co-authored-by: Carmen Cabrera <kr1000a@gmail.com>
  • Loading branch information
har777 and cicr99 committed Apr 25, 2024
1 parent 7bac1c4 commit b2602ab
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 16 deletions.
4 changes: 2 additions & 2 deletions pkg/hintrunner/utils/math_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion pkg/hintrunner/utils/math_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
15 changes: 7 additions & 8 deletions pkg/hintrunner/utils/secp_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -43,21 +49,14 @@ 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

split := make([]big.Int, 3)

baseBig, ok := getBaseBig()
if !ok {
return nil, fmt.Errorf("getBaseBig failed")
return nil, fmt.Errorf("GetBaseBig failed")
}

var residue big.Int
Expand Down
11 changes: 6 additions & 5 deletions pkg/hintrunner/zero/hintcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)])"
Expand Down
2 changes: 2 additions & 0 deletions pkg/hintrunner/zero/zerohint.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
87 changes: 87 additions & 0 deletions pkg/hintrunner/zero/zerohint_signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
82 changes: 82 additions & 0 deletions pkg/hintrunner/zero/zerohint_signature_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package zero

import (
"math/big"
"testing"

"github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter"
Expand Down Expand Up @@ -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),
}),
},
},
})
}

0 comments on commit b2602ab

Please sign in to comment.