Changeset View
Changeset View
Standalone View
Standalone View
src/script/interpreter.cpp
Show First 20 Lines • Show All 1,005 Lines • ▼ Show 20 Lines | try { | ||||
} | } | ||||
bool fSuccess = true; | bool fSuccess = true; | ||||
// Subset of script starting at the most recent | // Subset of script starting at the most recent | ||||
// codeseparator | // codeseparator | ||||
CScript scriptCode(pbegincodehash, pend); | CScript scriptCode(pbegincodehash, pend); | ||||
if ((flags & SCRIPT_ENABLE_NEW_MULTISIG) && | |||||
(stacktop(-idummy).size() != 0)) { | |||||
// NEW MULTISIG (SCHNORR / NULL) | |||||
// "Dummy" element is now an integer whose bits | |||||
// represent which pubkeys should be checked. Note | |||||
// that the int type must support numbers as large | |||||
// as 1 << MAX_PUBKEYS_PER_MULTISIG for the getint() | |||||
// overflow clamping to work correctly here. | |||||
int nCheckBits = | |||||
CScriptNum(stacktop(-idummy), fRequireMinimal) | |||||
.getint(); | |||||
if (nCheckBits < 0) { | |||||
return set_error(serror, | |||||
SCRIPT_ERR_INVALID_CHECKBITS); | |||||
} | |||||
while (nSigsCount > 0 && nKeysCount > 0) { | |||||
if (nCheckBits & 1) { | |||||
// Check signature as requested | |||||
valtype &vchPubKey = stacktop(-ikey); | |||||
valtype &vchSig = stacktop(-isig); | |||||
if (!CheckTransactionSchnorrSignatureEncoding( | |||||
vchSig, flags, serror) || | |||||
!CheckPubKeyEncoding(vchPubKey, flags, | |||||
serror)) { | |||||
// serror is set | |||||
return false; | |||||
} | |||||
if (!checker.CheckSig(vchSig, vchPubKey, | |||||
scriptCode, flags)) { | |||||
// It is forbidden to request invalid | |||||
// signature. Make the error message a | |||||
// bit informative though. | |||||
return set_error( | |||||
serror, | |||||
vchSig.size() | |||||
? SCRIPT_ERR_SIG_NULLFAIL | |||||
: SCRIPT_ERR_SIG_NULLDUMMY); | |||||
markblundeberg: may be worth making a new error message for the invalid signature case here… | |||||
} | |||||
// A successful checksig is the only way to | |||||
// decrement nSigsCount. | |||||
isig++; | |||||
nSigsCount--; | |||||
} | |||||
nCheckBits >>= 1; | |||||
ikey++; | |||||
nKeysCount--; | |||||
} | |||||
if (nCheckBits != 0) { | |||||
// Ended before consuming all bits, because too | |||||
// many bits were set, or too-high bits were | |||||
// set. | |||||
return set_error(serror, | |||||
SCRIPT_ERR_INVALID_CHECKBITS); | |||||
} | |||||
if (nSigsCount > 0) { | |||||
// Ended before checking all signatures, because | |||||
// too few bits were set. This can return false | |||||
// (without error) if all signatures were null | |||||
// and nCheckBits was 0 to start. | |||||
fSuccess = false; | |||||
} | |||||
} else { | |||||
// LEGACY MULTISIG (ECDSA / NULL) | |||||
// A bug causes CHECKMULTISIG to consume one extra | // A bug causes CHECKMULTISIG to consume one extra | ||||
// argument whose contents were not checked in any way. | // argument whose contents were not checked in any | ||||
// way. | |||||
// | // | ||||
// Unfortunately this is a potential source of | // Unfortunately this is a potential source of | ||||
// mutability, so optionally verify it is exactly equal | // mutability, so optionally verify it is exactly | ||||
// to zero. | // equal to zero. | ||||
if ((flags & SCRIPT_VERIFY_NULLDUMMY) && | if ((flags & SCRIPT_VERIFY_NULLDUMMY) && | ||||
stacktop(-idummy).size()) { | stacktop(-idummy).size()) { | ||||
return set_error(serror, SCRIPT_ERR_SIG_NULLDUMMY); | return set_error(serror, | ||||
SCRIPT_ERR_SIG_NULLDUMMY); | |||||
} | } | ||||
// Remove signature for pre-fork scripts | // Remove signature for pre-fork scripts | ||||
for (int k = 0; k < nSigsCount; k++) { | for (int k = 0; k < nSigsCount; k++) { | ||||
valtype &vchSig = stacktop(-isig - k); | valtype &vchSig = stacktop(-isig - k); | ||||
CleanupScriptCode(scriptCode, vchSig, flags); | CleanupScriptCode(scriptCode, vchSig, flags); | ||||
} | } | ||||
while (fSuccess && nSigsCount > 0) { | while (fSuccess && nSigsCount > 0) { | ||||
valtype &vchSig = stacktop(-isig); | valtype &vchSig = stacktop(-isig); | ||||
valtype &vchPubKey = stacktop(-ikey); | valtype &vchPubKey = stacktop(-ikey); | ||||
// Note how this makes the exact order of | // Note how this makes the exact order of | ||||
// pubkey/signature evaluation distinguishable by | // pubkey/signature evaluation distinguishable | ||||
// CHECKMULTISIG NOT if the STRICTENC flag is set. | // by CHECKMULTISIG NOT if the STRICTENC flag is | ||||
// See the script_(in)valid tests for details. | // set. See the script_(in)valid tests for | ||||
// details. | |||||
if (!CheckTransactionECDSASignatureEncoding( | if (!CheckTransactionECDSASignatureEncoding( | ||||
vchSig, flags, serror) || | vchSig, flags, serror) || | ||||
!CheckPubKeyEncoding(vchPubKey, flags, | !CheckPubKeyEncoding(vchPubKey, flags, | ||||
serror)) { | serror)) { | ||||
// serror is set | // serror is set | ||||
return false; | return false; | ||||
} | } | ||||
// Check signature | // Check signature | ||||
bool fOk = checker.CheckSig(vchSig, vchPubKey, | bool fOk = checker.CheckSig(vchSig, vchPubKey, | ||||
scriptCode, flags); | scriptCode, flags); | ||||
if (fOk) { | if (fOk) { | ||||
isig++; | isig++; | ||||
nSigsCount--; | nSigsCount--; | ||||
} | } | ||||
ikey++; | ikey++; | ||||
nKeysCount--; | nKeysCount--; | ||||
// If there are more signatures left than keys left, | // If there are more signatures left than keys | ||||
// then too many signatures have failed. Exit early, | // left, then too many signatures have failed. | ||||
// without checking any further signatures. | // Exit early, without checking any further | ||||
// signatures. | |||||
if (nSigsCount > nKeysCount) { | if (nSigsCount > nKeysCount) { | ||||
fSuccess = false; | fSuccess = false; | ||||
} | } | ||||
} | } | ||||
} | |||||
// Clean up stack of actual arguments | // Clean up stack of actual arguments | ||||
while (i-- > 1) { | while (i-- > 1) { | ||||
// If the operation failed, we require that all | // If the operation failed, we require that all | ||||
// signatures must be empty vector | // signatures must be empty vector | ||||
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && | if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && | ||||
!ikey2 && stacktop(-1).size()) { | !ikey2 && stacktop(-1).size()) { | ||||
return set_error(serror, | return set_error(serror, | ||||
▲ Show 20 Lines • Show All 599 Lines • Show Last 20 Lines |
may be worth making a new error message for the invalid signature case here (SCRIPT_ERROR_INVALID_SIGNATURE) ?