From 27817ff6ccf8f8fef2b26be3b72ece39fb0cef21 Mon Sep 17 00:00:00 2001 From: Shourya Goel Date: Wed, 3 Jul 2024 18:09:49 +0530 Subject: [PATCH] Implemented `SplitOutputMidLowHigh` (#511) Implemented SplitOutputMidLowHigh --- pkg/hintrunner/zero/hintcode.go | 1 + pkg/hintrunner/zero/zerohint.go | 2 + pkg/hintrunner/zero/zerohint_keccak.go | 102 ++++++++++++++++++++ pkg/hintrunner/zero/zerohint_keccak_test.go | 98 +++++++++++++++++++ 4 files changed, 203 insertions(+) diff --git a/pkg/hintrunner/zero/hintcode.go b/pkg/hintrunner/zero/hintcode.go index c0c27b896..e697e2b16 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)" + splitOutputMidLowHighCode string = "tmp, ids.output1_low = divmod(ids.output1, 256 ** 7)\nids.output1_high, ids.output1_mid = divmod(tmp, 2 ** 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 4ec0f0b62..26ffd6baf 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 splitOutputMidLowHighCode: + return createSplitOutputMidLowHighHinter(resolver) // Usort hints case usortEnterScopeCode: return createUsortEnterScopeHinter() diff --git a/pkg/hintrunner/zero/zerohint_keccak.go b/pkg/hintrunner/zero/zerohint_keccak.go index c5c099d87..4c27c6421 100644 --- a/pkg/hintrunner/zero/zerohint_keccak.go +++ b/pkg/hintrunner/zero/zerohint_keccak.go @@ -3,6 +3,7 @@ package zero import ( "fmt" "math" + "math/big" "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter" "github.com/NethermindEth/cairo-vm-go/pkg/utils" @@ -572,3 +573,104 @@ func createCompareBytesInWordNondetHinter(resolver hintReferenceResolver) (hinte return newCompareBytesInWordHint(nBytes), nil } + +// SplitOutputMidLowHigh hint assigns to `ids.output1_low` the remainder of the division +// of `ids.output1` variable by 256 ** 7 and uses its quotient as a variable which is +// divided by 2 ** 128, the quotient and remainder of which are then assigned to `ids.output1_high` +// and `ids.output1_mid` respectively. +// +// `newSplitOutputMidLowHighHint` takes 4 operanders as arguments +// - `output1Low` is the variable that will store the remainder of the first division +// - `output1Mid` is the variable that will store the remainder of the second division +// - `output1High` is the variable that will store the quotient of the second division +// - `output1` is the variable that will be divided in the first division +func newSplitOutputMidLowHighHint(output1, output1Low, output1Mid, output1High hinter.ResOperander) hinter.Hinter { + return &GenericZeroHinter{ + Name: "SplitOutputMidLowHigh", + Op: func(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error { + //> tmp, ids.output1_low = divmod(ids.output1, 256 ** 7) + //> ids.output1_high, ids.output1_mid = divmod(tmp, 2 ** 128) + + output1LowAddr, err := output1Low.GetAddress(vm) + if err != nil { + return err + } + + output1MidAddr, err := output1Mid.GetAddress(vm) + if err != nil { + return err + } + + output1HighAddr, err := output1High.GetAddress(vm) + if err != nil { + return err + } + + output1Felt, err := hinter.ResolveAsFelt(vm, output1) + if err != nil { + return err + } + + output1BigInt := new(big.Int) + output1Felt.BigInt(output1BigInt) + + tmpBigInt := new(big.Int) + output1LowBigInt := new(big.Int) + output1MidBigInt := new(big.Int) + output1HighBigInt := new(big.Int) + + divisorOne := new(big.Int).Exp(big.NewInt(256), big.NewInt(7), nil) + divisorTwo := new(big.Int).Exp(big.NewInt(2), big.NewInt(128), nil) + + tmpBigInt.DivMod(output1BigInt, divisorOne, output1LowBigInt) + output1HighBigInt.DivMod(tmpBigInt, divisorTwo, output1MidBigInt) + + var output1LowFelt fp.Element + output1LowFelt.SetBigInt(output1LowBigInt) + output1LowMv := memory.MemoryValueFromFieldElement(&output1LowFelt) + + var output1MidFelt fp.Element + output1MidFelt.SetBigInt(output1MidBigInt) + output1MidMv := memory.MemoryValueFromFieldElement(&output1MidFelt) + + var output1HighFelt fp.Element + output1HighFelt.SetBigInt(output1HighBigInt) + output1HighMv := memory.MemoryValueFromFieldElement(&output1HighFelt) + + err = vm.Memory.WriteToAddress(&output1LowAddr, &output1LowMv) + if err != nil { + return err + } + + err = vm.Memory.WriteToAddress(&output1MidAddr, &output1MidMv) + if err != nil { + return err + } + return vm.Memory.WriteToAddress(&output1HighAddr, &output1HighMv) + }, + } +} + +func createSplitOutputMidLowHighHinter(resolver hintReferenceResolver) (hinter.Hinter, error) { + output1, err := resolver.GetResOperander("output1") + if err != nil { + return nil, err + } + + output1Low, err := resolver.GetResOperander("output1_low") + if err != nil { + return nil, err + } + + output1Mid, err := resolver.GetResOperander("output1_mid") + if err != nil { + return nil, err + } + + output1High, err := resolver.GetResOperander("output1_high") + if err != nil { + return nil, err + } + + return newSplitOutputMidLowHighHint(output1, output1Low, output1Mid, output1High), nil +} diff --git a/pkg/hintrunner/zero/zerohint_keccak_test.go b/pkg/hintrunner/zero/zerohint_keccak_test.go index 8617d0cb0..03629ea3a 100644 --- a/pkg/hintrunner/zero/zerohint_keccak_test.go +++ b/pkg/hintrunner/zero/zerohint_keccak_test.go @@ -605,5 +605,103 @@ func TestZeroHintKeccak(t *testing.T) { check: apValueEquals(feltUint64(0)), }, }, + "SplitOutputMidLowHigh": { + { + operanders: []*hintOperander{ + {Name: "output1", Kind: apRelative, Value: feltUint64(0)}, + {Name: "output1_low", Kind: uninitialized}, + {Name: "output1_mid", Kind: uninitialized}, + {Name: "output1_high", Kind: uninitialized}, + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newSplitOutputMidLowHighHint(ctx.operanders["output1"], ctx.operanders["output1_low"], ctx.operanders["output1_mid"], ctx.operanders["output1_high"]) + }, + check: allVarValueEquals(map[string]*fp.Element{"output1_low": feltUint64(0), "output1_mid": feltUint64(0), "output1_high": feltUint64(0)}), + }, + { + operanders: []*hintOperander{ + {Name: "output1", Kind: apRelative, Value: feltUint64(72365738)}, + {Name: "output1_low", Kind: uninitialized}, + {Name: "output1_mid", Kind: uninitialized}, + {Name: "output1_high", Kind: uninitialized}, + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newSplitOutputMidLowHighHint(ctx.operanders["output1"], ctx.operanders["output1_low"], ctx.operanders["output1_mid"], ctx.operanders["output1_high"]) + }, + check: allVarValueEquals(map[string]*fp.Element{"output1_low": feltUint64(72365738), "output1_mid": feltUint64(0), "output1_high": feltUint64(0)}), + }, + { + operanders: []*hintOperander{ + {Name: "output1", Kind: apRelative, Value: feltUint64(72057594037927936)}, + {Name: "output1_low", Kind: uninitialized}, + {Name: "output1_mid", Kind: uninitialized}, + {Name: "output1_high", Kind: uninitialized}, + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newSplitOutputMidLowHighHint(ctx.operanders["output1"], ctx.operanders["output1_low"], ctx.operanders["output1_mid"], ctx.operanders["output1_high"]) + }, + check: allVarValueEquals(map[string]*fp.Element{"output1_low": feltUint64(0), "output1_mid": feltUint64(1), "output1_high": feltUint64(0)}), + }, + { + operanders: []*hintOperander{ + {Name: "output1", Kind: apRelative, Value: feltString("24519928653854221733733552434404946937899825954937634816")}, + {Name: "output1_low", Kind: uninitialized}, + {Name: "output1_mid", Kind: uninitialized}, + {Name: "output1_high", Kind: uninitialized}, + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newSplitOutputMidLowHighHint(ctx.operanders["output1"], ctx.operanders["output1_low"], ctx.operanders["output1_mid"], ctx.operanders["output1_high"]) + }, + check: allVarValueEquals(map[string]*fp.Element{"output1_low": feltUint64(0), "output1_mid": feltUint64(0), "output1_high": feltUint64(1)}), + }, + { + operanders: []*hintOperander{ + {Name: "output1", Kind: apRelative, Value: feltString("24519928653854221733733552434404946940926244904530608128")}, + {Name: "output1_low", Kind: uninitialized}, + {Name: "output1_mid", Kind: uninitialized}, + {Name: "output1_high", Kind: uninitialized}, + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newSplitOutputMidLowHighHint(ctx.operanders["output1"], ctx.operanders["output1_low"], ctx.operanders["output1_mid"], ctx.operanders["output1_high"]) + }, + check: allVarValueEquals(map[string]*fp.Element{"output1_low": feltUint64(0), "output1_mid": feltUint64(42), "output1_high": feltUint64(1)}), + }, + { + operanders: []*hintOperander{ + {Name: "output1", Kind: apRelative, Value: feltString("894386062958165334425")}, + {Name: "output1_low", Kind: uninitialized}, + {Name: "output1_mid", Kind: uninitialized}, + {Name: "output1_high", Kind: uninitialized}, + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newSplitOutputMidLowHighHint(ctx.operanders["output1"], ctx.operanders["output1_low"], ctx.operanders["output1_mid"], ctx.operanders["output1_high"]) + }, + check: allVarValueEquals(map[string]*fp.Element{"output1_low": feltUint64(7205759403792793), "output1_mid": feltUint64(12412), "output1_high": feltUint64(0)}), + }, + { + operanders: []*hintOperander{ + {Name: "output1", Kind: apRelative, Value: feltString("24519928653854221733733552434404946937899825956147353057")}, + {Name: "output1_low", Kind: uninitialized}, + {Name: "output1_mid", Kind: uninitialized}, + {Name: "output1_high", Kind: uninitialized}, + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newSplitOutputMidLowHighHint(ctx.operanders["output1"], ctx.operanders["output1_low"], ctx.operanders["output1_mid"], ctx.operanders["output1_high"]) + }, + check: allVarValueEquals(map[string]*fp.Element{"output1_low": feltUint64(1209718241), "output1_mid": feltUint64(0), "output1_high": feltUint64(1)}), + }, + { + operanders: []*hintOperander{ + {Name: "output1", Kind: apRelative, Value: feltString("24519928653854221733733552434404946940926244943286781240")}, + {Name: "output1_low", Kind: uninitialized}, + {Name: "output1_mid", Kind: uninitialized}, + {Name: "output1_high", Kind: uninitialized}, + }, + makeHinter: func(ctx *hintTestContext) hinter.Hinter { + return newSplitOutputMidLowHighHint(ctx.operanders["output1"], ctx.operanders["output1_low"], ctx.operanders["output1_mid"], ctx.operanders["output1_high"]) + }, + check: allVarValueEquals(map[string]*fp.Element{"output1_low": feltUint64(38756173112), "output1_mid": feltUint64(42), "output1_high": feltUint64(1)}), + }, + }, }) }