Changeset View
Changeset View
Standalone View
Standalone View
src/script/sigcache.cpp
Show All 11 Lines | |||||
#include "uint256.h" | #include "uint256.h" | ||||
#include "util.h" | #include "util.h" | ||||
#include <boost/thread/shared_mutex.hpp> | #include <boost/thread/shared_mutex.hpp> | ||||
namespace { | namespace { | ||||
/** | /** | ||||
* Valid signature cache, to avoid doing expensive ECDSA signature checking | * Valid signature cache, to avoid doing expensive signature checking | ||||
* twice for every transaction (once when accepted into memory pool, and | * twice for every transaction (once when accepted into memory pool, and | ||||
* again when accepted into the block chain) | * again when accepted into the block chain). | ||||
* | |||||
* We use a different nonce for ECDSA and Schnorr so that a valid 64-byte ECDSA | |||||
* signature cannot be maliciously reused as a Schnorr signature, and a valid | |||||
* Schnorr signature cannot be maliciously reused as a 64-byte ECDSA signature. | |||||
*/ | */ | ||||
class CSignatureCache { | class CSignatureCache { | ||||
private: | private: | ||||
//! Entries are SHA256(nonce || signature hash || public key || signature): | //! Entries are SHA256(nonce || signature hash || public key || signature): | ||||
uint256 nonce; | uint256 nonceECDSA; | ||||
uint256 nonceSchnorr; | |||||
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(nonceECDSA.begin(), 32); | |||||
GetRandBytes(nonceSchnorr.begin(), 32); | |||||
assert(nonceSchnorr != nonceECDSA); | |||||
} | |||||
void ComputeEntry(uint256 &entry, const uint256 &hash, | void ComputeEntryECDSA(uint256 &entry, const uint256 &hash, | ||||
const std::vector<uint8_t> &vchSig, | const std::vector<uint8_t> &vchSig, | ||||
const CPubKey &pubkey) { | const CPubKey &pubkey) { | ||||
CSHA256() | CSHA256() | ||||
.Write(nonce.begin(), 32) | .Write(nonceECDSA.begin(), 32) | ||||
.Write(hash.begin(), 32) | |||||
.Write(&pubkey[0], pubkey.size()) | |||||
.Write(&vchSig[0], vchSig.size()) | |||||
.Finalize(entry.begin()); | |||||
} | |||||
void ComputeEntrySchnorr(uint256 &entry, const uint256 &hash, | |||||
const std::vector<uint8_t> &vchSig, | |||||
const CPubKey &pubkey) { | |||||
CSHA256() | |||||
.Write(nonceSchnorr.begin(), 32) | |||||
.Write(hash.begin(), 32) | .Write(hash.begin(), 32) | ||||
.Write(&pubkey[0], pubkey.size()) | .Write(&pubkey[0], pubkey.size()) | ||||
.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); | ||||
Show All 31 Lines | 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::VerifySignatureECDSA( | bool CachingTransactionSignatureChecker::VerifySignatureECDSA( | ||||
const std::vector<uint8_t> &vchSig, const CPubKey &pubkey, | 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.ComputeEntryECDSA(entry, sighash, vchSig, pubkey); | ||||
if (signatureCache.Get(entry, !store)) { | if (signatureCache.Get(entry, !store)) { | ||||
return true; | return true; | ||||
} | } | ||||
if (!TransactionSignatureChecker::VerifySignatureECDSA(vchSig, pubkey, | if (!TransactionSignatureChecker::VerifySignatureECDSA(vchSig, pubkey, | ||||
sighash)) { | sighash)) { | ||||
return false; | return false; | ||||
} | } | ||||
if (store) { | if (store) { | ||||
signatureCache.Set(entry); | signatureCache.Set(entry); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CachingTransactionSignatureChecker::VerifySignatureSchnorr( | |||||
const std::vector<uint8_t> &vchSig, const CPubKey &pubkey, | |||||
const uint256 &sighash) const { | |||||
uint256 entry; | |||||
signatureCache.ComputeEntrySchnorr(entry, sighash, vchSig, pubkey); | |||||
if (signatureCache.Get(entry, !store)) { | |||||
return true; | |||||
} | |||||
if (!TransactionSignatureChecker::VerifySignatureSchnorr(vchSig, pubkey, | |||||
sighash)) { | |||||
return false; | |||||
} | |||||
if (store) { | |||||
signatureCache.Set(entry); | |||||
} | |||||
return true; | |||||
} |