Changeset View
Changeset View
Standalone View
Standalone View
src/script/interpreter.cpp
Show First 20 Lines • Show All 203 Lines • ▼ Show 20 Lines | static void CleanupScriptCode(CScript &scriptCode, | ||||
} | } | ||||
} | } | ||||
static bool IsDefinedHashtypeSignature(const valtype &vchSig) { | static bool IsDefinedHashtypeSignature(const valtype &vchSig) { | ||||
if (vchSig.size() == 0) { | if (vchSig.size() == 0) { | ||||
return false; | return false; | ||||
} | } | ||||
uint32_t nHashType = | uint32_t nHashType = | ||||
GetHashType(vchSig) & ~(SIGHASH_ANYONECANPAY | SIGHASH_FORKID); | GetHashType(vchSig) & | ||||
~(SIGHASH_SPENDANYOUTPUT | SIGHASH_ANYONECANPAY | SIGHASH_FORKID); | |||||
if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) { | if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) { | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CheckSignatureEncoding(const std::vector<uint8_t> &vchSig, uint32_t flags, | bool CheckSignatureEncoding(const std::vector<uint8_t> &vchSig, uint32_t flags, | ||||
Show All 12 Lines | if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && | ||||
!IsLowDERSignature(vchSig, serror)) { | !IsLowDERSignature(vchSig, serror)) { | ||||
// serror is set | // serror is set | ||||
return false; | return false; | ||||
} | } | ||||
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0) { | if ((flags & SCRIPT_VERIFY_STRICTENC) != 0) { | ||||
if (!IsDefinedHashtypeSignature(vchSig)) { | if (!IsDefinedHashtypeSignature(vchSig)) { | ||||
return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE); | return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE); | ||||
} | } | ||||
bool usesAnyOneCanPay = GetHashType(vchSig) & SIGHASH_ANYONECANPAY; | |||||
bool usesSpendAnyOutput = GetHashType(vchSig) & SIGHASH_SPENDANYOUTPUT; | |||||
bool spendAnyOutputEnabled = | |||||
flags & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT; | |||||
if (!spendAnyOutputEnabled && usesSpendAnyOutput) { | |||||
return set_error(serror, SCRIPT_ERR_SPENDANYOUTPUT_NOT_ENABLED); | |||||
} | |||||
// spend-any-output MUST use any-one-can-pay (otherwise, you'd need all | |||||
// pubkeys) | |||||
if (usesSpendAnyOutput && !usesAnyOneCanPay) { | |||||
return set_error(serror, | |||||
SCRIPT_ERR_SPENDANYOUTPUT_WITHOUT_ANYONECANPAY); | |||||
} | |||||
bool usesForkId = GetHashType(vchSig) & SIGHASH_FORKID; | bool usesForkId = GetHashType(vchSig) & SIGHASH_FORKID; | ||||
bool forkIdEnabled = flags & SCRIPT_ENABLE_SIGHASH_FORKID; | bool forkIdEnabled = flags & SCRIPT_ENABLE_SIGHASH_FORKID; | ||||
if (!forkIdEnabled && usesForkId) { | if (!forkIdEnabled && usesForkId) { | ||||
return set_error(serror, SCRIPT_ERR_ILLEGAL_FORKID); | return set_error(serror, SCRIPT_ERR_ILLEGAL_FORKID); | ||||
} | } | ||||
if (forkIdEnabled && !usesForkId) { | if (forkIdEnabled && !usesForkId) { | ||||
return set_error(serror, SCRIPT_ERR_MUST_USE_FORKID); | return set_error(serror, SCRIPT_ERR_MUST_USE_FORKID); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,096 Lines • ▼ Show 20 Lines | PrecomputedTransactionData::PrecomputedTransactionData( | ||||
const CTransaction &txTo) { | const CTransaction &txTo) { | ||||
hashPrevouts = GetPrevoutHash(txTo); | hashPrevouts = GetPrevoutHash(txTo); | ||||
hashSequence = GetSequenceHash(txTo); | hashSequence = GetSequenceHash(txTo); | ||||
hashOutputs = GetOutputsHash(txTo); | hashOutputs = GetOutputsHash(txTo); | ||||
} | } | ||||
uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo, | uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo, | ||||
unsigned int nIn, uint32_t nHashType, | unsigned int nIn, uint32_t nHashType, | ||||
const Amount &amount, | const Amount &amount, const CScript &scriptPubKey, | ||||
const PrecomputedTransactionData *cache, uint32_t flags) { | const PrecomputedTransactionData *cache, uint32_t flags) { | ||||
if ((nHashType & SIGHASH_FORKID) && | if ((nHashType & SIGHASH_FORKID) && | ||||
(flags & SCRIPT_ENABLE_SIGHASH_FORKID)) { | (flags & SCRIPT_ENABLE_SIGHASH_FORKID)) { | ||||
uint256 hashPrevouts; | uint256 hashPrevouts; | ||||
uint256 hashSequence; | uint256 hashSequence; | ||||
uint256 hashOutputs; | uint256 hashOutputs; | ||||
if (!(nHashType & SIGHASH_ANYONECANPAY)) { | if (!(nHashType & SIGHASH_ANYONECANPAY)) { | ||||
Show All 17 Lines | if ((nHashType & SIGHASH_FORKID) && | ||||
} | } | ||||
CHashWriter ss(SER_GETHASH, 0); | CHashWriter ss(SER_GETHASH, 0); | ||||
// Version | // Version | ||||
ss << txTo.nVersion; | ss << txTo.nVersion; | ||||
// Input prevouts/nSequence (none/all, depending on flags) | // Input prevouts/nSequence (none/all, depending on flags) | ||||
ss << hashPrevouts; | ss << hashPrevouts; | ||||
ss << hashSequence; | ss << hashSequence; | ||||
if ((nHashType & SIGHASH_SPENDANYOUTPUT) && | |||||
(flags & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT)) { | |||||
// SPENDANYOUTPUT includes the scriptcode and pubkey, but not the | |||||
// amount and prevout | |||||
ss << static_cast<const CScriptBase &>(scriptPubKey); | |||||
markblundeberg: Worth noting that this prevents implementing the floating transactions of Eltoo, which require… | |||||
ss << static_cast<const CScriptBase &>(scriptCode); | |||||
} else { | |||||
// The input being signed (replacing the scriptSig with scriptCode + | // The input being signed (replacing the scriptSig with scriptCode + | ||||
// amount). The prevout may already be contained in hashPrevout, and the | // amount). The prevout may already be contained in hashPrevout, and | ||||
// the | |||||
// nSequence may already be contain in hashSequence. | // nSequence may already be contain in hashSequence. | ||||
ss << txTo.vin[nIn].prevout; | ss << txTo.vin[nIn].prevout; | ||||
ss << static_cast<const CScriptBase &>(scriptCode); | ss << static_cast<const CScriptBase &>(scriptCode); | ||||
ss << amount.GetSatoshis(); | ss << amount.GetSatoshis(); | ||||
} | |||||
ss << txTo.vin[nIn].nSequence; | ss << txTo.vin[nIn].nSequence; | ||||
// Outputs (none/one/all, depending on flags) | // Outputs (none/one/all, depending on flags) | ||||
ss << hashOutputs; | ss << hashOutputs; | ||||
// Locktime | // Locktime | ||||
ss << txTo.nLockTime; | ss << txTo.nLockTime; | ||||
// Sighash type | // Sighash type | ||||
ss << nHashType; | ss << nHashType; | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | bool TransactionSignatureChecker::CheckSig( | ||||
std::vector<uint8_t> vchSig(vchSigIn); | std::vector<uint8_t> vchSig(vchSigIn); | ||||
if (vchSig.empty()) { | if (vchSig.empty()) { | ||||
return false; | return false; | ||||
} | } | ||||
uint32_t nHashType = GetHashType(vchSig); | uint32_t nHashType = GetHashType(vchSig); | ||||
vchSig.pop_back(); | vchSig.pop_back(); | ||||
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, | uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, | ||||
this->txdata, flags); | CScript(vchPubKey), this->txdata, flags); | ||||
if (!VerifySignature(vchSig, pubkey, sighash)) { | if (!VerifySignature(vchSig, pubkey, sighash)) { | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 168 Lines • Show Last 20 Lines |
Worth noting that this prevents implementing the floating transactions of Eltoo, which require that the UTXO script not be committed in the signature. Preferably scriptCode shouldn't be committed either, so it's not necessary to modify Eltoo scripts to use OP_CODESEPARATOR. (Easy modification in the case of Eltoo updates, but perhaps not so easy for more complex scripts).
https://blockstream.com/eltoo.pdf