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 : 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 2 : 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 : }