Index: src/script/interpreter.cpp =================================================================== --- src/script/interpreter.cpp +++ src/script/interpreter.cpp @@ -97,7 +97,7 @@ return true; case OP_MUL: - return true; + return false; case OP_LSHIFT: return true; @@ -730,6 +730,7 @@ case OP_ADD: case OP_SUB: + case OP_MUL: case OP_DIV: case OP_MOD: case OP_BOOLAND: @@ -760,6 +761,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 @@ -935,7 +935,7 @@ ["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "2DIV disabled"], ["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MAGNETIC_OPCODES", "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"], @@ -1049,7 +1049,31 @@ ["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"], +["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 @@ -30,7 +30,9 @@ for (uint32_t flags : flagset) { ScriptError err = SCRIPT_ERR_OK; stacktype stack{original_stack}; - bool r = EvalScript(stack, script, flags, sigchecker, &err); + bool r = + EvalScript(stack, script, flags | SCRIPT_ENABLE_MAGNETIC_OPCODES, + sigchecker, &err); BOOST_CHECK(r); BOOST_CHECK(stack == expected); } @@ -41,7 +43,8 @@ BaseSignatureChecker sigchecker; ScriptError err = SCRIPT_ERR_OK; stacktype stack{original_stack}; - bool r = EvalScript(stack, script, flags, sigchecker, &err); + bool r = EvalScript(stack, script, flags | SCRIPT_ENABLE_MAGNETIC_OPCODES, + sigchecker, &err); BOOST_CHECK(!r); BOOST_CHECK_EQUAL(err, expected_error); } @@ -635,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) { @@ -769,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()