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 1932 : 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 21516 : CBLSWrapper()
55 33396 : {
56 : }
57 35 : CBLSWrapper(const std::vector<unsigned char>& vecBytes) : CBLSWrapper<ImplType, _SerSize, C>()
58 : {
59 35 : SetByteVector(vecBytes);
60 35 : }
61 :
62 5912 : CBLSWrapper(const CBLSWrapper& ref) = default;
63 : CBLSWrapper& operator=(const CBLSWrapper& ref) = default;
64 7080 : CBLSWrapper(CBLSWrapper&& ref)
65 7160 : {
66 7080 : std::swap(impl, ref.impl);
67 7080 : std::swap(fValid, ref.fValid);
68 7080 : std::swap(cachedHash, ref.cachedHash);
69 7080 : }
70 5081 : CBLSWrapper& operator=(CBLSWrapper&& ref)
71 : {
72 5081 : std::swap(impl, ref.impl);
73 5081 : std::swap(fValid, ref.fValid);
74 5081 : std::swap(cachedHash, ref.cachedHash);
75 5081 : return *this;
76 : }
77 :
78 3339 : bool operator==(const C& r) const
79 : {
80 3325 : return fValid == r.fValid && impl == r.impl;
81 : }
82 14 : bool operator!=(const C& r) const
83 : {
84 17 : return !((*this) == r);
85 : }
86 :
87 178962 : bool IsValid() const
88 : {
89 169974 : return fValid;
90 : }
91 :
92 6244 : void Reset()
93 : {
94 9987 : *((C*)this) = C();
95 6244 : }
96 :
97 7327 : void SetByteVector(const std::vector<uint8_t>& vecBytes)
98 : {
99 7327 : if (vecBytes.size() != SerSize) {
100 0 : Reset();
101 0 : return;
102 : }
103 92999 : if (std::all_of(vecBytes.begin(), vecBytes.end(), [](uint8_t c) { return c == 0; })) {
104 4119 : Reset();
105 : } else {
106 : try {
107 3208 : impl = ImplType::FromBytes(bls::Bytes(vecBytes));
108 3203 : fValid = true;
109 10 : } catch (...) {
110 5 : Reset();
111 : }
112 : }
113 7327 : cachedHash.SetNull();
114 : }
115 :
116 18741 : std::vector<uint8_t> ToByteVector() const
117 : {
118 18741 : if (!fValid) {
119 4406 : return std::vector<uint8_t>(SerSize, 0);
120 : }
121 14335 : return impl.Serialize();
122 : }
123 :
124 4769 : const uint256& GetHash() const
125 : {
126 9538 : if (cachedHash.IsNull()) {
127 4769 : cachedHash = ::SerializeHash(*this);
128 : }
129 4769 : return cachedHash;
130 : }
131 :
132 : public:
133 : template <typename Stream>
134 7553 : inline void Serialize(Stream& s) const
135 : {
136 13014 : s.write((const char*)ToByteVector().data(), SerSize);
137 7553 : }
138 :
139 : template <typename Stream>
140 7281 : inline void Unserialize(Stream& s, bool checkMalleable = true)
141 : {
142 7281 : std::vector<uint8_t> vecBytes(SerSize, 0);
143 7281 : s.read((char*)vecBytes.data(), SerSize);
144 7281 : SetByteVector(vecBytes);
145 :
146 7281 : if (checkMalleable && !CheckMalleable(vecBytes)) {
147 0 : throw std::ios_base::failure("malleable BLS object");
148 : }
149 7281 : }
150 :
151 7285 : inline bool CheckMalleable(const std::vector<uint8_t>& vecBytes) const
152 : {
153 14570 : 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 0 : inline std::string ToString() const
165 : {
166 0 : std::vector<uint8_t> buf = ToByteVector();
167 0 : return HexStr(buf);
168 : }
169 : };
170 :
171 : struct CBLSIdImplicit : public uint256
172 : {
173 739 : CBLSIdImplicit() {}
174 40 : CBLSIdImplicit(const uint256& id)
175 40 : {
176 40 : 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 0 : std::vector<uint8_t> Serialize() const
185 : {
186 0 : return {begin(), end()};
187 : }
188 : };
189 :
190 0 : 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 579 : CBLSId() {}
198 : CBLSId(const uint256& nHash);
199 : };
200 :
201 20887 : 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 8327 : 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 39505 : 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 35 : using CBLSWrapper::CBLSWrapper;
250 :
251 8679 : 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 30 : 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 1386 : 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 693 : bufValid = true;
290 693 : }
291 :
292 3365 : CBLSLazyWrapper(const CBLSLazyWrapper& r)
293 6730 : {
294 3365 : *this = r;
295 3365 : }
296 :
297 3373 : CBLSLazyWrapper& operator=(const CBLSLazyWrapper& r)
298 : {
299 3373 : std::unique_lock<std::mutex> l(r.mutex);
300 3373 : bufValid = r.bufValid;
301 3373 : if (r.bufValid) {
302 3367 : vecBytes = r.vecBytes;
303 : } else {
304 6 : std::fill(vecBytes.begin(), vecBytes.end(), 0);
305 : }
306 3373 : objInitialized = r.objInitialized;
307 3373 : if (r.objInitialized) {
308 1381 : obj = r.obj;
309 : } else {
310 1992 : obj.Reset();
311 : }
312 3373 : hash = r.hash;
313 6746 : return *this;
314 : }
315 :
316 : template<typename Stream>
317 940 : inline void Serialize(Stream& s) const
318 : {
319 940 : std::unique_lock<std::mutex> l(mutex);
320 940 : if (!objInitialized && !bufValid) {
321 0 : throw std::ios_base::failure("obj and buf not initialized");
322 : }
323 940 : if (!bufValid) {
324 331 : vecBytes = obj.ToByteVector();
325 167 : bufValid = true;
326 167 : hash.SetNull();
327 : }
328 1528 : s.write((const char*)vecBytes.data(), vecBytes.size());
329 940 : }
330 :
331 : template<typename Stream>
332 0 : inline void Unserialize(Stream& s)
333 : {
334 0 : std::unique_lock<std::mutex> l(mutex);
335 0 : s.read((char*)vecBytes.data(), BLSObject::SerSize);
336 0 : bufValid = true;
337 0 : objInitialized = false;
338 0 : hash.SetNull();
339 0 : }
340 :
341 174 : void Set(const BLSObject& _obj)
342 : {
343 174 : std::unique_lock<std::mutex> l(mutex);
344 174 : bufValid = false;
345 174 : objInitialized = true;
346 174 : obj = _obj;
347 174 : hash.SetNull();
348 174 : }
349 :
350 454 : const BLSObject& Get() const
351 : {
352 908 : std::unique_lock<std::mutex> l(mutex);
353 472 : static BLSObject invalidObj;
354 454 : if (!bufValid && !objInitialized) {
355 : return invalidObj;
356 : }
357 454 : if (!objInitialized) {
358 4 : obj.SetByteVector(vecBytes);
359 4 : if (!obj.CheckMalleable(vecBytes)) {
360 0 : bufValid = false;
361 0 : objInitialized = false;
362 0 : obj = invalidObj;
363 : } else {
364 4 : objInitialized = true;
365 : }
366 : }
367 454 : return obj;
368 : }
369 :
370 2178 : bool operator==(const CBLSLazyWrapper& r) const
371 : {
372 2178 : if (bufValid && r.bufValid) {
373 2153 : return vecBytes == r.vecBytes;
374 : }
375 25 : if (objInitialized && r.objInitialized) {
376 21 : return obj == r.obj;
377 : }
378 4 : return Get() == r.Get();
379 : }
380 :
381 836 : bool operator!=(const CBLSLazyWrapper& r) const
382 : {
383 836 : return !(*this == r);
384 : }
385 :
386 14 : uint256 GetHash() const
387 : {
388 14 : std::unique_lock<std::mutex> l(mutex);
389 14 : if (!bufValid) {
390 0 : vecBytes = obj.ToByteVector();
391 0 : bufValid = true;
392 0 : hash.SetNull();
393 : }
394 28 : if (hash.IsNull()) {
395 12 : CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
396 24 : ss.write((const char*)vecBytes.data(), vecBytes.size());
397 12 : hash = ss.GetHash();
398 : }
399 28 : 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
|