/ src / script / sigcache.cpp
sigcache.cpp
 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 <span.h>
13  #include <uint256.h>
14  #include <util/log.h>
15  
16  #include <mutex>
17  #include <shared_mutex>
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  }