Bitcoin Core  24.99.0
P2P Digital Currency
sigcache.cpp
Go to the documentation of this file.
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 <pubkey.h>
9 #include <random.h>
10 #include <uint256.h>
11 #include <util/system.h>
12 
13 #include <cuckoocache.h>
14 
15 #include <algorithm>
16 #include <mutex>
17 #include <optional>
18 #include <shared_mutex>
19 #include <vector>
20 
21 namespace {
27 class CSignatureCache
28 {
29 private:
31  CSHA256 m_salted_hasher_ecdsa;
32  CSHA256 m_salted_hasher_schnorr;
34  map_type setValid;
35  std::shared_mutex cs_sigcache;
36 
37 public:
38  CSignatureCache()
39  {
41  // We want the nonce to be 64 bytes long to force the hasher to process
42  // this chunk, which makes later hash computations more efficient. We
43  // just write our 32-byte entropy, and then pad with 'E' for ECDSA and
44  // 'S' for Schnorr (followed by 0 bytes).
45  static constexpr unsigned char PADDING_ECDSA[32] = {'E'};
46  static constexpr unsigned char PADDING_SCHNORR[32] = {'S'};
47  m_salted_hasher_ecdsa.Write(nonce.begin(), 32);
48  m_salted_hasher_ecdsa.Write(PADDING_ECDSA, 32);
49  m_salted_hasher_schnorr.Write(nonce.begin(), 32);
50  m_salted_hasher_schnorr.Write(PADDING_SCHNORR, 32);
51  }
52 
53  void
54  ComputeEntryECDSA(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) const
55  {
56  CSHA256 hasher = m_salted_hasher_ecdsa;
57  hasher.Write(hash.begin(), 32).Write(pubkey.data(), pubkey.size()).Write(vchSig.data(), vchSig.size()).Finalize(entry.begin());
58  }
59 
60  void
61  ComputeEntrySchnorr(uint256& entry, const uint256 &hash, Span<const unsigned char> sig, const XOnlyPubKey& pubkey) const
62  {
63  CSHA256 hasher = m_salted_hasher_schnorr;
64  hasher.Write(hash.begin(), 32).Write(pubkey.data(), pubkey.size()).Write(sig.data(), sig.size()).Finalize(entry.begin());
65  }
66 
67  bool
68  Get(const uint256& entry, const bool erase)
69  {
70  std::shared_lock<std::shared_mutex> lock(cs_sigcache);
71  return setValid.contains(entry, erase);
72  }
73 
74  void Set(const uint256& entry)
75  {
76  std::unique_lock<std::shared_mutex> lock(cs_sigcache);
77  setValid.insert(entry);
78  }
79  std::optional<std::pair<uint32_t, size_t>> setup_bytes(size_t n)
80  {
81  return setValid.setup_bytes(n);
82  }
83 };
84 
85 /* In previous versions of this code, signatureCache was a local static variable
86  * in CachingTransactionSignatureChecker::VerifySignature. We initialize
87  * signatureCache outside of VerifySignature to avoid the atomic operation per
88  * call overhead associated with local static variables even though
89  * signatureCache could be made local to VerifySignature.
90 */
91 static CSignatureCache signatureCache;
92 } // namespace
93 
94 // To be called once in AppInitMain/BasicTestingSetup to initialize the
95 // signatureCache.
96 bool InitSignatureCache(size_t max_size_bytes)
97 {
98  auto setup_results = signatureCache.setup_bytes(max_size_bytes);
99  if (!setup_results) return false;
100 
101  const auto [num_elems, approx_size_bytes] = *setup_results;
102  LogPrintf("Using %zu MiB out of %zu MiB requested for signature cache, able to store %zu elements\n",
103  approx_size_bytes >> 20, max_size_bytes >> 20, num_elems);
104  return true;
105 }
106 
107 bool CachingTransactionSignatureChecker::VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
108 {
109  uint256 entry;
110  signatureCache.ComputeEntryECDSA(entry, sighash, vchSig, pubkey);
111  if (signatureCache.Get(entry, !store))
112  return true;
113  if (!TransactionSignatureChecker::VerifyECDSASignature(vchSig, pubkey, sighash))
114  return false;
115  if (store)
116  signatureCache.Set(entry);
117  return true;
118 }
119 
121 {
122  uint256 entry;
123  signatureCache.ComputeEntrySchnorr(entry, sighash, sig, pubkey);
124  if (signatureCache.Get(entry, !store)) return true;
125  if (!TransactionSignatureChecker::VerifySchnorrSignature(sig, pubkey, sighash)) return false;
126  if (store) signatureCache.Set(entry);
127  return true;
128 }
An encapsulated public key.
Definition: pubkey.h:34
unsigned int size() const
Simple read-only vector-like interface to the pubkey data.
Definition: pubkey.h:112
const unsigned char * data() const
Definition: pubkey.h:113
A hasher class for SHA-256.
Definition: sha256.h:14
void Finalize(unsigned char hash[OUTPUT_SIZE])
Definition: sha256.cpp:707
CSHA256 & Write(const unsigned char *data, size_t len)
Definition: sha256.cpp:681
bool VerifySchnorrSignature(Span< const unsigned char > sig, const XOnlyPubKey &pubkey, const uint256 &sighash) const override
Definition: sigcache.cpp:120
bool VerifyECDSASignature(const std::vector< unsigned char > &vchSig, const CPubKey &vchPubKey, const uint256 &sighash) const override
Definition: sigcache.cpp:107
cache implements a cache with properties similar to a cuckoo-set.
Definition: cuckoocache.h:163
virtual bool VerifySchnorrSignature(Span< const unsigned char > sig, const XOnlyPubKey &pubkey, const uint256 &sighash) const
virtual bool VerifyECDSASignature(const std::vector< unsigned char > &vchSig, const CPubKey &vchPubKey, const uint256 &sighash) const
constexpr std::size_t size() const noexcept
Definition: span.h:186
constexpr C * data() const noexcept
Definition: span.h:173
static constexpr size_t size()
Definition: pubkey.h:281
const unsigned char * data() const
Definition: pubkey.h:280
unsigned char * begin()
Definition: uint256.h:61
256-bit opaque blob.
Definition: uint256.h:119
#define LogPrintf(...)
Definition: logging.h:236
unsigned int nonce
Definition: miner_tests.cpp:69
uint256 GetRandHash() noexcept
Definition: random.cpp:592
bool InitSignatureCache(size_t max_size_bytes)
Definition: sigcache.cpp:96