Skip to content

Commit

Permalink
[feat]: Annotate signature hints + few improvements (#393)
Browse files Browse the repository at this point in the history
* signature hints description + few improvements

* fix

* address comments

* small fix
  • Loading branch information
TAdev0 committed May 8, 2024
1 parent 878c28c commit 362847a
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 36 deletions.
2 changes: 1 addition & 1 deletion pkg/hintrunner/zero/zerohint_dictionaries_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

func TestZeroHintDictionaries(t *testing.T) {
runHinterTests(t, map[string][]hintTestCase{
"SquashDictInnerAssertKeys": {
"SquashDictInnerAssertLenKeys": {
{
operanders: []*hintOperander{},
ctxInit: func(ctx *hinter.HintRunnerContext) {
Expand Down
90 changes: 71 additions & 19 deletions pkg/hintrunner/zero/zerohint_signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -203,72 +233,93 @@ 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)

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
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",
Expand Down Expand Up @@ -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)
},
}
}
Expand All @@ -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
Expand Down
26 changes: 10 additions & 16 deletions pkg/hintrunner/zero/zerohint_signature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -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)
Expand All @@ -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)),
},
Expand All @@ -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)),
},
Expand All @@ -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)),
},
Expand All @@ -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{},
Expand All @@ -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),
}),
},
{
Expand All @@ -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),
}),
},
{
Expand All @@ -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),
}),
},
},
Expand Down Expand Up @@ -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),
}),
},
Expand All @@ -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),
}),
},
Expand All @@ -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),
}),
},
Expand Down

0 comments on commit 362847a

Please sign in to comment.