Repository: NethermindEth/cairo-vm-go
Pull request #663 (2024-09-17 08:47:30)

Implemented `all_cairo` layout and add tests for `RangeCheck96`
#643 


Patch:
diff --git a/pkg/vm/builtins/layouts.go b/pkg/vm/builtins/layouts.go
index 59baeb4..661598b 100644
--- a/pkg/vm/builtins/layouts.go
+++ b/pkg/vm/builtins/layouts.go
@@ -111,6 +111,22 @@ func getAllSolidityLayout() Layout {
 	}}
 }
 
+// TODO: Add mul_mod and add_mod builtins
+// refer: https://github.com/lambdaclass/cairo-vm/blob/main/vm/src/types/instance_definitions/builtins_instance_def.rs#L168
+func getAllCairoLayout() Layout {
+	return Layout{Name: "all_cairo", RcUnits: 8, Builtins: []LayoutBuiltin{
+		{Runner: &Output{}, Builtin: starknet.Output},
+		{Runner: &Pedersen{ratio: 256}, Builtin: starknet.Pedersen},
+		{Runner: &RangeCheck{ratio: 8, RangeCheckNParts: 8}, Builtin: starknet.RangeCheck},
+		{Runner: &ECDSA{ratio: 2048}, Builtin: starknet.ECDSA},
+		{Runner: &Bitwise{ratio: 16}, Builtin: starknet.Bitwise},
+		{Runner: &EcOp{ratio: 1024, cache: make(map[uint64]fp.Element)}, Builtin: starknet.ECOP},
+		{Runner: &Keccak{ratio: 2048, cache: make(map[uint64]fp.Element)}, Builtin: starknet.Keccak},
+		{Runner: &Poseidon{ratio: 256, cache: make(map[uint64]fp.Element)}, Builtin: starknet.Poseidon},
+		{Runner: &RangeCheck{ratio: 8, RangeCheckNParts: 6}, Builtin: starknet.RangeCheck96},
+	}}
+}
+
 func GetLayout(layout string) (Layout, error) {
 	switch layout {
 	case "plain":
@@ -131,6 +147,8 @@ func GetLayout(layout string) (Layout, error) {
 		return getRecursiveWithPoseidonLayout(), nil
 	case "all_solidity":
 		return getAllSolidityLayout(), nil
+	case "all_cairo":
+		return getAllCairoLayout(), nil
 	case "":
 		return getPlainLayout(), nil
 	default:


Test patch:
diff --git a/integration_tests/cairozero_test.go b/integration_tests/cairozero_test.go
index c13cf91..0b0861e 100644
--- a/integration_tests/cairozero_test.go
+++ b/integration_tests/cairozero_test.go
@@ -302,6 +302,8 @@ func runPythonVm(testFilename, path string) (time.Duration, string, string, erro
 		args = append(args, "--layout", "recursive_with_poseidon")
 	} else if strings.HasSuffix(testFilename, ".all_solidity.cairo") {
 		args = append(args, "--layout", "all_solidity")
+	} else if strings.HasSuffix(testFilename, ".all_cairo.cairo") {
+		args = append(args, "--layout", "all_cairo")
 	}
 
 	cmd := exec.Command("cairo-run", args...)
@@ -347,6 +349,8 @@ func runVm(path string) (time.Duration, string, string, string, error) {
 		layout = "recursive_with_poseidon"
 	} else if strings.Contains(path, ".all_solidity") {
 		layout = "all_solidity"
+	} else if strings.Contains(path, ".all_cairo") {
+		layout = "all_cairo"
 	}
 
 	cmd := exec.Command(
diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go
index 45eb5a4..f6953ea 100644
--- a/pkg/runner/runner_test.go
+++ b/pkg/runner/runner_test.go
@@ -334,6 +334,52 @@ func TestRangeCheckBuiltinError(t *testing.T) {
 	require.ErrorContains(t, err, "cannot infer value")
 }
 
+func TestRangeCheck96Builtin(t *testing.T) {
+	// range_check96 is located at fp - 3 (fp - 2 and fp - 1 contain initialization vals)
+	// we write 5 and 2**96 - 1 to range check
+	// no error should come from this
+	runner := createRunner(`
+        [ap] = 5;
+        [ap] = [[fp - 3]];
+        [ap + 1] = 0xffffffffffffffffffffffff;
+        [ap + 1] = [[fp - 3] + 1];
+        ret;
+    `, "all_cairo", sn.RangeCheck96)
+
+	err := runner.Run()
+	require.NoError(t, err)
+
+	rangeCheck96, ok := runner.vm.Memory.FindSegmentWithBuiltin("range_check96")
+	require.True(t, ok)
+
+	felt := &fp.Element{}
+	felt, err = felt.SetString("0xffffffffffffffffffffffff")
+	require.NoError(t, err)
+
+	requireEqualSegments(t, createSegment(5, felt), rangeCheck96)
+}
+
+func TestRangeCheck96BuiltinError(t *testing.T) {
+	// first test fails due to out of bound check
+	runner := createRunner(`
+        [ap] = 0x1000000000000000000000000;
+        [ap] = [[fp - 3]];
+        ret;
+    `, "all_cairo", sn.RangeCheck96)
+
+	err := runner.Run()
+	require.ErrorContains(t, err, "check write: 2**96 <")
+
+	// second test fails due to reading unknown value
+	runner = createRunner(`
+        [ap] = [[fp - 3]];
+        ret;
+    `, "all_cairo", sn.RangeCheck96)
+
+	err = runner.Run()
+	require.ErrorContains(t, err, "cannot infer value")
+}
+
 func TestEcOpBuiltin(t *testing.T) {
 	// first, store P.x, P.y, Q.x, Q.y and m in the data segment
 	// then store them the EcOp builtin segment