From 2c3dd5163a0372faa9615f93f4810ca688e4753e Mon Sep 17 00:00:00 2001 From: TAdev0 Date: Mon, 1 Jul 2024 20:38:34 +0200 Subject: [PATCH 1/4] SplitOutput0 --- pkg/hintrunner/zero/hintcode.go | 1 + pkg/hintrunner/zero/zerohint.go | 2 + pkg/hintrunner/zero/zerohint_keccak.go | 75 ++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) 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 +} From 0d46986df97df7015751309376c5d32be1f994ab Mon Sep 17 00:00:00 2001 From: TAdev0 Date: Wed, 3 Jul 2024 17:17:49 +0200 Subject: [PATCH 2/4] fmt --- pkg/hintrunner/zero/hintcode.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/hintrunner/zero/hintcode.go b/pkg/hintrunner/zero/hintcode.go index f335ed23..e153ee16 100644 --- a/pkg/hintrunner/zero/hintcode.go +++ b/pkg/hintrunner/zero/hintcode.go @@ -129,7 +129,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)" - splitOutput0Code string = "ids.output0_low = ids.output0 & ((1 << 128) - 1)\nids.output0_high = ids.output0 >> 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 ------ From 1f705ad7e8196b28e85726e096dd13f053801fe6 Mon Sep 17 00:00:00 2001 From: TAdev0 Date: Wed, 3 Jul 2024 17:30:34 +0200 Subject: [PATCH 3/4] fmt --- pkg/hintrunner/zero/zerohint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/hintrunner/zero/zerohint.go b/pkg/hintrunner/zero/zerohint.go index 0883f553..a8c8d3e3 100644 --- a/pkg/hintrunner/zero/zerohint.go +++ b/pkg/hintrunner/zero/zerohint.go @@ -177,7 +177,7 @@ func GetHintFromCode(program *zero.ZeroProgram, rawHint zero.Hint, hintPC uint64 return createCompareBytesInWordNondetHinter(resolver) case splitOutputMidLowHighCode: return createSplitOutputMidLowHighHinter(resolver) - case splitOutput0Code: + case splitOutput0Code: return createSplitOutput0Hinter(resolver) case SplitNBytesCode: return createSplitNBytesHinter(resolver) From fa3c40e06f3e6263a2072e5f68d373b8eb0d2895 Mon Sep 17 00:00:00 2001 From: TAdev0 Date: Thu, 4 Jul 2024 10:57:13 +0200 Subject: [PATCH 4/4] add tests --- pkg/hintrunner/zero/zerohint_keccak_test.go | 46 +++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/pkg/hintrunner/zero/zerohint_keccak_test.go b/pkg/hintrunner/zero/zerohint_keccak_test.go index 247a299d..beffb71d 100644 --- a/pkg/hintrunner/zero/zerohint_keccak_test.go +++ b/pkg/hintrunner/zero/zerohint_keccak_test.go @@ -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")}), + }, + }, }) }