Index: src/script/interpreter.cpp =================================================================== --- src/script/interpreter.cpp +++ src/script/interpreter.cpp @@ -91,7 +91,7 @@ return true; case OP_MUL: - return true; + return false; case OP_LSHIFT: return true; @@ -724,6 +724,7 @@ case OP_ADD: case OP_SUB: + case OP_MUL: case OP_DIV: case OP_MOD: case OP_BOOLAND: @@ -754,6 +755,10 @@ bn = bn1 - bn2; break; + case OP_MUL: + bn = bn1 * bn2; + break; + case OP_DIV: // denominator must not be 0 if (bn2 == 0) { Index: src/script/script.h =================================================================== --- src/script/script.h +++ src/script/script.h @@ -277,6 +277,13 @@ return operator/(rhs.m_value); } + inline CScriptNum operator*(const int64_t &rhs) const { + return CScriptNum(m_value * rhs); + } + inline CScriptNum operator*(const CScriptNum &rhs) const { + return operator*(rhs.m_value); + } + inline CScriptNum operator%(const int64_t &rhs) const { return CScriptNum(m_value % rhs); } Index: src/test/data/script_tests.json =================================================================== --- src/test/data/script_tests.json +++ src/test/data/script_tests.json @@ -933,7 +933,7 @@ ["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "2MUL disabled"], ["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "2DIV disabled"], ["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "MUL disabled"], -["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MAGNETIC_OPCODES", "DISABLED_OPCODE", "MUL disabled"], +["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "MUL enabled"], ["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "LSHIFT disabled"], ["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MAGNETIC_OPCODES", "DISABLED_OPCODE", "LSHIFT disabled"], ["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "RSHIFT disabled"], @@ -1054,7 +1054,32 @@ ["MUL"], ["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], -["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "DISABLED_OPCODE", "disabled"], +["MUL", "4 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "INVALID_STACK_OPERATION", "no parameters"], +["2 MUL", "4 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "INVALID_STACK_OPERATION", "not enough parameters"], +["0x051234567890 2 MUL", "0 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "UNKNOWN_ERROR", "invalid param first"], +["2 0x051234567890 MUL", "0 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "UNKNOWN_ERROR", "invalid param second"], +["0x051234567890 0x051234567890 MUL", "0 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "UNKNOWN_ERROR", "both invalid param"], +["2 2 MUL", "4 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "single byte operands"], +["2 0x025624 MUL", "0x02AC48 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "single & double byte operands"], +["0x025624 2 MUL", "0x02AC48 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "single & double byte operands"], +["2 0x03563412 MUL", "0x03AC6824 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "single & triple byte operands"], +["0x03563412 2 MUL", "0x03AC6824 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "single & triple byte operands"], +["2 0x0478563412 MUL", "0x04F0AC6824 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "single & quad byte operands"], +["0x0478563412 2 MUL", "0x04F0AC6824 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "single & quad byte operands"], +["0x0478563412 0x0478563412 MUL", "0x0840D8F41DDC664B01 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "overflow"], +["0x04FFFFFF7F 0x04FFFFFF7F MUL", "0x0801000000FFFFFF3F EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "largest pos possible"], +["0x04FFFFFFFF 0x04FFFFFFFF MUL", "0x0801000000FFFFFF3F EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "largest neg possible"], +["0 478 MUL", "0 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "0 * anyvalue = 0"], +["478 0 MUL", "0 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "anyvalue * 0 = 0"], +["0 0 MUL", "0 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "0 * 0 = 0"], +["0x0180 478 MUL", "0 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "(neg 0) * anyvalue = 0"], +["1 478 MUL", "478 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "1 * anyvalue = anyvalue"], +["478 1 MUL", "478 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "anyvalue * 1 = anyvalue"], +["1 1 MUL", "1 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "1 * 1 = 1"], +["-1 478 MUL", "-478 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "-1 * anyvalue = -anyvalue"], +["4 -8 MUL", "-32 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "neg value second"], +["-4 8 MUL", "-32 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "neg value first"], +["-4 -8 MUL", "32 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "two neg value"], ["2MUL"], ["2 2MUL", "4 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], Index: src/test/opcode_tests.cpp =================================================================== --- src/test/opcode_tests.cpp +++ src/test/opcode_tests.cpp @@ -638,6 +638,30 @@ /** * Arithmetic Opcodes */ +static void CheckMul(const valtype &a, const valtype &b, + const valtype &expected) { + // Negative values for division + CheckBinaryOp(a, b, OP_MUL, expected); + CheckBinaryOp(a, NegativeValtype(b), OP_MUL, NegativeValtype(expected)); + CheckBinaryOp(NegativeValtype(a), b, OP_MUL, NegativeValtype(expected)); + CheckBinaryOp(NegativeValtype(a), NegativeValtype(b), OP_MUL, expected); + + // Commutativity + CheckBinaryOp(b, a, OP_MUL, expected); + CheckBinaryOp(b, NegativeValtype(a), OP_MUL, NegativeValtype(expected)); + CheckBinaryOp(NegativeValtype(b), a, OP_MUL, NegativeValtype(expected)); + CheckBinaryOp(NegativeValtype(b), NegativeValtype(a), OP_MUL, expected); + + // Multiplication identities + CheckBinaryOp(a, {0x01}, OP_MUL, a); + CheckBinaryOp(a, {0x81}, OP_MUL, NegativeValtype(a)); + CheckBinaryOp(a, {}, OP_MUL, {}); + + CheckBinaryOp({0x01}, b, OP_MUL, b); + CheckBinaryOp({0x81}, b, OP_MUL, NegativeValtype(b)); + CheckBinaryOp({}, b, OP_MUL, {}); +} + static void CheckDivMod(const valtype &a, const valtype &b, const valtype &divExpected, const valtype &modExpected) { @@ -772,4 +796,10 @@ {0xbb, 0xf0, 0x5d, 0x03}); } +BOOST_AUTO_TEST_CASE(mul_test) { + CheckMul({0xA0, 0xA0}, {0xF5, 0xE4}, + {0x20, 0xB9, 0xDD, 0x0C}); // -20A0*-64F5=0CDDB920 + CheckMul({0x02}, {0x56, 0x24}, {0xAC, 0x48}); +} + BOOST_AUTO_TEST_SUITE_END()