X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fscript.cpp;h=88587a00b154358e2e78bdbbf31d29b0e101e957;hb=2df3646c881ec9a358f93e78d993e34fa1ad161d;hp=4d3586aaa902c4ef185014cd02e6d04496647c45;hpb=9cb77566c305049f3208b711414880442fc7ac42;p=novacoin.git diff --git a/src/script.cpp b/src/script.cpp index 4d3586a..88587a0 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -270,10 +270,7 @@ bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) { return true; } -bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { - if (!(flags & SCRIPT_VERIFY_STRICTENC)) - return true; - +bool IsDERSignature(const valtype &vchSig, bool fWithHashType, bool fCheckLow) { // See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 // A canonical signature exists of: <30> <02> <02> // Where R and S are not negative (their first byte has its highest bit not set), and not @@ -283,18 +280,20 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { 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) + if (vchSig[1] != vchSig.size() - (fWithHashType ? 3 : 2)) return error("Non-canonical signature: wrong length marker"); + if (fWithHashType) { + unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); + if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) + return error("Non-canonical signature: unknown hashtype byte"); + } unsigned int nLenR = vchSig[3]; if (5 + nLenR >= vchSig.size()) return error("Non-canonical signature: S length misplaced"); unsigned int nLenS = vchSig[5+nLenR]; - if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) + if ((unsigned long)(nLenR + nLenS + (fWithHashType ? 7 : 6)) != vchSig.size()) return error("Non-canonical signature: R+S length mismatch"); const unsigned char *R = &vchSig[4]; @@ -317,14 +316,27 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) return error("Non-canonical signature: S value excessively padded"); - if (flags & SCRIPT_VERIFY_EVEN_S) { - if (S[nLenS-1] & 1) - return error("Non-canonical signature: S value odd"); + if (fCheckLow) { + unsigned int nLenR = vchSig[3]; + unsigned int nLenS = vchSig[5+nLenR]; + const unsigned char *S = &vchSig[6+nLenR]; + // 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"); } return true; } +bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { + if (!(flags & SCRIPT_VERIFY_STRICTENC)) + return true; + + return IsDERSignature(vchSig, true, flags & SCRIPT_VERIFY_LOW_S); +} + bool EvalScript(vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { CAutoBN_CTX pctx; @@ -575,7 +587,7 @@ bool EvalScript(vector >& stack, const CScript& script, co case OP_DEPTH: { // -- stacksize - CBigNum bn(stack.size()); + CBigNum bn((uint16_t) stack.size()); stack.push_back(bn.getvch()); } break; @@ -625,7 +637,7 @@ bool EvalScript(vector >& stack, const CScript& script, co // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) if (stack.size() < 2) return false; - int n = CastToBigNum(stacktop(-1)).getint(); + int n = CastToBigNum(stacktop(-1)).getint32(); popstack(stack); if (n < 0 || n >= (int)stack.size()) return false; @@ -673,7 +685,7 @@ bool EvalScript(vector >& stack, const CScript& script, co // (in -- in size) if (stack.size() < 1) return false; - CBigNum bn(stacktop(-1).size()); + CBigNum bn((uint16_t) stacktop(-1).size()); stack.push_back(bn.getvch()); } break; @@ -901,7 +913,7 @@ bool EvalScript(vector >& stack, const CScript& script, co if ((int)stack.size() < i) return false; - int nKeysCount = CastToBigNum(stacktop(-i)).getint(); + int nKeysCount = CastToBigNum(stacktop(-i)).getint32(); if (nKeysCount < 0 || nKeysCount > 20) return false; nOpCount += nKeysCount; @@ -912,7 +924,7 @@ bool EvalScript(vector >& stack, const CScript& script, co if ((int)stack.size() < i) return false; - int nSigsCount = CastToBigNum(stacktop(-i)).getint(); + int nSigsCount = CastToBigNum(stacktop(-i)).getint32(); if (nSigsCount < 0 || nSigsCount > nKeysCount) return false; int isig = ++i; @@ -1103,12 +1115,12 @@ public: // (~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 nMaxCacheSize = GetArg("-maxsigcachesize", 50000); + int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000); if (nMaxCacheSize <= 0) return; boost::shared_lock lock(cs_sigcache); - while (static_cast(setValid.size()) > nMaxCacheSize) + while (static_cast(setValid.size()) > nMaxCacheSize) { // Evict a random entry. Random because that helps // foil would-be DoS attackers who might try to pre-generate @@ -1435,36 +1447,49 @@ public: bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); } }; -bool IsMine(const CKeyStore &keystore, const CTxDestination &dest) +isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest) { - return boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest); + CScript script; + script.SetDestination(dest); + return IsMine(keystore, script); } -bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) +isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) { vector vSolutions; txnouttype whichType; - if (!Solver(scriptPubKey, whichType, vSolutions)) - return false; + if (!Solver(scriptPubKey, whichType, vSolutions)) { + if (keystore.HaveWatchOnly(scriptPubKey)) + return MINE_WATCH_ONLY; + return MINE_NO; + } CKeyID keyID; switch (whichType) { case TX_NONSTANDARD: case TX_NULL_DATA: - return false; + break; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); - return keystore.HaveKey(keyID); + if (keystore.HaveKey(keyID)) + return MINE_SPENDABLE; + break; case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); - return keystore.HaveKey(keyID); + if (keystore.HaveKey(keyID)) + return MINE_SPENDABLE; + break; case TX_SCRIPTHASH: { + CScriptID scriptID = CScriptID(uint160(vSolutions[0])); CScript subscript; - if (!keystore.GetCScript(CScriptID(uint160(vSolutions[0])), subscript)) - return false; - return IsMine(keystore, subscript); + if (keystore.GetCScript(scriptID, subscript)) { + isminetype ret = IsMine(keystore, subscript); + if (ret == MINE_SPENDABLE) + return ret; + } + break; } case TX_MULTISIG: { @@ -1474,10 +1499,15 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) // them) enable spend-out-from-under-you attacks, especially // in shared-wallet situations. vector keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); - return HaveKeys(keys, keystore) == keys.size(); + if (HaveKeys(keys, keystore) == keys.size()) + return MINE_SPENDABLE; + break; } } - return false; + + if (keystore.HaveWatchOnly(scriptPubKey)) + return MINE_WATCH_ONLY; + return MINE_NO; } bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) @@ -1509,6 +1539,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) class CAffectedKeysVisitor : public boost::static_visitor { private: const CKeyStore &keystore; + CAffectedKeysVisitor& operator=(CAffectedKeysVisitor const&); std::vector &vKeys; public: @@ -1647,7 +1678,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa } // Test solution - return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0); + return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STRICT_FLAGS, 0); } bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType) @@ -1689,7 +1720,7 @@ static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, u // 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; + unsigned int nPubKeys = (unsigned int)(vSolutions.size()-2); map sigs; BOOST_FOREACH(const valtype& sig, allsigs) { @@ -1905,5 +1936,5 @@ void CScript::SetMultisig(int nRequired, const std::vector& keys) *this << EncodeOP_N(nRequired); BOOST_FOREACH(const CKey& key, keys) *this << key.GetPubKey(); - *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; + *this << EncodeOP_N((int)(keys.size())) << OP_CHECKMULTISIG; }