Skip to content

Commit

Permalink
Add split int hints (#274)
Browse files Browse the repository at this point in the history
* Save work in progresx

* Add split int hints and integration test

* Add split int unitary test

* Add more unit test
  • Loading branch information
entropidelic authored Sep 20, 2023
1 parent 0510488 commit edaabf3
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 0 deletions.
18 changes: 18 additions & 0 deletions cairo_programs/split_int.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
%builtins range_check

from starkware.cairo.common.math import split_int
from starkware.cairo.common.alloc import alloc

func main{range_check_ptr: felt}() {
alloc_locals;
let value = 456;
let n = 3;
let base = 10;
let bound = 1000;
let output: felt* = alloc();
split_int(value, n, base, bound, output);
assert output[0] = 6;
assert output[1] = 5;
assert output[2] = 4;
return ();
}
4 changes: 4 additions & 0 deletions pkg/hints/hint_codes/math_hint_codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,7 @@ const ASSERT_LT_FELT = "from starkware.cairo.common.math_utils import assert_int
const ASSERT_250_BITS = "from starkware.cairo.common.math_utils import as_int\n\n# Correctness check.\nvalue = as_int(ids.value, PRIME) % PRIME\nassert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**250).'\n\n# Calculation for the assertion.\nids.high, ids.low = divmod(ids.value, ids.SHIFT)"

const SPLIT_FELT = "from starkware.cairo.common.math_utils import assert_integer\nassert ids.MAX_HIGH < 2**128 and ids.MAX_LOW < 2**128\nassert PRIME - 1 == ids.MAX_HIGH * 2**128 + ids.MAX_LOW\nassert_integer(ids.value)\nids.low = ids.value & ((1 << 128) - 1)\nids.high = ids.value >> 128"

const SPLIT_INT = "memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base\nassert res < ids.bound, f'split_int(): Limb {res} is out of range.'"

const SPLIT_INT_ASSERT_RANGE = "assert ids.value == 0, 'split_int(): value is out of range.'"
4 changes: 4 additions & 0 deletions pkg/hints/hint_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any,
return Assert250Bit(data.Ids, vm, constants)
case SPLIT_FELT:
return SplitFelt(data.Ids, vm, constants)
case SPLIT_INT:
return splitInt(data.Ids, vm)
case SPLIT_INT_ASSERT_RANGE:
return splitIntAssertRange(data.Ids, vm)
default:
return errors.Errorf("Unknown Hint: %s", data.Code)
}
Expand Down
63 changes: 63 additions & 0 deletions pkg/hints/math_hints.go
Original file line number Diff line number Diff line change
Expand Up @@ -542,3 +542,66 @@ func SplitFelt(ids IdsManager, vm *VirtualMachine, constants *map[string]Felt) e

return nil
}

/*
Implements hint:
%{
memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base
assert res < ids.bound, f'split_int(): Limb {res} is out of range.'"
%}
*/
func splitInt(ids IdsManager, vm *VirtualMachine) error {
value, err := ids.GetFelt("value", vm)
if err != nil {
return err
}

base, err := ids.GetFelt("base", vm)
if err != nil {
return err
}

bound, err := ids.GetFelt("bound", vm)
if err != nil {
return err
}

output, err := ids.GetRelocatable("output", vm)
if err != nil {
return err
}

res := value.ModFloor(base)

if res.Cmp(bound) == 1 {
return errors.Errorf("split_int(): Limb %d is out of range", res.ToBigInt())
}

err = vm.Segments.Memory.Insert(output, NewMaybeRelocatableFelt(res))
if err != nil {
return err
}

return nil
}

/*
Implements hint:
%{
assert ids.value == 0, 'split_int(): value is out of range.'
%}
*/
func splitIntAssertRange(ids IdsManager, vm *VirtualMachine) error {
value, err := ids.GetFelt("value", vm)
if err != nil {
return err
}

if !value.IsZero() {
return errors.Errorf("split_int(): value is out of range")
}

return nil
}
103 changes: 103 additions & 0 deletions pkg/hints/math_hints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1035,3 +1035,106 @@ func TestSplitFeltSuccess(t *testing.T) {
t.Errorf("Expected low == 0. Got: %v", low)
}
}

func TestSplitIntHintSuccess(t *testing.T) {
vm := NewVirtualMachine()
vm.Segments.AddSegment()
idsManager := SetupIdsForTest(
map[string][]*MaybeRelocatable{
"value": {NewMaybeRelocatableFelt(FeltFromDecString("6"))},
"base": {NewMaybeRelocatableFelt(FeltFromDecString("4"))},
"bound": {NewMaybeRelocatableFelt(FeltFromDecString("58"))},
"output": {NewMaybeRelocatableRelocatable(NewRelocatable(0, 4))},
},
vm,
)

hintProcessor := CairoVmHintProcessor{}
hintData := any(HintData{
Ids: idsManager,
Code: SPLIT_INT,
})

err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil)
if err != nil {
t.Errorf("SPLIT_INT hint failed with error %s", err)
}

res, err := vm.Segments.Memory.GetFelt(NewRelocatable(0, 4))
if err != nil {
t.Errorf("SPLIT_INT hint failed, `res` value not inserted")
}

if res.Cmp(lambdaworks.FeltFromUint64(2)) != 0 {
t.Errorf("SPLIT_INT hint failed. Expected 2, got: %d", res.ToBigInt())
}
}

func TestSplitIntHintOutOfBoundsError(t *testing.T) {
vm := NewVirtualMachine()
vm.Segments.AddSegment()
idsManager := SetupIdsForTest(
map[string][]*MaybeRelocatable{
"value": {NewMaybeRelocatableFelt(FeltFromDecString("17"))},
"base": {NewMaybeRelocatableFelt(FeltFromDecString("9"))},
"bound": {NewMaybeRelocatableFelt(FeltFromDecString("5"))},
"output": {NewMaybeRelocatableRelocatable(NewRelocatable(0, 4))},
},
vm,
)

hintProcessor := CairoVmHintProcessor{}
hintData := any(HintData{
Ids: idsManager,
Code: SPLIT_INT,
})

err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil)
if err == nil {
t.Errorf("SPLIT_INT hint should have failed")
}
}

func TestSplitIntAssertRangeHintSuccess(t *testing.T) {
vm := NewVirtualMachine()
vm.Segments.AddSegment()
idsManager := SetupIdsForTest(
map[string][]*MaybeRelocatable{
"value": {NewMaybeRelocatableFelt(FeltFromDecString("0"))},
},
vm,
)

hintProcessor := CairoVmHintProcessor{}
hintData := any(HintData{
Ids: idsManager,
Code: SPLIT_INT_ASSERT_RANGE,
})

err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil)
if err != nil {
t.Errorf("SPLIT_INT_ASSERT_RANGE hint failed with error: %s", err)
}
}

func TestSplitIntAssertRangeHintOutOfRangeError(t *testing.T) {
vm := NewVirtualMachine()
vm.Segments.AddSegment()
idsManager := SetupIdsForTest(
map[string][]*MaybeRelocatable{
"value": {NewMaybeRelocatableFelt(FeltFromDecString("3"))},
},
vm,
)

hintProcessor := CairoVmHintProcessor{}
hintData := any(HintData{
Ids: idsManager,
Code: SPLIT_INT_ASSERT_RANGE,
})

err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil)
if err == nil {
t.Errorf("SPLIT_INT_ASSERT_RANGE hint should have failed")
}
}
8 changes: 8 additions & 0 deletions pkg/vm/cairo_run/cairo_run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,11 @@ func TestDictSquash(t *testing.T) {
func TestSplitFeltHint(t *testing.T) {
testProgram("split_felt", t)
}

func TestSplitIntHint(t *testing.T) {
cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, Layout: "all_cairo", ProofMode: false}
_, err := cairo_run.CairoRun("../../../cairo_programs/split_int.json", cairoRunConfig)
if err != nil {
t.Errorf("Program execution failed with error: %s", err)
}
}

0 comments on commit edaabf3

Please sign in to comment.