Skip to content

Commit

Permalink
Implement DefaultRead
Browse files Browse the repository at this point in the history
  • Loading branch information
har777 committed Apr 22, 2024
1 parent 076f7b9 commit 99eada8
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 0 deletions.
9 changes: 9 additions & 0 deletions pkg/hintrunner/hinter/dict.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ type Dictionary struct {
idx uint64
// Default value for key not present in the dictionary
defaultValue *mem.MemoryValue
// first free offset in memory segment of dictionary
freeOffset uint64
}

// Gets the memory value at certain key
Expand All @@ -39,6 +41,11 @@ func (d *Dictionary) InitNumber() uint64 {
return d.idx
}

// Given a incrementBy value, it increments the freeOffset field of dictionary by it
func (d *Dictionary) IncrementFreeOffset(freeOffset uint64) {
d.freeOffset += freeOffset
}

// Used to manage dictionaries creation
type DictionaryManager struct {
// a map that links a segment index to a dictionary
Expand All @@ -60,6 +67,7 @@ func (dm *DictionaryManager) NewDictionary(vm *VM.VirtualMachine) mem.MemoryAddr
data: make(map[f.Element]*mem.MemoryValue),
idx: uint64(len(dm.dictionaries)),
defaultValue: nil,
freeOffset: 0,
}
return newDictAddr
}
Expand All @@ -74,6 +82,7 @@ func (dm *DictionaryManager) NewDefaultDictionary(vm *VM.VirtualMachine, default
data: make(map[f.Element]*mem.MemoryValue),
idx: uint64(len(dm.dictionaries)),
defaultValue: defaultValue,
freeOffset: 0,
}
return newDefaultDictAddr
}
Expand Down
1 change: 1 addition & 0 deletions pkg/hintrunner/zero/hintcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const (

// ------ Dictionaries hints related code ------
defaultDictNewCode string = "if '__dict_manager' not in globals():\n from starkware.cairo.common.dict import DictManager\n __dict_manager = DictManager()\n\nmemory[ap] = __dict_manager.new_default_dict(segments, ids.default_value)"
dictReadCode string = "dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)\ndict_tracker.current_ptr += ids.DictAccess.SIZE\nids.value = dict_tracker.data[ids.key]"

// ------ Other hints related code ------
allocSegmentCode string = "memory[ap] = segments.add()"
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 @@ -140,6 +140,8 @@ func GetHintFromCode(program *zero.ZeroProgram, rawHint zero.Hint, hintPC uint64
// Dictionary hints
case defaultDictNewCode:
return createDefaultDictNewHinter(resolver)
case dictReadCode:
return createDictReadHinter(resolver)
// Other hints
case allocSegmentCode:
return createAllocSegmentHinter(resolver)
Expand Down
61 changes: 61 additions & 0 deletions pkg/hintrunner/zero/zerohint_dictionaries.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package zero

import (
"fmt"

"github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter"
VM "github.com/NethermindEth/cairo-vm-go/pkg/vm"
mem "github.com/NethermindEth/cairo-vm-go/pkg/vm/memory"
Expand Down Expand Up @@ -50,3 +52,62 @@ func createDefaultDictNewHinter(resolver hintReferenceResolver) (hinter.Hinter,
}
return newDefaultDictNewHint(defaultValue), nil
}

func newDictReadHint(dictPtr, key, value hinter.ResOperander) hinter.Hinter {
return &GenericZeroHinter{
Name: "DictRead",
Op: func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error {
//> dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)
//> dict_tracker.current_ptr += ids.DictAccess.SIZE
//> ids.value = dict_tracker.data[ids.key]

//> dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)
dictPtr, err := hinter.ResolveAsAddress(vm, dictPtr)
if err != nil {
return err
}
dictionaryManager, ok := ctx.ScopeManager.GetDictionaryManager()
if !ok {
return fmt.Errorf("__dict_manager not in scope")
}
dictionary, err := dictionaryManager.GetDictionary(dictPtr)
if err != nil {
return err
}

//> dict_tracker.current_ptr += ids.DictAccess.SIZE
dictionary.IncrementFreeOffset(3)

//> ids.value = dict_tracker.data[ids.key]
key, err := hinter.ResolveAsFelt(vm, key)
if err != nil {
return err
}
keyValue, err := dictionary.At(key)
if err != nil {
return err
}
valueAddr, err := value.GetAddress(vm)
if err != nil {
return err
}
return vm.Memory.WriteToAddress(&valueAddr, keyValue)
},
}
}

func createDictReadHinter(resolver hintReferenceResolver) (hinter.Hinter, error) {
dictPtr, err := resolver.GetResOperander("dict_ptr")
if err != nil {
return nil, err
}
key, err := resolver.GetResOperander("key")
if err != nil {
return nil, err
}
value, err := resolver.GetResOperander("value")
if err != nil {
return nil, err
}
return newDictReadHint(dictPtr, key, value), nil
}
22 changes: 22 additions & 0 deletions pkg/hintrunner/zero/zerohint_dictionaries_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"

"github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter"
"github.com/NethermindEth/cairo-vm-go/pkg/vm/memory"
"github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
)

Expand Down Expand Up @@ -50,5 +51,26 @@ func TestZeroHintDictionaries(t *testing.T) {
},
},
},
"DictRead": {
{
operanders: []*hintOperander{
{Name: "dict_ptr", Kind: apRelative, Value: addrWithSegment(2, 0)},
{Name: "key", Kind: apRelative, Value: feltUint64(100)},
{Name: "value", Kind: uninitialized},
},
ctxInit: func(ctx *hinter.HintRunnerContext) {
hinter.InitializeDictionaryManager(ctx)
hinter.InitializeScopeManager(ctx, map[string]any{
"__dict_manager": ctx.DictionaryManager,
})
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
defaultValueMv := memory.MemoryValueFromInt(12345)
ctx.runnerContext.DictionaryManager.NewDefaultDictionary(ctx.vm, &defaultValueMv)
return newDictReadHint(ctx.operanders["dict_ptr"], ctx.operanders["key"], ctx.operanders["value"])
},
check: varValueEquals("value", feltUint64(12345)),
},
},
})
}

0 comments on commit 99eada8

Please sign in to comment.