Index: src/script/interpreter.cpp =================================================================== --- src/script/interpreter.cpp +++ src/script/interpreter.cpp @@ -29,6 +29,64 @@ return false; } +inline uint8_t make_rshift_mask(size_t n) { + static uint8_t mask[] = {0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80}; + return mask[n]; +} + +inline uint8_t make_lshift_mask(size_t n) { + static uint8_t mask[] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01}; + return mask[n]; +} + +static valtype RShift(const valtype &x, int n) { + int bit_shift_left = n % 8; + int byte_shift_left = n / 8; + + uint8_t mask = make_rshift_mask(bit_shift_left); + uint8_t overflow_mask = ~mask; + + valtype result(x.size(), 0x00); + for (int i = x.size() - 1; i >= 0; i--) { + int k = i - byte_shift_left; + if (k >= 0) { + uint8_t val = (x[i] & mask); + val >>= bit_shift_left; + result[k] |= val; + } + if (k - 1 >= 0) { + uint8_t carryval = (x[i] & overflow_mask); + carryval <<= 8 - bit_shift_left; + result[k - 1] |= carryval; + } + } + return result; +} + +static valtype LShift(const valtype &x, int n) { + int bit_shift_right = n % 8; + int byte_shift_right = n / 8; + + uint8_t mask = make_lshift_mask(bit_shift_right); + uint8_t overflow_mask = ~mask; + + valtype result(x.size(), 0x00); + for (int i = 0; i < (int)x.size(); i++) { + int k = i + byte_shift_right; + if (k < (int)x.size()) { + uint8_t val = (x[i] & mask); + val <<= bit_shift_right; + result[k] |= val; + } + if (k + 1 < (int)x.size()) { + uint8_t carryval = (x[i] & overflow_mask); + carryval >>= 8 - bit_shift_right; + result[k + 1] |= carryval; + } + } + return result; +} + /** * Script is a stack machine (like Forth) that evaluates a predicate * returning a bool indicating valid or not. There are no loops. @@ -94,10 +152,10 @@ return true; case OP_LSHIFT: - return true; + return false; case OP_RSHIFT: - return true; + return false; default: break; @@ -1234,6 +1292,44 @@ } } break; + case OP_LSHIFT: { + // (x n -- out) + if (stack.size() < 2) { + return set_error( + serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + } + + const valtype x = stacktop(-2); + CScriptNum n(stacktop(-1), fRequireMinimal); + if (n < 0) { + return set_error(serror, + SCRIPT_ERR_INVALID_NUMBER_RANGE); + } + + popstack(stack); + popstack(stack); + stack.push_back(LShift(x, n.getint())); + } break; + + case OP_RSHIFT: { + // (x n -- out) + if (stack.size() < 2) { + return set_error( + serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + } + + const valtype x = stacktop(-2); + CScriptNum n(stacktop(-1), fRequireMinimal); + if (n < 0) { + return set_error(serror, + SCRIPT_ERR_INVALID_NUMBER_RANGE); + } + + popstack(stack); + popstack(stack); + stack.push_back(RShift(x, n.getint())); + } break; + default: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } Index: src/test/data/script_tests.json =================================================================== --- src/test/data/script_tests.json +++ src/test/data/script_tests.json @@ -935,9 +935,9 @@ ["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 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 LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "LSHIFT enabled"], ["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "RSHIFT disabled"], -["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MAGNETIC_OPCODES", "DISABLED_OPCODE", "RSHIFT disabled"], +["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "RSHIFT enabled"], ["Bitwise opcodes"], ["AND"], @@ -975,11 +975,11 @@ ["LSHIFT"], ["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], -["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "DISABLED_OPCODE", "disabled"], +["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "simple LSHIFT"], ["RSHIFT"], ["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], -["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "DISABLED_OPCODE", "disabled"], +["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "simple RSHIFT"], ["INVERT"], 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); } @@ -80,6 +83,30 @@ return r; } +// Expects str to contain 8*n bits. +static valtype to_bitpattern(const char *str) { + size_t len = strlen(str); + + valtype val((len - 1) / 8 + 1, 0); + + const char *pin = &str[len - 1]; + for (size_t i = 0; i < len; i++) { + + int byte_idx = i / 8; + int bit_idx = i % 8; + + int8_t mask = 1 << bit_idx; + + if (*pin == '0') { + val[byte_idx] &= ~mask; + } else { + val[byte_idx] |= mask; + } + pin--; + } + return val; +} + BOOST_AUTO_TEST_CASE(negative_valtype_test) { // Test zero values BOOST_CHECK(NegativeValtype({}) == valtype{}); @@ -392,6 +419,157 @@ CheckAllBitwiseOpErrors({b, {}}, SCRIPT_ERR_INVALID_OPERAND_SIZE); } +static void CheckShiftOp(const valtype &x, const valtype &n, opcodetype op, + const valtype &expected) { + CheckBinaryOp(x, n, op, expected); +} + +BOOST_AUTO_TEST_CASE(lshift_test) { + CheckShiftOp({}, {}, OP_LSHIFT, {}); + CheckShiftOp({}, {0x01}, OP_LSHIFT, {}); + CheckShiftOp({}, {0x02}, OP_LSHIFT, {}); + CheckShiftOp({}, {0x07}, OP_LSHIFT, {}); + CheckShiftOp({}, {0x08}, OP_LSHIFT, {}); + CheckShiftOp({}, {0x09}, OP_LSHIFT, {}); + CheckShiftOp({}, {0x0F}, OP_LSHIFT, {}); + CheckShiftOp({}, {0x10}, OP_LSHIFT, {}); + CheckShiftOp({}, {0x11}, OP_LSHIFT, {}); + + CheckShiftOp({0xFF}, {}, OP_LSHIFT, to_bitpattern("11111111")); + CheckShiftOp({0xFF}, {0x01}, OP_LSHIFT, to_bitpattern("11111110")); + CheckShiftOp({0xFF}, {0x02}, OP_LSHIFT, to_bitpattern("11111100")); + CheckShiftOp({0xFF}, {0x03}, OP_LSHIFT, to_bitpattern("11111000")); + CheckShiftOp({0xFF}, {0x04}, OP_LSHIFT, to_bitpattern("11110000")); + CheckShiftOp({0xFF}, {0x05}, OP_LSHIFT, to_bitpattern("11100000")); + CheckShiftOp({0xFF}, {0x06}, OP_LSHIFT, to_bitpattern("11000000")); + CheckShiftOp({0xFF}, {0x07}, OP_LSHIFT, to_bitpattern("10000000")); + CheckShiftOp({0xFF}, {0x08}, OP_LSHIFT, to_bitpattern("00000000")); + + CheckShiftOp({0xFF}, {0x01}, OP_LSHIFT, {0xFE}); + CheckShiftOp({0xFF}, {0x02}, OP_LSHIFT, {0xFC}); + CheckShiftOp({0xFF}, {0x03}, OP_LSHIFT, {0xF8}); + CheckShiftOp({0xFF}, {0x04}, OP_LSHIFT, {0xF0}); + CheckShiftOp({0xFF}, {0x05}, OP_LSHIFT, {0xE0}); + CheckShiftOp({0xFF}, {0x06}, OP_LSHIFT, {0xC0}); + CheckShiftOp({0xFF}, {0x07}, OP_LSHIFT, {0x80}); + CheckShiftOp( + {0xFF}, {0x08}, OP_LSHIFT, + {0x00}); // bitpattern, not a number so not reduced to zero bytes + + // valtype {0x9F, 0x11, 0xF5, 0x55} is a bit pattern + // "01010101111101010001000110011111" + + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {}, OP_LSHIFT, + to_bitpattern("01010101111101010001000110011111")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x01}, OP_LSHIFT, + to_bitpattern("10101011111010100010001100111110")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x02}, OP_LSHIFT, + to_bitpattern("01010111110101000100011001111100")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x03}, OP_LSHIFT, + to_bitpattern("10101111101010001000110011111000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x04}, OP_LSHIFT, + to_bitpattern("01011111010100010001100111110000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x05}, OP_LSHIFT, + to_bitpattern("10111110101000100011001111100000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x06}, OP_LSHIFT, + to_bitpattern("01111101010001000110011111000000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x07}, OP_LSHIFT, + to_bitpattern("11111010100010001100111110000000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x08}, OP_LSHIFT, + to_bitpattern("11110101000100011001111100000000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x09}, OP_LSHIFT, + to_bitpattern("11101010001000110011111000000000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x0A}, OP_LSHIFT, + to_bitpattern("11010100010001100111110000000000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x0B}, OP_LSHIFT, + to_bitpattern("10101000100011001111100000000000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x0C}, OP_LSHIFT, + to_bitpattern("01010001000110011111000000000000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x0D}, OP_LSHIFT, + to_bitpattern("10100010001100111110000000000000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x0E}, OP_LSHIFT, + to_bitpattern("01000100011001111100000000000000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x0F}, OP_LSHIFT, + to_bitpattern("10001000110011111000000000000000")); + + CheckErrorForAllFlags({valtype{0x12, 0x34}}, + CScript() << OP_1NEGATE << OP_LSHIFT, + SCRIPT_ERR_INVALID_NUMBER_RANGE); +} + +BOOST_AUTO_TEST_CASE(rshift_test) { + CheckShiftOp({}, {}, OP_RSHIFT, {}); + CheckShiftOp({}, {0x01}, OP_RSHIFT, {}); + CheckShiftOp({}, {0x02}, OP_RSHIFT, {}); + CheckShiftOp({}, {0x07}, OP_RSHIFT, {}); + CheckShiftOp({}, {0x08}, OP_RSHIFT, {}); + CheckShiftOp({}, {0x09}, OP_RSHIFT, {}); + CheckShiftOp({}, {0x0F}, OP_RSHIFT, {}); + CheckShiftOp({}, {0x10}, OP_RSHIFT, {}); + CheckShiftOp({}, {0x11}, OP_RSHIFT, {}); + + CheckShiftOp({0xFF}, {}, OP_RSHIFT, to_bitpattern("11111111")); + CheckShiftOp({0xFF}, {0x01}, OP_RSHIFT, to_bitpattern("01111111")); + CheckShiftOp({0xFF}, {0x02}, OP_RSHIFT, to_bitpattern("00111111")); + CheckShiftOp({0xFF}, {0x03}, OP_RSHIFT, to_bitpattern("00011111")); + CheckShiftOp({0xFF}, {0x04}, OP_RSHIFT, to_bitpattern("00001111")); + CheckShiftOp({0xFF}, {0x05}, OP_RSHIFT, to_bitpattern("00000111")); + CheckShiftOp({0xFF}, {0x06}, OP_RSHIFT, to_bitpattern("00000011")); + CheckShiftOp({0xFF}, {0x07}, OP_RSHIFT, to_bitpattern("00000001")); + CheckShiftOp({0xFF}, {0x08}, OP_RSHIFT, to_bitpattern("00000000")); + + CheckShiftOp({0xFF}, {0x01}, OP_RSHIFT, {0x7F}); + CheckShiftOp({0xFF}, {0x02}, OP_RSHIFT, {0x3F}); + CheckShiftOp({0xFF}, {0x03}, OP_RSHIFT, {0x1F}); + CheckShiftOp({0xFF}, {0x04}, OP_RSHIFT, {0x0F}); + CheckShiftOp({0xFF}, {0x05}, OP_RSHIFT, {0x07}); + CheckShiftOp({0xFF}, {0x06}, OP_RSHIFT, {0x03}); + CheckShiftOp({0xFF}, {0x07}, OP_RSHIFT, {0x01}); + CheckShiftOp( + {0xFF}, {0x08}, OP_RSHIFT, + {0x00}); // bitpattern, not a number so not reduced to zero bytes + + // valtype {0x9F, 0x11, 0xF5, 0x55} is a bit pattern + // "01010101111101010001000110011111" + + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {}, OP_RSHIFT, + to_bitpattern("01010101111101010001000110011111")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x01}, OP_RSHIFT, + to_bitpattern("00101010111110101000100011001111")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x02}, OP_RSHIFT, + to_bitpattern("00010101011111010100010001100111")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x03}, OP_RSHIFT, + to_bitpattern("00001010101111101010001000110011")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x04}, OP_RSHIFT, + to_bitpattern("00000101010111110101000100011001")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x05}, OP_RSHIFT, + to_bitpattern("00000010101011111010100010001100")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x06}, OP_RSHIFT, + to_bitpattern("00000001010101111101010001000110")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x07}, OP_RSHIFT, + to_bitpattern("00000000101010111110101000100011")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x08}, OP_RSHIFT, + to_bitpattern("00000000010101011111010100010001")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x09}, OP_RSHIFT, + to_bitpattern("00000000001010101111101010001000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x0A}, OP_RSHIFT, + to_bitpattern("00000000000101010111110101000100")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x0B}, OP_RSHIFT, + to_bitpattern("00000000000010101011111010100010")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x0C}, OP_RSHIFT, + to_bitpattern("00000000000001010101111101010001")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x0D}, OP_RSHIFT, + to_bitpattern("00000000000000101010111110101000")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x0E}, OP_RSHIFT, + to_bitpattern("00000000000000010101011111010100")); + CheckShiftOp({0x9F, 0x11, 0xF5, 0x55}, {0x0F}, OP_RSHIFT, + to_bitpattern("00000000000000001010101111101010")); + + CheckErrorForAllFlags({valtype{0x12, 0x34}}, + CScript() << OP_1NEGATE << OP_RSHIFT, + SCRIPT_ERR_INVALID_NUMBER_RANGE); +} + /** * String opcodes. */