git / moonbite-core / src/script/sigcache.cpp · raw

// Copyright (c) 2009-2010 Satoshi Nakamoto// Copyright (c) 2009-2019 The Bitcoin Core developers// Distributed under the MIT software license, see the accompanying// file COPYING or http://www.opensource.org/licenses/mit-license.php.#include <script/sigcache.h>#include <pubkey.h>#include <random.h>#include <uint256.h>#include <util/system.h>#include <cuckoocache.h>#include <boost/thread/shared_mutex.hpp>namespace {/** * Valid signature cache, to avoid doing expensive ECDSA signature checking * twice for every transaction (once when accepted into memory pool, and * again when accepted into the block chain) */class CSignatureCache{private:     //! Entries are SHA256(nonce || 'E' or 'S' || 31 zero bytes || signature hash || public key || signature):    CSHA256 m_salted_hasher_ecdsa;    CSHA256 m_salted_hasher_schnorr;    typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type;    map_type setValid;    boost::shared_mutex cs_sigcache;public:    CSignatureCache()    {        uint256 nonce = GetRandHash();        // We want the nonce to be 64 bytes long to force the hasher to process        // this chunk, which makes later hash computations more efficient. We        // just write our 32-byte entropy, and then pad with 'E' for ECDSA and        // 'S' for Schnorr (followed by 0 bytes).        static constexpr unsigned char PADDING_ECDSA[32] = {'E'};        static constexpr unsigned char PADDING_SCHNORR[32] = {'S'};        m_salted_hasher_ecdsa.Write(nonce.begin(), 32);        m_salted_hasher_ecdsa.Write(PADDING_ECDSA, 32);        m_salted_hasher_schnorr.Write(nonce.begin(), 32);        m_salted_hasher_schnorr.Write(PADDING_SCHNORR, 32);    }    void    ComputeEntryECDSA(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) const    {        CSHA256 hasher = m_salted_hasher_ecdsa;        hasher.Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin());    }    void    ComputeEntrySchnorr(uint256& entry, const uint256 &hash, Span<const unsigned char> sig, const XOnlyPubKey& pubkey) const    {        CSHA256 hasher = m_salted_hasher_schnorr;        hasher.Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(sig.data(), sig.size()).Finalize(entry.begin());    }    bool    Get(const uint256& entry, const bool erase)    {        boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);        return setValid.contains(entry, erase);    }    void Set(uint256& entry)    {        boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);        setValid.insert(entry);    }    uint32_t setup_bytes(size_t n)    {        return setValid.setup_bytes(n);    }};/* In previous versions of this code, signatureCache was a local static variable * in CachingTransactionSignatureChecker::VerifySignature.  We initialize * signatureCache outside of VerifySignature to avoid the atomic operation per * call overhead associated with local static variables even though * signatureCache could be made local to VerifySignature.*/static CSignatureCache signatureCache;} // namespace// To be called once in AppInitMain/BasicTestingSetup to initialize the// signatureCache.void InitSignatureCache(){    // nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,    // setup_bytes creates the minimum possible cache (2 elements).    size_t nMaxCacheSize = std::min(std::max((int64_t)0, gArgs.GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) / 2), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);    size_t nElems = signatureCache.setup_bytes(nMaxCacheSize);    LogPrintf("Using %zu MiB out of %zu/2 requested for signature cache, able to store %zu elements\n",            (nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems);}bool CachingTransactionSignatureChecker::VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const{    uint256 entry;    signatureCache.ComputeEntryECDSA(entry, sighash, vchSig, pubkey);    if (signatureCache.Get(entry, !store))        return true;    if (!TransactionSignatureChecker::VerifyECDSASignature(vchSig, pubkey, sighash))        return false;    if (store)        signatureCache.Set(entry);    return true;}bool CachingTransactionSignatureChecker::VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const{    uint256 entry;    signatureCache.ComputeEntrySchnorr(entry, sighash, sig, pubkey);    if (signatureCache.Get(entry, !store)) return true;    if (!TransactionSignatureChecker::VerifySchnorrSignature(sig, pubkey, sighash)) return false;    if (store) signatureCache.Set(entry);    return true;}