From 358a1bb49412fae88107e4d59beef9304248b6bc Mon Sep 17 00:00:00 2001 From: Steven Roose Date: Tue, 8 Jan 2019 13:47:26 +0000 Subject: [PATCH] Add OP_DETERMINISTICRANDOM --- src/script/interpreter.cpp | 55 +++++++++++++++++++++++++++++++++ src/script/script.cpp | 1 + src/script/script.h | 3 +- src/test/data/script_tests.json | 2 -- src/test/script_tests.cpp | 2 +- 5 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index b553cc6932..9c726c0d9b 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1071,6 +1071,61 @@ bool EvalScript(std::vector >& stack, const CScript& } break; + case OP_DETERMINISTICRANDOM: + { + if (stack.size() < 3) + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + + valtype vchSeed = stacktop(-3); + CScriptNum bnMin(stacktop(-2), fRequireMinimal); + CScriptNum bnMax(stacktop(-1), fRequireMinimal); + + if (bnMin > bnMax) + return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); + + if (bnMin == bnMax) { + popstack(stack); + popstack(stack); + popstack(stack); + stack.push_back(bnMin.getvch()); + break; + } + + // The range of the random source must be a multiple of the modulus + // to give every possible output value an equal possibility + uint64_t nMax = (bnMax-bnMin).getint(); + uint64_t nRange = (std::numeric_limits::max() / nMax) * nMax; + uint64_t nRand; + + valtype vchHash(32, 0); + uint64_t nCounter = 0; + int nHashIndex = 3; + CSHA256 hasher; + hasher.Write(vchSeed.data(), vchSeed.size()); + do { + if (nHashIndex >= 3) { + //TODO this isn't endian safe + CSHA256(hasher).Write((const unsigned char*)&nCounter, sizeof(nCounter)).Finalize(vchHash.data()); + nHashIndex = 0; + nCounter++; + } + + nRand = 0; + for (size_t i=0; i<8; ++i) + nRand |= ((uint64_t)vchHash[(nHashIndex*8) + i]) << (8*i); + + nHashIndex++; + } while (nRand > nRange); + CScriptNum result(nRand % nMax); + result += bnMin.getint(); + + popstack(stack); + popstack(stack); + popstack(stack); + stack.push_back(result.getvch()); + } + break; + default: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } diff --git a/src/script/script.cpp b/src/script/script.cpp index fba7745983..373f09bf9f 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -126,6 +126,7 @@ const char* GetOpName(opcodetype opcode) case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY"; case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG"; case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY"; + case OP_DETERMINISTICRANDOM : return "OP_DETERMINISTICRANDOM"; // expansion case OP_NOP1 : return "OP_NOP1"; diff --git a/src/script/script.h b/src/script/script.h index a66dbc9353..e27937a990 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -173,6 +173,7 @@ enum opcodetype OP_CHECKSIGVERIFY = 0xad, OP_CHECKMULTISIG = 0xae, OP_CHECKMULTISIGVERIFY = 0xaf, + OP_DETERMINISTICRANDOM = 0xc0, // expansion OP_NOP1 = 0xb0, @@ -192,7 +193,7 @@ enum opcodetype }; // Maximum value that an opcode can be -static const unsigned int MAX_OPCODE = OP_NOP10; +static const unsigned int MAX_OPCODE = OP_DETERMINISTICRANDOM; const char* GetOpName(opcodetype opcode); diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json index 9b320b6943..5c42aad054 100644 --- a/src/test/data/script_tests.json +++ b/src/test/data/script_tests.json @@ -258,7 +258,6 @@ ["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], ["0", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], ["0", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], -["0", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], ["0", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], ["0", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], ["0", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], @@ -894,7 +893,6 @@ ["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], -["1", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index bc671394c0..d5796ea8a3 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1474,7 +1474,7 @@ BOOST_AUTO_TEST_CASE(script_HasValidOps) BOOST_CHECK(script.HasValidOps()); script = ScriptFromHex("ff88ac"); // Script with OP_INVALIDOPCODE explicit BOOST_CHECK(!script.HasValidOps()); - script = ScriptFromHex("88acc0"); // Script with undefined opcode + script = ScriptFromHex("88acc1"); // Script with undefined opcode: one higher then MAX_OPCODE BOOST_CHECK(!script.HasValidOps()); }