diff --git a/cairo_programs/uint256_integration_tests.cairo b/cairo_programs/uint256_integration_tests.cairo new file mode 100644 index 00000000..70599483 --- /dev/null +++ b/cairo_programs/uint256_integration_tests.cairo @@ -0,0 +1,151 @@ +%builtins range_check bitwise + +from starkware.cairo.common.uint256 import ( + Uint256, + uint256_add, + split_64, + uint256_sqrt, + uint256_signed_nn, + uint256_unsigned_div_rem, + uint256_mul, + uint256_or, + uint256_reverse_endian, +) +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import BitwiseBuiltin + +func fill_array(array_start: felt*, base: felt, step: felt, iter: felt, last: felt) -> () { + if (iter == last) { + return (); + } + assert array_start[iter] = base + step; + return fill_array(array_start, base + step, step, iter + 1, last); +} + +func fill_uint256_array{range_check_ptr: felt}( + array: Uint256*, base: Uint256, step: Uint256, array_len: felt, iterator: felt +) { + if (iterator == array_len) { + return (); + } + let (res: Uint256, carry_high: felt) = uint256_add(step, base); + + assert array[iterator] = res; + return fill_uint256_array(array, base, array[iterator], array_len, iterator + 1); +} + +func test_sqrt{range_check_ptr}( + base_array: Uint256*, new_array: Uint256*, iter: felt, last: felt +) -> () { + alloc_locals; + + if (iter == last) { + return (); + } + + let res: Uint256 = uint256_sqrt(base_array[iter]); + assert new_array[iter] = res; + + return test_sqrt(base_array, new_array, iter + 1, last); +} + +func test_signed_nn{range_check_ptr}( + base_array: Uint256*, new_array: felt*, iter: felt, last: felt +) -> () { + alloc_locals; + + if (iter == last) { + return (); + } + + let res: felt = uint256_signed_nn(base_array[iter]); + assert res = 1; + assert new_array[iter] = res; + + return test_signed_nn(base_array, new_array, iter + 1, last); +} + +func test_unsigned_div_rem{range_check_ptr}( + base_array: Uint256*, new_array: Uint256*, iter: felt, last: felt +) -> () { + alloc_locals; + + if (iter == last) { + return (); + } + + let (quotient: Uint256, remainder: Uint256) = uint256_unsigned_div_rem( + base_array[iter], Uint256(7, 8) + ); + assert new_array[(iter * 2)] = quotient; + assert new_array[(iter * 2) + 1] = remainder; + + return test_unsigned_div_rem(base_array, new_array, iter + 1, last); +} + +func test_split_64{range_check_ptr}( + base_array: felt*, new_array: felt*, iter: felt, last: felt +) -> () { + alloc_locals; + + if (iter == last) { + return (); + } + + let (low: felt, high: felt) = split_64(base_array[iter]); + assert new_array[(iter * 2)] = low; + assert new_array[(iter * 2) + 1] = high; + return test_split_64(base_array, new_array, iter + 1, last); +} + +func test_integration{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + base_array: Uint256*, new_array: Uint256*, iter: felt, last: felt +) -> () { + alloc_locals; + + if (iter == last) { + return (); + } + + let (add: Uint256, carry_high: felt) = uint256_add(base_array[iter], base_array[iter + 1]); + let (quotient: Uint256, remainder: Uint256) = uint256_unsigned_div_rem(add, Uint256(5, 3)); + let (low: Uint256, high: Uint256) = uint256_mul(quotient, remainder); + let (bitwise_or: Uint256) = uint256_or(low, high); + let (reverse_endian: Uint256) = uint256_reverse_endian(bitwise_or); + let (result: Uint256) = uint256_sqrt(reverse_endian); + + assert new_array[iter] = result; + return test_integration(base_array, new_array, iter + 1, last); +} + +func run_tests{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(array_len: felt) -> () { + alloc_locals; + let (uint256_array: Uint256*) = alloc(); + fill_uint256_array(uint256_array, Uint256(57, 8), Uint256(57, 101), array_len, 0); + + let (array_sqrt: Uint256*) = alloc(); + test_sqrt(uint256_array, array_sqrt, 0, array_len); + + let (array_signed_nn: felt*) = alloc(); + test_signed_nn(uint256_array, array_signed_nn, 0, array_len); + + let (array_unsigned_div_rem: Uint256*) = alloc(); + test_unsigned_div_rem(uint256_array, array_unsigned_div_rem, 0, array_len); + + let (felt_array: felt*) = alloc(); + fill_array(felt_array, 0, 3, 0, array_len); + + let (array_split_64: felt*) = alloc(); + test_split_64(felt_array, array_split_64, 0, array_len); + + let (array_test_integration: Uint256*) = alloc(); + test_integration(uint256_array, array_test_integration, 0, array_len - 1); + + return (); +} + +func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() { + run_tests(10); + + return (); +} diff --git a/pkg/hints/hint_utils/ids_manager.go b/pkg/hints/hint_utils/ids_manager.go index 11b703a4..e59b4092 100644 --- a/pkg/hints/hint_utils/ids_manager.go +++ b/pkg/hints/hint_utils/ids_manager.go @@ -241,8 +241,7 @@ func (ids *IdsManager) InsertUint256(name string, val lambdaworks.Uint256, vm *V // Inserts value into ap address func (ids *IdsManager) InsertValueIntoAP(vm *VirtualMachine, value MaybeRelocatable) error { - apAddr := NewRelocatable(ids.HintApTracking.Group, uint(ids.HintApTracking.Offset)) - return vm.Segments.Memory.Insert(apAddr, &value) + return vm.Segments.Memory.Insert(vm.RunContext.Ap, &value) } // Inserts value into the address of the given identifier diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index 2f74d244..6170f337 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -1,6 +1,7 @@ package hints import ( + "fmt" "math/big" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" @@ -30,6 +31,7 @@ Implements hints: */ func uint256Add(ids IdsManager, vm *VirtualMachine, lowOnly bool) error { + fmt.Println("enter: uint256Add") shift := FeltOne().Shl(128) aLow, err := ids.GetStructFieldFelt("a", 0, vm) if err != nil { @@ -71,6 +73,7 @@ func uint256Add(ids IdsManager, vm *VirtualMachine, lowOnly bool) error { ids.Insert("carry_high", NewMaybeRelocatableFelt(carryHigh), vm) } + fmt.Println("exit: uint256Add") return ids.Insert("carry_low", NewMaybeRelocatableFelt(carryLow), vm) } @@ -85,6 +88,7 @@ Implements hint: %} */ func split64(ids IdsManager, vm *VirtualMachine) error { + fmt.Println("enter: split64") a, err := ids.GetFelt("a", vm) if err != nil { return err @@ -100,6 +104,7 @@ func split64(ids IdsManager, vm *VirtualMachine) error { if err != nil { return err } + fmt.Println("exit: split64") return nil } @@ -118,6 +123,7 @@ Implements hint: %} */ func uint256Sqrt(ids IdsManager, vm *VirtualMachine, onlyLow bool) error { + fmt.Println("enter: uint256Sqrt") uintN, err := ids.GetUint256("n", vm) if err != nil { return err @@ -132,8 +138,10 @@ func uint256Sqrt(ids IdsManager, vm *VirtualMachine, onlyLow bool) error { feltRoot := FeltFromBigInt(root) if onlyLow { + fmt.Println("1. exit: uint256Sqrt") return ids.Insert("root", NewMaybeRelocatableFelt(feltRoot), vm) } else { + fmt.Println("2. exit: uint256Sqrt") return ids.InsertUint256("root", lambdaworks.Uint256{Low: feltRoot, High: FeltZero()}, vm) } } @@ -143,13 +151,16 @@ Implements hint: %{ memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0 %} */ func uint256SignedNN(ids IdsManager, vm *VirtualMachine) error { + fmt.Println("enter: uint256SignedNN") a, err := ids.GetUint256("a", vm) if err != nil { return err } if a.High.Cmp(SignedFeltMaxValue()) != 1 { + fmt.Println("1. exit: uint256SignedNN") return ids.InsertValueIntoAP(vm, *NewMaybeRelocatableFelt(FeltOne())) } else { + fmt.Println("2. exit: uint256SignedNN") return ids.InsertValueIntoAP(vm, *NewMaybeRelocatableFelt(FeltZero())) } } @@ -170,7 +181,9 @@ Implements hint: %} */ func uint256UnsignedDivRem(ids IdsManager, vm *VirtualMachine) error { + fmt.Println("enter: uint256UnsignedDivRem") return uint256OfssetedUnisgnedDivRem(ids, vm, 0, 1) + } /* @@ -193,20 +206,16 @@ func uint256ExpandedUnsignedDivRem(ids IdsManager, vm *VirtualMachine) error { } func uint256OfssetedUnisgnedDivRem(ids IdsManager, vm *VirtualMachine, divOffsetLow uint, divOffsetHigh uint) error { + fmt.Println("enter: uint256OfssetedUnisgnedDivRem") a, err := ids.GetUint256("a", vm) if err != nil { return err } - - baseDiv, err := ids.GetRelocatable("div", vm) - if err != nil { - return err - } - divLow, err := vm.Segments.Memory.GetFelt(baseDiv.AddUint(divOffsetLow)) + divLow, err := ids.GetStructFieldFelt("div", divOffsetLow, vm) if err != nil { return err } - divHigh, err := vm.Segments.Memory.GetFelt(baseDiv.AddUint(divOffsetHigh)) + divHigh, err := ids.GetStructFieldFelt("div", divOffsetHigh, vm) if err != nil { return err } @@ -215,6 +224,7 @@ func uint256OfssetedUnisgnedDivRem(ids IdsManager, vm *VirtualMachine, divOffset err = ids.InsertUint256("quotient", ToUint256(q), vm) if err != nil { + fmt.Println("error: uint256OfssetedUnisgnedDivRem") return err } return ids.InsertUint256("remainder", ToUint256(r), vm) @@ -237,6 +247,7 @@ Implements hint: %} */ func uint256MulDivMod(ids IdsManager, vm *VirtualMachine) error { + fmt.Println("enter: uint256MulDivMod") a, err := ids.GetUint256("a", vm) if err != nil { return err @@ -277,6 +288,7 @@ func uint256MulDivMod(ids IdsManager, vm *VirtualMachine) error { if err != nil { return err } + fmt.Println("exit: uint256MulDivMod") return ids.InsertUint256("remainder", remainder, vm) } diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index 2438042d..102c8ea5 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -413,7 +413,6 @@ func TestUint256SignedNNOkResultOne(t *testing.T) { }, } idsManager := SetupIdsForTest(ids, vm) - idsManager.HintApTracking = parser.ApTrackingData{Group: 4, Offset: 5} hintData := any(HintData{ Ids: idsManager, Code: UINT256_SIGNED_NN, @@ -424,7 +423,7 @@ func TestUint256SignedNNOkResultOne(t *testing.T) { t.Errorf("failed with error: %s", err) } - result, err := vm.Segments.Memory.GetFelt(NewRelocatable(4, 5)) + result, err := vm.Segments.Memory.GetFelt(vm.RunContext.Ap) if err != nil { t.Errorf("failed with error: %s", err) } @@ -436,7 +435,8 @@ func TestUint256SignedNNOkResultOne(t *testing.T) { func TestUint256SignedNNOkResultZero(t *testing.T) { vm := NewVirtualMachine() - vm.Segments = AddNSegments(vm.Segments, 5) + vm.Segments.AddSegment() + vm.RunContext.Ap = NewRelocatable(0, 5) ids := map[string][]*MaybeRelocatable{ "a": { NewMaybeRelocatableFelt(FeltFromUint64(1)), @@ -444,7 +444,6 @@ func TestUint256SignedNNOkResultZero(t *testing.T) { }, } idsManager := SetupIdsForTest(ids, vm) - idsManager.HintApTracking = parser.ApTrackingData{Group: 4, Offset: 5} hintData := any(HintData{ Ids: idsManager, Code: UINT256_SIGNED_NN, @@ -455,23 +454,21 @@ func TestUint256SignedNNOkResultZero(t *testing.T) { t.Errorf("failed with error: %s", err) } - result, err := vm.Segments.Memory.GetFelt(NewRelocatable(4, 5)) + result, err := vm.Segments.Memory.GetFelt(vm.RunContext.Ap) if err != nil { t.Errorf("failed with error: %s", err) } if result != FeltZero() { - t.Errorf("failed, expected result: %d, got: %d", FeltOne(), result) + t.Errorf("failed, expected result: %d, got: %d", FeltZero(), result) } } func TestUint256SignedNNInvalidMemoryInser(t *testing.T) { vm := NewVirtualMachine() - vm.Segments = AddNSegments(vm.Segments, 5) - err := vm.Segments.Memory.Insert(NewRelocatable(4, 5), NewMaybeRelocatableFeltFromUint64(10)) - if err != nil { - t.Errorf("failed with error: %s", err) - } + vm.Segments.AddSegment() + vm.RunContext.Ap = NewRelocatable(0, 5) + vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFeltFromUint64(10)) ids := map[string][]*MaybeRelocatable{ "a": { NewMaybeRelocatableFelt(FeltFromUint64(1)), @@ -485,8 +482,9 @@ func TestUint256SignedNNInvalidMemoryInser(t *testing.T) { Code: UINT256_SIGNED_NN, }) hintProcessor := CairoVmHintProcessor{} - err = hintProcessor.ExecuteHint(vm, &hintData, nil, nil) - expectedErr := ErrMemoryWriteOnce(NewRelocatable(4, 5), *NewMaybeRelocatableFeltFromUint64(10), *NewMaybeRelocatableFelt(FeltOne())) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + + expectedErr := ErrMemoryWriteOnce(NewRelocatable(0, 5), *NewMaybeRelocatableFeltFromUint64(10), *NewMaybeRelocatableFelt(FeltOne())) if err.Error() != expectedErr.Error() { t.Errorf("should fail with error: %s", err) } @@ -497,22 +495,15 @@ func TestUint256UnsignedDivRemOk(t *testing.T) { vm.Segments.AddSegment() vm.Segments.AddSegment() - // add div low - err := vm.Segments.Memory.Insert(NewRelocatable(1, 6), NewMaybeRelocatableFelt(FeltFromUint64(3))) - if err != nil { - t.Errorf("failed with error: %s", err) - } - // add div high - err = vm.Segments.Memory.Insert(NewRelocatable(1, 7), NewMaybeRelocatableFeltFromUint64(7)) - if err != nil { - t.Errorf("failed with error: %s", err) - } ids := map[string][]*MaybeRelocatable{ "a": { NewMaybeRelocatableFeltFromUint64(89), NewMaybeRelocatableFeltFromUint64(72), }, - "div": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 6))}, + "div": { + NewMaybeRelocatableFeltFromUint64(3), + NewMaybeRelocatableFeltFromUint64(7), + }, "quotient": {nil, nil}, "remainder": {nil, nil}, } @@ -522,7 +513,7 @@ func TestUint256UnsignedDivRemOk(t *testing.T) { Code: UINT256_UNSIGNED_DIV_REM, }) hintProcessor := CairoVmHintProcessor{} - err = hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) if err != nil { t.Errorf("failed with error: %s", err) } @@ -554,28 +545,16 @@ func TestUint256UnsignedDivRemInvalidMemoryInsert(t *testing.T) { vm.Segments.AddSegment() vm.Segments.AddSegment() - // add div low - err := vm.Segments.Memory.Insert(NewRelocatable(1, 6), NewMaybeRelocatableFelt(FeltFromUint64(3))) - if err != nil { - t.Errorf("failed with error: %s", err) - } - // add div high - err = vm.Segments.Memory.Insert(NewRelocatable(1, 7), NewMaybeRelocatableFeltFromUint64(7)) - if err != nil { - t.Errorf("failed with error: %s", err) - } - // add hardcoded value on quotient.low - err = vm.Segments.Memory.Insert(NewRelocatable(0, 3), NewMaybeRelocatableFeltFromUint64(8)) - if err != nil { - t.Errorf("failed with error: %s", err) - } ids := map[string][]*MaybeRelocatable{ "a": { NewMaybeRelocatableFeltFromUint64(89), NewMaybeRelocatableFeltFromUint64(72), }, - "div": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 6))}, - "quotient": {nil, nil}, + "div": { + NewMaybeRelocatableFeltFromUint64(3), + NewMaybeRelocatableFeltFromUint64(7), + }, + "quotient": {NewMaybeRelocatableFeltFromUint64(2), NewMaybeRelocatableFelt(FeltZero())}, "remainder": {nil, nil}, } idsManager := SetupIdsForTest(ids, vm) @@ -584,10 +563,9 @@ func TestUint256UnsignedDivRemInvalidMemoryInsert(t *testing.T) { Code: UINT256_UNSIGNED_DIV_REM, }) hintProcessor := CairoVmHintProcessor{} - err = hintProcessor.ExecuteHint(vm, &hintData, nil, nil) - expectedErr := ErrMemoryWriteOnce(NewRelocatable(0, 3), *NewMaybeRelocatableFeltFromUint64(8), *NewMaybeRelocatableFeltFromUint64(10)) - if err.Error() != expectedErr.Error() { - t.Errorf("failed with error: %s", err) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err == nil { + t.Errorf("this test should fail") } } @@ -596,22 +574,18 @@ func TestUint256ExpandedUnsignedDivRemOk(t *testing.T) { vm.Segments.AddSegment() vm.Segments.AddSegment() - // add div low - err := vm.Segments.Memory.Insert(NewRelocatable(1, 7), NewMaybeRelocatableFelt(FeltFromUint64(3))) - if err != nil { - t.Errorf("failed with error: %s", err) - } - // add div high - err = vm.Segments.Memory.Insert(NewRelocatable(1, 9), NewMaybeRelocatableFeltFromUint64(7)) - if err != nil { - t.Errorf("failed with error: %s", err) - } ids := map[string][]*MaybeRelocatable{ "a": { NewMaybeRelocatableFeltFromUint64(89), NewMaybeRelocatableFeltFromUint64(72), }, - "div": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 6))}, + + "div": { + NewMaybeRelocatableFelt(FeltFromDecString("55340232221128654848")), + NewMaybeRelocatableFeltFromUint64(3), + NewMaybeRelocatableFelt(FeltFromDecString("129127208515966861312")), + NewMaybeRelocatableFeltFromUint64(7), + }, "quotient": {nil, nil}, "remainder": {nil, nil}, } @@ -621,7 +595,7 @@ func TestUint256ExpandedUnsignedDivRemOk(t *testing.T) { Code: UINT256_EXPANDED_UNSIGNED_DIV_REM, }) hintProcessor := CairoVmHintProcessor{} - err = hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) if err != nil { t.Errorf("failed with error: %s", err) } diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index 47fb4e24..17498da2 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -335,3 +335,7 @@ func TestCairoKeccak(t *testing.T) { func TestKeccakAddUint256(t *testing.T) { testProgram("keccak_add_uint256", t) } + +func TestUint256Integration(t *testing.T) { + testProgram("uint256_integration_tests", t) +}