diff --git a/pkg/hintrunner/zero/hintcode.go b/pkg/hintrunner/zero/hintcode.go index 220102762..2fd6f5b30 100644 --- a/pkg/hintrunner/zero/hintcode.go +++ b/pkg/hintrunner/zero/hintcode.go @@ -37,6 +37,9 @@ const ( // split_felt() hints. splitFeltCode string = "from starkware.cairo.common.math_utils import assert_integer\nassert ids.MAX_HIGH < 2**128 and ids.MAX_LOW < 2**128\nassert PRIME - 1 == ids.MAX_HIGH * 2**128 + ids.MAX_LOW\nassert_integer(ids.value)\nids.low = ids.value & ((1 << 128) - 1)\nids.high = ids.value >> 128" + // sqrt() hint + sqrtCode string = "from starkware.python.math_utils import isqrt\nvalue = ids.value % PRIME\nassert value < 2 ** 250, f\"value={value} is outside of the range [0, 2**250).\"\nassert 2 ** 250 < PRIME\nids.root = isqrt(value)" + // ------ Uint256 hints related code ------ uint256AddCode string = "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" uint256AddLowCode string = "sum_low = ids.a.low + ids.b.low\nids.carry_low = 1 if sum_low >= ids.SHIFT else 0" diff --git a/pkg/hintrunner/zero/zerohint.go b/pkg/hintrunner/zero/zerohint.go index 06941162a..d2a2d8e53 100644 --- a/pkg/hintrunner/zero/zerohint.go +++ b/pkg/hintrunner/zero/zerohint.go @@ -102,6 +102,8 @@ func GetHintFromCode(program *zero.ZeroProgram, rawHint zero.Hint, hintPC uint64 return createUint256SqrtHinter(resolver) case uint256MulDivModCode: return createUint256MulDivModHinter(resolver) + case sqrtCode: + return createSqrtHinter(resolver) default: return nil, fmt.Errorf("Not identified hint") } diff --git a/pkg/hintrunner/zero/zerohint_math.go b/pkg/hintrunner/zero/zerohint_math.go index 04e046bfc..0587f08f8 100644 --- a/pkg/hintrunner/zero/zerohint_math.go +++ b/pkg/hintrunner/zero/zerohint_math.go @@ -4,6 +4,8 @@ import ( "fmt" "math/big" + "github.com/holiman/uint256" + "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/core" "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter" "github.com/NethermindEth/cairo-vm-go/pkg/utils" @@ -581,3 +583,53 @@ func createSplitFeltHinter(resolver hintReferenceResolver) (hinter.Hinter, error return newSplitFeltHint(low, high, value), nil } + +func newSqrtHint(root, value hinter.ResOperander) hinter.Hinter { + return &GenericZeroHinter{ + Name: "Sqrt", + Op: func(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error { + //> from starkware.python.math_utils import isqrt + // value = ids.value % PRIME + // assert value < 2 ** 250, f"value={value} is outside of the range [0, 2**250)." + // assert 2 ** 250 < PRIME + // ids.root = isqrt(value) + + rootAddr, err := root.GetAddress(vm) + if err != nil { + return err + } + + value, err := hinter.ResolveAsFelt(vm, value) + if err != nil { + return err + } + + if !utils.FeltLt(value, &utils.FeltUpperBound) { + return fmt.Errorf("assertion failed: %v is outside of the range [0, 2**250)", value) + } + + // Conversion needed to handle non-square values + valueU256 := uint256.Int(value.Bits()) + valueU256.Sqrt(&valueU256) + + result := fp.Element{} + result.SetBytes(valueU256.Bytes()) + + v := memory.MemoryValueFromFieldElement(&result) + return vm.Memory.WriteToAddress(&rootAddr, &v) + }, + } +} + +func createSqrtHinter(resolver hintReferenceResolver) (hinter.Hinter, error) { + + root, err := resolver.GetResOperander("root") + if err != nil { + return nil, err + } + value, err := resolver.GetResOperander("value") + if err != nil { + return nil, err + } + return newSqrtHint(root, value), nil +} diff --git a/pkg/hintrunner/zero/zerohint_math_test.go b/pkg/hintrunner/zero/zerohint_math_test.go index 1d25db04f..475fad0b4 100644 --- a/pkg/hintrunner/zero/zerohint_math_test.go +++ b/pkg/hintrunner/zero/zerohint_math_test.go @@ -586,5 +586,48 @@ func TestZeroHintMath(t *testing.T) { }), }, }, + + "SqrtHint": { + { + operanders: []*hintOperander{ + {Name: "root", Kind: uninitialized}, + {Name: "value", Kind: fpRelative, Value: feltInt64(25)}, + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newSqrtHint(ctx.operanders["root"], ctx.operanders["value"]) + }, + check: varValueEquals("root", feltInt64(5)), + }, + { + operanders: []*hintOperander{ + {Name: "root", Kind: uninitialized}, + {Name: "value", Kind: fpRelative, Value: feltInt64(0)}, + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newSqrtHint(ctx.operanders["root"], ctx.operanders["value"]) + }, + check: varValueEquals("root", feltInt64(0)), + }, + { + operanders: []*hintOperander{ + {Name: "root", Kind: uninitialized}, + {Name: "value", Kind: fpRelative, Value: feltInt64(50)}, + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newSqrtHint(ctx.operanders["root"], ctx.operanders["value"]) + }, + check: varValueEquals("root", feltInt64(7)), + }, + { + operanders: []*hintOperander{ + {Name: "root", Kind: uninitialized}, + {Name: "value", Kind: fpRelative, Value: feltInt64(-128)}, + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newSqrtHint(ctx.operanders["root"], ctx.operanders["value"]) + }, + errCheck: errorTextContains("outside of the range [0, 2**250)"), + }, + }, }) } diff --git a/pkg/hintrunner/zero/zerohint_uint256.go b/pkg/hintrunner/zero/zerohint_uint256.go index b14dd6b3e..353bb6179 100644 --- a/pkg/hintrunner/zero/zerohint_uint256.go +++ b/pkg/hintrunner/zero/zerohint_uint256.go @@ -259,9 +259,8 @@ func newUint256SignedNNHint(a hinter.ResOperander) hinter.Hinter { return err } var v memory.MemoryValue - felt127 := new(fp.Element).SetBigInt(new(big.Int).Lsh(big.NewInt(1), 127)) - if utils.FeltLt(aHigh, felt127) { + if utils.FeltLt(aHigh, &utils.Felt127) { v = memory.MemoryValueFromFieldElement(&utils.FeltOne) } else { v = memory.MemoryValueFromFieldElement(&utils.FeltZero) diff --git a/pkg/hintrunner/zero/zerohint_uint256_test.go b/pkg/hintrunner/zero/zerohint_uint256_test.go index c44c9d5e0..e784171f3 100644 --- a/pkg/hintrunner/zero/zerohint_uint256_test.go +++ b/pkg/hintrunner/zero/zerohint_uint256_test.go @@ -1,7 +1,6 @@ package zero import ( - "math/big" "testing" "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter" @@ -10,17 +9,13 @@ import ( ) func TestZeroHintUint256(t *testing.T) { - // Values used in the test cases - // 1 << 127 - felt127 := new(fp.Element).SetBigInt(new(big.Int).Lsh(big.NewInt(1), 127)) - runHinterTests(t, map[string][]hintTestCase{ "Uint256Add": { { operanders: []*hintOperander{ - {Name: "a.low", Kind: fpRelative, Value: felt127}, + {Name: "a.low", Kind: fpRelative, Value: &utils.Felt127}, {Name: "a.high", Kind: fpRelative, Value: feltUint64(0)}, - {Name: "b.low", Kind: apRelative, Value: felt127}, + {Name: "b.low", Kind: apRelative, Value: &utils.Felt127}, {Name: "b.high", Kind: apRelative, Value: feltUint64(0)}, {Name: "carry_low", Kind: uninitialized}, {Name: "carry_high", Kind: uninitialized}, @@ -35,10 +30,10 @@ func TestZeroHintUint256(t *testing.T) { }, { operanders: []*hintOperander{ - {Name: "a.low", Kind: fpRelative, Value: felt127}, - {Name: "a.high", Kind: fpRelative, Value: felt127}, - {Name: "b.low", Kind: apRelative, Value: felt127}, - {Name: "b.high", Kind: apRelative, Value: felt127}, + {Name: "a.low", Kind: fpRelative, Value: &utils.Felt127}, + {Name: "a.high", Kind: fpRelative, Value: &utils.Felt127}, + {Name: "b.low", Kind: apRelative, Value: &utils.Felt127}, + {Name: "b.high", Kind: apRelative, Value: &utils.Felt127}, {Name: "carry_low", Kind: uninitialized}, {Name: "carry_high", Kind: uninitialized}, }, @@ -53,9 +48,9 @@ func TestZeroHintUint256(t *testing.T) { { operanders: []*hintOperander{ {Name: "a.low", Kind: fpRelative, Value: feltUint64(0)}, - {Name: "a.high", Kind: fpRelative, Value: felt127}, + {Name: "a.high", Kind: fpRelative, Value: &utils.Felt127}, {Name: "b.low", Kind: apRelative, Value: feltUint64(0)}, - {Name: "b.high", Kind: apRelative, Value: felt127}, + {Name: "b.high", Kind: apRelative, Value: &utils.Felt127}, {Name: "carry_low", Kind: uninitialized}, {Name: "carry_high", Kind: uninitialized}, }, @@ -69,10 +64,10 @@ func TestZeroHintUint256(t *testing.T) { }, { operanders: []*hintOperander{ - {Name: "a.low", Kind: fpRelative, Value: felt127}, + {Name: "a.low", Kind: fpRelative, Value: &utils.Felt127}, {Name: "a.high", Kind: fpRelative, Value: feltUint64(0)}, {Name: "b.low", Kind: apRelative, Value: feltUint64(0)}, - {Name: "b.high", Kind: apRelative, Value: felt127}, + {Name: "b.high", Kind: apRelative, Value: &utils.Felt127}, {Name: "carry_low", Kind: uninitialized}, {Name: "carry_high", Kind: uninitialized}, }, @@ -104,7 +99,7 @@ func TestZeroHintUint256(t *testing.T) { // `low` is zero { operanders: []*hintOperander{ - {Name: "a", Kind: fpRelative, Value: felt127}, + {Name: "a", Kind: fpRelative, Value: &utils.Felt127}, {Name: "low", Kind: uninitialized}, {Name: "high", Kind: uninitialized}, }, @@ -180,8 +175,8 @@ func TestZeroHintUint256(t *testing.T) { }, { operanders: []*hintOperander{ - {Name: "n.low", Kind: fpRelative, Value: felt127}, - {Name: "n.high", Kind: fpRelative, Value: felt127}, + {Name: "n.low", Kind: fpRelative, Value: &utils.Felt127}, + {Name: "n.high", Kind: fpRelative, Value: &utils.Felt127}, {Name: "root.low", Kind: uninitialized}, {Name: "root.high", Kind: uninitialized}, }, @@ -198,7 +193,7 @@ func TestZeroHintUint256(t *testing.T) { { operanders: []*hintOperander{ {Name: "a.low", Kind: fpRelative, Value: feltUint64(0)}, - {Name: "a.high", Kind: fpRelative, Value: felt127}, + {Name: "a.high", Kind: fpRelative, Value: &utils.Felt127}, }, makeHinter: func(ctx *hintTestContext) hinter.Hinter { return newUint256SignedNNHint(ctx.operanders["a.low"]) @@ -240,9 +235,9 @@ func TestZeroHintUint256(t *testing.T) { }, { operanders: []*hintOperander{ - {Name: "a.low", Kind: fpRelative, Value: felt127}, + {Name: "a.low", Kind: fpRelative, Value: &utils.Felt127}, {Name: "a.high", Kind: fpRelative, Value: feltUint64(0)}, - {Name: "div.low", Kind: fpRelative, Value: felt127}, + {Name: "div.low", Kind: fpRelative, Value: &utils.Felt127}, {Name: "div.high", Kind: fpRelative, Value: feltUint64(0)}, {Name: "quotient.low", Kind: uninitialized}, {Name: "quotient.high", Kind: uninitialized}, @@ -262,9 +257,9 @@ func TestZeroHintUint256(t *testing.T) { { operanders: []*hintOperander{ {Name: "a.low", Kind: fpRelative, Value: feltUint64(5)}, - {Name: "a.high", Kind: fpRelative, Value: felt127}, + {Name: "a.high", Kind: fpRelative, Value: &utils.Felt127}, {Name: "div.low", Kind: fpRelative, Value: feltUint64(0)}, - {Name: "div.high", Kind: fpRelative, Value: felt127}, + {Name: "div.high", Kind: fpRelative, Value: &utils.Felt127}, {Name: "quotient.low", Kind: uninitialized}, {Name: "quotient.high", Kind: uninitialized}, {Name: "remainder.low", Kind: uninitialized}, diff --git a/pkg/utils/constant.go b/pkg/utils/constant.go index 1216d53f1..0202a2969 100644 --- a/pkg/utils/constant.go +++ b/pkg/utils/constant.go @@ -15,6 +15,10 @@ var FeltOne = fp.Element{ 18446744073709551585, 18446744073709551615, 18446744073709551615, 576460752303422960, } +// 1 << 127 +// same as 2 ** 127 +var Felt127 = fp.Element{18446744073704816641, 8703, 18446744073709551600, 576460752222928912} + // 1 << 128 // same as 2 ** 128 var FeltMax128 = fp.Element{18446744073700081665, 17407, 18446744073709551584, 576460752142434320}