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 3516 : static const std::unique_ptr<bls::CoreMPL> pSchemeLegacy{std::make_unique<bls::LegacySchemeMPL>()};
21 3516 : static const std::unique_ptr<bls::CoreMPL> pScheme(std::make_unique<bls::BasicSchemeMPL>());
22 :
23 245135 : static const std::unique_ptr<bls::CoreMPL>& Scheme(const bool fLegacy)
24 : {
25 245135 : return fLegacy ? pSchemeLegacy : pScheme;
26 : }
27 :
28 160114 : CBLSId::CBLSId(const uint256& nHash) : CBLSWrapper<CBLSIdImplicit, BLS_CURVE_ID_SIZE, CBLSId>()
29 160114 : {
30 80057 : impl = nHash;
31 80057 : fValid = true;
32 80057 : cachedHash.SetNull();
33 160114 : }
34 :
35 16967 : void CBLSSecretKey::AggregateInsecure(const CBLSSecretKey& o)
36 : {
37 16967 : assert(IsValid() && o.IsValid());
38 16967 : impl = bls::PrivateKey::Aggregate({impl, o.impl});
39 16967 : cachedHash.SetNull();
40 16967 : }
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 30470 : void CBLSSecretKey::MakeNewKey()
63 : {
64 : unsigned char buf[SerSize];
65 67446 : while (true) {
66 67446 : GetStrongRandBytes({buf, sizeof(buf)});
67 : try {
68 67446 : impl = bls::PrivateKey::FromBytes(bls::Bytes(reinterpret_cast<const uint8_t*>(buf), SerSize));
69 30470 : if (impl == bls::PrivateKey()) {
70 0 : continue;
71 : }
72 30470 : break;
73 36976 : } catch (...) {
74 36976 : }
75 : }
76 30470 : fValid = true;
77 30470 : cachedHash.SetNull();
78 67446 : }
79 : #endif
80 :
81 9832 : bool CBLSSecretKey::SecretKeyShare(Span<CBLSSecretKey> msk, const CBLSId& _id)
82 : {
83 9832 : fValid = false;
84 9832 : cachedHash.SetNull();
85 :
86 9832 : if (!_id.IsValid()) {
87 0 : return false;
88 : }
89 :
90 9832 : std::vector<bls::PrivateKey> mskVec;
91 9832 : mskVec.reserve(msk.size());
92 38051 : for (const CBLSSecretKey& sk : msk) {
93 28225 : if (!sk.IsValid()) {
94 0 : return false;
95 : }
96 28222 : mskVec.emplace_back(sk.impl);
97 : }
98 :
99 : try {
100 9826 : impl = bls::Threshold::PrivateKeyShare(mskVec, bls::Bytes(_id.impl.begin(), _id.impl.size()));
101 9826 : } catch (...) {
102 0 : return false;
103 0 : }
104 :
105 9826 : fValid = true;
106 9826 : cachedHash.SetNull();
107 9826 : return true;
108 9838 : }
109 :
110 37962 : CBLSPublicKey CBLSSecretKey::GetPublicKey() const
111 : {
112 37962 : if (!IsValid()) {
113 0 : return {};
114 : }
115 :
116 37962 : CBLSPublicKey pubKey;
117 37962 : pubKey.impl = impl.GetG1Element();
118 37962 : pubKey.fValid = true;
119 37962 : pubKey.cachedHash.SetNull();
120 37962 : return pubKey;
121 37962 : }
122 :
123 31582 : CBLSSignature CBLSSecretKey::Sign(const uint256& hash, const bool specificLegacyScheme) const
124 : {
125 31582 : if (!IsValid()) {
126 0 : return {};
127 : }
128 :
129 31582 : CBLSSignature sigRet;
130 : try {
131 31582 : sigRet.impl = Scheme(specificLegacyScheme)->Sign(impl, bls::Bytes(hash.begin(), hash.size()));
132 31156 : sigRet.fValid = true;
133 31156 : } catch (...) {
134 0 : sigRet.fValid = false;
135 0 : }
136 :
137 31156 : sigRet.cachedHash.SetNull();
138 :
139 31156 : return sigRet;
140 32098 : }
141 :
142 47647 : void CBLSPublicKey::AggregateInsecure(const CBLSPublicKey& o)
143 : {
144 47647 : assert(IsValid() && o.IsValid());
145 : try {
146 47647 : impl = Scheme(bls::bls_legacy_scheme.load())->Aggregate({impl, o.impl});
147 47647 : } catch (...) {
148 0 : fValid = false;
149 0 : }
150 47647 : cachedHash.SetNull();
151 48405 : }
152 :
153 38359 : CBLSPublicKey CBLSPublicKey::AggregateInsecure(Span<CBLSPublicKey> pks)
154 : {
155 38359 : if (pks.empty()) {
156 2 : return {};
157 : }
158 :
159 38357 : std::vector<bls::G1Element> vecPublicKeys;
160 38357 : vecPublicKeys.reserve(pks.size());
161 100269 : for (const auto& pk : pks) {
162 61916 : vecPublicKeys.emplace_back(pk.impl);
163 : }
164 :
165 38353 : CBLSPublicKey ret;
166 : try {
167 38354 : ret.impl = Scheme(bls::bls_legacy_scheme.load())->Aggregate(vecPublicKeys);
168 38354 : ret.fValid = true;
169 38354 : } catch (...) {
170 0 : ret.fValid = false;
171 0 : }
172 :
173 38354 : ret.cachedHash.SetNull();
174 38353 : return ret;
175 38363 : }
176 :
177 20782 : bool CBLSPublicKey::PublicKeyShare(Span<CBLSPublicKey> mpk, const CBLSId& _id)
178 : {
179 20782 : fValid = false;
180 20782 : cachedHash.SetNull();
181 :
182 20782 : if (!_id.IsValid()) {
183 0 : return false;
184 : }
185 :
186 20782 : std::vector<bls::G1Element> mpkVec;
187 20782 : mpkVec.reserve(mpk.size());
188 78964 : for (const CBLSPublicKey& pk : mpk) {
189 58188 : if (!pk.IsValid()) {
190 0 : return false;
191 : }
192 58193 : mpkVec.emplace_back(pk.impl);
193 : }
194 :
195 : try {
196 20776 : impl = bls::Threshold::PublicKeyShare(mpkVec, bls::Bytes(_id.impl.begin(), _id.impl.size()));
197 20776 : } catch (...) {
198 0 : return false;
199 0 : }
200 :
201 20776 : fValid = true;
202 20776 : cachedHash.SetNull();
203 20776 : return true;
204 20802 : }
205 :
206 18859 : bool CBLSPublicKey::DHKeyExchange(const CBLSSecretKey& sk, const CBLSPublicKey& pk)
207 : {
208 18859 : fValid = false;
209 18859 : cachedHash.SetNull();
210 :
211 18859 : if (!sk.IsValid() || !pk.IsValid()) {
212 0 : return false;
213 : }
214 18859 : impl = sk.impl * pk.impl;
215 18859 : fValid = true;
216 18859 : cachedHash.SetNull();
217 18859 : return true;
218 18859 : }
219 :
220 3996 : void CBLSSignature::AggregateInsecure(const CBLSSignature& o)
221 : {
222 3996 : assert(IsValid() && o.IsValid());
223 : try {
224 3996 : impl = Scheme(bls::bls_legacy_scheme.load())->Aggregate({impl, o.impl});
225 3996 : } catch (...) {
226 0 : fValid = false;
227 0 : }
228 3996 : cachedHash.SetNull();
229 4002 : }
230 :
231 24943 : CBLSSignature CBLSSignature::AggregateInsecure(Span<CBLSSignature> sigs)
232 : {
233 24943 : if (sigs.empty()) {
234 0 : return {};
235 : }
236 :
237 24943 : std::vector<bls::G2Element> v;
238 24943 : v.reserve(sigs.size());
239 67156 : for (const auto& pk : sigs) {
240 42216 : v.emplace_back(pk.impl);
241 : }
242 :
243 24940 : CBLSSignature ret;
244 : try {
245 24942 : ret.impl = Scheme(bls::bls_legacy_scheme.load())->Aggregate(v);
246 24940 : ret.fValid = true;
247 24940 : } catch (...) {
248 0 : ret.fValid = false;
249 0 : }
250 :
251 24940 : ret.cachedHash.SetNull();
252 24941 : return ret;
253 24949 : }
254 :
255 1857 : CBLSSignature CBLSSignature::AggregateSecure(Span<CBLSSignature> sigs,
256 : Span<CBLSPublicKey> pks,
257 : const uint256& hash)
258 : {
259 1857 : if (sigs.size() != pks.size() || sigs.empty()) {
260 8 : return {};
261 : }
262 :
263 1857 : std::vector<bls::G1Element> vecPublicKeys;
264 1857 : vecPublicKeys.reserve(pks.size());
265 8771 : for (const auto& pk : pks) {
266 6918 : vecPublicKeys.push_back(pk.impl);
267 : }
268 :
269 1857 : std::vector<bls::G2Element> vecSignatures;
270 1857 : vecSignatures.reserve(pks.size());
271 8771 : for (const auto& sig : sigs) {
272 6919 : vecSignatures.push_back(sig.impl);
273 : }
274 :
275 1852 : CBLSSignature ret;
276 : try {
277 1855 : ret.impl = Scheme(bls::bls_legacy_scheme.load())->AggregateSecure(vecPublicKeys, vecSignatures, bls::Bytes(hash.begin(), hash.size()));
278 1853 : ret.fValid = true;
279 1853 : } catch (...) {
280 0 : ret.fValid = false;
281 0 : }
282 :
283 1853 : ret.cachedHash.SetNull();
284 1853 : return ret;
285 1877 : }
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 51104 : bool CBLSSignature::VerifyInsecure(const CBLSPublicKey& pubKey, const uint256& hash, const bool specificLegacyScheme) const
295 : {
296 51104 : if (!IsValid() || !pubKey.IsValid()) {
297 7 : return false;
298 : }
299 :
300 : try {
301 51097 : return Scheme(specificLegacyScheme)->Verify(pubKey.impl, bls::Bytes(hash.begin(), hash.size()), impl);
302 0 : } catch (...) {
303 0 : return false;
304 0 : }
305 51108 : }
306 :
307 45393 : bool CBLSSignature::VerifyInsecure(const CBLSPublicKey& pubKey, const uint256& hash) const
308 : {
309 45393 : return VerifyInsecure(pubKey, hash, bls::bls_legacy_scheme.load());
310 : }
311 :
312 37301 : bool CBLSSignature::VerifyInsecureAggregated(Span<CBLSPublicKey> pubKeys, Span<uint256> hashes) const
313 : {
314 37301 : if (!IsValid()) {
315 0 : return false;
316 : }
317 37301 : assert(!pubKeys.empty() && !hashes.empty() && pubKeys.size() == hashes.size());
318 :
319 37301 : std::vector<bls::G1Element> pubKeyVec;
320 37301 : std::vector<bls::Bytes> hashes2;
321 37301 : hashes2.reserve(hashes.size());
322 37285 : pubKeyVec.reserve(pubKeys.size());
323 91761 : for (size_t i = 0; i < pubKeys.size(); i++) {
324 54472 : const auto& p = pubKeys[i];
325 54472 : if (!p.IsValid()) {
326 0 : return false;
327 : }
328 54473 : pubKeyVec.push_back(p.impl);
329 54478 : hashes2.emplace_back(hashes[i].begin(), hashes[i].size());
330 54475 : }
331 :
332 : try {
333 37289 : return Scheme(bls::bls_legacy_scheme.load())->AggregateVerify(pubKeyVec, hashes2, impl);
334 0 : } catch (...) {
335 0 : return false;
336 0 : }
337 37331 : }
338 :
339 9097 : bool CBLSSignature::VerifySecureAggregated(Span<CBLSPublicKey> pks, const uint256& hash) const
340 : {
341 9097 : if (pks.empty()) {
342 0 : return false;
343 : }
344 :
345 9097 : std::vector<bls::G1Element> vecPublicKeys;
346 9097 : vecPublicKeys.reserve(pks.size());
347 42572 : for (const auto& pk : pks) {
348 33475 : vecPublicKeys.push_back(pk.impl);
349 : }
350 :
351 : try {
352 9097 : 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 9101 : }
357 :
358 10436 : bool CBLSSignature::Recover(Span<CBLSSignature> sigs, Span<CBLSId> ids)
359 : {
360 10436 : fValid = false;
361 10436 : cachedHash.SetNull();
362 :
363 10436 : if (sigs.empty() || ids.empty() || sigs.size() != ids.size()) {
364 10 : return false;
365 : }
366 :
367 10434 : std::vector<bls::G2Element> sigsVec;
368 10434 : std::vector<bls::Bytes> idsVec;
369 10434 : sigsVec.reserve(sigs.size());
370 10430 : idsVec.reserve(sigs.size());
371 :
372 40120 : for (size_t i = 0; i < sigs.size(); i++) {
373 29695 : if (!sigs[i].IsValid() || !ids[i].IsValid()) {
374 5 : return false;
375 : }
376 29689 : sigsVec.emplace_back(sigs[i].impl);
377 29688 : idsVec.emplace_back(ids[i].impl.begin(), ids[i].impl.size());
378 29690 : }
379 :
380 : try {
381 10425 : impl = bls::Threshold::SignatureRecover(sigsVec, idsVec);
382 10425 : } catch (...) {
383 2 : return false;
384 2 : }
385 :
386 10423 : fValid = true;
387 10423 : cachedHash.SetNull();
388 10423 : return true;
389 10442 : }
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 1921 : static void create_secure_allocator()
396 : {
397 : // make sure LockedPoolManager is initialized first (ensures destruction order)
398 1921 : LockedPoolManager::Instance();
399 :
400 : // static variable in function scope ensures it's initialized when first accessed
401 : // and destroyed before LockedPoolManager
402 1921 : static mt_pooled_secure_allocator<uint8_t> a(sizeof(bn_t) + sizeof(size_t));
403 1921 : secure_allocator_instance = &a;
404 1921 : }
405 :
406 1344495 : static mt_pooled_secure_allocator<uint8_t>& get_secure_allocator()
407 : {
408 1344495 : std::call_once(init_flag, create_secure_allocator);
409 1344495 : return *secure_allocator_instance;
410 : }
411 :
412 672315 : static void* secure_allocate(size_t n)
413 : {
414 672315 : uint8_t* ptr = get_secure_allocator().allocate(n + sizeof(size_t));
415 672315 : *reinterpret_cast<size_t*>(ptr) = n;
416 672315 : return ptr + sizeof(size_t);
417 : }
418 :
419 672311 : static void secure_free(void* p)
420 : {
421 672311 : if (p == nullptr) {
422 0 : return;
423 : }
424 :
425 672311 : uint8_t* ptr = reinterpret_cast<uint8_t*>(p) - sizeof(size_t);
426 672311 : size_t n = *reinterpret_cast<size_t*>(ptr);
427 672311 : return get_secure_allocator().deallocate(ptr, n);
428 672311 : }
429 : #endif
430 :
431 3659 : bool BLSInit()
432 : {
433 : #ifndef BUILD_BITCOIN_INTERNAL
434 3659 : bls::BLS::SetSecureAllocator(secure_allocate, secure_free);
435 : #endif
436 3659 : return true;
437 : }
|