Branch data Line data Source code
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 : 0 : 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 : 2 : CSignatureCache()
40 : : {
41 : 2 : 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 [ + - ][ + - ]: 2 : m_salted_hasher_ecdsa.Write(nonce.begin(), 32);
49 [ + - ]: 2 : m_salted_hasher_ecdsa.Write(PADDING_ECDSA, 32);
50 [ + - ][ + - ]: 2 : m_salted_hasher_schnorr.Write(nonce.begin(), 32);
51 [ + - ]: 2 : m_salted_hasher_schnorr.Write(PADDING_SCHNORR, 32);
52 : 2 : }
53 : :
54 : : void
55 : 0 : ComputeEntryECDSA(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) const
56 : : {
57 : 0 : CSHA256 hasher = m_salted_hasher_ecdsa;
58 : 0 : hasher.Write(hash.begin(), 32).Write(pubkey.data(), pubkey.size()).Write(vchSig.data(), vchSig.size()).Finalize(entry.begin());
59 : 0 : }
60 : :
61 : : void
62 : 0 : ComputeEntrySchnorr(uint256& entry, const uint256 &hash, Span<const unsigned char> sig, const XOnlyPubKey& pubkey) const
63 : : {
64 : 0 : CSHA256 hasher = m_salted_hasher_schnorr;
65 : 0 : hasher.Write(hash.begin(), 32).Write(pubkey.data(), pubkey.size()).Write(sig.data(), sig.size()).Finalize(entry.begin());
66 : 0 : }
67 : :
68 : : bool
69 : 0 : Get(const uint256& entry, const bool erase)
70 : : {
71 : 0 : std::shared_lock<std::shared_mutex> lock(cs_sigcache);
72 [ # # ]: 0 : return setValid.contains(entry, erase);
73 : 0 : }
74 : :
75 : 0 : void Set(const uint256& entry)
76 : : {
77 : 0 : std::unique_lock<std::shared_mutex> lock(cs_sigcache);
78 [ # # ]: 0 : setValid.insert(entry);
79 : 0 : }
80 : 1 : std::optional<std::pair<uint32_t, size_t>> setup_bytes(size_t n)
81 : : {
82 : 1 : 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 : 2 : static CSignatureCache signatureCache;
93 : : } // namespace
94 : :
95 : : // To be called once in AppInitMain/BasicTestingSetup to initialize the
96 : : // signatureCache.
97 : 1 : bool InitSignatureCache(size_t max_size_bytes)
98 : : {
99 : 1 : auto setup_results = signatureCache.setup_bytes(max_size_bytes);
100 [ - + ]: 1 : if (!setup_results) return false;
101 : :
102 : 3 : const auto [num_elems, approx_size_bytes] = *setup_results;
103 [ + - ][ + - ]: 1 : 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 : 1 : return true;
106 : 1 : }
107 : :
108 : 0 : bool CachingTransactionSignatureChecker::VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
109 : : {
110 : 0 : uint256 entry;
111 : 0 : signatureCache.ComputeEntryECDSA(entry, sighash, vchSig, pubkey);
112 [ # # ]: 0 : if (signatureCache.Get(entry, !store))
113 : 0 : return true;
114 [ # # ]: 0 : if (!TransactionSignatureChecker::VerifyECDSASignature(vchSig, pubkey, sighash))
115 : 0 : return false;
116 [ # # ]: 0 : if (store)
117 : 0 : signatureCache.Set(entry);
118 : 0 : return true;
119 : 0 : }
120 : :
121 : 0 : bool CachingTransactionSignatureChecker::VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const
122 : : {
123 : 0 : uint256 entry;
124 : 0 : signatureCache.ComputeEntrySchnorr(entry, sighash, sig, pubkey);
125 [ # # ]: 0 : if (signatureCache.Get(entry, !store)) return true;
126 [ # # ]: 0 : if (!TransactionSignatureChecker::VerifySchnorrSignature(sig, pubkey, sighash)) return false;
127 [ # # ]: 0 : if (store) signatureCache.Set(entry);
128 : 0 : return true;
129 : 0 : }
|