Skip to content

Commit

Permalink
SplitNBytesCode hint (#510)
Browse files Browse the repository at this point in the history
* Implemented hint

* Bug Fix

* Added some more tests

* nit

* Resolved merge conflict
  • Loading branch information
Sh0g0-1758 committed Jul 3, 2024
1 parent 27817ff commit 00f0205
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 4 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])`
compareBytesInWordCode string = "memory[ap] = to_felt_or_relocatable(ids.n_bytes < ids.BYTES_IN_WORD)"
compareKeccakFullRateInBytesCode string = "memory[ap] = to_felt_or_relocatable(ids.n_bytes >= ids.KECCAK_FULL_RATE_IN_BYTES)"
splitOutputMidLowHighCode string = "tmp, ids.output1_low = divmod(ids.output1, 256 ** 7)\nids.output1_high, ids.output1_mid = divmod(tmp, 2 ** 128)"
SplitNBytesCode string = "ids.n_words_to_copy, ids.n_bytes_left = divmod(ids.n_bytes, ids.BYTES_IN_WORD)"

// ------ Dictionaries hints related code ------
dictNewCode string = "if '__dict_manager' not in globals():\n from starkware.cairo.common.dict import DictManager\n __dict_manager = DictManager()\n\nmemory[ap] = __dict_manager.new_dict(segments, initial_dict)\ndel initial_dict"
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 @@ -175,6 +175,8 @@ func GetHintFromCode(program *zero.ZeroProgram, rawHint zero.Hint, hintPC uint64
return createCompareBytesInWordNondetHinter(resolver)
case splitOutputMidLowHighCode:
return createSplitOutputMidLowHighHinter(resolver)
case SplitNBytesCode:
return createSplitNBytesHinter(resolver)
// Usort hints
case usortEnterScopeCode:
return createUsortEnterScopeHinter()
Expand Down
83 changes: 79 additions & 4 deletions pkg/hintrunner/zero/zerohint_keccak.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,8 @@ func createUnsafeKeccakFinalizeHinter(resolver hintReferenceResolver) (hinter.Hi
// - `low` is the low part of the `uint256` argument for the Keccac function
// - `high` is the high part of the `uint256` argument for the Keccac function
func newKeccakWriteArgsHint(inputs, low, high hinter.ResOperander) hinter.Hinter {
name := "KeccakWriteArgs"
return &GenericZeroHinter{
Name: name,
Name: "KeccakWriteArgs",
Op: func(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error {
//> segments.write_arg(ids.inputs, [ids.low % 2 ** 64, ids.low // 2 ** 64])
//> segments.write_arg(ids.inputs + 2, [ids.high % 2 ** 64, ids.high // 2 ** 64])
Expand Down Expand Up @@ -460,9 +459,8 @@ func createCompareKeccakFullRateInBytesNondetHinter(resolver hintReferenceResolv
// `newBlockPermutationHint` reads 25 memory cells starting from `keccakPtr - 25`, and writes
// the result of the Keccak block permutation in the next 25 memory cells, starting from `keccakPtr`
func newBlockPermutationHint(keccakPtr hinter.ResOperander) hinter.Hinter {
name := "BlockPermutation"
return &GenericZeroHinter{
Name: name,
Name: "BlockPermutation",
Op: func(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error {
//> from starkware.cairo.common.keccak_utils.keccak_utils import keccak_func
//> _keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
Expand Down Expand Up @@ -674,3 +672,80 @@ func createSplitOutputMidLowHighHinter(resolver hintReferenceResolver) (hinter.H

return newSplitOutputMidLowHighHint(output1, output1Low, output1Mid, output1High), 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`
//
// `newSplitNBytesHint` takes 3 operanders as arguments
// - `nWordsToCopy` is the variable that will store the quotient of the division
// - `nBytesLeft` is the variable that will store the remainder of the division
// - `nBytes` is the variable that will be divided
func newSplitNBytesHint(nBytes, nWordsToCopy, nBytesLeft hinter.ResOperander) hinter.Hinter {
name := "SplitNBytes"
return &GenericZeroHinter{
Name: name,
Op: func(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error {
//> ids.n_words_to_copy, ids.n_bytes_left = divmod(ids.n_bytes, ids.BYTES_IN_WORD)

nWordsToCopyAddr, err := nWordsToCopy.GetAddress(vm)
if err != nil {
return err
}

nBytesLeftAddr, err := nBytesLeft.GetAddress(vm)
if err != nil {
return err
}

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

nBytesBigInt := new(big.Int)
nBytesFelt.BigInt(nBytesBigInt)

bytesInWord := big.NewInt(8)

nWordsToCopyBigInt := new(big.Int)
nBytesLeftBigInt := new(big.Int)

nWordsToCopyBigInt.DivMod(nBytesBigInt, bytesInWord, nBytesLeftBigInt)

var nWordsToCopyFelt fp.Element
nWordsToCopyFelt.SetBigInt(nWordsToCopyBigInt)
nWordsToCopyMv := memory.MemoryValueFromFieldElement(&nWordsToCopyFelt)

var nBytesLeftFelt fp.Element
nBytesLeftFelt.SetBigInt(nBytesLeftBigInt)
nBytesLeftMv := memory.MemoryValueFromFieldElement(&nBytesLeftFelt)

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

return vm.Memory.WriteToAddress(&nWordsToCopyAddr, &nWordsToCopyMv)
},
}
}

func createSplitNBytesHinter(resolver hintReferenceResolver) (hinter.Hinter, error) {
nBytes, err := resolver.GetResOperander("n_bytes")
if err != nil {
return nil, err
}

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

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

return newSplitNBytesHint(nBytes, nWordsToCopy, nBytesLeft), nil
}
57 changes: 57 additions & 0 deletions pkg/hintrunner/zero/zerohint_keccak_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -703,5 +703,62 @@ func TestZeroHintKeccak(t *testing.T) {
check: allVarValueEquals(map[string]*fp.Element{"output1_low": feltUint64(38756173112), "output1_mid": feltUint64(42), "output1_high": feltUint64(1)}),
},
},
"SplitNBytes": {
{
operanders: []*hintOperander{
{Name: "n_bytes", Kind: apRelative, Value: feltUint64(0)},
{Name: "n_words_to_copy", Kind: uninitialized},
{Name: "n_bytes_left", Kind: uninitialized},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newSplitNBytesHint(ctx.operanders["n_bytes"], ctx.operanders["n_words_to_copy"], ctx.operanders["n_bytes_left"])
},
check: allVarValueEquals(map[string]*fp.Element{"n_words_to_copy": feltUint64(0), "n_bytes_left": feltUint64(0)}),
},
{
operanders: []*hintOperander{
{Name: "n_bytes", Kind: apRelative, Value: feltUint64(45)},
{Name: "n_words_to_copy", Kind: uninitialized},
{Name: "n_bytes_left", Kind: uninitialized},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newSplitNBytesHint(ctx.operanders["n_bytes"], ctx.operanders["n_words_to_copy"], ctx.operanders["n_bytes_left"])
},
check: allVarValueEquals(map[string]*fp.Element{"n_words_to_copy": feltUint64(5), "n_bytes_left": feltUint64(5)}),
},
{
operanders: []*hintOperander{
{Name: "n_bytes", Kind: apRelative, Value: feltUint64(80)},
{Name: "n_words_to_copy", Kind: uninitialized},
{Name: "n_bytes_left", Kind: uninitialized},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newSplitNBytesHint(ctx.operanders["n_bytes"], ctx.operanders["n_words_to_copy"], ctx.operanders["n_bytes_left"])
},
check: allVarValueEquals(map[string]*fp.Element{"n_words_to_copy": feltUint64(10), "n_bytes_left": feltUint64(0)}),
},
{
operanders: []*hintOperander{
{Name: "n_bytes", Kind: apRelative, Value: feltUint64(7)},
{Name: "n_words_to_copy", Kind: uninitialized},
{Name: "n_bytes_left", Kind: uninitialized},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newSplitNBytesHint(ctx.operanders["n_bytes"], ctx.operanders["n_words_to_copy"], ctx.operanders["n_bytes_left"])
},
check: allVarValueEquals(map[string]*fp.Element{"n_words_to_copy": feltUint64(0), "n_bytes_left": feltUint64(7)}),
},
{
operanders: []*hintOperander{
{Name: "n_bytes", Kind: apRelative, Value: feltUint64(7523672657695691)},
{Name: "n_words_to_copy", Kind: uninitialized},
{Name: "n_bytes_left", Kind: uninitialized},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newSplitNBytesHint(ctx.operanders["n_bytes"], ctx.operanders["n_words_to_copy"], ctx.operanders["n_bytes_left"])
},
check: allVarValueEquals(map[string]*fp.Element{"n_words_to_copy": feltUint64(940459082211961), "n_bytes_left": feltUint64(3)}),
},
},
})
}

0 comments on commit 00f0205

Please sign in to comment.