LCOV - code coverage report
Current view: top level - src/script - sigcache.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 18 53 34.0 %
Date: 2023-10-05 12:38:51 Functions: 6 12 50.0 %
Branches: 11 38 28.9 %

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

Generated by: LCOV version 1.14