// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2013 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "scriptutils.h" #include "core.h" #include "key.h" #include "keystore.h" #include "uint256.h" #include "util.h" #include using namespace std; typedef vector valtype; const char* GetTxnOutputType(txnouttype t) { switch (t) { case TX_NONSTANDARD: return "nonstandard"; case TX_PUBKEY: return "pubkey"; case TX_PUBKEYHASH: return "pubkeyhash"; case TX_SCRIPTHASH: return "scripthash"; case TX_MULTISIG: return "multisig"; case TX_NULL_DATA: return "nulldata"; } return NULL; } // // Return public keys or hashes from scriptPubKey, for 'standard' transaction types. // bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector >& vSolutionsRet) { // Templates static multimap mTemplates; if (mTemplates.empty()) { // Standard tx, sender provides pubkey, receiver adds signature mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); // Sender provides N pubkeys, receivers provides M signatures mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); // Empty, provably prunable, data-carrying output if (GetBoolArg("-datacarrier", true)) mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA)); mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN)); } // Shortcut for pay-to-script-hash, which are more constrained than the other types: // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL if (scriptPubKey.IsPayToScriptHash()) { typeRet = TX_SCRIPTHASH; vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); vSolutionsRet.push_back(hashBytes); return true; } // Scan templates const CScript& script1 = scriptPubKey; BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates) { const CScript& script2 = tplate.second; vSolutionsRet.clear(); opcodetype opcode1, opcode2; vector vch1, vch2; // Compare CScript::const_iterator pc1 = script1.begin(); CScript::const_iterator pc2 = script2.begin(); while (true) { if (pc1 == script1.end() && pc2 == script2.end()) { // Found a match typeRet = tplate.first; if (typeRet == TX_MULTISIG) { // Additional checks for TX_MULTISIG: unsigned char m = vSolutionsRet.front()[0]; unsigned char n = vSolutionsRet.back()[0]; if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n) return false; } return true; } if (!script1.GetOp(pc1, opcode1, vch1)) break; if (!script2.GetOp(pc2, opcode2, vch2)) break; // Template matching opcodes: if (opcode2 == OP_PUBKEYS) { while (vch1.size() >= 33 && vch1.size() <= 65) { vSolutionsRet.push_back(vch1); if (!script1.GetOp(pc1, opcode1, vch1)) break; } if (!script2.GetOp(pc2, opcode2, vch2)) break; // Normal situation is to fall through // to other if/else statements } if (opcode2 == OP_PUBKEY) { if (vch1.size() < 33 || vch1.size() > 65) break; vSolutionsRet.push_back(vch1); } else if (opcode2 == OP_PUBKEYHASH) { if (vch1.size() != sizeof(uint160)) break; vSolutionsRet.push_back(vch1); } else if (opcode2 == OP_SMALLINTEGER) { // Single-byte small integer pushed onto vSolutions if (opcode1 == OP_0 || (opcode1 >= OP_1 && opcode1 <= OP_16)) { char n = (char)CScript::DecodeOP_N(opcode1); vSolutionsRet.push_back(valtype(1, n)); } else break; } else if (opcode2 == OP_SMALLDATA) { // small pushdata, <= MAX_OP_RETURN_RELAY bytes if (vch1.size() > MAX_OP_RETURN_RELAY) break; } else if (opcode1 != opcode2 || vch1 != vch2) { // Others must match exactly break; } } } vSolutionsRet.clear(); typeRet = TX_NONSTANDARD; return false; } bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) { CKey key; if (!keystore.GetKey(address, key)) return false; vector vchSig; if (!key.Sign(hash, vchSig)) return false; vchSig.push_back((unsigned char)nHashType); scriptSigRet << vchSig; return true; } bool SignN(const vector& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) { int nSigned = 0; int nRequired = multisigdata.front()[0]; for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++) { const valtype& pubkey = multisigdata[i]; CKeyID keyID = CPubKey(pubkey).GetID(); if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) ++nSigned; } 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. // bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet, txnouttype& whichTypeRet) { scriptSigRet.clear(); vector vSolutions; if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) return false; CKeyID keyID; switch (whichTypeRet) { case TX_NONSTANDARD: case TX_NULL_DATA: return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); return Sign1(keyID, keystore, hash, nHashType, scriptSigRet); case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) return false; else { CPubKey vch; keystore.GetPubKey(keyID, vch); scriptSigRet << vch; } return true; case TX_SCRIPTHASH: return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet); case TX_MULTISIG: scriptSigRet << OP_0; // workaround CHECKMULTISIG bug return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet)); } return false; } int ScriptSigArgsExpected(txnouttype t, const std::vector >& vSolutions) { switch (t) { case TX_NONSTANDARD: case TX_NULL_DATA: return -1; case TX_PUBKEY: return 1; case TX_PUBKEYHASH: return 2; case TX_MULTISIG: if (vSolutions.size() < 1 || vSolutions[0].size() < 1) return -1; return vSolutions[0][0] + 1; case TX_SCRIPTHASH: return 1; // doesn't include args needed by the script } return -1; } bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) { vector vSolutions; if (!Solver(scriptPubKey, whichType, vSolutions)) return false; if (whichType == TX_MULTISIG) { unsigned char m = vSolutions.front()[0]; unsigned char n = vSolutions.back()[0]; // Support up to x-of-3 multisig txns as standard if (n < 1 || n > 3) return false; if (m < 1 || m > n) return false; } return whichType != TX_NONSTANDARD; } unsigned int HaveKeys(const vector& pubkeys, const CKeyStore& keystore) { unsigned int nResult = 0; BOOST_FOREACH(const valtype& pubkey, pubkeys) { CKeyID keyID = CPubKey(pubkey).GetID(); if (keystore.HaveKey(keyID)) ++nResult; } return nResult; } isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest) { CScript script; script.SetDestination(dest); return IsMine(keystore, script); } isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) { vector vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) { if (keystore.HaveWatchOnly(scriptPubKey)) return ISMINE_WATCH_ONLY; return ISMINE_NO; } CKeyID keyID; switch (whichType) { case TX_NONSTANDARD: case TX_NULL_DATA: break; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); if (keystore.HaveKey(keyID)) return ISMINE_SPENDABLE; break; case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (keystore.HaveKey(keyID)) return ISMINE_SPENDABLE; break; case TX_SCRIPTHASH: { CScriptID scriptID = CScriptID(uint160(vSolutions[0])); CScript subscript; if (keystore.GetCScript(scriptID, subscript)) { isminetype ret = IsMine(keystore, subscript); if (ret == ISMINE_SPENDABLE) return ret; } break; } case TX_MULTISIG: { // Only consider transactions "mine" if we own ALL the // keys involved. multi-signature transactions that are // partially owned (somebody else has a key that can spend // them) enable spend-out-from-under-you attacks, especially // in shared-wallet situations. vector keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); if (HaveKeys(keys, keystore) == keys.size()) return ISMINE_SPENDABLE; break; } } if (keystore.HaveWatchOnly(scriptPubKey)) return ISMINE_WATCH_ONLY; return ISMINE_NO; } bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { vector vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) return false; if (whichType == TX_PUBKEY) { addressRet = CPubKey(vSolutions[0]).GetID(); return true; } else if (whichType == TX_PUBKEYHASH) { addressRet = CKeyID(uint160(vSolutions[0])); return true; } else if (whichType == TX_SCRIPTHASH) { addressRet = CScriptID(uint160(vSolutions[0])); return true; } // Multisig txns have more than one address... return false; } bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector& addressRet, int& nRequiredRet) { addressRet.clear(); typeRet = TX_NONSTANDARD; vector vSolutions; if (!Solver(scriptPubKey, typeRet, vSolutions)) return false; if (typeRet == TX_NULL_DATA){ // This is data, not addresses return false; } if (typeRet == TX_MULTISIG) { nRequiredRet = vSolutions.front()[0]; for (unsigned int i = 1; i < vSolutions.size()-1; i++) { CTxDestination address = CPubKey(vSolutions[i]).GetID(); addressRet.push_back(address); } } else { nRequiredRet = 1; CTxDestination address; if (!ExtractDestination(scriptPubKey, address)) return false; addressRet.push_back(address); } return true; } class CAffectedKeysVisitor : public boost::static_visitor { private: const CKeyStore &keystore; std::vector &vKeys; public: CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {} void Process(const CScript &script) { txnouttype type; std::vector vDest; int nRequired; if (ExtractDestinations(script, type, vDest, nRequired)) { BOOST_FOREACH(const CTxDestination &dest, vDest) boost::apply_visitor(*this, dest); } } void operator()(const CKeyID &keyId) { if (keystore.HaveKey(keyId)) vKeys.push_back(keyId); } void operator()(const CScriptID &scriptId) { CScript script; if (keystore.GetCScript(scriptId, script)) Process(script); } void operator()(const CNoDestination &none) {} }; void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector &vKeys) { CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey); } bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType) { assert(nIn < txTo.vin.size()); CTxIn& txin = txTo.vin[nIn]; // Leave out the signature from the hash, since a signature can't sign itself. // The checksig op will also drop the signatures from its hash. uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType); txnouttype whichType; if (!Solver(keystore, fromPubKey, hash, nHashType, txin.scriptSig, whichType)) return false; if (whichType == TX_SCRIPTHASH) { // Solver returns the subscript that need to be evaluated; // the final scriptSig is the signatures from that // and then the serialized subscript: CScript subscript = txin.scriptSig; // Recompute txn hash using subscript in place of scriptPubKey: uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType); txnouttype subType; bool fSolved = Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH; // Append serialized subscript whether or not it is completely signed: txin.scriptSig << static_cast(subscript); if (!fSolved) return false; } // Test solution return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0); } bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) { assert(nIn < txTo.vin.size()); CTxIn& txin = txTo.vin[nIn]; assert(txin.prevout.n < txFrom.vout.size()); const CTxOut& txout = txFrom.vout[txin.prevout.n]; return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType); } static CScript PushAll(const vector& values) { CScript result; BOOST_FOREACH(const valtype& v, values) result << v; return result; } static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn, const vector& vSolutions, vector& sigs1, vector& sigs2) { // Combine all the signatures we've got: set allsigs; BOOST_FOREACH(const valtype& v, sigs1) { if (!v.empty()) allsigs.insert(v); } BOOST_FOREACH(const valtype& v, sigs2) { if (!v.empty()) allsigs.insert(v); } // Build a map of pubkey -> signature by matching sigs to pubkeys: assert(vSolutions.size() > 1); unsigned int nSigsRequired = vSolutions.front()[0]; unsigned int nPubKeys = vSolutions.size()-2; map sigs; BOOST_FOREACH(const valtype& sig, allsigs) { for (unsigned int i = 0; i < nPubKeys; i++) { const valtype& pubkey = vSolutions[i+1]; if (sigs.count(pubkey)) continue; // Already got a sig for this pubkey if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0, 0)) { sigs[pubkey] = sig; break; } } } // Now build a merged CScript: unsigned int nSigsHave = 0; CScript result; result << OP_0; // pop-one-too-many workaround for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++) { if (sigs.count(vSolutions[i+1])) { result << sigs[vSolutions[i+1]]; ++nSigsHave; } } // Fill any missing with OP_0: for (unsigned int i = nSigsHave; i < nSigsRequired; i++) result << OP_0; return result; } static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const txnouttype txType, const vector& vSolutions, vector& sigs1, vector& sigs2) { switch (txType) { case TX_NONSTANDARD: case TX_NULL_DATA: // Don't know anything about this, assume bigger one is correct: if (sigs1.size() >= sigs2.size()) return PushAll(sigs1); return PushAll(sigs2); case TX_PUBKEY: case TX_PUBKEYHASH: // Signatures are bigger than placeholders or empty scripts: if (sigs1.empty() || sigs1[0].empty()) return PushAll(sigs2); return PushAll(sigs1); case TX_SCRIPTHASH: if (sigs1.empty() || sigs1.back().empty()) return PushAll(sigs2); else if (sigs2.empty() || sigs2.back().empty()) return PushAll(sigs1); else { // Recur to combine: valtype spk = sigs1.back(); CScript pubKey2(spk.begin(), spk.end()); txnouttype txType2; vector > vSolutions2; Solver(pubKey2, txType2, vSolutions2); sigs1.pop_back(); sigs2.pop_back(); CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2); result << spk; return result; } case TX_MULTISIG: return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2); } return CScript(); } CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2) { txnouttype txType; vector > vSolutions; Solver(scriptPubKey, txType, vSolutions); vector stack1; EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); vector stack2; EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2); } 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 &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 &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; }