sigcache.cpp raw

   1  // Copyright (c) 2009-2010 Satoshi Nakamoto
   2  // Copyright (c) 2009-present 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 <crypto/sha256.h>
   9  #include <pubkey.h>
  10  #include <random.h>
  11  #include <script/interpreter.h>
  12  #include <uint256.h>
  13  #include <util/log.h>
  14  
  15  #include <mutex>
  16  #include <shared_mutex>
  17  #include <utility>
  18  #include <vector>
  19  
  20  SignatureCache::SignatureCache(const size_t max_size_bytes)
  21  {
  22      uint256 nonce = GetRandHash();
  23      // We want the nonce to be 64 bytes long to force the hasher to process
  24      // this chunk, which makes later hash computations more efficient. We
  25      // just write our 32-byte entropy, and then pad with 'E' for ECDSA and
  26      // 'S' for Schnorr (followed by 0 bytes).
  27      static constexpr unsigned char PADDING_ECDSA[32] = {'E'};
  28      static constexpr unsigned char PADDING_SCHNORR[32] = {'S'};
  29      m_salted_hasher_ecdsa.Write(nonce.begin(), 32);
  30      m_salted_hasher_ecdsa.Write(PADDING_ECDSA, 32);
  31      m_salted_hasher_schnorr.Write(nonce.begin(), 32);
  32      m_salted_hasher_schnorr.Write(PADDING_SCHNORR, 32);
  33  
  34      const auto [num_elems, approx_size_bytes] = setValid.setup_bytes(max_size_bytes);
  35      LogInfo("Using %zu MiB out of %zu MiB requested for signature cache, able to store %zu elements",
  36                approx_size_bytes >> 20, max_size_bytes >> 20, num_elems);
  37  }
  38  
  39  void SignatureCache::ComputeEntryECDSA(uint256& entry, const uint256& hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) const
  40  {
  41      CSHA256 hasher = m_salted_hasher_ecdsa;
  42      hasher.Write(hash.begin(), 32).Write(pubkey.data(), pubkey.size()).Write(vchSig.data(), vchSig.size()).Finalize(entry.begin());
  43  }
  44  
  45  void SignatureCache::ComputeEntrySchnorr(uint256& entry, const uint256& hash, std::span<const unsigned char> sig, const XOnlyPubKey& pubkey) const
  46  {
  47      CSHA256 hasher = m_salted_hasher_schnorr;
  48      hasher.Write(hash.begin(), 32).Write(pubkey.data(), pubkey.size()).Write(sig.data(), sig.size()).Finalize(entry.begin());
  49  }
  50  
  51  bool SignatureCache::Get(const uint256& entry, const bool erase)
  52  {
  53      std::shared_lock<std::shared_mutex> lock(cs_sigcache);
  54      return setValid.contains(entry, erase);
  55  }
  56  
  57  void SignatureCache::Set(const uint256& entry)
  58  {
  59      std::unique_lock<std::shared_mutex> lock(cs_sigcache);
  60      setValid.insert(entry);
  61  }
  62  
  63  bool CachingTransactionSignatureChecker::VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
  64  {
  65      uint256 entry;
  66      m_signature_cache.ComputeEntryECDSA(entry, sighash, vchSig, pubkey);
  67      if (m_signature_cache.Get(entry, !store))
  68          return true;
  69      if (!TransactionSignatureChecker::VerifyECDSASignature(vchSig, pubkey, sighash))
  70          return false;
  71      if (store)
  72          m_signature_cache.Set(entry);
  73      return true;
  74  }
  75  
  76  bool CachingTransactionSignatureChecker::VerifySchnorrSignature(std::span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const
  77  {
  78      uint256 entry;
  79      m_signature_cache.ComputeEntrySchnorr(entry, sighash, sig, pubkey);
  80      if (m_signature_cache.Get(entry, !store)) return true;
  81      if (!TransactionSignatureChecker::VerifySchnorrSignature(sig, pubkey, sighash)) return false;
  82      if (store) m_signature_cache.Set(entry);
  83      return true;
  84  }
  85