/ src / script / sigcache.cpp
sigcache.cpp
  1  // Copyright (c) 2009-2010 Satoshi Nakamoto
  2  // Copyright (c) 2009-2022 The Bitcoin Core developers
  3  // Distributed under the MIT software license, see the accompanying
  4  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  5  
  6  #include <script/sigcache.h>
  7  
  8  #include <common/system.h>
  9  #include <logging.h>
 10  #include <pubkey.h>
 11  #include <random.h>
 12  #include <uint256.h>
 13  
 14  #include <cuckoocache.h>
 15  
 16  #include <algorithm>
 17  #include <mutex>
 18  #include <optional>
 19  #include <shared_mutex>
 20  #include <vector>
 21  
 22  namespace {
 23  /**
 24   * Valid signature cache, to avoid doing expensive ECDSA signature checking
 25   * twice for every transaction (once when accepted into memory pool, and
 26   * again when accepted into the block chain)
 27   */
 28  class CSignatureCache
 29  {
 30  private:
 31       //! Entries are SHA256(nonce || 'E' or 'S' || 31 zero bytes || signature hash || public key || signature):
 32      CSHA256 m_salted_hasher_ecdsa;
 33      CSHA256 m_salted_hasher_schnorr;
 34      typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type;
 35      map_type setValid;
 36      std::shared_mutex cs_sigcache;
 37  
 38  public:
 39      CSignatureCache()
 40      {
 41          uint256 nonce = GetRandHash();
 42          // We want the nonce to be 64 bytes long to force the hasher to process
 43          // this chunk, which makes later hash computations more efficient. We
 44          // just write our 32-byte entropy, and then pad with 'E' for ECDSA and
 45          // 'S' for Schnorr (followed by 0 bytes).
 46          static constexpr unsigned char PADDING_ECDSA[32] = {'E'};
 47          static constexpr unsigned char PADDING_SCHNORR[32] = {'S'};
 48          m_salted_hasher_ecdsa.Write(nonce.begin(), 32);
 49          m_salted_hasher_ecdsa.Write(PADDING_ECDSA, 32);
 50          m_salted_hasher_schnorr.Write(nonce.begin(), 32);
 51          m_salted_hasher_schnorr.Write(PADDING_SCHNORR, 32);
 52      }
 53  
 54      void
 55      ComputeEntryECDSA(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) const
 56      {
 57          CSHA256 hasher = m_salted_hasher_ecdsa;
 58          hasher.Write(hash.begin(), 32).Write(pubkey.data(), pubkey.size()).Write(vchSig.data(), vchSig.size()).Finalize(entry.begin());
 59      }
 60  
 61      void
 62      ComputeEntrySchnorr(uint256& entry, const uint256 &hash, Span<const unsigned char> sig, const XOnlyPubKey& pubkey) const
 63      {
 64          CSHA256 hasher = m_salted_hasher_schnorr;
 65          hasher.Write(hash.begin(), 32).Write(pubkey.data(), pubkey.size()).Write(sig.data(), sig.size()).Finalize(entry.begin());
 66      }
 67  
 68      bool
 69      Get(const uint256& entry, const bool erase)
 70      {
 71          std::shared_lock<std::shared_mutex> lock(cs_sigcache);
 72          return setValid.contains(entry, erase);
 73      }
 74  
 75      void Set(const uint256& entry)
 76      {
 77          std::unique_lock<std::shared_mutex> lock(cs_sigcache);
 78          setValid.insert(entry);
 79      }
 80      std::optional<std::pair<uint32_t, size_t>> setup_bytes(size_t n)
 81      {
 82          return setValid.setup_bytes(n);
 83      }
 84  };
 85  
 86  /* In previous versions of this code, signatureCache was a local static variable
 87   * in CachingTransactionSignatureChecker::VerifySignature.  We initialize
 88   * signatureCache outside of VerifySignature to avoid the atomic operation per
 89   * call overhead associated with local static variables even though
 90   * signatureCache could be made local to VerifySignature.
 91  */
 92  static CSignatureCache signatureCache;
 93  } // namespace
 94  
 95  // To be called once in AppInitMain/BasicTestingSetup to initialize the
 96  // signatureCache.
 97  bool InitSignatureCache(size_t max_size_bytes)
 98  {
 99      auto setup_results = signatureCache.setup_bytes(max_size_bytes);
100      if (!setup_results) return false;
101  
102      const auto [num_elems, approx_size_bytes] = *setup_results;
103      LogPrintf("Using %zu MiB out of %zu MiB requested for signature cache, able to store %zu elements\n",
104                approx_size_bytes >> 20, max_size_bytes >> 20, num_elems);
105      return true;
106  }
107  
108  bool CachingTransactionSignatureChecker::VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
109  {
110      uint256 entry;
111      signatureCache.ComputeEntryECDSA(entry, sighash, vchSig, pubkey);
112      if (signatureCache.Get(entry, !store))
113          return true;
114      if (!TransactionSignatureChecker::VerifyECDSASignature(vchSig, pubkey, sighash))
115          return false;
116      if (store)
117          signatureCache.Set(entry);
118      return true;
119  }
120  
121  bool CachingTransactionSignatureChecker::VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const
122  {
123      uint256 entry;
124      signatureCache.ComputeEntrySchnorr(entry, sighash, sig, pubkey);
125      if (signatureCache.Get(entry, !store)) return true;
126      if (!TransactionSignatureChecker::VerifySchnorrSignature(sig, pubkey, sighash)) return false;
127      if (store) signatureCache.Set(entry);
128      return true;
129  }