From fe960e7a69eae60b4a4a30ffba9cc8b9cd34cd3e Mon Sep 17 00:00:00 2001 From: Sh0g0-1758 Date: Tue, 1 Oct 2024 16:51:05 +0530 Subject: [PATCH 01/12] Wrote tests for ModBuiltin --- .github/workflows/integration-test.yml | 2 +- pkg/hintrunner/core/cairo_hintparser.go | 8 ++ pkg/hintrunner/core/hint.go | 41 +++++++ pkg/hintrunner/core/hint_test.go | 145 ++++++++++++++++++++++++ pkg/hintrunner/zero/hintcode.go | 1 + pkg/hintrunner/zero/zerohint.go | 2 + pkg/hintrunner/zero/zerohint_others.go | 29 +++++ pkg/parsers/starknet/hint.go | 10 ++ pkg/vm/builtins/modulo.go | 112 +++++++++--------- pkg/vm/builtins/modulo_test.go | 2 +- 10 files changed, 298 insertions(+), 54 deletions(-) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 81cf92190..59c73cf74 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -18,7 +18,7 @@ jobs: python-version: "3.9" - name: Install cairo-lang - run: pip install cairo-lang==0.13.1 + run: pip install cairo-lang==0.13.2 - name: Install sympy run: pip install sympy==1.11.1 diff --git a/pkg/hintrunner/core/cairo_hintparser.go b/pkg/hintrunner/core/cairo_hintparser.go index 51bda93de..86168d73f 100644 --- a/pkg/hintrunner/core/cairo_hintparser.go +++ b/pkg/hintrunner/core/cairo_hintparser.go @@ -95,6 +95,14 @@ func GetHintByName(hint starknet.Hint) (hinter.Hinter, error) { return &AllocSegment{ Dst: parseCellRefer(args.Dst), }, nil + case starknet.EvalCircuitName: + args := hint.Args.(*starknet.EvalCircuit) + return &EvalCircuit{ + AddModN: parseResOperand(args.NAddMods), + AddModPtr: parseResOperand(args.AddModPtr), + MulModN: parseResOperand(args.NMulMods), + MulModPtr: parseResOperand(args.MulModPtr), + }, nil case starknet.TestLessThanName: args := hint.Args.(*starknet.TestLessThan) return &TestLessThan{ diff --git a/pkg/hintrunner/core/hint.go b/pkg/hintrunner/core/hint.go index 23b426b38..8e98ad233 100644 --- a/pkg/hintrunner/core/hint.go +++ b/pkg/hintrunner/core/hint.go @@ -12,6 +12,7 @@ import ( "github.com/NethermindEth/cairo-vm-go/pkg/parsers/starknet" "github.com/NethermindEth/cairo-vm-go/pkg/utils" VM "github.com/NethermindEth/cairo-vm-go/pkg/vm" + "github.com/NethermindEth/cairo-vm-go/pkg/vm/builtins" mem "github.com/NethermindEth/cairo-vm-go/pkg/vm/memory" f "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" ) @@ -56,6 +57,46 @@ func (hint *AllocSegment) Execute(vm *VM.VirtualMachine, _ *hinter.HintRunnerCon return nil } +type EvalCircuit struct { + AddModN hinter.Reference + AddModPtr hinter.Reference + MulModN hinter.Reference + MulModPtr hinter.Reference +} + +func (hint *EvalCircuit) String() string { + return "EvalCircuit" +} + +func (hint *EvalCircuit) Execute(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error { + addModInputAddress, err := hinter.ResolveAsAddress(vm, hint.AddModPtr) + if err != nil { + return fmt.Errorf("resolve addModBuiltin pointer: %w", err) + } + nAddMods, err := hint.AddModN.Resolve(vm) + if err != nil { + return fmt.Errorf("resolve nAddMods operand %s: %v", hint.AddModN, err) + } + nAddModsFelt, err := nAddMods.Uint64() + if err != nil { + return err + } + mulModInputAddress, err := hinter.ResolveAsAddress(vm, hint.MulModPtr) + if err != nil { + return fmt.Errorf("resolve mulModBuiltin pointer: %w", err) + } + nMulMods, err := hint.MulModN.Resolve(vm) + if err != nil { + return fmt.Errorf("resolve nMulMods operand %s: %v", hint.MulModN, err) + } + nMulModsFelt, err := nMulMods.Uint64() + if err != nil { + return err + } + + return builtins.FillMemory(vm.Memory, *addModInputAddress, nAddModsFelt, *mulModInputAddress, nMulModsFelt) +} + type TestLessThan struct { dst hinter.Reference lhs hinter.Reference diff --git a/pkg/hintrunner/core/hint_test.go b/pkg/hintrunner/core/hint_test.go index 82bf52ffb..3406cd302 100644 --- a/pkg/hintrunner/core/hint_test.go +++ b/pkg/hintrunner/core/hint_test.go @@ -455,6 +455,151 @@ func TestDivModDivisionByZeroError(t *testing.T) { require.ErrorContains(t, err, "cannot be divided by zero, rhs: 0") } +func TestEvalCircuit(t *testing.T) { + vm := VM.DefaultVirtualMachine() + + vm.Context.Ap = 0 + vm.Context.Fp = 0 + + // Test : p = 2^96 + 1 + // Note that these calculations are performed based on the offsets that we provide + // x1 = 1 (4 memory cells) + // nil (4 memory cells) (should become equal to 0 as 2^96 + 1 mod p = 0) + // x2 = 2^96 + 2 (4 memory cells) + // res = 0 (4 memory cells) (multiplication of the above two numbers) + + // Values Array + // x1 = UInt384(17,0,0,0) + utils.WriteTo(vm, VM.ExecutionSegment, 0, mem.MemoryValueFromInt(17)) + utils.WriteTo(vm, VM.ExecutionSegment, 1, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 3, mem.MemoryValueFromInt(0)) + + // 4 unallocated memory cells + + // x2 = UInt384(23,1,0,0) + utils.WriteTo(vm, VM.ExecutionSegment, 8, mem.MemoryValueFromInt(23)) + utils.WriteTo(vm, VM.ExecutionSegment, 9, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 10, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 11, mem.MemoryValueFromInt(0)) + + // 4 unallocated memory cells for res + + // AddMod Offsets Array + utils.WriteTo(vm, VM.ExecutionSegment, 16, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 17, mem.MemoryValueFromInt(4)) + utils.WriteTo(vm, VM.ExecutionSegment, 18, mem.MemoryValueFromInt(8)) + + // MulMod Offsets Array + utils.WriteTo(vm, VM.ExecutionSegment, 19, mem.MemoryValueFromInt(4)) + utils.WriteTo(vm, VM.ExecutionSegment, 20, mem.MemoryValueFromInt(8)) + utils.WriteTo(vm, VM.ExecutionSegment, 21, mem.MemoryValueFromInt(12)) + + AddModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 96, 1, builtins.Add)) + MulModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 96, 1, builtins.Mul)) + + /* + The Add and Mul Mod builtin structure are defined as: + struct ModBuiltin { + p: UInt384, // The modulus. + values_ptr: UInt384*, // A pointer to input values, the intermediate results and the output. + offsets_ptr: felt*, // A pointer to offsets inside the values array, defining the circuit. + // The offsets array should contain 3 * n elements. + n: felt, // The number of operations to perform. + } + */ + + // add_mod_ptr + // p = UInt384(1,1,0,0) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 0, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 1, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 3, mem.MemoryValueFromInt(0)) + + // values_ptr + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 4, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 0})) + + // offsets_ptr + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 5, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 16})) + + // n + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 6, mem.MemoryValueFromInt(1)) + + // mul_mod_ptr + // p = UInt384(1,1,0,0) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 0, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 1, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 3, mem.MemoryValueFromInt(0)) + + // values_ptr + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 4, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 0})) + + // offsets_ptr + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 5, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 19})) + + // n + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 6, mem.MemoryValueFromInt(1)) + + // To get the address of mul_mod_ptr and add_mod_ptr + utils.WriteTo(vm, VM.ExecutionSegment, 22, mem.MemoryValueFromSegmentAndOffset(AddModBuiltin.SegmentIndex, 0)) + utils.WriteTo(vm, VM.ExecutionSegment, 23, mem.MemoryValueFromSegmentAndOffset(MulModBuiltin.SegmentIndex, 0)) + + var addRef hinter.ApCellRef = 22 + var mulRef hinter.ApCellRef = 23 + + nAddMods := hinter.Immediate(f.NewElement(1)) + nMulMods := hinter.Immediate(f.NewElement(1)) + addModPtrAddr := hinter.Deref{Deref: addRef} + mulModPtrAddr := hinter.Deref{Deref: mulRef} + + hint := EvalCircuit{ + AddModN: nAddMods, + AddModPtr: addModPtrAddr, + MulModN: nMulMods, + MulModPtr: mulModPtrAddr, + } + + err := hint.Execute(vm, nil) + require.Nil(t, err) + + res1 := &f.Element{} + res1.SetInt64(138) + + require.Equal( + t, + mem.MemoryValueFromFieldElement(res1), + utils.ReadFrom(vm, VM.ExecutionSegment, 12), + ) + + res2 := &f.Element{} + res2.SetInt64(0) + + require.Equal( + t, + mem.MemoryValueFromFieldElement(res2), + utils.ReadFrom(vm, VM.ExecutionSegment, 13), + ) + + res3 := &f.Element{} + res3.SetInt64(0) + + require.Equal( + t, + mem.MemoryValueFromFieldElement(res2), + utils.ReadFrom(vm, VM.ExecutionSegment, 14), + ) + + res4 := &f.Element{} + res4.SetInt64(0) + + require.Equal( + t, + mem.MemoryValueFromFieldElement(res2), + utils.ReadFrom(vm, VM.ExecutionSegment, 15), + ) +} + func TestU256InvModN(t *testing.T) { t.Run("test u256InvModN (n == 1)", func(t *testing.T) { vm := VM.DefaultVirtualMachine() diff --git a/pkg/hintrunner/zero/hintcode.go b/pkg/hintrunner/zero/hintcode.go index 1fa40ffca..d79146b38 100755 --- a/pkg/hintrunner/zero/hintcode.go +++ b/pkg/hintrunner/zero/hintcode.go @@ -173,6 +173,7 @@ const ( // ------ Other hints related code ------ allocSegmentCode string = "memory[ap] = segments.add()" + evalCircuitCode string = "from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner\nassert builtin_runners[\"add_mod_builtin\"].instance_def.batch_size == 1\nassert builtin_runners[\"mul_mod_builtin\"].instance_def.batch_size == 1\n\nModBuiltinRunner.fill_memory(\n memory=memory,\n add_mod=(ids.add_mod_ptr.address_, builtin_runners[\"add_mod_builtin\"], ids.add_mod_n),\n mul_mod=(ids.mul_mod_ptr.address_, builtin_runners[\"mul_mod_builtin\"], ids.mul_mod_n),\n)" memcpyContinueCopyingCode string = "n -= 1\nids.continue_copying = 1 if n > 0 else 0" memsetContinueLoopCode string = "n -= 1\nids.continue_loop = 1 if n > 0 else 0" memcpyEnterScopeCode string = "vm_enter_scope({'n': ids.len})" diff --git a/pkg/hintrunner/zero/zerohint.go b/pkg/hintrunner/zero/zerohint.go index ccc105b26..b241a77be 100755 --- a/pkg/hintrunner/zero/zerohint.go +++ b/pkg/hintrunner/zero/zerohint.go @@ -319,6 +319,8 @@ func GetHintFromCode(program *zero.ZeroProgram, rawHint zero.Hint) (hinter.Hinte // Other hints case allocSegmentCode: return createAllocSegmentHinter() + case evalCircuitCode: + return createEvalCircuitHinter(resolver) case memcpyContinueCopyingCode: return createMemContinueHinter(resolver, false) case memsetContinueLoopCode: diff --git a/pkg/hintrunner/zero/zerohint_others.go b/pkg/hintrunner/zero/zerohint_others.go index efd061576..a44b13acb 100644 --- a/pkg/hintrunner/zero/zerohint_others.go +++ b/pkg/hintrunner/zero/zerohint_others.go @@ -81,6 +81,35 @@ func createAllocSegmentHinter() (hinter.Hinter, error) { return &core.AllocSegment{Dst: hinter.ApCellRef(0)}, nil } +func createEvalCircuitHinter(resolver hintReferenceResolver) (hinter.Hinter, error) { + addModPtr, err := resolver.GetReference("add_mod_ptr") + if err != nil { + return nil, err + } + + nAddMods, err := resolver.GetReference("add_mod_n") + if err != nil { + return nil, err + } + + mulModPtr, err := resolver.GetReference("mul_mod_ptr") + if err != nil { + return nil, err + } + + nMulMods, err := resolver.GetReference("mul_mod_n") + if err != nil { + return nil, err + } + + return &core.EvalCircuit{ + AddModN: nAddMods, + AddModPtr: addModPtr, + MulModN: nMulMods, + MulModPtr: mulModPtr, + }, nil +} + // VMEnterScope hint enters a new scope in the Cairo VM func createVMEnterScopeHinter() (hinter.Hinter, error) { return &GenericZeroHinter{ diff --git a/pkg/parsers/starknet/hint.go b/pkg/parsers/starknet/hint.go index 768b20d65..01bc19ac8 100644 --- a/pkg/parsers/starknet/hint.go +++ b/pkg/parsers/starknet/hint.go @@ -18,6 +18,7 @@ const ( CheatcodeName HintName = "Cheatcode" // Core hints AllocSegmentName HintName = "AllocSegment" + EvalCircuitName HintName = "EvalCircuit" TestLessThanName HintName = "TestLessThan" TestLessThanOrEqualName HintName = "TestLessThanOrEqual" TestLessThanOrEqualAddressName HintName = "TestLessThanOrEqualAddress" @@ -75,6 +76,13 @@ type AllocSegment struct { Dst CellRef `json:"dst" validate:"required"` } +type EvalCircuit struct { + NAddMods ResOperand `json:"add_mod_n" validate:"required"` + AddModPtr ResOperand `json:"add_mod_ptr" validate:"required"` + NMulMods ResOperand `json:"mul_mod_n" validate:"required"` + MulModPtr ResOperand `json:"mul_mod_ptr" validate:"required"` +} + type TestLessThan struct { Lhs ResOperand `json:"lhs" validate:"required"` Rhs ResOperand `json:"rhs" validate:"required"` @@ -489,6 +497,8 @@ func (h *Hint) UnmarshalJSON(data []byte) error { // Core hints case AllocSegmentName: args = &AllocSegment{} + case EvalCircuitName: + args = &EvalCircuit{} case TestLessThanName: args = &TestLessThan{} case TestLessThanOrEqualName: diff --git a/pkg/vm/builtins/modulo.go b/pkg/vm/builtins/modulo.go index 4a3a97f87..332cb635a 100644 --- a/pkg/vm/builtins/modulo.go +++ b/pkg/vm/builtins/modulo.go @@ -352,7 +352,6 @@ func (m *ModBuiltin) fillValue(mem *memory.Memory, inputs ModBuiltinInputs, inde if kBound == nil { kBound = new(big.Int).Set(intLim) } - switch { case a != nil && b != nil && c == nil: var value big.Int @@ -464,78 +463,87 @@ func (m *ModBuiltin) fillValue(mem *memory.Memory, inputs ModBuiltinInputs, inde // The number of operations written to the input of the first instance n should be at // least n and a multiple of batch_size. Previous offsets are copied to the end of the // offsets table to make its length 3n'. -func FillMemory(mem *memory.Memory, addModBuiltinAddr memory.MemoryAddress, nAddModsIndex uint64, mulModBuiltinAddr memory.MemoryAddress, nMulModsIndex uint64) error { - if nAddModsIndex > MAX_N { +func FillMemory(mem *memory.Memory, addModInputAddress memory.MemoryAddress, nAddMods uint64, mulModInputAddress memory.MemoryAddress, nMulMods uint64) error { + if nAddMods > MAX_N { return fmt.Errorf("AddMod builtin: n must be <= {MAX_N}") } - if nMulModsIndex > MAX_N { + if nMulMods > MAX_N { return fmt.Errorf("MulMod builtin: n must be <= {MAX_N}") } - addModBuiltinSegment, ok := mem.FindSegmentWithBuiltin("AddMod") - if !ok { - return fmt.Errorf("AddMod builtin segment doesn't exist") - } - mulModBuiltinSegment, ok := mem.FindSegmentWithBuiltin("MulMod") - if !ok { - return fmt.Errorf("MulMod builtin segment doesn't exist") - } - addModBuiltinRunner, ok := addModBuiltinSegment.BuiltinRunner.(*ModBuiltin) - if !ok { - return fmt.Errorf("addModBuiltinRunner is not a ModBuiltin") - } - mulModBuiltinRunner, ok := mulModBuiltinSegment.BuiltinRunner.(*ModBuiltin) - if !ok { - return fmt.Errorf("mulModBuiltinRunner is not a ModBuiltin") - } + var addModBuiltinRunner *ModBuiltin + var mulModBuiltinRunner *ModBuiltin - if addModBuiltinRunner.wordBitLen != mulModBuiltinRunner.wordBitLen { - return fmt.Errorf("AddMod and MulMod wordBitLen mismatch") + if nAddMods != 0 { + addModBuiltinSegment, ok := mem.FindSegmentWithBuiltin("AddMod") + if !ok { + return fmt.Errorf("AddMod builtin segment doesn't exist") + } + addModBuiltinRunner, ok = addModBuiltinSegment.BuiltinRunner.(*ModBuiltin) + if !ok { + return fmt.Errorf("addModBuiltinRunner is not a ModBuiltin") + } + } else { + addModBuiltinRunner = nil } - addModBuiltinInputs, err := addModBuiltinRunner.readInputs(mem, addModBuiltinAddr, true) - if err != nil { - return err - } - if err := addModBuiltinRunner.fillInputs(mem, addModBuiltinAddr, addModBuiltinInputs); err != nil { - return err - } - if err := addModBuiltinRunner.fillOffsets(mem, addModBuiltinInputs.offsetsPtr, nAddModsIndex, addModBuiltinInputs.n-nAddModsIndex); err != nil { - return err + if nMulMods != 0 { + mulModBuiltinSegment, ok := mem.FindSegmentWithBuiltin("MulMod") + if !ok { + return fmt.Errorf("MulMod builtin segment doesn't exist") + } + mulModBuiltinRunner, ok = mulModBuiltinSegment.BuiltinRunner.(*ModBuiltin) + if !ok { + return fmt.Errorf("mulModBuiltinRunner is not a ModBuiltin") + } + } else { + mulModBuiltinRunner = nil } - mulModBuiltinInputs, err := mulModBuiltinRunner.readInputs(mem, mulModBuiltinAddr, true) - if err != nil { - return err - } - if err := mulModBuiltinRunner.fillInputs(mem, mulModBuiltinAddr, mulModBuiltinInputs); err != nil { - return err - } - if err := mulModBuiltinRunner.fillOffsets(mem, mulModBuiltinInputs.offsetsPtr, nMulModsIndex, mulModBuiltinInputs.n-nMulModsIndex); err != nil { - return err - } + var addModBuiltinInputs, mulModBuiltinInputs ModBuiltinInputs + var err error - addModIndex, mulModIndex := uint64(0), uint64(0) - for addModIndex < nAddModsIndex { - ok, err := addModBuiltinRunner.fillValue(mem, addModBuiltinInputs, int(addModIndex), Add) + if addModBuiltinRunner != nil { + addModBuiltinInputs, err = addModBuiltinRunner.readInputs(mem, addModInputAddress, true) if err != nil { return err } - if ok { - addModIndex++ + if err := addModBuiltinRunner.fillInputs(mem, addModInputAddress, addModBuiltinInputs); err != nil { + return err + } + if err := addModBuiltinRunner.fillOffsets(mem, addModBuiltinInputs.offsetsPtr, nAddMods, addModBuiltinInputs.n-nAddMods); err != nil { + return err } } - for mulModIndex < nMulModsIndex { - ok, err = mulModBuiltinRunner.fillValue(mem, mulModBuiltinInputs, int(mulModIndex), Mul) + if mulModBuiltinRunner != nil { + mulModBuiltinInputs, err = mulModBuiltinRunner.readInputs(mem, mulModInputAddress, true) if err != nil { return err } - if ok { - mulModIndex++ - } } - // POTENTIALY: add n_computed_mul_gates features in the future + addModIndex, mulModIndex := uint64(0), uint64(0) + for addModIndex < nAddMods || mulModIndex < nMulMods { + if addModIndex < nAddMods && addModBuiltinRunner != nil { + ok, err := addModBuiltinRunner.fillValue(mem, addModBuiltinInputs, int(addModIndex), Add) + if err != nil { + return err + } + if ok { + addModIndex++ + } + } + + if mulModIndex < nMulMods && mulModBuiltinRunner != nil { + ok, err := mulModBuiltinRunner.fillValue(mem, mulModBuiltinInputs, int(mulModIndex), Mul) + if err != nil { + return err + } + if ok { + mulModIndex++ + } + } + } return nil } diff --git a/pkg/vm/builtins/modulo_test.go b/pkg/vm/builtins/modulo_test.go index 722817b72..875adcdb2 100644 --- a/pkg/vm/builtins/modulo_test.go +++ b/pkg/vm/builtins/modulo_test.go @@ -12,7 +12,7 @@ import ( /* Tests whether runner completes a trio a, b, c as the input implies: -If inverse is False it tests whether a = x1, b=x2, c = None will be completed with c = res. +If inverse is False it tests whether a = x1, b = x2, c = None will be completed with c = res. If inverse is True it tests whether c = x1, b = x2, a = None will be completed with a = res. */ func checkResult(runner ModBuiltin, inverse bool, p, x1, x2 big.Int) (*big.Int, error) { From c3f603eadb5f4f5f656716337cb686428326635f Mon Sep 17 00:00:00 2001 From: Sh0g0-1758 Date: Tue, 1 Oct 2024 16:58:40 +0530 Subject: [PATCH 02/12] it --- pkg/hintrunner/core/hint_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/hintrunner/core/hint_test.go b/pkg/hintrunner/core/hint_test.go index 3406cd302..2fb470464 100644 --- a/pkg/hintrunner/core/hint_test.go +++ b/pkg/hintrunner/core/hint_test.go @@ -464,9 +464,9 @@ func TestEvalCircuit(t *testing.T) { // Test : p = 2^96 + 1 // Note that these calculations are performed based on the offsets that we provide // x1 = 1 (4 memory cells) - // nil (4 memory cells) (should become equal to 0 as 2^96 + 1 mod p = 0) + // nil (4 memory cells) (should become equal to 6) // x2 = 2^96 + 2 (4 memory cells) - // res = 0 (4 memory cells) (multiplication of the above two numbers) + // res = 138 (4 memory cells) (multiplication of the above two numbers) // Values Array // x1 = UInt384(17,0,0,0) From ad9e07a2ce0d36446b6ad0c99f0c36f7d09470b6 Mon Sep 17 00:00:00 2001 From: Sh0g0-1758 Date: Tue, 1 Oct 2024 17:17:01 +0530 Subject: [PATCH 03/12] Added another test --- pkg/hintrunner/core/hint_test.go | 382 +++++++++++++++++++++---------- 1 file changed, 265 insertions(+), 117 deletions(-) diff --git a/pkg/hintrunner/core/hint_test.go b/pkg/hintrunner/core/hint_test.go index 2fb470464..9215656c7 100644 --- a/pkg/hintrunner/core/hint_test.go +++ b/pkg/hintrunner/core/hint_test.go @@ -456,148 +456,296 @@ func TestDivModDivisionByZeroError(t *testing.T) { } func TestEvalCircuit(t *testing.T) { - vm := VM.DefaultVirtualMachine() + t.Run("test mod_builtin_runner (1)", func(t *testing.T) { + vm := VM.DefaultVirtualMachine() - vm.Context.Ap = 0 - vm.Context.Fp = 0 + vm.Context.Ap = 0 + vm.Context.Fp = 0 - // Test : p = 2^96 + 1 - // Note that these calculations are performed based on the offsets that we provide - // x1 = 1 (4 memory cells) - // nil (4 memory cells) (should become equal to 6) - // x2 = 2^96 + 2 (4 memory cells) - // res = 138 (4 memory cells) (multiplication of the above two numbers) + // Test : p = 2^96 + 1 + // Note that these calculations are performed based on the offsets that we provide + // x1 = 17 (4 memory cells) + // nil (4 memory cells) (should become equal to 6) + // x2 = 23 (4 memory cells) + // res = nil (4 memory cells) (multiplication of the above two numbers should then equal 138) + + // Values Array + // x1 = UInt384(17,0,0,0) + utils.WriteTo(vm, VM.ExecutionSegment, 0, mem.MemoryValueFromInt(17)) + utils.WriteTo(vm, VM.ExecutionSegment, 1, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 3, mem.MemoryValueFromInt(0)) + + // 4 unallocated memory cells + + // x2 = UInt384(23,1,0,0) + utils.WriteTo(vm, VM.ExecutionSegment, 8, mem.MemoryValueFromInt(23)) + utils.WriteTo(vm, VM.ExecutionSegment, 9, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 10, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 11, mem.MemoryValueFromInt(0)) + + // 4 unallocated memory cells for res + + // AddMod Offsets Array + utils.WriteTo(vm, VM.ExecutionSegment, 16, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 17, mem.MemoryValueFromInt(4)) + utils.WriteTo(vm, VM.ExecutionSegment, 18, mem.MemoryValueFromInt(8)) + + // MulMod Offsets Array + utils.WriteTo(vm, VM.ExecutionSegment, 19, mem.MemoryValueFromInt(4)) + utils.WriteTo(vm, VM.ExecutionSegment, 20, mem.MemoryValueFromInt(8)) + utils.WriteTo(vm, VM.ExecutionSegment, 21, mem.MemoryValueFromInt(12)) + + AddModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 96, 1, builtins.Add)) + MulModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 96, 1, builtins.Mul)) + + /* + The Add and Mul Mod builtin structure are defined as: + struct ModBuiltin { + p: UInt384, // The modulus. + values_ptr: UInt384*, // A pointer to input values, the intermediate results and the output. + offsets_ptr: felt*, // A pointer to offsets inside the values array, defining the circuit. + // The offsets array should contain 3 * n elements. + n: felt, // The number of operations to perform. + } + */ - // Values Array - // x1 = UInt384(17,0,0,0) - utils.WriteTo(vm, VM.ExecutionSegment, 0, mem.MemoryValueFromInt(17)) - utils.WriteTo(vm, VM.ExecutionSegment, 1, mem.MemoryValueFromInt(0)) - utils.WriteTo(vm, VM.ExecutionSegment, 2, mem.MemoryValueFromInt(0)) - utils.WriteTo(vm, VM.ExecutionSegment, 3, mem.MemoryValueFromInt(0)) - - // 4 unallocated memory cells - - // x2 = UInt384(23,1,0,0) - utils.WriteTo(vm, VM.ExecutionSegment, 8, mem.MemoryValueFromInt(23)) - utils.WriteTo(vm, VM.ExecutionSegment, 9, mem.MemoryValueFromInt(0)) - utils.WriteTo(vm, VM.ExecutionSegment, 10, mem.MemoryValueFromInt(0)) - utils.WriteTo(vm, VM.ExecutionSegment, 11, mem.MemoryValueFromInt(0)) - - // 4 unallocated memory cells for res - - // AddMod Offsets Array - utils.WriteTo(vm, VM.ExecutionSegment, 16, mem.MemoryValueFromInt(0)) - utils.WriteTo(vm, VM.ExecutionSegment, 17, mem.MemoryValueFromInt(4)) - utils.WriteTo(vm, VM.ExecutionSegment, 18, mem.MemoryValueFromInt(8)) - - // MulMod Offsets Array - utils.WriteTo(vm, VM.ExecutionSegment, 19, mem.MemoryValueFromInt(4)) - utils.WriteTo(vm, VM.ExecutionSegment, 20, mem.MemoryValueFromInt(8)) - utils.WriteTo(vm, VM.ExecutionSegment, 21, mem.MemoryValueFromInt(12)) - - AddModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 96, 1, builtins.Add)) - MulModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 96, 1, builtins.Mul)) - - /* - The Add and Mul Mod builtin structure are defined as: - struct ModBuiltin { - p: UInt384, // The modulus. - values_ptr: UInt384*, // A pointer to input values, the intermediate results and the output. - offsets_ptr: felt*, // A pointer to offsets inside the values array, defining the circuit. - // The offsets array should contain 3 * n elements. - n: felt, // The number of operations to perform. + // add_mod_ptr + // p = UInt384(1,1,0,0) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 0, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 1, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 3, mem.MemoryValueFromInt(0)) + + // values_ptr + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 4, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 0})) + + // offsets_ptr + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 5, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 16})) + + // n + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 6, mem.MemoryValueFromInt(1)) + + // mul_mod_ptr + // p = UInt384(1,1,0,0) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 0, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 1, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 3, mem.MemoryValueFromInt(0)) + + // values_ptr + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 4, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 0})) + + // offsets_ptr + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 5, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 19})) + + // n + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 6, mem.MemoryValueFromInt(1)) + + // To get the address of mul_mod_ptr and add_mod_ptr + utils.WriteTo(vm, VM.ExecutionSegment, 22, mem.MemoryValueFromSegmentAndOffset(AddModBuiltin.SegmentIndex, 0)) + utils.WriteTo(vm, VM.ExecutionSegment, 23, mem.MemoryValueFromSegmentAndOffset(MulModBuiltin.SegmentIndex, 0)) + + var addRef hinter.ApCellRef = 22 + var mulRef hinter.ApCellRef = 23 + + nAddMods := hinter.Immediate(f.NewElement(1)) + nMulMods := hinter.Immediate(f.NewElement(1)) + addModPtrAddr := hinter.Deref{Deref: addRef} + mulModPtrAddr := hinter.Deref{Deref: mulRef} + + hint := EvalCircuit{ + AddModN: nAddMods, + AddModPtr: addModPtrAddr, + MulModN: nMulMods, + MulModPtr: mulModPtrAddr, } - */ - // add_mod_ptr - // p = UInt384(1,1,0,0) - utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 0, mem.MemoryValueFromInt(1)) - utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 1, mem.MemoryValueFromInt(1)) - utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 2, mem.MemoryValueFromInt(0)) - utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 3, mem.MemoryValueFromInt(0)) + err := hint.Execute(vm, nil) + require.Nil(t, err) - // values_ptr - utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 4, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 0})) + res1 := &f.Element{} + res1.SetInt64(138) - // offsets_ptr - utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 5, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 16})) + require.Equal( + t, + mem.MemoryValueFromFieldElement(res1), + utils.ReadFrom(vm, VM.ExecutionSegment, 12), + ) - // n - utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 6, mem.MemoryValueFromInt(1)) + res2 := &f.Element{} + res2.SetInt64(0) - // mul_mod_ptr - // p = UInt384(1,1,0,0) - utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 0, mem.MemoryValueFromInt(1)) - utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 1, mem.MemoryValueFromInt(1)) - utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 2, mem.MemoryValueFromInt(0)) - utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 3, mem.MemoryValueFromInt(0)) + require.Equal( + t, + mem.MemoryValueFromFieldElement(res2), + utils.ReadFrom(vm, VM.ExecutionSegment, 13), + ) - // values_ptr - utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 4, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 0})) + res3 := &f.Element{} + res3.SetInt64(0) - // offsets_ptr - utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 5, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 19})) + require.Equal( + t, + mem.MemoryValueFromFieldElement(res2), + utils.ReadFrom(vm, VM.ExecutionSegment, 14), + ) - // n - utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 6, mem.MemoryValueFromInt(1)) + res4 := &f.Element{} + res4.SetInt64(0) - // To get the address of mul_mod_ptr and add_mod_ptr - utils.WriteTo(vm, VM.ExecutionSegment, 22, mem.MemoryValueFromSegmentAndOffset(AddModBuiltin.SegmentIndex, 0)) - utils.WriteTo(vm, VM.ExecutionSegment, 23, mem.MemoryValueFromSegmentAndOffset(MulModBuiltin.SegmentIndex, 0)) + require.Equal( + t, + mem.MemoryValueFromFieldElement(res2), + utils.ReadFrom(vm, VM.ExecutionSegment, 15), + ) + }) - var addRef hinter.ApCellRef = 22 - var mulRef hinter.ApCellRef = 23 + t.Run("test mod_builtin_runner (2)", func(t *testing.T) { + vm := VM.DefaultVirtualMachine() - nAddMods := hinter.Immediate(f.NewElement(1)) - nMulMods := hinter.Immediate(f.NewElement(1)) - addModPtrAddr := hinter.Deref{Deref: addRef} - mulModPtrAddr := hinter.Deref{Deref: mulRef} + vm.Context.Ap = 0 + vm.Context.Fp = 0 - hint := EvalCircuit{ - AddModN: nAddMods, - AddModPtr: addModPtrAddr, - MulModN: nMulMods, - MulModPtr: mulModPtrAddr, - } + // Test : p = 2^96 + 1 + // Note that these calculations are performed based on the offsets that we provide + // x1 = 1 (4 memory cells) + // nil (4 memory cells) (should become equal to 0) + // x2 = 2^96 + 2 (4 memory cells) + // res = nil (4 memory cells) (multiplication of the above two numbers should then equal 0) + + // Values Array + // x1 = UInt384(17,0,0,0) + utils.WriteTo(vm, VM.ExecutionSegment, 0, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, VM.ExecutionSegment, 1, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 3, mem.MemoryValueFromInt(0)) + + // 4 unallocated memory cells + + // x2 = UInt384(23,1,0,0) + utils.WriteTo(vm, VM.ExecutionSegment, 8, mem.MemoryValueFromInt(2)) + utils.WriteTo(vm, VM.ExecutionSegment, 9, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, VM.ExecutionSegment, 10, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 11, mem.MemoryValueFromInt(0)) + + // 4 unallocated memory cells for res + + // AddMod Offsets Array + utils.WriteTo(vm, VM.ExecutionSegment, 16, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 17, mem.MemoryValueFromInt(4)) + utils.WriteTo(vm, VM.ExecutionSegment, 18, mem.MemoryValueFromInt(8)) + + // MulMod Offsets Array + utils.WriteTo(vm, VM.ExecutionSegment, 19, mem.MemoryValueFromInt(4)) + utils.WriteTo(vm, VM.ExecutionSegment, 20, mem.MemoryValueFromInt(8)) + utils.WriteTo(vm, VM.ExecutionSegment, 21, mem.MemoryValueFromInt(12)) + + AddModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 96, 1, builtins.Add)) + MulModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 96, 1, builtins.Mul)) + + /* + The Add and Mul Mod builtin structure are defined as: + struct ModBuiltin { + p: UInt384, // The modulus. + values_ptr: UInt384*, // A pointer to input values, the intermediate results and the output. + offsets_ptr: felt*, // A pointer to offsets inside the values array, defining the circuit. + // The offsets array should contain 3 * n elements. + n: felt, // The number of operations to perform. + } + */ - err := hint.Execute(vm, nil) - require.Nil(t, err) + // add_mod_ptr + // p = UInt384(1,1,0,0) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 0, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 1, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 3, mem.MemoryValueFromInt(0)) - res1 := &f.Element{} - res1.SetInt64(138) + // values_ptr + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 4, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 0})) - require.Equal( - t, - mem.MemoryValueFromFieldElement(res1), - utils.ReadFrom(vm, VM.ExecutionSegment, 12), - ) + // offsets_ptr + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 5, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 16})) - res2 := &f.Element{} - res2.SetInt64(0) + // n + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 6, mem.MemoryValueFromInt(1)) - require.Equal( - t, - mem.MemoryValueFromFieldElement(res2), - utils.ReadFrom(vm, VM.ExecutionSegment, 13), - ) + // mul_mod_ptr + // p = UInt384(1,1,0,0) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 0, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 1, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 3, mem.MemoryValueFromInt(0)) - res3 := &f.Element{} - res3.SetInt64(0) + // values_ptr + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 4, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 0})) - require.Equal( - t, - mem.MemoryValueFromFieldElement(res2), - utils.ReadFrom(vm, VM.ExecutionSegment, 14), - ) + // offsets_ptr + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 5, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 19})) - res4 := &f.Element{} - res4.SetInt64(0) + // n + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 6, mem.MemoryValueFromInt(1)) + + // To get the address of mul_mod_ptr and add_mod_ptr + utils.WriteTo(vm, VM.ExecutionSegment, 22, mem.MemoryValueFromSegmentAndOffset(AddModBuiltin.SegmentIndex, 0)) + utils.WriteTo(vm, VM.ExecutionSegment, 23, mem.MemoryValueFromSegmentAndOffset(MulModBuiltin.SegmentIndex, 0)) + + var addRef hinter.ApCellRef = 22 + var mulRef hinter.ApCellRef = 23 + + nAddMods := hinter.Immediate(f.NewElement(1)) + nMulMods := hinter.Immediate(f.NewElement(1)) + addModPtrAddr := hinter.Deref{Deref: addRef} + mulModPtrAddr := hinter.Deref{Deref: mulRef} + + hint := EvalCircuit{ + AddModN: nAddMods, + AddModPtr: addModPtrAddr, + MulModN: nMulMods, + MulModPtr: mulModPtrAddr, + } + + err := hint.Execute(vm, nil) + require.Nil(t, err) + + res1 := &f.Element{} + res1.SetInt64(0) + + require.Equal( + t, + mem.MemoryValueFromFieldElement(res1), + utils.ReadFrom(vm, VM.ExecutionSegment, 12), + ) + + res2 := &f.Element{} + res2.SetInt64(0) + + require.Equal( + t, + mem.MemoryValueFromFieldElement(res2), + utils.ReadFrom(vm, VM.ExecutionSegment, 13), + ) + + res3 := &f.Element{} + res3.SetInt64(0) + + require.Equal( + t, + mem.MemoryValueFromFieldElement(res2), + utils.ReadFrom(vm, VM.ExecutionSegment, 14), + ) + + res4 := &f.Element{} + res4.SetInt64(0) + + require.Equal( + t, + mem.MemoryValueFromFieldElement(res2), + utils.ReadFrom(vm, VM.ExecutionSegment, 15), + ) + }) - require.Equal( - t, - mem.MemoryValueFromFieldElement(res2), - utils.ReadFrom(vm, VM.ExecutionSegment, 15), - ) } func TestU256InvModN(t *testing.T) { From 3039b319863503c46cf75b05271107e493646997 Mon Sep 17 00:00:00 2001 From: Sh0g0-1758 Date: Tue, 1 Oct 2024 17:32:52 +0530 Subject: [PATCH 04/12] big test --- pkg/hintrunner/core/hint_test.go | 163 ++++++++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 3 deletions(-) diff --git a/pkg/hintrunner/core/hint_test.go b/pkg/hintrunner/core/hint_test.go index 9215656c7..8b1eb55e2 100644 --- a/pkg/hintrunner/core/hint_test.go +++ b/pkg/hintrunner/core/hint_test.go @@ -478,7 +478,7 @@ func TestEvalCircuit(t *testing.T) { // 4 unallocated memory cells - // x2 = UInt384(23,1,0,0) + // x2 = UInt384(23,0,0,0) utils.WriteTo(vm, VM.ExecutionSegment, 8, mem.MemoryValueFromInt(23)) utils.WriteTo(vm, VM.ExecutionSegment, 9, mem.MemoryValueFromInt(0)) utils.WriteTo(vm, VM.ExecutionSegment, 10, mem.MemoryValueFromInt(0)) @@ -615,7 +615,7 @@ func TestEvalCircuit(t *testing.T) { // res = nil (4 memory cells) (multiplication of the above two numbers should then equal 0) // Values Array - // x1 = UInt384(17,0,0,0) + // x1 = UInt384(1,0,0,0) utils.WriteTo(vm, VM.ExecutionSegment, 0, mem.MemoryValueFromInt(1)) utils.WriteTo(vm, VM.ExecutionSegment, 1, mem.MemoryValueFromInt(0)) utils.WriteTo(vm, VM.ExecutionSegment, 2, mem.MemoryValueFromInt(0)) @@ -623,7 +623,7 @@ func TestEvalCircuit(t *testing.T) { // 4 unallocated memory cells - // x2 = UInt384(23,1,0,0) + // x2 = UInt384(2,1,0,0) utils.WriteTo(vm, VM.ExecutionSegment, 8, mem.MemoryValueFromInt(2)) utils.WriteTo(vm, VM.ExecutionSegment, 9, mem.MemoryValueFromInt(1)) utils.WriteTo(vm, VM.ExecutionSegment, 10, mem.MemoryValueFromInt(0)) @@ -746,6 +746,163 @@ func TestEvalCircuit(t *testing.T) { ) }) + t.Run("test mod_builtin_runner (3)", func(t *testing.T) { + vm := VM.DefaultVirtualMachine() + + vm.Context.Ap = 0 + vm.Context.Fp = 0 + + // Test : p = 2^96 + 1 + // Note that the calculations are performed based on the offsets that we provide + // x1 = 1 + // x2 = 2^96 + 2 + // x3 = 2 + + // Values Array + // x1 = UInt384(1,0,0,0) + utils.WriteTo(vm, VM.ExecutionSegment, 0, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, VM.ExecutionSegment, 1, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 3, mem.MemoryValueFromInt(0)) + + // x2 = UInt384(2,1,0,0) + utils.WriteTo(vm, VM.ExecutionSegment, 4, mem.MemoryValueFromInt(2)) + utils.WriteTo(vm, VM.ExecutionSegment, 5, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, VM.ExecutionSegment, 6, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 7, mem.MemoryValueFromInt(0)) + + // x3 = UInt384(2,0,0,0) + utils.WriteTo(vm, VM.ExecutionSegment, 8, mem.MemoryValueFromInt(2)) + utils.WriteTo(vm, VM.ExecutionSegment, 9, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 10, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 11, mem.MemoryValueFromInt(0)) + + // 20 unallocated memory cells for res and other calculations + + // AddMod Offsets Array + utils.WriteTo(vm, VM.ExecutionSegment, 32, mem.MemoryValueFromInt(0)) // x1 + utils.WriteTo(vm, VM.ExecutionSegment, 33, mem.MemoryValueFromInt(12)) // x2 - x1 + utils.WriteTo(vm, VM.ExecutionSegment, 34, mem.MemoryValueFromInt(4)) // x2 + utils.WriteTo(vm, VM.ExecutionSegment, 35, mem.MemoryValueFromInt(16)) // (x2 - x1) / x3 + utils.WriteTo(vm, VM.ExecutionSegment, 36, mem.MemoryValueFromInt(20)) // x1 / x3 + utils.WriteTo(vm, VM.ExecutionSegment, 37, mem.MemoryValueFromInt(24)) // (x2 - x1) / x3 + x1 / x3 + + // MulMod Offsets Array + utils.WriteTo(vm, VM.ExecutionSegment, 38, mem.MemoryValueFromInt(8)) // x3 + utils.WriteTo(vm, VM.ExecutionSegment, 39, mem.MemoryValueFromInt(16)) // (x2 - x1) / x3 + utils.WriteTo(vm, VM.ExecutionSegment, 40, mem.MemoryValueFromInt(12)) // (x2 - x1) + utils.WriteTo(vm, VM.ExecutionSegment, 41, mem.MemoryValueFromInt(8)) // x3 + utils.WriteTo(vm, VM.ExecutionSegment, 42, mem.MemoryValueFromInt(20)) // x1 / x3 + utils.WriteTo(vm, VM.ExecutionSegment, 43, mem.MemoryValueFromInt(0)) // x1 + utils.WriteTo(vm, VM.ExecutionSegment, 44, mem.MemoryValueFromInt(8)) // x3 + utils.WriteTo(vm, VM.ExecutionSegment, 45, mem.MemoryValueFromInt(24)) // ((x2 - x1) / x3 + x1 / x3) + utils.WriteTo(vm, VM.ExecutionSegment, 46, mem.MemoryValueFromInt(28)) // ((x2 - x1) / x3 + x1 / x3) * x3 + + AddModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 96, 1, builtins.Add)) + MulModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 96, 1, builtins.Mul)) + + /* + The Add and Mul Mod builtin structure are defined as: + struct ModBuiltin { + p: UInt384, // The modulus. + values_ptr: UInt384*, // A pointer to input values, the intermediate results and the output. + offsets_ptr: felt*, // A pointer to offsets inside the values array, defining the circuit. + // The offsets array should contain 3 * n elements. + n: felt, // The number of operations to perform. + } + */ + + // add_mod_ptr + // p = UInt384(1,1,0,0) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 0, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 1, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 3, mem.MemoryValueFromInt(0)) + + // values_ptr + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 4, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 0})) + + // offsets_ptr + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 5, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 32})) + + // n + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 6, mem.MemoryValueFromInt(2)) + + // mul_mod_ptr + // p = UInt384(1,1,0,0) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 0, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 1, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 3, mem.MemoryValueFromInt(0)) + + // values_ptr + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 4, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 0})) + + // offsets_ptr + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 5, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 38})) + + // n + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 6, mem.MemoryValueFromInt(3)) + + // To get the address of mul_mod_ptr and add_mod_ptr + utils.WriteTo(vm, VM.ExecutionSegment, 47, mem.MemoryValueFromSegmentAndOffset(AddModBuiltin.SegmentIndex, 0)) + utils.WriteTo(vm, VM.ExecutionSegment, 48, mem.MemoryValueFromSegmentAndOffset(MulModBuiltin.SegmentIndex, 0)) + + var addRef hinter.ApCellRef = 47 + var mulRef hinter.ApCellRef = 48 + + nAddMods := hinter.Immediate(f.NewElement(2)) + nMulMods := hinter.Immediate(f.NewElement(3)) + addModPtrAddr := hinter.Deref{Deref: addRef} + mulModPtrAddr := hinter.Deref{Deref: mulRef} + + hint := EvalCircuit{ + AddModN: nAddMods, + AddModPtr: addModPtrAddr, + MulModN: nMulMods, + MulModPtr: mulModPtrAddr, + } + + err := hint.Execute(vm, nil) + require.Nil(t, err) + + res1 := &f.Element{} + res1.SetInt64(1) + + require.Equal( + t, + mem.MemoryValueFromFieldElement(res1), + utils.ReadFrom(vm, VM.ExecutionSegment, 28), + ) + + res2 := &f.Element{} + res2.SetInt64(0) + + require.Equal( + t, + mem.MemoryValueFromFieldElement(res2), + utils.ReadFrom(vm, VM.ExecutionSegment, 29), + ) + + res3 := &f.Element{} + res3.SetInt64(0) + + require.Equal( + t, + mem.MemoryValueFromFieldElement(res2), + utils.ReadFrom(vm, VM.ExecutionSegment, 30), + ) + + res4 := &f.Element{} + res4.SetInt64(0) + + require.Equal( + t, + mem.MemoryValueFromFieldElement(res2), + utils.ReadFrom(vm, VM.ExecutionSegment, 31), + ) + }) + } func TestU256InvModN(t *testing.T) { From f4341b9be9c2b5b3cbfd414aa22026efb39ee1ec Mon Sep 17 00:00:00 2001 From: Sh0g0-1758 Date: Tue, 1 Oct 2024 17:52:26 +0530 Subject: [PATCH 05/12] add zerodivisor --- pkg/vm/builtins/modulo.go | 59 +++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/pkg/vm/builtins/modulo.go b/pkg/vm/builtins/modulo.go index 332cb635a..9d4dbbc36 100644 --- a/pkg/vm/builtins/modulo.go +++ b/pkg/vm/builtins/modulo.go @@ -320,23 +320,23 @@ func (m *ModBuiltin) writeNWordsValue(mem *memory.Memory, addr memory.MemoryAddr // Returns true on success or if all values are already known. // Given known, res, p fillValue tries to compute the minimal integer operand x which // satisfies the equation op(x,known) = res + k*p for some k in {0,1,...,self.k_bound-1}. -func (m *ModBuiltin) fillValue(mem *memory.Memory, inputs ModBuiltinInputs, index int, op ModBuiltinType) (bool, error) { +func (m *ModBuiltin) fillValue(mem *memory.Memory, inputs ModBuiltinInputs, index int, op ModBuiltinType) (int, error) { addresses := make([]memory.MemoryAddress, 0, 3) values := make([]*big.Int, 0, 3) for i := 0; i < 3; i++ { addr, err := inputs.offsetsPtr.AddOffset(int16(3*index + i)) if err != nil { - return false, err + return 0, err } offsetFelt, err := mem.ReadAsElement(addr.SegmentIndex, addr.Offset) if err != nil { - return false, err + return 0, err } offset := offsetFelt.Uint64() addr, err = inputs.valuesPtr.AddOffset(int16(offset)) if err != nil { - return false, err + return 0, err } addresses = append(addresses, addr) // do not check for error, as the value might not be in memory @@ -362,7 +362,7 @@ func (m *ModBuiltin) fillValue(mem *memory.Memory, inputs ModBuiltinInputs, inde } // value - (kBound - 1) * p <= intLim - 1 if new(big.Int).Sub(&value, new(big.Int).Mul((new(big.Int).Sub(kBound, big.NewInt(1))), &inputs.p)).Cmp(new(big.Int).Sub(intLim, big.NewInt(1))) == 1 { - return false, fmt.Errorf("%s builtin: Expected a %s b - %d * p <= %d", m.String(), m.modBuiltinType, kBound.Sub(kBound, big.NewInt(1)), intLim.Sub(intLim, big.NewInt(1))) + return 0, fmt.Errorf("%s builtin: Expected a %s b - %d * p <= %d", m.String(), m.modBuiltinType, kBound.Sub(kBound, big.NewInt(1)), intLim.Sub(intLim, big.NewInt(1))) } if value.Cmp(new(big.Int).Mul(kBound, &inputs.p)) < 0 { value.Mod(&value, &inputs.p) @@ -370,16 +370,17 @@ func (m *ModBuiltin) fillValue(mem *memory.Memory, inputs ModBuiltinInputs, inde value.Sub(&value, new(big.Int).Mul(new(big.Int).Sub(kBound, big.NewInt(1)), &inputs.p)) } if err := m.writeNWordsValue(mem, addresses[2], value); err != nil { - return false, err + return 0, err } - return true, nil + return 1, nil case a != nil && b == nil && c != nil: + zeroDivisor := false var value big.Int if op == Add { // Right now only k = 2 is an option, hence as we stated above that x + known can only take values // from res to res + (k - 1) * p, hence known <= res + p if a.Cmp(new(big.Int).Add(c, &inputs.p)) > 0 { - return false, fmt.Errorf("%s builtin: addend greater than sum + p: %d > %d + %d", m.String(), a, c, &inputs.p) + return 0, fmt.Errorf("%s builtin: addend greater than sum + p: %d > %d + %d", m.String(), a, c, &inputs.p) } else { if a.Cmp(c) <= 0 { value = *new(big.Int).Sub(c, a) @@ -391,16 +392,17 @@ func (m *ModBuiltin) fillValue(mem *memory.Memory, inputs ModBuiltinInputs, inde x, _, gcd := utils.Igcdex(a, &inputs.p) // if gcd != 1, the known value is 0, in which case the res must be 0 if gcd.Cmp(big.NewInt(1)) != 0 { + zeroDivisor = true value = *new(big.Int).Div(&inputs.p, &gcd) } else { value = *new(big.Int).Mul(c, &x) value = *value.Mod(&value, &inputs.p) tmpK, err := utils.SafeDiv(new(big.Int).Sub(new(big.Int).Mul(a, &value), c), &inputs.p) if err != nil { - return false, err + return 0, err } if tmpK.Cmp(kBound) >= 0 { - return false, fmt.Errorf("%s builtin: ((%d * q) - %d) / %d > %d for any q > 0, such that %d * q = %d (mod %d) ", m.String(), a, c, &inputs.p, kBound, a, c, &inputs.p) + return 0, fmt.Errorf("%s builtin: ((%d * q) - %d) / %d > %d for any q > 0, such that %d * q = %d (mod %d) ", m.String(), a, c, &inputs.p, kBound, a, c, &inputs.p) } if tmpK.Cmp(big.NewInt(0)) < 0 { value = *value.Add(&value, new(big.Int).Mul(&inputs.p, new(big.Int).Div(new(big.Int).Sub(a, new(big.Int).Sub(&tmpK, big.NewInt(1))), a))) @@ -408,16 +410,20 @@ func (m *ModBuiltin) fillValue(mem *memory.Memory, inputs ModBuiltinInputs, inde } } if err := m.writeNWordsValue(mem, addresses[1], value); err != nil { - return false, err + return 0, err } - return true, nil + if zeroDivisor { + return 2, nil + } + return 1, nil case a == nil && b != nil && c != nil: + zeroDivisor := false var value big.Int if op == Add { // Right now only k = 2 is an option, hence as we stated above that x + known can only take values // from res to res + (k - 1) * p, hence known <= res + p if b.Cmp(new(big.Int).Add(c, &inputs.p)) > 0 { - return false, fmt.Errorf("%s builtin: addend greater than sum + p: %d > %d + %d", m.String(), b, c, &inputs.p) + return 0, fmt.Errorf("%s builtin: addend greater than sum + p: %d > %d + %d", m.String(), b, c, &inputs.p) } else { if b.Cmp(c) <= 0 { value = *new(big.Int).Sub(c, b) @@ -429,16 +435,17 @@ func (m *ModBuiltin) fillValue(mem *memory.Memory, inputs ModBuiltinInputs, inde x, _, gcd := utils.Igcdex(b, &inputs.p) // if gcd != 1, the known value is 0, in which case the res must be 0 if gcd.Cmp(big.NewInt(1)) != 0 { + zeroDivisor = true value = *new(big.Int).Div(&inputs.p, &gcd) } else { value = *new(big.Int).Mul(c, &x) value = *value.Mod(&value, &inputs.p) tmpK, err := utils.SafeDiv(new(big.Int).Sub(new(big.Int).Mul(b, &value), c), &inputs.p) if err != nil { - return false, err + return 0, err } if tmpK.Cmp(kBound) >= 0 { - return false, fmt.Errorf("%s builtin: ((%d * q) - %d) / %d > %d for any q > 0, such that %d * q = %d (mod %d) ", m.String(), b, c, &inputs.p, kBound, b, c, &inputs.p) + return 0, fmt.Errorf("%s builtin: ((%d * q) - %d) / %d > %d for any q > 0, such that %d * q = %d (mod %d) ", m.String(), b, c, &inputs.p, kBound, b, c, &inputs.p) } if tmpK.Cmp(big.NewInt(0)) < 0 { value = *value.Add(&value, new(big.Int).Mul(&inputs.p, new(big.Int).Div(new(big.Int).Sub(b, new(big.Int).Sub(&tmpK, big.NewInt(1))), b))) @@ -446,13 +453,16 @@ func (m *ModBuiltin) fillValue(mem *memory.Memory, inputs ModBuiltinInputs, inde } } if err := m.writeNWordsValue(mem, addresses[0], value); err != nil { - return false, err + return 0, err + } + if zeroDivisor { + return 2, nil } - return true, nil + return 1, nil case a != nil && b != nil && c != nil: - return true, nil + return 1, nil default: - return false, nil + return 0, nil } } @@ -526,23 +536,24 @@ func FillMemory(mem *memory.Memory, addModInputAddress memory.MemoryAddress, nAd addModIndex, mulModIndex := uint64(0), uint64(0) for addModIndex < nAddMods || mulModIndex < nMulMods { if addModIndex < nAddMods && addModBuiltinRunner != nil { - ok, err := addModBuiltinRunner.fillValue(mem, addModBuiltinInputs, int(addModIndex), Add) + res, err := addModBuiltinRunner.fillValue(mem, addModBuiltinInputs, int(addModIndex), Add) if err != nil { return err } - if ok { + if res == 1 { addModIndex++ } } if mulModIndex < nMulMods && mulModBuiltinRunner != nil { - ok, err := mulModBuiltinRunner.fillValue(mem, mulModBuiltinInputs, int(mulModIndex), Mul) + res, err := mulModBuiltinRunner.fillValue(mem, mulModBuiltinInputs, int(mulModIndex), Mul) if err != nil { return err } - if ok { - mulModIndex++ + if res == 0 { + return fmt.Errorf("MulMod builtin: Could not fill the values table") } + mulModIndex++ } } return nil From 0147b17656899c53538fc441cd277b0c99f1f7e7 Mon Sep 17 00:00:00 2001 From: Sh0g0-1758 Date: Tue, 1 Oct 2024 18:14:20 +0530 Subject: [PATCH 06/12] implemented nComputedMulGates --- pkg/vm/builtins/modulo.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/pkg/vm/builtins/modulo.go b/pkg/vm/builtins/modulo.go index 9d4dbbc36..21384f279 100644 --- a/pkg/vm/builtins/modulo.go +++ b/pkg/vm/builtins/modulo.go @@ -534,6 +534,7 @@ func FillMemory(mem *memory.Memory, addModInputAddress memory.MemoryAddress, nAd } addModIndex, mulModIndex := uint64(0), uint64(0) + nComputedMulGates := uint64(0) for addModIndex < nAddMods || mulModIndex < nMulMods { if addModIndex < nAddMods && addModBuiltinRunner != nil { res, err := addModBuiltinRunner.fillValue(mem, addModBuiltinInputs, int(addModIndex), Add) @@ -553,8 +554,37 @@ func FillMemory(mem *memory.Memory, addModInputAddress memory.MemoryAddress, nAd if res == 0 { return fmt.Errorf("MulMod builtin: Could not fill the values table") } + if res == 2 && nComputedMulGates == 0 { + nComputedMulGates = mulModIndex + } mulModIndex++ } + + if mulModBuiltinRunner != nil { + if nComputedMulGates == 0 { + nComputedMulGates = mulModBuiltinInputs.n + if nComputedMulGates == 0 { + nComputedMulGates = nMulMods + } + mulModBuiltinInputs.n = nComputedMulGates + mulModBuiltinRunner.fillOffsets(mem, mulModBuiltinInputs.offsetsPtr, nMulMods, nComputedMulGates-nMulMods) + } else { + if mulModBuiltinRunner.batchSize != 1 { + return fmt.Errorf("MulMod builtin: Inverse failure is supported only at batch_size == 1") + } + } + mulModBuiltinInputs.n = nComputedMulGates + mulModInputNAddr, err := mulModInputAddress.AddOffset(int16(N_OFFSET)) + if err != nil { + return err + } + mv := memory.MemoryValueFromFieldElement(new(fp.Element).SetUint64(nComputedMulGates)) + if err := mem.WriteToAddress(&mulModInputNAddr, &mv); err != nil { + return err + } + + mulModBuiltinRunner.fillInputs(mem, mulModInputAddress, mulModBuiltinInputs) + } } return nil } From 37bc6bfa4e474b51e38b28208afde59d2e47ad86 Mon Sep 17 00:00:00 2001 From: Sh0g0-1758 Date: Tue, 1 Oct 2024 18:40:55 +0530 Subject: [PATCH 07/12] Done with tests --- pkg/hintrunner/core/hint_test.go | 129 ++++++++++++++++++++++++++++++- pkg/vm/builtins/modulo.go | 8 +- 2 files changed, 132 insertions(+), 5 deletions(-) diff --git a/pkg/hintrunner/core/hint_test.go b/pkg/hintrunner/core/hint_test.go index 8b1eb55e2..39dbe0796 100644 --- a/pkg/hintrunner/core/hint_test.go +++ b/pkg/hintrunner/core/hint_test.go @@ -752,10 +752,10 @@ func TestEvalCircuit(t *testing.T) { vm.Context.Ap = 0 vm.Context.Fp = 0 - // Test : p = 2^96 + 1 + // Test : p = 2^3 + 1 // Note that the calculations are performed based on the offsets that we provide // x1 = 1 - // x2 = 2^96 + 2 + // x2 = 2^3 + 2 // x3 = 2 // Values Array @@ -798,8 +798,8 @@ func TestEvalCircuit(t *testing.T) { utils.WriteTo(vm, VM.ExecutionSegment, 45, mem.MemoryValueFromInt(24)) // ((x2 - x1) / x3 + x1 / x3) utils.WriteTo(vm, VM.ExecutionSegment, 46, mem.MemoryValueFromInt(28)) // ((x2 - x1) / x3 + x1 / x3) * x3 - AddModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 96, 1, builtins.Add)) - MulModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 96, 1, builtins.Mul)) + AddModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 3, 1, builtins.Add)) + MulModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 3, 1, builtins.Mul)) /* The Add and Mul Mod builtin structure are defined as: @@ -903,6 +903,127 @@ func TestEvalCircuit(t *testing.T) { ) }) + t.Run("test mod_builtin_runner (4)", func(t *testing.T) { + vm := VM.DefaultVirtualMachine() + + vm.Context.Ap = 0 + vm.Context.Fp = 0 + + // Test : p = 2^3 + 1 + // Note that the calculations are performed based on the offsets that we provide + // x1 = 8 + // x2 = 2^3 + 2 + // x3 = 2 + + // Values Array + // x1 = UInt384(8,0,0,0) + utils.WriteTo(vm, VM.ExecutionSegment, 0, mem.MemoryValueFromInt(8)) + utils.WriteTo(vm, VM.ExecutionSegment, 1, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 3, mem.MemoryValueFromInt(0)) + + // x2 = UInt384(2,1,0,0) + utils.WriteTo(vm, VM.ExecutionSegment, 4, mem.MemoryValueFromInt(2)) + utils.WriteTo(vm, VM.ExecutionSegment, 5, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, VM.ExecutionSegment, 6, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 7, mem.MemoryValueFromInt(0)) + + // x3 = UInt384(2,0,0,0) + utils.WriteTo(vm, VM.ExecutionSegment, 8, mem.MemoryValueFromInt(2)) + utils.WriteTo(vm, VM.ExecutionSegment, 9, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 10, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, VM.ExecutionSegment, 11, mem.MemoryValueFromInt(0)) + + // 20 unallocated memory cells for res and other calculations + + // AddMod Offsets Array + utils.WriteTo(vm, VM.ExecutionSegment, 32, mem.MemoryValueFromInt(0)) // x1 + utils.WriteTo(vm, VM.ExecutionSegment, 33, mem.MemoryValueFromInt(12)) // x2 - x1 + utils.WriteTo(vm, VM.ExecutionSegment, 34, mem.MemoryValueFromInt(4)) // x2 + utils.WriteTo(vm, VM.ExecutionSegment, 35, mem.MemoryValueFromInt(16)) // (x2 - x1) / x3 + utils.WriteTo(vm, VM.ExecutionSegment, 36, mem.MemoryValueFromInt(20)) // x1 / x3 + utils.WriteTo(vm, VM.ExecutionSegment, 37, mem.MemoryValueFromInt(24)) // (x2 - x1) / x3 + x1 / x3 + + // MulMod Offsets Array + utils.WriteTo(vm, VM.ExecutionSegment, 38, mem.MemoryValueFromInt(8)) // x3 + utils.WriteTo(vm, VM.ExecutionSegment, 39, mem.MemoryValueFromInt(16)) // (x2 - x1) / x3 + utils.WriteTo(vm, VM.ExecutionSegment, 40, mem.MemoryValueFromInt(12)) // (x2 - x1) + utils.WriteTo(vm, VM.ExecutionSegment, 41, mem.MemoryValueFromInt(8)) // x3 + utils.WriteTo(vm, VM.ExecutionSegment, 42, mem.MemoryValueFromInt(20)) // x1 / x3 + utils.WriteTo(vm, VM.ExecutionSegment, 43, mem.MemoryValueFromInt(0)) // x1 + utils.WriteTo(vm, VM.ExecutionSegment, 44, mem.MemoryValueFromInt(8)) // x3 + utils.WriteTo(vm, VM.ExecutionSegment, 45, mem.MemoryValueFromInt(24)) // ((x2 - x1) / x3 + x1 / x3) + utils.WriteTo(vm, VM.ExecutionSegment, 46, mem.MemoryValueFromInt(28)) // ((x2 - x1) / x3 + x1 / x3) * x3 + + AddModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 3, 1, builtins.Add)) + MulModBuiltin := vm.Memory.AllocateBuiltinSegment(builtins.NewModBuiltin(1, 3, 1, builtins.Mul)) + + /* + The Add and Mul Mod builtin structure are defined as: + struct ModBuiltin { + p: UInt384, // The modulus. + values_ptr: UInt384*, // A pointer to input values, the intermediate results and the output. + offsets_ptr: felt*, // A pointer to offsets inside the values array, defining the circuit. + // The offsets array should contain 3 * n elements. + n: felt, // The number of operations to perform. + } + */ + + // add_mod_ptr + // p = UInt384(1,1,0,0) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 0, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 1, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 3, mem.MemoryValueFromInt(0)) + + // values_ptr + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 4, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 0})) + + // offsets_ptr + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 5, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 32})) + + // n + utils.WriteTo(vm, AddModBuiltin.SegmentIndex, 6, mem.MemoryValueFromInt(2)) + + // mul_mod_ptr + // p = UInt384(1,1,0,0) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 0, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 1, mem.MemoryValueFromInt(1)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 2, mem.MemoryValueFromInt(0)) + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 3, mem.MemoryValueFromInt(0)) + + // values_ptr + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 4, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 0})) + + // offsets_ptr + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 5, mem.MemoryValueFromMemoryAddress(&mem.MemoryAddress{SegmentIndex: VM.ExecutionSegment, Offset: 38})) + + // n + utils.WriteTo(vm, MulModBuiltin.SegmentIndex, 6, mem.MemoryValueFromInt(3)) + + // To get the address of mul_mod_ptr and add_mod_ptr + utils.WriteTo(vm, VM.ExecutionSegment, 47, mem.MemoryValueFromSegmentAndOffset(AddModBuiltin.SegmentIndex, 0)) + utils.WriteTo(vm, VM.ExecutionSegment, 48, mem.MemoryValueFromSegmentAndOffset(MulModBuiltin.SegmentIndex, 0)) + + var addRef hinter.ApCellRef = 47 + var mulRef hinter.ApCellRef = 48 + + nAddMods := hinter.Immediate(f.NewElement(2)) + nMulMods := hinter.Immediate(f.NewElement(3)) + addModPtrAddr := hinter.Deref{Deref: addRef} + mulModPtrAddr := hinter.Deref{Deref: mulRef} + + hint := EvalCircuit{ + AddModN: nAddMods, + AddModPtr: addModPtrAddr, + MulModN: nMulMods, + MulModPtr: mulModPtrAddr, + } + + err := hint.Execute(vm, nil) + require.ErrorContains(t, err, "expected integer at address") + }) + } func TestU256InvModN(t *testing.T) { diff --git a/pkg/vm/builtins/modulo.go b/pkg/vm/builtins/modulo.go index 21384f279..290342b1e 100644 --- a/pkg/vm/builtins/modulo.go +++ b/pkg/vm/builtins/modulo.go @@ -3,6 +3,7 @@ package builtins import ( "fmt" "math/big" + "strings" "github.com/NethermindEth/cairo-vm-go/pkg/utils" @@ -340,7 +341,12 @@ func (m *ModBuiltin) fillValue(mem *memory.Memory, inputs ModBuiltinInputs, inde } addresses = append(addresses, addr) // do not check for error, as the value might not be in memory - _, value, _ := m.readNWordsValue(mem, addr) + _, value, err := m.readNWordsValue(mem, addr) + if err != nil { + if strings.Contains(err.Error(), "expected integer at address") { + return 0, err + } + } values = append(values, value) } From 30649bb22d3a92fdf46418276fbf631de847b565 Mon Sep 17 00:00:00 2001 From: Sh0g0-1758 Date: Tue, 1 Oct 2024 18:44:23 +0530 Subject: [PATCH 08/12] lint --- pkg/vm/builtins/modulo.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/vm/builtins/modulo.go b/pkg/vm/builtins/modulo.go index 290342b1e..a47d29de9 100644 --- a/pkg/vm/builtins/modulo.go +++ b/pkg/vm/builtins/modulo.go @@ -573,7 +573,9 @@ func FillMemory(mem *memory.Memory, addModInputAddress memory.MemoryAddress, nAd nComputedMulGates = nMulMods } mulModBuiltinInputs.n = nComputedMulGates - mulModBuiltinRunner.fillOffsets(mem, mulModBuiltinInputs.offsetsPtr, nMulMods, nComputedMulGates-nMulMods) + if err := mulModBuiltinRunner.fillOffsets(mem, mulModBuiltinInputs.offsetsPtr, nMulMods, nComputedMulGates-nMulMods); err != nil { + return err + } } else { if mulModBuiltinRunner.batchSize != 1 { return fmt.Errorf("MulMod builtin: Inverse failure is supported only at batch_size == 1") @@ -589,7 +591,9 @@ func FillMemory(mem *memory.Memory, addModInputAddress memory.MemoryAddress, nAd return err } - mulModBuiltinRunner.fillInputs(mem, mulModInputAddress, mulModBuiltinInputs) + if err := mulModBuiltinRunner.fillInputs(mem, mulModInputAddress, mulModBuiltinInputs); err != nil { + return err + } } } return nil From 4394b3c4252522c1d113c87312c7a6add70faa43 Mon Sep 17 00:00:00 2001 From: Sh0g0-1758 Date: Wed, 2 Oct 2024 17:04:38 +0530 Subject: [PATCH 09/12] nit --- pkg/vm/builtins/modulo.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/vm/builtins/modulo.go b/pkg/vm/builtins/modulo.go index a47d29de9..719d9d584 100644 --- a/pkg/vm/builtins/modulo.go +++ b/pkg/vm/builtins/modulo.go @@ -318,7 +318,9 @@ func (m *ModBuiltin) writeNWordsValue(mem *memory.Memory, addr memory.MemoryAddr } // Fills a value in the values table, if exactly one value is missing. -// Returns true on success or if all values are already known. +// Returns 1 on success or if all values are already known. +// Returns 0 if there is an error or is the value cannot be filled +// Returns 2 when the mulModBuiltin has a zero divisor. // Given known, res, p fillValue tries to compute the minimal integer operand x which // satisfies the equation op(x,known) = res + k*p for some k in {0,1,...,self.k_bound-1}. func (m *ModBuiltin) fillValue(mem *memory.Memory, inputs ModBuiltinInputs, index int, op ModBuiltinType) (int, error) { From 34ba25f8e9b04299fbc3542f1bdd188e96077ce1 Mon Sep 17 00:00:00 2001 From: Sh0g0-1758 Date: Wed, 2 Oct 2024 17:07:48 +0530 Subject: [PATCH 10/12] nit --- pkg/vm/builtins/modulo.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/vm/builtins/modulo.go b/pkg/vm/builtins/modulo.go index 719d9d584..b8879af5e 100644 --- a/pkg/vm/builtins/modulo.go +++ b/pkg/vm/builtins/modulo.go @@ -342,7 +342,8 @@ func (m *ModBuiltin) fillValue(mem *memory.Memory, inputs ModBuiltinInputs, inde return 0, err } addresses = append(addresses, addr) - // do not check for error, as the value might not be in memory + // do not check for all errors, as the value might not be in memory + // only check for the error when the value in memory exceeds 2**wordBitLen _, value, err := m.readNWordsValue(mem, addr) if err != nil { if strings.Contains(err.Error(), "expected integer at address") { From 3b4d1899f7ef9587866d80cf41b4469b38b8e79a Mon Sep 17 00:00:00 2001 From: Sh0g0-1758 Date: Wed, 2 Oct 2024 19:25:56 +0530 Subject: [PATCH 11/12] nit --- pkg/vm/builtins/modulo.go | 77 ++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/pkg/vm/builtins/modulo.go b/pkg/vm/builtins/modulo.go index b8879af5e..935d16ec1 100644 --- a/pkg/vm/builtins/modulo.go +++ b/pkg/vm/builtins/modulo.go @@ -492,6 +492,8 @@ func FillMemory(mem *memory.Memory, addModInputAddress memory.MemoryAddress, nAd var addModBuiltinRunner *ModBuiltin var mulModBuiltinRunner *ModBuiltin + var addModBuiltinInputs, mulModBuiltinInputs ModBuiltinInputs + var err error if nAddMods != 0 { addModBuiltinSegment, ok := mem.FindSegmentWithBuiltin("AddMod") @@ -502,6 +504,17 @@ func FillMemory(mem *memory.Memory, addModInputAddress memory.MemoryAddress, nAd if !ok { return fmt.Errorf("addModBuiltinRunner is not a ModBuiltin") } + + addModBuiltinInputs, err = addModBuiltinRunner.readInputs(mem, addModInputAddress, true) + if err != nil { + return err + } + if err := addModBuiltinRunner.fillInputs(mem, addModInputAddress, addModBuiltinInputs); err != nil { + return err + } + if err := addModBuiltinRunner.fillOffsets(mem, addModBuiltinInputs.offsetsPtr, nAddMods, addModBuiltinInputs.n-nAddMods); err != nil { + return err + } } else { addModBuiltinRunner = nil } @@ -515,31 +528,13 @@ func FillMemory(mem *memory.Memory, addModInputAddress memory.MemoryAddress, nAd if !ok { return fmt.Errorf("mulModBuiltinRunner is not a ModBuiltin") } - } else { - mulModBuiltinRunner = nil - } - - var addModBuiltinInputs, mulModBuiltinInputs ModBuiltinInputs - var err error - - if addModBuiltinRunner != nil { - addModBuiltinInputs, err = addModBuiltinRunner.readInputs(mem, addModInputAddress, true) - if err != nil { - return err - } - if err := addModBuiltinRunner.fillInputs(mem, addModInputAddress, addModBuiltinInputs); err != nil { - return err - } - if err := addModBuiltinRunner.fillOffsets(mem, addModBuiltinInputs.offsetsPtr, nAddMods, addModBuiltinInputs.n-nAddMods); err != nil { - return err - } - } - if mulModBuiltinRunner != nil { mulModBuiltinInputs, err = mulModBuiltinRunner.readInputs(mem, mulModInputAddress, true) if err != nil { return err } + } else { + mulModBuiltinRunner = nil } addModIndex, mulModIndex := uint64(0), uint64(0) @@ -568,35 +563,35 @@ func FillMemory(mem *memory.Memory, addModInputAddress memory.MemoryAddress, nAd } mulModIndex++ } + } - if mulModBuiltinRunner != nil { + if mulModBuiltinRunner != nil { + if nComputedMulGates == 0 { + nComputedMulGates = mulModBuiltinInputs.n if nComputedMulGates == 0 { - nComputedMulGates = mulModBuiltinInputs.n - if nComputedMulGates == 0 { - nComputedMulGates = nMulMods - } - mulModBuiltinInputs.n = nComputedMulGates - if err := mulModBuiltinRunner.fillOffsets(mem, mulModBuiltinInputs.offsetsPtr, nMulMods, nComputedMulGates-nMulMods); err != nil { - return err - } - } else { - if mulModBuiltinRunner.batchSize != 1 { - return fmt.Errorf("MulMod builtin: Inverse failure is supported only at batch_size == 1") - } + nComputedMulGates = nMulMods } mulModBuiltinInputs.n = nComputedMulGates - mulModInputNAddr, err := mulModInputAddress.AddOffset(int16(N_OFFSET)) - if err != nil { + if err := mulModBuiltinRunner.fillOffsets(mem, mulModBuiltinInputs.offsetsPtr, nMulMods, nComputedMulGates-nMulMods); err != nil { return err } - mv := memory.MemoryValueFromFieldElement(new(fp.Element).SetUint64(nComputedMulGates)) - if err := mem.WriteToAddress(&mulModInputNAddr, &mv); err != nil { - return err + } else { + if mulModBuiltinRunner.batchSize != 1 { + return fmt.Errorf("MulMod builtin: Inverse failure is supported only at batch_size == 1") } + } + mulModBuiltinInputs.n = nComputedMulGates + mulModInputNAddr, err := mulModInputAddress.AddOffset(int16(N_OFFSET)) + if err != nil { + return err + } + mv := memory.MemoryValueFromFieldElement(new(fp.Element).SetUint64(nComputedMulGates)) + if err := mem.WriteToAddress(&mulModInputNAddr, &mv); err != nil { + return err + } - if err := mulModBuiltinRunner.fillInputs(mem, mulModInputAddress, mulModBuiltinInputs); err != nil { - return err - } + if err := mulModBuiltinRunner.fillInputs(mem, mulModInputAddress, mulModBuiltinInputs); err != nil { + return err } } return nil From 3d4f7ed9a5e05ce60656d34fbc94698e4c4829e4 Mon Sep 17 00:00:00 2001 From: Sh0g0-1758 Date: Wed, 2 Oct 2024 19:32:12 +0530 Subject: [PATCH 12/12] nit --- pkg/vm/builtins/modulo.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/vm/builtins/modulo.go b/pkg/vm/builtins/modulo.go index 935d16ec1..450330724 100644 --- a/pkg/vm/builtins/modulo.go +++ b/pkg/vm/builtins/modulo.go @@ -565,6 +565,7 @@ func FillMemory(mem *memory.Memory, addModInputAddress memory.MemoryAddress, nAd } } + // TODO: Investigate tests that fail when nComputedMulGates is not implemented if mulModBuiltinRunner != nil { if nComputedMulGates == 0 { nComputedMulGates = mulModBuiltinInputs.n