diff --git a/cmd/cli/main.go b/cmd/cli/main.go index 4e1ed773a..d6d7af8ab 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -5,7 +5,11 @@ import ( "math" "os" + "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/core" + "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter" hintrunner "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/zero" + cairoversion "github.com/NethermindEth/cairo-vm-go/pkg/parsers/cairo_version" + "github.com/NethermindEth/cairo-vm-go/pkg/parsers/starknet" zero "github.com/NethermindEth/cairo-vm-go/pkg/parsers/zero" runnerzero "github.com/NethermindEth/cairo-vm-go/pkg/runners/zero" "github.com/urfave/cli/v2" @@ -90,28 +94,36 @@ func main() { if pathToFile == "" { return fmt.Errorf("path to cairo file not set") } - - fmt.Printf("Loading program at %s\n", pathToFile) - content, err := os.ReadFile(pathToFile) + cairoVersion, err := cairoversion.GetCairoVersion(pathToFile) if err != nil { - return fmt.Errorf("cannot load program: %w", err) + return fmt.Errorf("cannot get cairo version: %w", err) } - - cairoZeroJson, err := zero.ZeroProgramFromJSON(content) + fmt.Printf("Loading program at %s\n", pathToFile) + zeroProgram, err := zero.ZeroProgramFromFile(pathToFile) if err != nil { return fmt.Errorf("cannot load program: %w", err) } - program, err := runnerzero.LoadCairoZeroProgram(cairoZeroJson) - if err != nil { - return fmt.Errorf("cannot load program: %w", err) + var hints map[uint64][]hinter.Hinter + if cairoVersion > 0 { + cairoProgram, err := starknet.StarknetProgramFromFile(pathToFile) + if err != nil { + return fmt.Errorf("cannot load program: %w", err) + } + hints, err = core.GetCairoHints(cairoProgram) + if err != nil { + return fmt.Errorf("cannot get hints: %w", err) + } + } else { + hints, err = hintrunner.GetZeroHints(zeroProgram) + if err != nil { + return fmt.Errorf("cannot create hints: %w", err) + } } - - hints, err := hintrunner.GetZeroHints(cairoZeroJson) + program, err := runnerzero.LoadCairoZeroProgram(zeroProgram) if err != nil { - return fmt.Errorf("cannot create hints: %w", err) + return fmt.Errorf("cannot load program: %w", err) } - fmt.Println("Running....") runner, err := runnerzero.NewRunner(program, hints, proofmode, collectTrace, maxsteps, layoutName) if err != nil { diff --git a/pkg/hintrunner/core/cairo_hintparser.go b/pkg/hintrunner/core/cairo_hintparser.go new file mode 100644 index 000000000..e6c38fb7d --- /dev/null +++ b/pkg/hintrunner/core/cairo_hintparser.go @@ -0,0 +1,282 @@ +package core + +import ( + "fmt" + + "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter" + "github.com/NethermindEth/cairo-vm-go/pkg/parsers/starknet" + "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" +) + +func parseCellRefer(cr starknet.CellRef) hinter.CellRefer { + switch cr.Register { + case starknet.AP: + return hinter.ApCellRef(cr.Offset) + case starknet.FP: + return hinter.FpCellRef(cr.Offset) + } + return nil +} + +func parseDeref(ro starknet.ResOperand) hinter.Deref { + cr := parseCellRefer(ro.ResOperand.(*starknet.Deref).Deref) + return hinter.Deref{ + Deref: cr, + } +} + +func parseDoubleDeref(ro starknet.ResOperand) hinter.DoubleDeref { + dd := ro.ResOperand.(*starknet.DoubleDeref) + offset := int16(dd.Inner.Offset) + cr := parseCellRefer(dd.Inner.CellRef) + deref := hinter.Deref{ + Deref: cr, + } + return hinter.DoubleDeref{ + Offset: offset, + Deref: deref, + } +} + +func parseImmediate(ro starknet.ResOperand) hinter.Immediate { + val := ro.ResOperand.(*starknet.Immediate).Immediate + valFelt := new(fp.Element).SetBigInt(val) + return hinter.Immediate(*valFelt) +} + +func parseBinOp(ro starknet.ResOperand) hinter.BinaryOp { + binOp := ro.ResOperand.(*starknet.BinOp).BinOp + a := hinter.Deref{ + Deref: parseCellRefer(binOp.A), + } + var b hinter.ResOperander = nil + switch binOp.B.Inner.(type) { + case *starknet.Deref: + b = &hinter.Deref{ + Deref: parseCellRefer(binOp.B.Inner.(*starknet.Deref).Deref), + } + case *starknet.Immediate: + val := binOp.B.Inner.(*starknet.Immediate).Immediate + valFelt := new(fp.Element).SetBigInt(val) + b = hinter.Immediate(*valFelt) + } + var operation hinter.Operator = 0 + switch binOp.Op { + case starknet.Add: + operation = hinter.Add + case starknet.Mul: + operation = hinter.Add + } + return hinter.BinaryOp{ + Operator: operation, + Lhs: a, + Rhs: b, + } +} + +func parseResOperand(ro starknet.ResOperand) hinter.ResOperander { + switch ro.Name { + case starknet.DerefName: + return parseDeref(ro) + case starknet.DoubleDerefName: + return parseDoubleDeref(ro) + case starknet.ImmediateName: + return parseImmediate(ro) + case starknet.BinOpName: + return parseBinOp(ro) + } + return nil +} + +func GetHintByName(hint starknet.Hint) (hinter.Hinter, error) { + switch hint.Name { + case starknet.AllocSegmentName: + args := hint.Args.(*starknet.AllocSegment) + return &AllocSegment{ + Dst: parseCellRefer(args.Dst), + }, nil + case starknet.TestLessThanName: + args := hint.Args.(*starknet.TestLessThan) + return &TestLessThan{ + lhs: parseResOperand(args.Lhs), + rhs: parseResOperand(args.Rhs), + dst: parseCellRefer(args.Dst), + }, nil + case starknet.TestLessThanOrEqualName: + args := hint.Args.(*starknet.TestLessThanOrEqual) + return &TestLessThanOrEqual{ + lhs: parseResOperand(args.Lhs), + rhs: parseResOperand(args.Rhs), + dst: parseCellRefer(args.Dst), + }, nil + case starknet.LinearSplitName: + args := hint.Args.(*starknet.LinearSplit) + return &LinearSplit{ + value: parseResOperand(args.Value), + scalar: parseResOperand(args.Scalar), + maxX: parseResOperand(args.MaxX), + x: parseCellRefer(args.X), + y: parseCellRefer(args.Y), + }, nil + case starknet.WideMul128Name: + args := hint.Args.(*starknet.WideMul128) + return &WideMul128{ + lhs: parseResOperand(args.Lhs), + rhs: parseResOperand(args.Rhs), + high: parseCellRefer(args.High), + low: parseCellRefer(args.Low), + }, nil + case starknet.DivModName: + args := hint.Args.(*starknet.DivMod) + return &DivMod{ + lhs: parseResOperand(args.Lhs), + rhs: parseResOperand(args.Rhs), + quotient: parseCellRefer(args.Quotient), + remainder: parseCellRefer(args.Remainder), + }, nil + case starknet.Uint256DivModName: + args := hint.Args.(*starknet.Uint256DivMod) + return &Uint256DivMod{ + dividend0: parseResOperand(args.Dividend0), + dividend1: parseResOperand(args.Dividend1), + divisor0: parseResOperand(args.Divisor0), + divisor1: parseResOperand(args.Divisor1), + quotient0: parseCellRefer(args.Quotient0), + quotient1: parseCellRefer(args.Quotient1), + remainder0: parseCellRefer(args.Remainder0), + remainder1: parseCellRefer(args.Remainder1), + }, nil + case starknet.DebugPrintName: + args := hint.Args.(*starknet.DebugPrint) + return &DebugPrint{ + start: parseResOperand(args.Start), + end: parseResOperand(args.End), + }, nil + case starknet.SquareRootName: + args := hint.Args.(*starknet.SquareRoot) + return &SquareRoot{ + value: parseResOperand(args.Value), + dst: parseCellRefer(args.Dst), + }, nil + case starknet.Uint256SquareRootName: + args := hint.Args.(*starknet.Uint256SquareRoot) + return &Uint256SquareRoot{ + valueLow: parseResOperand(args.ValueLow), + valueHigh: parseResOperand(args.ValueHigh), + sqrt0: parseCellRefer(args.Sqrt0), + sqrt1: parseCellRefer(args.Sqrt1), + remainderLow: parseCellRefer(args.RemainderLow), + remainderHigh: parseCellRefer(args.RemainderHigh), + sqrtMul2MinusRemainderGeU128: parseCellRefer(args.SqrtMul2MinusRemainderGeU128), + }, nil + case starknet.AllocFelt252DictName: + args := hint.Args.(*starknet.AllocFelt252Dict) + return &AllocFelt252Dict{ + SegmentArenaPtr: parseResOperand(args.SegmentArenaPtr), + }, nil + case starknet.Felt252DictEntryInitName: + args := hint.Args.(*starknet.Felt252DictEntryInit) + return &Felt252DictEntryInit{ + DictPtr: parseResOperand(args.DictPtr), + Key: parseResOperand(args.Key), + }, nil + case starknet.Felt252DictEntryUpdateName: + args := hint.Args.(*starknet.Felt252DictEntryUpdate) + return &Felt252DictEntryUpdate{ + DictPtr: parseResOperand(args.DictPtr), + Value: parseResOperand(args.Value), + }, nil + case starknet.GetSegmentArenaIndexName: + args := hint.Args.(*starknet.GetSegmentArenaIndex) + return &GetSegmentArenaIndex{ + DictEndPtr: parseResOperand(args.DictEndPtr), + DictIndex: parseCellRefer(args.DictIndex), + }, nil + case starknet.InitSquashDataName: + args := hint.Args.(*starknet.InitSquashData) + return &InitSquashData{ + DictAccesses: parseResOperand(args.DictAccesses), + NumAccesses: parseResOperand(args.NAccesses), + BigKeys: parseCellRefer(args.BigKeys), + FirstKey: parseCellRefer(args.FirstKey), + }, nil + case starknet.GetCurrentAccessIndexName: + args := hint.Args.(*starknet.GetCurrentAccessIndex) + return &GetCurrentAccessIndex{ + RangeCheckPtr: parseResOperand(args.RangeCheckPtr), + }, nil + case starknet.ShouldSkipSquashLoopName: + args := hint.Args.(*starknet.ShouldSkipSquashLoop) + return &ShouldSkipSquashLoop{ + ShouldSkipLoop: parseCellRefer(args.ShouldSkipLoop), + }, nil + case starknet.GetCurrentAccessDeltaName: + args := hint.Args.(*starknet.GetCurrentAccessDelta) + return &GetCurrentAccessDelta{ + IndexDeltaMinusOne: parseCellRefer(args.IndexDeltaMinus1), + }, nil + case starknet.ShouldContinueSquashLoopName: + args := hint.Args.(*starknet.ShouldContinueSquashLoop) + return &ShouldContinueSquashLoop{ + ShouldContinue: parseCellRefer(args.ShouldContinue), + }, nil + case starknet.GetNextDictKeyName: + args := hint.Args.(*starknet.GetNextDictKey) + return &GetNextDictKey{ + NextKey: parseCellRefer(args.NextKey), + }, nil + case starknet.Uint512DivModByUint256Name: + args := hint.Args.(*starknet.Uint512DivModByUint256) + return &Uint512DivModByUint256{ + dividend0: parseResOperand(args.Dividend0), + dividend1: parseResOperand(args.Dividend1), + dividend2: parseResOperand(args.Dividend2), + dividend3: parseResOperand(args.Dividend3), + divisor0: parseResOperand(args.Divisor0), + divisor1: parseResOperand(args.Divisor1), + quotient0: parseCellRefer(args.Quotient0), + quotient1: parseCellRefer(args.Quotient1), + quotient2: parseCellRefer(args.Quotient2), + quotient3: parseCellRefer(args.Quotient3), + remainder0: parseCellRefer(args.Remainder0), + remainder1: parseCellRefer(args.Remainder1), + }, nil + case starknet.AllocConstantSizeName: + args := hint.Args.(*starknet.AllocConstantSize) + return &AllocConstantSize{ + Dst: parseCellRefer(args.Dst), + Size: parseResOperand(args.Size), + }, nil + case starknet.AssertLeFindSmallArcsName: + args := hint.Args.(*starknet.AssertLeFindSmallArcs) + return &AssertLeFindSmallArc{ + A: parseResOperand(args.A), + B: parseResOperand(args.B), + RangeCheckPtr: parseResOperand(args.RangeCheckPtr), + }, nil + case starknet.AssertLeIsFirstArcExcludedName: + args := hint.Args.(*starknet.AssertLeIsFirstArcExcluded) + return &AssertLeIsFirstArcExcluded{ + SkipExcludeAFlag: parseCellRefer(args.SkipExcludeAFlag), + }, nil + case starknet.AssertLeIsSecondArcExcludedName: + args := hint.Args.(*starknet.AssertLeIsSecondArcExcluded) + return &AssertLeIsSecondArcExcluded{ + SkipExcludeBMinusA: parseCellRefer(args.SkipExcludeBMinusA), + }, nil + case starknet.RandomEcPointName: + args := hint.Args.(*starknet.RandomEcPoint) + return &RandomEcPoint{ + x: parseCellRefer(args.X), + y: parseCellRefer(args.Y), + }, nil + case starknet.FieldSqrtName: + args := hint.Args.(*starknet.FieldSqrt) + return &FieldSqrt{ + val: parseResOperand(args.Val), + sqrt: parseCellRefer(args.Sqrt), + }, nil + default: + return nil, fmt.Errorf("unknown hint: %v", hint.Name) + } +} diff --git a/pkg/hintrunner/core/cairo_hintparser_test.go b/pkg/hintrunner/core/cairo_hintparser_test.go new file mode 100644 index 000000000..2fe10c093 --- /dev/null +++ b/pkg/hintrunner/core/cairo_hintparser_test.go @@ -0,0 +1,428 @@ +package core + +import ( + "testing" + + "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter" + "github.com/NethermindEth/cairo-vm-go/pkg/parsers/starknet" + "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" + "github.com/stretchr/testify/require" +) + +func TestCairoHintParser(t *testing.T) { + t.Run("TestCairoHintParser", func(t *testing.T) { + cairoProgramString := []byte(` + { + "hints": [ + [ + 2, + [ + { + "AllocFelt252Dict": { + "segment_arena_ptr": { + "Deref": { + "register": "FP", + "offset": -4 + } + } + } + } + ] + ], + [ + 13, + [ + { + "AllocFelt252Dict": { + "segment_arena_ptr": { + "BinOp": { + "op": "Add", + "a": { + "register": "FP", + "offset": -4 + }, + "b": { + "Immediate": "0x3" + } + } + } + } + } + ] + ], + [ + 46, + [ + { + "Felt252DictEntryInit": { + "dict_ptr": { + "Deref": { + "register": "FP", + "offset": 2 + } + }, + "key": { + "Deref": { + "register": "AP", + "offset": -1 + } + } + } + } + ] + ], + [ + 49, + [ + { + "Felt252DictEntryUpdate": { + "dict_ptr": { + "BinOp": { + "op": "Add", + "a": { + "register": "FP", + "offset": 2 + }, + "b": { + "Immediate": "0x3" + } + } + }, + "value": { + "Deref": { + "register": "AP", + "offset": -1 + } + } + } + } + ] + ], + [ + 104, + [ + { + "GetSegmentArenaIndex": { + "dict_end_ptr": { + "Deref": { + "register": "FP", + "offset": -3 + } + }, + "dict_index": { + "register": "FP", + "offset": 0 + } + } + } + ] + ], + [ + 145, + [ + { + "AllocSegment": { + "dst": { + "register": "FP", + "offset": 3 + } + } + } + ] + ], + [ + 153, + [ + { + "InitSquashData": { + "dict_accesses": { + "Deref": { + "register": "FP", + "offset": -4 + } + }, + "ptr_diff": { + "Deref": { + "register": "FP", + "offset": 0 + } + }, + "n_accesses": { + "Deref": { + "register": "AP", + "offset": -1 + } + }, + "big_keys": { + "register": "FP", + "offset": 2 + }, + "first_key": { + "register": "FP", + "offset": 1 + } + } + } + ] + ], + [ + 172, + [ + { + "GetCurrentAccessIndex": { + "range_check_ptr": { + "Deref": { + "register": "FP", + "offset": -9 + } + } + } + } + ] + ], + [ + 185, + [ + { + "ShouldSkipSquashLoop": { + "should_skip_loop": { + "register": "AP", + "offset": -4 + } + } + } + ] + ], + [ + 187, + [ + { + "GetCurrentAccessDelta": { + "index_delta_minus1": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 198, + [ + { + "ShouldContinueSquashLoop": { + "should_continue": { + "register": "AP", + "offset": -4 + } + } + } + ] + ], + [ + 212, + [ + { + "GetNextDictKey": { + "next_key": { + "register": "FP", + "offset": 0 + } + } + } + ] + ], + [ + 231, + [ + { + "AssertLeFindSmallArcs": { + "range_check_ptr": { + "BinOp": { + "op": "Add", + "a": { + "register": "AP", + "offset": -4 + }, + "b": { + "Immediate": "0x1" + } + } + }, + "a": { + "Deref": { + "register": "FP", + "offset": -6 + } + }, + "b": { + "Deref": { + "register": "FP", + "offset": 0 + } + } + } + } + ] + ], + [ + 243, + [ + { + "AssertLeIsFirstArcExcluded": { + "skip_exclude_a_flag": { + "register": "AP", + "offset": 0 + } + } + } + ] + ], + [ + 255, + [ + { + "AssertLeIsSecondArcExcluded": { + "skip_exclude_b_minus_a": { + "register": "AP", + "offset": 0 + } + } + } + ] + ] + ] + } + `) + expectedHintMap := map[uint64][]hinter.Hinter{ + 2: { + &AllocFelt252Dict{ + SegmentArenaPtr: hinter.Deref{ + Deref: hinter.FpCellRef(-4), + }, + }, + }, + 13: { + &AllocFelt252Dict{ + SegmentArenaPtr: hinter.BinaryOp{ + Operator: hinter.Add, + Lhs: hinter.Deref{ + Deref: hinter.FpCellRef(-4), + }, + Rhs: hinter.Immediate(*new(fp.Element).SetInt64(3)), + }, + }, + }, + 46: { + &Felt252DictEntryInit{ + DictPtr: hinter.Deref{ + Deref: hinter.FpCellRef(2), + }, + Key: hinter.Deref{ + Deref: hinter.ApCellRef(-1), + }, + }, + }, + 49: { + &Felt252DictEntryUpdate{ + DictPtr: hinter.BinaryOp{ + Operator: hinter.Add, + Lhs: hinter.Deref{ + Deref: hinter.FpCellRef(2), + }, + Rhs: hinter.Immediate(*new(fp.Element).SetInt64(3)), + }, + Value: hinter.Deref{ + Deref: hinter.ApCellRef(-1), + }, + }, + }, + 104: { + &GetSegmentArenaIndex{ + DictEndPtr: hinter.Deref{ + Deref: hinter.FpCellRef(-3), + }, + DictIndex: hinter.FpCellRef(0), + }, + }, + 145: { + &AllocSegment{ + Dst: hinter.FpCellRef(3), + }, + }, + 153: { + &InitSquashData{ + DictAccesses: hinter.Deref{ + Deref: hinter.FpCellRef(-4), + }, + NumAccesses: hinter.Deref{ + Deref: hinter.ApCellRef(-1), + }, + BigKeys: hinter.FpCellRef(2), + FirstKey: hinter.FpCellRef(1), + }, + }, + 172: { + &GetCurrentAccessIndex{ + RangeCheckPtr: hinter.Deref{ + Deref: hinter.FpCellRef(-9), + }, + }, + }, + 185: { + &ShouldSkipSquashLoop{ + ShouldSkipLoop: hinter.ApCellRef(-4), + }, + }, + 187: { + &GetCurrentAccessDelta{ + IndexDeltaMinusOne: hinter.ApCellRef(0), + }, + }, + 198: { + &ShouldContinueSquashLoop{ + ShouldContinue: hinter.ApCellRef(-4), + }, + }, + 212: { + &GetNextDictKey{ + NextKey: hinter.FpCellRef(0), + }, + }, + 231: { + &AssertLeFindSmallArc{ + RangeCheckPtr: hinter.BinaryOp{ + Operator: hinter.Add, + Lhs: hinter.Deref{ + Deref: hinter.ApCellRef(-4), + }, + Rhs: hinter.Immediate(*new(fp.Element).SetInt64(1)), + }, + A: hinter.Deref{ + Deref: hinter.FpCellRef(-6), + }, + B: hinter.Deref{ + Deref: hinter.FpCellRef(0), + }, + }, + }, + 243: { + &AssertLeIsFirstArcExcluded{ + SkipExcludeAFlag: hinter.ApCellRef(0), + }, + }, + 255: { + &AssertLeIsSecondArcExcluded{ + SkipExcludeBMinusA: hinter.ApCellRef(0), + }, + }, + } + + starknetProgram, err := starknet.StarknetProgramFromJSON(cairoProgramString) + require.NoError(t, err) + output, err := GetCairoHints(starknetProgram) + require.NoError(t, err) + + require.Equal(t, expectedHintMap, output, "Hint maps do not match") + }) +} diff --git a/pkg/hintrunner/core/hint.go b/pkg/hintrunner/core/hint.go index a738570e8..469f4754b 100644 --- a/pkg/hintrunner/core/hint.go +++ b/pkg/hintrunner/core/hint.go @@ -9,12 +9,28 @@ import ( "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter" u "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/utils" + "github.com/NethermindEth/cairo-vm-go/pkg/parsers/starknet" "github.com/NethermindEth/cairo-vm-go/pkg/utils" VM "github.com/NethermindEth/cairo-vm-go/pkg/vm" mem "github.com/NethermindEth/cairo-vm-go/pkg/vm/memory" f "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" ) +func GetCairoHints(cairoProgramJson *starknet.StarknetProgram) (map[uint64][]hinter.Hinter, error) { + hints := make(map[uint64][]hinter.Hinter) + for _, hintsList := range cairoProgramJson.Hints { + for _, hint := range hintsList.Hints { + processedHint, err := GetHintByName(hint) + if err != nil { + return nil, err + } + hints[hintsList.Index] = append(hints[hintsList.Index], processedHint) + } + } + + return hints, nil +} + type AllocSegment struct { Dst hinter.CellRefer } @@ -188,6 +204,10 @@ type LinearSplit struct { y hinter.CellRefer } +func (hint LinearSplit) String() string { + return "LinearSplit" +} + func (hint LinearSplit) Execute(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error { value, err := hint.value.Resolve(vm) if err != nil { @@ -546,6 +566,10 @@ type DebugPrint struct { end hinter.ResOperander } +func (hint DebugPrint) String() string { + return "DebugPrint" +} + func (hint DebugPrint) Execute(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error { start, err := hint.start.Resolve(vm) if err != nil { @@ -1542,7 +1566,7 @@ func (hint *RandomEcPoint) String() string { return "RandomEc" } -func (hint *RandomEcPoint) Execute(vm *VM.VirtualMachine) error { +func (hint *RandomEcPoint) Execute(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error { // Keep sampling a random field element `X` until `X^3 + X + beta` is a quadratic residue. // Starkware's elliptic curve Beta value https://docs.starkware.co/starkex/crypto/stark-curve.html @@ -1601,7 +1625,7 @@ func (hint *FieldSqrt) String() string { return "FieldSqrt" } -func (hint *FieldSqrt) Execute(vm *VM.VirtualMachine) error { +func (hint *FieldSqrt) Execute(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error { val, err := hint.val.Resolve(vm) if err != nil { return fmt.Errorf("resolve val operand %s: %v", hint.val, err) diff --git a/pkg/hintrunner/core/hint_benchmark_test.go b/pkg/hintrunner/core/hint_benchmark_test.go index c70fccd90..5032645fc 100644 --- a/pkg/hintrunner/core/hint_benchmark_test.go +++ b/pkg/hintrunner/core/hint_benchmark_test.go @@ -410,7 +410,7 @@ func BenchmarkRandomEcPoint(b *testing.B) { y: hinter.ApCellRef(1), } - err := hint.Execute(vm) + err := hint.Execute(vm, nil) if err != nil { b.Error(err) break @@ -433,7 +433,7 @@ func BenchmarkFieldSqrt(b *testing.B) { sqrt: hinter.ApCellRef(0), } - err := hint.Execute(vm) + err := hint.Execute(vm, nil) if err != nil { b.Error(err) break diff --git a/pkg/hintrunner/core/hint_test.go b/pkg/hintrunner/core/hint_test.go index 0fce1b0ef..3525de565 100644 --- a/pkg/hintrunner/core/hint_test.go +++ b/pkg/hintrunner/core/hint_test.go @@ -1200,7 +1200,7 @@ func TestRandomEcPoint(t *testing.T) { y: hinter.ApCellRef(1), } - err := hint.Execute(vm) + err := hint.Execute(vm, nil) require.NoError(t, err) expectedX := mem.MemoryValueFromFieldElement( @@ -1247,7 +1247,7 @@ func TestFieldSqrt(t *testing.T) { sqrt: hinter.ApCellRef(0), } - err := hint.Execute(vm) + err := hint.Execute(vm, nil) require.NoError(t, err) require.Equal( diff --git a/pkg/parsers/cairo_version/cairo_version.go b/pkg/parsers/cairo_version/cairo_version.go new file mode 100644 index 000000000..c17104e3c --- /dev/null +++ b/pkg/parsers/cairo_version/cairo_version.go @@ -0,0 +1,30 @@ +package cairoversion + +import ( + "encoding/json" + "os" + "strconv" + "strings" +) + +type CairoVersion struct { + Version string `json:"compiler_version"` +} + +func GetCairoVersion(pathToFile string) (uint8, error) { + content, err := os.ReadFile(pathToFile) + if err != nil { + return 0, err + } + cv := CairoVersion{} + err = json.Unmarshal(content, &cv) + if err != nil { + return 0, err + } + firstNumberStr := strings.Split(cv.Version, ".")[0] + firstNumber, err := strconv.ParseUint(firstNumberStr, 10, 8) + if err != nil { + return 0, err + } + return uint8(firstNumber), nil +} diff --git a/pkg/parsers/starknet/hint.go b/pkg/parsers/starknet/hint.go index 0db74ff3b..9f6e62499 100644 --- a/pkg/parsers/starknet/hint.go +++ b/pkg/parsers/starknet/hint.go @@ -191,7 +191,7 @@ type ShouldSkipSquashLoop struct { } type GetCurrentAccessDelta struct { - IndexDeltaMinus1 CellRef `json:"index_delta_minus_1" validate:"required"` + IndexDeltaMinus1 CellRef `json:"index_delta_minus1" validate:"required"` } type ShouldContinueSquashLoop struct { @@ -291,6 +291,7 @@ const ( type Operand interface{} type ResOperand struct { + Name ResOperandName ResOperand Operand `validate:"required"` } @@ -303,16 +304,21 @@ func (ro *ResOperand) UnmarshalJSON(data []byte) error { } var op any + var name ResOperandName for k := range resOp { switch ResOperandName(k) { case DerefName: op = &Deref{} + name = DerefName case DoubleDerefName: op = &DoubleDeref{} + name = DoubleDerefName case ImmediateName: op = &Immediate{} + name = ImmediateName case BinOpName: op = &BinOp{} + name = BinOpName default: return fmt.Errorf("unknown res operand %s", k) } @@ -324,6 +330,7 @@ func (ro *ResOperand) UnmarshalJSON(data []byte) error { } ro.ResOperand = op + ro.Name = name return nil }