X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fscript.cpp;h=c97c8946a72d70f6004b7974d946229dab1714aa;hb=e10fa48ea2c24f9647668aafa1f9caa48a51de2f;hp=44f77aedcc1a4fe5b0b44b78ec6c05a06a9c0873;hpb=77a43545b4491b9703d803765da9059d2bdd5aaa;p=novacoin.git diff --git a/src/script.cpp b/src/script.cpp index 44f77ae..c97c894 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -99,6 +99,7 @@ const char* GetTxnOutputType(txnouttype t) { case TX_NONSTANDARD: return "nonstandard"; case TX_PUBKEY: return "pubkey"; + case TX_PUBKEY_DROP: return "pubkeydrop"; case TX_PUBKEYHASH: return "pubkeyhash"; case TX_SCRIPTHASH: return "scripthash"; case TX_MULTISIG: return "multisig"; @@ -270,10 +271,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 +281,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 ((nLenR + nLenS + (fWithHashType ? 7 : 6)) != vchSig.size()) return error("Non-canonical signature: R+S length mismatch"); const unsigned char *R = &vchSig[4]; @@ -317,7 +317,13 @@ 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_LOW_S) { + 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"); } @@ -325,6 +331,13 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { 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) != 0); +} + bool EvalScript(vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { CAutoBN_CTX pctx; @@ -575,7 +588,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 +638,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 +686,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 +914,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 +925,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; @@ -1182,6 +1195,12 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector SMALLDATA_SWITCH_TIME) + { + // Malleable pubkey tx hack, sender provides generated pubkey combined with R parameter. The R parameter is dropped before checking a signature. + mTemplates.insert(make_pair(TX_PUBKEY_DROP, CScript() << OP_PUBKEY << OP_PUBKEY << OP_DROP << 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)); @@ -1276,8 +1295,8 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector 80) + // small pushdata, <= 1024 bytes + if (vch1.size() > (GetTime() > SMALLDATA_SWITCH_TIME ? 1024 : 80)) break; } else if (opcode1 != opcode2 || vch1 != vch2) @@ -1294,7 +1313,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) +bool SignR(const CPubKey& pubKey, const CPubKey& R, const CKeyStore& keystore, const uint256& hash, int nHashType, CScript& scriptSigRet) +{ + CKey key; + if (!keystore.CreatePrivKey(pubKey, R, 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, const uint256& hash, int nHashType, CScript& scriptSigRet) { int nSigned = 0; int nRequired = multisigdata.front()[0]; @@ -1329,7 +1363,7 @@ bool SignN(const vector& multisigdata, const CKeyStore& keystore, uint2 // 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, +bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, const uint256& hash, int nHashType, CScript& scriptSigRet, txnouttype& whichTypeRet) { scriptSigRet.clear(); @@ -1347,6 +1381,12 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); return Sign1(keyID, keystore, hash, nHashType, scriptSigRet); + case TX_PUBKEY_DROP: + { + CPubKey key = CPubKey(vSolutions[0]); + CPubKey R = CPubKey(vSolutions[1]); + return SignR(key, R, keystore, hash, nHashType, scriptSigRet); + } case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) @@ -1377,6 +1417,7 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector { private: const CKeyStore &keystore; + CAffectedKeysVisitor& operator=(CAffectedKeysVisitor const&); std::vector &vKeys; public: @@ -1569,7 +1619,10 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto if (!Solver(scriptPubKey, typeRet, vSolutions)) return false; if (typeRet == TX_NULL_DATA) + { + nRequiredRet = 0; return true; + } if (typeRet == TX_MULTISIG) { @@ -1583,6 +1636,8 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto else { nRequiredRet = 1; + if (typeRet == TX_PUBKEY_DROP) + return true; CTxDestination address; if (!ExtractDestination(scriptPubKey, address)) return false; @@ -1687,7 +1742,7 @@ static CScript PushAll(const vector& values) return result; } -static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, +static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const vector& vSolutions, vector& sigs1, vector& sigs2) { @@ -1707,7 +1762,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) { @@ -1742,7 +1797,7 @@ static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, u 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& vSolutions, vector& sigs1, vector& sigs2) { @@ -1755,6 +1810,7 @@ static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, return PushAll(sigs1); return PushAll(sigs2); case TX_PUBKEY: + case TX_PUBKEY_DROP: case TX_PUBKEYHASH: // Signatures are bigger than placeholders or empty scripts: if (sigs1.empty() || sigs1[0].empty()) @@ -1787,7 +1843,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; @@ -1916,6 +1972,13 @@ void CScript::SetDestination(const CTxDestination& dest) boost::apply_visitor(CScriptVisitor(this), dest); } +void CScript::SetDestination(const CPubKey& R, CPubKey& pubKeyVariant) +{ + this->clear(); + *this << pubKeyVariant << R << OP_DROP << OP_CHECKSIG; +} + + void CScript::SetMultisig(int nRequired, const std::vector& keys) { this->clear(); @@ -1923,5 +1986,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; }