Changeset View
Changeset View
Standalone View
Standalone View
src/script/interpreter.cpp
Show First 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | static bool CheckMinimalPush(const valtype &data, opcodetype opcode) { | ||||
} | } | ||||
if (data.size() <= 65535) { | if (data.size() <= 65535) { | ||||
// Could have used OP_PUSHDATA2. | // Could have used OP_PUSHDATA2. | ||||
return opcode == OP_PUSHDATA2; | return opcode == OP_PUSHDATA2; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
static bool IsSchnorrDataSignature(const valtype &vchSig) { | |||||
return vchSig.size() == 64; | |||||
// return vchSig.size == 65 && vchSig[0] == 's'; | |||||
} | |||||
static bool IsSchnorrTransactionSignature(const valtype &vchSig) { | |||||
return vchSig.size() == 65; | |||||
// return vchSig.size == 66 && vchSig[0] == 's'; | |||||
} | |||||
static bool IsOpcodeDisabled(opcodetype opcode, uint32_t flags) { | static bool IsOpcodeDisabled(opcodetype opcode, uint32_t flags) { | ||||
switch (opcode) { | switch (opcode) { | ||||
case OP_INVERT: | case OP_INVERT: | ||||
case OP_2MUL: | case OP_2MUL: | ||||
case OP_2DIV: | case OP_2DIV: | ||||
case OP_MUL: | case OP_MUL: | ||||
case OP_LSHIFT: | case OP_LSHIFT: | ||||
case OP_RSHIFT: | case OP_RSHIFT: | ||||
▲ Show 20 Lines • Show All 779 Lines • ▼ Show 20 Lines | try { | ||||
// (sig pubkey -- bool) | // (sig pubkey -- bool) | ||||
if (stack.size() < 2) { | if (stack.size() < 2) { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype &vchSig = stacktop(-2); | valtype &vchSig = stacktop(-2); | ||||
valtype &vchPubKey = stacktop(-1); | valtype &vchPubKey = stacktop(-1); | ||||
if (!CheckTransactionSignatureEncoding(vchSig, flags, | if (!CheckPubKeyEncoding(vchPubKey, flags, serror)) { | ||||
serror) || | // serror is set | ||||
!CheckPubKeyEncoding(vchPubKey, flags, serror)) { | return false; | ||||
} | |||||
bool isSchnorr = (flags & SCRIPT_ENABLE_SCHNORR) && | |||||
IsSchnorrTransactionSignature(vchSig); | |||||
if (isSchnorr) { | |||||
if (!CheckTransactionSchnorrSignatureEncoding( | |||||
deadalnix: CheckTransactionSignatureEncoding is passed the flags, so it knows if it is admissible that… | |||||
markblundebergAuthorUnsubmitted Done Inline ActionsCheckTransactionSignatureEncoding gets used in CHECKMULTISIG too, where schnorrs are inadmissible regardless of flags. It's a bit awkward, but the whole logic of this diff is built around the fact that it is the responsibility of opcodes in EvalScript to already decide whether a signature ought to be put into the ECDSA or Schnorr pipelines. (the specification will have to be clarified on this front, it's an important conceptual point) markblundeberg: CheckTransactionSignatureEncoding gets used in CHECKMULTISIG too, where schnorrs are… | |||||
vchSig, flags, serror)) { | |||||
// serror is set | |||||
return false; | |||||
} | |||||
} else { | |||||
if (!CheckTransactionECDSASignatureEncoding( | |||||
vchSig, flags, serror)) { | |||||
// serror is set | // serror is set | ||||
return false; | return false; | ||||
} | } | ||||
} | |||||
// 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); | ||||
// Remove signature for pre-fork scripts | // Remove signature for pre-fork scripts | ||||
CleanupScriptCode(scriptCode, vchSig, flags); | CleanupScriptCode(scriptCode, vchSig, flags); | ||||
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, | bool fSuccess = checker.CheckSig( | ||||
scriptCode, flags); | isSchnorr, vchSig, vchPubKey, scriptCode, flags); | ||||
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && | if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && | ||||
vchSig.size()) { | vchSig.size()) { | ||||
return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); | return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); | ||||
} | } | ||||
popstack(stack); | popstack(stack); | ||||
popstack(stack); | popstack(stack); | ||||
Show All 20 Lines | try { | ||||
return set_error( | return set_error( | ||||
serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | ||||
} | } | ||||
valtype &vchSig = stacktop(-3); | valtype &vchSig = stacktop(-3); | ||||
valtype &vchMessage = stacktop(-2); | valtype &vchMessage = stacktop(-2); | ||||
valtype &vchPubKey = stacktop(-1); | valtype &vchPubKey = stacktop(-1); | ||||
if (!CheckDataSignatureEncoding(vchSig, flags, | if (!CheckPubKeyEncoding(vchPubKey, flags, serror)) { | ||||
serror) || | // serror is set | ||||
!CheckPubKeyEncoding(vchPubKey, flags, serror)) { | return false; | ||||
} | |||||
bool isSchnorr = (flags & SCRIPT_ENABLE_SCHNORR) && | |||||
IsSchnorrDataSignature(vchSig); | |||||
// Schnorr sigs do not need ECDSA encoding checked. | |||||
if (!isSchnorr && !CheckDataECDSASignatureEncoding( | |||||
vchSig, flags, serror)) { | |||||
// serror is set | // serror is set | ||||
return false; | return false; | ||||
} | } | ||||
bool fSuccess = false; | bool fSuccess = false; | ||||
if (vchSig.size()) { | if (vchSig.size()) { | ||||
valtype vchHash(32); | valtype vchHash(32); | ||||
CSHA256() | CSHA256() | ||||
.Write(vchMessage.data(), vchMessage.size()) | .Write(vchMessage.data(), vchMessage.size()) | ||||
.Finalize(vchHash.data()); | .Finalize(vchHash.data()); | ||||
fSuccess = checker.VerifySignature( | fSuccess = checker.VerifySignature( | ||||
vchSig, CPubKey(vchPubKey), uint256(vchHash)); | isSchnorr, vchSig, CPubKey(vchPubKey), | ||||
uint256(vchHash)); | |||||
} | } | ||||
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && | if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && | ||||
vchSig.size()) { | vchSig.size()) { | ||||
return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); | return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); | ||||
} | } | ||||
popstack(stack); | popstack(stack); | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | try { | ||||
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 by | ||||
// CHECKMULTISIG NOT if the STRICTENC flag is set. | // CHECKMULTISIG NOT if the STRICTENC flag is set. | ||||
// See the script_(in)valid tests for details. | // See the script_(in)valid tests for details. | ||||
if (!CheckTransactionSignatureEncoding( | 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( | ||||
scriptCode, flags); | false, vchSig, vchPubKey, scriptCode, flags); | ||||
if (fOk) { | if (fOk) { | ||||
isig++; | isig++; | ||||
nSigsCount--; | nSigsCount--; | ||||
} | } | ||||
ikey++; | ikey++; | ||||
nKeysCount--; | nKeysCount--; | ||||
▲ Show 20 Lines • Show All 407 Lines • ▼ Show 20 Lines | uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo, | ||||
CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, sigHashType); | CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, sigHashType); | ||||
// Serialize and hash | // Serialize and hash | ||||
CHashWriter ss(SER_GETHASH, 0); | CHashWriter ss(SER_GETHASH, 0); | ||||
ss << txTmp << sigHashType; | ss << txTmp << sigHashType; | ||||
return ss.GetHash(); | return ss.GetHash(); | ||||
} | } | ||||
bool BaseSignatureChecker::VerifySignature(const std::vector<uint8_t> &vchSig, | bool BaseSignatureChecker::VerifySignature(bool isSchnorr, | ||||
const std::vector<uint8_t> &vchSig, | |||||
const CPubKey &pubkey, | const CPubKey &pubkey, | ||||
const uint256 &sighash) const { | const uint256 &sighash) const { | ||||
if (isSchnorr) { | |||||
return pubkey.VerifySchnorr(sighash, vchSig); | |||||
} else { | |||||
return pubkey.Verify(sighash, vchSig); | return pubkey.Verify(sighash, vchSig); | ||||
} | } | ||||
} | |||||
bool TransactionSignatureChecker::CheckSig( | bool TransactionSignatureChecker::CheckSig( | ||||
const std::vector<uint8_t> &vchSigIn, const std::vector<uint8_t> &vchPubKey, | bool isSchnorr, const std::vector<uint8_t> &vchSigIn, | ||||
const CScript &scriptCode, uint32_t flags) const { | const std::vector<uint8_t> &vchPubKey, const CScript &scriptCode, | ||||
uint32_t flags) const { | |||||
CPubKey pubkey(vchPubKey); | CPubKey pubkey(vchPubKey); | ||||
if (!pubkey.IsValid()) { | if (!pubkey.IsValid()) { | ||||
return false; | return false; | ||||
} | } | ||||
// Hash type is one byte tacked on to the end of the signature | // Hash type is one byte tacked on to the end of the signature | ||||
std::vector<uint8_t> vchSig(vchSigIn); | std::vector<uint8_t> vchSig(vchSigIn); | ||||
if (vchSig.empty()) { | if (vchSig.empty()) { | ||||
return false; | return false; | ||||
} | } | ||||
SigHashType sigHashType = GetHashType(vchSig); | SigHashType sigHashType = GetHashType(vchSig); | ||||
vchSig.pop_back(); | vchSig.pop_back(); | ||||
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, sigHashType, amount, | uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, sigHashType, amount, | ||||
this->txdata, flags); | this->txdata, flags); | ||||
if (!VerifySignature(vchSig, pubkey, sighash)) { | if (!VerifySignature(isSchnorr, vchSig, pubkey, sighash)) { | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool TransactionSignatureChecker::CheckLockTime( | bool TransactionSignatureChecker::CheckLockTime( | ||||
const CScriptNum &nLockTime) const { | const CScriptNum &nLockTime) const { | ||||
▲ Show 20 Lines • Show All 166 Lines • Show Last 20 Lines |
CheckTransactionSignatureEncoding is passed the flags, so it knows if it is admissible that this is a shnorr signature. This whole thing should be internal mechanic of checking the signature encoding, IMO.