From 362847a71dbcf69a7a5f7fa4dfc5b504d4029f8a Mon Sep 17 00:00:00 2001 From: Tristan <122918260+TAdev0@users.noreply.github.com> Date: Wed, 8 May 2024 12:52:18 +0200 Subject: [PATCH] [feat]: Annotate signature hints + few improvements (#393) * signature hints description + few improvements * fix * address comments * small fix --- .../zero/zerohint_dictionaries_test.go | 2 +- pkg/hintrunner/zero/zerohint_signature.go | 90 +++++++++++++++---- .../zero/zerohint_signature_test.go | 26 +++--- 3 files changed, 82 insertions(+), 36 deletions(-) diff --git a/pkg/hintrunner/zero/zerohint_dictionaries_test.go b/pkg/hintrunner/zero/zerohint_dictionaries_test.go index c2615dd1..f891db52 100644 --- a/pkg/hintrunner/zero/zerohint_dictionaries_test.go +++ b/pkg/hintrunner/zero/zerohint_dictionaries_test.go @@ -9,7 +9,7 @@ import ( func TestZeroHintDictionaries(t *testing.T) { runHinterTests(t, map[string][]hintTestCase{ - "SquashDictInnerAssertKeys": { + "SquashDictInnerAssertLenKeys": { { operanders: []*hintOperander{}, ctxInit: func(ctx *hinter.HintRunnerContext) { diff --git a/pkg/hintrunner/zero/zerohint_signature.go b/pkg/hintrunner/zero/zerohint_signature.go index 107d07ac..8d74140d 100644 --- a/pkg/hintrunner/zero/zerohint_signature.go +++ b/pkg/hintrunner/zero/zerohint_signature.go @@ -12,6 +12,16 @@ import ( "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" ) +// VerifyZero hint verifies that a packed value is zero modulo the SECP256R1 prime +// and stores in memory the quotient of the modular divison of the packed value by +// SECP256R1 prime +// +// `newVerifyZeroHint` takes 2 operanders as arguments +// - `value` is the value that will be verified +// - `q` is the variable that will store the quotient of the modular division +// +// `newVerifyZeroHint` writes the quotient of the modular division of the packed value +// by SECP256R1 prime to the memory address corresponding to `q` func newVerifyZeroHint(val, q hinter.ResOperander) hinter.Hinter { return &GenericZeroHinter{ Name: "VerifyZero", @@ -58,7 +68,7 @@ func newVerifyZeroHint(val, q hinter.ResOperander) hinter.Hinter { //> assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." if rBig.Cmp(big.NewInt(0)) != 0 { - return fmt.Errorf("verify_zero: Invalid input (%v, %v, %v).", valValues[0], valValues[1], valValues[2]) + return fmt.Errorf("verify_zero: Invalid input (%v, %v, %v)", valValues[0], valValues[1], valValues[2]) } //> ids.q = q % PRIME @@ -79,6 +89,7 @@ func createVerifyZeroHinter(resolver hintReferenceResolver) (hinter.Hinter, erro if err != nil { return nil, err } + q, err := resolver.GetResOperander("q") if err != nil { return nil, err @@ -87,7 +98,15 @@ func createVerifyZeroHinter(resolver hintReferenceResolver) (hinter.Hinter, erro return newVerifyZeroHint(val, q), nil } -func newVerifyECDSASignatureHinter(ecdsaPtr, signature_r, signature_s hinter.ResOperander) hinter.Hinter { +// VerifyECDSASignature hint writes an ECDSA signature to a given address +// +// `newVerifyECDSASignatureHint` takes 3 operanders as arguments +// - `ecdsaPtr` is the pointer variable that stores the address +// where to write the signature +// - `signature_r` and `signature_s` are the r and s parts of the signature +// +// `newVerifyECDSASignatureHint` uses the ECDSA builtin to perform this operation +func newVerifyECDSASignatureHint(ecdsaPtr, signature_r, signature_s hinter.ResOperander) hinter.Hinter { return &GenericZeroHinter{ Name: "VerifyECDSASignature", Op: func(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error { @@ -119,20 +138,31 @@ func createVerifyECDSASignatureHinter(resolver hintReferenceResolver) (hinter.Hi 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 + + return newVerifyECDSASignatureHint(ecdsaPtr, signature_r, signature_s), nil } -func newGetPointFromXHinter(xCube, v hinter.ResOperander) hinter.Hinter { +// GetPointFromX hint calculates the y-coordinate of a point +// on an elliptic curve for a given x-coordinate +// +// `newGetPointFromXHint` takes 2 operanders as arguments +// - `xCube` is the x-coordinate value used to calculate the point +// - `v` is the parity of the `y` result, it should be either 0 or 1 +// +// `newGetPointFromXHint` assigns the y-coordinate as `value` in the current scope +func newGetPointFromXHint(xCube, v hinter.ResOperander) hinter.Hinter { return &GenericZeroHinter{ - Name: "VerifyECDSASignature", + Name: "GetPointFromX", 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 @@ -203,34 +233,48 @@ func createGetPointFromXHinter(resolver hintReferenceResolver) (hinter.Hinter, e if err != nil { return nil, err } + v, err := resolver.GetResOperander("v") if err != nil { return nil, err } - return newGetPointFromXHinter(xCube, v), nil + + return newGetPointFromXHint(xCube, v), nil } -func newImportSecp256R1PHinter() hinter.Hinter { +// ImportSecp256R1P hint imports the `SECP_P` constant from SECP256R1 +// curve utilities in the current scope +// +// `newImportSecp256R1PHint` doesn't take any operander as argument +// +// `newGetPointFromXHint` assigns `SECP_P` variable in the current scope +func newImportSecp256R1PHint() hinter.Hinter { return &GenericZeroHinter{ - Name: "Secp256R1", + Name: "ImportSecp256R1P", 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 fmt.Errorf("SECP256R1_P failed") } + return ctx.ScopeManager.AssignVariable("SECP_P", &SECP256R1_PBig) }, } } func createImportSecp256R1PHinter() (hinter.Hinter, error) { - return newImportSecp256R1PHinter(), nil + return newImportSecp256R1PHint(), nil } -func newDivModSafeDivHinter() hinter.Hinter { +// DivModSafeDiv hint computes a safe division in the context of the N constant +// +// `newDivModSafeDivHint` doesn't take any operander as argument +// +// `newDivModSafeDivHint` assigns the result `k` as `value` in the current scope +func newDivModSafeDivHint() hinter.Hinter { return &GenericZeroHinter{ - Name: "DivModSafeDivHinter", + Name: "DivModSafeDiv", Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { //> value = k = safe_div(res * b - a, N) @@ -238,37 +282,44 @@ func newDivModSafeDivHinter() hinter.Hinter { 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 + return newDivModSafeDivHint(), nil } +// DivModNPackedDivmodV1 hint caculates the division modulo N for packed values +// +// `newDivModNPackedDivmodV1Hint` takes 2 operanders as arguments +// - `a` is the packed value that will be divided +// - `b` is the packed value that will divide `a` +// +// `newDivModNPackedDivmodV1Hint` assigns the result `res` as `value` in the current scope func newDivModNPackedDivmodV1Hint(a, b hinter.ResOperander) hinter.Hinter { return &GenericZeroHinter{ Name: "DivModNPackedDivmodV1", @@ -338,7 +389,7 @@ func newDivModNPackedDivmodV1Hint(a, b hinter.ResOperander) hinter.Hinter { } valueBig := new(big.Int).Set(&resBig) - return ctx.ScopeManager.AssignVariables(map[string]any{"res": &resBig, "value": valueBig}) + return ctx.ScopeManager.AssignVariable("value", valueBig) }, } } @@ -348,6 +399,7 @@ func createDivModNPackedDivmodV1Hinter(resolver hintReferenceResolver) (hinter.H if err != nil { return nil, err } + b, err := resolver.GetResOperander("b") if err != nil { return nil, err diff --git a/pkg/hintrunner/zero/zerohint_signature_test.go b/pkg/hintrunner/zero/zerohint_signature_test.go index 9e225873..a4bab8c8 100644 --- a/pkg/hintrunner/zero/zerohint_signature_test.go +++ b/pkg/hintrunner/zero/zerohint_signature_test.go @@ -35,7 +35,7 @@ func TestVerifyZeroHint(t *testing.T) { makeHinter: func(ctx *hintTestContext) hinter.Hinter { return newVerifyZeroHint(ctx.operanders["val.d0"], ctx.operanders["q"]) }, - errCheck: errorTextContains("verify_zero: Invalid input (1, 1, 1)."), + errCheck: errorTextContains("verify_zero: Invalid input (1, 1, 1)"), }, { operanders: []*hintOperander{ @@ -60,7 +60,7 @@ func TestVerifyZeroHint(t *testing.T) { }, makeHinter: func(ctx *hintTestContext) hinter.Hinter { ecdsaPtr := ctx.operanders["ecdsaPtr"].(*hinter.DoubleDeref).Deref - return newVerifyECDSASignatureHinter(ecdsaPtr, ctx.operanders["signature_r"], ctx.operanders["signature_s"]) + return newVerifyECDSASignatureHint(ecdsaPtr, ctx.operanders["signature_r"], ctx.operanders["signature_s"]) }, errCheck: func(t *testing.T, ctx *hintTestContext, err error) { require.NoError(t, err) @@ -77,7 +77,7 @@ func TestVerifyZeroHint(t *testing.T) { {Name: "v", Kind: apRelative, Value: &utils.FeltZero}, }, makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newGetPointFromXHinter(ctx.operanders["xCube.d0"], ctx.operanders["v"]) + return newGetPointFromXHint(ctx.operanders["xCube.d0"], ctx.operanders["v"]) }, check: varValueInScopeEquals("value", bigIntString("64828261740814840065360381756190772627110652128289340260788836867053167272156", 10)), }, @@ -90,7 +90,7 @@ func TestVerifyZeroHint(t *testing.T) { {Name: "v", Kind: apRelative, Value: &utils.FeltZero}, }, makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newGetPointFromXHinter(ctx.operanders["xCube.d0"], ctx.operanders["v"]) + return newGetPointFromXHint(ctx.operanders["xCube.d0"], ctx.operanders["v"]) }, check: varValueInScopeEquals("value", bigIntString("3754707778961574900176639079436749683878498834289427635045629810524611907876", 10)), }, @@ -103,7 +103,7 @@ func TestVerifyZeroHint(t *testing.T) { {Name: "v", Kind: apRelative, Value: feltString("77371252455336267181195264")}, }, makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newGetPointFromXHinter(ctx.operanders["xCube.d0"], ctx.operanders["v"]) + return newGetPointFromXHint(ctx.operanders["xCube.d0"], ctx.operanders["v"]) }, check: varValueInScopeEquals("value", bigIntString("64330220386510520462271671435567806262107470356169873352512014089172394266548", 10)), }, @@ -112,12 +112,12 @@ func TestVerifyZeroHint(t *testing.T) { { operanders: []*hintOperander{}, makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newImportSecp256R1PHinter() + return newImportSecp256R1PHint() }, check: varValueInScopeEquals("SECP_P", bigIntString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)), }, }, - "DivModNSafeDivHint": { + "DivModNSafeDiv": { { // zero quotient operanders: []*hintOperander{}, @@ -133,11 +133,10 @@ func TestVerifyZeroHint(t *testing.T) { } }, makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newDivModSafeDivHinter() + return newDivModSafeDivHint() }, check: varListInScopeEquals(map[string]any{ "value": bigIntString("0", 10), - "k": bigIntString("0", 10), }), }, { @@ -155,11 +154,10 @@ func TestVerifyZeroHint(t *testing.T) { } }, makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newDivModSafeDivHinter() + return newDivModSafeDivHint() }, check: varListInScopeEquals(map[string]any{ "value": bigIntString("-1", 10), - "k": bigIntString("-1", 10), }), }, { @@ -177,11 +175,10 @@ func TestVerifyZeroHint(t *testing.T) { } }, makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newDivModSafeDivHinter() + return newDivModSafeDivHint() }, check: varListInScopeEquals(map[string]any{ "value": bigIntString("140", 10), - "k": bigIntString("140", 10), }), }, }, @@ -213,7 +210,6 @@ func TestVerifyZeroHint(t *testing.T) { return newDivModNPackedDivmodV1Hint(ctx.operanders["a.d0"], ctx.operanders["b.d0"]) }, check: allVarValueInScopeEquals(map[string]any{ - "res": big.NewInt(1), "value": big.NewInt(1), }), }, @@ -231,7 +227,6 @@ func TestVerifyZeroHint(t *testing.T) { return newDivModNPackedDivmodV1Hint(ctx.operanders["a.d0"], ctx.operanders["b.d0"]) }, check: allVarValueInScopeEquals(map[string]any{ - "res": big.NewInt(1), "value": big.NewInt(1), }), }, @@ -249,7 +244,6 @@ func TestVerifyZeroHint(t *testing.T) { return newDivModNPackedDivmodV1Hint(ctx.operanders["a.d0"], ctx.operanders["b.d0"]) }, check: allVarValueInScopeEquals(map[string]any{ - "res": bigIntString("62733347149736974538461843763852691885676254208529184638286052021917647089374", 10), "value": bigIntString("62733347149736974538461843763852691885676254208529184638286052021917647089374", 10), }), },