diff --git a/pkg/hintrunner/zero/hintcode.go b/pkg/hintrunner/zero/hintcode.go index c0c27b89..da005b71 100644 --- a/pkg/hintrunner/zero/hintcode.go +++ b/pkg/hintrunner/zero/hintcode.go @@ -127,6 +127,7 @@ ids.multiplicities = segments.gen_arg([len(positions_dict[k]) for k in output])` blockPermutationCode string = "from starkware.cairo.common.keccak_utils.keccak_utils import keccak_func\n_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)\nassert 0 <= _keccak_state_size_felts < 100\noutput_values = keccak_func(memory.get_range(\nids.keccak_ptr - _keccak_state_size_felts, _keccak_state_size_felts))\nsegments.write_arg(ids.keccak_ptr, output_values)" 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)" + splitOutput0Code string = "ids.output0_low = ids.output0 & ((1 << 128) - 1)\nids.output0_high = ids.output0 >> 128" // ------ 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" diff --git a/pkg/hintrunner/zero/zerohint.go b/pkg/hintrunner/zero/zerohint.go index 4ec0f0b6..d59a750b 100644 --- a/pkg/hintrunner/zero/zerohint.go +++ b/pkg/hintrunner/zero/zerohint.go @@ -173,6 +173,8 @@ func GetHintFromCode(program *zero.ZeroProgram, rawHint zero.Hint, hintPC uint64 return createBlockPermutationHinter(resolver) case compareBytesInWordCode: return createCompareBytesInWordNondetHinter(resolver) + case splitOutput0Code: + return createSplitOutput0Hinter(resolver) // Usort hints case usortEnterScopeCode: return createUsortEnterScopeHinter() diff --git a/pkg/hintrunner/zero/zerohint_keccak.go b/pkg/hintrunner/zero/zerohint_keccak.go index c5c099d8..e41daf30 100644 --- a/pkg/hintrunner/zero/zerohint_keccak.go +++ b/pkg/hintrunner/zero/zerohint_keccak.go @@ -572,3 +572,78 @@ func createCompareBytesInWordNondetHinter(resolver hintReferenceResolver) (hinte return newCompareBytesInWordHint(nBytes), 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 +}