-
Notifications
You must be signed in to change notification settings - Fork 43
/
zerohint.go
186 lines (166 loc) · 5.25 KB
/
zerohint.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package zero
import (
"fmt"
"strconv"
"github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter"
zero "github.com/NethermindEth/cairo-vm-go/pkg/parsers/zero"
VM "github.com/NethermindEth/cairo-vm-go/pkg/vm"
)
// GenericZeroHinter wraps an adhoc Cairo0 inline (pythonic) hint implementation.
type GenericZeroHinter struct {
Name string
Op func(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error
}
func (hint *GenericZeroHinter) String() string {
return hint.Name
}
func (hint *GenericZeroHinter) Execute(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error {
return hint.Op(vm, ctx)
}
func GetZeroHints(cairoZeroJson *zero.ZeroProgram) (map[uint64][]hinter.Hinter, error) {
hints := make(map[uint64][]hinter.Hinter)
for counter, rawHints := range cairoZeroJson.Hints {
pc, err := strconv.ParseUint(counter, 10, 64)
if err != nil {
return nil, err
}
for _, rawHint := range rawHints {
hint, err := GetHintFromCode(cairoZeroJson, rawHint, pc)
if err != nil {
return nil, err
}
hints[pc] = append(hints[pc], hint)
}
}
return hints, nil
}
func GetHintFromCode(program *zero.ZeroProgram, rawHint zero.Hint, hintPC uint64) (hinter.Hinter, error) {
resolver, err := getParameters(program, rawHint, hintPC)
if err != nil {
return nil, err
}
switch rawHint.Code {
// Math hints
case isLeFeltCode:
return createIsLeFeltHinter(resolver)
case assertLtFeltCode:
return createAssertLtFeltHinter(resolver)
case assertNotZeroCode:
return createAssertNotZeroHinter(resolver)
case assertNNCode:
return createAssertNNHinter(resolver)
case assertNotEqualCode:
return createAssertNotEqualHinter(resolver)
case assert250bits:
return createAssert250bitsHinter(resolver)
case assertLeFeltCode:
return createAssertLeFeltHinter(resolver)
case assertLeFeltExcluded0Code:
return createAssertLeFeltExcluded0Hinter(resolver)
case assertLeFeltExcluded1Code:
return createAssertLeFeltExcluded1Hinter(resolver)
case assertLeFeltExcluded2Code:
return createAssertLeFeltExcluded2Hinter(resolver)
case isNNCode:
return createIsNNHinter(resolver)
case isNNOutOfRangeCode:
return createIsNNOutOfRangeHinter(resolver)
case isPositiveCode:
return createIsPositiveHinter(resolver)
case splitIntAssertRange:
return createSplitIntAssertRangeHinter(resolver)
case splitIntCode:
return createSplitIntHinter(resolver)
case powCode:
return createPowHinter(resolver)
case splitFeltCode:
return createSplitFeltHinter(resolver)
case sqrtCode:
return createSqrtHinter(resolver)
case unsignedDivRemCode:
return createUnsignedDivRemHinter(resolver)
// Uint256 hints
case uint256AddCode:
return createUint256AddHinter(resolver, false)
case uint256AddLowCode:
return createUint256AddHinter(resolver, true)
case split64Code:
return createSplit64Hinter(resolver)
case uint256SignedNNCode:
return createUint256SignedNNHinter(resolver)
case uint256UnsignedDivRemCode:
return createUint256UnsignedDivRemHinter(resolver)
case uint256SqrtCode:
return createUint256SqrtHinter(resolver)
case uint256MulDivModCode:
return createUint256MulDivModHinter(resolver)
// Other hints
case allocSegmentCode:
return createAllocSegmentHinter(resolver)
case vmEnterScopeCode:
return createVMEnterScopeHinter(resolver)
case vmExitScopeCode:
return createVMExitScopeHinter(resolver)
case testAssignCode:
return createTestAssignHinter(resolver)
default:
return nil, fmt.Errorf("Not identified hint")
}
}
func getParameters(zeroProgram *zero.ZeroProgram, hint zero.Hint, hintPC uint64) (hintReferenceResolver, error) {
resolver := NewReferenceResolver()
for referenceName := range hint.FlowTrackingData.ReferenceIds {
rawIdentifier, ok := zeroProgram.Identifiers[referenceName]
if !ok {
return resolver, fmt.Errorf("missing identifier %s", referenceName)
}
if len(rawIdentifier.References) == 0 {
return resolver, fmt.Errorf("identifier %s should have at least one reference", referenceName)
}
references := rawIdentifier.References
// Go through the references in reverse order to get the one with biggest pc smaller or equal to the hint pc
var reference zero.Reference
ok = false
for i := len(references) - 1; i >= 0; i-- {
if references[i].Pc <= hintPC {
reference = references[i]
ok = true
break
}
}
if !ok {
return resolver, fmt.Errorf("identifier %s should have a reference with pc smaller or equal than %d", referenceName, hintPC)
}
param, err := ParseIdentifier(reference.Value)
if err != nil {
return resolver, err
}
param = param.ApplyApTracking(hint.FlowTrackingData.ApTracking, reference.ApTrackingData)
if err := resolver.AddReference(referenceName, param); err != nil {
return resolver, err
}
}
return resolver, nil
}
func createTestAssignHinter(resolver hintReferenceResolver) (hinter.Hinter, error) {
arg, err := resolver.GetReference("a")
if err != nil {
return nil, err
}
a, ok := arg.(hinter.ResOperander)
if !ok {
return nil, fmt.Errorf("expected a ResOperander reference")
}
h := &GenericZeroHinter{
Name: "TestAssign",
Op: func(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error {
apAddr := vm.Context.AddressAp()
v, err := a.Resolve(vm)
if err != nil {
return err
}
return vm.Memory.WriteToAddress(&apAddr, &v)
},
}
return h, nil
}