From 878c28c153186f362bf5cf85c97a4d7ad031b56f Mon Sep 17 00:00:00 2001 From: Tristan <122918260+TAdev0@users.noreply.github.com> Date: Wed, 8 May 2024 10:19:30 +0200 Subject: [PATCH] [feat]: Annotate usort and dict hints + few improvements (#389) * usort and dict description + few improvements * add comments for errors in UsortVerifyMultiplicityBody hint * address comments * fix * fmt * update comments * fix * add comment for wrong UsortVerifyMultiplicityBody impl * fix --- pkg/hintrunner/zero/zerohint_dictionaries.go | 6 ++- pkg/hintrunner/zero/zerohint_ec.go | 2 +- pkg/hintrunner/zero/zerohint_others.go | 2 +- pkg/hintrunner/zero/zerohint_usort.go | 47 +++++++++++++++++--- pkg/hintrunner/zero/zerohint_usort_test.go | 8 ++-- 5 files changed, 52 insertions(+), 13 deletions(-) diff --git a/pkg/hintrunner/zero/zerohint_dictionaries.go b/pkg/hintrunner/zero/zerohint_dictionaries.go index 9817ff54..2d896276 100644 --- a/pkg/hintrunner/zero/zerohint_dictionaries.go +++ b/pkg/hintrunner/zero/zerohint_dictionaries.go @@ -8,9 +8,13 @@ import ( f "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" ) +// SquashDictInnerAssertLenKeys hint asserts that the length +// of the `keys` descending list is zero during the squashing process +// +// `newSquashDictInnerAssertLenKeysHint` doesn't take any operander as argument func newSquashDictInnerAssertLenKeysHint() hinter.Hinter { return &GenericZeroHinter{ - Name: "SquashDictInnerAssertKeys", + Name: "SquashDictInnerAssertLenKeys", Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { //> assert len(keys) == 0 keys_, err := ctx.ScopeManager.GetVariableValue("keys") diff --git a/pkg/hintrunner/zero/zerohint_ec.go b/pkg/hintrunner/zero/zerohint_ec.go index c13275b2..52d3813e 100644 --- a/pkg/hintrunner/zero/zerohint_ec.go +++ b/pkg/hintrunner/zero/zerohint_ec.go @@ -538,7 +538,7 @@ func createEcDoubleAssignNewXV1Hinter(resolver hintReferenceResolver) (hinter.Hi return newEcDoubleAssignNewXV1Hint(slope, point), nil } -// ComputeSlopeV1Hint hint computes the slope between two points on an elliptic curve +// ComputeSlopeV1 hint computes the slope between two points on an elliptic curve // // `newComputeSlopeV1Hint` takes 2 operanders as arguments // - `point0` is the first point on an elliptic curve to operate on diff --git a/pkg/hintrunner/zero/zerohint_others.go b/pkg/hintrunner/zero/zerohint_others.go index 6a79d07d..b95a6d03 100644 --- a/pkg/hintrunner/zero/zerohint_others.go +++ b/pkg/hintrunner/zero/zerohint_others.go @@ -32,7 +32,7 @@ func createVMExitScopeHinter() (hinter.Hinter, error) { }, nil } -// MemcpyEnterScopeHint hint enters a new scope for the memory copy operation with a specified length +// MemcpyEnterScope hint enters a new scope for the memory copy operation with a specified length // // `newMemcpyEnterScopeHint` takes 1 operander as argument // - `len` is the length value that is added in the new scope diff --git a/pkg/hintrunner/zero/zerohint_usort.go b/pkg/hintrunner/zero/zerohint_usort.go index fbab84a4..1fe34bac 100644 --- a/pkg/hintrunner/zero/zerohint_usort.go +++ b/pkg/hintrunner/zero/zerohint_usort.go @@ -10,7 +10,13 @@ import ( "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" ) -func newUsortEnterScopeHinter() hinter.Hinter { +// UsortEnterScope hint enters a new scope with `__usort_max_size` value +// +// `newUsortEnterScopeHint` doesn't take any operander as argument +// +// `newUsortEnterScopeHint` gets `__usort_max_size` value from the current +// scope and enters a new scope with this same value +func newUsortEnterScopeHint() hinter.Hinter { return &GenericZeroHinter{ Name: "UsortEnterScope", Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { @@ -31,10 +37,17 @@ func newUsortEnterScopeHinter() hinter.Hinter { } func createUsortEnterScopeHinter() (hinter.Hinter, error) { - return newUsortEnterScopeHinter(), nil + return newUsortEnterScopeHint(), nil } -func newUsortVerifyMultiplicityAssertHinter() hinter.Hinter { +// UsortVerifyMultiplicityAssert hint checks that the `positions` variable in scope +// doesn't contain any value +// +// `newUsortVerifyMultiplicityAssertHint` doesn't take any operander as argument +// +// This hint is used when sorting an array of field elements while removing duplicates +// in `usort` Cairo function +func newUsortVerifyMultiplicityAssertHint() hinter.Hinter { return &GenericZeroHinter{ Name: "UsortVerifyMultiplicityAssert", Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { @@ -60,10 +73,20 @@ func newUsortVerifyMultiplicityAssertHinter() hinter.Hinter { } func createUsortVerifyMultiplicityAssertHinter() (hinter.Hinter, error) { - return newUsortEnterScopeHinter(), nil + return newUsortEnterScopeHint(), nil } -func newUsortVerifyHinter(value hinter.ResOperander) hinter.Hinter { +// UsortVerify hint prepares for verifying the presence of duplicates of +// a specific value in the sorted output (array of fields) +// +// `newUsortVerifyHint` takes one operander as argument +// - `value` is the value at the given position in the output +// +// `last_pos` is set to zero +// `positions` is set to the reversed order list associated with `ids.value` +// key in `positions_dict` +// `newUsortVerifyHint` assigns `last_pos` and `positions` in the current scope +func newUsortVerifyHint(value hinter.ResOperander) hinter.Hinter { return &GenericZeroHinter{ Name: "UsortVerify", Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { @@ -106,9 +129,18 @@ func createUsortVerifyHinter(resolver hintReferenceResolver) (hinter.Hinter, err return nil, err } - return newUsortVerifyHinter(value), nil + return newUsortVerifyHint(value), nil } +// UsortVerifyMultiplicityBody hint extracts a specific value +// of the sorted output with `pop`, updating indices for the verification +// of the next value +// +// `newUsortVerifyMultiplicityBodyHint` takes one operander as argument +// - `nextItemIndex` is the index of the next item +// +// `next_item_index` is set to `current_pos - last_pos` for the next iteration +// `newUsortVerifyMultiplicityBodyHint` assigns `last_pos` in the current scope func newUsortVerifyMultiplicityBodyHint(nextItemIndex hinter.ResOperander) hinter.Hinter { return &GenericZeroHinter{ Name: "UsortVerifyMultiplicityBody", @@ -132,6 +164,8 @@ func newUsortVerifyMultiplicityBodyHint(nextItemIndex hinter.ResOperander) hinte return err } + // TODO : This is not correct, `newCurrentPos` should be used + // and there is not `current_pos` variable to retrieve in scope currentPos, err := ctx.ScopeManager.GetVariableValue("current_pos") if err != nil { return err @@ -167,6 +201,7 @@ func newUsortVerifyMultiplicityBodyHint(nextItemIndex hinter.ResOperander) hinte return err } + // TODO : Only last_pos should be assigned in current scope // Save `current_pos` and `last_pos` values in scope variables return ctx.ScopeManager.AssignVariables(map[string]any{ "current_pos": newCurrentPos, diff --git a/pkg/hintrunner/zero/zerohint_usort_test.go b/pkg/hintrunner/zero/zerohint_usort_test.go index 2920a43e..84b2cf15 100644 --- a/pkg/hintrunner/zero/zerohint_usort_test.go +++ b/pkg/hintrunner/zero/zerohint_usort_test.go @@ -19,7 +19,7 @@ func TestZeroHintUsort(t *testing.T) { } }, makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newUsortEnterScopeHinter() + return newUsortEnterScopeHint() }, check: varValueInScopeEquals("__usort_max_size", feltUint64(1)), }, @@ -33,7 +33,7 @@ func TestZeroHintUsort(t *testing.T) { } }, makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newUsortVerifyMultiplicityAssertHinter() + return newUsortVerifyMultiplicityAssertHint() }, errCheck: errorTextContains("assertion `len(positions) == 0` failed"), }, @@ -45,7 +45,7 @@ func TestZeroHintUsort(t *testing.T) { } }, makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newUsortVerifyMultiplicityAssertHinter() + return newUsortVerifyMultiplicityAssertHint() }, errCheck: errorIsNil, }, @@ -64,7 +64,7 @@ func TestZeroHintUsort(t *testing.T) { {Name: "value", Kind: fpRelative, Value: feltUint64(0)}, }, makeHinter: func(ctx *hintTestContext) hinter.Hinter { - return newUsortVerifyHinter(ctx.operanders["value"]) + return newUsortVerifyHint(ctx.operanders["value"]) }, check: func(t *testing.T, ctx *hintTestContext) { positions, err := ctx.runnerContext.ScopeManager.GetVariableValue("positions")