mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-12-11 05:03:16 +01:00
Merge pull request #1742 from sipa/canonical
Check for canonical public keys and signatures
This commit is contained in:
@@ -253,7 +253,68 @@ const char* GetOpName(opcodetype opcode)
|
||||
}
|
||||
}
|
||||
|
||||
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType)
|
||||
bool IsCanonicalPubKey(const valtype &vchPubKey) {
|
||||
if (vchPubKey.size() < 33)
|
||||
return error("Non-canonical public key: too short");
|
||||
if (vchPubKey[0] == 0x04) {
|
||||
if (vchPubKey.size() != 65)
|
||||
return error("Non-canonical public key: invalid length for uncompressed key");
|
||||
} else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) {
|
||||
if (vchPubKey.size() != 33)
|
||||
return error("Non-canonical public key: invalid length for compressed key");
|
||||
} else {
|
||||
return error("Non-canonical public key: compressed nor uncompressed");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsCanonicalSignature(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");
|
||||
if (vchSig[vchSig.size() - 1] & 0x7C)
|
||||
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");
|
||||
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())
|
||||
return error("Non-canonical signature: R+S length mismatch");
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, bool fStrictEncodings, int nHashType)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
CScript::const_iterator pc = script.begin();
|
||||
@@ -944,7 +1005,9 @@ 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 = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType);
|
||||
bool fSuccess = (!fStrictEncodings || (IsCanonicalSignature(vchSig) && IsCanonicalPubKey(vchPubKey)));
|
||||
if (fSuccess)
|
||||
fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType);
|
||||
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
@@ -1004,8 +1067,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
|
||||
valtype& vchPubKey = stacktop(-ikey);
|
||||
|
||||
// Check signature
|
||||
if (CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType))
|
||||
{
|
||||
bool fOk = (!fStrictEncodings || (IsCanonicalSignature(vchSig) && IsCanonicalPubKey(vchPubKey)));
|
||||
if (fOk)
|
||||
fOk = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType);
|
||||
|
||||
if (fOk) {
|
||||
isig++;
|
||||
nSigsCount--;
|
||||
}
|
||||
@@ -1572,14 +1638,14 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto
|
||||
}
|
||||
|
||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||
bool fValidatePayToScriptHash, int nHashType)
|
||||
bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType)
|
||||
{
|
||||
vector<vector<unsigned char> > stack, stackCopy;
|
||||
if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType))
|
||||
if (!EvalScript(stack, scriptSig, txTo, nIn, fStrictEncodings, nHashType))
|
||||
return false;
|
||||
if (fValidatePayToScriptHash)
|
||||
stackCopy = stack;
|
||||
if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType))
|
||||
if (!EvalScript(stack, scriptPubKey, txTo, nIn, fStrictEncodings, nHashType))
|
||||
return false;
|
||||
if (stack.empty())
|
||||
return false;
|
||||
@@ -1597,7 +1663,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
|
||||
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
|
||||
popstack(stackCopy);
|
||||
|
||||
if (!EvalScript(stackCopy, pubKey2, txTo, nIn, nHashType))
|
||||
if (!EvalScript(stackCopy, pubKey2, txTo, nIn, fStrictEncodings, nHashType))
|
||||
return false;
|
||||
if (stackCopy.empty())
|
||||
return false;
|
||||
@@ -1640,7 +1706,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa
|
||||
}
|
||||
|
||||
// Test solution
|
||||
return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, true, 0);
|
||||
return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, true, true, 0);
|
||||
}
|
||||
|
||||
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType)
|
||||
@@ -1653,7 +1719,7 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTrans
|
||||
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
|
||||
}
|
||||
|
||||
bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, int nHashType)
|
||||
bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType)
|
||||
{
|
||||
assert(nIn < txTo.vin.size());
|
||||
const CTxIn& txin = txTo.vin[nIn];
|
||||
@@ -1664,7 +1730,7 @@ bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsig
|
||||
if (txin.prevout.hash != txFrom.GetHash())
|
||||
return false;
|
||||
|
||||
return VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, fValidatePayToScriptHash, nHashType);
|
||||
return VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, fValidatePayToScriptHash, fStrictEncodings, nHashType);
|
||||
}
|
||||
|
||||
static CScript PushAll(const vector<valtype>& values)
|
||||
@@ -1782,9 +1848,9 @@ CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsign
|
||||
Solver(scriptPubKey, txType, vSolutions);
|
||||
|
||||
vector<valtype> stack1;
|
||||
EvalScript(stack1, scriptSig1, CTransaction(), 0, 0);
|
||||
EvalScript(stack1, scriptSig1, CTransaction(), 0, true, 0);
|
||||
vector<valtype> stack2;
|
||||
EvalScript(stack2, scriptSig2, CTransaction(), 0, 0);
|
||||
EvalScript(stack2, scriptSig2, CTransaction(), 0, true, 0);
|
||||
|
||||
return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user