diff options
Diffstat (limited to 'src/script.cpp')
-rw-r--r-- | src/script.cpp | 221 |
1 files changed, 26 insertions, 195 deletions
diff --git a/src/script.cpp b/src/script.cpp index 5e5cd096cd..b411666353 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -16,7 +16,7 @@ using namespace boost; #include "sync.h" #include "util.h" -bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); +bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); @@ -54,32 +54,6 @@ bool CastToBool(const valtype& vch) return false; } -// -// WARNING: This does not work as expected for signed integers; the sign-bit -// is left in place as the integer is zero-extended. The correct behavior -// would be to move the most significant bit of the last byte during the -// resize process. MakeSameSize() is currently only used by the disabled -// opcodes OP_AND, OP_OR, and OP_XOR. -// -void MakeSameSize(valtype& vch1, valtype& vch2) -{ - // Lengthen the shorter one - if (vch1.size() < vch2.size()) - // PATCH: - // +unsigned char msb = vch1[vch1.size()-1]; - // +vch1[vch1.size()-1] &= 0x7f; - // vch1.resize(vch2.size(), 0); - // +vch1[vch1.size()-1] = msb; - vch1.resize(vch2.size(), 0); - if (vch2.size() < vch1.size()) - // PATCH: - // +unsigned char msb = vch2[vch2.size()-1]; - // +vch2[vch2.size()-1] &= 0x7f; - // vch2.resize(vch1.size(), 0); - // +vch2[vch2.size()-1] = msb; - vch2.resize(vch1.size(), 0); -} - // @@ -361,7 +335,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT) - return false; + return false; // Disabled opcodes. if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) stack.push_back(vchPushValue); @@ -659,64 +633,6 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co break; - // - // Splice ops - // - case OP_CAT: - { - // (x1 x2 -- out) - if (stack.size() < 2) - return false; - valtype& vch1 = stacktop(-2); - valtype& vch2 = stacktop(-1); - vch1.insert(vch1.end(), vch2.begin(), vch2.end()); - popstack(stack); - if (stacktop(-1).size() > MAX_SCRIPT_ELEMENT_SIZE) - return false; - } - break; - - case OP_SUBSTR: - { - // (in begin size -- out) - if (stack.size() < 3) - return false; - valtype& vch = stacktop(-3); - int nBegin = CastToBigNum(stacktop(-2)).getint(); - int nEnd = nBegin + CastToBigNum(stacktop(-1)).getint(); - if (nBegin < 0 || nEnd < nBegin) - return false; - if (nBegin > (int)vch.size()) - nBegin = vch.size(); - if (nEnd > (int)vch.size()) - nEnd = vch.size(); - vch.erase(vch.begin() + nEnd, vch.end()); - vch.erase(vch.begin(), vch.begin() + nBegin); - popstack(stack); - popstack(stack); - } - break; - - case OP_LEFT: - case OP_RIGHT: - { - // (in size -- out) - if (stack.size() < 2) - return false; - valtype& vch = stacktop(-2); - int nSize = CastToBigNum(stacktop(-1)).getint(); - if (nSize < 0) - return false; - if (nSize > (int)vch.size()) - nSize = vch.size(); - if (opcode == OP_LEFT) - vch.erase(vch.begin() + nSize, vch.end()); - else - vch.erase(vch.begin(), vch.end() - nSize); - popstack(stack); - } - break; - case OP_SIZE: { // (in -- in size) @@ -731,51 +647,6 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // // Bitwise logic // - case OP_INVERT: - { - // (in - out) - if (stack.size() < 1) - return false; - valtype& vch = stacktop(-1); - for (unsigned int i = 0; i < vch.size(); i++) - vch[i] = ~vch[i]; - } - break; - - // - // WARNING: These disabled opcodes exhibit unexpected behavior - // when used on signed integers due to a bug in MakeSameSize() - // [see definition of MakeSameSize() above]. - // - case OP_AND: - case OP_OR: - case OP_XOR: - { - // (x1 x2 - out) - if (stack.size() < 2) - return false; - valtype& vch1 = stacktop(-2); - valtype& vch2 = stacktop(-1); - MakeSameSize(vch1, vch2); // <-- NOT SAFE FOR SIGNED VALUES - if (opcode == OP_AND) - { - for (unsigned int i = 0; i < vch1.size(); i++) - vch1[i] &= vch2[i]; - } - else if (opcode == OP_OR) - { - for (unsigned int i = 0; i < vch1.size(); i++) - vch1[i] |= vch2[i]; - } - else if (opcode == OP_XOR) - { - for (unsigned int i = 0; i < vch1.size(); i++) - vch1[i] ^= vch2[i]; - } - popstack(stack); - } - break; - case OP_EQUAL: case OP_EQUALVERIFY: //case OP_NOTEQUAL: // use OP_NUMNOTEQUAL @@ -810,8 +681,6 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // case OP_1ADD: case OP_1SUB: - case OP_2MUL: - case OP_2DIV: case OP_NEGATE: case OP_ABS: case OP_NOT: @@ -825,8 +694,6 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co { case OP_1ADD: bn += bnOne; break; case OP_1SUB: bn -= bnOne; break; - case OP_2MUL: bn <<= 1; break; - case OP_2DIV: bn >>= 1; break; case OP_NEGATE: bn = -bn; break; case OP_ABS: if (bn < bnZero) bn = -bn; break; case OP_NOT: bn = (bn == bnZero); break; @@ -840,11 +707,6 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co case OP_ADD: case OP_SUB: - case OP_MUL: - case OP_DIV: - case OP_MOD: - case OP_LSHIFT: - case OP_RSHIFT: case OP_BOOLAND: case OP_BOOLOR: case OP_NUMEQUAL: @@ -873,33 +735,6 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co bn = bn1 - bn2; break; - case OP_MUL: - if (!BN_mul(&bn, &bn1, &bn2, pctx)) - return false; - break; - - case OP_DIV: - if (!BN_div(&bn, NULL, &bn1, &bn2, pctx)) - return false; - break; - - case OP_MOD: - if (!BN_mod(&bn, &bn1, &bn2, pctx)) - return false; - break; - - case OP_LSHIFT: - if (bn2 < bnZero || bn2 > CBigNum(2048)) - return false; - bn = bn1 << bn2.getulong(); - break; - - case OP_RSHIFT: - if (bn2 < bnZero || bn2 > CBigNum(2048)) - return false; - bn = bn1 >> bn2.getulong(); - 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; @@ -1198,13 +1033,13 @@ class CSignatureCache { private: // sigdata_type is (signature hash, signature, public key): - typedef boost::tuple<uint256, std::vector<unsigned char>, std::vector<unsigned char> > sigdata_type; + typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type; std::set< sigdata_type> setValid; boost::shared_mutex cs_sigcache; public: bool - Get(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey) + Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) { boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); @@ -1215,7 +1050,7 @@ public: return false; } - void Set(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey) + 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) @@ -1246,11 +1081,15 @@ public: } }; -bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, +bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags) { static CSignatureCache signatureCache; + CPubKey pubkey(vchPubKey); + if (!pubkey.IsValid()) + return false; + // Hash type is one byte tacked on to the end of the signature if (vchSig.empty()) return false; @@ -1262,18 +1101,14 @@ bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CSc uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); - if (signatureCache.Get(sighash, vchSig, vchPubKey)) + if (signatureCache.Get(sighash, vchSig, pubkey)) return true; - CKey key; - if (!key.SetPubKey(vchPubKey)) - return false; - - if (!key.Verify(sighash, vchSig)) + if (!pubkey.Verify(sighash, vchSig)) return false; if (!(flags & SCRIPT_VERIFY_NOCACHE)) - signatureCache.Set(sighash, vchSig, vchPubKey); + signatureCache.Set(sighash, vchSig, pubkey); return true; } @@ -1935,13 +1770,13 @@ void CScript::SetDestination(const CTxDestination& dest) boost::apply_visitor(CScriptVisitor(this), dest); } -void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys) +void CScript::SetMultisig(int nRequired, const std::vector<CPubKey>& keys) { this->clear(); *this << EncodeOP_N(nRequired); - BOOST_FOREACH(const CKey& key, keys) - *this << key.GetPubKey(); + BOOST_FOREACH(const CPubKey& key, keys) + *this << key; *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; } @@ -1966,20 +1801,17 @@ bool CScriptCompressor::IsToScriptID(CScriptID &hash) const return false; } -bool CScriptCompressor::IsToPubKey(std::vector<unsigned char> &pubkey) const +bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const { if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG && (script[1] == 0x02 || script[1] == 0x03)) { - pubkey.resize(33); - memcpy(&pubkey[0], &script[1], 33); + pubkey.Set(&script[1], &script[34]); return true; } if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG && script[1] == 0x04) { - pubkey.resize(65); - memcpy(&pubkey[0], &script[1], 65); - CKey key; - return (key.SetPubKey(CPubKey(pubkey))); // SetPubKey fails if this is not a valid public key, a case that would not be compressible + pubkey.Set(&script[1], &script[66]); + return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible } return false; } @@ -2000,7 +1832,7 @@ bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const memcpy(&out[1], &scriptID, 20); return true; } - std::vector<unsigned char> pubkey; + CPubKey pubkey; if (IsToPubKey(pubkey)) { out.resize(33); memcpy(&out[1], &pubkey[1], 32); @@ -2053,17 +1885,16 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigne return true; case 0x04: case 0x05: - std::vector<unsigned char> vch(33, 0x00); + unsigned char vch[33] = {}; vch[0] = nSize - 2; memcpy(&vch[1], &in[0], 32); - CKey key; - if (!key.SetPubKey(CPubKey(vch))) + CPubKey pubkey(&vch[0], &vch[33]); + if (!pubkey.Decompress()) return false; - key.SetCompressedPubKey(false); // Decompress public key - CPubKey pubkey = key.GetPubKey(); + assert(pubkey.size() == 65); script.resize(67); script[0] = 65; - memcpy(&script[1], &pubkey.Raw()[0], 65); + memcpy(&script[1], pubkey.begin(), 65); script[66] = OP_CHECKSIG; return true; } |