Skip to content

Commit

Permalink
SplitOutput0 hint (#509)
Browse files Browse the repository at this point in the history
* SplitOutput0

* fmt

* fmt

* add tests

---------

Co-authored-by: Shourya Goel <[email protected]>
  • Loading branch information
TAdev0 and Sh0g0-1758 authored Jul 4, 2024
1 parent 312d061 commit 420549c
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 0 deletions.
1 change: 1 addition & 0 deletions pkg/hintrunner/zero/hintcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ ids.multiplicities = segments.gen_arg([len(positions_dict[k]) for k in output])`
splitInput12Code string = "ids.high12, ids.low12 = divmod(memory[ids.inputs + 12], 256 ** 4)"
splitInput15Code string = "ids.high15, ids.low15 = divmod(memory[ids.inputs + 15], 256 ** 5)"
splitOutputMidLowHighCode string = "tmp, ids.output1_low = divmod(ids.output1, 256 ** 7)\nids.output1_high, ids.output1_mid = divmod(tmp, 2 ** 128)"
splitOutput0Code string = "ids.output0_low = ids.output0 & ((1 << 128) - 1)\nids.output0_high = ids.output0 >> 128"
SplitNBytesCode string = "ids.n_words_to_copy, ids.n_bytes_left = divmod(ids.n_bytes, ids.BYTES_IN_WORD)"

// ------ Dictionaries hints related code ------
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 @@ -187,6 +187,8 @@ func GetHintFromCode(program *zero.ZeroProgram, rawHint zero.Hint, hintPC uint64
return createSplitInput15Hinter(resolver)
case splitOutputMidLowHighCode:
return createSplitOutputMidLowHighHinter(resolver)
case splitOutput0Code:
return createSplitOutput0Hinter(resolver)
case SplitNBytesCode:
return createSplitNBytesHinter(resolver)
// Usort hints
Expand Down
75 changes: 75 additions & 0 deletions pkg/hintrunner/zero/zerohint_keccak.go
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,81 @@ func createSplitOutputMidLowHighHinter(resolver hintReferenceResolver) (hinter.H
return newSplitOutputMidLowHighHint(output1, output1Low, output1Mid, output1High), nil
}

// SplitOutput0 hint splits `output0` into `output0_low` (16 bytes) and `output0_high` (9 bytes)
//
// `newSplitOutput0Hint` takes 3 operanders as arguments
// - `output0_low` is the variable that will store the low part of `output0`
// - `output0_high` is the variable that will store the high part of `output0`
// - `output0` is the value to split
func newSplitOutput0Hint(output0Low, output0High, output0 hinter.ResOperander) hinter.Hinter {
return &GenericZeroHinter{
Name: "SplitOutput0",
Op: func(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error {
//> ids.output0_low = ids.output0 & ((1 << 128) - 1)
//> ids.output0_high = ids.output0 >> 128

output0LowAddr, err := output0Low.GetAddress(vm)
if err != nil {
return err
}

output0HighAddr, err := output0High.GetAddress(vm)
if err != nil {
return err
}

output0, err := hinter.ResolveAsFelt(vm, output0)
if err != nil {
return err
}

output0Uint := uint256.Int(output0.Bits())

var output0Low uint256.Int
mask := new(uint256.Int).Lsh(uint256.NewInt(1), 128)
mask.Sub(mask, uint256.NewInt(1))
output0Low.And(&output0Uint, mask)
output0LowBytes := output0Low.Bytes()
output0LowFelt := fp.Element{}
output0LowFelt.SetBytes(output0LowBytes)
output0LowMv := memory.MemoryValueFromFieldElement(&output0LowFelt)

var output0High uint256.Int
output0High.Rsh(&output0Uint, 128)
output0HighBytes := output0High.Bytes()
output0HighFelt := fp.Element{}
output0HighFelt.SetBytes(output0HighBytes)
output0HighMv := memory.MemoryValueFromFieldElement(&output0HighFelt)

err = vm.Memory.WriteToAddress(&output0LowAddr, &output0LowMv)
if err != nil {
return err
}

return vm.Memory.WriteToAddress(&output0HighAddr, &output0HighMv)
},
}
}

func createSplitOutput0Hinter(resolver hintReferenceResolver) (hinter.Hinter, error) {
output0Low, err := resolver.GetResOperander("output0_low")
if err != nil {
return nil, err
}

output0High, err := resolver.GetResOperander("output0_high")
if err != nil {
return nil, err
}

output0, err := resolver.GetResOperander("output0")
if err != nil {
return nil, err
}

return newSplitOutput0Hint(output0Low, output0High, output0), nil
}

// SplitNBytes hint assigns to `ids.n_words_to_copy` and `ids.n_bytes_left` variables
// the quotient and remainder of the division of `ids.n_bytes` variable by the
// variable `ids.BYTES_IN_WORD`
Expand Down
46 changes: 46 additions & 0 deletions pkg/hintrunner/zero/zerohint_keccak_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1220,5 +1220,51 @@ func TestZeroHintKeccak(t *testing.T) {
check: allVarValueEquals(map[string]*fp.Element{"high9": feltUint64(10), "low9": feltUint64(1)}),
},
},
"SplitOutput0": {
{
operanders: []*hintOperander{
{Name: "output0", Kind: apRelative, Value: feltUint64(0)},
{Name: "output0_low", Kind: uninitialized},
{Name: "output0_high", Kind: uninitialized},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newSplitOutput0Hint(ctx.operanders["output0_low"], ctx.operanders["output0_high"], ctx.operanders["output0"])
},
check: allVarValueEquals(map[string]*fp.Element{"output0_low": feltUint64(0), "output0_high": feltUint64(0)}),
},
{
operanders: []*hintOperander{
{Name: "output0", Kind: apRelative, Value: feltUint64(1)},
{Name: "output0_low", Kind: uninitialized},
{Name: "output0_high", Kind: uninitialized},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newSplitOutput0Hint(ctx.operanders["output0_low"], ctx.operanders["output0_high"], ctx.operanders["output0"])
},
check: allVarValueEquals(map[string]*fp.Element{"output0_low": feltUint64(1), "output0_high": feltUint64(0)}),
},
{
operanders: []*hintOperander{
{Name: "output0", Kind: apRelative, Value: feltString("340282366920938463463374607431768211455")},
{Name: "output0_low", Kind: uninitialized},
{Name: "output0_high", Kind: uninitialized},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newSplitOutput0Hint(ctx.operanders["output0_low"], ctx.operanders["output0_high"], ctx.operanders["output0"])
},
check: allVarValueEquals(map[string]*fp.Element{"output0_low": feltString("340282366920938463463374607431768211455"), "output0_high": feltString("0")}),
},
{
operanders: []*hintOperander{
{Name: "output0", Kind: apRelative, Value: feltString("340282366920938463463374607431768211456")},
{Name: "output0_low", Kind: uninitialized},
{Name: "output0_high", Kind: uninitialized},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newSplitOutput0Hint(ctx.operanders["output0_low"], ctx.operanders["output0_high"], ctx.operanders["output0"])
},
check: allVarValueEquals(map[string]*fp.Element{"output0_low": feltString("0"), "output0_high": feltString("1")}),
},
},
})
}

0 comments on commit 420549c

Please sign in to comment.