mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-18 22:35:39 +01:00
Make SCRIPT_VERIFY_STRICTENC compatible with BIP62
* Delete canonical_tests.cpp, and move the tests to script_tests.cpp. * Split off SCRIPT_VERIFY_DERSIG from SCRIPT_VERIFY_STRICTENC (the BIP62 part of it). * Change signature STRICTENC/DERSIG semantics to fail the script entirely rather than the CHECKSIG result (softfork safety, and BIP62 requirement). * Add many autogenerated tests for several odd cases. * Mention specific BIP62 rules in the script verification flags.
This commit is contained in:
@@ -52,10 +52,7 @@ static inline void popstack(vector<valtype>& stack)
|
||||
stack.pop_back();
|
||||
}
|
||||
|
||||
bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) {
|
||||
if (!(flags & SCRIPT_VERIFY_STRICTENC))
|
||||
return true;
|
||||
|
||||
bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
|
||||
if (vchPubKey.size() < 33)
|
||||
return error("Non-canonical public key: too short");
|
||||
if (vchPubKey[0] == 0x04) {
|
||||
@@ -70,10 +67,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 static IsDERSignature(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
|
||||
@@ -83,9 +77,6 @@ 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)
|
||||
@@ -117,14 +108,51 @@ 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 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 static IsLowDERSignature(const valtype &vchSig) {
|
||||
if (!IsDERSignature(vchSig)) {
|
||||
return false;
|
||||
}
|
||||
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 static IsDefinedHashtypeSignature(const valtype &vchSig) {
|
||||
if (vchSig.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY));
|
||||
if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
|
||||
return error("Non-canonical signature: unknown hashtype byte");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags) {
|
||||
if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsDERSignature(vchSig)) {
|
||||
return false;
|
||||
} else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig)) {
|
||||
return false;
|
||||
} else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSig)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags) {
|
||||
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchSig)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -670,8 +698,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||
// Drop the signature, since there's no way for a signature to sign itself
|
||||
scriptCode.FindAndDelete(CScript(vchSig));
|
||||
|
||||
bool fSuccess = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) &&
|
||||
checker.CheckSig(vchSig, vchPubKey, scriptCode);
|
||||
if (!CheckSignatureEncoding(vchSig, flags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fSuccess = CheckPubKeyEncoding(vchPubKey, flags) && checker.CheckSig(vchSig, vchPubKey, scriptCode);
|
||||
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
@@ -730,9 +761,12 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||
valtype& vchSig = stacktop(-isig);
|
||||
valtype& vchPubKey = stacktop(-ikey);
|
||||
|
||||
if (!CheckSignatureEncoding(vchSig, flags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check signature
|
||||
bool fOk = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) &&
|
||||
checker.CheckSig(vchSig, vchPubKey, scriptCode);
|
||||
bool fOk = CheckPubKeyEncoding(vchPubKey, flags) && checker.CheckSig(vchSig, vchPubKey, scriptCode);
|
||||
|
||||
if (fOk) {
|
||||
isig++;
|
||||
|
||||
@@ -28,14 +28,25 @@ enum
|
||||
enum
|
||||
{
|
||||
SCRIPT_VERIFY_NONE = 0,
|
||||
SCRIPT_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
|
||||
SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys
|
||||
SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) in signatures (depends on STRICTENC)
|
||||
SCRIPT_VERIFY_NULLDUMMY = (1U << 3), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length
|
||||
};
|
||||
|
||||
bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags);
|
||||
bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int flags);
|
||||
// Evaluate P2SH subscripts (softfork safe, BIP16).
|
||||
SCRIPT_VERIFY_P2SH = (1U << 0),
|
||||
|
||||
// Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.
|
||||
// Passing a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) to checksig causes that pubkey to be
|
||||
// skipped (not softfork safe: this flag can widen the validity of OP_CHECKSIG OP_NOT).
|
||||
SCRIPT_VERIFY_STRICTENC = (1U << 1),
|
||||
|
||||
// Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1)
|
||||
SCRIPT_VERIFY_DERSIG = (1U << 2),
|
||||
|
||||
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
|
||||
// (softfork safe, BIP62 rule 5).
|
||||
SCRIPT_VERIFY_LOW_S = (1U << 3),
|
||||
|
||||
// verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7).
|
||||
SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
|
||||
};
|
||||
|
||||
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user