diff --git a/src/core_write.cpp b/src/core_write.cpp index 75c11dbc2b..2716693b34 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -1,240 +1,242 @@ // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "core_io.h" #include "dstencode.h" #include "primitives/transaction.h" #include "script/script.h" #include "script/sigencoding.h" #include "script/standard.h" #include "serialize.h" #include "streams.h" #include "util.h" #include "utilmoneystr.h" #include "utilstrencodings.h" #include std::string FormatScript(const CScript &script) { std::string ret; CScript::const_iterator it = script.begin(); opcodetype op; while (it != script.end()) { CScript::const_iterator it2 = it; std::vector vch; if (script.GetOp2(it, op, &vch)) { if (op == OP_0) { ret += "0 "; continue; } if ((op >= OP_1 && op <= OP_16) || op == OP_1NEGATE) { ret += strprintf("%i ", op - OP_1NEGATE - 1); continue; } if (op >= OP_NOP && op <= OP_NOP10) { std::string str(GetOpName(op)); if (str.substr(0, 3) == std::string("OP_")) { ret += str.substr(3, std::string::npos) + " "; continue; } } if (vch.size() > 0) { ret += strprintf("0x%x 0x%x ", HexStr(it2, it - vch.size()), HexStr(it - vch.size(), it)); } else { ret += strprintf("0x%x ", HexStr(it2, it)); } continue; } ret += strprintf("0x%x ", HexStr(it2, script.end())); break; } return ret.substr(0, ret.size() - 1); } const std::map mapSigHashTypes = { {SIGHASH_ALL, "ALL"}, {SIGHASH_ALL | SIGHASH_ANYONECANPAY, "ALL|ANYONECANPAY"}, {SIGHASH_ALL | SIGHASH_FORKID, "ALL|FORKID"}, {SIGHASH_ALL | SIGHASH_FORKID | SIGHASH_ANYONECANPAY, "ALL|FORKID|ANYONECANPAY"}, {SIGHASH_NONE, "NONE"}, {SIGHASH_NONE | SIGHASH_ANYONECANPAY, "NONE|ANYONECANPAY"}, {SIGHASH_NONE | SIGHASH_FORKID, "NONE|FORKID"}, {SIGHASH_NONE | SIGHASH_FORKID | SIGHASH_ANYONECANPAY, "NONE|FORKID|ANYONECANPAY"}, {SIGHASH_SINGLE, "SINGLE"}, {SIGHASH_SINGLE | SIGHASH_ANYONECANPAY, "SINGLE|ANYONECANPAY"}, {SIGHASH_SINGLE | SIGHASH_FORKID, "SINGLE|FORKID"}, {SIGHASH_SINGLE | SIGHASH_FORKID | SIGHASH_ANYONECANPAY, "SINGLE|FORKID|ANYONECANPAY"}, }; /** * Create the assembly string representation of a CScript object. * @param[in] script CScript object to convert into the asm string * representation. * @param[in] fAttemptSighashDecode Whether to attempt to decode sighash * types on data within the script that matches the format of a signature. Only * pass true for scripts you believe could contain signatures. For example, pass * false, or omit the this argument (defaults to false), for scriptPubKeys. */ std::string ScriptToAsmStr(const CScript &script, const bool fAttemptSighashDecode) { std::string str; opcodetype opcode; std::vector vch; CScript::const_iterator pc = script.begin(); while (pc < script.end()) { if (!str.empty()) { str += " "; } if (!script.GetOp(pc, opcode, vch)) { str += "[error]"; return str; } if (0 <= opcode && opcode <= OP_PUSHDATA4) { if (vch.size() <= static_cast::size_type>(4)) { str += strprintf("%d", CScriptNum(vch, false).getint()); } else { // the IsUnspendable check makes sure not to try to decode // OP_RETURN data that may match the format of a signature if (fAttemptSighashDecode && !script.IsUnspendable()) { std::string strSigHashDecode; // goal: only attempt to decode a defined sighash type from // data that looks like a signature within a scriptSig. This // won't decode correctly formatted public keys in Pubkey or // Multisig scripts due to the restrictions on the pubkey // formats (see IsCompressedOrUncompressedPubKey) being - // incongruous with the checks in CheckSignatureEncoding. + // incongruous with the checks in + // CheckTransactionSignatureEncoding. uint32_t flags = SCRIPT_VERIFY_STRICTENC; if (vch.back() & SIGHASH_FORKID) { // If the transaction is using SIGHASH_FORKID, we need // to set the apropriate flag. // TODO: Remove after the Hard Fork. flags |= SCRIPT_ENABLE_SIGHASH_FORKID; } - if (CheckSignatureEncoding(vch, flags, nullptr)) { + if (CheckTransactionSignatureEncoding(vch, flags, + nullptr)) { const uint8_t chSigHashType = vch.back(); if (mapSigHashTypes.count(chSigHashType)) { strSigHashDecode = "[" + mapSigHashTypes.find(chSigHashType)->second + "]"; // remove the sighash type byte. it will be replaced // by the decode. vch.pop_back(); } } str += HexStr(vch) + strSigHashDecode; } else { str += HexStr(vch); } } } else { str += GetOpName(opcode); } } return str; } std::string EncodeHexTx(const CTransaction &tx, const int serialFlags) { CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serialFlags); ssTx << tx; return HexStr(ssTx.begin(), ssTx.end()); } void ScriptPubKeyToUniv(const CScript &scriptPubKey, UniValue &out, bool fIncludeHex) { txnouttype type; std::vector addresses; int nRequired; out.pushKV("asm", ScriptToAsmStr(scriptPubKey)); if (fIncludeHex) { out.pushKV("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())); } if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) { out.pushKV("type", GetTxnOutputType(type)); return; } out.pushKV("reqSigs", nRequired); out.pushKV("type", GetTxnOutputType(type)); UniValue a(UniValue::VARR); for (const CTxDestination &addr : addresses) { a.push_back(EncodeDestination(addr)); } out.pushKV("addresses", a); } void TxToUniv(const CTransaction &tx, const uint256 &hashBlock, UniValue &entry) { entry.pushKV("txid", tx.GetId().GetHex()); entry.pushKV("hash", tx.GetHash().GetHex()); entry.pushKV("version", tx.nVersion); entry.pushKV("locktime", (int64_t)tx.nLockTime); UniValue vin(UniValue::VARR); for (unsigned int i = 0; i < tx.vin.size(); i++) { const CTxIn &txin = tx.vin[i]; UniValue in(UniValue::VOBJ); if (tx.IsCoinBase()) { in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); } else { in.pushKV("txid", txin.prevout.GetTxId().GetHex()); in.pushKV("vout", int64_t(txin.prevout.GetN())); UniValue o(UniValue::VOBJ); o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); in.pushKV("scriptSig", o); } in.pushKV("sequence", (int64_t)txin.nSequence); vin.push_back(in); } entry.pushKV("vin", vin); UniValue vout(UniValue::VARR); for (unsigned int i = 0; i < tx.vout.size(); i++) { const CTxOut &txout = tx.vout[i]; UniValue out(UniValue::VOBJ); UniValue outValue(UniValue::VNUM, FormatMoney(txout.nValue)); out.pushKV("value", outValue); out.pushKV("n", (int64_t)i); UniValue o(UniValue::VOBJ); ScriptPubKeyToUniv(txout.scriptPubKey, o, true); out.pushKV("scriptPubKey", o); vout.push_back(out); } entry.pushKV("vout", vout); if (!hashBlock.IsNull()) { entry.pushKV("blockhash", hashBlock.GetHex()); } // the hex-encoded transaction. used the name "hex" to be consistent with // the verbose output of "getrawtransaction". entry.pushKV("hex", EncodeHexTx(tx)); } diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 717610ed93..9894539f3d 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1,1614 +1,1615 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2017-2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "interpreter.h" #include "crypto/ripemd160.h" #include "crypto/sha1.h" #include "crypto/sha256.h" #include "primitives/transaction.h" #include "pubkey.h" #include "script/script.h" #include "script/script_flags.h" #include "script/sigencoding.h" #include "uint256.h" bool CastToBool(const valtype &vch) { for (size_t i = 0; i < vch.size(); i++) { if (vch[i] != 0) { // Can be negative zero if (i == vch.size() - 1 && vch[i] == 0x80) { return false; } return true; } } return false; } /** * Script is a stack machine (like Forth) that evaluates a predicate * returning a bool indicating valid or not. There are no loops. */ #define stacktop(i) (stack.at(stack.size() + (i))) #define altstacktop(i) (altstack.at(altstack.size() + (i))) static inline void popstack(std::vector &stack) { if (stack.empty()) { throw std::runtime_error("popstack(): stack empty"); } stack.pop_back(); } static void CleanupScriptCode(CScript &scriptCode, const std::vector &vchSig, uint32_t flags) { // Drop the signature in scripts when SIGHASH_FORKID is not used. SigHashType sigHashType = GetHashType(vchSig); if (!(flags & SCRIPT_ENABLE_SIGHASH_FORKID) || !sigHashType.hasForkId()) { scriptCode.FindAndDelete(CScript(vchSig)); } } static bool CheckMinimalPush(const valtype &data, opcodetype opcode) { if (data.size() == 0) { // Could have used OP_0. return opcode == OP_0; } if (data.size() == 1 && data[0] >= 1 && data[0] <= 16) { // Could have used OP_1 .. OP_16. return opcode == OP_1 + (data[0] - 1); } if (data.size() == 1 && data[0] == 0x81) { // Could have used OP_1NEGATE. return opcode == OP_1NEGATE; } if (data.size() <= 75) { // Could have used a direct push (opcode indicating number of bytes // pushed + those bytes). return opcode == data.size(); } if (data.size() <= 255) { // Could have used OP_PUSHDATA. return opcode == OP_PUSHDATA1; } if (data.size() <= 65535) { // Could have used OP_PUSHDATA2. return opcode == OP_PUSHDATA2; } return true; } static bool IsOpcodeDisabled(opcodetype opcode, uint32_t flags) { switch (opcode) { case OP_INVERT: case OP_2MUL: case OP_2DIV: case OP_MUL: case OP_LSHIFT: case OP_RSHIFT: // Disabled opcodes. return true; default: break; } return false; } bool EvalScript(std::vector &stack, const CScript &script, uint32_t flags, const BaseSignatureChecker &checker, ScriptError *serror) { static const CScriptNum bnZero(0); static const CScriptNum bnOne(1); static const valtype vchFalse(0); static const valtype vchTrue(1, 1); CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); CScript::const_iterator pbegincodehash = script.begin(); opcodetype opcode; valtype vchPushValue; std::vector vfExec; std::vector altstack; set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); if (script.size() > MAX_SCRIPT_SIZE) { return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE); } int nOpCount = 0; bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; try { while (pc < pend) { bool fExec = !count(vfExec.begin(), vfExec.end(), false); // // Read instruction // if (!script.GetOp(pc, opcode, vchPushValue)) { return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) { return set_error(serror, SCRIPT_ERR_PUSH_SIZE); } // Note how OP_RESERVED does not count towards the opcode limit. if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT) { return set_error(serror, SCRIPT_ERR_OP_COUNT); } // Some opcodes are disabled. if (IsOpcodeDisabled(opcode, flags)) { return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); } if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) { if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) { return set_error(serror, SCRIPT_ERR_MINIMALDATA); } stack.push_back(vchPushValue); } else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) { switch (opcode) { // // Push value // case OP_1NEGATE: case OP_1: case OP_2: case OP_3: case OP_4: case OP_5: case OP_6: case OP_7: case OP_8: case OP_9: case OP_10: case OP_11: case OP_12: case OP_13: case OP_14: case OP_15: case OP_16: { // ( -- value) CScriptNum bn((int)opcode - (int)(OP_1 - 1)); stack.push_back(bn.getvch()); // The result of these opcodes should always be the // minimal way to push the data they push, so no need // for a CheckMinimalPush here. } break; // // Control // case OP_NOP: break; case OP_CHECKLOCKTIMEVERIFY: { if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) { // not enabled; treat as a NOP2 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { return set_error( serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); } break; } if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } // Note that elsewhere numeric opcodes are limited to // operands in the range -2**31+1 to 2**31-1, however it // is legal for opcodes to produce results exceeding // that range. This limitation is implemented by // CScriptNum's default 4-byte limit. // // If we kept to that limit we'd have a year 2038 // problem, even though the nLockTime field in // transactions themselves is uint32 which only becomes // meaningless after the year 2106. // // Thus as a special case we tell CScriptNum to accept // up to 5-byte bignums, which are good until 2**39-1, // well beyond the 2**32-1 limit of the nLockTime field // itself. const CScriptNum nLockTime(stacktop(-1), fRequireMinimal, 5); // In the rare event that the argument may be < 0 due to // some arithmetic being done first, you can always use // 0 MAX CHECKLOCKTIMEVERIFY. if (nLockTime < 0) { return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME); } // Actually compare the specified lock time with the // transaction. if (!checker.CheckLockTime(nLockTime)) { return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME); } break; } case OP_CHECKSEQUENCEVERIFY: { if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) { // not enabled; treat as a NOP3 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { return set_error( serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); } break; } if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } // nSequence, like nLockTime, is a 32-bit unsigned // integer field. See the comment in CHECKLOCKTIMEVERIFY // regarding 5-byte numeric operands. const CScriptNum nSequence(stacktop(-1), fRequireMinimal, 5); // In the rare event that the argument may be < 0 due to // some arithmetic being done first, you can always use // 0 MAX CHECKSEQUENCEVERIFY. if (nSequence < 0) { return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME); } // To provide for future soft-fork extensibility, if the // operand has the disabled lock-time flag set, // CHECKSEQUENCEVERIFY behaves as a NOP. if ((nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0) { break; } // Compare the specified sequence number with the input. if (!checker.CheckSequence(nSequence)) { return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME); } break; } case OP_NOP1: case OP_NOP4: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: { if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { return set_error( serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); } } break; case OP_IF: case OP_NOTIF: { // if [statements] [else [statements]] // endif bool fValue = false; if (fExec) { if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); } valtype &vch = stacktop(-1); if (flags & SCRIPT_VERIFY_MINIMALIF) { if (vch.size() > 1) { return set_error(serror, SCRIPT_ERR_MINIMALIF); } if (vch.size() == 1 && vch[0] != 1) { return set_error(serror, SCRIPT_ERR_MINIMALIF); } } fValue = CastToBool(vch); if (opcode == OP_NOTIF) { fValue = !fValue; } popstack(stack); } vfExec.push_back(fValue); } break; case OP_ELSE: { if (vfExec.empty()) { return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); } vfExec.back() = !vfExec.back(); } break; case OP_ENDIF: { if (vfExec.empty()) { return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); } vfExec.pop_back(); } break; case OP_VERIFY: { // (true -- ) or // (false -- false) and return if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } bool fValue = CastToBool(stacktop(-1)); if (fValue) { popstack(stack); } else { return set_error(serror, SCRIPT_ERR_VERIFY); } } break; case OP_RETURN: { return set_error(serror, SCRIPT_ERR_OP_RETURN); } break; // // Stack ops // case OP_TOALTSTACK: { if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } altstack.push_back(stacktop(-1)); popstack(stack); } break; case OP_FROMALTSTACK: { if (altstack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_ALTSTACK_OPERATION); } stack.push_back(altstacktop(-1)); popstack(altstack); } break; case OP_2DROP: { // (x1 x2 -- ) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } popstack(stack); popstack(stack); } break; case OP_2DUP: { // (x1 x2 -- x1 x2 x1 x2) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch1 = stacktop(-2); valtype vch2 = stacktop(-1); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_3DUP: { // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) if (stack.size() < 3) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch1 = stacktop(-3); valtype vch2 = stacktop(-2); valtype vch3 = stacktop(-1); stack.push_back(vch1); stack.push_back(vch2); stack.push_back(vch3); } break; case OP_2OVER: { // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) if (stack.size() < 4) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch1 = stacktop(-4); valtype vch2 = stacktop(-3); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_2ROT: { // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) if (stack.size() < 6) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch1 = stacktop(-6); valtype vch2 = stacktop(-5); stack.erase(stack.end() - 6, stack.end() - 4); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_2SWAP: { // (x1 x2 x3 x4 -- x3 x4 x1 x2) if (stack.size() < 4) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } swap(stacktop(-4), stacktop(-2)); swap(stacktop(-3), stacktop(-1)); } break; case OP_IFDUP: { // (x - 0 | x x) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch = stacktop(-1); if (CastToBool(vch)) { stack.push_back(vch); } } break; case OP_DEPTH: { // -- stacksize CScriptNum bn(stack.size()); stack.push_back(bn.getvch()); } break; case OP_DROP: { // (x -- ) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } popstack(stack); } break; case OP_DUP: { // (x -- x x) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch = stacktop(-1); stack.push_back(vch); } break; case OP_NIP: { // (x1 x2 -- x2) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } stack.erase(stack.end() - 2); } break; case OP_OVER: { // (x1 x2 -- x1 x2 x1) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch = stacktop(-2); stack.push_back(vch); } break; case OP_PICK: case OP_ROLL: { // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } int n = CScriptNum(stacktop(-1), fRequireMinimal).getint(); popstack(stack); if (n < 0 || n >= (int)stack.size()) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch = stacktop(-n - 1); if (opcode == OP_ROLL) { stack.erase(stack.end() - n - 1); } stack.push_back(vch); } break; case OP_ROT: { // (x1 x2 x3 -- x2 x3 x1) // x2 x1 x3 after first swap // x2 x3 x1 after second swap if (stack.size() < 3) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } swap(stacktop(-3), stacktop(-2)); swap(stacktop(-2), stacktop(-1)); } break; case OP_SWAP: { // (x1 x2 -- x2 x1) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } swap(stacktop(-2), stacktop(-1)); } break; case OP_TUCK: { // (x1 x2 -- x2 x1 x2) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch = stacktop(-1); stack.insert(stack.end() - 2, vch); } break; case OP_SIZE: { // (in -- in size) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } CScriptNum bn(stacktop(-1).size()); stack.push_back(bn.getvch()); } break; // // Bitwise logic // case OP_AND: case OP_OR: case OP_XOR: { // (x1 x2 - out) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype &vch1 = stacktop(-2); valtype &vch2 = stacktop(-1); // Inputs must be the same size if (vch1.size() != vch2.size()) { return set_error(serror, SCRIPT_ERR_INVALID_OPERAND_SIZE); } // To avoid allocating, we modify vch1 in place. switch (opcode) { case OP_AND: for (size_t i = 0; i < vch1.size(); ++i) { vch1[i] &= vch2[i]; } break; case OP_OR: for (size_t i = 0; i < vch1.size(); ++i) { vch1[i] |= vch2[i]; } break; case OP_XOR: for (size_t i = 0; i < vch1.size(); ++i) { vch1[i] ^= vch2[i]; } break; default: break; } // And pop vch2. popstack(stack); } break; case OP_EQUAL: case OP_EQUALVERIFY: // case OP_NOTEQUAL: // use OP_NUMNOTEQUAL { // (x1 x2 - bool) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype &vch1 = stacktop(-2); valtype &vch2 = stacktop(-1); bool fEqual = (vch1 == vch2); // OP_NOTEQUAL is disabled because it would be too // easy to say something like n != 1 and have some // wiseguy pass in 1 with extra zero bytes after it // (numerically, 0x01 == 0x0001 == 0x000001) // if (opcode == OP_NOTEQUAL) // fEqual = !fEqual; popstack(stack); popstack(stack); stack.push_back(fEqual ? vchTrue : vchFalse); if (opcode == OP_EQUALVERIFY) { if (fEqual) { popstack(stack); } else { return set_error(serror, SCRIPT_ERR_EQUALVERIFY); } } } break; // // Numeric // case OP_1ADD: case OP_1SUB: case OP_NEGATE: case OP_ABS: case OP_NOT: case OP_0NOTEQUAL: { // (in -- out) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } CScriptNum bn(stacktop(-1), fRequireMinimal); switch (opcode) { case OP_1ADD: bn += bnOne; break; case OP_1SUB: bn -= bnOne; break; case OP_NEGATE: bn = -bn; break; case OP_ABS: if (bn < bnZero) { bn = -bn; } break; case OP_NOT: bn = (bn == bnZero); break; case OP_0NOTEQUAL: bn = (bn != bnZero); break; default: assert(!"invalid opcode"); break; } popstack(stack); stack.push_back(bn.getvch()); } break; case OP_ADD: case OP_SUB: case OP_DIV: case OP_MOD: case OP_BOOLAND: case OP_BOOLOR: case OP_NUMEQUAL: case OP_NUMEQUALVERIFY: case OP_NUMNOTEQUAL: case OP_LESSTHAN: case OP_GREATERTHAN: case OP_LESSTHANOREQUAL: case OP_GREATERTHANOREQUAL: case OP_MIN: case OP_MAX: { // (x1 x2 -- out) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } CScriptNum bn1(stacktop(-2), fRequireMinimal); CScriptNum bn2(stacktop(-1), fRequireMinimal); CScriptNum bn(0); switch (opcode) { case OP_ADD: bn = bn1 + bn2; break; case OP_SUB: bn = bn1 - bn2; break; case OP_DIV: // denominator must not be 0 if (bn2 == 0) { return set_error(serror, SCRIPT_ERR_DIV_BY_ZERO); } bn = bn1 / bn2; break; case OP_MOD: // divisor must not be 0 if (bn2 == 0) { return set_error(serror, SCRIPT_ERR_MOD_BY_ZERO); } bn = bn1 % bn2; break; case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; case OP_NUMEQUAL: bn = (bn1 == bn2); break; case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break; case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break; case OP_LESSTHAN: bn = (bn1 < bn2); break; case OP_GREATERTHAN: bn = (bn1 > bn2); break; case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break; case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break; case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break; default: assert(!"invalid opcode"); break; } popstack(stack); popstack(stack); stack.push_back(bn.getvch()); if (opcode == OP_NUMEQUALVERIFY) { if (CastToBool(stacktop(-1))) { popstack(stack); } else { return set_error(serror, SCRIPT_ERR_NUMEQUALVERIFY); } } } break; case OP_WITHIN: { // (x min max -- out) if (stack.size() < 3) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } CScriptNum bn1(stacktop(-3), fRequireMinimal); CScriptNum bn2(stacktop(-2), fRequireMinimal); CScriptNum bn3(stacktop(-1), fRequireMinimal); bool fValue = (bn2 <= bn1 && bn1 < bn3); popstack(stack); popstack(stack); popstack(stack); stack.push_back(fValue ? vchTrue : vchFalse); } break; // // Crypto // case OP_RIPEMD160: case OP_SHA1: case OP_SHA256: case OP_HASH160: case OP_HASH256: { // (in -- hash) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype &vch = stacktop(-1); valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); if (opcode == OP_RIPEMD160) { CRIPEMD160() .Write(vch.data(), vch.size()) .Finalize(vchHash.data()); } else if (opcode == OP_SHA1) { CSHA1() .Write(vch.data(), vch.size()) .Finalize(vchHash.data()); } else if (opcode == OP_SHA256) { CSHA256() .Write(vch.data(), vch.size()) .Finalize(vchHash.data()); } else if (opcode == OP_HASH160) { CHash160() .Write(vch.data(), vch.size()) .Finalize(vchHash.data()); } else if (opcode == OP_HASH256) { CHash256() .Write(vch.data(), vch.size()) .Finalize(vchHash.data()); } popstack(stack); stack.push_back(vchHash); } break; case OP_CODESEPARATOR: { // Hash starts after the code separator pbegincodehash = pc; } break; case OP_CHECKSIG: case OP_CHECKSIGVERIFY: { // (sig pubkey -- bool) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype &vchSig = stacktop(-2); valtype &vchPubKey = stacktop(-1); - if (!CheckSignatureEncoding(vchSig, flags, serror) || + if (!CheckTransactionSignatureEncoding(vchSig, flags, + serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) { // serror is set return false; } // Subset of script starting at the most recent // codeseparator CScript scriptCode(pbegincodehash, pend); // Remove signature for pre-fork scripts CleanupScriptCode(scriptCode, vchSig, flags); bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, flags); if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size()) { return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); } popstack(stack); popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); if (opcode == OP_CHECKSIGVERIFY) { if (fSuccess) { popstack(stack); } else { return set_error(serror, SCRIPT_ERR_CHECKSIGVERIFY); } } } break; case OP_CHECKMULTISIG: case OP_CHECKMULTISIGVERIFY: { // ([sig ...] num_of_signatures [pubkey ...] // num_of_pubkeys -- bool) int i = 1; if ((int)stack.size() < i) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); if (nKeysCount < 0 || nKeysCount > MAX_PUBKEYS_PER_MULTISIG) { return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT); } nOpCount += nKeysCount; if (nOpCount > MAX_OPS_PER_SCRIPT) { return set_error(serror, SCRIPT_ERR_OP_COUNT); } int ikey = ++i; // ikey2 is the position of last non-signature item in // the stack. Top stack item = 1. With // SCRIPT_VERIFY_NULLFAIL, this is used for cleanup if // operation fails. int ikey2 = nKeysCount + 2; i += nKeysCount; if ((int)stack.size() < i) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } int nSigsCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); if (nSigsCount < 0 || nSigsCount > nKeysCount) { return set_error(serror, SCRIPT_ERR_SIG_COUNT); } int isig = ++i; i += nSigsCount; if ((int)stack.size() < i) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } // Subset of script starting at the most recent // codeseparator CScript scriptCode(pbegincodehash, pend); // Remove signature for pre-fork scripts for (int k = 0; k < nSigsCount; k++) { valtype &vchSig = stacktop(-isig - k); CleanupScriptCode(scriptCode, vchSig, flags); } bool fSuccess = true; while (fSuccess && nSigsCount > 0) { valtype &vchSig = stacktop(-isig); valtype &vchPubKey = stacktop(-ikey); // Note how this makes the exact order of // pubkey/signature evaluation distinguishable by // CHECKMULTISIG NOT if the STRICTENC flag is set. // See the script_(in)valid tests for details. - if (!CheckSignatureEncoding(vchSig, flags, - serror) || + if (!CheckTransactionSignatureEncoding( + vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) { // serror is set return false; } // Check signature bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, flags); if (fOk) { isig++; nSigsCount--; } ikey++; nKeysCount--; // If there are more signatures left than keys left, // then too many signatures have failed. Exit early, // without checking any further signatures. if (nSigsCount > nKeysCount) { fSuccess = false; } } // Clean up stack of actual arguments while (i-- > 1) { // If the operation failed, we require that all // signatures must be empty vector if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && !ikey2 && stacktop(-1).size()) { return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); } if (ikey2 > 0) { ikey2--; } popstack(stack); } // A bug causes CHECKMULTISIG to consume one extra // argument whose contents were not checked in any way. // // Unfortunately this is a potential source of // mutability, so optionally verify it is exactly equal // to zero prior to removing it from the stack. if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size()) { return set_error(serror, SCRIPT_ERR_SIG_NULLDUMMY); } popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); if (opcode == OP_CHECKMULTISIGVERIFY) { if (fSuccess) { popstack(stack); } else { return set_error( serror, SCRIPT_ERR_CHECKMULTISIGVERIFY); } } } break; case OP_CHECKDATASIG: case OP_CHECKDATASIGVERIFY: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); // // Byte string operations // case OP_CAT: { // (x1 x2 -- out) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype &vch1 = stacktop(-2); valtype &vch2 = stacktop(-1); if (vch1.size() + vch2.size() > MAX_SCRIPT_ELEMENT_SIZE) { return set_error(serror, SCRIPT_ERR_PUSH_SIZE); } vch1.insert(vch1.end(), vch2.begin(), vch2.end()); popstack(stack); } break; case OP_SPLIT: { // (in position -- x1 x2) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } const valtype &data = stacktop(-2); // Make sure the split point is apropriate. uint64_t position = CScriptNum(stacktop(-1), fRequireMinimal).getint(); if (position > data.size()) { return set_error(serror, SCRIPT_ERR_INVALID_SPLIT_RANGE); } // Prepare the results in their own buffer as `data` // will be invalidated. valtype n1(data.begin(), data.begin() + position); valtype n2(data.begin() + position, data.end()); // Replace existing stack values by the new values. stacktop(-2) = std::move(n1); stacktop(-1) = std::move(n2); } break; // // Conversion operations // case OP_NUM2BIN: { // (in size -- out) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } uint64_t size = CScriptNum(stacktop(-1), fRequireMinimal).getint(); if (size > MAX_SCRIPT_ELEMENT_SIZE) { return set_error(serror, SCRIPT_ERR_PUSH_SIZE); } popstack(stack); valtype &rawnum = stacktop(-1); // Try to see if we can fit that number in the number of // byte requested. CScriptNum::MinimallyEncode(rawnum); if (rawnum.size() > size) { // We definitively cannot. return set_error(serror, SCRIPT_ERR_IMPOSSIBLE_ENCODING); } // We already have an element of the right size, we // don't need to do anything. if (rawnum.size() == size) { break; } uint8_t signbit = 0x00; if (rawnum.size() > 0) { signbit = rawnum.back() & 0x80; rawnum[rawnum.size() - 1] &= 0x7f; } rawnum.reserve(size); while (rawnum.size() < size - 1) { rawnum.push_back(0x00); } rawnum.push_back(signbit); } break; case OP_BIN2NUM: { // (in -- out) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype &n = stacktop(-1); CScriptNum::MinimallyEncode(n); // The resulting number must be a valid number. if (!CScriptNum::IsMinimallyEncoded(n)) { return set_error(serror, SCRIPT_ERR_INVALID_NUMBER_RANGE); } } break; default: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } } // Size limits if (stack.size() + altstack.size() > 1000) { return set_error(serror, SCRIPT_ERR_STACK_SIZE); } } } catch (...) { return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); } if (!vfExec.empty()) { return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); } return set_success(serror); } namespace { /** * Wrapper that serializes like CTransaction, but with the modifications * required for the signature hash done in-place */ class CTransactionSignatureSerializer { private: //!< reference to the spending transaction (the one being serialized) const CTransaction &txTo; //!< output script being consumed const CScript &scriptCode; //!< input index of txTo being signed const unsigned int nIn; //!< container for hashtype flags const SigHashType sigHashType; public: CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, SigHashType sigHashTypeIn) : txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn), sigHashType(sigHashTypeIn) {} /** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */ template void SerializeScriptCode(S &s) const { CScript::const_iterator it = scriptCode.begin(); CScript::const_iterator itBegin = it; opcodetype opcode; unsigned int nCodeSeparators = 0; while (scriptCode.GetOp(it, opcode)) { if (opcode == OP_CODESEPARATOR) { nCodeSeparators++; } } ::WriteCompactSize(s, scriptCode.size() - nCodeSeparators); it = itBegin; while (scriptCode.GetOp(it, opcode)) { if (opcode == OP_CODESEPARATOR) { s.write((char *)&itBegin[0], it - itBegin - 1); itBegin = it; } } if (itBegin != scriptCode.end()) { s.write((char *)&itBegin[0], it - itBegin); } } /** Serialize an input of txTo */ template void SerializeInput(S &s, unsigned int nInput) const { // In case of SIGHASH_ANYONECANPAY, only the input being signed is // serialized if (sigHashType.hasAnyoneCanPay()) { nInput = nIn; } // Serialize the prevout ::Serialize(s, txTo.vin[nInput].prevout); // Serialize the script if (nInput != nIn) { // Blank out other inputs' signatures ::Serialize(s, CScript()); } else { SerializeScriptCode(s); } // Serialize the nSequence if (nInput != nIn && (sigHashType.getBaseType() == BaseSigHashType::SINGLE || sigHashType.getBaseType() == BaseSigHashType::NONE)) { // let the others update at will ::Serialize(s, (int)0); } else { ::Serialize(s, txTo.vin[nInput].nSequence); } } /** Serialize an output of txTo */ template void SerializeOutput(S &s, unsigned int nOutput) const { if (sigHashType.getBaseType() == BaseSigHashType::SINGLE && nOutput != nIn) { // Do not lock-in the txout payee at other indices as txin ::Serialize(s, CTxOut()); } else { ::Serialize(s, txTo.vout[nOutput]); } } /** Serialize txTo */ template void Serialize(S &s) const { // Serialize nVersion ::Serialize(s, txTo.nVersion); // Serialize vin unsigned int nInputs = sigHashType.hasAnyoneCanPay() ? 1 : txTo.vin.size(); ::WriteCompactSize(s, nInputs); for (unsigned int nInput = 0; nInput < nInputs; nInput++) { SerializeInput(s, nInput); } // Serialize vout unsigned int nOutputs = (sigHashType.getBaseType() == BaseSigHashType::NONE) ? 0 : ((sigHashType.getBaseType() == BaseSigHashType::SINGLE) ? nIn + 1 : txTo.vout.size()); ::WriteCompactSize(s, nOutputs); for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++) { SerializeOutput(s, nOutput); } // Serialize nLockTime ::Serialize(s, txTo.nLockTime); } }; uint256 GetPrevoutHash(const CTransaction &txTo) { CHashWriter ss(SER_GETHASH, 0); for (size_t n = 0; n < txTo.vin.size(); n++) { ss << txTo.vin[n].prevout; } return ss.GetHash(); } uint256 GetSequenceHash(const CTransaction &txTo) { CHashWriter ss(SER_GETHASH, 0); for (size_t n = 0; n < txTo.vin.size(); n++) { ss << txTo.vin[n].nSequence; } return ss.GetHash(); } uint256 GetOutputsHash(const CTransaction &txTo) { CHashWriter ss(SER_GETHASH, 0); for (size_t n = 0; n < txTo.vout.size(); n++) { ss << txTo.vout[n]; } return ss.GetHash(); } } // namespace PrecomputedTransactionData::PrecomputedTransactionData( const CTransaction &txTo) { hashPrevouts = GetPrevoutHash(txTo); hashSequence = GetSequenceHash(txTo); hashOutputs = GetOutputsHash(txTo); } uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo, unsigned int nIn, SigHashType sigHashType, const Amount amount, const PrecomputedTransactionData *cache, uint32_t flags) { if (flags & SCRIPT_ENABLE_REPLAY_PROTECTION) { // Legacy chain's value for fork id must be of the form 0xffxxxx. // By xoring with 0xdead, we ensure that the value will be different // from the original one, even if it already starts with 0xff. uint32_t newForkValue = sigHashType.getForkValue() ^ 0xdead; sigHashType = sigHashType.withForkValue(0xff0000 | newForkValue); } if (sigHashType.hasForkId() && (flags & SCRIPT_ENABLE_SIGHASH_FORKID)) { uint256 hashPrevouts; uint256 hashSequence; uint256 hashOutputs; if (!sigHashType.hasAnyoneCanPay()) { hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo); } if (!sigHashType.hasAnyoneCanPay() && (sigHashType.getBaseType() != BaseSigHashType::SINGLE) && (sigHashType.getBaseType() != BaseSigHashType::NONE)) { hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo); } if ((sigHashType.getBaseType() != BaseSigHashType::SINGLE) && (sigHashType.getBaseType() != BaseSigHashType::NONE)) { hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo); } else if ((sigHashType.getBaseType() == BaseSigHashType::SINGLE) && (nIn < txTo.vout.size())) { CHashWriter ss(SER_GETHASH, 0); ss << txTo.vout[nIn]; hashOutputs = ss.GetHash(); } CHashWriter ss(SER_GETHASH, 0); // Version ss << txTo.nVersion; // Input prevouts/nSequence (none/all, depending on flags) ss << hashPrevouts; ss << hashSequence; // The input being signed (replacing the scriptSig with scriptCode + // amount). The prevout may already be contained in hashPrevout, and the // nSequence may already be contain in hashSequence. ss << txTo.vin[nIn].prevout; ss << scriptCode; ss << amount; ss << txTo.vin[nIn].nSequence; // Outputs (none/one/all, depending on flags) ss << hashOutputs; // Locktime ss << txTo.nLockTime; // Sighash type ss << sigHashType; return ss.GetHash(); } static const uint256 one(uint256S( "0000000000000000000000000000000000000000000000000000000000000001")); if (nIn >= txTo.vin.size()) { // nIn out of range return one; } // Check for invalid use of SIGHASH_SINGLE if ((sigHashType.getBaseType() == BaseSigHashType::SINGLE) && (nIn >= txTo.vout.size())) { // nOut out of range return one; } // Wrapper to serialize only the necessary parts of the transaction being // signed CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, sigHashType); // Serialize and hash CHashWriter ss(SER_GETHASH, 0); ss << txTmp << sigHashType; return ss.GetHash(); } bool TransactionSignatureChecker::VerifySignature( const std::vector &vchSig, const CPubKey &pubkey, const uint256 &sighash) const { return pubkey.Verify(sighash, vchSig); } bool TransactionSignatureChecker::CheckSig( const std::vector &vchSigIn, const std::vector &vchPubKey, const CScript &scriptCode, uint32_t flags) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) { return false; } // Hash type is one byte tacked on to the end of the signature std::vector vchSig(vchSigIn); if (vchSig.empty()) { return false; } SigHashType sigHashType = GetHashType(vchSig); vchSig.pop_back(); uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, sigHashType, amount, this->txdata, flags); if (!VerifySignature(vchSig, pubkey, sighash)) { return false; } return true; } bool TransactionSignatureChecker::CheckLockTime( const CScriptNum &nLockTime) const { // There are two kinds of nLockTime: lock-by-blockheight and // lock-by-blocktime, distinguished by whether nLockTime < // LOCKTIME_THRESHOLD. // // We want to compare apples to apples, so fail the script unless the type // of nLockTime being tested is the same as the nLockTime in the // transaction. if (!((txTo->nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) || (txTo->nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD))) { return false; } // Now that we know we're comparing apples-to-apples, the comparison is a // simple numeric one. if (nLockTime > int64_t(txTo->nLockTime)) { return false; } // Finally the nLockTime feature can be disabled and thus // CHECKLOCKTIMEVERIFY bypassed if every txin has been finalized by setting // nSequence to maxint. The transaction would be allowed into the // blockchain, making the opcode ineffective. // // Testing if this vin is not final is sufficient to prevent this condition. // Alternatively we could test all inputs, but testing just this input // minimizes the data required to prove correct CHECKLOCKTIMEVERIFY // execution. if (CTxIn::SEQUENCE_FINAL == txTo->vin[nIn].nSequence) { return false; } return true; } bool TransactionSignatureChecker::CheckSequence( const CScriptNum &nSequence) const { // Relative lock times are supported by comparing the passed in operand to // the sequence number of the input. const int64_t txToSequence = int64_t(txTo->vin[nIn].nSequence); // Fail if the transaction's version number is not set high enough to // trigger BIP 68 rules. if (static_cast(txTo->nVersion) < 2) { return false; } // Sequence numbers with their most significant bit set are not consensus // constrained. Testing that the transaction's sequence number do not have // this bit set prevents using this property to get around a // CHECKSEQUENCEVERIFY check. if (txToSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) { return false; } // Mask off any bits that do not have consensus-enforced meaning before // doing the integer comparisons const uint32_t nLockTimeMask = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | CTxIn::SEQUENCE_LOCKTIME_MASK; const int64_t txToSequenceMasked = txToSequence & nLockTimeMask; const CScriptNum nSequenceMasked = nSequence & nLockTimeMask; // There are two kinds of nSequence: lock-by-blockheight and // lock-by-blocktime, distinguished by whether nSequenceMasked < // CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG. // // We want to compare apples to apples, so fail the script unless the type // of nSequenceMasked being tested is the same as the nSequenceMasked in the // transaction. if (!((txToSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) || (txToSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG))) { return false; } // Now that we know we're comparing apples-to-apples, the comparison is a // simple numeric one. if (nSequenceMasked > txToSequenceMasked) { return false; } return true; } bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, uint32_t flags, const BaseSignatureChecker &checker, ScriptError *serror) { set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); // If FORKID is enabled, we also ensure strict encoding. if (flags & SCRIPT_ENABLE_SIGHASH_FORKID) { flags |= SCRIPT_VERIFY_STRICTENC; } if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) { return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); } std::vector stack, stackCopy; if (!EvalScript(stack, scriptSig, flags, checker, serror)) { // serror is set return false; } if (flags & SCRIPT_VERIFY_P2SH) { stackCopy = stack; } if (!EvalScript(stack, scriptPubKey, flags, checker, serror)) { // serror is set return false; } if (stack.empty()) { return set_error(serror, SCRIPT_ERR_EVAL_FALSE); } if (CastToBool(stack.back()) == false) { return set_error(serror, SCRIPT_ERR_EVAL_FALSE); } // Additional validation for spend-to-script-hash transactions: if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) { // scriptSig must be literals-only or validation fails if (!scriptSig.IsPushOnly()) { return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); } // Restore stack. swap(stack, stackCopy); // stack cannot be empty here, because if it was the P2SH HASH <> EQUAL // scriptPubKey would be evaluated with an empty stack and the // EvalScript above would return false. assert(!stack.empty()); const valtype &pubKeySerialized = stack.back(); CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stack); if (!EvalScript(stack, pubKey2, flags, checker, serror)) { // serror is set return false; } if (stack.empty()) { return set_error(serror, SCRIPT_ERR_EVAL_FALSE); } if (!CastToBool(stack.back())) { return set_error(serror, SCRIPT_ERR_EVAL_FALSE); } } // The CLEANSTACK check is only performed after potential P2SH evaluation, // as the non-P2SH evaluation of a P2SH script will obviously not result in // a clean stack (the P2SH inputs remain). The same holds for witness // evaluation. if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0) { // Disallow CLEANSTACK without P2SH, as otherwise a switch // CLEANSTACK->P2SH+CLEANSTACK would be possible, which is not a // softfork (and P2SH should be one). assert((flags & SCRIPT_VERIFY_P2SH) != 0); if (stack.size() != 1) { return set_error(serror, SCRIPT_ERR_CLEANSTACK); } } return set_success(serror); } diff --git a/src/script/sigencoding.cpp b/src/script/sigencoding.cpp index 55c726fd61..ea76ded50e 100644 --- a/src/script/sigencoding.cpp +++ b/src/script/sigencoding.cpp @@ -1,239 +1,246 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2017-2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "sigencoding.h" #include "pubkey.h" #include "script_flags.h" #include +typedef boost::sliced_range slicedvaltype; + /** * A canonical signature exists of: <30> <02> <02> , where R and S are not negative (their first byte has its * highest bit not set), and not excessively padded (do not start with a 0 byte, * unless an otherwise negative number follows, in which case a single 0 byte is * necessary and even required). * * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 * * This function is consensus-critical since BIP66. */ -static bool -IsValidSignatureEncoding(const boost::sliced_range &sig) { +static bool IsValidSignatureEncoding(const slicedvaltype &sig) { // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] // * total-length: 1-byte length descriptor of everything that follows, // excluding the sighash byte. // * R-length: 1-byte length descriptor of the R value that follows. // * R: arbitrary-length big-endian encoded R value. It must use the // shortest possible encoding for a positive integers (which means no null // bytes at the start, except a single one when the next byte has its // highest bit set). // * S-length: 1-byte length descriptor of the S value that follows. // * S: arbitrary-length big-endian encoded S value. The same rules apply. // Minimum and maximum size constraints. if (sig.size() < 8 || sig.size() > 72) { return false; } // // Check that the signature is a coumpound structure of proper size. // // A signature is of type 0x30 (compound). if (sig[0] != 0x30) { return false; } // Make sure the length covers the entire signature. // Remove: // * 1 byte for the coupound type. // * 1 byte for the length of the signature. if (sig[1] != sig.size() - 2) { return false; } // // Check that R is an positive integer of sensible size. // // Check whether the R element is an integer. if (sig[2] != 0x02) { return false; } // Extract the length of the R element. const uint32_t lenR = sig[3]; // Zero-length integers are not allowed for R. if (lenR == 0) { return false; } // Negative numbers are not allowed for R. if (sig[4] & 0x80) { return false; } // Make sure the length of the R element is consistent with the signature // size. // Remove: // * 1 byte for the coumpound type. // * 1 byte for the length of the signature. // * 2 bytes for the integer type of R and S. // * 2 bytes for the size of R and S. // * 1 byte for S itself. if (lenR > (sig.size() - 7)) { return false; } // Null bytes at the start of R are not allowed, unless R would otherwise be // interpreted as a negative number. // // /!\ This check can only be performed after we checked that lenR is // consistent with the size of the signature or we risk to access out of // bound elements. if (lenR > 1 && (sig[4] == 0x00) && !(sig[5] & 0x80)) { return false; } // // Check that S is an positive integer of sensible size. // // S's definition starts after R's definition: // * 1 byte for the coumpound type. // * 1 byte for the length of the signature. // * 1 byte for the size of R. // * lenR bytes for R itself. // * 1 byte to get to S. const uint32_t startS = lenR + 4; // Check whether the S element is an integer. if (sig[startS] != 0x02) { return false; } // Extract the length of the S element. const uint32_t lenS = sig[startS + 1]; // Zero-length integers are not allowed for S. if (lenS == 0) { return false; } // Negative numbers are not allowed for S. if (sig[startS + 2] & 0x80) { return false; } // Verify that the length of S is consistent with the size of the signature // including metadatas: // * 1 byte for the integer type of S. // * 1 byte for the size of S. if (size_t(startS + lenS + 2) != sig.size()) { return false; } // Null bytes at the start of S are not allowed, unless S would otherwise be // interpreted as a negative number. // // /!\ This check can only be performed after we checked that lenR and lenS // are consistent with the size of the signature or we risk to access // out of bound elements. if (lenS > 1 && (sig[startS + 2] == 0x00) && !(sig[startS + 3] & 0x80)) { return false; } return true; } -static bool IsLowDERSignature(const valtype &vchSig, ScriptError *serror) { - assert(vchSig.size() > 0); - if (CPubKey::CheckLowS(vchSig | - boost::adaptors::sliced(0, vchSig.size() - 1))) { - return true; +static bool CheckRawSignatureEncoding(const slicedvaltype &sig, uint32_t flags, + ScriptError *serror) { + if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | + SCRIPT_VERIFY_STRICTENC)) && + !IsValidSignatureEncoding(sig)) { + return set_error(serror, SCRIPT_ERR_SIG_DER); } - return set_error(serror, SCRIPT_ERR_SIG_HIGH_S); + + if ((flags & SCRIPT_VERIFY_LOW_S) && !CPubKey::CheckLowS(sig)) { + return set_error(serror, SCRIPT_ERR_SIG_HIGH_S); + } + + return true; } -bool CheckSignatureEncoding(const valtype &vchSig, uint32_t flags, - ScriptError *serror) { +bool CheckTransactionSignatureEncoding(const valtype &vchSig, uint32_t flags, + ScriptError *serror) { // Empty signature. Not strictly DER encoded, but allowed to provide a // compact way to provide an invalid signature for use with CHECK(MULTI)SIG if (vchSig.size() == 0) { return true; } - if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | - SCRIPT_VERIFY_STRICTENC)) != 0 && - !IsValidSignatureEncoding( - vchSig | boost::adaptors::sliced(0, vchSig.size() - 1))) { - return set_error(serror, SCRIPT_ERR_SIG_DER); - } - if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && - !IsLowDERSignature(vchSig, serror)) { + + if (!CheckRawSignatureEncoding( + vchSig | boost::adaptors::sliced(0, vchSig.size() - 1), flags, + serror)) { // serror is set return false; } - if ((flags & SCRIPT_VERIFY_STRICTENC) != 0) { + + if (flags & SCRIPT_VERIFY_STRICTENC) { if (!GetHashType(vchSig).isDefined()) { return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE); } + bool usesForkId = GetHashType(vchSig).hasForkId(); bool forkIdEnabled = flags & SCRIPT_ENABLE_SIGHASH_FORKID; if (!forkIdEnabled && usesForkId) { return set_error(serror, SCRIPT_ERR_ILLEGAL_FORKID); } + if (forkIdEnabled && !usesForkId) { return set_error(serror, SCRIPT_ERR_MUST_USE_FORKID); } } + return true; } static bool IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) { switch (vchPubKey.size()) { case 33: // Compressed public key: must start with 0x02 or 0x03. return vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03; case 65: // Non-compressed public key: must start with 0x04. return vchPubKey[0] == 0x04; default: // Non-canonical public key: invalid size. return false; } } static bool IsCompressedPubKey(const valtype &vchPubKey) { if (vchPubKey.size() != 33) { // Non-canonical public key: invalid length for compressed key return false; } if (vchPubKey[0] != 0x02 && vchPubKey[0] != 0x03) { // Non-canonical public key: invalid prefix for compressed key return false; } return true; } bool CheckPubKeyEncoding(const valtype &vchPubKey, uint32_t flags, ScriptError *serror) { if ((flags & SCRIPT_VERIFY_STRICTENC) && !IsCompressedOrUncompressedPubKey(vchPubKey)) { return set_error(serror, SCRIPT_ERR_PUBKEYTYPE); } // Only compressed keys are accepted when // SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE is enabled. if ((flags & SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE) && !IsCompressedPubKey(vchPubKey)) { return set_error(serror, SCRIPT_ERR_NONCOMPRESSED_PUBKEY); } return true; } diff --git a/src/script/sigencoding.h b/src/script/sigencoding.h index d99f404fdb..e48a3b3515 100644 --- a/src/script/sigencoding.h +++ b/src/script/sigencoding.h @@ -1,35 +1,44 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2017-2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SCRIPT_SIGENCODING_H #define BITCOIN_SCRIPT_SIGENCODING_H #include "script_error.h" #include "sighashtype.h" #include #include typedef std::vector valtype; namespace { inline SigHashType GetHashType(const valtype &vchSig) { if (vchSig.size() == 0) { return SigHashType(0); } return SigHashType(vchSig[vchSig.size() - 1]); } } // namespace -bool CheckSignatureEncoding(const valtype &vchSig, uint32_t flags, - ScriptError *serror); +/** + * Check that the signature provided to authentify a transaction is properly + * encoded. Signatures passed to OP_CHECKSIG, OP_CHECKMULTISIG and their verify + * variants must be checked using this function. + */ +bool CheckTransactionSignatureEncoding(const valtype &vchSig, uint32_t flags, + ScriptError *serror); + +/** + * Check that a public key is encoded properly. + */ bool CheckPubKeyEncoding(const valtype &vchPubKey, uint32_t flags, ScriptError *serror); #endif // BITCOIN_SCRIPT_SIGENCODING_H diff --git a/src/test/sigencoding_tests.cpp b/src/test/sigencoding_tests.cpp index b132a02c50..e903161f1a 100644 --- a/src/test/sigencoding_tests.cpp +++ b/src/test/sigencoding_tests.cpp @@ -1,367 +1,369 @@ // Copyright (c) 2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "test/test_bitcoin.h" #include "script/script_flags.h" #include "script/sigencoding.h" #include BOOST_FIXTURE_TEST_SUITE(sigencoding_tests, BasicTestingSetup) static valtype SignatureWithHashType(valtype vchSig, SigHashType sigHash) { vchSig.push_back(static_cast(sigHash.getRawSigHashType())); return vchSig; } static void CheckSignatureErrorForAllSigHashType(const valtype &vchSig, uint32_t flags, const ScriptError expected_error) { for (int i = 0; i <= 0xff; i++) { ScriptError err = SCRIPT_ERR_OK; valtype sig = SignatureWithHashType(vchSig, SigHashType(i)); - BOOST_CHECK(!CheckSignatureEncoding(sig, flags, &err)); + BOOST_CHECK(!CheckTransactionSignatureEncoding(sig, flags, &err)); BOOST_CHECK_EQUAL(err, expected_error); } } static void CheckSignatureEncodingWithSigHashType(const valtype &vchSig, uint32_t flags) { const bool hasForkId = (flags & SCRIPT_ENABLE_SIGHASH_FORKID) != 0; const bool hasStrictEnc = (flags & SCRIPT_VERIFY_STRICTENC) != 0; std::vector allBaseTypes{ BaseSigHashType::ALL, BaseSigHashType::NONE, BaseSigHashType::SINGLE}; std::vector baseSigHashes; for (const BaseSigHashType baseType : allBaseTypes) { const SigHashType baseSigHash = SigHashType().withBaseType(baseType); baseSigHashes.push_back(baseSigHash); baseSigHashes.push_back(baseSigHash.withAnyoneCanPay(true)); } for (const SigHashType baseSigHash : baseSigHashes) { ScriptError err = SCRIPT_ERR_OK; // Check the signature with the proper forkid flag. SigHashType sigHash = baseSigHash.withForkId(hasForkId); valtype validSig = SignatureWithHashType(vchSig, sigHash); - BOOST_CHECK(CheckSignatureEncoding(validSig, flags, &err)); + BOOST_CHECK(CheckTransactionSignatureEncoding(validSig, flags, &err)); // If we have strict encoding, we prevent the use of undefined flags. std::array undefSigHashes{ SigHashType(sigHash.getRawSigHashType() | 0x20), sigHash.withBaseType(BaseSigHashType::UNSUPPORTED), }; for (SigHashType undefSigHash : undefSigHashes) { valtype undefSighash = SignatureWithHashType(vchSig, undefSigHash); - BOOST_CHECK_EQUAL(CheckSignatureEncoding(undefSighash, flags, &err), - !hasStrictEnc); + BOOST_CHECK_EQUAL( + CheckTransactionSignatureEncoding(undefSighash, flags, &err), + !hasStrictEnc); if (hasStrictEnc) { BOOST_CHECK_EQUAL(err, SCRIPT_ERR_SIG_HASHTYPE); } } // If we check strict encoding, then invalid forkid is an error. SigHashType invalidSigHash = baseSigHash.withForkId(!hasForkId); valtype invalidSig = SignatureWithHashType(vchSig, invalidSigHash); - BOOST_CHECK_EQUAL(CheckSignatureEncoding(invalidSig, flags, &err), - !hasStrictEnc); + BOOST_CHECK_EQUAL( + CheckTransactionSignatureEncoding(invalidSig, flags, &err), + !hasStrictEnc); if (hasStrictEnc) { BOOST_CHECK_EQUAL(err, hasForkId ? SCRIPT_ERR_MUST_USE_FORKID : SCRIPT_ERR_ILLEGAL_FORKID); } } } BOOST_AUTO_TEST_CASE(checksignatureencoding_test) { valtype minimalSig{0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; valtype highSSig{ 0x30, 0x45, 0x02, 0x20, 0x3e, 0x45, 0x16, 0xda, 0x72, 0x53, 0xcf, 0x06, 0x8e, 0xff, 0xec, 0x6b, 0x95, 0xc4, 0x12, 0x21, 0xc0, 0xcf, 0x3a, 0x8e, 0x6c, 0xcb, 0x8c, 0xbf, 0x17, 0x25, 0xb5, 0x62, 0xe9, 0xaf, 0xde, 0x2c, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0}; std::vector nonDERSigs{ // Non canonical total length. {0x30, 0x80, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}, // Zero length R. {0x30, 0x2f, 0x02, 0x00, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0}, // Non canonical length for R. {0x30, 0x31, 0x02, 0x80, 0x01, 0x6c, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0}, // Negative R. {0x30, 0x30, 0x02, 0x01, 0x80, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0}, // Null prefixed R. {0x30, 0x31, 0x02, 0x02, 0x00, 0x01, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0}, // Zero length S. {0x30, 0x2f, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0, 0x02, 0x00}, // Non canonical length for S. {0x30, 0x31, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0, 0x02, 0x80, 0x01, 0x6c}, // Negative S. {0x30, 0x30, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0, 0x02, 0x01, 0x80}, // Null prefixed S. {0x30, 0x31, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0, 0x02, 0x02, 0x00, 0x01}, }; std::vector nonParsableSigs{ // Too short. {0x30}, {0x30, 0x06}, {0x30, 0x06, 0x02}, {0x30, 0x06, 0x02, 0x01}, {0x30, 0x06, 0x02, 0x01, 0x01}, {0x30, 0x06, 0x02, 0x01, 0x01, 0x02}, {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01}, // Invalid type (must be 0x30, coumpound). {0x42, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}, // Invalid sizes. {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}, {0x30, 0x07, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}, // Invalid R and S sizes. {0x30, 0x06, 0x02, 0x00, 0x01, 0x02, 0x01, 0x01}, {0x30, 0x06, 0x02, 0x02, 0x01, 0x02, 0x01, 0x01}, {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x00, 0x01}, {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01}, // Invalid R and S types. {0x30, 0x06, 0x42, 0x01, 0x01, 0x02, 0x01, 0x01}, {0x30, 0x06, 0x02, 0x01, 0x01, 0x42, 0x01, 0x01}, // Too long. {0x30, 0x47, 0x02, 0x21, 0x00, 0x8e, 0x45, 0x16, 0xda, 0x72, 0x53, 0xcf, 0x06, 0x8e, 0xff, 0xec, 0x6b, 0x95, 0xc4, 0x12, 0x21, 0xc0, 0xcf, 0x3a, 0x8e, 0x6c, 0xcb, 0x8c, 0xbf, 0x17, 0x25, 0xb5, 0x62, 0xe9, 0xaf, 0xde, 0x2c, 0x02, 0x22, 0x00, 0xab, 0x1e, 0x3d, 0x00, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0}, }; // If we add many more flags, this loop can get too expensive, but we can // rewrite in the future to randomly pick a set of flags to evaluate. for (uint32_t flags = 0; flags < (1U << 17); flags++) { ScriptError err = SCRIPT_ERR_OK; // Empty sig is always valid. - BOOST_CHECK(CheckSignatureEncoding({}, flags, &err)); + BOOST_CHECK(CheckTransactionSignatureEncoding({}, flags, &err)); // Signature are valid as long as the forkid flag is correct. CheckSignatureEncodingWithSigHashType(minimalSig, flags); if (flags & SCRIPT_VERIFY_LOW_S) { // If we do enforce low S, then high S sigs are rejected. CheckSignatureErrorForAllSigHashType(highSSig, flags, SCRIPT_ERR_SIG_HIGH_S); } else { // If we do not enforce low S, then high S sigs are accepted. CheckSignatureEncodingWithSigHashType(highSSig, flags); } for (const valtype &nonDERSig : nonDERSigs) { if (flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) { // If we get any of the dersig flags, the non canonical dersig // signature fails. CheckSignatureErrorForAllSigHashType(nonDERSig, flags, SCRIPT_ERR_SIG_DER); } else { // If we do not check, then it is accepted. CheckSignatureEncodingWithSigHashType(nonDERSig, flags); } } for (const valtype &nonDERSig : nonParsableSigs) { if (flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) { // If we get any of the dersig flags, the invalid signature // fails. CheckSignatureErrorForAllSigHashType(nonDERSig, flags, SCRIPT_ERR_SIG_DER); } else { // If we do not check, then it is accepted even though it cannot // even be parsed. CheckSignatureEncodingWithSigHashType(nonDERSig, flags); } } } } BOOST_AUTO_TEST_CASE(checkpubkeyencoding_test) { valtype compressedKey0{0x02, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}; valtype compressedKey1{0x03, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}; valtype fullKey{0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}; std::vector invalidKeys{ // Degenerate keys. {}, {0x00}, {0x01}, {0x02}, {0x03}, {0x04}, {0x05}, {0x42}, {0xff}, // Invalid first byte 0x00. {0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, {0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, // Invalid first byte 0x01. {0x01, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, {0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, // Invalid first byte 0x05. {0x05, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, {0x05, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, // Invalid first byte 0xff. {0xff, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, {0xff, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, // Compressed key too short. {0x02, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, {0x03, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, // Compressed key too long. {0x02, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0xab, 0xba, 0x9a, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, {0x03, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xab, 0xba, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, // Compressed key, full key size. {0x02, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, {0x03, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, // Full key, too short. {0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, // Full key, too long. {0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x56, 0x78, 0xab, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, // Full key, compressed key size. {0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0xab, 0xba, 0x9a, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, }; // If we add many more flags, this loop can get too expensive, but we can // rewrite in the future to randomly pick a set of flags to evaluate. for (uint32_t flags = 0; flags < (1U << 17); flags++) { ScriptError err = SCRIPT_ERR_OK; // Compressed pubkeys are always valid. BOOST_CHECK(CheckPubKeyEncoding(compressedKey0, flags, &err)); BOOST_CHECK(CheckPubKeyEncoding(compressedKey1, flags, &err)); // If SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE is specified, full key are // disabled. const bool allowFullKey = (flags & SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE) == 0; BOOST_CHECK_EQUAL(CheckPubKeyEncoding(fullKey, flags, &err), allowFullKey); if (!allowFullKey) { BOOST_CHECK_EQUAL(err, SCRIPT_ERR_NONCOMPRESSED_PUBKEY); } // If SCRIPT_VERIFY_STRICTENC or SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE is // specified, we rule out invalid keys. const bool hasStrictEnc = (flags & SCRIPT_VERIFY_STRICTENC) != 0; const bool allowInvalidKeys = allowFullKey && !hasStrictEnc; for (const valtype &key : invalidKeys) { BOOST_CHECK_EQUAL(CheckPubKeyEncoding(key, flags, &err), allowInvalidKeys); if (!allowInvalidKeys) { BOOST_CHECK_EQUAL(err, hasStrictEnc ? SCRIPT_ERR_PUBKEYTYPE : SCRIPT_ERR_NONCOMPRESSED_PUBKEY); } } } } BOOST_AUTO_TEST_SUITE_END()