LCOV - code coverage report
Current view: top level - src/bls - bls_wrapper.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 141 150 94.0 %
Date: 2025-02-23 09:33:43 Functions: 58 61 95.1 %

          Line data    Source code
       1             : // Copyright (c) 2018 The Dash Core developers
       2             : // Copyright (c) 2021-2022 The PIVX 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             : #ifndef PIVX_BLS_BLS_WRAPPER_H
       7             : #define PIVX_BLS_BLS_WRAPPER_H
       8             : 
       9             : #include "hash.h"
      10             : #include "serialize.h"
      11             : #include "uint256.h"
      12             : #include "utilstrencodings.h"
      13             : 
      14             : // chiabls uses relic, which may define DEBUG and ERROR, which leads to many warnings in some build setups
      15             : #undef ERROR
      16             : #undef DEBUG
      17             : #include <bls.hpp>
      18             : #include <privatekey.hpp>
      19             : #include <elements.hpp>
      20             : #include <schemes.hpp>
      21             : #include <threshold.hpp>
      22             : #undef DOUBLE
      23             : 
      24             : #include <array>
      25             : #include <mutex>
      26             : #include <unistd.h>
      27             : 
      28             : // reversed BLS12-381
      29             : #define BLS_CURVE_ID_SIZE 32
      30             : #define BLS_CURVE_SECKEY_SIZE 32
      31             : #define BLS_CURVE_PUBKEY_SIZE 48
      32             : #define BLS_CURVE_SIG_SIZE 96
      33             : 
      34             : class CBLSSignature;
      35             : class CBLSPublicKey;
      36             : 
      37             : template <typename ImplType, size_t _SerSize, typename C>
      38       11963 : class CBLSWrapper
      39             : {
      40             :     friend class CBLSSecretKey;
      41             :     friend class CBLSPublicKey;
      42             :     friend class CBLSSignature;
      43             : 
      44             : protected:
      45             :     ImplType impl;
      46             :     bool fValid{false};
      47             :     mutable uint256 cachedHash;
      48             : 
      49             :     inline constexpr size_t GetSerSize() const { return SerSize; }
      50             : 
      51             : public:
      52             :     static const size_t SerSize = _SerSize;
      53             : 
      54      128243 :     CBLSWrapper()
      55      234077 :     {
      56             :     }
      57         690 :     CBLSWrapper(const std::vector<unsigned char>& vecBytes) : CBLSWrapper<ImplType, _SerSize, C>()
      58             :     {
      59         690 :         SetByteVector(vecBytes);
      60         690 :     }
      61             : 
      62       12552 :     CBLSWrapper(const CBLSWrapper& ref) = default;
      63             :     CBLSWrapper& operator=(const CBLSWrapper& ref) = default;
      64       14074 :     CBLSWrapper(CBLSWrapper&& ref)
      65       15710 :     {
      66       14074 :         std::swap(impl, ref.impl);
      67       14074 :         std::swap(fValid, ref.fValid);
      68       14074 :         std::swap(cachedHash, ref.cachedHash);
      69       14074 :     }
      70       50925 :     CBLSWrapper& operator=(CBLSWrapper&& ref)
      71             :     {
      72       50925 :         std::swap(impl, ref.impl);
      73       50925 :         std::swap(fValid, ref.fValid);
      74       50925 :         std::swap(cachedHash, ref.cachedHash);
      75       50925 :         return *this;
      76             :     }
      77             : 
      78        4954 :     bool operator==(const C& r) const
      79             :     {
      80        4834 :         return fValid == r.fValid && impl == r.impl;
      81             :     }
      82         658 :     bool operator!=(const C& r) const
      83             :     {
      84         688 :         return !((*this) == r);
      85             :     }
      86             : 
      87      239681 :     bool IsValid() const
      88             :     {
      89      216127 :         return fValid;
      90             :     }
      91             : 
      92       73095 :     void Reset()
      93             :     {
      94      122631 :         *((C*)this) = C();
      95       73095 :     }
      96             : 
      97       44321 :     void SetByteVector(const std::vector<uint8_t>& vecBytes)
      98             :     {
      99       44321 :         if (vecBytes.size() != SerSize) {
     100           3 :             Reset();
     101           3 :             return;
     102             :         }
     103      648317 :         if (std::all_of(vecBytes.begin(), vecBytes.end(), [](uint8_t c) { return c == 0; })) {
     104       29459 :             Reset();
     105             :         } else {
     106             :             try {
     107       14859 :                 impl = ImplType::FromBytes(bls::Bytes(vecBytes));
     108       14853 :                 fValid = true;
     109          12 :             } catch (...) {
     110           6 :                 Reset();
     111             :             }
     112             :         }
     113       44321 :         cachedHash.SetNull();
     114             :     }
     115             : 
     116       74196 :     std::vector<uint8_t> ToByteVector() const
     117             :     {
     118       74196 :         if (!fValid) {
     119       30864 :             return std::vector<uint8_t>(SerSize, 0);
     120             :         }
     121       43491 :         return impl.Serialize();
     122             :     }
     123             : 
     124        7539 :     const uint256& GetHash() const
     125             :     {
     126       15078 :         if (cachedHash.IsNull()) {
     127        6875 :             cachedHash = ::SerializeHash(*this);
     128             :         }
     129        7539 :         return cachedHash;
     130             :     }
     131             : 
     132             : public:
     133             :     template <typename Stream>
     134       22536 :     inline void Serialize(Stream& s) const
     135             :     {
     136       37357 :         s.write((const char*)ToByteVector().data(), SerSize);
     137       22536 :     }
     138             : 
     139             :     template <typename Stream>
     140       41252 :     inline void Unserialize(Stream& s, bool checkMalleable = true)
     141             :     {
     142       41252 :         std::vector<uint8_t> vecBytes(SerSize, 0);
     143       41252 :         s.read((char*)vecBytes.data(), SerSize);
     144       41252 :         SetByteVector(vecBytes);
     145             : 
     146       41252 :         if (checkMalleable && !CheckMalleable(vecBytes)) {
     147           0 :             throw std::ios_base::failure("malleable BLS object");
     148             :         }
     149       41252 :     }
     150             : 
     151       43623 :     inline bool CheckMalleable(const std::vector<uint8_t>& vecBytes) const
     152             :     {
     153       87246 :         if (memcmp(vecBytes.data(), ToByteVector().data(), SerSize)) {
     154             :             // TODO not sure if this is actually possible with the BLS libs. I'm assuming here that somewhere deep inside
     155             :             // these libs masking might happen, so that 2 different binary representations could result in the same object
     156             :             // representation
     157           0 :             return false;
     158             :         }
     159             :         return true;
     160             :     }
     161             : 
     162             :     // hex-encoding. Used only for signatures.
     163             :     // For secret/public keys use bls::EncodeSecret/EncodePublic
     164         136 :     inline std::string ToString() const
     165             :     {
     166         136 :         std::vector<uint8_t> buf = ToByteVector();
     167         272 :         return HexStr(buf);
     168             :     }
     169             : };
     170             : 
     171             : struct CBLSIdImplicit : public uint256
     172             : {
     173        7307 :     CBLSIdImplicit() {}
     174        2092 :     CBLSIdImplicit(const uint256& id)
     175        2092 :     {
     176        2092 :         memcpy(begin(), id.begin(), sizeof(uint256));
     177             :     }
     178             :     static CBLSIdImplicit FromBytes(const uint8_t* buffer)
     179             :     {
     180             :         CBLSIdImplicit instance;
     181             :         memcpy(instance.begin(), buffer, sizeof(CBLSIdImplicit));
     182             :         return instance;
     183             :     }
     184         159 :     std::vector<uint8_t> Serialize() const
     185             :     {
     186         159 :         return {begin(), end()};
     187             :     }
     188             : };
     189             : 
     190         778 : class CBLSId : public CBLSWrapper<CBLSIdImplicit, BLS_CURVE_ID_SIZE, CBLSId>
     191             : {
     192             : public:
     193             :     using CBLSWrapper::operator=;
     194             :     using CBLSWrapper::operator==;
     195             :     using CBLSWrapper::operator!=;
     196             : 
     197        1991 :     CBLSId() {}
     198             :     CBLSId(const uint256& nHash);
     199             : };
     200             : 
     201       39634 : class CBLSSecretKey : public CBLSWrapper<bls::PrivateKey, BLS_CURVE_SECKEY_SIZE, CBLSSecretKey>
     202             : {
     203             : public:
     204             :     using CBLSWrapper::operator=;
     205             :     using CBLSWrapper::operator==;
     206             :     using CBLSWrapper::operator!=;
     207             : 
     208             :     void AggregateInsecure(const CBLSSecretKey& o);
     209             :     static CBLSSecretKey AggregateInsecure(const std::vector<CBLSSecretKey>& sks);
     210             : 
     211             : #ifndef BUILD_BITCOIN_INTERNAL
     212             :     void MakeNewKey();
     213             : #endif
     214             :     bool SecretKeyShare(const std::vector<CBLSSecretKey>& msk, const CBLSId& id);
     215             : 
     216             :     CBLSPublicKey GetPublicKey() const;
     217             :     CBLSSignature Sign(const uint256& hash) const;
     218             :     bool Recover(const std::vector<CBLSSecretKey>& keys, const std::vector<CBLSId>& ids);
     219             : };
     220             : 
     221       54080 : class CBLSPublicKey : public CBLSWrapper<bls::G1Element, BLS_CURVE_PUBKEY_SIZE, CBLSPublicKey>
     222             : {
     223             :     friend class CBLSSecretKey;
     224             :     friend class CBLSSignature;
     225             : 
     226             : public:
     227             :     using CBLSWrapper::operator=;
     228             :     using CBLSWrapper::operator==;
     229             :     using CBLSWrapper::operator!=;
     230             :     using CBLSWrapper::CBLSWrapper;
     231             : 
     232      229734 :     CBLSPublicKey() {}
     233             : 
     234             :     void AggregateInsecure(const CBLSPublicKey& o);
     235             :     static CBLSPublicKey AggregateInsecure(const std::vector<CBLSPublicKey>& pks);
     236             : 
     237             :     bool PublicKeyShare(const std::vector<CBLSPublicKey>& mpk, const CBLSId& id);
     238             :     bool DHKeyExchange(const CBLSSecretKey& sk, const CBLSPublicKey& pk);
     239             : 
     240             : };
     241             : 
     242             : class CBLSSignature : public CBLSWrapper<bls::G2Element, BLS_CURVE_SIG_SIZE, CBLSSignature>
     243             : {
     244             :     friend class CBLSSecretKey;
     245             : 
     246             : public:
     247             :     using CBLSWrapper::operator==;
     248             :     using CBLSWrapper::operator!=;
     249         690 :     using CBLSWrapper::CBLSWrapper;
     250             : 
     251       90739 :     CBLSSignature() {}
     252             :     CBLSSignature(const CBLSSignature&) = default;
     253             :     CBLSSignature& operator=(const CBLSSignature&) = default;
     254             : 
     255             :     void AggregateInsecure(const CBLSSignature& o);
     256             :     static CBLSSignature AggregateInsecure(const std::vector<CBLSSignature>& sigs);
     257             :     static CBLSSignature AggregateSecure(const std::vector<CBLSSignature>& sigs, const std::vector<CBLSPublicKey>& pks, const uint256& hash);
     258             : 
     259             :     void SubInsecure(const CBLSSignature& o);
     260             : 
     261             :     bool VerifyInsecure(const CBLSPublicKey& pubKey, const uint256& hash) const;
     262             :     bool VerifyInsecureAggregated(const std::vector<CBLSPublicKey>& pubKeys, const std::vector<uint256>& hashes) const;
     263             : 
     264             :     bool VerifySecureAggregated(const std::vector<CBLSPublicKey>& pks, const uint256& hash) const;
     265             : 
     266             :     bool Recover(const std::vector<CBLSSignature>& sigs, const std::vector<CBLSId>& ids);
     267             : };
     268             : 
     269             : #ifndef BUILD_BITCOIN_INTERNAL
     270             : 
     271             : template<typename BLSObject>
     272       29719 : class CBLSLazyWrapper
     273             : {
     274             : private:
     275             :     mutable std::mutex mutex;
     276             : 
     277             :     mutable std::vector<uint8_t> vecBytes;
     278             :     mutable bool bufValid{false};
     279             : 
     280             :     mutable BLSObject obj;
     281             :     mutable bool objInitialized{false};
     282             : 
     283             :     mutable uint256 hash;
     284             : 
     285             : public:
     286       36322 :     CBLSLazyWrapper() : vecBytes(BLSObject::SerSize, 0)
     287             :     {
     288             :         // the all-zero buf is considered a valid buf, but the resulting object will return false for IsValid
     289       18161 :         bufValid = true;
     290       18161 :     }
     291             : 
     292       67684 :     CBLSLazyWrapper(const CBLSLazyWrapper& r)
     293      135368 :     {
     294       67684 :         *this = r;
     295       67684 :     }
     296             : 
     297       68774 :     CBLSLazyWrapper& operator=(const CBLSLazyWrapper& r)
     298             :     {
     299       68774 :         std::unique_lock<std::mutex> l(r.mutex);
     300       68774 :         bufValid = r.bufValid;
     301       68774 :         if (r.bufValid) {
     302       64408 :             vecBytes = r.vecBytes;
     303             :         } else {
     304        4366 :             std::fill(vecBytes.begin(), vecBytes.end(), 0);
     305             :         }
     306       68774 :         objInitialized = r.objInitialized;
     307       68774 :         if (r.objInitialized) {
     308       25624 :             obj = r.obj;
     309             :         } else {
     310       43150 :             obj.Reset();
     311             :         }
     312       68774 :         hash = r.hash;
     313      137548 :         return *this;
     314             :     }
     315             : 
     316             :     template<typename Stream>
     317       12403 :     inline void Serialize(Stream& s) const
     318             :     {
     319       12403 :         std::unique_lock<std::mutex> l(mutex);
     320       12403 :         if (!objInitialized && !bufValid) {
     321           0 :             throw std::ios_base::failure("obj and buf not initialized");
     322             :         }
     323       12403 :         if (!bufValid) {
     324        2733 :             vecBytes = obj.ToByteVector();
     325        1834 :             bufValid = true;
     326        1834 :             hash.SetNull();
     327             :         }
     328       18738 :         s.write((const char*)vecBytes.data(), vecBytes.size());
     329       12403 :     }
     330             : 
     331             :     template<typename Stream>
     332        4376 :     inline void Unserialize(Stream& s)
     333             :     {
     334        4376 :         std::unique_lock<std::mutex> l(mutex);
     335        4376 :         s.read((char*)vecBytes.data(), BLSObject::SerSize);
     336        4376 :         bufValid = true;
     337        4376 :         objInitialized = false;
     338        4376 :         hash.SetNull();
     339        4376 :     }
     340             : 
     341        1974 :     void Set(const BLSObject& _obj)
     342             :     {
     343        1974 :         std::unique_lock<std::mutex> l(mutex);
     344        1974 :         bufValid = false;
     345        1974 :         objInitialized = true;
     346        1974 :         obj = _obj;
     347        1974 :         hash.SetNull();
     348        1974 :     }
     349             : 
     350       11727 :     const BLSObject& Get() const
     351             :     {
     352       23454 :         std::unique_lock<std::mutex> l(mutex);
     353       11821 :         static BLSObject invalidObj;
     354       11727 :         if (!bufValid && !objInitialized) {
     355             :             return invalidObj;
     356             :         }
     357       11727 :         if (!objInitialized) {
     358        2371 :             obj.SetByteVector(vecBytes);
     359        2371 :             if (!obj.CheckMalleable(vecBytes)) {
     360           0 :                 bufValid = false;
     361           0 :                 objInitialized = false;
     362           0 :                 obj = invalidObj;
     363             :             } else {
     364        2371 :                 objInitialized = true;
     365             :             }
     366             :         }
     367       11727 :         return obj;
     368             :     }
     369             : 
     370       36963 :     bool operator==(const CBLSLazyWrapper& r) const
     371             :     {
     372       36963 :         if (bufValid && r.bufValid) {
     373       36744 :             return vecBytes == r.vecBytes;
     374             :         }
     375         219 :         if (objInitialized && r.objInitialized) {
     376         199 :             return obj == r.obj;
     377             :         }
     378          20 :         return Get() == r.Get();
     379             :     }
     380             : 
     381       14989 :     bool operator!=(const CBLSLazyWrapper& r) const
     382             :     {
     383       14989 :         return !(*this == r);
     384             :     }
     385             : 
     386         114 :     uint256 GetHash() const
     387             :     {
     388         114 :         std::unique_lock<std::mutex> l(mutex);
     389         114 :         if (!bufValid) {
     390           0 :             vecBytes = obj.ToByteVector();
     391           0 :             bufValid = true;
     392           0 :             hash.SetNull();
     393             :         }
     394         228 :         if (hash.IsNull()) {
     395         112 :             CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
     396         224 :             ss.write((const char*)vecBytes.data(), vecBytes.size());
     397         112 :             hash = ss.GetHash();
     398             :         }
     399         228 :         return hash;
     400             :     }
     401             : };
     402             : typedef CBLSLazyWrapper<CBLSSignature> CBLSLazySignature;
     403             : typedef CBLSLazyWrapper<CBLSPublicKey> CBLSLazyPublicKey;
     404             : typedef CBLSLazyWrapper<CBLSSecretKey> CBLSLazySecretKey;
     405             : 
     406             : #endif
     407             : 
     408             : typedef std::vector<CBLSId> BLSIdVector;
     409             : typedef std::vector<CBLSPublicKey> BLSVerificationVector;
     410             : typedef std::vector<CBLSPublicKey> BLSPublicKeyVector;
     411             : typedef std::vector<CBLSSecretKey> BLSSecretKeyVector;
     412             : typedef std::vector<CBLSSignature> BLSSignatureVector;
     413             : 
     414             : typedef std::shared_ptr<BLSIdVector> BLSIdVectorPtr;
     415             : typedef std::shared_ptr<BLSVerificationVector> BLSVerificationVectorPtr;
     416             : typedef std::shared_ptr<BLSPublicKeyVector> BLSPublicKeyVectorPtr;
     417             : typedef std::shared_ptr<BLSSecretKeyVector> BLSSecretKeyVectorPtr;
     418             : typedef std::shared_ptr<BLSSignatureVector> BLSSignatureVectorPtr;
     419             : 
     420             : bool BLSInit();
     421             : 
     422             : #endif // PIVX_BLS_BLS_WRAPPER_H

Generated by: LCOV version 1.14