From 1b85c7d20e2ac376de120a6bed0cd76bf9f505a2 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Thu, 21 Sep 2023 09:44:03 +0200 Subject: [PATCH 01/31] draft uint256 add --- pkg/hints/hint_codes/uint256_hint_codes.go | 3 ++ pkg/hints/hint_processor.go | 2 + pkg/hints/uint256_hints.go | 48 ++++++++++++++++++++++ pkg/hints/uint256_hints_test.go | 0 4 files changed, 53 insertions(+) create mode 100644 pkg/hints/hint_codes/uint256_hint_codes.go create mode 100644 pkg/hints/uint256_hints.go create mode 100644 pkg/hints/uint256_hints_test.go diff --git a/pkg/hints/hint_codes/uint256_hint_codes.go b/pkg/hints/hint_codes/uint256_hint_codes.go new file mode 100644 index 00000000..260802e4 --- /dev/null +++ b/pkg/hints/hint_codes/uint256_hint_codes.go @@ -0,0 +1,3 @@ +package hint_codes + +const UINT256_ADD = "sum_low = ids.a.low + ids.b.low \n ids.carry_low = 1 if sum_low >= ids.SHIFT else 0 \n sum_high = ids.a.high + ids.b.high + ids.carry_low \n ids.carry_high = 1 if sum_high >= ids.SHIFT else 0" diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 75cbc952..f840e2c7 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -138,6 +138,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return splitInt(data.Ids, vm) case SPLIT_INT_ASSERT_RANGE: return splitIntAssertRange(data.Ids, vm) + case UINT256_ADD: + return uint256Add(data.Ids, execScopes, vm, false) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go new file mode 100644 index 00000000..28310ae0 --- /dev/null +++ b/pkg/hints/uint256_hints.go @@ -0,0 +1,48 @@ +package hints + +import ( + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + . "github.com/lambdaclass/cairo-vm.go/pkg/types" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" +) + +type Uint256 struct { + low Felt + high Felt +} + +/* +Implements hints: +%{ + sum_low = ids.a.low + ids.b.low + ids.carry_low = 1 if sum_low >= ids.SHIFT else 0 + sum_high = ids.a.high + ids.b.high + ids.carry_low + ids.carry_high = 1 if sum_high >= ids.SHIFT else 0 +%} +%{ + sum_low = ids.a.low + ids.b.low + ids.carry_low = 1 if sum_low >= ids.SHIFT else 0 +%} +*/ + +func uint256Add(ids IdsManager, scopes *ExecutionScopes, vm *VirtualMachine, lowOnly bool) error { + shift := FeltOne().Shl(128) + a, err := ids.GetStructField("a", vm) + b, err := ids.GetUint256("b", vm) + aLow := a.low + bLow := b.low + sumLow := aLow.Add(bLow) + carryLow := FeltFromUint64(sumLow >= shift) + if !lowOnly { + aHigh := a.high + bHigh := b.high + sumHigh := aHigh.Add(bHigh.Add(carryLow)) + carryHigh := FeltFromUint64(sumHigh >= sumHigh) + ids.InsertStructField("carry_high") + } + + ids.InsertStructField("carry_low") + +} diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go new file mode 100644 index 00000000..e69de29b From a7b78c09bcf64a9ab8a77f08f0d2ed04671911d0 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Thu, 21 Sep 2023 09:58:24 +0200 Subject: [PATCH 02/31] implement hint uint256_add --- pkg/hints/uint256_hints.go | 46 +++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index 28310ae0..fd0f0ea0 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -29,20 +29,46 @@ Implements hints: func uint256Add(ids IdsManager, scopes *ExecutionScopes, vm *VirtualMachine, lowOnly bool) error { shift := FeltOne().Shl(128) - a, err := ids.GetStructField("a", vm) - b, err := ids.GetUint256("b", vm) - aLow := a.low - bLow := b.low + aLow, err := ids.GetStructFieldFelt("a", 0, vm) + if err != nil { + return err + } + + bLow, err := ids.GetStructFieldFelt("b", 0, vm) + if err != nil { + return err + } + sumLow := aLow.Add(bLow) - carryLow := FeltFromUint64(sumLow >= shift) + var carryLow Felt + switch sumLow.Cmp(shift) { + case -1: + carryLow = FeltZero() + default: + carryLow = FeltOne() + } + if !lowOnly { - aHigh := a.high - bHigh := b.high + aHigh, err := ids.GetStructFieldFelt("a", 1, vm) + if err != nil { + return err + } + bHigh, err := ids.GetStructFieldFelt("b", 1, vm) + if err != nil { + return err + } + sumHigh := aHigh.Add(bHigh.Add(carryLow)) - carryHigh := FeltFromUint64(sumHigh >= sumHigh) - ids.InsertStructField("carry_high") + var carryHigh Felt + switch sumHigh.Cmp(shift) { + case -1: + carryHigh = FeltZero() + default: + carryHigh = FeltOne() + } + ids.Insert("carry_high", NewMaybeRelocatableFelt(carryHigh), vm) } - ids.InsertStructField("carry_low") + return ids.Insert("carry_low", NewMaybeRelocatableFelt(carryLow), vm) } From 6c00a5f1eabf736e0c43393c847834d4d418c395 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Thu, 21 Sep 2023 11:37:14 +0200 Subject: [PATCH 03/31] add tests --- pkg/hints/uint256_hints_test.go | 265 ++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index e69de29b..de661c22 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -0,0 +1,265 @@ +package hints_test + +import ( + "testing" + + . "github.com/lambdaclass/cairo-vm.go/pkg/hints" + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + . "github.com/lambdaclass/cairo-vm.go/pkg/types" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" +) + +/* +flag := (1 << 128) + + a := { + a.low: flag - 5 + a.high = ... + } + + b := { + b.low: 4 + b.high = ... + } + +a.low + b.low < flag -> carryLow = 0 +*/ +func TestUint256AddCarryLow0(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + + flag := FeltOne().Shl(128) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(flag.Sub(FeltFromUint64(5))), + NewMaybeRelocatableFelt(FeltZero()), + }, + "b": { + NewMaybeRelocatableFelt(FeltFromUint64(4)), + NewMaybeRelocatableFelt(FeltZero()), + }, + "carry_low": { + nil, + nil, + }, + "carry_high": { + nil, + nil, + }, + }, + vm, + ) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_ADD, + }) + scopes := NewExecutionScopes() + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + carry_low, err := idsManager.GetStructFieldFelt("carry_low", 0, vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + if carry_low != FeltZero() { + t.Errorf("expected carry_low: 0, got: %s", carry_low.ToSignedFeltString()) + } +} + +/* +flag := (1 << 128) + + a := { + a.low: flag + a.high = ... + } + + b := { + b.low: 0 + b.high = ... + } + +a.low + b.low >= flag -> carryLow = 1 +*/ +func TestUint256AddCarryLow1(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + + flag := FeltOne().Shl(128) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(flag), + NewMaybeRelocatableFelt(FeltOne()), + }, + "b": { + NewMaybeRelocatableFelt(FeltZero()), + NewMaybeRelocatableFelt(FeltOne()), + }, + "carry_low": { + nil, + nil, + }, + "carry_high": { + nil, + nil, + }, + }, + vm, + ) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_ADD, + }) + scopes := NewExecutionScopes() + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + carry_low, err := idsManager.GetStructFieldFelt("carry_low", 0, vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + if carry_low != FeltOne() { + t.Errorf("expected carry_low: 1, got: %s", carry_low.ToSignedFeltString()) + } +} + +/* +flag := (1 << 128) + + a := { + a.low: 0 + a.high = flag / 2 + } + + b := { + b.low: 0 + b.high = a.high - 1 + } + +a.low + b.low < flag -> carryLow = 0 +a.high + b.high + carryLow < flag -> carry_high = 0 +*/ +func TestUint256AddCarryHigh0(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + + flag := FeltOne().Shl(128) + aHigh := flag.Div(FeltFromUint64(2)) + bHigh := aHigh.Sub(FeltFromUint64(1)) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(FeltZero()), + NewMaybeRelocatableFelt(aHigh), + }, + "b": { + NewMaybeRelocatableFelt(FeltZero()), + NewMaybeRelocatableFelt(bHigh), + }, + "carry_low": { + nil, + nil, + }, + "carry_high": { + nil, + nil, + }, + }, + vm, + ) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_ADD, + }) + scopes := NewExecutionScopes() + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + carry_high, err := idsManager.GetStructFieldFelt("carry_high", 0, vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + if carry_high != FeltZero() { + t.Errorf("expected carry_low: 0, got: %s", carry_high.ToSignedFeltString()) + } +} + +/* + flag := (1 << 128) + a := { + a.low: flag + a.high = flag / 2 + } + + b := { + b.low: 0 + b.high = a.high - 1 + } + + a.low + b.low >= flag -> carryLow = 1 + a.high + b.high + carryLow > flag -> carry_high = 1 +*/ +func TestUint256AddCarryHigh1(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + + flag := FeltOne().Shl(128) + aHigh := flag.Div(FeltFromUint64(2)) + bHigh := aHigh.Sub(FeltFromUint64(1)) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(flag), + NewMaybeRelocatableFelt(aHigh), + }, + "b": { + NewMaybeRelocatableFelt(FeltZero()), + NewMaybeRelocatableFelt(bHigh), + }, + "carry_low": { + nil, + nil, + }, + "carry_high": { + nil, + nil, + }, + }, + vm, + ) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_ADD, + }) + scopes := NewExecutionScopes() + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("failed with error: %s", err) + } + carry_high, err := idsManager.GetStructFieldFelt("carry_high", 0, vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + if carry_high != FeltOne() { + t.Errorf("expected carry_low: 1, got: %s", carry_high.ToSignedFeltString()) + } +} From b968f3d1e88ec5f4cf5f422b0beb3222f8d352e6 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Thu, 21 Sep 2023 11:55:22 +0200 Subject: [PATCH 04/31] add hint uint256_add_low --- pkg/hints/hint_codes/uint256_hint_codes.go | 3 ++- pkg/hints/hint_processor.go | 2 ++ pkg/hints/uint256_hints_test.go | 12 ++++++------ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pkg/hints/hint_codes/uint256_hint_codes.go b/pkg/hints/hint_codes/uint256_hint_codes.go index 260802e4..c7f3024a 100644 --- a/pkg/hints/hint_codes/uint256_hint_codes.go +++ b/pkg/hints/hint_codes/uint256_hint_codes.go @@ -1,3 +1,4 @@ package hint_codes -const UINT256_ADD = "sum_low = ids.a.low + ids.b.low \n ids.carry_low = 1 if sum_low >= ids.SHIFT else 0 \n sum_high = ids.a.high + ids.b.high + ids.carry_low \n ids.carry_high = 1 if sum_high >= ids.SHIFT else 0" +const UINT256_ADD = "sum_low = ids.a.low + ids.b.low\nids.carry_low = 1 if sum_low >= ids.SHIFT else 0\nsum_high = ids.a.high + ids.b.high + ids.carry_low\nids.carry_high = 1 if sum_high >= ids.SHIFT else 0" +const UINT256_ADD_LOW = "sum_low = ids.a.low + ids.b.low\nids.carry_low = 1 if sum_low >= ids.SHIFT else 0" diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index f840e2c7..f6258fc3 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -140,6 +140,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return splitIntAssertRange(data.Ids, vm) case UINT256_ADD: return uint256Add(data.Ids, execScopes, vm, false) + case UINT256_ADD_LOW: + return uint256Add(data.Ids, execScopes, vm, true) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index de661c22..23bc4082 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -37,11 +37,11 @@ func TestUint256AddCarryLow0(t *testing.T) { map[string][]*MaybeRelocatable{ "a": { NewMaybeRelocatableFelt(flag.Sub(FeltFromUint64(5))), - NewMaybeRelocatableFelt(FeltZero()), + nil, }, "b": { NewMaybeRelocatableFelt(FeltFromUint64(4)), - NewMaybeRelocatableFelt(FeltZero()), + nil, }, "carry_low": { nil, @@ -56,7 +56,7 @@ func TestUint256AddCarryLow0(t *testing.T) { ) hintData := any(HintData{ Ids: idsManager, - Code: UINT256_ADD, + Code: UINT256_ADD_LOW, }) scopes := NewExecutionScopes() hintProcessor := CairoVmHintProcessor{} @@ -99,11 +99,11 @@ func TestUint256AddCarryLow1(t *testing.T) { map[string][]*MaybeRelocatable{ "a": { NewMaybeRelocatableFelt(flag), - NewMaybeRelocatableFelt(FeltOne()), + nil, }, "b": { NewMaybeRelocatableFelt(FeltZero()), - NewMaybeRelocatableFelt(FeltOne()), + nil, }, "carry_low": { nil, @@ -118,7 +118,7 @@ func TestUint256AddCarryLow1(t *testing.T) { ) hintData := any(HintData{ Ids: idsManager, - Code: UINT256_ADD, + Code: UINT256_ADD_LOW, }) scopes := NewExecutionScopes() hintProcessor := CairoVmHintProcessor{} From 4717989377ed16a9b6f9d78717c4f722a5db4922 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Thu, 21 Sep 2023 12:41:17 +0200 Subject: [PATCH 05/31] implement split_64 hint --- pkg/hints/hint_codes/uint256_hint_codes.go | 1 + pkg/hints/hint_processor.go | 6 ++- pkg/hints/uint256_hints.go | 32 ++++++++++++++- pkg/hints/uint256_hints_test.go | 46 ++++++++++++++++++++++ 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/pkg/hints/hint_codes/uint256_hint_codes.go b/pkg/hints/hint_codes/uint256_hint_codes.go index c7f3024a..9e264344 100644 --- a/pkg/hints/hint_codes/uint256_hint_codes.go +++ b/pkg/hints/hint_codes/uint256_hint_codes.go @@ -2,3 +2,4 @@ package hint_codes const UINT256_ADD = "sum_low = ids.a.low + ids.b.low\nids.carry_low = 1 if sum_low >= ids.SHIFT else 0\nsum_high = ids.a.high + ids.b.high + ids.carry_low\nids.carry_high = 1 if sum_high >= ids.SHIFT else 0" const UINT256_ADD_LOW = "sum_low = ids.a.low + ids.b.low\nids.carry_low = 1 if sum_low >= ids.SHIFT else 0" +const SPLIT_64 = "ids.low = ids.a & ((1<<64) - 1)\nids.high = ids.a >> 64" diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index f6258fc3..c9a013f3 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -139,9 +139,11 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, case SPLIT_INT_ASSERT_RANGE: return splitIntAssertRange(data.Ids, vm) case UINT256_ADD: - return uint256Add(data.Ids, execScopes, vm, false) + return uint256Add(data.Ids, vm, false) case UINT256_ADD_LOW: - return uint256Add(data.Ids, execScopes, vm, true) + return uint256Add(data.Ids, vm, true) + case SPLIT_64: + return split64(data.Ids, vm) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index fd0f0ea0..1b76e05b 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -3,7 +3,6 @@ package hints import ( . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" - . "github.com/lambdaclass/cairo-vm.go/pkg/types" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" ) @@ -27,7 +26,7 @@ Implements hints: %} */ -func uint256Add(ids IdsManager, scopes *ExecutionScopes, vm *VirtualMachine, lowOnly bool) error { +func uint256Add(ids IdsManager, vm *VirtualMachine, lowOnly bool) error { shift := FeltOne().Shl(128) aLow, err := ids.GetStructFieldFelt("a", 0, vm) if err != nil { @@ -72,3 +71,32 @@ func uint256Add(ids IdsManager, scopes *ExecutionScopes, vm *VirtualMachine, low return ids.Insert("carry_low", NewMaybeRelocatableFelt(carryLow), vm) } + +/* +Implements hint: + + %{ + ids.low = ids.a & ((1<<64) - 1) + ids.high = ids.a >> 64 + +%} +*/ +func split64(ids IdsManager, vm *VirtualMachine) error { + a, err := ids.GetFelt("a", vm) + if err != nil { + return err + } + flag := (FeltOne().Shl(64)).Sub(FeltOne()) // (1 << 64) - 1 + low := a.And(flag) + high := a.Shr(64) // a >> 64 + err = ids.Insert("low", NewMaybeRelocatableFelt(low), vm) + if err != nil { + return err + } + err = ids.Insert("high", NewMaybeRelocatableFelt(high), vm) + if err != nil { + return err + } + return nil + +} diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index 23bc4082..daae2856 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -263,3 +263,49 @@ func TestUint256AddCarryHigh1(t *testing.T) { t.Errorf("expected carry_low: 1, got: %s", carry_high.ToSignedFeltString()) } } + +func TestSplit64Ok(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(FeltFromDecString("-3")), + }, + "low": {nil}, + "high": {nil}, + }, + vm, + ) + + hintData := any(HintData{ + Ids: idsManager, + Code: SPLIT_64, + }) + scopes := NewExecutionScopes() + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + low, err := idsManager.GetFelt("low", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + expected_low := FeltFromDecString("-3").And(FeltOne().Shl(64).Sub(FeltOne())) + if low != expected_low { + t.Errorf("expected low: %d, got: %d", expected_low, low) + } + + high, err := idsManager.GetFelt("high", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + expected_high := FeltFromDecString("-3").Shr(64) + if high != expected_high { + t.Errorf("expected high: %d, got: %d", expected_high, high) + } + +} From 60b009a53f863a6ee4fefa415d9ed3553a4cef3b Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Thu, 21 Sep 2023 16:27:44 +0200 Subject: [PATCH 06/31] change location of uint256 struct --- pkg/lambdaworks/lambdaworks.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index d6b27bdc..7165610f 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -26,6 +26,11 @@ type Felt struct { limbs [N_LIMBS_IN_FELT]Limb } +type Uint256 struct { + Low Felt + High Felt +} + func LambdaworksError(err error) error { return errors.Wrapf(err, "Lambdaworks Error") } From bf6e11e3670d7fb57de48fed306867c3ec57b161 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Thu, 21 Sep 2023 16:28:15 +0200 Subject: [PATCH 07/31] implement auxiliar methods to ids manager to insert u256 structs --- pkg/hints/hint_utils/ids_manager.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pkg/hints/hint_utils/ids_manager.go b/pkg/hints/hint_utils/ids_manager.go index ef2550b5..d53be1df 100644 --- a/pkg/hints/hint_utils/ids_manager.go +++ b/pkg/hints/hint_utils/ids_manager.go @@ -76,6 +76,18 @@ func (ids *IdsManager) GetFelt(name string, vm *VirtualMachine) (lambdaworks.Fel return felt, nil } +func (ids *IdsManager) GetUint256(name string, vm *VirtualMachine) (lambdaworks.Uint256, error) { + low, err := ids.GetStructFieldFelt(name, 0, vm) + if err != nil { + return lambdaworks.Uint256{}, err + } + high, err := ids.GetStructFieldFelt(name, 1, vm) + if err != nil { + return lambdaworks.Uint256{}, err + } + return lambdaworks.Uint256{Low: low, High: high}, nil +} + // Returns the value of an identifier as a Relocatable func (ids *IdsManager) GetRelocatable(name string, vm *VirtualMachine) (Relocatable, error) { val, err := ids.Get(name, vm) @@ -217,6 +229,20 @@ func (ids *IdsManager) InsertStructField(name string, field_off uint, value *May return vm.Segments.Memory.Insert(addr.AddUint(field_off), value) } +// Inserts Uint256 value into an ids field (given the identifier is a Uint256) +func (ids *IdsManager) InsertUint256(name string, val lambdaworks.Uint256, vm *VirtualMachine) error { + err := ids.InsertStructField(name, 0, NewMaybeRelocatableFelt(val.Low), vm) + if err != nil { + return err + } + err = ids.InsertStructField(name, 1, NewMaybeRelocatableFelt(val.High), vm) + if err != nil { + return err + } + return nil + +} + // Inserts value into the address of the given identifier func insertIdsFromReference(value *MaybeRelocatable, reference *HintReference, apTracking parser.ApTrackingData, vm *VirtualMachine) error { addr, ok := getAddressFromReference(reference, apTracking, vm) From 9ee1dc02502339d39a9aef6d3d6b1a5371d7769e Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Thu, 21 Sep 2023 16:30:39 +0200 Subject: [PATCH 08/31] implement uint256sqrt hint --- pkg/hints/hint_codes/uint256_hint_codes.go | 2 + pkg/hints/hint_processor.go | 4 ++ pkg/hints/uint256_hints.go | 46 +++++++++++++++++++--- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/pkg/hints/hint_codes/uint256_hint_codes.go b/pkg/hints/hint_codes/uint256_hint_codes.go index 9e264344..1099a4b1 100644 --- a/pkg/hints/hint_codes/uint256_hint_codes.go +++ b/pkg/hints/hint_codes/uint256_hint_codes.go @@ -3,3 +3,5 @@ package hint_codes const UINT256_ADD = "sum_low = ids.a.low + ids.b.low\nids.carry_low = 1 if sum_low >= ids.SHIFT else 0\nsum_high = ids.a.high + ids.b.high + ids.carry_low\nids.carry_high = 1 if sum_high >= ids.SHIFT else 0" const UINT256_ADD_LOW = "sum_low = ids.a.low + ids.b.low\nids.carry_low = 1 if sum_low >= ids.SHIFT else 0" const SPLIT_64 = "ids.low = ids.a & ((1<<64) - 1)\nids.high = ids.a >> 64" +const UINT256_SQRT = "from starkware.python.math_utils import isqrt\nn = (ids.n.high << 128) + ids.n.low\nroot = isqrt(n)\nassert 0 <= root < 2 ** 128\nids.root.low = root\nids.root.high = 0" +const UINT256_SQRT_FELT = "from starkware.python.math_utils import isqrt\nn = (ids.n.high << 128) + ids.n.low\nroot = isqrt(n)\nassert 0 <= root < 2 ** 128\nids.root = root;" diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index c9a013f3..c3ce75a4 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -144,6 +144,10 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return uint256Add(data.Ids, vm, true) case SPLIT_64: return split64(data.Ids, vm) + case UINT256_SQRT: + return uint256Sqrt(data.Ids, vm, false) + case UINT256_SQRT_FELT: + return uint256Sqrt(data.Ids, vm, true) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index 1b76e05b..b9b6ce40 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -1,17 +1,16 @@ package hints import ( + "math/big" + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" + "github.com/pkg/errors" ) -type Uint256 struct { - low Felt - high Felt -} - /* Implements hints: %{ @@ -100,3 +99,40 @@ func split64(ids IdsManager, vm *VirtualMachine) error { return nil } + +/* +Implements hint: + + %{ + from starkware.python.math_utils import isqrt + n = (ids.n.high << 128) + ids.n.low + root = isqrt(n) + assert 0 <= root < 2 ** 128 + ids.root.low = root + ids.root.high = 0 + +%} +*/ +func uint256Sqrt(ids IdsManager, vm *VirtualMachine, onlyLow bool) error { + uintN, err := ids.GetUint256("n", vm) + if err != nil { + return err + } + + bHigh := new(big.Int).Lsh(uintN.High.ToBigInt(), 128) + bLow := uintN.Low.ToBigInt() + n := new(big.Int).Add(bHigh, bLow) + root := new(big.Int).Sqrt(n) + + if root.BitLen() > 128 { + return errors.Errorf("assert 0 <= %d < 2**128", root) + } + + feltRoot := FeltFromBigInt(root) + + if onlyLow { + return ids.Insert("root", NewMaybeRelocatableFelt(feltRoot), vm) + } else { + return ids.InsertUint256("root", lambdaworks.Uint256{Low: feltRoot, High: FeltZero()}, vm) + } +} From f8dddddb19f8d802d09f0a4a16b004aaba81500d Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Thu, 21 Sep 2023 17:30:22 +0200 Subject: [PATCH 09/31] add unit test sqrt --- pkg/hints/hint_utils/ids_manager.go | 6 +---- pkg/hints/uint256_hints.go | 3 +++ pkg/hints/uint256_hints_test.go | 42 +++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/pkg/hints/hint_utils/ids_manager.go b/pkg/hints/hint_utils/ids_manager.go index d53be1df..64337349 100644 --- a/pkg/hints/hint_utils/ids_manager.go +++ b/pkg/hints/hint_utils/ids_manager.go @@ -235,11 +235,7 @@ func (ids *IdsManager) InsertUint256(name string, val lambdaworks.Uint256, vm *V if err != nil { return err } - err = ids.InsertStructField(name, 1, NewMaybeRelocatableFelt(val.High), vm) - if err != nil { - return err - } - return nil + return ids.InsertStructField(name, 1, NewMaybeRelocatableFelt(val.High), vm) } diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index b9b6ce40..4173cc0d 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" @@ -122,7 +123,9 @@ func uint256Sqrt(ids IdsManager, vm *VirtualMachine, onlyLow bool) error { bHigh := new(big.Int).Lsh(uintN.High.ToBigInt(), 128) bLow := uintN.Low.ToBigInt() n := new(big.Int).Add(bHigh, bLow) + fmt.Printf("n value as big.Int is: %d\n", n) root := new(big.Int).Sqrt(n) + fmt.Printf("root value as big.Int is: %d\n", root) if root.BitLen() > 128 { return errors.Errorf("assert 0 <= %d < 2**128", root) diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index daae2856..cb0ae891 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -1,11 +1,13 @@ package hints_test import ( + "math/big" "testing" . "github.com/lambdaclass/cairo-vm.go/pkg/hints" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/types" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" @@ -309,3 +311,43 @@ func TestSplit64Ok(t *testing.T) { } } + +func TestUint256SqrtOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "n": { + NewMaybeRelocatableFelt(FeltFromUint64(^uint64(0))), + NewMaybeRelocatableFelt(FeltFromUint64(^uint64(0))), + }, + "root": {nil}, + }, + vm, + ) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_SQRT, + }) + scopes := NewExecutionScopes() + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + l := new(big.Int).SetUint64(^uint64(0)) + h := new(big.Int).Lsh(l, 128) + expectedRoot := new(big.Int).Sqrt(new(big.Int).Add(l, h)) + + expectedResult := lambdaworks.Uint256{Low: FeltFromBigInt(expectedRoot), High: FeltZero()} + + root, err := idsManager.GetUint256("root", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + if root != expectedResult { + t.Errorf("failed, expected root: %d, got: %d", expectedResult, root) + } +} From dbd88bbc05512ef77726915319c1c55749363251 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Fri, 22 Sep 2023 17:49:54 +0200 Subject: [PATCH 10/31] fix unit test --- pkg/hints/uint256_hints.go | 9 +++++---- pkg/hints/uint256_hints_test.go | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index 4173cc0d..e3aa8eda 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -1,7 +1,6 @@ package hints import ( - "fmt" "math/big" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" @@ -12,6 +11,10 @@ import ( "github.com/pkg/errors" ) +func ErrRootOOR(root *big.Int) error { + return errors.Errorf("assert 0 <= %d < 2**128", root) +} + /* Implements hints: %{ @@ -123,12 +126,10 @@ func uint256Sqrt(ids IdsManager, vm *VirtualMachine, onlyLow bool) error { bHigh := new(big.Int).Lsh(uintN.High.ToBigInt(), 128) bLow := uintN.Low.ToBigInt() n := new(big.Int).Add(bHigh, bLow) - fmt.Printf("n value as big.Int is: %d\n", n) root := new(big.Int).Sqrt(n) - fmt.Printf("root value as big.Int is: %d\n", root) if root.BitLen() > 128 { - return errors.Errorf("assert 0 <= %d < 2**128", root) + return ErrRootOOR(root) } feltRoot := FeltFromBigInt(root) diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index cb0ae891..22d1bd1f 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -351,3 +351,24 @@ func TestUint256SqrtOk(t *testing.T) { t.Errorf("failed, expected root: %d, got: %d", expectedResult, root) } } + +func TestUint256SqrtKo(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + + idsManager := SetupIdsForTest(map[string][]*MaybeRelocatable{ + "n": { + NewMaybeRelocatableFelt(FeltZero()), + NewMaybeRelocatableFelt(FeltFromDecString("340282366920938463463374607431768211458")), + }, + "root": {nil}, + }, vm) + + hintData := any(HintData{Ids: idsManager, Code: UINT256_SQRT}) + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, NewExecutionScopes()) + expectedRoot := FeltFromDecString("340282366920938463463374607431768211456") + if err.Error() != ErrRootOOR(expectedRoot.ToBigInt()).Error() { + t.Errorf("failed with error: %s", err) + } +} From 8cbd0b50907a07f2541e8631841cfc5b869f6dc8 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Fri, 22 Sep 2023 19:51:53 +0200 Subject: [PATCH 11/31] add unit tests uint256_sqrt --- pkg/hints/uint256_hints.go | 3 -- pkg/hints/uint256_hints_test.go | 52 +++++++++++++++++++++++++-------- pkg/lambdaworks/lambdaworks.go | 4 +++ 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index e3aa8eda..f3dd513e 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -122,18 +122,15 @@ func uint256Sqrt(ids IdsManager, vm *VirtualMachine, onlyLow bool) error { if err != nil { return err } - bHigh := new(big.Int).Lsh(uintN.High.ToBigInt(), 128) bLow := uintN.Low.ToBigInt() n := new(big.Int).Add(bHigh, bLow) root := new(big.Int).Sqrt(n) - if root.BitLen() > 128 { return ErrRootOOR(root) } feltRoot := FeltFromBigInt(root) - if onlyLow { return ids.Insert("root", NewMaybeRelocatableFelt(feltRoot), vm) } else { diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index 22d1bd1f..471d9124 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -7,7 +7,6 @@ import ( . "github.com/lambdaclass/cairo-vm.go/pkg/hints" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" - "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/types" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" @@ -319,8 +318,8 @@ func TestUint256SqrtOk(t *testing.T) { idsManager := SetupIdsForTest( map[string][]*MaybeRelocatable{ "n": { - NewMaybeRelocatableFelt(FeltFromUint64(^uint64(0))), - NewMaybeRelocatableFelt(FeltFromUint64(^uint64(0))), + NewMaybeRelocatableFelt(FeltFromUint64(17)), + NewMaybeRelocatableFelt(FeltFromUint64(7)), }, "root": {nil}, }, @@ -337,18 +336,13 @@ func TestUint256SqrtOk(t *testing.T) { t.Errorf("failed with error: %s", err) } - l := new(big.Int).SetUint64(^uint64(0)) - h := new(big.Int).Lsh(l, 128) - expectedRoot := new(big.Int).Sqrt(new(big.Int).Add(l, h)) - - expectedResult := lambdaworks.Uint256{Low: FeltFromBigInt(expectedRoot), High: FeltZero()} - - root, err := idsManager.GetUint256("root", vm) + expected_root, _ := new(big.Int).SetString("48805497317890012913", 10) + root, err := idsManager.GetFelt("root", vm) if err != nil { t.Errorf("failed with error: %s", err) } - if root != expectedResult { - t.Errorf("failed, expected root: %d, got: %d", expectedResult, root) + if root != FeltFromBigInt(expected_root) { + t.Errorf("failed, expected root: %d, got: %d", FeltFromBigInt(expected_root), root) } } @@ -372,3 +366,37 @@ func TestUint256SqrtKo(t *testing.T) { t.Errorf("failed with error: %s", err) } } + +func TestUint256SqrtFeltOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "n": { + NewMaybeRelocatableFelt(FeltFromUint64(879232)), + NewMaybeRelocatableFelt(FeltFromUint64(135906)), + }, + "root": {nil}, + }, + vm, + ) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_SQRT_FELT, + }) + scopes := NewExecutionScopes() + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("failed with error: %s", err) + } + expected_root, _ := new(big.Int).SetString("6800471701195223914689", 10) + expectedResult := FeltFromBigInt(expected_root) + root, err := idsManager.GetFelt("root", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + if root != expectedResult { + t.Errorf("failed, expected root: %d, got: %d", expectedResult, root) + } +} diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index 7165610f..10db9562 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -355,3 +355,7 @@ func (a Felt) Cmp(b Felt) int { var b_c C.felt_t = b.toC() return int(C.cmp(&a_c[0], &b_c[0])) } + +func (ui256 *Uint256) ToString() string { + return "Uint256 {low: " + ui256.Low.ToSignedFeltString() + ", high: " + ui256.High.ToSignedFeltString() + "}" +} From 7494b4422fc9016f54e3439a80dd77093d5419d1 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Tue, 26 Sep 2023 12:50:00 +0200 Subject: [PATCH 12/31] implement hint uint256_signed_nn --- pkg/hints/hint_codes/uint256_hint_codes.go | 1 + pkg/hints/hint_processor.go | 2 ++ pkg/hints/hint_utils/ids_manager.go | 6 ++++++ pkg/hints/uint256_hints.go | 16 ++++++++++++++++ pkg/lambdaworks/lambdaworks.go | 2 +- 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/pkg/hints/hint_codes/uint256_hint_codes.go b/pkg/hints/hint_codes/uint256_hint_codes.go index 1099a4b1..d644e03b 100644 --- a/pkg/hints/hint_codes/uint256_hint_codes.go +++ b/pkg/hints/hint_codes/uint256_hint_codes.go @@ -5,3 +5,4 @@ const UINT256_ADD_LOW = "sum_low = ids.a.low + ids.b.low\nids.carry_low = 1 if s const SPLIT_64 = "ids.low = ids.a & ((1<<64) - 1)\nids.high = ids.a >> 64" const UINT256_SQRT = "from starkware.python.math_utils import isqrt\nn = (ids.n.high << 128) + ids.n.low\nroot = isqrt(n)\nassert 0 <= root < 2 ** 128\nids.root.low = root\nids.root.high = 0" const UINT256_SQRT_FELT = "from starkware.python.math_utils import isqrt\nn = (ids.n.high << 128) + ids.n.low\nroot = isqrt(n)\nassert 0 <= root < 2 ** 128\nids.root = root;" +const UINT256_SIGNED_NN = "memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0" diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 0278cadf..e9cf66f3 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -158,6 +158,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return uint256Sqrt(data.Ids, vm, false) case UINT256_SQRT_FELT: return uint256Sqrt(data.Ids, vm, true) + case UINT256_SIGNED_NN: + return uint246SignedNN(data.Ids, vm) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/hint_utils/ids_manager.go b/pkg/hints/hint_utils/ids_manager.go index 64337349..11b703a4 100644 --- a/pkg/hints/hint_utils/ids_manager.go +++ b/pkg/hints/hint_utils/ids_manager.go @@ -239,6 +239,12 @@ 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) +} + // Inserts value into the address of the given identifier func insertIdsFromReference(value *MaybeRelocatable, reference *HintReference, apTracking parser.ApTrackingData, vm *VirtualMachine) error { addr, ok := getAddressFromReference(reference, apTracking, vm) diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index f3dd513e..1de825ff 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -137,3 +137,19 @@ func uint256Sqrt(ids IdsManager, vm *VirtualMachine, onlyLow bool) error { return ids.InsertUint256("root", lambdaworks.Uint256{Low: feltRoot, High: FeltZero()}, vm) } } + +/* +Implements hint: +%{ memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0 %} +*/ +func uint246SignedNN(ids IdsManager, vm *VirtualMachine) error { + a, err := ids.GetUint256("a", vm) + if err != nil { + return err + } + if a.High.Cmp(SignedFeltMaxValue()) != 1 { + return ids.InsertValueIntoAP(vm, *NewMaybeRelocatableFelt(FeltOne())) + } else { + return ids.InsertValueIntoAP(vm, *NewMaybeRelocatableFelt(FeltZero())) + } +} diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index e6e7f865..96048924 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -359,7 +359,7 @@ func (a Felt) DivFloor(b Felt) Felt { } /* -Compares x and y and returns: +Compares a and b and returns: -1 if a < b 0 if a == b From 6a550b763e1050d3bccba784a82763fff2348c72 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Tue, 26 Sep 2023 13:10:24 +0200 Subject: [PATCH 13/31] add tests --- pkg/hints/uint256_hints_test.go | 92 +++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index 471d9124..d48cb2b9 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -8,7 +8,9 @@ import ( . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + "github.com/lambdaclass/cairo-vm.go/pkg/parser" . "github.com/lambdaclass/cairo-vm.go/pkg/types" + . "github.com/lambdaclass/cairo-vm.go/pkg/utils" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" ) @@ -400,3 +402,93 @@ func TestUint256SqrtFeltOk(t *testing.T) { t.Errorf("failed, expected root: %d, got: %d", expectedResult, root) } } + +func TestUint256SignedNNOkResultOne(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments = AddNSegments(vm.Segments, 5) + ids := map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(FeltFromUint64(1)), + NewMaybeRelocatableFelt(FeltFromUint64(1)), + }, + } + idsManager := SetupIdsForTest(ids, vm) + idsManager.HintApTracking = parser.ApTrackingData{Group: 4, Offset: 5} + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_SIGNED_NN, + }) + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + result, err := vm.Segments.Memory.GetFelt(NewRelocatable(4, 5)) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + if result != FeltOne() { + t.Errorf("failed, expected result: %d, got: %d", FeltOne(), result) + } +} + +func TestUint256SignedNNOkResultZero(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments = AddNSegments(vm.Segments, 5) + ids := map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(FeltFromUint64(1)), + NewMaybeRelocatableFelt(FeltFromDecString("-4")), + }, + } + idsManager := SetupIdsForTest(ids, vm) + idsManager.HintApTracking = parser.ApTrackingData{Group: 4, Offset: 5} + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_SIGNED_NN, + }) + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + result, err := vm.Segments.Memory.GetFelt(NewRelocatable(4, 5)) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + if result != FeltZero() { + t.Errorf("failed, expected result: %d, got: %d", FeltOne(), 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) + } + ids := map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(FeltFromUint64(1)), + NewMaybeRelocatableFelt(FeltFromUint64(1)), + }, + } + idsManager := SetupIdsForTest(ids, vm) + idsManager.HintApTracking = parser.ApTrackingData{Group: 4, Offset: 5} + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_SIGNED_NN, + }) + hintProcessor := CairoVmHintProcessor{} + err = hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + expectedErr := ErrMemoryWriteOnce(NewRelocatable(4, 5), *NewMaybeRelocatableFeltFromUint64(10), *NewMaybeRelocatableFelt(FeltOne())) + if err.Error() != expectedErr.Error() { + t.Errorf("should fail with error: %s", err) + } +} + From ec08ea81645a66156740e68bfc48d15759413a3f Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Tue, 26 Sep 2023 14:00:36 +0200 Subject: [PATCH 14/31] implement UINT256_UNSIGNED_DIV_REM hint --- pkg/hints/hint_codes/uint256_hint_codes.go | 1 + pkg/hints/hint_processor.go | 4 +- pkg/hints/uint256_hints.go | 52 +++++++++++++++++++++- pkg/hints/uint256_hints_test.go | 1 - pkg/lambdaworks/lambdaworks.go | 21 +++++++++ 5 files changed, 76 insertions(+), 3 deletions(-) diff --git a/pkg/hints/hint_codes/uint256_hint_codes.go b/pkg/hints/hint_codes/uint256_hint_codes.go index d644e03b..6eb3034a 100644 --- a/pkg/hints/hint_codes/uint256_hint_codes.go +++ b/pkg/hints/hint_codes/uint256_hint_codes.go @@ -6,3 +6,4 @@ const SPLIT_64 = "ids.low = ids.a & ((1<<64) - 1)\nids.high = ids.a >> 64" const UINT256_SQRT = "from starkware.python.math_utils import isqrt\nn = (ids.n.high << 128) + ids.n.low\nroot = isqrt(n)\nassert 0 <= root < 2 ** 128\nids.root.low = root\nids.root.high = 0" const UINT256_SQRT_FELT = "from starkware.python.math_utils import isqrt\nn = (ids.n.high << 128) + ids.n.low\nroot = isqrt(n)\nassert 0 <= root < 2 ** 128\nids.root = root;" const UINT256_SIGNED_NN = "memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0" +const UINT256_UNSIGNED_DIV_REM = "a = (ids.a.high << 128) + ids.a.low\ndiv = (ids.div.high << 128) + ids.div.low\nquotient, remainder = divmod(a, div)\n\nids.quotient.low = quotient & ((1 << 128) - 1)\nids.quotient.high = quotient >> 128\nids.remainder.low = remainder & ((1 << 128) - 1)\nids.remainder.high = remainder >> 128" diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index e9cf66f3..eb1a6c3e 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -159,7 +159,9 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, case UINT256_SQRT_FELT: return uint256Sqrt(data.Ids, vm, true) case UINT256_SIGNED_NN: - return uint246SignedNN(data.Ids, vm) + return uint256SignedNN(data.Ids, vm) + case UINT256_UNSIGNED_DIV_REM: + return uint256UnsignedDivRem(data.Ids, vm) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index 1de825ff..a6a5d08f 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -142,7 +142,7 @@ func uint256Sqrt(ids IdsManager, vm *VirtualMachine, onlyLow bool) error { Implements hint: %{ memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0 %} */ -func uint246SignedNN(ids IdsManager, vm *VirtualMachine) error { +func uint256SignedNN(ids IdsManager, vm *VirtualMachine) error { a, err := ids.GetUint256("a", vm) if err != nil { return err @@ -153,3 +153,53 @@ func uint246SignedNN(ids IdsManager, vm *VirtualMachine) error { return ids.InsertValueIntoAP(vm, *NewMaybeRelocatableFelt(FeltZero())) } } + +/* +Implements hint: + + %{ + a = (ids.a.high << 128) + ids.a.low + div = (ids.div.high << 128) + ids.div.low + quotient, remainder = divmod(a, div) + + ids.quotient.low = quotient & ((1 << 128) - 1) + ids.quotient.high = quotient >> 128 + ids.remainder.low = remainder & ((1 << 128) - 1) + ids.remainder.high = remainder >> 128 + +%} +*/ +func uint256UnsignedDivRem(ids IdsManager, vm *VirtualMachine) error { + return uint256OfssetedUnisgnedDivRem(ids, vm, 0, 1) +} + +func uint256OfssetedUnisgnedDivRem(ids IdsManager, vm *VirtualMachine, divOffsetLow uint, divOffsetHigh uint) error { + 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)) + if err != nil { + return err + } + divHigh, err := vm.Segments.Memory.GetFelt(baseDiv.AddUint(divOffsetHigh)) + if err != nil { + return err + } + + div := Uint256{Low: divLow, High: divHigh} + + q, r := new(big.Int).DivMod(a.ToBigInt(), div.ToBigInt(), nil) + + err = ids.InsertUint256("quotient", ToUint256(q), vm) + if err != nil { + return err + } + return ids.InsertUint256("remainder", ToUint256(r), vm) + +} diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index d48cb2b9..4e3791da 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -491,4 +491,3 @@ func TestUint256SignedNNInvalidMemoryInser(t *testing.T) { t.Errorf("should fail with error: %s", err) } } - diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index 96048924..cac13144 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -374,3 +374,24 @@ func (a Felt) Cmp(b Felt) int { func (ui256 *Uint256) ToString() string { return "Uint256 {low: " + ui256.Low.ToSignedFeltString() + ", high: " + ui256.High.ToSignedFeltString() + "}" } + +/* +Returns a Uint256 as a big.Int + + res = high << 128 + low +*/ +func (ui256 *Uint256) ToBigInt() *big.Int { + high := new(big.Int).Lsh(ui256.High.ToBigInt(), 128) + low := ui256.Low.ToBigInt() + res := new(big.Int).Add(high, low) + return res +} + +/* +Returns a big.Int as Uint256 +*/ +func ToUint256(a *big.Int) Uint256 { + low := new(big.Int).And(Prime(), a) + high := new(big.Int).Rsh(a, 128) + return Uint256{Low: FeltFromBigInt(low), High: FeltFromBigInt(high)} +} From ea1a4a8c6bf56a4abc38561ec99d1d76441b6969 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Tue, 26 Sep 2023 17:43:13 +0200 Subject: [PATCH 15/31] add tests --- pkg/hints/uint256_hints.go | 4 +- pkg/hints/uint256_hints_test.go | 99 +++++++++++++++++++++++++++++++++ pkg/lambdaworks/lambdaworks.go | 3 +- pkg/vm/memory/memory.go | 2 +- 4 files changed, 103 insertions(+), 5 deletions(-) diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index a6a5d08f..167e3938 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -191,10 +191,8 @@ func uint256OfssetedUnisgnedDivRem(ids IdsManager, vm *VirtualMachine, divOffset if err != nil { return err } - div := Uint256{Low: divLow, High: divHigh} - - q, r := new(big.Int).DivMod(a.ToBigInt(), div.ToBigInt(), nil) + q, r := new(big.Int).DivMod(a.ToBigInt(), div.ToBigInt(), new(big.Int)) err = ids.InsertUint256("quotient", ToUint256(q), vm) if err != nil { diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index 4e3791da..12d2db56 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -491,3 +491,102 @@ func TestUint256SignedNNInvalidMemoryInser(t *testing.T) { t.Errorf("should fail with error: %s", err) } } + +func TestUint256UnsignedDivRemOk(t *testing.T) { + vm := NewVirtualMachine() + 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))}, + "quotient": {nil, nil}, + "remainder": {nil, nil}, + } + idsManager := SetupIdsForTest(ids, vm) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_UNSIGNED_DIV_REM, + }) + hintProcessor := CairoVmHintProcessor{} + err = hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + quotient, err := idsManager.GetUint256("quotient", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + expectedQuotient := Uint256{Low: FeltFromUint(10), High: FeltFromUint(0)} + if quotient != expectedQuotient { + t.Errorf("expected quotient: %s, got: %s", expectedQuotient.ToString(), quotient.ToString()) + } + + remainder, err := idsManager.GetUint256("remainder", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + expectedRemainder := Uint256{Low: FeltFromUint(59), High: FeltFromUint(2)} + if remainder != expectedRemainder { + t.Errorf("expected remainder: %s, got: %s", expectedRemainder.ToString(), remainder.ToString()) + } + +} + +func TestUint256UnsignedDivRemInvalidMemoryInsert(t *testing.T) { + vm := NewVirtualMachine() + 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}, + "remainder": {nil, nil}, + } + idsManager := SetupIdsForTest(ids, vm) + hintData := any(HintData{ + Ids: idsManager, + 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) + } +} diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index cac13144..adc1e594 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -391,7 +391,8 @@ func (ui256 *Uint256) ToBigInt() *big.Int { Returns a big.Int as Uint256 */ func ToUint256(a *big.Int) Uint256 { - low := new(big.Int).And(Prime(), a) + maxU128, _ := new(big.Int).SetString("340282366920938463463374607431768211455", 10) + low := new(big.Int).And(a, maxU128) high := new(big.Int).Rsh(a, 128) return Uint256{Low: FeltFromBigInt(low), High: FeltFromBigInt(high)} } diff --git a/pkg/vm/memory/memory.go b/pkg/vm/memory/memory.go index 4939a8a0..86aa49cf 100644 --- a/pkg/vm/memory/memory.go +++ b/pkg/vm/memory/memory.go @@ -117,7 +117,7 @@ func (m *Memory) Get(addr Relocatable) (*MaybeRelocatable, error) { value, ok := m.Data[addr] if !ok { - return nil, errors.New("Memory Get: Value not found") + return nil, errors.Errorf("Memory Get: Value not found in addr: %s", addr.ToString()) } return &value, nil From 73c84c8959b578cc7e5ced271d9d1438bf249eca Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Tue, 26 Sep 2023 18:19:11 +0200 Subject: [PATCH 16/31] implement hint and test --- pkg/hints/hint_codes/uint256_hint_codes.go | 1 + pkg/hints/hint_processor.go | 2 + pkg/hints/uint256_hints.go | 19 ++++++++ pkg/hints/uint256_hints_test.go | 57 ++++++++++++++++++++++ 4 files changed, 79 insertions(+) diff --git a/pkg/hints/hint_codes/uint256_hint_codes.go b/pkg/hints/hint_codes/uint256_hint_codes.go index 6eb3034a..da872720 100644 --- a/pkg/hints/hint_codes/uint256_hint_codes.go +++ b/pkg/hints/hint_codes/uint256_hint_codes.go @@ -7,3 +7,4 @@ const UINT256_SQRT = "from starkware.python.math_utils import isqrt\nn = (ids.n. const UINT256_SQRT_FELT = "from starkware.python.math_utils import isqrt\nn = (ids.n.high << 128) + ids.n.low\nroot = isqrt(n)\nassert 0 <= root < 2 ** 128\nids.root = root;" const UINT256_SIGNED_NN = "memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0" const UINT256_UNSIGNED_DIV_REM = "a = (ids.a.high << 128) + ids.a.low\ndiv = (ids.div.high << 128) + ids.div.low\nquotient, remainder = divmod(a, div)\n\nids.quotient.low = quotient & ((1 << 128) - 1)\nids.quotient.high = quotient >> 128\nids.remainder.low = remainder & ((1 << 128) - 1)\nids.remainder.high = remainder >> 128" +const UINT256_EXPANDED_UNSIGNED_DIV_REM = "a = (ids.a.high << 128) + ids.a.low\ndiv = (ids.div.b23 << 128) + ids.div.b01\nquotient, remainder = divmod(a, div)\n\nids.quotient.low = quotient & ((1 << 128) - 1)\nids.quotient.high = quotient >> 128\nids.remainder.low = remainder & ((1 << 128) - 1)\nids.remainder.high = remainder >> 128" diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index eb1a6c3e..06ff893a 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -162,6 +162,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return uint256SignedNN(data.Ids, vm) case UINT256_UNSIGNED_DIV_REM: return uint256UnsignedDivRem(data.Ids, vm) + case UINT256_EXPANDED_UNSIGNED_DIV_REM: + return uint256ExpandedUnsignedDivRem(data.Ids, vm) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index 167e3938..a82c1fec 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -173,6 +173,25 @@ func uint256UnsignedDivRem(ids IdsManager, vm *VirtualMachine) error { return uint256OfssetedUnisgnedDivRem(ids, vm, 0, 1) } +/* +Implements hint: + + %{ + a = (ids.a.high << 128) + ids.a.low + div = (ids.div.b23 << 128) + ids.div.b01 + quotient, remainder = divmod(a, div) + + ids.quotient.low = quotient & ((1 << 128) - 1) + ids.quotient.high = quotient >> 128 + ids.remainder.low = remainder & ((1 << 128) - 1) + ids.remainder.high = remainder >> 128 + +%} +*/ +func uint256ExpandedUnsignedDivRem(ids IdsManager, vm *VirtualMachine) error { + return uint256OfssetedUnisgnedDivRem(ids, vm, 1, 3) +} + func uint256OfssetedUnisgnedDivRem(ids IdsManager, vm *VirtualMachine, divOffsetLow uint, divOffsetHigh uint) error { a, err := ids.GetUint256("a", vm) if err != nil { diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index 12d2db56..30b389cc 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -590,3 +590,60 @@ func TestUint256UnsignedDivRemInvalidMemoryInsert(t *testing.T) { t.Errorf("failed with error: %s", err) } } + +func TestUint256ExpandedUnsignedDivRemOk(t *testing.T) { + vm := NewVirtualMachine() + 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))}, + "quotient": {nil, nil}, + "remainder": {nil, nil}, + } + idsManager := SetupIdsForTest(ids, vm) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_EXPANDED_UNSIGNED_DIV_REM, + }) + hintProcessor := CairoVmHintProcessor{} + err = hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + quotient, err := idsManager.GetUint256("quotient", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + expectedQuotient := Uint256{Low: FeltFromUint(10), High: FeltFromUint(0)} + if quotient != expectedQuotient { + t.Errorf("expected quotient: %s, got: %s", expectedQuotient.ToString(), quotient.ToString()) + } + + remainder, err := idsManager.GetUint256("remainder", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + expectedRemainder := Uint256{Low: FeltFromUint(59), High: FeltFromUint(2)} + if remainder != expectedRemainder { + t.Errorf("expected remainder: %s, got: %s", expectedRemainder.ToString(), remainder.ToString()) + } + +} From e95ae5da86b536f6a835bad8934a798958845c9b Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Wed, 27 Sep 2023 13:45:33 +0200 Subject: [PATCH 17/31] implement hint --- pkg/hints/hint_codes/uint256_hint_codes.go | 1 + pkg/hints/hint_processor.go | 2 + pkg/hints/uint256_hints.go | 70 ++++++++++++++++++++++ pkg/hints/uint256_hints_test.go | 54 +++++++++++++++++ 4 files changed, 127 insertions(+) diff --git a/pkg/hints/hint_codes/uint256_hint_codes.go b/pkg/hints/hint_codes/uint256_hint_codes.go index da872720..eb81031f 100644 --- a/pkg/hints/hint_codes/uint256_hint_codes.go +++ b/pkg/hints/hint_codes/uint256_hint_codes.go @@ -8,3 +8,4 @@ const UINT256_SQRT_FELT = "from starkware.python.math_utils import isqrt\nn = (i const UINT256_SIGNED_NN = "memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0" const UINT256_UNSIGNED_DIV_REM = "a = (ids.a.high << 128) + ids.a.low\ndiv = (ids.div.high << 128) + ids.div.low\nquotient, remainder = divmod(a, div)\n\nids.quotient.low = quotient & ((1 << 128) - 1)\nids.quotient.high = quotient >> 128\nids.remainder.low = remainder & ((1 << 128) - 1)\nids.remainder.high = remainder >> 128" const UINT256_EXPANDED_UNSIGNED_DIV_REM = "a = (ids.a.high << 128) + ids.a.low\ndiv = (ids.div.b23 << 128) + ids.div.b01\nquotient, remainder = divmod(a, div)\n\nids.quotient.low = quotient & ((1 << 128) - 1)\nids.quotient.high = quotient >> 128\nids.remainder.low = remainder & ((1 << 128) - 1)\nids.remainder.high = remainder >> 128" +const UINT256_MUL_DIV_MOD = "a = (ids.a.high << 128) + ids.a.low\nb = (ids.b.high << 128) + ids.b.low\ndiv = (ids.div.high << 128) + ids.div.low\nquotient, remainder = divmod(a * b, div)\n\nids.quotient_low.low = quotient & ((1 << 128) - 1)\nids.quotient_low.high = (quotient >> 128) & ((1 << 128) - 1)\nids.quotient_high.low = (quotient >> 256) & ((1 << 128) - 1)\nids.quotient_high.high = quotient >> 384\nids.remainder.low = remainder & ((1 << 128) - 1)\nids.remainder.high = remainder >> 128" diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 06ff893a..d9bf1fd1 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -164,6 +164,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return uint256UnsignedDivRem(data.Ids, vm) case UINT256_EXPANDED_UNSIGNED_DIV_REM: return uint256ExpandedUnsignedDivRem(data.Ids, vm) + case UINT256_MUL_DIV_MOD: + return uint256MulDivMod(data.Ids, vm) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index a82c1fec..a81c70b1 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -220,3 +220,73 @@ func uint256OfssetedUnisgnedDivRem(ids IdsManager, vm *VirtualMachine, divOffset return ids.InsertUint256("remainder", ToUint256(r), vm) } + +/* +Implements hint: + + %{ + a = (ids.a.high << 128) + ids.a.low + div = (ids.div.b23 << 128) + ids.div.b01 + quotient, remainder = divmod(a, div) + + ids.quotient.low = quotient & ((1 << 128) - 1) + ids.quotient.high = quotient >> 128 + ids.remainder.low = remainder & ((1 << 128) - 1) + ids.remainder.high = remainder >> 128 + +%} +*/ +func uint256MulDivMod(ids IdsManager, vm *VirtualMachine) error { + a, err := ids.GetUint256("a", vm) + if err != nil { + return err + } + b, err := ids.GetUint256("b", vm) + if err != nil { + return err + } + div, err := ids.GetUint256("div", vm) + if err != nil { + return err + } + quotientLow, err := ids.GetUint256("quotient_low", vm) + if err != nil { + fmt.Pri + return err + } + quotientHigh, err := ids.GetUint256("quotient_high", vm) + if err != nil { + return err + } + remainder, err := ids.GetUint256("remainder", vm) + if err != nil { + return err + } + + if div.ToBigInt().Cmp(big.NewInt(0)) == 0 { + return errors.Errorf("Attempted to divide by zero") + } + + mul := new(big.Int).Mul(a.ToBigInt(), b.ToBigInt()) + quotient, rem := new(big.Int).DivMod(mul, div.ToBigInt(), new(big.Int)) + + maxU128, _ := new(big.Int).SetString("340282366920938463463374607431768211455", 10) + + quotientLow.Low = FeltFromBigInt(new(big.Int).And(quotient, maxU128)) // q & maxU128 + quotientLow.High = FeltFromBigInt(new(big.Int).And(new(big.Int).Rsh(quotient, 128), maxU128)) // q >> 128 & maxU128 + quotientHigh.Low = FeltFromBigInt(new(big.Int).And(new(big.Int).Rsh(quotient, 256), maxU128)) // q >> 256 & maxU128 + quotientHigh.High = FeltFromBigInt(new(big.Int).Rsh(quotient, 384)) // q >> 384 + remainder.Low = FeltFromBigInt(new(big.Int).And(rem, maxU128)) // rem & maxU128 + remainder.High = FeltFromBigInt(new(big.Int).And(new(big.Int).Rsh(rem, 128), maxU128)) // rem >> 128 & maxU128 + + err = ids.InsertUint256("quotient_low", quotientLow, vm) + if err != nil { + return err + } + err = ids.InsertUint256("quotient_high", quotientHigh, vm) + if err != nil { + return err + } + return ids.InsertUint256("remainder", remainder, vm) + +} diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index 30b389cc..3a10fcf1 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -647,3 +647,57 @@ func TestUint256ExpandedUnsignedDivRemOk(t *testing.T) { } } + +func TestUint256MulDivOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + vm.Segments.AddSegment() + + ids := map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFeltFromUint64(89), + NewMaybeRelocatableFeltFromUint64(72), + }, + "b": { + NewMaybeRelocatableFeltFromUint64(3), + NewMaybeRelocatableFeltFromUint64(7), + }, + "div": { + NewMaybeRelocatableFeltFromUint64(107), + NewMaybeRelocatableFeltFromUint64(114), + }, + "quotient_low": {nil, nil}, + "quotient_high": {nil, nil}, + "remainder": {nil, nil}, + } + idsManager := SetupIdsForTest(ids, vm) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_MUL_DIV_MOD, + }) + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + // quotient, err := idsManager.GetUint256("quotient", vm) + // if err != nil { + // t.Errorf("failed with error: %s", err) + // } + + // expectedQuotient := Uint256{Low: FeltFromUint(10), High: FeltFromUint(0)} + // if quotient != expectedQuotient { + // t.Errorf("expected quotient: %s, got: %s", expectedQuotient.ToString(), quotient.ToString()) + // } + + // remainder, err := idsManager.GetUint256("remainder", vm) + // if err != nil { + // t.Errorf("failed with error: %s", err) + // } + + // expectedRemainder := Uint256{Low: FeltFromUint(59), High: FeltFromUint(2)} + // if remainder != expectedRemainder { + // t.Errorf("expected remainder: %s, got: %s", expectedRemainder.ToString(), remainder.ToString()) + // } +} From c1cd05a2a4e6c7569191e5251471270687d6c89c Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Wed, 27 Sep 2023 15:20:29 +0200 Subject: [PATCH 18/31] add test and improve commit --- pkg/hints/uint256_hints.go | 16 +++--------- pkg/hints/uint256_hints_test.go | 45 +++++++++++++++++++-------------- pkg/lambdaworks/lambdaworks.go | 4 +++ 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index a81c70b1..2f74d244 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -249,19 +249,6 @@ func uint256MulDivMod(ids IdsManager, vm *VirtualMachine) error { if err != nil { return err } - quotientLow, err := ids.GetUint256("quotient_low", vm) - if err != nil { - fmt.Pri - return err - } - quotientHigh, err := ids.GetUint256("quotient_high", vm) - if err != nil { - return err - } - remainder, err := ids.GetUint256("remainder", vm) - if err != nil { - return err - } if div.ToBigInt().Cmp(big.NewInt(0)) == 0 { return errors.Errorf("Attempted to divide by zero") @@ -272,6 +259,9 @@ func uint256MulDivMod(ids IdsManager, vm *VirtualMachine) error { maxU128, _ := new(big.Int).SetString("340282366920938463463374607431768211455", 10) + var quotientLow Uint256 + var quotientHigh Uint256 + var remainder Uint256 quotientLow.Low = FeltFromBigInt(new(big.Int).And(quotient, maxU128)) // q & maxU128 quotientLow.High = FeltFromBigInt(new(big.Int).And(new(big.Int).Rsh(quotient, 128), maxU128)) // q >> 128 & maxU128 quotientHigh.Low = FeltFromBigInt(new(big.Int).And(new(big.Int).Rsh(quotient, 256), maxU128)) // q >> 256 & maxU128 diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index 3a10fcf1..1706ebb3 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -681,23 +681,30 @@ func TestUint256MulDivOk(t *testing.T) { t.Errorf("failed with error: %s", err) } - // quotient, err := idsManager.GetUint256("quotient", vm) - // if err != nil { - // t.Errorf("failed with error: %s", err) - // } - - // expectedQuotient := Uint256{Low: FeltFromUint(10), High: FeltFromUint(0)} - // if quotient != expectedQuotient { - // t.Errorf("expected quotient: %s, got: %s", expectedQuotient.ToString(), quotient.ToString()) - // } - - // remainder, err := idsManager.GetUint256("remainder", vm) - // if err != nil { - // t.Errorf("failed with error: %s", err) - // } - - // expectedRemainder := Uint256{Low: FeltFromUint(59), High: FeltFromUint(2)} - // if remainder != expectedRemainder { - // t.Errorf("expected remainder: %s, got: %s", expectedRemainder.ToString(), remainder.ToString()) - // } + quotientLow, err := idsManager.GetUint256("quotient_low", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + expectedQuotientLow := Uint256{Low: FeltFromDecString("143276786071974089879315624181797141668"), High: FeltFromUint(4)} + if !quotientLow.IsEqual(expectedQuotientLow) { + t.Errorf("expected quotient_low: %s, got: %s", expectedQuotientLow.ToString(), quotientLow.ToString()) + } + + quotientHigh, err := idsManager.GetUint256("quotient_high", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + expectedQuotientHigh := Uint256{Low: FeltFromUint(0), High: FeltFromUint(0)} + if !quotientHigh.IsEqual(expectedQuotientHigh) { + t.Errorf("expected quotient_high: %s, got: %s", expectedQuotientHigh.ToString(), quotientHigh.ToString()) + } + + remainder, err := idsManager.GetUint256("remainder", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + expectedRemainder := Uint256{Low: FeltFromDecString("322372768661941702228460154409043568767"), High: FeltFromUint(101)} + if !remainder.IsEqual(expectedRemainder) { + t.Errorf("expected remainder: %s, got: %s", expectedRemainder.ToString(), remainder.ToString()) + } } diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index adc1e594..598c1f07 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -396,3 +396,7 @@ func ToUint256(a *big.Int) Uint256 { high := new(big.Int).Rsh(a, 128) return Uint256{Low: FeltFromBigInt(low), High: FeltFromBigInt(high)} } + +func (u *Uint256) IsEqual(other Uint256) bool { + return u.Low == other.High && u.High == other.High +} From 8ff45d8cfab4116f5e7f33903103ce14d6e18881 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Wed, 27 Sep 2023 15:29:26 +0200 Subject: [PATCH 19/31] fix test --- pkg/hints/uint256_hints_test.go | 2 +- pkg/lambdaworks/lambdaworks.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index 1706ebb3..2438042d 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -323,7 +323,7 @@ func TestUint256SqrtOk(t *testing.T) { NewMaybeRelocatableFelt(FeltFromUint64(17)), NewMaybeRelocatableFelt(FeltFromUint64(7)), }, - "root": {nil}, + "root": {nil, nil}, }, vm, ) diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index ca1868c5..b8ad8ecd 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -397,5 +397,5 @@ func ToUint256(a *big.Int) Uint256 { } func (u *Uint256) IsEqual(other Uint256) bool { - return u.Low == other.High && u.High == other.High + return u.Low.Cmp(other.Low) == 0 && u.High.Cmp(other.High) == 0 } From e25b7b44979bfd7f53165fe9006143c1e4a3b91d Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Wed, 27 Sep 2023 18:20:23 +0200 Subject: [PATCH 20/31] add integration tests --- .../uint256_integration_tests.cairo | 151 ++++++++++++++++++ pkg/hints/hint_utils/ids_manager.go | 3 +- pkg/hints/uint256_hints.go | 26 ++- pkg/hints/uint256_hints_test.go | 90 ++++------- pkg/vm/cairo_run/cairo_run_test.go | 4 + 5 files changed, 207 insertions(+), 67 deletions(-) create mode 100644 cairo_programs/uint256_integration_tests.cairo 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) +} From 89d40bb7eb920d06c7430884749a7bf17033c857 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Wed, 27 Sep 2023 19:28:02 +0200 Subject: [PATCH 21/31] fix unit and integration tests --- cairo_programs/uint256.cairo | 115 +++++++++++++ .../uint256_integration_tests.cairo | 151 ++++++++++++++++++ pkg/hints/hint_utils/ids_manager.go | 3 +- pkg/hints/uint256_hints.go | 37 +++-- pkg/hints/uint256_hints_test.go | 92 ++++------- pkg/lambdaworks/lambdaworks.go | 2 +- pkg/vm/cairo_run/cairo_run_test.go | 8 + 7 files changed, 337 insertions(+), 71 deletions(-) create mode 100644 cairo_programs/uint256.cairo create mode 100644 cairo_programs/uint256_integration_tests.cairo diff --git a/cairo_programs/uint256.cairo b/cairo_programs/uint256.cairo new file mode 100644 index 00000000..f3e4daf1 --- /dev/null +++ b/cairo_programs/uint256.cairo @@ -0,0 +1,115 @@ +%builtins range_check + +from starkware.cairo.common.uint256 import ( + Uint256, + uint256_add, + split_64, + uint256_sqrt, + uint256_signed_nn, + uint256_unsigned_div_rem, + uint256_mul, + uint256_mul_div_mod +) +from starkware.cairo.common.alloc import alloc + +func fill_array{range_check_ptr: felt}( + array: Uint256*, base: Uint256, step: Uint256, array_length: felt, iterator: felt +) { + if (iterator == array_length) { + return (); + } + let (res, carry_high) = uint256_add(step, base); + let (sqrt) = uint256_sqrt(res); + + assert array[iterator] = sqrt; + return fill_array(array, base, array[iterator], array_length, iterator + 1); +} + +func main{range_check_ptr: felt}() { + let x: Uint256 = Uint256(5, 2); + let y = Uint256(3, 7); + let (res, carry_high) = uint256_add(x, y); + assert res.low = 8; + assert res.high = 9; + assert carry_high = 0; + + let (low, high) = split_64(850981239023189021389081239089023); + assert low = 7249717543555297151; + assert high = 46131785404667; + + let (root) = uint256_sqrt(Uint256(17, 7)); + assert root = Uint256(48805497317890012913, 0); + + let (signed_nn) = uint256_signed_nn(Uint256(5, 2)); + assert signed_nn = 1; + let (p) = uint256_signed_nn(Uint256(1, 170141183460469231731687303715884105728)); + assert p = 0; + let (q) = uint256_signed_nn(Uint256(1, 170141183460469231731687303715884105727)); + assert q = 1; + + let (a_quotient, a_remainder) = uint256_unsigned_div_rem(Uint256(89, 72), Uint256(3, 7)); + assert a_quotient = Uint256(10, 0); + assert a_remainder = Uint256(59, 2); + + let (b_quotient, b_remainder) = uint256_unsigned_div_rem( + Uint256(-3618502788666131213697322783095070105282824848410658236509717448704103809099, 2), + Uint256(5, 2), + ); + assert b_quotient = Uint256(1, 0); + assert b_remainder = Uint256(340282366920938463463374607431768211377, 0); + + let (c_quotient, c_remainder) = uint256_unsigned_div_rem( + Uint256(340282366920938463463374607431768211455, 340282366920938463463374607431768211455), + Uint256(1, 0), + ); + + assert c_quotient = Uint256(340282366920938463463374607431768211455, 340282366920938463463374607431768211455); + assert c_remainder = Uint256(0, 0); + + let (a_quotient_low, a_quotient_high, a_remainder) = uint256_mul_div_mod( + Uint256(89, 72), + Uint256(3, 7), + Uint256(107, 114), + ); + assert a_quotient_low = Uint256(143276786071974089879315624181797141668, 4); + assert a_quotient_high = Uint256(0, 0); + assert a_remainder = Uint256(322372768661941702228460154409043568767, 101); + + let (b_quotient_low, b_quotient_high, b_remainder) = uint256_mul_div_mod( + Uint256(-3618502788666131213697322783095070105282824848410658236509717448704103809099, 2), + Uint256(1, 1), + Uint256(5, 2), + ); + assert b_quotient_low = Uint256(170141183460469231731687303715884105688, 1); + assert b_quotient_high = Uint256(0, 0); + assert b_remainder = Uint256(170141183460469231731687303715884105854, 1); + + let (c_quotient_low, c_quotient_high, c_remainder) = uint256_mul_div_mod( + Uint256(340281070833283907490476236129005105807, 340282366920938463463374607431768211455), + Uint256(2447157533618445569039502, 0), + Uint256(0, 1), + ); + + assert c_quotient_low = Uint256(340282366920938463454053728725133866491, 2447157533618445569039501); + assert c_quotient_high = Uint256(0, 0); + assert c_remainder = Uint256(326588112914912836985603897252688572242, 0); + + let (mult_low_a, mult_high_a) = uint256_mul(Uint256(59, 2), Uint256(10, 0)); + assert mult_low_a = Uint256(590, 20); + assert mult_high_a = Uint256(0, 0); + + let (mult_low_b: Uint256, mult_high_b: Uint256) = uint256_mul( + Uint256(271442546951262198976322048597925888860, 0), + Uint256(271442546951262198976322048597925888860, 0), + ); + assert mult_low_b = Uint256( + 42047520920204780886066537579778623760, 216529163594619381764978757921136443390 + ); + assert mult_high_b = Uint256(0, 0); + + let array_length = 100; + let (sum_array: Uint256*) = alloc(); + fill_array(sum_array, Uint256(57, 8), Uint256(17, 7), array_length, 0); + + return (); +} 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..57fcc3bc 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("uint256Add") shift := FeltOne().Shl(128) aLow, err := ids.GetStructFieldFelt("a", 0, vm) if err != nil { @@ -70,7 +72,7 @@ func uint256Add(ids IdsManager, vm *VirtualMachine, lowOnly bool) error { } ids.Insert("carry_high", NewMaybeRelocatableFelt(carryHigh), vm) } - + fmt.Println("uint256Add") return ids.Insert("carry_low", NewMaybeRelocatableFelt(carryLow), vm) } @@ -85,6 +87,7 @@ Implements hint: %} */ func split64(ids IdsManager, vm *VirtualMachine) error { + fmt.Println("split64") a, err := ids.GetFelt("a", vm) if err != nil { return err @@ -100,6 +103,7 @@ func split64(ids IdsManager, vm *VirtualMachine) error { if err != nil { return err } + fmt.Println("split64") return nil } @@ -118,6 +122,7 @@ Implements hint: %} */ func uint256Sqrt(ids IdsManager, vm *VirtualMachine, onlyLow bool) error { + fmt.Println("uint256Sqrt") uintN, err := ids.GetUint256("n", vm) if err != nil { return err @@ -132,8 +137,12 @@ func uint256Sqrt(ids IdsManager, vm *VirtualMachine, onlyLow bool) error { feltRoot := FeltFromBigInt(root) if onlyLow { + fmt.Println("1.uint256Sqrt") + return ids.Insert("root", NewMaybeRelocatableFelt(feltRoot), vm) } else { + fmt.Println("2.uint256Sqrt") + return ids.InsertUint256("root", lambdaworks.Uint256{Low: feltRoot, High: FeltZero()}, vm) } } @@ -143,13 +152,18 @@ Implements hint: %{ memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 127 else 0 %} */ func uint256SignedNN(ids IdsManager, vm *VirtualMachine) error { + fmt.Println("uint256SignedNN") a, err := ids.GetUint256("a", vm) if err != nil { return err } - if a.High.Cmp(SignedFeltMaxValue()) != 1 { + i128Max := FeltFromDecString("170141183460469231731687303715884105727") + if a.High.Cmp(FeltZero()) != -1 && a.High.Cmp(i128Max) != 1 { + fmt.Println("1.uint256SignedNN") return ids.InsertValueIntoAP(vm, *NewMaybeRelocatableFelt(FeltOne())) } else { + fmt.Println("2.uint256SignedNN") + return ids.InsertValueIntoAP(vm, *NewMaybeRelocatableFelt(FeltZero())) } } @@ -170,7 +184,9 @@ Implements hint: %} */ func uint256UnsignedDivRem(ids IdsManager, vm *VirtualMachine) error { + fmt.Println("uint256UnsignedDivRem") return uint256OfssetedUnisgnedDivRem(ids, vm, 0, 1) + } /* @@ -189,24 +205,21 @@ Implements hint: %} */ func uint256ExpandedUnsignedDivRem(ids IdsManager, vm *VirtualMachine) error { + fmt.Println("uint256ExpandedUnsignedDivRem") return uint256OfssetedUnisgnedDivRem(ids, vm, 1, 3) } func uint256OfssetedUnisgnedDivRem(ids IdsManager, vm *VirtualMachine, divOffsetLow uint, divOffsetHigh uint) error { + fmt.Println("uint256OfssetedUnisgnedDivRem") a, err := ids.GetUint256("a", vm) if err != nil { return err } - - baseDiv, err := ids.GetRelocatable("div", vm) + divLow, err := ids.GetStructFieldFelt("div", divOffsetLow, vm) if err != nil { return err } - divLow, err := vm.Segments.Memory.GetFelt(baseDiv.AddUint(divOffsetLow)) - 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,8 +228,11 @@ func uint256OfssetedUnisgnedDivRem(ids IdsManager, vm *VirtualMachine, divOffset err = ids.InsertUint256("quotient", ToUint256(q), vm) if err != nil { + fmt.Println("error: uint256OfssetedUnisgnedDivRem") return err } + fmt.Println("uint256OfssetedUnisgnedDivRem") + return ids.InsertUint256("remainder", ToUint256(r), vm) } @@ -237,6 +253,7 @@ Implements hint: %} */ func uint256MulDivMod(ids IdsManager, vm *VirtualMachine) error { + fmt.Println("uint256MulDivMod") a, err := ids.GetUint256("a", vm) if err != nil { return err @@ -277,6 +294,8 @@ func uint256MulDivMod(ids IdsManager, vm *VirtualMachine) error { if err != nil { return err } + fmt.Println("uint256MulDivMod") + return ids.InsertUint256("remainder", remainder, vm) } diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index 1706ebb3..102c8ea5 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -323,7 +323,7 @@ func TestUint256SqrtOk(t *testing.T) { NewMaybeRelocatableFelt(FeltFromUint64(17)), NewMaybeRelocatableFelt(FeltFromUint64(7)), }, - "root": {nil}, + "root": {nil, nil}, }, vm, ) @@ -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/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index ca1868c5..b8ad8ecd 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -397,5 +397,5 @@ func ToUint256(a *big.Int) Uint256 { } func (u *Uint256) IsEqual(other Uint256) bool { - return u.Low == other.High && u.High == other.High + return u.Low.Cmp(other.Low) == 0 && u.High.Cmp(other.High) == 0 } diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index 47fb4e24..c0df9707 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -335,3 +335,11 @@ 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) +} + +func TestUint256(t *testing.T) { + testProgram("uint256", t) +} From c597a0f97d32172a302c13a406e2c3498e35bbc0 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Wed, 27 Sep 2023 19:36:08 +0200 Subject: [PATCH 22/31] =?UTF-8?q?improve=20code=C2=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/hints/uint256_hints.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index 78cae7d7..631e9200 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -121,9 +121,7 @@ func uint256Sqrt(ids IdsManager, vm *VirtualMachine, onlyLow bool) error { if err != nil { return err } - bHigh := new(big.Int).Lsh(uintN.High.ToBigInt(), 128) - bLow := uintN.Low.ToBigInt() - n := new(big.Int).Add(bHigh, bLow) + n := uintN.ToBigInt() root := new(big.Int).Sqrt(n) if root.BitLen() > 128 { return ErrRootOOR(root) From 5012e76d892b544888bebb583c9f5c6d72665fd0 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Wed, 27 Sep 2023 19:42:11 +0200 Subject: [PATCH 23/31] add uint256 utils --- pkg/hints/hint_utils/ids_manager.go | 10 +++---- pkg/hints/hint_utils/uint256_utils.go | 42 +++++++++++++++++++++++++++ pkg/hints/uint256_hints.go | 3 +- pkg/lambdaworks/lambdaworks.go | 35 ---------------------- 4 files changed, 48 insertions(+), 42 deletions(-) create mode 100644 pkg/hints/hint_utils/uint256_utils.go diff --git a/pkg/hints/hint_utils/ids_manager.go b/pkg/hints/hint_utils/ids_manager.go index e59b4092..e44bb0aa 100644 --- a/pkg/hints/hint_utils/ids_manager.go +++ b/pkg/hints/hint_utils/ids_manager.go @@ -76,16 +76,16 @@ func (ids *IdsManager) GetFelt(name string, vm *VirtualMachine) (lambdaworks.Fel return felt, nil } -func (ids *IdsManager) GetUint256(name string, vm *VirtualMachine) (lambdaworks.Uint256, error) { +func (ids *IdsManager) GetUint256(name string, vm *VirtualMachine) (Uint256, error) { low, err := ids.GetStructFieldFelt(name, 0, vm) if err != nil { - return lambdaworks.Uint256{}, err + return Uint256{}, err } high, err := ids.GetStructFieldFelt(name, 1, vm) if err != nil { - return lambdaworks.Uint256{}, err + return Uint256{}, err } - return lambdaworks.Uint256{Low: low, High: high}, nil + return Uint256{Low: low, High: high}, nil } // Returns the value of an identifier as a Relocatable @@ -230,7 +230,7 @@ func (ids *IdsManager) InsertStructField(name string, field_off uint, value *May } // Inserts Uint256 value into an ids field (given the identifier is a Uint256) -func (ids *IdsManager) InsertUint256(name string, val lambdaworks.Uint256, vm *VirtualMachine) error { +func (ids *IdsManager) InsertUint256(name string, val Uint256, vm *VirtualMachine) error { err := ids.InsertStructField(name, 0, NewMaybeRelocatableFelt(val.Low), vm) if err != nil { return err diff --git a/pkg/hints/hint_utils/uint256_utils.go b/pkg/hints/hint_utils/uint256_utils.go new file mode 100644 index 00000000..20967fb5 --- /dev/null +++ b/pkg/hints/hint_utils/uint256_utils.go @@ -0,0 +1,42 @@ +package hint_utils + +import ( + "math/big" + + . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" +) + +type Uint256 struct { + Low Felt + High Felt +} + +func (ui256 *Uint256) ToString() string { + return "Uint256 {low: " + ui256.Low.ToSignedFeltString() + ", high: " + ui256.High.ToSignedFeltString() + "}" +} + +/* +Returns a Uint256 as a big.Int + + res = high << 128 + low +*/ +func (u *Uint256) ToBigInt() *big.Int { + high := new(big.Int).Lsh(u.High.ToBigInt(), 128) + low := u.Low.ToBigInt() + res := new(big.Int).Add(high, low) + return res +} + +/* +Returns a big.Int as Uint256 +*/ +func ToUint256(a *big.Int) Uint256 { + maxU128, _ := new(big.Int).SetString("340282366920938463463374607431768211455", 10) + low := new(big.Int).And(a, maxU128) + high := new(big.Int).Rsh(a, 128) + return Uint256{Low: FeltFromBigInt(low), High: FeltFromBigInt(high)} +} + +func (u *Uint256) IsEqual(other Uint256) bool { + return u.Low.Cmp(other.Low) == 0 && u.High.Cmp(other.High) == 0 +} diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index 631e9200..30513e50 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -4,7 +4,6 @@ import ( "math/big" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" - "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" @@ -131,7 +130,7 @@ func uint256Sqrt(ids IdsManager, vm *VirtualMachine, onlyLow bool) error { if onlyLow { return ids.Insert("root", NewMaybeRelocatableFelt(feltRoot), vm) } else { - return ids.InsertUint256("root", lambdaworks.Uint256{Low: feltRoot, High: FeltZero()}, vm) + return ids.InsertUint256("root", Uint256{Low: feltRoot, High: FeltZero()}, vm) } } diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index b8ad8ecd..fb175502 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -26,11 +26,6 @@ type Felt struct { limbs [N_LIMBS_IN_FELT]Limb } -type Uint256 struct { - Low Felt - High Felt -} - func LambdaworksError(err error) error { return errors.Wrapf(err, "Lambdaworks Error") } @@ -369,33 +364,3 @@ func (a Felt) Cmp(b Felt) int { var b_c C.felt_t = b.toC() return int(C.cmp(&a_c[0], &b_c[0])) } - -func (ui256 *Uint256) ToString() string { - return "Uint256 {low: " + ui256.Low.ToSignedFeltString() + ", high: " + ui256.High.ToSignedFeltString() + "}" -} - -/* -Returns a Uint256 as a big.Int - - res = high << 128 + low -*/ -func (ui256 *Uint256) ToBigInt() *big.Int { - high := new(big.Int).Lsh(ui256.High.ToBigInt(), 128) - low := ui256.Low.ToBigInt() - res := new(big.Int).Add(high, low) - return res -} - -/* -Returns a big.Int as Uint256 -*/ -func ToUint256(a *big.Int) Uint256 { - maxU128, _ := new(big.Int).SetString("340282366920938463463374607431768211455", 10) - low := new(big.Int).And(a, maxU128) - high := new(big.Int).Rsh(a, 128) - return Uint256{Low: FeltFromBigInt(low), High: FeltFromBigInt(high)} -} - -func (u *Uint256) IsEqual(other Uint256) bool { - return u.Low.Cmp(other.Low) == 0 && u.High.Cmp(other.High) == 0 -} From 5c71c1fde2f22aa17724df6325074e225ccbc4d0 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Thu, 28 Sep 2023 15:51:22 +0200 Subject: [PATCH 24/31] add test --- pkg/hints/uint256_hints_test.go | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index 102c8ea5..f56a4fe4 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -313,6 +313,52 @@ func TestSplit64Ok(t *testing.T) { } +func TestSplit64BigA(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(FeltFromDecString("400066369019890261321163226850167045262")), + }, + "low": {nil}, + "high": {nil}, + }, + vm, + ) + + hintData := any(HintData{ + Ids: idsManager, + Code: SPLIT_64, + }) + scopes := NewExecutionScopes() + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + low, err := idsManager.GetFelt("low", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + expected_low := FeltFromUint64(2279400676465785998) + if low.Cmp(expected_low) != 0 { + t.Errorf("expected low: %d, got: %d", expected_low, low) + } + high, err := idsManager.GetFelt("high", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + expected_high := FeltFromDecString("21687641321487626429") + if high.Cmp(expected_high) != 0 { + t.Errorf("expected high: %d, got: %d", expected_high, high) + } + +} + func TestUint256SqrtOk(t *testing.T) { vm := NewVirtualMachine() vm.Segments.AddSegment() From ef3080e26fbdc515ec07a855947c30ff223b606f Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Thu, 28 Sep 2023 17:32:54 +0200 Subject: [PATCH 25/31] fix comments --- pkg/hints/hint_utils/ids_manager.go | 22 +-- pkg/hints/uint256_hints.go | 37 ++--- pkg/hints/uint256_hints_test.go | 205 +++++----------------------- 3 files changed, 58 insertions(+), 206 deletions(-) diff --git a/pkg/hints/hint_utils/ids_manager.go b/pkg/hints/hint_utils/ids_manager.go index e44bb0aa..2394f8b1 100644 --- a/pkg/hints/hint_utils/ids_manager.go +++ b/pkg/hints/hint_utils/ids_manager.go @@ -77,11 +77,15 @@ func (ids *IdsManager) GetFelt(name string, vm *VirtualMachine) (lambdaworks.Fel } func (ids *IdsManager) GetUint256(name string, vm *VirtualMachine) (Uint256, error) { - low, err := ids.GetStructFieldFelt(name, 0, vm) + lowAddr, err := ids.GetAddr(name, vm) if err != nil { return Uint256{}, err } - high, err := ids.GetStructFieldFelt(name, 1, vm) + low, err := vm.Segments.Memory.GetFelt(lowAddr) + if err != nil { + return Uint256{}, err + } + high, err := vm.Segments.Memory.GetFelt(lowAddr.AddUint(1)) if err != nil { return Uint256{}, err } @@ -231,17 +235,15 @@ func (ids *IdsManager) InsertStructField(name string, field_off uint, value *May // Inserts Uint256 value into an ids field (given the identifier is a Uint256) func (ids *IdsManager) InsertUint256(name string, val Uint256, vm *VirtualMachine) error { - err := ids.InsertStructField(name, 0, NewMaybeRelocatableFelt(val.Low), vm) + baseAddr, err := ids.GetAddr(name, vm) if err != nil { return err } - return ids.InsertStructField(name, 1, NewMaybeRelocatableFelt(val.High), vm) - -} - -// Inserts value into ap address -func (ids *IdsManager) InsertValueIntoAP(vm *VirtualMachine, value MaybeRelocatable) error { - return vm.Segments.Memory.Insert(vm.RunContext.Ap, &value) + err = vm.Segments.Memory.Insert(baseAddr, NewMaybeRelocatableFelt(val.Low)) + if err != nil { + return err + } + return vm.Segments.Memory.Insert(baseAddr.AddUint(1), NewMaybeRelocatableFelt(val.High)) } // Inserts value into the address of the given identifier diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index 30513e50..ae4f72a7 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -30,44 +30,31 @@ Implements hints: func uint256Add(ids IdsManager, vm *VirtualMachine, lowOnly bool) error { shift := FeltOne().Shl(128) - aLow, err := ids.GetStructFieldFelt("a", 0, vm) + a, err := ids.GetUint256("a", vm) if err != nil { return err } - - bLow, err := ids.GetStructFieldFelt("b", 0, vm) + b, err := ids.GetUint256("b", vm) if err != nil { return err } - sumLow := aLow.Add(bLow) - var carryLow Felt - switch sumLow.Cmp(shift) { - case -1: - carryLow = FeltZero() - default: + sumLow := a.Low.Add(b.Low) + carryLow := FeltZero() + if sumLow.Cmp(shift) != -1 { carryLow = FeltOne() } if !lowOnly { - aHigh, err := ids.GetStructFieldFelt("a", 1, vm) - if err != nil { - return err + sumHigh := a.High.Add(b.High.Add(carryLow)) + carryHigh := FeltZero() + if sumHigh.Cmp(shift) != -1 { + carryHigh = FeltOne() } - bHigh, err := ids.GetStructFieldFelt("b", 1, vm) + err := ids.Insert("carry_high", NewMaybeRelocatableFelt(carryHigh), vm) if err != nil { return err } - - sumHigh := aHigh.Add(bHigh.Add(carryLow)) - var carryHigh Felt - switch sumHigh.Cmp(shift) { - case -1: - carryHigh = FeltZero() - default: - carryHigh = FeltOne() - } - ids.Insert("carry_high", NewMaybeRelocatableFelt(carryHigh), vm) } return ids.Insert("carry_low", NewMaybeRelocatableFelt(carryLow), vm) @@ -145,9 +132,9 @@ func uint256SignedNN(ids IdsManager, vm *VirtualMachine) error { } i128Max := FeltFromDecString("170141183460469231731687303715884105727") if a.High.Cmp(FeltZero()) != -1 && a.High.Cmp(i128Max) != 1 { - return ids.InsertValueIntoAP(vm, *NewMaybeRelocatableFelt(FeltOne())) + return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltOne())) } else { - return ids.InsertValueIntoAP(vm, *NewMaybeRelocatableFelt(FeltZero())) + return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltZero())) } } diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index f56a4fe4..20e9411b 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -15,51 +15,28 @@ import ( . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" ) -/* -flag := (1 << 128) - - a := { - a.low: flag - 5 - a.high = ... - } - - b := { - b.low: 4 - b.high = ... - } - -a.low + b.low < flag -> carryLow = 0 -*/ -func TestUint256AddCarryLow0(t *testing.T) { +func TestUint256AddOk(t *testing.T) { vm := NewVirtualMachine() vm.Segments.AddSegment() - flag := FeltOne().Shl(128) - idsManager := SetupIdsForTest( map[string][]*MaybeRelocatable{ "a": { - NewMaybeRelocatableFelt(flag.Sub(FeltFromUint64(5))), - nil, + NewMaybeRelocatableFeltFromUint64(2), + NewMaybeRelocatableFeltFromUint64(3), }, "b": { - NewMaybeRelocatableFelt(FeltFromUint64(4)), - nil, - }, - "carry_low": { - nil, - nil, - }, - "carry_high": { - nil, - nil, + NewMaybeRelocatableFeltFromUint64(4), + NewMaybeRelocatableFelt(FeltFromDecString("340282366920938463463374607431768211455")), }, + "carry_low": {nil}, + "carry_high": {nil}, }, vm, ) hintData := any(HintData{ Ids: idsManager, - Code: UINT256_ADD_LOW, + Code: UINT256_ADD, }) scopes := NewExecutionScopes() hintProcessor := CairoVmHintProcessor{} @@ -68,125 +45,43 @@ func TestUint256AddCarryLow0(t *testing.T) { t.Errorf("failed with error: %s", err) } - carry_low, err := idsManager.GetStructFieldFelt("carry_low", 0, vm) + carry_low, err := idsManager.GetFelt("carry_low", vm) if err != nil { t.Errorf("failed with error: %s", err) } - if carry_low != FeltZero() { + if carry_low.Cmp(FeltZero()) != 0 { t.Errorf("expected carry_low: 0, got: %s", carry_low.ToSignedFeltString()) } -} - -/* -flag := (1 << 128) - - a := { - a.low: flag - a.high = ... - } - - b := { - b.low: 0 - b.high = ... - } - -a.low + b.low >= flag -> carryLow = 1 -*/ -func TestUint256AddCarryLow1(t *testing.T) { - vm := NewVirtualMachine() - vm.Segments.AddSegment() - - flag := FeltOne().Shl(128) - - idsManager := SetupIdsForTest( - map[string][]*MaybeRelocatable{ - "a": { - NewMaybeRelocatableFelt(flag), - nil, - }, - "b": { - NewMaybeRelocatableFelt(FeltZero()), - nil, - }, - "carry_low": { - nil, - nil, - }, - "carry_high": { - nil, - nil, - }, - }, - vm, - ) - hintData := any(HintData{ - Ids: idsManager, - Code: UINT256_ADD_LOW, - }) - scopes := NewExecutionScopes() - hintProcessor := CairoVmHintProcessor{} - err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) - if err != nil { - t.Errorf("failed with error: %s", err) - } - - carry_low, err := idsManager.GetStructFieldFelt("carry_low", 0, vm) + carry_high, err := idsManager.GetFelt("carry_high", vm) if err != nil { t.Errorf("failed with error: %s", err) } - if carry_low != FeltOne() { - t.Errorf("expected carry_low: 1, got: %s", carry_low.ToSignedFeltString()) + if carry_high.Cmp(FeltOne()) != 0 { + t.Errorf("expected carry_high: 0, got: %s", carry_high.ToSignedFeltString()) } } -/* -flag := (1 << 128) - - a := { - a.low: 0 - a.high = flag / 2 - } - - b := { - b.low: 0 - b.high = a.high - 1 - } - -a.low + b.low < flag -> carryLow = 0 -a.high + b.high + carryLow < flag -> carry_high = 0 -*/ -func TestUint256AddCarryHigh0(t *testing.T) { +func TestUint256AddLowOnlyOk(t *testing.T) { vm := NewVirtualMachine() vm.Segments.AddSegment() - flag := FeltOne().Shl(128) - aHigh := flag.Div(FeltFromUint64(2)) - bHigh := aHigh.Sub(FeltFromUint64(1)) - idsManager := SetupIdsForTest( map[string][]*MaybeRelocatable{ "a": { - NewMaybeRelocatableFelt(FeltZero()), - NewMaybeRelocatableFelt(aHigh), + NewMaybeRelocatableFeltFromUint64(2), + NewMaybeRelocatableFeltFromUint64(3), }, "b": { - NewMaybeRelocatableFelt(FeltZero()), - NewMaybeRelocatableFelt(bHigh), - }, - "carry_low": { - nil, - nil, - }, - "carry_high": { - nil, - nil, + NewMaybeRelocatableFeltFromUint64(4), + NewMaybeRelocatableFelt(FeltFromDecString("340282366920938463463374607431768211455")), }, + "carry_low": {nil}, }, vm, ) hintData := any(HintData{ Ids: idsManager, - Code: UINT256_ADD, + Code: UINT256_ADD_LOW, }) scopes := NewExecutionScopes() hintProcessor := CairoVmHintProcessor{} @@ -195,76 +90,44 @@ func TestUint256AddCarryHigh0(t *testing.T) { t.Errorf("failed with error: %s", err) } - carry_high, err := idsManager.GetStructFieldFelt("carry_high", 0, vm) + carry_low, err := idsManager.GetFelt("carry_low", vm) if err != nil { t.Errorf("failed with error: %s", err) } - if carry_high != FeltZero() { - t.Errorf("expected carry_low: 0, got: %s", carry_high.ToSignedFeltString()) + if carry_low.Cmp(FeltZero()) != 0 { + t.Errorf("expected carry_low: 0, got: %s", carry_low.ToSignedFeltString()) } } -/* - flag := (1 << 128) - a := { - a.low: flag - a.high = flag / 2 - } - - b := { - b.low: 0 - b.high = a.high - 1 - } - - a.low + b.low >= flag -> carryLow = 1 - a.high + b.high + carryLow > flag -> carry_high = 1 -*/ -func TestUint256AddCarryHigh1(t *testing.T) { +func TestUint256AddFailInsert(t *testing.T) { vm := NewVirtualMachine() vm.Segments.AddSegment() - - flag := FeltOne().Shl(128) - aHigh := flag.Div(FeltFromUint64(2)) - bHigh := aHigh.Sub(FeltFromUint64(1)) - idsManager := SetupIdsForTest( map[string][]*MaybeRelocatable{ "a": { - NewMaybeRelocatableFelt(flag), - NewMaybeRelocatableFelt(aHigh), + NewMaybeRelocatableFeltFromUint64(2), + NewMaybeRelocatableFeltFromUint64(3), }, "b": { - NewMaybeRelocatableFelt(FeltZero()), - NewMaybeRelocatableFelt(bHigh), - }, - "carry_low": { - nil, - nil, - }, - "carry_high": { - nil, - nil, + NewMaybeRelocatableFeltFromUint64(4), + NewMaybeRelocatableFeltFromUint64(2), }, + "carry_low": {NewMaybeRelocatableFeltFromUint64(2)}, }, vm, ) hintData := any(HintData{ Ids: idsManager, - Code: UINT256_ADD, + Code: UINT256_ADD_LOW, }) scopes := NewExecutionScopes() hintProcessor := CairoVmHintProcessor{} err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) - if err != nil { - t.Errorf("failed with error: %s", err) - } - carry_high, err := idsManager.GetStructFieldFelt("carry_high", 0, vm) - if err != nil { - t.Errorf("failed with error: %s", err) - } - if carry_high != FeltOne() { - t.Errorf("expected carry_low: 1, got: %s", carry_high.ToSignedFeltString()) + expected_err := ErrMemoryWriteOnce(NewRelocatable(0, 4), *NewMaybeRelocatableFeltFromUint64(2), *NewMaybeRelocatableFeltFromUint64(0)) + if err.Error() != expected_err.Error() { + t.Errorf("should fail with error: %s", expected_err) } + } func TestSplit64Ok(t *testing.T) { From c7583922e9f5ad8acaae40c3f77ce6dc73380871 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Fri, 29 Sep 2023 12:13:43 +0200 Subject: [PATCH 26/31] improve ToString method on Uint256 --- pkg/hints/hint_utils/uint256_utils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/hints/hint_utils/uint256_utils.go b/pkg/hints/hint_utils/uint256_utils.go index 20967fb5..be26da96 100644 --- a/pkg/hints/hint_utils/uint256_utils.go +++ b/pkg/hints/hint_utils/uint256_utils.go @@ -11,8 +11,8 @@ type Uint256 struct { High Felt } -func (ui256 *Uint256) ToString() string { - return "Uint256 {low: " + ui256.Low.ToSignedFeltString() + ", high: " + ui256.High.ToSignedFeltString() + "}" +func (u *Uint256) ToString() string { + return "Uint256 { low: " + u.Low.ToSignedFeltString() + ", high: " + u.High.ToSignedFeltString() + " }" } /* From 97b550214e9ffe0d9a9a7087c3b36107fd8c783d Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Fri, 29 Sep 2023 14:09:55 +0200 Subject: [PATCH 27/31] fix test --- pkg/hints/uint256_hints_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index 20e9411b..81180f18 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -123,9 +123,8 @@ func TestUint256AddFailInsert(t *testing.T) { scopes := NewExecutionScopes() hintProcessor := CairoVmHintProcessor{} err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) - expected_err := ErrMemoryWriteOnce(NewRelocatable(0, 4), *NewMaybeRelocatableFeltFromUint64(2), *NewMaybeRelocatableFeltFromUint64(0)) - if err.Error() != expected_err.Error() { - t.Errorf("should fail with error: %s", expected_err) + if err == nil { + t.Errorf("should fail with error: ErrMemoryWriteOnce") } } From 6fd3a7fc73653c4e4703b2711726af1a9e105413 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Tue, 3 Oct 2023 18:00:58 +0200 Subject: [PATCH 28/31] fix hint --- pkg/hints/math_cmp_hints.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/hints/math_cmp_hints.go b/pkg/hints/math_cmp_hints.go index 5e4e064b..2e22e667 100644 --- a/pkg/hints/math_cmp_hints.go +++ b/pkg/hints/math_cmp_hints.go @@ -26,7 +26,9 @@ func isNNOutOfRange(ids IdsManager, vm *VirtualMachine) error { if err != nil { return err } - if (FeltZero().Sub(a).Sub(FeltOne())).Bits() < builtins.RANGE_CHECK_N_PARTS*builtins.INNER_RC_BOUND_SHIFT { + op := FeltZero().Sub(a).Sub(FeltOne()) + bound := FeltOne().Shl(16 * builtins.RANGE_CHECK_N_PARTS) + if op.Cmp(bound) == -1 { return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltZero())) } return vm.Segments.Memory.Insert(vm.RunContext.Ap, NewMaybeRelocatableFelt(FeltOne())) From 5b371277cb166eb72f48016438c946ba26538f7f Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Tue, 3 Oct 2023 18:03:18 +0200 Subject: [PATCH 29/31] add extra test used to debug error --- cairo_programs/uint256_root.cairo | 12 ++++++++++++ pkg/vm/cairo_run/cairo_run_test.go | 4 ++++ 2 files changed, 16 insertions(+) create mode 100644 cairo_programs/uint256_root.cairo diff --git a/cairo_programs/uint256_root.cairo b/cairo_programs/uint256_root.cairo new file mode 100644 index 00000000..8f5adc50 --- /dev/null +++ b/cairo_programs/uint256_root.cairo @@ -0,0 +1,12 @@ +%builtins range_check bitwise +from starkware.cairo.common.uint256 import ( + Uint256, + uint256_sqrt, +) +from starkware.cairo.common.cairo_builtins import BitwiseBuiltin + +func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() { + let n = Uint256(0, 157560248172239344387757911110183813120); + let res = uint256_sqrt(n); + return (); +} \ No newline at end of file diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index d2628744..405ee393 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -344,3 +344,7 @@ func TestUint256Integration(t *testing.T) { func TestUint256(t *testing.T) { testProgram("uint256", t) } + +func TestUint256Root(t *testing.T) { + testProgram("uint256_root", t) +} From da80a293c1872554bc5f400c1dfae286717f5f71 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Tue, 3 Oct 2023 19:04:09 +0200 Subject: [PATCH 30/31] add hint uint256_sub --- pkg/hints/hint_codes/uint256_hint_codes.go | 17 +++ pkg/hints/hint_processor.go | 2 + pkg/hints/uint256_hints.go | 56 ++++++- pkg/hints/uint256_hints_test.go | 166 +++++++++++++++++++++ 4 files changed, 240 insertions(+), 1 deletion(-) diff --git a/pkg/hints/hint_codes/uint256_hint_codes.go b/pkg/hints/hint_codes/uint256_hint_codes.go index eb81031f..1881c125 100644 --- a/pkg/hints/hint_codes/uint256_hint_codes.go +++ b/pkg/hints/hint_codes/uint256_hint_codes.go @@ -9,3 +9,20 @@ const UINT256_SIGNED_NN = "memory[ap] = 1 if 0 <= (ids.a.high % PRIME) < 2 ** 12 const UINT256_UNSIGNED_DIV_REM = "a = (ids.a.high << 128) + ids.a.low\ndiv = (ids.div.high << 128) + ids.div.low\nquotient, remainder = divmod(a, div)\n\nids.quotient.low = quotient & ((1 << 128) - 1)\nids.quotient.high = quotient >> 128\nids.remainder.low = remainder & ((1 << 128) - 1)\nids.remainder.high = remainder >> 128" const UINT256_EXPANDED_UNSIGNED_DIV_REM = "a = (ids.a.high << 128) + ids.a.low\ndiv = (ids.div.b23 << 128) + ids.div.b01\nquotient, remainder = divmod(a, div)\n\nids.quotient.low = quotient & ((1 << 128) - 1)\nids.quotient.high = quotient >> 128\nids.remainder.low = remainder & ((1 << 128) - 1)\nids.remainder.high = remainder >> 128" const UINT256_MUL_DIV_MOD = "a = (ids.a.high << 128) + ids.a.low\nb = (ids.b.high << 128) + ids.b.low\ndiv = (ids.div.high << 128) + ids.div.low\nquotient, remainder = divmod(a * b, div)\n\nids.quotient_low.low = quotient & ((1 << 128) - 1)\nids.quotient_low.high = (quotient >> 128) & ((1 << 128) - 1)\nids.quotient_high.low = (quotient >> 256) & ((1 << 128) - 1)\nids.quotient_high.high = quotient >> 384\nids.remainder.low = remainder & ((1 << 128) - 1)\nids.remainder.high = remainder >> 128" +const UINT256_SUB = `def split(num: int, num_bits_shift: int = 128, length: int = 2): + a = [] + for _ in range(length): + a.append( num & ((1 << num_bits_shift) - 1) ) + num = num >> num_bits_shift + return tuple(a) + +def pack(z, num_bits_shift: int = 128) -> int: + limbs = (z.low, z.high) + return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) + +a = pack(ids.a) +b = pack(ids.b) +res = (a - b)%2**256 +res_split = split(res) +ids.res.low = res_split[0] +ids.res.high = res_split[1]` diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 0001bc31..4c0d52fe 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -180,6 +180,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return uint256Add(data.Ids, vm, false) case UINT256_ADD_LOW: return uint256Add(data.Ids, vm, true) + case UINT256_SUB: + return uint256Sub(data.Ids, vm) case SPLIT_64: return split64(data.Ids, vm) case UINT256_SQRT: diff --git a/pkg/hints/uint256_hints.go b/pkg/hints/uint256_hints.go index ae4f72a7..8e7f413c 100644 --- a/pkg/hints/uint256_hints.go +++ b/pkg/hints/uint256_hints.go @@ -60,6 +60,61 @@ func uint256Add(ids IdsManager, vm *VirtualMachine, lowOnly bool) error { } +/* +Implements hint: +%{ + def split(num: int, num_bits_shift: int = 128, length: int = 2): + a = [] + for _ in range(length): + a.append( num & ((1 << num_bits_shift) - 1) ) + num = num >> num_bits_shift + return tuple(a) + + def pack(z, num_bits_shift: int = 128) -> int: + limbs = (z.low, z.high) + return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) + + a = pack(ids.a) + b = pack(ids.b) + res = (a - b)%2**256 + res_split = split(res) + ids.res.low = res_split[0] + ids.res.high = res_split[1] +%} +*/ + +func uint256Sub(ids IdsManager, vm *VirtualMachine) error { + a, err := ids.GetUint256("a", vm) + if err != nil { + return err + } + b, err := ids.GetUint256("b", vm) + if err != nil { + return err + } + var resBigInt *big.Int + if a.ToBigInt().Cmp(b.ToBigInt()) != -1 { + resBigInt = new(big.Int).Sub(a.ToBigInt(), b.ToBigInt()) + } else { + mod256 := new(big.Int).Lsh(new(big.Int).SetUint64(1), 256) + if mod256.Cmp(b.ToBigInt()) != -1 { + resBigInt = new(big.Int).Sub(mod256, b.ToBigInt()) + resBigInt = new(big.Int).Add(resBigInt, a.ToBigInt()) + } else { + loweredB := new(big.Int).Mod(b.ToBigInt(), mod256) + if a.ToBigInt().Cmp(loweredB) != -1 { + resBigInt = new(big.Int).Sub(a.ToBigInt(), loweredB) + } else { + resBigInt = new(big.Int).Sub(mod256, loweredB) + resBigInt = new(big.Int).Add(resBigInt, a.ToBigInt()) + } + } + } + + res := ToUint256(resBigInt) + return ids.InsertUint256("res", res, vm) +} + /* Implements hint: @@ -258,5 +313,4 @@ func uint256MulDivMod(ids IdsManager, vm *VirtualMachine) error { return err } return ids.InsertUint256("remainder", remainder, vm) - } diff --git a/pkg/hints/uint256_hints_test.go b/pkg/hints/uint256_hints_test.go index 81180f18..89f350f0 100644 --- a/pkg/hints/uint256_hints_test.go +++ b/pkg/hints/uint256_hints_test.go @@ -590,3 +590,169 @@ func TestUint256MulDivOk(t *testing.T) { t.Errorf("expected remainder: %s, got: %s", expectedRemainder.ToString(), remainder.ToString()) } } + +func TestUint256SubNonNegativeOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + + ids := map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFeltFromUint64(12179), + NewMaybeRelocatableFeltFromUint64(13044), + }, + "b": { + NewMaybeRelocatableFeltFromUint64(1001), + NewMaybeRelocatableFeltFromUint64(6687), + }, + "res": {nil, nil}, + } + idsManager := SetupIdsForTest(ids, vm) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_SUB, + }) + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + result, err := idsManager.GetUint256("res", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + expectedResult := Uint256{Low: FeltFromUint(11178), High: FeltFromUint(6357)} + if !result.IsEqual(expectedResult) { + t.Errorf("expected result: %s, got: %s", expectedResult.ToString(), result.ToString()) + } +} + +func TestUint256SubNegativeOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + + ids := map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFeltFromUint64(1001), + NewMaybeRelocatableFeltFromUint64(6687), + }, + "b": { + NewMaybeRelocatableFeltFromUint64(12179), + NewMaybeRelocatableFeltFromUint64(13044), + }, + "res": {nil, nil}, + } + idsManager := SetupIdsForTest(ids, vm) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_SUB, + }) + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + result, err := idsManager.GetUint256("res", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + expectedResult := Uint256{Low: FeltFromDecString("340282366920938463463374607431768200278"), High: FeltFromDecString("340282366920938463463374607431768205098")} + if !result.IsEqual(expectedResult) { + t.Errorf("expected result: %s, got: %s", expectedResult.ToString(), result.ToString()) + } +} + +func TestUint256SubBHighGt256LteA(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + + ids := map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(FeltFromDecString("340282366920938463463374607431768211456")), + NewMaybeRelocatableFelt(FeltZero()), + }, + "b": { + NewMaybeRelocatableFelt(FeltZero()), + NewMaybeRelocatableFelt(FeltFromDecString("340282366920938463463374607431768211457")), + }, + "res": {nil, nil}, + } + idsManager := SetupIdsForTest(ids, vm) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_SUB, + }) + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + result, err := idsManager.GetUint256("res", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + expectedResult := Uint256{Low: FeltZero(), High: FeltZero()} + if !result.IsEqual(expectedResult) { + t.Errorf("expected result: %s, got: %s", expectedResult.ToString(), result.ToString()) + } +} + +func TestUint256SubBHighGt256GtA(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + + ids := map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(FeltOne()), + NewMaybeRelocatableFelt(FeltZero()), + }, + "b": { + NewMaybeRelocatableFelt(FeltZero()), + NewMaybeRelocatableFelt(FeltFromDecString("340282366920938463463374607431768211457")), + }, + "res": {nil, nil}, + } + idsManager := SetupIdsForTest(ids, vm) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_SUB, + }) + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("failed with error: %s", err) + } + + result, err := idsManager.GetUint256("res", vm) + if err != nil { + t.Errorf("failed with error: %s", err) + } + expectedResult := Uint256{Low: FeltOne(), High: FeltFromDecString("340282366920938463463374607431768211455")} + if !result.IsEqual(expectedResult) { + t.Errorf("expected result: %s, got: %s", expectedResult.ToString(), result.ToString()) + } +} + +func TestUint256SubMissingNumber(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + + ids := map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(FeltOne()), + nil, + }, + } + idsManager := SetupIdsForTest(ids, vm) + hintData := any(HintData{ + Ids: idsManager, + Code: UINT256_SUB, + }) + hintProcessor := CairoVmHintProcessor{} + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err == nil { + t.Errorf("should fail with error: Memory Get: Value not found") + } +} From b3c532c0eea3df68ab57d24c336be3cd042de77d Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Tue, 3 Oct 2023 19:16:08 +0200 Subject: [PATCH 31/31] wip: remaining uint256 hints --- cairo_programs/uint256_improvements.cairo | 390 +++++++++++++++++++++ pkg/hints/hint_codes/uint384_hint_codes.go | 4 + pkg/hints/uint384_hints.go | 30 ++ pkg/hints/uint384_hints_test.go | 1 + 4 files changed, 425 insertions(+) create mode 100644 cairo_programs/uint256_improvements.cairo create mode 100644 pkg/hints/hint_codes/uint384_hint_codes.go create mode 100644 pkg/hints/uint384_hints.go create mode 100644 pkg/hints/uint384_hints_test.go diff --git a/cairo_programs/uint256_improvements.cairo b/cairo_programs/uint256_improvements.cairo new file mode 100644 index 00000000..b21df0ad --- /dev/null +++ b/cairo_programs/uint256_improvements.cairo @@ -0,0 +1,390 @@ +%builtins range_check + +// Source: https://github.com/NethermindEth/research-basic-Cairo-operations-big-integers/blob/fe1ddf69549354a4f241074486db4cd9fb259d51/lib/uint256_improvements.cairo + +from starkware.cairo.common.uint256 import ( + Uint256, + SHIFT, + HALF_SHIFT, + split_64, + uint256_check, + uint256_add, + uint256_le, + uint256_lt, +) + +// Splits a field element in the range [0, 2^224) to its low 128-bit and high 96-bit parts. +func split_128{range_check_ptr}(a: felt) -> (low: felt, high: felt) { + alloc_locals; + const UPPER_BOUND = 2 ** 224; + const HIGH_BOUND = UPPER_BOUND / SHIFT; + local low: felt; + local high: felt; + + %{ + ids.low = ids.a & ((1<<128) - 1) + ids.high = ids.a >> 128 + %} + assert a = low + high * SHIFT; + assert [range_check_ptr + 0] = high; + assert [range_check_ptr + 1] = HIGH_BOUND - 1 - high; + assert [range_check_ptr + 2] = low; + let range_check_ptr = range_check_ptr + 3; + return (low, high); +} + +// Adds two integers. Returns the result as a 256-bit integer and the (1-bit) carry. +// Doesn't verify that the result is a valid Uint256 +// For use when that check would be performed elsewhere +func _uint256_add_no_uint256_check{range_check_ptr}(a: Uint256, b: Uint256) -> ( + res: Uint256, carry: felt +) { + alloc_locals; + local res: Uint256; + local carry_low: felt; + local carry_high: felt; + %{ + sum_low = ids.a.low + ids.b.low + ids.carry_low = 1 if sum_low >= ids.SHIFT else 0 + sum_high = ids.a.high + ids.b.high + ids.carry_low + ids.carry_high = 1 if sum_high >= ids.SHIFT else 0 + %} + + assert carry_low * carry_low = carry_low; + assert carry_high * carry_high = carry_high; + + assert res.low = a.low + b.low - carry_low * SHIFT; + assert res.high = a.high + b.high + carry_low - carry_high * SHIFT; + + return (res, carry_high); +} + +func uint256_mul{range_check_ptr}(a: Uint256, b: Uint256) -> (low: Uint256, high: Uint256) { + alloc_locals; + let (a0, a1) = split_64(a.low); + let (a2, a3) = split_64(a.high); + let (b0, b1) = split_64(b.low); + let (b2, b3) = split_64(b.high); + + local B0 = b0 * HALF_SHIFT; + local b12 = b1 + b2 * HALF_SHIFT; + + let (res0, carry) = split_128(a1 * B0 + a0 * b.low); + let (res2, carry) = split_128(a3 * B0 + a2 * b.low + a1 * b12 + a0 * b.high + carry); + let (res4, carry) = split_128(a3 * b12 + a2 * b.high + a1 * b3 + carry); + // let (res6, carry) = split_64(a3 * b3 + carry); + + return (low=Uint256(low=res0, high=res2), high=Uint256(low=res4, high=a3 * b3 + carry)); +} + +func uint256_square{range_check_ptr}(a: Uint256) -> (low: Uint256, high: Uint256) { + alloc_locals; + let (a0, a1) = split_64(a.low); + let (a2, a3) = split_64(a.high); + + const HALF_SHIFT2 = 2 * HALF_SHIFT; + + local a12 = a1 + a2 * HALF_SHIFT2; + + let (res0, carry) = split_128(a0 * (a0 + a1 * HALF_SHIFT2)); + let (res2, carry) = split_128(a0 * a.high * 2 + a1 * a12 + carry); + let (res4, carry) = split_128(a3 * (a1 + a12) + a2 * a2 + carry); + // let (res6, carry) = split_64(a3*a3 + carry); + + return (low=Uint256(low=res0, high=res2), high=Uint256(low=res4, high=a3 * a3 + carry)); +} + +// Returns the floor value of the square root of a uint256 integer. +func uint256_sqrt{range_check_ptr}(n: Uint256) -> (res: Uint256) { + alloc_locals; + local root: felt; + + %{ + from starkware.python.math_utils import isqrt + n = (ids.n.high << 128) + ids.n.low + root = isqrt(n) + assert 0 <= root < 2 ** 128 + ids.root = root + %} + + // Verify that 0 <= root < 2**128. + [range_check_ptr] = root; + let range_check_ptr = range_check_ptr + 1; + + // Verify that n >= root**2. + let (root_squared) = uint128_square(root); + let (check_lower_bound) = uint256_le(root_squared, n); + assert check_lower_bound = 1; + + // Verify that n <= (root+1)**2 - 1. + // Note that (root+1)**2 - 1 = root**2 + 2*root. + // In the case where root = 2**128 - 1, + // Since (root+1)**2 = 2**256, next_root_squared_minus_one = 2**256 - 1, as desired. + let (twice_root) = uint128_add(root, root); + let (next_root_squared_minus_one, _) = uint256_add(root_squared, twice_root); + let (check_upper_bound) = uint256_le(n, next_root_squared_minus_one); + assert check_upper_bound = 1; + + return (res=Uint256(low=root, high=0)); +} + +// Uses new uint256_mul, also uses no_uint256_check version of add +func uint256_unsigned_div_rem{range_check_ptr}(a: Uint256, div: Uint256) -> ( + quotient: Uint256, remainder: Uint256 +) { + alloc_locals; + + // If div == 0, return (0, 0). + if (div.low + div.high == 0) { + return (quotient=Uint256(0, 0), remainder=Uint256(0, 0)); + } + + // Guess the quotient and the remainder. + local quotient: Uint256; + local remainder: Uint256; + %{ + a = (ids.a.high << 128) + ids.a.low + div = (ids.div.high << 128) + ids.div.low + quotient, remainder = divmod(a, div) + + ids.quotient.low = quotient & ((1 << 128) - 1) + ids.quotient.high = quotient >> 128 + ids.remainder.low = remainder & ((1 << 128) - 1) + ids.remainder.high = remainder >> 128 + %} + uint256_check(quotient); + uint256_check(remainder); + let (res_mul, carry) = uint256_mul(quotient, div); + assert carry = Uint256(0, 0); + + let (check_val, add_carry) = _uint256_add_no_uint256_check(res_mul, remainder); + assert check_val = a; + assert add_carry = 0; + + let (is_valid) = uint256_lt(remainder, div); + assert is_valid = 1; + return (quotient=quotient, remainder=remainder); +} + +// Subtracts two integers. Returns the result as a 256-bit integer +// and a sign felt that is 1 if the result is non-negative, convention based on signed_nn +// although I think the opposite convetion makes more sense +func uint256_sub{range_check_ptr}(a: Uint256, b: Uint256) -> (res: Uint256, sign: felt) { + alloc_locals; + local res: Uint256; + %{ + def split(num: int, num_bits_shift: int = 128, length: int = 2): + a = [] + for _ in range(length): + a.append( num & ((1 << num_bits_shift) - 1) ) + num = num >> num_bits_shift + return tuple(a) + + def pack(z, num_bits_shift: int = 128) -> int: + limbs = (z.low, z.high) + return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) + + a = pack(ids.a) + b = pack(ids.b) + res = (a - b)%2**256 + res_split = split(res) + ids.res.low = res_split[0] + ids.res.high = res_split[1] + %} + uint256_check(res); + let (aa, inv_sign) = _uint256_add_no_uint256_check(res, b); + assert aa = a; + return (res, 1 - inv_sign); +} + +// assumes inputs are <2**128 +func uint128_add{range_check_ptr}(a: felt, b: felt) -> (result: Uint256) { + alloc_locals; + local carry: felt; + %{ + res = ids.a + ids.b + ids.carry = 1 if res >= ids.SHIFT else 0 + %} + // Either 0 or 1 + assert carry * carry = carry; + local res = a + b - carry * SHIFT; + [range_check_ptr] = res; + let range_check_ptr = range_check_ptr + 1; + + return (result=Uint256(low=res, high=carry)); +} + +// assumes inputs are <2**128 +func uint128_mul{range_check_ptr}(a: felt, b: felt) -> (result: Uint256) { + let (a0, a1) = split_64(a); + let (b0, b1) = split_64(b); + + let (res0, carry) = split_128(a1 * b0 * HALF_SHIFT + a0 * b); + // let (res2, carry) = split_64(a1 * b1 + carry); + + return (result=Uint256(low=res0, high=a1 * b1 + carry)); +} + +// assumes input is <2**128 +func uint128_square{range_check_ptr}(a: felt) -> (result: Uint256) { + let (a0, a1) = split_64(a); + + let (res0, carry) = split_128(a0 * (a + a1 * HALF_SHIFT)); + // let (res2, carry) = split_64(a1 * a1 + carry); + + return (result=Uint256(low=res0, high=a1 * a1 + carry)); +} + +// a series of overlapping 128-bit sections of a Uint256. +// for use in uint128_mul_expanded and uint128_unsigned_div_rem_expanded +struct Uint256_expand { + B0: felt, + b01: felt, + b12: felt, + b23: felt, + b3: felt, +} + +// expands a Uint256 into a Uint256_expand +func uint256_expand{range_check_ptr}(a: Uint256) -> (exp: Uint256_expand) { + let (a0, a1) = split_64(a.low); + let (a2, a3) = split_64(a.high); + + return (exp=Uint256_expand(a0 * HALF_SHIFT, a.low, a1 + a2 * HALF_SHIFT, a.high, a3)); +} + +func uint256_mul_expanded{range_check_ptr}(a: Uint256, b: Uint256_expand) -> ( + low: Uint256, high: Uint256 +) { + let (a0, a1) = split_64(a.low); + let (a2, a3) = split_64(a.high); + + let (res0, carry) = split_128(a1 * b.B0 + a0 * b.b01); + let (res2, carry) = split_128(a3 * b.B0 + a2 * b.b01 + a1 * b.b12 + a0 * b.b23 + carry); + let (res4, carry) = split_128(a3 * b.b12 + a2 * b.b23 + a1 * b.b3 + carry); + // let (res6, carry) = split_64(a3 * b.b3 + carry); + + return (low=Uint256(low=res0, high=res2), high=Uint256(low=res4, high=a3 * b.b3 + carry)); +} + +func uint256_unsigned_div_rem_expanded{range_check_ptr}(a: Uint256, div: Uint256_expand) -> ( + quotient: Uint256, remainder: Uint256 +) { + alloc_locals; + + // Guess the quotient and the remainder. + local quotient: Uint256; + local remainder: Uint256; + %{ + a = (ids.a.high << 128) + ids.a.low + div = (ids.div.b23 << 128) + ids.div.b01 + quotient, remainder = divmod(a, div) + + ids.quotient.low = quotient & ((1 << 128) - 1) + ids.quotient.high = quotient >> 128 + ids.remainder.low = remainder & ((1 << 128) - 1) + ids.remainder.high = remainder >> 128 + %} + uint256_check(quotient); + uint256_check(remainder); + let (res_mul, carry) = uint256_mul_expanded(quotient, div); + assert carry = Uint256(0, 0); + + let (check_val, add_carry) = _uint256_add_no_uint256_check(res_mul, remainder); + assert check_val = a; + assert add_carry = 0; + + let (is_valid) = uint256_lt(remainder, Uint256(div.b01, div.b23)); + assert is_valid = 1; + return (quotient=quotient, remainder=remainder); +} + +func test_udiv_expanded{range_check_ptr}() { + let (a_div_expanded) = uint256_expand(Uint256(3, 7)); + let (a_quotient, a_remainder) = uint256_unsigned_div_rem_expanded( + Uint256(89, 72), a_div_expanded + ); + assert a_quotient = Uint256(10, 0); + assert a_remainder = Uint256(59, 2); + + let (b_div_expanded) = uint256_expand(Uint256(5, 2)); + let (b_quotient, b_remainder) = uint256_unsigned_div_rem_expanded( + Uint256(-3618502788666131213697322783095070105282824848410658236509717448704103809099, 2), + b_div_expanded, + ); + assert b_quotient = Uint256(1, 0); + assert b_remainder = Uint256(340282366920938463463374607431768211377, 0); + + let (c_div_expanded) = uint256_expand(Uint256(1, 0)); + + let (c_quotient, c_remainder) = uint256_unsigned_div_rem_expanded( + Uint256(340282366920938463463374607431768211455, 340282366920938463463374607431768211455), + c_div_expanded, + ); + + assert c_quotient = Uint256(340282366920938463463374607431768211455, 340282366920938463463374607431768211455); + assert c_remainder = Uint256(0, 0); + return (); +} + +func test_uint256_sub{range_check_ptr}() { + let x = Uint256(421, 5135); + let y = Uint256(787, 968); + + // Compute x - y + let (res, sign) = uint256_sub(x, y); + + assert res = Uint256(340282366920938463463374607431768211090, 4166); + // x - y >= 0 + assert sign = 1; + + // Compute y - x + let (res, sign) = uint256_sub(y, x); + + assert res = Uint256(366, 340282366920938463463374607431768207289); + // y - x < 0 + assert sign = 0; + + return (); +} + +func test_uint128_add{range_check_ptr}() { + let (res) = uint128_add(5, 66); + + assert res = Uint256(71, 0); + + let (res) = uint128_add( + 340282366920938463463374607431768211455, 340282366920938463463374607431768211455 + ); + + assert res = Uint256(340282366920938463463374607431768211454, 1); + + return (); +} + +func test_uint256_sqrt{range_check_ptr}() { + let n = Uint256(8, 0); + + let (res) = uint256_sqrt(n); + + assert res = Uint256(2, 0); + + let n = Uint256( + 340282366920938463463374607431768211455, 21267647932558653966460912964485513215 + ); + + let (res) = uint256_sqrt(n); + + assert res = Uint256(85070591730234615865843651857942052863, 0); + + return (); +} + +func main{range_check_ptr}() { + test_udiv_expanded(); + test_uint256_sub(); + test_uint128_add(); + test_uint256_sqrt(); + + return (); +} diff --git a/pkg/hints/hint_codes/uint384_hint_codes.go b/pkg/hints/hint_codes/uint384_hint_codes.go new file mode 100644 index 00000000..35908067 --- /dev/null +++ b/pkg/hints/hint_codes/uint384_hint_codes.go @@ -0,0 +1,4 @@ +package hint_codes + +const UINT384_SPLIT_128 = `ids.low = ids.a & ((1<<128) - 1) +ids.high = ids.a >> 128` diff --git a/pkg/hints/uint384_hints.go b/pkg/hints/uint384_hints.go new file mode 100644 index 00000000..161f4a37 --- /dev/null +++ b/pkg/hints/uint384_hints.go @@ -0,0 +1,30 @@ +package hints + +import ( + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" +) + +/* +Implements Hint: + + %{ + ids.low = ids.a & ((1<<128) - 1) + ids.high = ids.a >> 128 + %} +*/ +func uint384Split128(ids IdsManager, vm *VirtualMachine) error { + a, err := ids.GetFelt("a", vm) + if err != nil { + return err + } + low := a.And(FeltFromDecString("340282366920938463463374607431768211455")) + err = ids.Insert("low", NewMaybeRelocatableFelt(low), vm) + if err != nil { + return err + } + high := a.Shr(128) + return ids.Insert("high", NewMaybeRelocatableFelt(high), vm) +} diff --git a/pkg/hints/uint384_hints_test.go b/pkg/hints/uint384_hints_test.go new file mode 100644 index 00000000..a21420aa --- /dev/null +++ b/pkg/hints/uint384_hints_test.go @@ -0,0 +1 @@ +package hints_test