Changeset View
Changeset View
Standalone View
Standalone View
src/script/sigcache.cpp
Show All 26 Lines | private: | ||||
uint256 nonce; | uint256 nonce; | ||||
typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type; | typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type; | ||||
map_type setValid; | map_type setValid; | ||||
boost::shared_mutex cs_sigcache; | boost::shared_mutex cs_sigcache; | ||||
public: | public: | ||||
CSignatureCache() { GetRandBytes(nonce.begin(), 32); } | CSignatureCache() { GetRandBytes(nonce.begin(), 32); } | ||||
void ComputeEntry(uint256 &entry, const uint256 &hash, | void ComputeEntry(uint256 &entry, const uint256 &hash, bool isSchnorr, | ||||
const std::vector<uint8_t> &vchSig, | const std::vector<uint8_t> &vchSig, | ||||
const CPubKey &pubkey) { | const CPubKey &pubkey) { | ||||
uint8_t sb = isSchnorr ? 1 : 0; | |||||
CSHA256() | CSHA256() | ||||
.Write(nonce.begin(), 32) | .Write(nonce.begin(), 32) | ||||
.Write(hash.begin(), 32) | .Write(hash.begin(), 32) | ||||
.Write(&pubkey[0], pubkey.size()) | .Write(&pubkey[0], pubkey.size()) | ||||
.Write(&sb, 1) | |||||
deadalnix: What is the goal of this ? | |||||
markblundebergAuthorUnsubmitted Done Inline ActionsIf we do the unflagged 64-byte signature approach, I think this explicit distinguishing is important for consensus security. Consider the case where a valid 64-byte ECDSA signature is put into the cache somehow: either during pre-upgrade or from checkmultisig. It then gets maliciously reused post-upgrade as a "Schnorr" signature. This is supposed to fail since it is an incorrect schnorr signature, but it would instead pass due to cache lookup. I think I know how to turn this into an attack where an attacker could cause a mining node to mine only invalid blocks, but it's too elaborate to get into here... markblundeberg: If we do the unflagged 64-byte signature approach, I think this explicit distinguishing is… | |||||
deadalnixUnsubmitted Not Done Inline ActionsI see. deadalnix: I see. | |||||
.Write(&vchSig[0], vchSig.size()) | .Write(&vchSig[0], vchSig.size()) | ||||
.Finalize(entry.begin()); | .Finalize(entry.begin()); | ||||
} | } | ||||
bool Get(const uint256 &entry, const bool erase) { | bool Get(const uint256 &entry, const bool erase) { | ||||
boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); | boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); | ||||
return setValid.contains(entry, erase); | return setValid.contains(entry, erase); | ||||
} | } | ||||
Show All 26 Lines | size_t nMaxCacheSize = | ||||
(size_t(1) << 20); | (size_t(1) << 20); | ||||
size_t nElems = signatureCache.setup_bytes(nMaxCacheSize); | size_t nElems = signatureCache.setup_bytes(nMaxCacheSize); | ||||
LogPrintf("Using %zu MiB out of %zu requested for signature cache, able to " | LogPrintf("Using %zu MiB out of %zu requested for signature cache, able to " | ||||
"store %zu elements\n", | "store %zu elements\n", | ||||
(nElems * sizeof(uint256)) >> 20, nMaxCacheSize >> 20, nElems); | (nElems * sizeof(uint256)) >> 20, nMaxCacheSize >> 20, nElems); | ||||
} | } | ||||
bool CachingTransactionSignatureChecker::VerifySignature( | bool CachingTransactionSignatureChecker::VerifySignature( | ||||
const std::vector<uint8_t> &vchSig, const CPubKey &pubkey, | bool isSchnorr, const std::vector<uint8_t> &vchSig, const CPubKey &pubkey, | ||||
const uint256 &sighash) const { | const uint256 &sighash) const { | ||||
uint256 entry; | uint256 entry; | ||||
signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey); | signatureCache.ComputeEntry(entry, sighash, isSchnorr, vchSig, pubkey); | ||||
if (signatureCache.Get(entry, !store)) { | if (signatureCache.Get(entry, !store)) { | ||||
return true; | return true; | ||||
} | } | ||||
if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, | if (!TransactionSignatureChecker::VerifySignature(isSchnorr, vchSig, pubkey, | ||||
sighash)) { | sighash)) { | ||||
return false; | return false; | ||||
} | } | ||||
if (store) { | if (store) { | ||||
signatureCache.Set(entry); | signatureCache.Set(entry); | ||||
} | } | ||||
return true; | return true; | ||||
} | } |
What is the goal of this ?