From 787ee3a769d0bd1d85613610c92c80c3e0de067c Mon Sep 17 00:00:00 2001 From: Ekaterina Pavlova Date: Mon, 28 Oct 2024 16:08:01 +0300 Subject: [PATCH] vm: fix MODPOW operation Close #3612 Signed-off-by: Ekaterina Pavlova --- pkg/compiler/syscall_test.go | 4 ++-- pkg/vm/vm.go | 11 ++++++++--- pkg/vm/vm_test.go | 6 ++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/pkg/compiler/syscall_test.go b/pkg/compiler/syscall_test.go index 0995eb8bd7..4bc87feef4 100644 --- a/pkg/compiler/syscall_test.go +++ b/pkg/compiler/syscall_test.go @@ -375,9 +375,9 @@ func TestOpcode(t *testing.T) { }` eval(t, src, []stackitem.Item{ stackitem.Make(1), - stackitem.Make(2), + stackitem.Make(-3), stackitem.Make(1), - stackitem.Make(2), + stackitem.Make(-3), stackitem.Make(52), }) }) diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index 4149f9ac64..ff0ddcaa36 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -1036,6 +1036,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro modulus := v.estack.Pop().BigInt() exponent := v.estack.Pop().BigInt() base := v.estack.Pop().BigInt() + absModulus := new(big.Int).Abs(modulus) res := new(big.Int) switch exponent.Cmp(bigMinusOne) { case -1: @@ -1044,17 +1045,21 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro if base.Cmp(bigZero) <= 0 { panic("invalid base") } - if modulus.Cmp(bigTwo) < 0 { + if absModulus.Cmp(bigTwo) < 0 { panic("invalid modulus") } - if res.ModInverse(base, modulus) == nil { + if res.ModInverse(base, absModulus) == nil { panic("base and modulus are not relatively prime") } case 1: if modulus.Sign() == 0 { panic("zero modulus") // https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger.modpow?view=net-6.0#exceptions } - res.Exp(base, exponent, modulus) + res.Exp(base, exponent, absModulus) + + if base.Sign() < 0 && exponent.Bit(0) == 1 { + res.Sub(res, absModulus) + } } v.estack.PushItem(stackitem.NewBigInteger(res)) diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index 38e29f1ff5..8337120438 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -747,9 +747,11 @@ func TestMODMUL(t *testing.T) { func TestMODPOW(t *testing.T) { prog := makeProgram(opcode.MODPOW) t.Run("good, positive base", getTestFuncForVM(prog, 1, 3, 4, 5)) - t.Run("good, negative base", getTestFuncForVM(prog, 2, -3, 5, 5)) + t.Run("good, negative base", getTestFuncForVM(prog, -3, -3, 5, 5)) + t.Run("good, negative base", getTestFuncForVM(prog, -1, -1, 3, 3)) t.Run("good, positive base, negative mod", getTestFuncForVM(prog, 1, 3, 4, -5)) - t.Run("good, negative base, negative mod", getTestFuncForVM(prog, 2, -3, 5, -5)) + t.Run("good, negative base, negative mod", getTestFuncForVM(prog, -3, -3, 5, -5)) + t.Run("good, negative base, negative mod", getTestFuncForVM(prog, -2, -5, 5, -3)) t.Run("bad, big negative exponent", getTestFuncForVM(prog, nil, 3, -2, 5)) t.Run("bad, zero modulus", getTestFuncForVM(prog, nil, 3, 4, 0))