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 12779 : 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 126159 : CBLSWrapper()
55 240816 : {
56 : }
57 625 : CBLSWrapper(const std::vector<unsigned char>& vecBytes) : CBLSWrapper<ImplType, _SerSize, C>()
58 : {
59 625 : SetByteVector(vecBytes);
60 625 : }
61 :
62 12682 : CBLSWrapper(const CBLSWrapper& ref) = default;
63 : CBLSWrapper& operator=(const CBLSWrapper& ref) = default;
64 13160 : CBLSWrapper(CBLSWrapper&& ref)
65 14164 : {
66 13160 : std::swap(impl, ref.impl);
67 13160 : std::swap(fValid, ref.fValid);
68 13160 : std::swap(cachedHash, ref.cachedHash);
69 13160 : }
70 55641 : CBLSWrapper& operator=(CBLSWrapper&& ref)
71 : {
72 55641 : std::swap(impl, ref.impl);
73 55641 : std::swap(fValid, ref.fValid);
74 55641 : std::swap(cachedHash, ref.cachedHash);
75 55641 : return *this;
76 : }
77 :
78 4995 : bool operator==(const C& r) const
79 : {
80 4875 : return fValid == r.fValid && impl == r.impl;
81 : }
82 728 : bool operator!=(const C& r) const
83 : {
84 758 : return !((*this) == r);
85 : }
86 :
87 232340 : bool IsValid() const
88 : {
89 210013 : return fValid;
90 : }
91 :
92 76465 : void Reset()
93 : {
94 130675 : *((C*)this) = C();
95 76465 : }
96 :
97 44921 : void SetByteVector(const std::vector<uint8_t>& vecBytes)
98 : {
99 44921 : if (vecBytes.size() != SerSize) {
100 3 : Reset();
101 3 : return;
102 : }
103 667563 : if (std::all_of(vecBytes.begin(), vecBytes.end(), [](uint8_t c) { return c == 0; })) {
104 30409 : Reset();
105 : } else {
106 : try {
107 14509 : impl = ImplType::FromBytes(bls::Bytes(vecBytes));
108 14504 : fValid = true;
109 10 : } catch (...) {
110 5 : Reset();
111 : }
112 : }
113 44921 : cachedHash.SetNull();
114 : }
115 :
116 76229 : std::vector<uint8_t> ToByteVector() const
117 : {
118 76229 : if (!fValid) {
119 31866 : return std::vector<uint8_t>(SerSize, 0);
120 : }
121 44547 : return impl.Serialize();
122 : }
123 :
124 7754 : const uint256& GetHash() const
125 : {
126 15508 : if (cachedHash.IsNull()) {
127 6995 : cachedHash = ::SerializeHash(*this);
128 : }
129 7754 : return cachedHash;
130 : }
131 :
132 : public:
133 : template <typename Stream>
134 24064 : inline void Serialize(Stream& s) const
135 : {
136 39758 : s.write((const char*)ToByteVector().data(), SerSize);
137 24064 : }
138 :
139 : template <typename Stream>
140 42849 : inline void Unserialize(Stream& s, bool checkMalleable = true)
141 : {
142 42849 : std::vector<uint8_t> vecBytes(SerSize, 0);
143 42849 : s.read((char*)vecBytes.data(), SerSize);
144 42849 : SetByteVector(vecBytes);
145 :
146 42849 : if (checkMalleable && !CheckMalleable(vecBytes)) {
147 0 : throw std::ios_base::failure("malleable BLS object");
148 : }
149 42849 : }
150 :
151 44289 : inline bool CheckMalleable(const std::vector<uint8_t>& vecBytes) const
152 : {
153 88578 : 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 166 : inline std::string ToString() const
165 : {
166 166 : std::vector<uint8_t> buf = ToByteVector();
167 332 : return HexStr(buf);
168 : }
169 : };
170 :
171 : struct CBLSIdImplicit : public uint256
172 : {
173 5887 : CBLSIdImplicit() {}
174 1706 : CBLSIdImplicit(const uint256& id)
175 1706 : {
176 1706 : 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 184 : std::vector<uint8_t> Serialize() const
185 : {
186 184 : return {begin(), end()};
187 : }
188 : };
189 :
190 462 : 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 1963 : CBLSId() {}
198 : CBLSId(const uint256& nHash);
199 : };
200 :
201 41019 : 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 58820 : 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 247505 : 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 625 : using CBLSWrapper::CBLSWrapper;
250 :
251 84857 : 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 19893 : 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 32930 : 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 16465 : bufValid = true;
290 16465 : }
291 :
292 71647 : CBLSLazyWrapper(const CBLSLazyWrapper& r)
293 143294 : {
294 71647 : *this = r;
295 71647 : }
296 :
297 72430 : CBLSLazyWrapper& operator=(const CBLSLazyWrapper& r)
298 : {
299 72430 : std::unique_lock<std::mutex> l(r.mutex);
300 72430 : bufValid = r.bufValid;
301 72430 : if (r.bufValid) {
302 69148 : vecBytes = r.vecBytes;
303 : } else {
304 3282 : std::fill(vecBytes.begin(), vecBytes.end(), 0);
305 : }
306 72430 : objInitialized = r.objInitialized;
307 72430 : if (r.objInitialized) {
308 26872 : obj = r.obj;
309 : } else {
310 45558 : obj.Reset();
311 : }
312 72430 : hash = r.hash;
313 144860 : return *this;
314 : }
315 :
316 : template<typename Stream>
317 8535 : inline void Serialize(Stream& s) const
318 : {
319 8535 : std::unique_lock<std::mutex> l(mutex);
320 8535 : if (!objInitialized && !bufValid) {
321 0 : throw std::ios_base::failure("obj and buf not initialized");
322 : }
323 8535 : if (!bufValid) {
324 2267 : vecBytes = obj.ToByteVector();
325 1526 : bufValid = true;
326 1526 : hash.SetNull();
327 : }
328 12994 : s.write((const char*)vecBytes.data(), vecBytes.size());
329 8535 : }
330 :
331 : template<typename Stream>
332 2542 : inline void Unserialize(Stream& s)
333 : {
334 2542 : std::unique_lock<std::mutex> l(mutex);
335 2542 : s.read((char*)vecBytes.data(), BLSObject::SerSize);
336 2542 : bufValid = true;
337 2542 : objInitialized = false;
338 2542 : hash.SetNull();
339 2542 : }
340 :
341 1509 : void Set(const BLSObject& _obj)
342 : {
343 1509 : std::unique_lock<std::mutex> l(mutex);
344 1509 : bufValid = false;
345 1509 : objInitialized = true;
346 1509 : obj = _obj;
347 1509 : hash.SetNull();
348 1509 : }
349 :
350 9487 : const BLSObject& Get() const
351 : {
352 18974 : std::unique_lock<std::mutex> l(mutex);
353 9579 : static BLSObject invalidObj;
354 9487 : if (!bufValid && !objInitialized) {
355 : return invalidObj;
356 : }
357 9487 : if (!objInitialized) {
358 1440 : obj.SetByteVector(vecBytes);
359 1440 : if (!obj.CheckMalleable(vecBytes)) {
360 0 : bufValid = false;
361 0 : objInitialized = false;
362 0 : obj = invalidObj;
363 : } else {
364 1440 : objInitialized = true;
365 : }
366 : }
367 9487 : return obj;
368 : }
369 :
370 40794 : bool operator==(const CBLSLazyWrapper& r) const
371 : {
372 40794 : if (bufValid && r.bufValid) {
373 40602 : return vecBytes == r.vecBytes;
374 : }
375 192 : if (objInitialized && r.objInitialized) {
376 172 : return obj == r.obj;
377 : }
378 20 : return Get() == r.Get();
379 : }
380 :
381 16463 : bool operator!=(const CBLSLazyWrapper& r) const
382 : {
383 16463 : return !(*this == r);
384 : }
385 :
386 104 : uint256 GetHash() const
387 : {
388 104 : std::unique_lock<std::mutex> l(mutex);
389 104 : if (!bufValid) {
390 0 : vecBytes = obj.ToByteVector();
391 0 : bufValid = true;
392 0 : hash.SetNull();
393 : }
394 208 : if (hash.IsNull()) {
395 102 : CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
396 204 : ss.write((const char*)vecBytes.data(), vecBytes.size());
397 102 : hash = ss.GetHash();
398 : }
399 208 : 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
|