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 11963 : 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 128243 : CBLSWrapper()
55 234077 : {
56 : }
57 690 : CBLSWrapper(const std::vector<unsigned char>& vecBytes) : CBLSWrapper<ImplType, _SerSize, C>()
58 : {
59 690 : SetByteVector(vecBytes);
60 690 : }
61 :
62 12552 : CBLSWrapper(const CBLSWrapper& ref) = default;
63 : CBLSWrapper& operator=(const CBLSWrapper& ref) = default;
64 14074 : CBLSWrapper(CBLSWrapper&& ref)
65 15710 : {
66 14074 : std::swap(impl, ref.impl);
67 14074 : std::swap(fValid, ref.fValid);
68 14074 : std::swap(cachedHash, ref.cachedHash);
69 14074 : }
70 50925 : CBLSWrapper& operator=(CBLSWrapper&& ref)
71 : {
72 50925 : std::swap(impl, ref.impl);
73 50925 : std::swap(fValid, ref.fValid);
74 50925 : std::swap(cachedHash, ref.cachedHash);
75 50925 : return *this;
76 : }
77 :
78 4954 : bool operator==(const C& r) const
79 : {
80 4834 : return fValid == r.fValid && impl == r.impl;
81 : }
82 658 : bool operator!=(const C& r) const
83 : {
84 688 : return !((*this) == r);
85 : }
86 :
87 239681 : bool IsValid() const
88 : {
89 216127 : return fValid;
90 : }
91 :
92 73095 : void Reset()
93 : {
94 122631 : *((C*)this) = C();
95 73095 : }
96 :
97 44321 : void SetByteVector(const std::vector<uint8_t>& vecBytes)
98 : {
99 44321 : if (vecBytes.size() != SerSize) {
100 3 : Reset();
101 3 : return;
102 : }
103 648317 : if (std::all_of(vecBytes.begin(), vecBytes.end(), [](uint8_t c) { return c == 0; })) {
104 29459 : Reset();
105 : } else {
106 : try {
107 14859 : impl = ImplType::FromBytes(bls::Bytes(vecBytes));
108 14853 : fValid = true;
109 12 : } catch (...) {
110 6 : Reset();
111 : }
112 : }
113 44321 : cachedHash.SetNull();
114 : }
115 :
116 74196 : std::vector<uint8_t> ToByteVector() const
117 : {
118 74196 : if (!fValid) {
119 30864 : return std::vector<uint8_t>(SerSize, 0);
120 : }
121 43491 : return impl.Serialize();
122 : }
123 :
124 7539 : const uint256& GetHash() const
125 : {
126 15078 : if (cachedHash.IsNull()) {
127 6875 : cachedHash = ::SerializeHash(*this);
128 : }
129 7539 : return cachedHash;
130 : }
131 :
132 : public:
133 : template <typename Stream>
134 22536 : inline void Serialize(Stream& s) const
135 : {
136 37357 : s.write((const char*)ToByteVector().data(), SerSize);
137 22536 : }
138 :
139 : template <typename Stream>
140 41252 : inline void Unserialize(Stream& s, bool checkMalleable = true)
141 : {
142 41252 : std::vector<uint8_t> vecBytes(SerSize, 0);
143 41252 : s.read((char*)vecBytes.data(), SerSize);
144 41252 : SetByteVector(vecBytes);
145 :
146 41252 : if (checkMalleable && !CheckMalleable(vecBytes)) {
147 0 : throw std::ios_base::failure("malleable BLS object");
148 : }
149 41252 : }
150 :
151 43623 : inline bool CheckMalleable(const std::vector<uint8_t>& vecBytes) const
152 : {
153 87246 : 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 136 : inline std::string ToString() const
165 : {
166 136 : std::vector<uint8_t> buf = ToByteVector();
167 272 : return HexStr(buf);
168 : }
169 : };
170 :
171 : struct CBLSIdImplicit : public uint256
172 : {
173 7307 : CBLSIdImplicit() {}
174 2092 : CBLSIdImplicit(const uint256& id)
175 2092 : {
176 2092 : 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 159 : std::vector<uint8_t> Serialize() const
185 : {
186 159 : return {begin(), end()};
187 : }
188 : };
189 :
190 778 : 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 1991 : CBLSId() {}
198 : CBLSId(const uint256& nHash);
199 : };
200 :
201 39634 : 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 54080 : 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 229734 : 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 690 : using CBLSWrapper::CBLSWrapper;
250 :
251 90739 : 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 29719 : 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 36322 : 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 18161 : bufValid = true;
290 18161 : }
291 :
292 67684 : CBLSLazyWrapper(const CBLSLazyWrapper& r)
293 135368 : {
294 67684 : *this = r;
295 67684 : }
296 :
297 68774 : CBLSLazyWrapper& operator=(const CBLSLazyWrapper& r)
298 : {
299 68774 : std::unique_lock<std::mutex> l(r.mutex);
300 68774 : bufValid = r.bufValid;
301 68774 : if (r.bufValid) {
302 64408 : vecBytes = r.vecBytes;
303 : } else {
304 4366 : std::fill(vecBytes.begin(), vecBytes.end(), 0);
305 : }
306 68774 : objInitialized = r.objInitialized;
307 68774 : if (r.objInitialized) {
308 25624 : obj = r.obj;
309 : } else {
310 43150 : obj.Reset();
311 : }
312 68774 : hash = r.hash;
313 137548 : return *this;
314 : }
315 :
316 : template<typename Stream>
317 12403 : inline void Serialize(Stream& s) const
318 : {
319 12403 : std::unique_lock<std::mutex> l(mutex);
320 12403 : if (!objInitialized && !bufValid) {
321 0 : throw std::ios_base::failure("obj and buf not initialized");
322 : }
323 12403 : if (!bufValid) {
324 2733 : vecBytes = obj.ToByteVector();
325 1834 : bufValid = true;
326 1834 : hash.SetNull();
327 : }
328 18738 : s.write((const char*)vecBytes.data(), vecBytes.size());
329 12403 : }
330 :
331 : template<typename Stream>
332 4376 : inline void Unserialize(Stream& s)
333 : {
334 4376 : std::unique_lock<std::mutex> l(mutex);
335 4376 : s.read((char*)vecBytes.data(), BLSObject::SerSize);
336 4376 : bufValid = true;
337 4376 : objInitialized = false;
338 4376 : hash.SetNull();
339 4376 : }
340 :
341 1974 : void Set(const BLSObject& _obj)
342 : {
343 1974 : std::unique_lock<std::mutex> l(mutex);
344 1974 : bufValid = false;
345 1974 : objInitialized = true;
346 1974 : obj = _obj;
347 1974 : hash.SetNull();
348 1974 : }
349 :
350 11727 : const BLSObject& Get() const
351 : {
352 23454 : std::unique_lock<std::mutex> l(mutex);
353 11821 : static BLSObject invalidObj;
354 11727 : if (!bufValid && !objInitialized) {
355 : return invalidObj;
356 : }
357 11727 : if (!objInitialized) {
358 2371 : obj.SetByteVector(vecBytes);
359 2371 : if (!obj.CheckMalleable(vecBytes)) {
360 0 : bufValid = false;
361 0 : objInitialized = false;
362 0 : obj = invalidObj;
363 : } else {
364 2371 : objInitialized = true;
365 : }
366 : }
367 11727 : return obj;
368 : }
369 :
370 36963 : bool operator==(const CBLSLazyWrapper& r) const
371 : {
372 36963 : if (bufValid && r.bufValid) {
373 36744 : return vecBytes == r.vecBytes;
374 : }
375 219 : if (objInitialized && r.objInitialized) {
376 199 : return obj == r.obj;
377 : }
378 20 : return Get() == r.Get();
379 : }
380 :
381 14989 : bool operator!=(const CBLSLazyWrapper& r) const
382 : {
383 14989 : return !(*this == r);
384 : }
385 :
386 114 : uint256 GetHash() const
387 : {
388 114 : std::unique_lock<std::mutex> l(mutex);
389 114 : if (!bufValid) {
390 0 : vecBytes = obj.ToByteVector();
391 0 : bufValid = true;
392 0 : hash.SetNull();
393 : }
394 228 : if (hash.IsNull()) {
395 112 : CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
396 224 : ss.write((const char*)vecBytes.data(), vecBytes.size());
397 112 : hash = ss.GetHash();
398 : }
399 228 : 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
|