Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cairo0 hint pow #306

Merged
merged 9 commits into from
Mar 29, 2024
15 changes: 15 additions & 0 deletions integration_tests/cairo_files/pow.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
%builtins range_check

from starkware.cairo.common.pow import pow

func main{range_check_ptr: felt}() {
let (x) = pow(5, 3);
assert x = 125;
let (x) = pow(4, 3);
assert x = 64;
let (x) = pow(2, 10);
assert x = 1024;
let (y) = pow(x, 2);
assert x = 1048576;
return ();
}
7 changes: 1 addition & 6 deletions pkg/hintrunner/hinter/operand.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,7 @@ func (v Immediate) ApplyApTracking(hint, ref zero.ApTracking) Reference {
return v
}

func GetConsecutiveValues(vm *VM.VirtualMachine, ref ResOperander, size int16) ([]mem.MemoryValue, error) {
addr, err := ref.GetAddress(vm)
if err != nil {
return nil, err
}

func GetConsecutiveValues(vm *VM.VirtualMachine, addr mem.MemoryAddress, size int16) ([]mem.MemoryValue, error) {
values := make([]mem.MemoryValue, size)
for i := int16(0); i < size; i++ {
nAddr, err := addr.AddOffset(i)
Expand Down
12 changes: 12 additions & 0 deletions pkg/hintrunner/zero/hint_reference_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ func (m *hintReferenceResolver) GetResOperander(name string) (hinter.ResOperande
return op, nil
}

func (m *hintReferenceResolver) GetCellRefer(name string) (hinter.CellRefer, error) {
ref, err := m.GetReference(name)
if err != nil {
return nil, err
}
op, ok := ref.(hinter.CellRefer)
if !ok {
return nil, fmt.Errorf("expected %s to be CellRefer (got %T)", name, ref)
}
return op, nil
}

// shortSymbolName turns a full symbol name like "a.b.c" into just "c".
func shortSymbolName(name string) string {
i := strings.LastIndexByte(name, '.')
Expand Down
3 changes: 3 additions & 0 deletions pkg/hintrunner/zero/hintcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ const (
splitIntAssertRange string = "assert ids.value == 0, 'split_int(): value is out of range.'"
splitIntCode string = "memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base\nassert res < ids.bound, f'split_int(): Limb {res} is out of range.'"

// pow hints
powCode string = "ids.locs.bit = (ids.prev_locs.exp % PRIME) & 1"

unsignedDivRemCode string = "from starkware.cairo.common.math_utils import assert_integer\nassert_integer(ids.div)\nassert 0 < ids.div <= PRIME // range_check_builtin.bound, \\\n f'div={hex(ids.div)} is out of the valid range.'\nids.q, ids.r = divmod(ids.value, ids.div)"

// split_felt() hints.
Expand Down
2 changes: 2 additions & 0 deletions pkg/hintrunner/zero/zerohint.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ func GetHintFromCode(program *zero.ZeroProgram, rawHint zero.Hint, hintPC uint64
return createSplitIntAssertRangeHinter(resolver)
case splitIntCode:
return createSplitIntHinter(resolver)
case powCode:
return createPowHinter(resolver)
case uint256AddCode:
return createUint256AddHinter(resolver, false)
case uint256AddLowCode:
Expand Down
55 changes: 53 additions & 2 deletions pkg/hintrunner/zero/zerohint_math.go
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,59 @@ func createSplitIntHinter(resolver hintReferenceResolver) (hinter.Hinter, error)
return newSplitIntHint(output, value, base, bound), nil
}

func newPowHint(locs, prevLocs hinter.ResOperander) hinter.Hinter {
return &GenericZeroHinter{
Name: "Pow",
Op: func(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error {
//> ids.locs.bit = (ids.prev_locs.exp % PRIME) & 1
/*> struct LoopLocals {
bit: felt,
temp0: felt,

res: felt,
base: felt,
exp: felt,
} */
const expStructOffset = 4
locsBitAddress, err := locs.GetAddress(vm)
if err != nil {
return err
}
prevLocsBitAddress, err := prevLocs.GetAddress(vm)
if err != nil {
return err
}
loopLocals, err := hinter.GetConsecutiveValues(vm, prevLocsBitAddress, expStructOffset+1)
if err != nil {
return err
}
prevLocsExp, err := loopLocals[expStructOffset].FieldElement()
if err != nil {
return err
}
var prevLocsExpBig big.Int
prevLocsExp.BigInt(&prevLocsExpBig)
locsBitBig := new(big.Int).And(&prevLocsExpBig, big.NewInt(1))
v := memory.MemoryValueFromFieldElement(new(fp.Element).SetBigInt(locsBitBig))
return vm.Memory.WriteToAddress(&locsBitAddress, &v)
},
}
}

func createPowHinter(resolver hintReferenceResolver) (hinter.Hinter, error) {
locs, err := resolver.GetCellRefer("locs")
if err != nil {
return nil, err
}
prev_locs, err := resolver.GetCellRefer("prev_locs")
if err != nil {
return nil, err
}
locsRes := hinter.Deref{Deref: locs}
prevLocsRes := hinter.Deref{Deref: prev_locs}
return newPowHint(locsRes, prevLocsRes), nil
cicr99 marked this conversation as resolved.
Show resolved Hide resolved
}

func newSplitFeltHint(low, high, value hinter.ResOperander) hinter.Hinter {
return &GenericZeroHinter{
Name: "SplitFelt",
Expand Down Expand Up @@ -622,7 +675,6 @@ func newSqrtHint(root, value hinter.ResOperander) hinter.Hinter {
}

func createSqrtHinter(resolver hintReferenceResolver) (hinter.Hinter, error) {

root, err := resolver.GetResOperander("root")
if err != nil {
return nil, err
Expand Down Expand Up @@ -703,6 +755,5 @@ func createUnsignedDivRemHinter(resolver hintReferenceResolver) (hinter.Hinter,
if err != nil {
return nil, err
}

return newUnsignedDivRemHinter(value, div, q, r), nil
}
35 changes: 34 additions & 1 deletion pkg/hintrunner/zero/zerohint_math_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,40 @@ func TestZeroHintMath(t *testing.T) {
errCheck: errorTextContains("outside of the range [0, 2**250)"),
},
},

"Pow": {
{
operanders: []*hintOperander{
{Name: "prev_locs.bit", Kind: apRelative, Value: feltInt64(0)},
{Name: "prev_locs.temp0", Kind: apRelative, Value: feltInt64(0)},
{Name: "prev_locs.res", Kind: apRelative, Value: feltInt64(0)},
{Name: "prev_locs.base", Kind: apRelative, Value: feltInt64(0)},
{Name: "prev_locs.exp", Kind: apRelative, Value: feltInt64(256)},
{Name: "locs.bit", Kind: uninitialized},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newPowHint(ctx.operanders["locs.bit"], ctx.operanders["prev_locs.bit"])
},
check: allVarValueEquals(map[string]*fp.Element{
"locs.bit": feltInt64(0),
}),
},
{
operanders: []*hintOperander{
{Name: "prev_locs.bit", Kind: apRelative, Value: feltInt64(0)},
{Name: "prev_locs.temp0", Kind: apRelative, Value: feltInt64(0)},
{Name: "prev_locs.res", Kind: apRelative, Value: feltInt64(0)},
{Name: "prev_locs.base", Kind: apRelative, Value: feltInt64(0)},
{Name: "prev_locs.exp", Kind: apRelative, Value: feltInt64(255)},
{Name: "locs.bit", Kind: uninitialized},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newPowHint(ctx.operanders["locs.bit"], ctx.operanders["prev_locs.bit"])
},
check: allVarValueEquals(map[string]*fp.Element{
"locs.bit": feltInt64(1),
}),
},
},
"SplitFelt": {
{
operanders: []*hintOperander{
Expand Down
7 changes: 6 additions & 1 deletion pkg/hintrunner/zero/zerohint_uint256.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ import (
)

func GetUint256AsFelts(vm *VM.VirtualMachine, ref hinter.ResOperander) (*fp.Element, *fp.Element, error) {
values, err := hinter.GetConsecutiveValues(vm, ref, int16(2))
refAddr, err := ref.GetAddress(vm)
if err != nil {
return nil, nil, err
}

values, err := hinter.GetConsecutiveValues(vm, refAddr, int16(2))
if err != nil {
return nil, nil, err
}
Expand Down