LCOV - code coverage report
Current view: top level - src/bls - bls.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 229 269 85.1 %
Date: 2026-06-25 07:23:51 Functions: 29 29 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2018-2025 The Dash Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <bls/bls.h>
       6             : 
       7             : #include <random.h>
       8             : 
       9             : #ifndef BUILD_BITCOIN_INTERNAL
      10             : #include <support/allocators/mt_pooled_secure.h>
      11             : #endif
      12             : 
      13             : #include <cassert>
      14             : #include <cstring>
      15             : 
      16             : namespace bls {
      17             :     std::atomic<bool> bls_legacy_scheme = std::atomic<bool>(true);
      18             : }
      19             : 
      20         218 : static const std::unique_ptr<bls::CoreMPL> pSchemeLegacy{std::make_unique<bls::LegacySchemeMPL>()};
      21         218 : static const std::unique_ptr<bls::CoreMPL> pScheme(std::make_unique<bls::BasicSchemeMPL>());
      22             : 
      23        1888 : static const std::unique_ptr<bls::CoreMPL>& Scheme(const bool fLegacy)
      24             : {
      25        1888 :     return fLegacy ? pSchemeLegacy : pScheme;
      26             : }
      27             : 
      28          80 : CBLSId::CBLSId(const uint256& nHash) : CBLSWrapper<CBLSIdImplicit, BLS_CURVE_ID_SIZE, CBLSId>()
      29          80 : {
      30          40 :     impl = nHash;
      31          40 :     fValid = true;
      32          40 :     cachedHash.SetNull();
      33          80 : }
      34             : 
      35           2 : void CBLSSecretKey::AggregateInsecure(const CBLSSecretKey& o)
      36             : {
      37           2 :     assert(IsValid() && o.IsValid());
      38           2 :     impl = bls::PrivateKey::Aggregate({impl, o.impl});
      39           2 :     cachedHash.SetNull();
      40           2 : }
      41             : 
      42           5 : CBLSSecretKey CBLSSecretKey::AggregateInsecure(Span<CBLSSecretKey> sks)
      43             : {
      44           5 :     if (sks.empty()) {
      45           2 :         return {};
      46             :     }
      47             : 
      48           3 :     std::vector<bls::PrivateKey> v;
      49           3 :     v.reserve(sks.size());
      50       20013 :     for (const auto& sk : sks) {
      51       20010 :         v.emplace_back(sk.impl);
      52             :     }
      53             : 
      54           3 :     CBLSSecretKey ret;
      55           3 :     ret.impl = bls::PrivateKey::Aggregate(v);
      56           3 :     ret.fValid = true;
      57           3 :     ret.cachedHash.SetNull();
      58           3 :     return ret;
      59           5 : }
      60             : 
      61             : #ifndef BUILD_BITCOIN_INTERNAL
      62       20237 : void CBLSSecretKey::MakeNewKey()
      63             : {
      64             :     unsigned char buf[SerSize];
      65       44879 :     while (true) {
      66       44879 :         GetStrongRandBytes({buf, sizeof(buf)});
      67             :         try {
      68       44879 :             impl = bls::PrivateKey::FromBytes(bls::Bytes(reinterpret_cast<const uint8_t*>(buf), SerSize));
      69       20237 :             if (impl == bls::PrivateKey()) {
      70           0 :                 continue;
      71             :             }
      72       20237 :             break;
      73       24642 :         } catch (...) {
      74       24642 :         }
      75             :     }
      76       20237 :     fValid = true;
      77       20237 :     cachedHash.SetNull();
      78       44879 : }
      79             : #endif
      80             : 
      81          40 : bool CBLSSecretKey::SecretKeyShare(Span<CBLSSecretKey> msk, const CBLSId& _id)
      82             : {
      83          40 :     fValid = false;
      84          40 :     cachedHash.SetNull();
      85             : 
      86          40 :     if (!_id.IsValid()) {
      87           0 :         return false;
      88             :     }
      89             : 
      90          40 :     std::vector<bls::PrivateKey> mskVec;
      91          40 :     mskVec.reserve(msk.size());
      92         640 :     for (const CBLSSecretKey& sk : msk) {
      93         600 :         if (!sk.IsValid()) {
      94           0 :             return false;
      95             :         }
      96         600 :         mskVec.emplace_back(sk.impl);
      97             :     }
      98             : 
      99             :     try {
     100          40 :         impl = bls::Threshold::PrivateKeyShare(mskVec, bls::Bytes(_id.impl.begin(), _id.impl.size()));
     101          40 :     } catch (...) {
     102           0 :         return false;
     103           0 :     }
     104             : 
     105          40 :     fValid = true;
     106          40 :     cachedHash.SetNull();
     107          40 :     return true;
     108          40 : }
     109             : 
     110       20246 : CBLSPublicKey CBLSSecretKey::GetPublicKey() const
     111             : {
     112       20246 :     if (!IsValid()) {
     113           0 :         return {};
     114             :     }
     115             : 
     116       20246 :     CBLSPublicKey pubKey;
     117       20246 :     pubKey.impl = impl.GetG1Element();
     118       20246 :     pubKey.fValid = true;
     119       20246 :     pubKey.cachedHash.SetNull();
     120       20246 :     return pubKey;
     121       20246 : }
     122             : 
     123         515 : CBLSSignature CBLSSecretKey::Sign(const uint256& hash, const bool specificLegacyScheme) const
     124             : {
     125         515 :     if (!IsValid()) {
     126           0 :         return {};
     127             :     }
     128             : 
     129         515 :     CBLSSignature sigRet;
     130             :     try {
     131         515 :         sigRet.impl = Scheme(specificLegacyScheme)->Sign(impl, bls::Bytes(hash.begin(), hash.size()));
     132         515 :         sigRet.fValid = true;
     133         515 :     } catch (...) {
     134           0 :         sigRet.fValid = false;
     135           0 :     }
     136             : 
     137         515 :     sigRet.cachedHash.SetNull();
     138             : 
     139         515 :     return sigRet;
     140         515 : }
     141             : 
     142           2 : void CBLSPublicKey::AggregateInsecure(const CBLSPublicKey& o)
     143             : {
     144           2 :     assert(IsValid() && o.IsValid());
     145             :     try {
     146           2 :         impl = Scheme(bls::bls_legacy_scheme.load())->Aggregate({impl, o.impl});
     147           2 :     } catch (...) {
     148           0 :         fValid = false;
     149           0 :     }
     150           2 :     cachedHash.SetNull();
     151           2 : }
     152             : 
     153         237 : CBLSPublicKey CBLSPublicKey::AggregateInsecure(Span<CBLSPublicKey> pks)
     154             : {
     155         237 :     if (pks.empty()) {
     156           2 :         return {};
     157             :     }
     158             : 
     159         235 :     std::vector<bls::G1Element> vecPublicKeys;
     160         235 :     vecPublicKeys.reserve(pks.size());
     161       20553 :     for (const auto& pk : pks) {
     162       20318 :         vecPublicKeys.emplace_back(pk.impl);
     163             :     }
     164             : 
     165         235 :     CBLSPublicKey ret;
     166             :     try {
     167         235 :         ret.impl = Scheme(bls::bls_legacy_scheme.load())->Aggregate(vecPublicKeys);
     168         235 :         ret.fValid = true;
     169         235 :     } catch (...) {
     170           0 :         ret.fValid = false;
     171           0 :     }
     172             : 
     173         235 :     ret.cachedHash.SetNull();
     174         235 :     return ret;
     175         237 : }
     176             : 
     177          40 : bool CBLSPublicKey::PublicKeyShare(Span<CBLSPublicKey> mpk, const CBLSId& _id)
     178             : {
     179          40 :     fValid = false;
     180          40 :     cachedHash.SetNull();
     181             : 
     182          40 :     if (!_id.IsValid()) {
     183           0 :         return false;
     184             :     }
     185             : 
     186          40 :     std::vector<bls::G1Element> mpkVec;
     187          40 :     mpkVec.reserve(mpk.size());
     188         640 :     for (const CBLSPublicKey& pk : mpk) {
     189         600 :         if (!pk.IsValid()) {
     190           0 :             return false;
     191             :         }
     192         600 :         mpkVec.emplace_back(pk.impl);
     193             :     }
     194             : 
     195             :     try {
     196          40 :         impl = bls::Threshold::PublicKeyShare(mpkVec, bls::Bytes(_id.impl.begin(), _id.impl.size()));
     197          40 :     } catch (...) {
     198           0 :         return false;
     199           0 :     }
     200             : 
     201          40 :     fValid = true;
     202          40 :     cachedHash.SetNull();
     203          40 :     return true;
     204          40 : }
     205             : 
     206           4 : bool CBLSPublicKey::DHKeyExchange(const CBLSSecretKey& sk, const CBLSPublicKey& pk)
     207             : {
     208           4 :     fValid = false;
     209           4 :     cachedHash.SetNull();
     210             : 
     211           4 :     if (!sk.IsValid() || !pk.IsValid()) {
     212           0 :         return false;
     213             :     }
     214           4 :     impl = sk.impl * pk.impl;
     215           4 :     fValid = true;
     216           4 :     cachedHash.SetNull();
     217           4 :     return true;
     218           4 : }
     219             : 
     220          38 : void CBLSSignature::AggregateInsecure(const CBLSSignature& o)
     221             : {
     222          38 :     assert(IsValid() && o.IsValid());
     223             :     try {
     224          38 :         impl = Scheme(bls::bls_legacy_scheme.load())->Aggregate({impl, o.impl});
     225          38 :     } catch (...) {
     226           0 :         fValid = false;
     227           0 :     }
     228          38 :     cachedHash.SetNull();
     229          38 : }
     230             : 
     231         258 : CBLSSignature CBLSSignature::AggregateInsecure(Span<CBLSSignature> sigs)
     232             : {
     233         258 :     if (sigs.empty()) {
     234           0 :         return {};
     235             :     }
     236             : 
     237         258 :     std::vector<bls::G2Element> v;
     238         258 :     v.reserve(sigs.size());
     239         878 :     for (const auto& pk : sigs) {
     240         620 :         v.emplace_back(pk.impl);
     241             :     }
     242             : 
     243         258 :     CBLSSignature ret;
     244             :     try {
     245         258 :         ret.impl = Scheme(bls::bls_legacy_scheme.load())->Aggregate(v);
     246         258 :         ret.fValid = true;
     247         258 :     } catch (...) {
     248           0 :         ret.fValid = false;
     249           0 :     }
     250             : 
     251         258 :     ret.cachedHash.SetNull();
     252         258 :     return ret;
     253         258 : }
     254             : 
     255           2 : CBLSSignature CBLSSignature::AggregateSecure(Span<CBLSSignature> sigs,
     256             :                                              Span<CBLSPublicKey> pks,
     257             :                                              const uint256& hash)
     258             : {
     259           2 :     if (sigs.size() != pks.size() || sigs.empty()) {
     260           0 :         return {};
     261             :     }
     262             : 
     263           2 :     std::vector<bls::G1Element> vecPublicKeys;
     264           2 :     vecPublicKeys.reserve(pks.size());
     265          22 :     for (const auto& pk : pks) {
     266          20 :         vecPublicKeys.push_back(pk.impl);
     267             :     }
     268             : 
     269           2 :     std::vector<bls::G2Element> vecSignatures;
     270           2 :     vecSignatures.reserve(pks.size());
     271          22 :     for (const auto& sig : sigs) {
     272          20 :         vecSignatures.push_back(sig.impl);
     273             :     }
     274             : 
     275           2 :     CBLSSignature ret;
     276             :     try {
     277           2 :         ret.impl = Scheme(bls::bls_legacy_scheme.load())->AggregateSecure(vecPublicKeys, vecSignatures, bls::Bytes(hash.begin(), hash.size()));
     278           2 :         ret.fValid = true;
     279           2 :     } catch (...) {
     280           0 :         ret.fValid = false;
     281           0 :     }
     282             : 
     283           2 :     ret.cachedHash.SetNull();
     284           2 :     return ret;
     285           2 : }
     286             : 
     287          38 : void CBLSSignature::SubInsecure(const CBLSSignature& o)
     288             : {
     289          38 :     assert(IsValid() && o.IsValid());
     290          38 :     impl = impl + o.impl.Negate();
     291          38 :     cachedHash.SetNull();
     292          38 : }
     293             : 
     294         466 : bool CBLSSignature::VerifyInsecure(const CBLSPublicKey& pubKey, const uint256& hash, const bool specificLegacyScheme) const
     295             : {
     296         466 :     if (!IsValid() || !pubKey.IsValid()) {
     297           4 :         return false;
     298             :     }
     299             : 
     300             :     try {
     301         462 :         return Scheme(specificLegacyScheme)->Verify(pubKey.impl, bls::Bytes(hash.begin(), hash.size()), impl);
     302           0 :     } catch (...) {
     303           0 :         return false;
     304           0 :     }
     305         466 : }
     306             : 
     307         464 : bool CBLSSignature::VerifyInsecure(const CBLSPublicKey& pubKey, const uint256& hash) const
     308             : {
     309         464 :     return VerifyInsecure(pubKey, hash, bls::bls_legacy_scheme.load());
     310             : }
     311             : 
     312         374 : bool CBLSSignature::VerifyInsecureAggregated(Span<CBLSPublicKey> pubKeys, Span<uint256> hashes) const
     313             : {
     314         374 :     if (!IsValid()) {
     315           0 :         return false;
     316             :     }
     317         374 :     assert(!pubKeys.empty() && !hashes.empty() && pubKeys.size() == hashes.size());
     318             : 
     319         374 :     std::vector<bls::G1Element> pubKeyVec;
     320         374 :     std::vector<bls::Bytes> hashes2;
     321         374 :     hashes2.reserve(hashes.size());
     322         374 :     pubKeyVec.reserve(pubKeys.size());
     323        2098 :     for (size_t i = 0; i < pubKeys.size(); i++) {
     324        1724 :         const auto& p = pubKeys[i];
     325        1724 :         if (!p.IsValid()) {
     326           0 :             return false;
     327             :         }
     328        1724 :         pubKeyVec.push_back(p.impl);
     329        1724 :         hashes2.emplace_back(hashes[i].begin(), hashes[i].size());
     330        1724 :     }
     331             : 
     332             :     try {
     333         374 :         return Scheme(bls::bls_legacy_scheme.load())->AggregateVerify(pubKeyVec, hashes2, impl);
     334           0 :     } catch (...) {
     335           0 :         return false;
     336           0 :     }
     337         374 : }
     338             : 
     339           2 : bool CBLSSignature::VerifySecureAggregated(Span<CBLSPublicKey> pks, const uint256& hash) const
     340             : {
     341           2 :     if (pks.empty()) {
     342           0 :         return false;
     343             :     }
     344             : 
     345           2 :     std::vector<bls::G1Element> vecPublicKeys;
     346           2 :     vecPublicKeys.reserve(pks.size());
     347          22 :     for (const auto& pk : pks) {
     348          20 :         vecPublicKeys.push_back(pk.impl);
     349             :     }
     350             : 
     351             :     try {
     352           2 :         return Scheme(bls::bls_legacy_scheme.load())->VerifySecure(vecPublicKeys, impl, bls::Bytes(hash.begin(), hash.size()));
     353           0 :     } catch (...) {
     354           0 :         return false;
     355           0 :     }
     356           2 : }
     357             : 
     358          40 : bool CBLSSignature::Recover(Span<CBLSSignature> sigs, Span<CBLSId> ids)
     359             : {
     360          40 :     fValid = false;
     361          40 :     cachedHash.SetNull();
     362             : 
     363          40 :     if (sigs.empty() || ids.empty() || sigs.size() != ids.size()) {
     364           2 :         return false;
     365             :     }
     366             : 
     367          38 :     std::vector<bls::G2Element> sigsVec;
     368          38 :     std::vector<bls::Bytes> idsVec;
     369          38 :     sigsVec.reserve(sigs.size());
     370          38 :     idsVec.reserve(sigs.size());
     371             : 
     372         418 :     for (size_t i = 0; i < sigs.size(); i++) {
     373         380 :         if (!sigs[i].IsValid() || !ids[i].IsValid()) {
     374           0 :             return false;
     375             :         }
     376         380 :         sigsVec.emplace_back(sigs[i].impl);
     377         380 :         idsVec.emplace_back(ids[i].impl.begin(), ids[i].impl.size());
     378         380 :     }
     379             : 
     380             :     try {
     381          38 :         impl = bls::Threshold::SignatureRecover(sigsVec, idsVec);
     382          38 :     } catch (...) {
     383           2 :         return false;
     384           2 :     }
     385             : 
     386          36 :     fValid = true;
     387          36 :     cachedHash.SetNull();
     388          36 :     return true;
     389          42 : }
     390             : 
     391             : #ifndef BUILD_BITCOIN_INTERNAL
     392             : 
     393             : static std::once_flag init_flag;
     394             : static mt_pooled_secure_allocator<uint8_t>* secure_allocator_instance;
     395           9 : static void create_secure_allocator()
     396             : {
     397             :     // make sure LockedPoolManager is initialized first (ensures destruction order)
     398           9 :     LockedPoolManager::Instance();
     399             : 
     400             :     // static variable in function scope ensures it's initialized when first accessed
     401             :     // and destroyed before LockedPoolManager
     402           9 :     static mt_pooled_secure_allocator<uint8_t> a(sizeof(bn_t) + sizeof(size_t));
     403           9 :     secure_allocator_instance = &a;
     404           9 : }
     405             : 
     406        1266 : static mt_pooled_secure_allocator<uint8_t>& get_secure_allocator()
     407             : {
     408        1266 :     std::call_once(init_flag, create_secure_allocator);
     409        1266 :     return *secure_allocator_instance;
     410             : }
     411             : 
     412         633 : static void* secure_allocate(size_t n)
     413             : {
     414         633 :     uint8_t* ptr = get_secure_allocator().allocate(n + sizeof(size_t));
     415         633 :     *reinterpret_cast<size_t*>(ptr) = n;
     416         633 :     return ptr + sizeof(size_t);
     417             : }
     418             : 
     419         633 : static void secure_free(void* p)
     420             : {
     421         633 :     if (p == nullptr) {
     422           0 :         return;
     423             :     }
     424             : 
     425         633 :     uint8_t* ptr = reinterpret_cast<uint8_t*>(p) - sizeof(size_t);
     426         633 :     size_t n = *reinterpret_cast<size_t*>(ptr);
     427         633 :     return get_secure_allocator().deallocate(ptr, n);
     428         633 : }
     429             : #endif
     430             : 
     431         627 : bool BLSInit()
     432             : {
     433             : #ifndef BUILD_BITCOIN_INTERNAL
     434         627 :     bls::BLS::SetSecureAllocator(secure_allocate, secure_free);
     435             : #endif
     436         627 :     return true;
     437             : }

Generated by: LCOV version 1.16