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