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