vm: fix MODPOW operation

Close #3612

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
This commit is contained in:
Ekaterina Pavlova 2024-10-30 23:02:28 +03:00
parent b8a65d3c37
commit cccbe843be
3 changed files with 12 additions and 4 deletions

View file

@ -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),
})
})

View file

@ -1055,6 +1055,12 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
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)
// https://github.com/nspcc-dev/neo-go/issues/3612
if base.Sign() < 0 && exponent.Bit(0) == 1 && res.Sign() != 0 {
absModulus := new(big.Int).Abs(modulus)
res.Sub(res, absModulus)
}
}
v.estack.PushItem(stackitem.NewBigInteger(res))

View file

@ -747,11 +747,12 @@ 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, 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("bad, big negative exponent", getTestFuncForVM(prog, nil, 3, -2, 5))
t.Run("bad, zero modulus", getTestFuncForVM(prog, nil, 3, 4, 0))
t.Run("zero result, negative base, even exponent", getTestFuncForVM(prog, 0, -2, 3, 8))
t.Run("inverse compatibility", func(t *testing.T) { // Tests are taken from C# node.
t.Run("bad mod", getTestFuncForVM(prog, nil, 1, -1, 0))
@ -760,6 +761,7 @@ func TestMODPOW(t *testing.T) {
t.Run("bad base", getTestFuncForVM(prog, nil, 0, -1, 1))
t.Run("no inverse exists", getTestFuncForVM(prog, nil, math.MaxUint16, -1, math.MaxUint8))
t.Run("good", getTestFuncForVM(prog, 52, 19, -1, 141))
t.Run("good", getTestFuncForVM(prog, 1, 5, -1, 4))
})
}