diff options
Diffstat (limited to 'src/script')
| -rw-r--r-- | src/script/bitcoinconsensus.cpp | 91 | ||||
| -rw-r--r-- | src/script/bitcoinconsensus.h | 67 | ||||
| -rw-r--r-- | src/script/compressor.cpp | 127 | ||||
| -rw-r--r-- | src/script/compressor.h | 84 | ||||
| -rw-r--r-- | src/script/interpreter.cpp | 583 | ||||
| -rw-r--r-- | src/script/interpreter.h | 95 | ||||
| -rw-r--r-- | src/script/script.cpp | 53 | ||||
| -rw-r--r-- | src/script/script.h | 163 | ||||
| -rw-r--r-- | src/script/script_error.cpp | 71 | ||||
| -rw-r--r-- | src/script/script_error.h | 58 | ||||
| -rw-r--r-- | src/script/sigcache.cpp | 90 | ||||
| -rw-r--r-- | src/script/sigcache.h | 26 | ||||
| -rw-r--r-- | src/script/sign.cpp | 34 | ||||
| -rw-r--r-- | src/script/sign.h | 16 | ||||
| -rw-r--r-- | src/script/standard.cpp | 39 | ||||
| -rw-r--r-- | src/script/standard.h | 59 |
16 files changed, 1021 insertions, 635 deletions
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp new file mode 100644 index 000000000..c8dd54a74 --- /dev/null +++ b/src/script/bitcoinconsensus.cpp @@ -0,0 +1,91 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 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 "bitcoinconsensus.h" + +#include "primitives/transaction.h" +#include "script/interpreter.h" +#include "version.h" + +namespace { + +/** A class that deserializes a single CTransaction one time. */ +class TxInputStream +{ +public: + TxInputStream(int nTypeIn, int nVersionIn, const unsigned char *txTo, size_t txToLen) : + m_type(nTypeIn), + m_version(nVersionIn), + m_data(txTo), + m_remaining(txToLen) + {} + + TxInputStream& read(char* pch, size_t nSize) + { + if (nSize > m_remaining) + throw std::ios_base::failure(std::string(__func__) + ": end of data"); + + if (pch == NULL) + throw std::ios_base::failure(std::string(__func__) + ": bad destination buffer"); + + if (m_data == NULL) + throw std::ios_base::failure(std::string(__func__) + ": bad source buffer"); + + memcpy(pch, m_data, nSize); + m_remaining -= nSize; + m_data += nSize; + return *this; + } + + template<typename T> + TxInputStream& operator>>(T& obj) + { + ::Unserialize(*this, obj, m_type, m_version); + return *this; + } + +private: + const int m_type; + const int m_version; + const unsigned char* m_data; + size_t m_remaining; +}; + +inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror) +{ + if (ret) + *ret = serror; + return 0; +} + +} // anon namespace + +int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, + const unsigned char *txTo , unsigned int txToLen, + unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err) +{ + try { + TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen); + CTransaction tx; + stream >> tx; + if (nIn >= tx.vin.size()) + return set_error(err, bitcoinconsensus_ERR_TX_INDEX); + if (tx.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) != txToLen) + return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH); + + // Regardless of the verification result, the tx did not error. + set_error(err, bitcoinconsensus_ERR_OK); + + return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, SignatureChecker(tx, nIn), NULL); + } catch (const std::exception&) { + return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing + } +} + +unsigned int bitcoinconsensus_version() +{ + // Just use the API version for now + return BITCOINCONSENSUS_API_VER; +} diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h new file mode 100644 index 000000000..9d9c26643 --- /dev/null +++ b/src/script/bitcoinconsensus.h @@ -0,0 +1,67 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_BITCOINCONSENSUS_H +#define BITCOIN_BITCOINCONSENSUS_H + +#if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" + #if defined(_WIN32) + #if defined(DLL_EXPORT) + #if defined(HAVE_FUNC_ATTRIBUTE_DLLEXPORT) + #define EXPORT_SYMBOL __declspec(dllexport) + #else + #define EXPORT_SYMBOL + #endif + #endif + #elif defined(HAVE_FUNC_ATTRIBUTE_VISIBILITY) + #define EXPORT_SYMBOL __attribute__ ((visibility ("default"))) + #endif +#elif defined(MSC_VER) && !defined(STATIC_LIBBITCOINCONSENSUS) + #define EXPORT_SYMBOL __declspec(dllimport) +#endif + +#ifndef EXPORT_SYMBOL + #define EXPORT_SYMBOL +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define BITCOINCONSENSUS_API_VER 0 + +typedef enum bitcoinconsensus_error_t +{ + bitcoinconsensus_ERR_OK = 0, + bitcoinconsensus_ERR_TX_INDEX, + bitcoinconsensus_ERR_TX_SIZE_MISMATCH, + bitcoinconsensus_ERR_TX_DESERIALIZE, +} bitcoinconsensus_error; + +/** Script verification flags */ +enum +{ + bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0, + bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts +}; + +/// Returns 1 if the input nIn of the serialized transaction pointed to by +/// txTo correctly spends the scriptPubKey pointed to by scriptPubKey under +/// the additional constraints specified by flags. +/// If not NULL, err will contain an error/success code for the operation +EXPORT_SYMBOL int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, + const unsigned char *txTo , unsigned int txToLen, + unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err); + +EXPORT_SYMBOL unsigned int bitcoinconsensus_version(); + +#ifdef __cplusplus +} // extern "C" +#endif + +#undef EXPORT_SYMBOL + +#endif // BITCOIN_BITCOINCONSENSUS_H diff --git a/src/script/compressor.cpp b/src/script/compressor.cpp deleted file mode 100644 index 51a3cf602..000000000 --- a/src/script/compressor.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "compressor.h" - -bool CScriptCompressor::IsToKeyID(CKeyID &hash) const -{ - if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 - && script[2] == 20 && script[23] == OP_EQUALVERIFY - && script[24] == OP_CHECKSIG) { - memcpy(&hash, &script[3], 20); - return true; - } - return false; -} - -bool CScriptCompressor::IsToScriptID(CScriptID &hash) const -{ - if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20 - && script[22] == OP_EQUAL) { - memcpy(&hash, &script[2], 20); - return true; - } - return false; -} - -bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const -{ - if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG - && (script[1] == 0x02 || script[1] == 0x03)) { - pubkey.Set(&script[1], &script[34]); - return true; - } - if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG - && script[1] == 0x04) { - pubkey.Set(&script[1], &script[66]); - return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible - } - return false; -} - -bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const -{ - CKeyID keyID; - if (IsToKeyID(keyID)) { - out.resize(21); - out[0] = 0x00; - memcpy(&out[1], &keyID, 20); - return true; - } - CScriptID scriptID; - if (IsToScriptID(scriptID)) { - out.resize(21); - out[0] = 0x01; - memcpy(&out[1], &scriptID, 20); - return true; - } - CPubKey pubkey; - if (IsToPubKey(pubkey)) { - out.resize(33); - memcpy(&out[1], &pubkey[1], 32); - if (pubkey[0] == 0x02 || pubkey[0] == 0x03) { - out[0] = pubkey[0]; - return true; - } else if (pubkey[0] == 0x04) { - out[0] = 0x04 | (pubkey[64] & 0x01); - return true; - } - } - return false; -} - -unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const -{ - if (nSize == 0 || nSize == 1) - return 20; - if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5) - return 32; - return 0; -} - -bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigned char> &in) -{ - switch(nSize) { - case 0x00: - script.resize(25); - script[0] = OP_DUP; - script[1] = OP_HASH160; - script[2] = 20; - memcpy(&script[3], &in[0], 20); - script[23] = OP_EQUALVERIFY; - script[24] = OP_CHECKSIG; - return true; - case 0x01: - script.resize(23); - script[0] = OP_HASH160; - script[1] = 20; - memcpy(&script[2], &in[0], 20); - script[22] = OP_EQUAL; - return true; - case 0x02: - case 0x03: - script.resize(35); - script[0] = 33; - script[1] = nSize; - memcpy(&script[2], &in[0], 32); - script[34] = OP_CHECKSIG; - return true; - case 0x04: - case 0x05: - unsigned char vch[33] = {}; - vch[0] = nSize - 2; - memcpy(&vch[1], &in[0], 32); - CPubKey pubkey(&vch[0], &vch[33]); - if (!pubkey.Decompress()) - return false; - assert(pubkey.size() == 65); - script.resize(67); - script[0] = 65; - memcpy(&script[1], pubkey.begin(), 65); - script[66] = OP_CHECKSIG; - return true; - } - return false; -} diff --git a/src/script/compressor.h b/src/script/compressor.h deleted file mode 100644 index 53c6bf3ec..000000000 --- a/src/script/compressor.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef H_BITCOIN_SCRIPT_COMPRESSOR -#define H_BITCOIN_SCRIPT_COMPRESSOR - -#include "script/script.h" - -/** Compact serializer for scripts. - * - * It detects common cases and encodes them much more efficiently. - * 3 special cases are defined: - * * Pay to pubkey hash (encoded as 21 bytes) - * * Pay to script hash (encoded as 21 bytes) - * * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes) - * - * Other scripts up to 121 bytes require 1 byte + script length. Above - * that, scripts up to 16505 bytes require 2 bytes + script length. - */ -class CScriptCompressor -{ -private: - // make this static for now (there are only 6 special scripts defined) - // this can potentially be extended together with a new nVersion for - // transactions, in which case this value becomes dependent on nVersion - // and nHeight of the enclosing transaction. - static const unsigned int nSpecialScripts = 6; - - CScript &script; -protected: - // These check for scripts for which a special case with a shorter encoding is defined. - // They are implemented separately from the CScript test, as these test for exact byte - // sequence correspondences, and are more strict. For example, IsToPubKey also verifies - // whether the public key is valid (as invalid ones cannot be represented in compressed - // form). - bool IsToKeyID(CKeyID &hash) const; - bool IsToScriptID(CScriptID &hash) const; - bool IsToPubKey(CPubKey &pubkey) const; - - bool Compress(std::vector<unsigned char> &out) const; - unsigned int GetSpecialSize(unsigned int nSize) const; - bool Decompress(unsigned int nSize, const std::vector<unsigned char> &out); -public: - CScriptCompressor(CScript &scriptIn) : script(scriptIn) { } - - unsigned int GetSerializeSize(int nType, int nVersion) const { - std::vector<unsigned char> compr; - if (Compress(compr)) - return compr.size(); - unsigned int nSize = script.size() + nSpecialScripts; - return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion); - } - - template<typename Stream> - void Serialize(Stream &s, int nType, int nVersion) const { - std::vector<unsigned char> compr; - if (Compress(compr)) { - s << CFlatData(compr); - return; - } - unsigned int nSize = script.size() + nSpecialScripts; - s << VARINT(nSize); - s << CFlatData(script); - } - - template<typename Stream> - void Unserialize(Stream &s, int nType, int nVersion) { - unsigned int nSize = 0; - s >> VARINT(nSize); - if (nSize < nSpecialScripts) { - std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00); - s >> REF(CFlatData(vch)); - Decompress(nSize, vch); - return; - } - nSize -= nSpecialScripts; - script.resize(nSize); - s >> REF(CFlatData(script)); - } -}; - -#endif // H_BITCOIN_SCRIPT_COMPRESSOR diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index a71f55dd2..8a06f3d11 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1,32 +1,40 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2014 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 "interpreter.h" -#include "core.h" +#include "primitives/transaction.h" #include "crypto/ripemd160.h" #include "crypto/sha1.h" -#include "crypto/sha2.h" -#include "random.h" +#include "crypto/sha256.h" +#include "eccryptoverify.h" +#include "pubkey.h" #include "script/script.h" #include "uint256.h" -#include "util.h" - -#include <boost/thread.hpp> -#include <boost/tuple/tuple_comparison.hpp> using namespace std; typedef vector<unsigned char> valtype; -static const valtype vchFalse(0); -static const valtype vchZero(0); -static const valtype vchTrue(1, 1); -static const CScriptNum bnZero(0); -static const CScriptNum bnOne(1); -static const CScriptNum bnFalse(0); -static const CScriptNum bnTrue(1); + +namespace { + +inline bool set_success(ScriptError* ret) +{ + if (ret) + *ret = SCRIPT_ERR_OK; + return true; +} + +inline bool set_error(ScriptError* ret, const ScriptError serror) +{ + if (ret) + *ret = serror; + return false; +} + +} // anon namespace bool CastToBool(const valtype& vch) { @@ -43,10 +51,10 @@ bool CastToBool(const valtype& vch) return false; } -// -// Script is a stack machine (like Forth) that evaluates a predicate -// returning a bool indicating valid or not. There are no loops. -// +/** + * 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(vector<valtype>& stack) @@ -56,84 +64,187 @@ static inline void popstack(vector<valtype>& stack) stack.pop_back(); } -bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) { - if (!(flags & SCRIPT_VERIFY_STRICTENC)) - return true; - - if (vchPubKey.size() < 33) - return error("Non-canonical public key: too short"); +bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) { + if (vchPubKey.size() < 33) { + // Non-canonical public key: too short + return false; + } if (vchPubKey[0] == 0x04) { - if (vchPubKey.size() != 65) - return error("Non-canonical public key: invalid length for uncompressed key"); + if (vchPubKey.size() != 65) { + // Non-canonical public key: invalid length for uncompressed key + return false; + } } else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) { - if (vchPubKey.size() != 33) - return error("Non-canonical public key: invalid length for compressed key"); + if (vchPubKey.size() != 33) { + // Non-canonical public key: invalid length for compressed key + return false; + } } else { - return error("Non-canonical public key: neither compressed nor uncompressed"); + // Non-canonical public key: neither compressed nor uncompressed + return false; } return true; } -bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { - if (!(flags & SCRIPT_VERIFY_STRICTENC)) - return true; +/** + * A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype> + * 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 + */ +bool static IsDERSignature(const valtype &vchSig) { - // See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 - // A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype> - // 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). - if (vchSig.size() < 9) - return error("Non-canonical signature: too short"); - if (vchSig.size() > 73) - return error("Non-canonical signature: too long"); - unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); - if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) - return error("Non-canonical signature: unknown hashtype byte"); - if (vchSig[0] != 0x30) - return error("Non-canonical signature: wrong type"); - if (vchSig[1] != vchSig.size()-3) - return error("Non-canonical signature: wrong length marker"); + if (vchSig.size() < 9) { + // Non-canonical signature: too short + return false; + } + if (vchSig.size() > 73) { + // Non-canonical signature: too long + return false; + } + if (vchSig[0] != 0x30) { + // Non-canonical signature: wrong type + return false; + } + if (vchSig[1] != vchSig.size()-3) { + // Non-canonical signature: wrong length marker + return false; + } unsigned int nLenR = vchSig[3]; - if (5 + nLenR >= vchSig.size()) - return error("Non-canonical signature: S length misplaced"); + if (5 + nLenR >= vchSig.size()) { + // Non-canonical signature: S length misplaced + return false; + } unsigned int nLenS = vchSig[5+nLenR]; - if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) - return error("Non-canonical signature: R+S length mismatch"); + if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) { + // Non-canonical signature: R+S length mismatch + return false; + } const unsigned char *R = &vchSig[4]; - if (R[-2] != 0x02) - return error("Non-canonical signature: R value type mismatch"); - if (nLenR == 0) - return error("Non-canonical signature: R length is zero"); - if (R[0] & 0x80) - return error("Non-canonical signature: R value negative"); - if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80)) - return error("Non-canonical signature: R value excessively padded"); + if (R[-2] != 0x02) { + // Non-canonical signature: R value type mismatch + return false; + } + if (nLenR == 0) { + // Non-canonical signature: R length is zero + return false; + } + if (R[0] & 0x80) { + // Non-canonical signature: R value negative + return false; + } + if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80)) { + // Non-canonical signature: R value excessively padded + return false; + } + + const unsigned char *S = &vchSig[6+nLenR]; + if (S[-2] != 0x02) { + // Non-canonical signature: S value type mismatch + return false; + } + if (nLenS == 0) { + // Non-canonical signature: S length is zero + return false; + } + if (S[0] & 0x80) { + // Non-canonical signature: S value negative + return false; + } + if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) { + // Non-canonical signature: S value excessively padded + return false; + } + return true; +} +bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) { + if (!IsDERSignature(vchSig)) { + return set_error(serror, SCRIPT_ERR_SIG_DER); + } + unsigned int nLenR = vchSig[3]; + unsigned int nLenS = vchSig[5+nLenR]; const unsigned char *S = &vchSig[6+nLenR]; - if (S[-2] != 0x02) - return error("Non-canonical signature: S value type mismatch"); - if (nLenS == 0) - return error("Non-canonical signature: S length is zero"); - if (S[0] & 0x80) - return error("Non-canonical signature: S value negative"); - if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) - return error("Non-canonical signature: S value excessively padded"); - - if (flags & SCRIPT_VERIFY_LOW_S) { - // If the S value is above the order of the curve divided by two, its - // complement modulo the order could have been used instead, which is - // one byte shorter when encoded correctly. - if (!CKey::CheckSignatureElement(S, nLenS, true)) - return error("Non-canonical signature: S value is unnecessarily high"); + // If the S value is above the order of the curve divided by two, its + // complement modulo the order could have been used instead, which is + // one byte shorter when encoded correctly. + if (!eccrypto::CheckSignatureElement(S, nLenS, true)) + return set_error(serror, SCRIPT_ERR_SIG_HIGH_S); + + return true; +} + +bool static IsDefinedHashtypeSignature(const valtype &vchSig) { + if (vchSig.size() == 0) { + return false; + } + unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); + if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) + return false; + + return true; +} + +bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int 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 && !IsDERSignature(vchSig)) { + return set_error(serror, SCRIPT_ERR_SIG_DER); + } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) { + // serror is set + return false; + } else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSig)) { + return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE); + } + return true; +} + +bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) { + if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchSig)) { + return set_error(serror, SCRIPT_ERR_PUBKEYTYPE); } + return true; +} +bool static CheckMinimalPush(const valtype& data, opcodetype opcode) { + if (data.size() == 0) { + // Could have used OP_0. + return opcode == OP_0; + } else if (data.size() == 1 && data[0] >= 1 && data[0] <= 16) { + // Could have used OP_1 .. OP_16. + return opcode == OP_1 + (data[0] - 1); + } else if (data.size() == 1 && data[0] == 0x81) { + // Could have used OP_1NEGATE. + return opcode == OP_1NEGATE; + } else if (data.size() <= 75) { + // Could have used a direct push (opcode indicating number of bytes pushed + those bytes). + return opcode == data.size(); + } else if (data.size() <= 255) { + // Could have used OP_PUSHDATA. + return opcode == OP_PUSHDATA1; + } else if (data.size() <= 65535) { + // Could have used OP_PUSHDATA2. + return opcode == OP_PUSHDATA2; + } return true; } -bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags) +bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { + static const CScriptNum bnZero(0); + static const CScriptNum bnOne(1); + static const CScriptNum bnFalse(0); + static const CScriptNum bnTrue(1); + static const valtype vchFalse(0); + static const valtype vchZero(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(); @@ -141,9 +252,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co valtype vchPushValue; vector<bool> vfExec; vector<valtype> altstack; + set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); if (script.size() > 10000) - return false; + return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE); int nOpCount = 0; + bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; try { @@ -155,13 +268,13 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // Read instruction // if (!script.GetOp(pc, opcode, vchPushValue)) - return false; + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) - return false; + return set_error(serror, SCRIPT_ERR_PUSH_SIZE); // Note how OP_RESERVED does not count towards the opcode limit. if (opcode > OP_16 && ++nOpCount > 201) - return false; + return set_error(serror, SCRIPT_ERR_OP_COUNT); if (opcode == OP_CAT || opcode == OP_SUBSTR || @@ -178,11 +291,14 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT) - return false; // Disabled opcodes. + return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes. - if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) + 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)) + } else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) switch (opcode) { // @@ -209,6 +325,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // ( -- 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; @@ -217,8 +335,14 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // Control // case OP_NOP: + break; + case OP_NOP1: case OP_NOP2: case OP_NOP3: 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: @@ -229,7 +353,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co if (fExec) { if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); valtype& vch = stacktop(-1); fValue = CastToBool(vch); if (opcode == OP_NOTIF) @@ -243,7 +367,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co case OP_ELSE: { if (vfExec.empty()) - return false; + return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); vfExec.back() = !vfExec.back(); } break; @@ -251,7 +375,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co case OP_ENDIF: { if (vfExec.empty()) - return false; + return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); vfExec.pop_back(); } break; @@ -261,18 +385,18 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // (true -- ) or // (false -- false) and return if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); bool fValue = CastToBool(stacktop(-1)); if (fValue) popstack(stack); else - return false; + return set_error(serror, SCRIPT_ERR_VERIFY); } break; case OP_RETURN: { - return false; + return set_error(serror, SCRIPT_ERR_OP_RETURN); } break; @@ -283,7 +407,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co case OP_TOALTSTACK: { if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); altstack.push_back(stacktop(-1)); popstack(stack); } @@ -292,7 +416,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co case OP_FROMALTSTACK: { if (altstack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_ALTSTACK_OPERATION); stack.push_back(altstacktop(-1)); popstack(altstack); } @@ -302,7 +426,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x1 x2 -- ) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); popstack(stack); popstack(stack); } @@ -312,7 +436,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x1 x2 -- x1 x2 x1 x2) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch1 = stacktop(-2); valtype vch2 = stacktop(-1); stack.push_back(vch1); @@ -324,7 +448,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) if (stack.size() < 3) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch1 = stacktop(-3); valtype vch2 = stacktop(-2); valtype vch3 = stacktop(-1); @@ -338,7 +462,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) if (stack.size() < 4) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch1 = stacktop(-4); valtype vch2 = stacktop(-3); stack.push_back(vch1); @@ -350,7 +474,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) if (stack.size() < 6) - return false; + 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); @@ -363,7 +487,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x1 x2 x3 x4 -- x3 x4 x1 x2) if (stack.size() < 4) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); swap(stacktop(-4), stacktop(-2)); swap(stacktop(-3), stacktop(-1)); } @@ -373,7 +497,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x - 0 | x x) if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch = stacktop(-1); if (CastToBool(vch)) stack.push_back(vch); @@ -392,7 +516,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x -- ) if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); popstack(stack); } break; @@ -401,7 +525,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x -- x x) if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch = stacktop(-1); stack.push_back(vch); } @@ -411,7 +535,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x1 x2 -- x2) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); stack.erase(stack.end() - 2); } break; @@ -420,7 +544,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x1 x2 -- x1 x2 x1) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch = stacktop(-2); stack.push_back(vch); } @@ -432,11 +556,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) if (stack.size() < 2) - return false; - int n = CScriptNum(stacktop(-1)).getint(); + 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 false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch = stacktop(-n-1); if (opcode == OP_ROLL) stack.erase(stack.end()-n-1); @@ -450,7 +574,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // x2 x1 x3 after first swap // x2 x3 x1 after second swap if (stack.size() < 3) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); swap(stacktop(-3), stacktop(-2)); swap(stacktop(-2), stacktop(-1)); } @@ -460,7 +584,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x1 x2 -- x2 x1) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); swap(stacktop(-2), stacktop(-1)); } break; @@ -469,7 +593,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x1 x2 -- x2 x1 x2) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch = stacktop(-1); stack.insert(stack.end()-2, vch); } @@ -480,7 +604,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (in -- in size) if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); CScriptNum bn(stacktop(-1).size()); stack.push_back(bn.getvch()); } @@ -496,7 +620,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x1 x2 - bool) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype& vch1 = stacktop(-2); valtype& vch2 = stacktop(-1); bool fEqual = (vch1 == vch2); @@ -513,7 +637,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co if (fEqual) popstack(stack); else - return false; + return set_error(serror, SCRIPT_ERR_EQUALVERIFY); } } break; @@ -531,8 +655,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (in -- out) if (stack.size() < 1) - return false; - CScriptNum bn(stacktop(-1)); + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + CScriptNum bn(stacktop(-1), fRequireMinimal); switch (opcode) { case OP_1ADD: bn += bnOne; break; @@ -564,9 +688,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x1 x2 -- out) if (stack.size() < 2) - return false; - CScriptNum bn1(stacktop(-2)); - CScriptNum bn2(stacktop(-1)); + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + CScriptNum bn1(stacktop(-2), fRequireMinimal); + CScriptNum bn2(stacktop(-1), fRequireMinimal); CScriptNum bn(0); switch (opcode) { @@ -600,7 +724,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co if (CastToBool(stacktop(-1))) popstack(stack); else - return false; + return set_error(serror, SCRIPT_ERR_NUMEQUALVERIFY); } } break; @@ -609,10 +733,10 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (x min max -- out) if (stack.size() < 3) - return false; - CScriptNum bn1(stacktop(-3)); - CScriptNum bn2(stacktop(-2)); - CScriptNum bn3(stacktop(-1)); + 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); @@ -633,7 +757,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (in -- hash) if (stack.size() < 1) - return false; + 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) @@ -663,7 +787,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { // (sig pubkey -- bool) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype& vchSig = stacktop(-2); valtype& vchPubKey = stacktop(-1); @@ -674,8 +798,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // Drop the signature, since there's no way for a signature to sign itself scriptCode.FindAndDelete(CScript(vchSig)); - bool fSuccess = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) && - CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, flags); + if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) { + //serror is set + return false; + } + bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode); popstack(stack); popstack(stack); @@ -685,7 +812,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co if (fSuccess) popstack(stack); else - return false; + return set_error(serror, SCRIPT_ERR_CHECKSIGVERIFY); } } break; @@ -697,26 +824,26 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co int i = 1; if ((int)stack.size() < i) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - int nKeysCount = CScriptNum(stacktop(-i)).getint(); + int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); if (nKeysCount < 0 || nKeysCount > 20) - return false; + return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT); nOpCount += nKeysCount; if (nOpCount > 201) - return false; + return set_error(serror, SCRIPT_ERR_OP_COUNT); int ikey = ++i; i += nKeysCount; if ((int)stack.size() < i) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - int nSigsCount = CScriptNum(stacktop(-i)).getint(); + int nSigsCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); if (nSigsCount < 0 || nSigsCount > nKeysCount) - return false; + return set_error(serror, SCRIPT_ERR_SIG_COUNT); int isig = ++i; i += nSigsCount; if ((int)stack.size() < i) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); // Subset of script starting at the most recent codeseparator CScript scriptCode(pbegincodehash, pend); @@ -734,9 +861,16 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co 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) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) { + // serror is set + return false; + } + // Check signature - bool fOk = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) && - CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, flags); + bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode); if (fOk) { isig++; @@ -746,7 +880,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co nKeysCount--; // If there are more signatures left than keys left, - // then too many signatures have failed + // then too many signatures have failed. Exit early, + // without checking any further signatures. if (nSigsCount > nKeysCount) fSuccess = false; } @@ -762,9 +897,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // so optionally verify it is exactly equal to zero prior // to removing it from the stack. if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size()) - return error("CHECKMULTISIG dummy argument not null"); + return set_error(serror, SCRIPT_ERR_SIG_NULLDUMMY); popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); @@ -774,44 +909,45 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co if (fSuccess) popstack(stack); else - return false; + return set_error(serror, SCRIPT_ERR_CHECKMULTISIGVERIFY); } } break; default: - return false; + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } // Size limits if (stack.size() + altstack.size() > 1000) - return false; + return set_error(serror, SCRIPT_ERR_STACK_SIZE); } } catch (...) { - return false; + return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); } if (!vfExec.empty()) - return false; + return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); - return true; + return set_success(serror); } namespace { -/** Wrapper that serializes like CTransaction, but with the modifications +/** + * Wrapper that serializes like CTransaction, but with the modifications * required for the signature hash done in-place */ class CTransactionSignatureSerializer { private: - const CTransaction &txTo; // reference to the spending transaction (the one being serialized) - const CScript &scriptCode; // output script being consumed - const unsigned int nIn; // input index of txTo being signed - const bool fAnyoneCanPay; // whether the hashtype has the SIGHASH_ANYONECANPAY flag set - const bool fHashSingle; // whether the hashtype is SIGHASH_SINGLE - const bool fHashNone; // whether the hashtype is SIGHASH_NONE + const CTransaction &txTo; //! reference to the spending transaction (the one being serialized) + const CScript &scriptCode; //! output script being consumed + const unsigned int nIn; //! input index of txTo being signed + const bool fAnyoneCanPay; //! whether the hashtype has the SIGHASH_ANYONECANPAY flag set + const bool fHashSingle; //! whether the hashtype is SIGHASH_SINGLE + const bool fHashNone; //! whether the hashtype is SIGHASH_NONE public: CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) : @@ -890,25 +1026,26 @@ public: ::WriteCompactSize(s, nOutputs); for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++) SerializeOutput(s, nOutput, nType, nVersion); - // Serialie nLockTime + // Serialize nLockTime ::Serialize(s, txTo.nLockTime, nType, nVersion); } }; } // anon namespace -uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) +uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) { + static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); if (nIn >= txTo.vin.size()) { - LogPrintf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); - return 1; + // nIn out of range + return one; } // Check for invalid use of SIGHASH_SINGLE if ((nHashType & 0x1f) == SIGHASH_SINGLE) { if (nIn >= txTo.vout.size()) { - LogPrintf("ERROR: SignatureHash() : nOut=%d out of range\n", nIn); - return 1; + // nOut out of range + return one; } } @@ -921,70 +1058,19 @@ uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsig return ss.GetHash(); } -// Valid signature cache, to avoid doing expensive ECDSA signature checking -// twice for every transaction (once when accepted into memory pool, and -// again when accepted into the block chain) -class CSignatureCache +bool SignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const { -private: - // sigdata_type is (signature hash, signature, public key): - typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type; - std::set< sigdata_type> setValid; - boost::shared_mutex cs_sigcache; - -public: - bool - Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) - { - boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); - - sigdata_type k(hash, vchSig, pubKey); - std::set<sigdata_type>::iterator mi = setValid.find(k); - if (mi != setValid.end()) - return true; - return false; - } - - void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) - { - // DoS prevention: limit cache size to less than 10MB - // (~200 bytes per cache entry times 50,000 entries) - // Since there are a maximum of 20,000 signature operations per block - // 50,000 is a reasonable default. - int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000); - if (nMaxCacheSize <= 0) return; - - boost::unique_lock<boost::shared_mutex> lock(cs_sigcache); - - while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize) - { - // Evict a random entry. Random because that helps - // foil would-be DoS attackers who might try to pre-generate - // and re-use a set of valid signatures just-slightly-greater - // than our cache size. - uint256 randomHash = GetRandHash(); - std::vector<unsigned char> unused; - std::set<sigdata_type>::iterator it = - setValid.lower_bound(sigdata_type(randomHash, unused, unused)); - if (it == setValid.end()) - it = setValid.begin(); - setValid.erase(*it); - } - - sigdata_type k(hash, vchSig, pubKey); - setValid.insert(k); - } -}; + return pubkey.Verify(sighash, vchSig); +} -bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char>& vchPubKey, const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int flags) +bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const { - static CSignatureCache signatureCache; - CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) return false; // Hash type is one byte tacked on to the end of the signature + vector<unsigned char> vchSig(vchSigIn); if (vchSig.empty()) return false; int nHashType = vchSig.back(); @@ -992,54 +1078,73 @@ bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char>& vchPubK uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); - if (signatureCache.Get(sighash, vchSig, pubkey)) - return true; - - if (!pubkey.Verify(sighash, vchSig)) + if (!VerifySignature(vchSig, pubkey, sighash)) return false; - if (!(flags & SCRIPT_VERIFY_NOCACHE)) - signatureCache.Set(sighash, vchSig, pubkey); - return true; } -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags) +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { + set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); + + if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) { + return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); + } + vector<vector<unsigned char> > stack, stackCopy; - if (!EvalScript(stack, scriptSig, txTo, nIn, flags)) + if (!EvalScript(stack, scriptSig, flags, checker, serror)) + // serror is set return false; if (flags & SCRIPT_VERIFY_P2SH) stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, txTo, nIn, flags)) + if (!EvalScript(stack, scriptPubKey, flags, checker, serror)) + // serror is set return false; if (stack.empty()) - return false; - + return set_error(serror, SCRIPT_ERR_EVAL_FALSE); if (CastToBool(stack.back()) == false) - return false; + return set_error(serror, SCRIPT_ERR_EVAL_FALSE); // Additional validation for spend-to-script-hash transactions: if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) { - if (!scriptSig.IsPushOnly()) // scriptSig must be literals-only - return false; // or validation fails + // scriptSig must be literals-only or validation fails + if (!scriptSig.IsPushOnly()) + return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); + + // Restore stack. + swap(stack, stackCopy); - // stackCopy cannot be empty here, because if it was the + // 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(!stackCopy.empty()); + assert(!stack.empty()); - const valtype& pubKeySerialized = stackCopy.back(); + const valtype& pubKeySerialized = stack.back(); CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); - popstack(stackCopy); + popstack(stack); - if (!EvalScript(stackCopy, pubKey2, txTo, nIn, flags)) + if (!EvalScript(stack, pubKey2, flags, checker, serror)) + // serror is set return false; - if (stackCopy.empty()) - return false; - return CastToBool(stackCopy.back()); + if (stack.empty()) + return set_error(serror, SCRIPT_ERR_EVAL_FALSE); + if (!CastToBool(stack.back())) + return set_error(serror, SCRIPT_ERR_EVAL_FALSE); } - return true; + // 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). + 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/interpreter.h b/src/script/interpreter.h index adca2142a..8bf379ed8 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -1,15 +1,18 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef H_BITCOIN_SCRIPT_INTERPRETER -#define H_BITCOIN_SCRIPT_INTERPRETER +#ifndef BITCOIN_SCRIPT_INTERPRETER_H +#define BITCOIN_SCRIPT_INTERPRETER_H + +#include "script_error.h" #include <vector> #include <stdint.h> #include <string> +class CPubKey; class CScript; class CTransaction; class uint256; @@ -27,19 +30,81 @@ enum enum { SCRIPT_VERIFY_NONE = 0, - SCRIPT_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts - SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys - SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) in signatures (depends on STRICTENC) - SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it) - SCRIPT_VERIFY_NULLDUMMY = (1U << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length -}; -bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags); -bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int flags); + // Evaluate P2SH subscripts (softfork safe, BIP16). + SCRIPT_VERIFY_P2SH = (1U << 0), + + // Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure. + // Evaluating a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script failure. + // (softfork safe, but not used or intended as a consensus rule). + SCRIPT_VERIFY_STRICTENC = (1U << 1), + + // Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1) + SCRIPT_VERIFY_DERSIG = (1U << 2), + + // Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure + // (softfork safe, BIP62 rule 5). + SCRIPT_VERIFY_LOW_S = (1U << 3), + + // verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7). + SCRIPT_VERIFY_NULLDUMMY = (1U << 4), + + // Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2). + SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5), + + // Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct + // pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating + // any other push causes the script to fail (BIP62 rule 3). + // In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4). + // (softfork safe) + SCRIPT_VERIFY_MINIMALDATA = (1U << 6), + + // Discourage use of NOPs reserved for upgrades (NOP1-10) + // + // Provided so that nodes can avoid accepting or mining transactions + // containing executed NOP's whose meaning may change after a soft-fork, + // thus rendering the script invalid; with this flag set executing + // discouraged NOPs fails the script. This verification flag will never be + // a mandatory flag applied to scripts in a block. NOPs that are not + // executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected. + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7), + + // Require that only a single stack element remains after evaluation. This changes the success criterion from + // "At least one stack element must remain, and when interpreted as a boolean, it must be true" to + // "Exactly one stack element must remain, and when interpreted as a boolean, it must be true". + // (softfork safe, BIP62 rule 6) + // Note: CLEANSTACK should never be used without P2SH. + SCRIPT_VERIFY_CLEANSTACK = (1U << 8), +}; uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); -bool CheckSig(std::vector<unsigned char> vchSig, const std::vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int flags); -bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags); -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags); -#endif // H_BITCOIN_SCRIPT_INTERPRETER +class BaseSignatureChecker +{ +public: + virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const + { + return false; + } + + virtual ~BaseSignatureChecker() {} +}; + +class SignatureChecker : public BaseSignatureChecker +{ +private: + const CTransaction& txTo; + unsigned int nIn; + +protected: + virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; + +public: + SignatureChecker(const CTransaction& txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {} + bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const; +}; + +bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); + +#endif // BITCOIN_SCRIPT_INTERPRETER_H diff --git a/src/script/script.cpp b/src/script/script.cpp index a5126e7cc..fd3392473 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -1,11 +1,22 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2014 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 "script.h" -#include <boost/foreach.hpp> +#include "tinyformat.h" +#include "utilstrencodings.h" + +namespace { +inline std::string ValueString(const std::vector<unsigned char>& vch) +{ + if (vch.size() <= 4) + return strprintf("%d", CScriptNum(vch, false).getint()); + else + return HexStr(vch); +} +} // anon namespace using namespace std; @@ -219,7 +230,7 @@ bool CScript::IsPushOnly() const return false; // Note that IsPushOnly() *does* consider OP_RESERVED to be a // push-type opcode, however execution of OP_RESERVED fails, so - // it's not relevant to P2SH as the scriptSig would fail prior to + // it's not relevant to P2SH/BIP62 as the scriptSig would fail prior to // the P2SH special validation code being executed. if (opcode > OP_16) return false; @@ -227,29 +238,25 @@ bool CScript::IsPushOnly() const return true; } -bool CScript::HasCanonicalPushes() const +std::string CScript::ToString() const { + std::string str; + opcodetype opcode; + std::vector<unsigned char> vch; const_iterator pc = begin(); while (pc < end()) { - opcodetype opcode; - std::vector<unsigned char> data; - if (!GetOp(pc, opcode, data)) - return false; - if (opcode > OP_16) - continue; - if (opcode < OP_PUSHDATA1 && opcode > OP_0 && (data.size() == 1 && data[0] <= 16)) - // Could have used an OP_n code, rather than a 1-byte push. - return false; - if (opcode == OP_PUSHDATA1 && data.size() < OP_PUSHDATA1) - // Could have used a normal n-byte push, rather than OP_PUSHDATA1. - return false; - if (opcode == OP_PUSHDATA2 && data.size() <= 0xFF) - // Could have used an OP_PUSHDATA1. - return false; - if (opcode == OP_PUSHDATA4 && data.size() <= 0xFFFF) - // Could have used an OP_PUSHDATA2. - return false; + if (!str.empty()) + str += " "; + if (!GetOp(pc, opcode, vch)) + { + str += "[error]"; + return str; + } + if (0 <= opcode && opcode <= OP_PUSHDATA4) + str += ValueString(vch); + else + str += GetOpName(opcode); } - return true; + return str; } diff --git a/src/script/script.h b/src/script/script.h index caf176476..78fd12cd2 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -1,21 +1,28 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef H_BITCOIN_SCRIPT -#define H_BITCOIN_SCRIPT - -#include "key.h" -#include "tinyformat.h" -#include "utilstrencodings.h" +#ifndef BITCOIN_SCRIPT_SCRIPT_H +#define BITCOIN_SCRIPT_SCRIPT_H +#include <assert.h> +#include <climits> +#include <limits> #include <stdexcept> - -#include <boost/variant.hpp> +#include <stdint.h> +#include <string.h> +#include <string> +#include <vector> static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes +template <typename T> +std::vector<unsigned char> ToByteVector(const T& in) +{ + return std::vector<unsigned char>(in.begin(), in.end()); +} + /** Script opcodes */ enum opcodetype { @@ -172,12 +179,14 @@ public: class CScriptNum { -// Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers. -// The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1], -// but results may overflow (and are valid as long as they are not used in a subsequent -// numeric operation). CScriptNum enforces those semantics by storing results as -// an int64 and allowing out-of-range values to be returned as a vector of bytes but -// throwing an exception if arithmetic is done or the result is interpreted as an integer. +/** + * Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers. + * The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1], + * but results may overflow (and are valid as long as they are not used in a subsequent + * numeric operation). CScriptNum enforces those semantics by storing results as + * an int64 and allowing out-of-range values to be returned as a vector of bytes but + * throwing an exception if arithmetic is done or the result is interpreted as an integer. + */ public: explicit CScriptNum(const int64_t& n) @@ -185,10 +194,29 @@ public: m_value = n; } - explicit CScriptNum(const std::vector<unsigned char>& vch) + explicit CScriptNum(const std::vector<unsigned char>& vch, bool fRequireMinimal) { - if (vch.size() > nMaxNumSize) - throw scriptnum_error("CScriptNum(const std::vector<unsigned char>&) : overflow"); + if (vch.size() > nMaxNumSize) { + throw scriptnum_error("script number overflow"); + } + if (fRequireMinimal && vch.size() > 0) { + // Check that the number is encoded with the minimum possible + // number of bytes. + // + // If the most-significant-byte - excluding the sign bit - is zero + // then we're not minimal. Note how this test also rejects the + // negative-zero encoding, 0x80. + if ((vch.back() & 0x7f) == 0) { + // One exception: if there's more than one byte and the most + // significant bit of the second-most-significant-byte is set + // it would conflict with the sign bit. An example of this case + // is +-255, which encode to 0xff00 and 0xff80 respectively. + // (big-endian). + if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) { + throw scriptnum_error("non-minimally encoded script number"); + } + } + } m_value = set_vch(vch); } @@ -312,14 +340,6 @@ private: int64_t m_value; }; -inline std::string ValueString(const std::vector<unsigned char>& vch) -{ - if (vch.size() <= 4) - return strprintf("%d", CScriptNum(vch).getint()); - else - return HexStr(vch); -} - /** Serialized script, used inside transaction inputs and outputs */ class CScript : public std::vector<unsigned char> { @@ -330,6 +350,10 @@ protected: { push_back(n + (OP_1 - 1)); } + else if (n == 0) + { + push_back(OP_0); + } else { *this << CScriptNum::serialize(n); @@ -358,7 +382,6 @@ public: CScript(int64_t b) { operator<<(b); } explicit CScript(opcodetype b) { operator<<(b); } - explicit CScript(const uint256& b) { operator<<(b); } explicit CScript(const CScriptNum& b) { operator<<(b); } explicit CScript(const std::vector<unsigned char>& b) { operator<<(b); } @@ -373,28 +396,6 @@ public: return *this; } - CScript& operator<<(const uint160& b) - { - insert(end(), sizeof(b)); - insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b)); - return *this; - } - - CScript& operator<<(const uint256& b) - { - insert(end(), sizeof(b)); - insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b)); - return *this; - } - - CScript& operator<<(const CPubKey& key) - { - assert(key.size() < OP_PUSHDATA1); - insert(end(), (unsigned char)key.size()); - insert(end(), key.begin(), key.end()); - return *this; - } - CScript& operator<<(const CScriptNum& b) { *this << b.getvch(); @@ -517,7 +518,7 @@ public: return true; } - // Encode/decode small integers: + /** Encode/decode small integers: */ static int DecodeOP_N(opcodetype opcode) { if (opcode == OP_0) @@ -561,61 +562,37 @@ public: return nFound; } - // Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs - // as 20 sigops. With pay-to-script-hash, that changed: - // CHECKMULTISIGs serialized in scriptSigs are - // counted more accurately, assuming they are of the form - // ... OP_N CHECKMULTISIG ... + /** + * Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs + * as 20 sigops. With pay-to-script-hash, that changed: + * CHECKMULTISIGs serialized in scriptSigs are + * counted more accurately, assuming they are of the form + * ... OP_N CHECKMULTISIG ... + */ unsigned int GetSigOpCount(bool fAccurate) const; - // Accurately count sigOps, including sigOps in - // pay-to-script-hash transactions: + /** + * Accurately count sigOps, including sigOps in + * pay-to-script-hash transactions: + */ unsigned int GetSigOpCount(const CScript& scriptSig) const; bool IsPayToScriptHash() const; - // Called by IsStandardTx and P2SH VerifyScript (which makes it consensus-critical). + /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */ bool IsPushOnly() const; - // Called by IsStandardTx. - bool HasCanonicalPushes() const; - - // Returns whether the script is guaranteed to fail at execution, - // regardless of the initial stack. This allows outputs to be pruned - // instantly when entering the UTXO set. + /** + * Returns whether the script is guaranteed to fail at execution, + * regardless of the initial stack. This allows outputs to be pruned + * instantly when entering the UTXO set. + */ bool IsUnspendable() const { return (size() > 0 && *begin() == OP_RETURN); } - std::string ToString() const - { - std::string str; - opcodetype opcode; - std::vector<unsigned char> vch; - const_iterator pc = begin(); - while (pc < end()) - { - if (!str.empty()) - str += " "; - if (!GetOp(pc, opcode, vch)) - { - str += "[error]"; - return str; - } - if (0 <= opcode && opcode <= OP_PUSHDATA4) - str += ValueString(vch); - else - str += GetOpName(opcode); - } - return str; - } - - CScriptID GetID() const - { - return CScriptID(Hash160(*this)); - } - + std::string ToString() const; void clear() { // The default std::vector::clear() does not release memory. @@ -623,4 +600,4 @@ public: } }; -#endif // H_BITCOIN_SCRIPT +#endif // BITCOIN_SCRIPT_SCRIPT_H diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp new file mode 100644 index 000000000..d8ecfde1d --- /dev/null +++ b/src/script/script_error.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 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 "script_error.h" + +const char* ScriptErrorString(const ScriptError serror) +{ + switch (serror) + { + case SCRIPT_ERR_OK: + return "No error"; + case SCRIPT_ERR_EVAL_FALSE: + return "Script evaluated without error but finished with a false/empty top stack element"; + case SCRIPT_ERR_VERIFY: + return "Script failed an OP_VERIFY operation"; + case SCRIPT_ERR_EQUALVERIFY: + return "Script failed an OP_EQUALVERIFY operation"; + case SCRIPT_ERR_CHECKMULTISIGVERIFY: + return "Script failed an OP_CHECKMULTISIGVERIFY operation"; + case SCRIPT_ERR_CHECKSIGVERIFY: + return "Script failed an OP_CHECKSIGVERIFY operation"; + case SCRIPT_ERR_NUMEQUALVERIFY: + return "Script failed an OP_NUMEQUALVERIFY operation"; + case SCRIPT_ERR_SCRIPT_SIZE: + return "Script is too big"; + case SCRIPT_ERR_PUSH_SIZE: + return "Push value size limit exceeded"; + case SCRIPT_ERR_OP_COUNT: + return "Operation limit exceeded"; + case SCRIPT_ERR_STACK_SIZE: + return "Stack size limit exceeded"; + case SCRIPT_ERR_SIG_COUNT: + return "Signature count negative or greater than pubkey count"; + case SCRIPT_ERR_PUBKEY_COUNT: + return "Pubkey count negative or limit exceeded"; + case SCRIPT_ERR_BAD_OPCODE: + return "Opcode missing or not understood"; + case SCRIPT_ERR_DISABLED_OPCODE: + return "Attempted to use a disabled opcode"; + case SCRIPT_ERR_INVALID_STACK_OPERATION: + return "Operation not valid with the current stack size"; + case SCRIPT_ERR_INVALID_ALTSTACK_OPERATION: + return "Operation not valid with the current altstack size"; + case SCRIPT_ERR_OP_RETURN: + return "OP_RETURN was encountered"; + case SCRIPT_ERR_UNBALANCED_CONDITIONAL: + return "Invalid OP_IF construction"; + case SCRIPT_ERR_SIG_HASHTYPE: + return "Signature hash type missing or not understood"; + case SCRIPT_ERR_SIG_DER: + return "Non-canonical DER signature"; + case SCRIPT_ERR_MINIMALDATA: + return "Data push larger than necessary"; + case SCRIPT_ERR_SIG_PUSHONLY: + return "Only non-push operators allowed in signatures"; + case SCRIPT_ERR_SIG_HIGH_S: + return "Non-canonical signature: S value is unnecessarily high"; + case SCRIPT_ERR_SIG_NULLDUMMY: + return "Dummy CHECKMULTISIG argument must be zero"; + case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS: + return "NOPx reserved for soft-fork upgrades"; + case SCRIPT_ERR_PUBKEYTYPE: + return "Public key is neither compressed or uncompressed"; + case SCRIPT_ERR_UNKNOWN_ERROR: + case SCRIPT_ERR_ERROR_COUNT: + default: break; + } + return "unknown error"; +} diff --git a/src/script/script_error.h b/src/script/script_error.h new file mode 100644 index 000000000..6365680b2 --- /dev/null +++ b/src/script/script_error.h @@ -0,0 +1,58 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_SCRIPT_SCRIPT_ERROR_H +#define BITCOIN_SCRIPT_SCRIPT_ERROR_H + +typedef enum ScriptError_t +{ + SCRIPT_ERR_OK = 0, + SCRIPT_ERR_UNKNOWN_ERROR, + SCRIPT_ERR_EVAL_FALSE, + SCRIPT_ERR_OP_RETURN, + + /* Max sizes */ + SCRIPT_ERR_SCRIPT_SIZE, + SCRIPT_ERR_PUSH_SIZE, + SCRIPT_ERR_OP_COUNT, + SCRIPT_ERR_STACK_SIZE, + SCRIPT_ERR_SIG_COUNT, + SCRIPT_ERR_PUBKEY_COUNT, + + /* Failed verify operations */ + SCRIPT_ERR_VERIFY, + SCRIPT_ERR_EQUALVERIFY, + SCRIPT_ERR_CHECKMULTISIGVERIFY, + SCRIPT_ERR_CHECKSIGVERIFY, + SCRIPT_ERR_NUMEQUALVERIFY, + + /* Logical/Format/Canonical errors */ + SCRIPT_ERR_BAD_OPCODE, + SCRIPT_ERR_DISABLED_OPCODE, + SCRIPT_ERR_INVALID_STACK_OPERATION, + SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, + SCRIPT_ERR_UNBALANCED_CONDITIONAL, + + /* BIP62 */ + SCRIPT_ERR_SIG_HASHTYPE, + SCRIPT_ERR_SIG_DER, + SCRIPT_ERR_MINIMALDATA, + SCRIPT_ERR_SIG_PUSHONLY, + SCRIPT_ERR_SIG_HIGH_S, + SCRIPT_ERR_SIG_NULLDUMMY, + SCRIPT_ERR_PUBKEYTYPE, + SCRIPT_ERR_CLEANSTACK, + + /* softfork safeness */ + SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, + + SCRIPT_ERR_ERROR_COUNT +} ScriptError; + +#define SCRIPT_ERR_LAST SCRIPT_ERR_ERROR_COUNT + +const char* ScriptErrorString(const ScriptError error); + +#endif // BITCOIN_SCRIPT_SCRIPT_ERROR_H diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp new file mode 100644 index 000000000..75ecdb563 --- /dev/null +++ b/src/script/sigcache.cpp @@ -0,0 +1,90 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 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 "sigcache.h" + +#include "pubkey.h" +#include "random.h" +#include "uint256.h" +#include "util.h" + +#include <boost/thread.hpp> +#include <boost/tuple/tuple_comparison.hpp> + +namespace { + +/** + * Valid signature cache, to avoid doing expensive ECDSA signature checking + * twice for every transaction (once when accepted into memory pool, and + * again when accepted into the block chain) + */ +class CSignatureCache +{ +private: + //! sigdata_type is (signature hash, signature, public key): + typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type; + std::set< sigdata_type> setValid; + boost::shared_mutex cs_sigcache; + +public: + bool + Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) + { + boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); + + sigdata_type k(hash, vchSig, pubKey); + std::set<sigdata_type>::iterator mi = setValid.find(k); + if (mi != setValid.end()) + return true; + return false; + } + + void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) + { + // DoS prevention: limit cache size to less than 10MB + // (~200 bytes per cache entry times 50,000 entries) + // Since there are a maximum of 20,000 signature operations per block + // 50,000 is a reasonable default. + int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000); + if (nMaxCacheSize <= 0) return; + + boost::unique_lock<boost::shared_mutex> lock(cs_sigcache); + + while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize) + { + // Evict a random entry. Random because that helps + // foil would-be DoS attackers who might try to pre-generate + // and re-use a set of valid signatures just-slightly-greater + // than our cache size. + uint256 randomHash = GetRandHash(); + std::vector<unsigned char> unused; + std::set<sigdata_type>::iterator it = + setValid.lower_bound(sigdata_type(randomHash, unused, unused)); + if (it == setValid.end()) + it = setValid.begin(); + setValid.erase(*it); + } + + sigdata_type k(hash, vchSig, pubKey); + setValid.insert(k); + } +}; + +} + +bool CachingSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const +{ + static CSignatureCache signatureCache; + + if (signatureCache.Get(sighash, vchSig, pubkey)) + return true; + + if (!SignatureChecker::VerifySignature(vchSig, pubkey, sighash)) + return false; + + if (store) + signatureCache.Set(sighash, vchSig, pubkey); + return true; +} diff --git a/src/script/sigcache.h b/src/script/sigcache.h new file mode 100644 index 000000000..3bd11caff --- /dev/null +++ b/src/script/sigcache.h @@ -0,0 +1,26 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_SCRIPT_SIGCACHE_H +#define BITCOIN_SCRIPT_SIGCACHE_H + +#include "script/interpreter.h" + +#include <vector> + +class CPubKey; + +class CachingSignatureChecker : public SignatureChecker +{ +private: + bool store; + +public: + CachingSignatureChecker(const CTransaction& txToIn, unsigned int nInIn, bool storeIn=true) : SignatureChecker(txToIn, nInIn), store(storeIn) {} + + bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; +}; + +#endif // BITCOIN_SCRIPT_SIGCACHE_H diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 8abd8d221..adddd4ec7 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -1,11 +1,11 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2014 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 "script/sign.h" -#include "core.h" +#include "primitives/transaction.h" #include "key.h" #include "keystore.h" #include "script/standard.h" @@ -46,12 +46,12 @@ bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint2 return nSigned==nRequired; } -// -// Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type. -// Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed), -// unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script. -// Returns false if scriptPubKey could not be completely satisfied. -// +/** + * Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type. + * Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed), + * unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script. + * Returns false if scriptPubKey could not be completely satisfied. + */ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet, txnouttype& whichTypeRet) { @@ -78,7 +78,7 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash { CPubKey vch; keystore.GetPubKey(keyID, vch); - scriptSigRet << vch; + scriptSigRet << ToByteVector(vch); } return true; case TX_SCRIPTHASH: @@ -123,7 +123,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutabl } // Test solution - return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS); + return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(txTo, nIn)); } bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) @@ -144,9 +144,9 @@ static CScript PushAll(const vector<valtype>& values) return result; } -static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn, +static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const vector<valtype>& vSolutions, - vector<valtype>& sigs1, vector<valtype>& sigs2) + const vector<valtype>& sigs1, const vector<valtype>& sigs2) { // Combine all the signatures we've got: set<valtype> allsigs; @@ -174,7 +174,7 @@ static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& if (sigs.count(pubkey)) continue; // Already got a sig for this pubkey - if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0)) + if (SignatureChecker(txTo, nIn).CheckSig(sig, pubkey, scriptPubKey)) { sigs[pubkey] = sig; break; @@ -199,7 +199,7 @@ static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& return result; } -static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, +static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const txnouttype txType, const vector<valtype>& vSolutions, vector<valtype>& sigs1, vector<valtype>& sigs2) { @@ -244,7 +244,7 @@ static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, return CScript(); } -CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, +CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2) { txnouttype txType; @@ -252,9 +252,9 @@ CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsign Solver(scriptPubKey, txType, vSolutions); vector<valtype> stack1; - EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC); + EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker()); vector<valtype> stack2; - EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC); + EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker()); return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2); } diff --git a/src/script/sign.h b/src/script/sign.h index f218a6456..e197d5fab 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -1,10 +1,10 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef H_BITCOIN_SCRIPT_SIGN -#define H_BITCOIN_SCRIPT_SIGN +#ifndef BITCOIN_SCRIPT_SIGN_H +#define BITCOIN_SCRIPT_SIGN_H #include "script/interpreter.h" @@ -17,8 +17,10 @@ struct CMutableTransaction; bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); -// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders, -// combine them intelligently and return the result. -CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2); +/** + * Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders, + * combine them intelligently and return the result. + */ +CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2); -#endif // H_BITCOIN_SCRIPT_SIGN +#endif // BITCOIN_SCRIPT_SIGN_H diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 407baf621..ce50e3aad 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -1,12 +1,14 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2014 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 "script/standard.h" +#include "pubkey.h" #include "script/script.h" #include "util.h" +#include "utilstrencodings.h" #include <boost/foreach.hpp> @@ -14,6 +16,10 @@ using namespace std; typedef vector<unsigned char> valtype; +unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY; + +CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} + const char* GetTxnOutputType(txnouttype t) { switch (t) @@ -28,9 +34,9 @@ const char* GetTxnOutputType(txnouttype t) return NULL; } -// -// Return public keys or hashes from scriptPubKey, for 'standard' transaction types. -// +/** + * Return public keys or hashes from scriptPubKey, for 'standard' transaction types. + */ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet) { // Templates @@ -136,8 +142,8 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi } else if (opcode2 == OP_SMALLDATA) { - // small pushdata, <= MAX_OP_RETURN_RELAY bytes - if (vch1.size() > MAX_OP_RETURN_RELAY) + // small pushdata, <= nMaxDatacarrierBytes + if (vch1.size() > nMaxDatacarrierBytes) break; } else if (opcode1 != opcode2 || vch1 != vch2) @@ -203,7 +209,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) if (whichType == TX_PUBKEY) { - addressRet = CPubKey(vSolutions[0]).GetID(); + CPubKey pubKey(vSolutions[0]); + if (!pubKey.IsValid()) + return false; + + addressRet = pubKey.GetID(); return true; } else if (whichType == TX_PUBKEYHASH) @@ -237,9 +247,16 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto nRequiredRet = vSolutions.front()[0]; for (unsigned int i = 1; i < vSolutions.size()-1; i++) { - CTxDestination address = CPubKey(vSolutions[i]).GetID(); + CPubKey pubKey(vSolutions[i]); + if (!pubKey.IsValid()) + continue; + + CTxDestination address = pubKey.GetID(); addressRet.push_back(address); } + + if (addressRet.empty()) + return false; } else { @@ -269,13 +286,13 @@ public: bool operator()(const CKeyID &keyID) const { script->clear(); - *script << OP_DUP << OP_HASH160 << keyID << OP_EQUALVERIFY << OP_CHECKSIG; + *script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; return true; } bool operator()(const CScriptID &scriptID) const { script->clear(); - *script << OP_HASH160 << scriptID << OP_EQUAL; + *script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL; return true; } }; @@ -295,7 +312,7 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys) script << CScript::EncodeOP_N(nRequired); BOOST_FOREACH(const CPubKey& key, keys) - script << key; + script << ToByteVector(key); script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; return script; } diff --git a/src/script/standard.h b/src/script/standard.h index ead79b82a..ac8019377 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -1,37 +1,57 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef H_BITCOIN_SCRIPT_STANDARD -#define H_BITCOIN_SCRIPT_STANDARD +#ifndef BITCOIN_SCRIPT_STANDARD_H +#define BITCOIN_SCRIPT_STANDARD_H -#include "script/script.h" #include "script/interpreter.h" +#include "uint256.h" + +#include <boost/variant.hpp> #include <stdint.h> +class CKeyID; class CScript; -static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes +/** A reference to a CScript: the Hash160 of its serialization (see script.h) */ +class CScriptID : public uint160 +{ +public: + CScriptID() : uint160() {} + CScriptID(const CScript& in); + CScriptID(const uint160& in) : uint160(in) {} +}; -// Mandatory script verification flags that all new blocks must comply with for -// them to be valid. (but old blocks may not comply with) Currently just P2SH, -// but in the future other flags may be added, such as a soft-fork to enforce -// strict DER encoding. -// -// Failing one of these tests may trigger a DoS ban - see CheckInputs() for -// details. +static const unsigned int MAX_OP_RETURN_RELAY = 40; //! bytes +extern unsigned nMaxDatacarrierBytes; + +/** + * Mandatory script verification flags that all new blocks must comply with for + * them to be valid. (but old blocks may not comply with) Currently just P2SH, + * but in the future other flags may be added, such as a soft-fork to enforce + * strict DER encoding. + * + * Failing one of these tests may trigger a DoS ban - see CheckInputs() for + * details. + */ static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH; -// Standard script verification flags that standard transactions will comply -// with. However scripts violating these flags may still be present in valid -// blocks and we must accept those blocks. +/** + * Standard script verification flags that standard transactions will comply + * with. However scripts violating these flags may still be present in valid + * blocks and we must accept those blocks. + */ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_STRICTENC | - SCRIPT_VERIFY_NULLDUMMY; + SCRIPT_VERIFY_MINIMALDATA | + SCRIPT_VERIFY_NULLDUMMY | + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS | + SCRIPT_VERIFY_CLEANSTACK; -// For convenience, standard but not mandatory verify flags. +/** For convenience, standard but not mandatory verify flags. */ static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; enum txnouttype @@ -51,7 +71,8 @@ public: friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; } }; -/** A txout script template with a specific destination. It is either: +/** + * A txout script template with a specific destination. It is either: * * CNoDestination: no destination set * * CKeyID: TX_PUBKEYHASH destination * * CScriptID: TX_SCRIPTHASH destination @@ -70,4 +91,4 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std:: CScript GetScriptForDestination(const CTxDestination& dest); CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys); -#endif // H_BITCOIN_SCRIPT_STANDARD +#endif // BITCOIN_SCRIPT_STANDARD_H |