LCOV - code coverage report
Current view: top level - src/bls - bls_worker.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 27 30 90.0 %
Date: 2025-02-23 09:33:43 Functions: 3 4 75.0 %

          Line data    Source code
       1             : // Copyright (c) 2018 The Dash Core developers
       2             : // Copyright (c) 2021 The PIVX Core developers
       3             : // Distributed under the MIT/X11 software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #ifndef PIVX_BLS_BLS_WORKER_H
       7             : #define PIVX_BLS_BLS_WORKER_H
       8             : 
       9             : #include "bls/bls_wrapper.h"
      10             : #include "ctpl_stl.h"
      11             : 
      12             : #include <future>
      13             : #include <mutex>
      14             : 
      15             : // Low level BLS/DKG stuff. All very compute intensive and optimized for parallelization
      16             : // The worker tries to parallelize as much as possible and utilizes a few properties of BLS aggregation to speed up things
      17             : // For example, public key vectors can be aggregated in parallel if they are split into batches and the batched aggregations are
      18             : // aggregated to a final public key. This utilizes that when aggregating keys (a+b+c+d) gives the same result as (a+b)+(c+d)
      19             : class CBLSWorker
      20             : {
      21             : public:
      22             :     typedef std::function<void(const CBLSSignature&)> SignDoneCallback;
      23             :     typedef std::function<void(bool)> SigVerifyDoneCallback;
      24             :     typedef std::function<bool()> CancelCond;
      25             : 
      26             : private:
      27             :     ctpl::thread_pool workerPool;
      28             : 
      29             :     static const int SIG_VERIFY_BATCH_SIZE = 8;
      30             :     struct SigVerifyJob {
      31             :         SigVerifyDoneCallback doneCallback;
      32             :         CancelCond cancelCond;
      33             :         CBLSSignature sig;
      34             :         CBLSPublicKey pubKey;
      35             :         uint256 msgHash;
      36           0 :         SigVerifyJob(SigVerifyDoneCallback&& _doneCallback, CancelCond&& _cancelCond, const CBLSSignature& _sig, const CBLSPublicKey& _pubKey, const uint256& _msgHash) :
      37             :             doneCallback(_doneCallback),
      38             :             cancelCond(_cancelCond),
      39             :             sig(_sig),
      40             :             pubKey(_pubKey),
      41           0 :             msgHash(_msgHash)
      42             :         {
      43           0 :         }
      44             :     };
      45             : 
      46             :     std::mutex sigVerifyMutex;
      47             :     int sigVerifyBatchesInProgress{0};
      48             :     std::vector<SigVerifyJob> sigVerifyQueue;
      49             : 
      50             : public:
      51             :     CBLSWorker();
      52             :     ~CBLSWorker();
      53             : 
      54             :     void Start();
      55             :     void Stop();
      56             : 
      57             :     bool GenerateContributions(int threshold, const BLSIdVector& ids, BLSVerificationVectorPtr& vvecRet, BLSSecretKeyVector& skShares);
      58             : 
      59             :     // The following functions are all used to aggregate verification (public key) vectors
      60             :     // Inputs are in the following form:
      61             :     //   [
      62             :     //     [a1, b1, c1, d1],
      63             :     //     [a2, b2, c2, d2],
      64             :     //     [a3, b3, c3, d3],
      65             :     //     [a4, b4, c4, d4],
      66             :     //   ]
      67             :     // The result is in the following form:
      68             :     //   [ a1+a2+a3+a4, b1+b2+b3+b4, c1+c2+c3+c4, d1+d2+d3+d4]
      69             :     // Multiple things can be parallelized here. For example, all 4 entries in the result vector can be calculated in parallel
      70             :     // Also, each individual vector can be split into multiple batches and aggregating the batches can also be paralellized.
      71             :     void AsyncBuildQuorumVerificationVector(const std::vector<BLSVerificationVectorPtr>& vvecs,
      72             :                                             size_t start, size_t count, bool parallel,
      73             :                                             std::function<void(const BLSVerificationVectorPtr&)> doneCallback);
      74             :     std::future<BLSVerificationVectorPtr> AsyncBuildQuorumVerificationVector(const std::vector<BLSVerificationVectorPtr>& vvecs,
      75             :                                                                              size_t start, size_t count, bool parallel);
      76             :     BLSVerificationVectorPtr BuildQuorumVerificationVector(const std::vector<BLSVerificationVectorPtr>& vvecs,
      77             :                                                            size_t start = 0, size_t count = 0, bool parallel = true);
      78             : 
      79             :     // The following functions are all used to aggregate single vectors
      80             :     // Inputs are in the following form:
      81             :     //   [a, b, c, d],
      82             :     // The result is simply a+b+c+d
      83             :     // Aggregation is paralellized by splitting up the input vector into multiple batches and then aggregating the individual batch results
      84             :     void AsyncAggregateSecretKeys(const BLSSecretKeyVector& secKeys,
      85             :                                   size_t start, size_t count, bool parallel,
      86             :                                   std::function<void(const CBLSSecretKey&)> doneCallback);
      87             :     std::future<CBLSSecretKey> AsyncAggregateSecretKeys(const BLSSecretKeyVector& secKeys,
      88             :                                                         size_t start, size_t count, bool parallel);
      89             :     CBLSSecretKey AggregateSecretKeys(const BLSSecretKeyVector& secKeys, size_t start = 0, size_t count = 0, bool parallel = true);
      90             : 
      91             :     void AsyncAggregatePublicKeys(const BLSPublicKeyVector& pubKeys,
      92             :                                   size_t start, size_t count, bool parallel,
      93             :                                   std::function<void(const CBLSPublicKey&)> doneCallback);
      94             :     std::future<CBLSPublicKey> AsyncAggregatePublicKeys(const BLSPublicKeyVector& pubKeys,
      95             :                                                         size_t start, size_t count, bool parallel);
      96             :     CBLSPublicKey AggregatePublicKeys(const BLSPublicKeyVector& pubKeys, size_t start = 0, size_t count = 0, bool parallel = true);
      97             : 
      98             :     void AsyncAggregateSigs(const BLSSignatureVector& sigs,
      99             :                             size_t start, size_t count, bool parallel,
     100             :                             std::function<void(const CBLSSignature&)> doneCallback);
     101             :     std::future<CBLSSignature> AsyncAggregateSigs(const BLSSignatureVector& sigs,
     102             :                                                         size_t start, size_t count, bool parallel);
     103             :     CBLSSignature AggregateSigs(const BLSSignatureVector& sigs, size_t start = 0, size_t count = 0, bool parallel = true);
     104             : 
     105             : 
     106             :     // Calculate public key share from public key vector and id. Not parallelized
     107             :     CBLSPublicKey BuildPubKeyShare(const BLSVerificationVectorPtr& vvec, const CBLSId& id);
     108             : 
     109             :     // The following functions verify multiple verification vectors and contributions for the same id
     110             :     // This is parallelized by performing batched verification. The verification vectors and the contributions of
     111             :     // a batch are aggregated (in parallel, see AsyncBuildQuorumVerificationVector and AsyncBuildSecretKeyShare). The
     112             :     // result per batch is a single aggregated verification vector and a single aggregated contribution, which are then
     113             :     // verified with VerifyContributionShare. If verification of the aggregated inputs is successful, the whole batch
     114             :     // is marked as valid. If the batch verification fails, the individual entries are verified in a non-aggregated manner
     115             :     void AsyncVerifyContributionShares(const CBLSId& forId, const std::vector<BLSVerificationVectorPtr>& vvecs, const BLSSecretKeyVector& skShares,
     116             :                                        bool parallel, bool aggregated, std::function<void(const std::vector<bool>&)> doneCallback);
     117             :     std::future<std::vector<bool> > AsyncVerifyContributionShares(const CBLSId& forId, const std::vector<BLSVerificationVectorPtr>& vvecs, const BLSSecretKeyVector& skShares,
     118             :                                                                   bool parallel, bool aggregated);
     119             :     std::vector<bool> VerifyContributionShares(const CBLSId& forId, const std::vector<BLSVerificationVectorPtr>& vvecs, const BLSSecretKeyVector& skShares,
     120             :                                                bool parallel = true, bool aggregated = true);
     121             : 
     122             :     std::future<bool> AsyncVerifyContributionShare(const CBLSId& forId, const BLSVerificationVectorPtr& vvec, const CBLSSecretKey& skContribution);
     123             : 
     124             :     // Non paralellized verification of a single contribution
     125             :     bool VerifyContributionShare(const CBLSId& forId, const BLSVerificationVectorPtr& vvec, const CBLSSecretKey& skContribution);
     126             : 
     127             :     // Simple verification of vectors. Checks x.IsValid() for every entry and checks for duplicate entries
     128             :     bool VerifyVerificationVector(const BLSVerificationVector& vvec, size_t start = 0, size_t count = 0);
     129             :     bool VerifyVerificationVectors(const std::vector<BLSVerificationVectorPtr>& vvecs, size_t start = 0, size_t count = 0);
     130             :     bool VerifySecretKeyVector(const BLSSecretKeyVector& secKeys, size_t start = 0, size_t count = 0);
     131             :     bool VerifySignatureVector(const BLSSignatureVector& sigs, size_t start = 0, size_t count = 0);
     132             : 
     133             :     // Internally batched signature signing and verification
     134             :     void AsyncSign(const CBLSSecretKey& secKey, const uint256& msgHash, SignDoneCallback doneCallback);
     135             :     std::future<CBLSSignature> AsyncSign(const CBLSSecretKey& secKey, const uint256& msgHash);
     136             :     void AsyncVerifySig(const CBLSSignature& sig, const CBLSPublicKey& pubKey, const uint256& msgHash, SigVerifyDoneCallback doneCallback, CancelCond cancelCond = [] { return false; });
     137             :     std::future<bool> AsyncVerifySig(const CBLSSignature& sig, const CBLSPublicKey& pubKey, const uint256& msgHash, CancelCond cancelCond = [] { return false; });
     138             :     bool IsAsyncVerifyInProgress();
     139             : 
     140             : private:
     141             :     void PushSigVerifyBatch();
     142             : };
     143             : 
     144             : // Builds and caches different things from CBLSWorker
     145             : // Cache keys are provided externally as computing hashes on BLS vectors is too expensive
     146             : // If multiple threads try to build the same thing at the same time, only one will actually build it
     147             : // and the other ones will wait for the result of the first caller
     148             : class CBLSWorkerCache
     149             : {
     150             : private:
     151             :     CBLSWorker& worker;
     152             : 
     153             :     std::mutex cacheCs;
     154             :     std::map<uint256, std::shared_future<BLSVerificationVectorPtr> > vvecCache;
     155             :     std::map<uint256, std::shared_future<CBLSSecretKey> > secretKeyShareCache;
     156             :     std::map<uint256, std::shared_future<CBLSPublicKey> > publicKeyShareCache;
     157             : 
     158             : public:
     159        1127 :     explicit CBLSWorkerCache(CBLSWorker& _worker) :
     160        1127 :         worker(_worker) {}
     161             : 
     162         215 :     BLSVerificationVectorPtr BuildQuorumVerificationVector(const uint256& cacheKey, const std::vector<BLSVerificationVectorPtr>& vvecs)
     163             :     {
     164         272 :         return GetOrBuild(cacheKey, vvecCache, [&]() {
     165          57 :             return worker.BuildQuorumVerificationVector(vvecs);
     166         215 :         });
     167             :     }
     168          56 :     CBLSSecretKey AggregateSecretKeys(const uint256& cacheKey, const BLSSecretKeyVector& skShares)
     169             :     {
     170         112 :         return GetOrBuild(cacheKey, secretKeyShareCache, [&]() {
     171          56 :             return worker.AggregateSecretKeys(skShares);
     172          56 :         });
     173             :     }
     174         929 :     CBLSPublicKey BuildPubKeyShare(const uint256& cacheKey, const BLSVerificationVectorPtr& vvec, const CBLSId& id)
     175             :     {
     176        1239 :         return GetOrBuild(cacheKey, publicKeyShareCache, [&]() {
     177         310 :             return worker.BuildPubKeyShare(vvec, id);
     178         929 :         });
     179             :     }
     180             : 
     181             : private:
     182             :     template <typename T, typename Builder>
     183        1200 :     T GetOrBuild(const uint256& cacheKey, std::map<uint256, std::shared_future<T> >& cache, Builder&& builder)
     184             :     {
     185        1200 :         cacheCs.lock();
     186        1200 :         auto it = cache.find(cacheKey);
     187        1200 :         if (it != cache.end()) {
     188        1554 :             auto f = it->second;
     189        1554 :             cacheCs.unlock();
     190         777 :             return f.get();
     191             :         }
     192             : 
     193         423 :         std::promise<T> p;
     194         423 :         cache.emplace(cacheKey, p.get_future());
     195         846 :         cacheCs.unlock();
     196             : 
     197         423 :         T v = builder();
     198         423 :         p.set_value(v);
     199         423 :         return v;
     200             :     }
     201             : };
     202             : 
     203             : #endif // PIVX_BLS_BLS_WORKER_H

Generated by: LCOV version 1.14