Bitcoin Core  27.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 <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 {
28 class CSignatureCache
29 {
30 private:
32  CSHA256 m_salted_hasher_ecdsa;
33  CSHA256 m_salted_hasher_schnorr;
35  map_type setValid;
36  std::shared_mutex cs_sigcache;
37 
38 public:
39  CSignatureCache()
40  {
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 
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 }
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:728
CSHA256 & Write(const unsigned char *data, size_t len)
Definition: sha256.cpp:702
bool VerifySchnorrSignature(Span< const unsigned char > sig, const XOnlyPubKey &pubkey, const uint256 &sighash) const override
Definition: sigcache.cpp:121
bool VerifyECDSASignature(const std::vector< unsigned char > &vchSig, const CPubKey &vchPubKey, const uint256 &sighash) const override
Definition: sigcache.cpp:108
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:187
constexpr C * data() const noexcept
Definition: span.h:174
static constexpr size_t size()
Definition: pubkey.h:288
const unsigned char * data() const
Definition: pubkey.h:289
constexpr unsigned char * begin()
Definition: uint256.h:68
256-bit opaque blob.
Definition: uint256.h:106
#define LogPrintf(...)
Definition: logging.h:245
unsigned int nonce
Definition: miner_tests.cpp:71
uint256 GetRandHash() noexcept
Definition: random.cpp:650
bool InitSignatureCache(size_t max_size_bytes)
Definition: sigcache.cpp:97