PIVX Core  5.6.99
P2P Digital Currency
bls_wrapper.h
Go to the documentation of this file.
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>
39 {
40  friend class CBLSSecretKey;
41  friend class CBLSPublicKey;
42  friend class CBLSSignature;
43 
44 protected:
45  ImplType impl;
46  bool fValid{false};
48 
49  inline constexpr size_t GetSerSize() const { return SerSize; }
50 
51 public:
52  static const size_t SerSize = _SerSize;
53 
55  {
56  }
57  CBLSWrapper(const std::vector<unsigned char>& vecBytes) : CBLSWrapper<ImplType, _SerSize, C>()
58  {
59  SetByteVector(vecBytes);
60  }
61 
62  CBLSWrapper(const CBLSWrapper& ref) = default;
63  CBLSWrapper& operator=(const CBLSWrapper& ref) = default;
65  {
66  std::swap(impl, ref.impl);
67  std::swap(fValid, ref.fValid);
68  std::swap(cachedHash, ref.cachedHash);
69  }
71  {
72  std::swap(impl, ref.impl);
73  std::swap(fValid, ref.fValid);
74  std::swap(cachedHash, ref.cachedHash);
75  return *this;
76  }
77 
78  bool operator==(const C& r) const
79  {
80  return fValid == r.fValid && impl == r.impl;
81  }
82  bool operator!=(const C& r) const
83  {
84  return !((*this) == r);
85  }
86 
87  bool IsValid() const
88  {
89  return fValid;
90  }
91 
92  void Reset()
93  {
94  *((C*)this) = C();
95  }
96 
97  void SetByteVector(const std::vector<uint8_t>& vecBytes)
98  {
99  if (vecBytes.size() != SerSize) {
100  Reset();
101  return;
102  }
103  if (std::all_of(vecBytes.begin(), vecBytes.end(), [](uint8_t c) { return c == 0; })) {
104  Reset();
105  } else {
106  try {
107  impl = ImplType::FromBytes(bls::Bytes(vecBytes));
108  fValid = true;
109  } catch (...) {
110  Reset();
111  }
112  }
114  }
115 
116  std::vector<uint8_t> ToByteVector() const
117  {
118  if (!fValid) {
119  return std::vector<uint8_t>(SerSize, 0);
120  }
121  return impl.Serialize();
122  }
123 
124  const uint256& GetHash() const
125  {
126  if (cachedHash.IsNull()) {
127  cachedHash = ::SerializeHash(*this);
128  }
129  return cachedHash;
130  }
131 
132 public:
133  template <typename Stream>
134  inline void Serialize(Stream& s) const
135  {
136  s.write((const char*)ToByteVector().data(), SerSize);
137  }
138 
139  template <typename Stream>
140  inline void Unserialize(Stream& s, bool checkMalleable = true)
141  {
142  std::vector<uint8_t> vecBytes(SerSize, 0);
143  s.read((char*)vecBytes.data(), SerSize);
144  SetByteVector(vecBytes);
145 
146  if (checkMalleable && !CheckMalleable(vecBytes)) {
147  throw std::ios_base::failure("malleable BLS object");
148  }
149  }
150 
151  inline bool CheckMalleable(const std::vector<uint8_t>& vecBytes) const
152  {
153  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  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  inline std::string ToString() const
165  {
166  std::vector<uint8_t> buf = ToByteVector();
167  return HexStr(buf);
168  }
169 };
170 
171 struct CBLSIdImplicit : public uint256
172 {
175  {
176  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  std::vector<uint8_t> Serialize() const
185  {
186  return {begin(), end()};
187  }
188 };
189 
190 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  CBLSId() {}
198  CBLSId(const uint256& nHash);
199 };
200 
201 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 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!=;
231 
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!=;
250 
252  CBLSSignature(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>
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  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  bufValid = true;
290  }
291 
293  {
294  *this = r;
295  }
296 
298  {
299  std::unique_lock<std::mutex> l(r.mutex);
300  bufValid = r.bufValid;
301  if (r.bufValid) {
302  vecBytes = r.vecBytes;
303  } else {
304  std::fill(vecBytes.begin(), vecBytes.end(), 0);
305  }
307  if (r.objInitialized) {
308  obj = r.obj;
309  } else {
310  obj.Reset();
311  }
312  hash = r.hash;
313  return *this;
314  }
315 
316  template<typename Stream>
317  inline void Serialize(Stream& s) const
318  {
319  std::unique_lock<std::mutex> l(mutex);
320  if (!objInitialized && !bufValid) {
321  throw std::ios_base::failure("obj and buf not initialized");
322  }
323  if (!bufValid) {
324  vecBytes = obj.ToByteVector();
325  bufValid = true;
326  hash.SetNull();
327  }
328  s.write((const char*)vecBytes.data(), vecBytes.size());
329  }
330 
331  template<typename Stream>
332  inline void Unserialize(Stream& s)
333  {
334  std::unique_lock<std::mutex> l(mutex);
335  s.read((char*)vecBytes.data(), BLSObject::SerSize);
336  bufValid = true;
337  objInitialized = false;
338  hash.SetNull();
339  }
340 
341  void Set(const BLSObject& _obj)
342  {
343  std::unique_lock<std::mutex> l(mutex);
344  bufValid = false;
345  objInitialized = true;
346  obj = _obj;
347  hash.SetNull();
348  }
349 
350  const BLSObject& Get() const
351  {
352  std::unique_lock<std::mutex> l(mutex);
353  static BLSObject invalidObj;
354  if (!bufValid && !objInitialized) {
355  return invalidObj;
356  }
357  if (!objInitialized) {
358  obj.SetByteVector(vecBytes);
359  if (!obj.CheckMalleable(vecBytes)) {
360  bufValid = false;
361  objInitialized = false;
362  obj = invalidObj;
363  } else {
364  objInitialized = true;
365  }
366  }
367  return obj;
368  }
369 
370  bool operator==(const CBLSLazyWrapper& r) const
371  {
372  if (bufValid && r.bufValid) {
373  return vecBytes == r.vecBytes;
374  }
375  if (objInitialized && r.objInitialized) {
376  return obj == r.obj;
377  }
378  return Get() == r.Get();
379  }
380 
381  bool operator!=(const CBLSLazyWrapper& r) const
382  {
383  return !(*this == r);
384  }
385 
386  uint256 GetHash() const
387  {
388  std::unique_lock<std::mutex> l(mutex);
389  if (!bufValid) {
390  vecBytes = obj.ToByteVector();
391  bufValid = true;
392  hash.SetNull();
393  }
394  if (hash.IsNull()) {
395  CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
396  ss.write((const char*)vecBytes.data(), vecBytes.size());
397  hash = ss.GetHash();
398  }
399  return hash;
400  }
401 };
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
std::vector< CBLSId > BLSIdVector
Definition: bls_wrapper.h:408
std::shared_ptr< BLSIdVector > BLSIdVectorPtr
Definition: bls_wrapper.h:414
bool BLSInit()
std::vector< CBLSPublicKey > BLSVerificationVector
Definition: bls_wrapper.h:409
std::vector< CBLSPublicKey > BLSPublicKeyVector
Definition: bls_wrapper.h:410
std::shared_ptr< BLSSignatureVector > BLSSignatureVectorPtr
Definition: bls_wrapper.h:418
CBLSLazyWrapper< CBLSSignature > CBLSLazySignature
Definition: bls_wrapper.h:402
CBLSLazyWrapper< CBLSPublicKey > CBLSLazyPublicKey
Definition: bls_wrapper.h:403
std::shared_ptr< BLSVerificationVector > BLSVerificationVectorPtr
Definition: bls_wrapper.h:415
std::shared_ptr< BLSPublicKeyVector > BLSPublicKeyVectorPtr
Definition: bls_wrapper.h:416
std::shared_ptr< BLSSecretKeyVector > BLSSecretKeyVectorPtr
Definition: bls_wrapper.h:417
std::vector< CBLSSecretKey > BLSSecretKeyVector
Definition: bls_wrapper.h:411
std::vector< CBLSSignature > BLSSignatureVector
Definition: bls_wrapper.h:412
CBLSLazyWrapper< CBLSSecretKey > CBLSLazySecretKey
Definition: bls_wrapper.h:404
std::vector< uint8_t > vecBytes
Definition: bls_wrapper.h:277
uint256 GetHash() const
Definition: bls_wrapper.h:386
void Unserialize(Stream &s)
Definition: bls_wrapper.h:332
std::mutex mutex
Definition: bls_wrapper.h:275
BLSObject obj
Definition: bls_wrapper.h:280
bool operator==(const CBLSLazyWrapper &r) const
Definition: bls_wrapper.h:370
void Serialize(Stream &s) const
Definition: bls_wrapper.h:317
const BLSObject & Get() const
Definition: bls_wrapper.h:350
bool operator!=(const CBLSLazyWrapper &r) const
Definition: bls_wrapper.h:381
CBLSLazyWrapper(const CBLSLazyWrapper &r)
Definition: bls_wrapper.h:292
void Set(const BLSObject &_obj)
Definition: bls_wrapper.h:341
CBLSLazyWrapper & operator=(const CBLSLazyWrapper &r)
Definition: bls_wrapper.h:297
void AggregateInsecure(const CBLSPublicKey &o)
bool PublicKeyShare(const std::vector< CBLSPublicKey > &mpk, const CBLSId &id)
bool DHKeyExchange(const CBLSSecretKey &sk, const CBLSPublicKey &pk)
void MakeNewKey()
Definition: bls_wrapper.cpp:54
CBLSPublicKey GetPublicKey() const
Definition: bls_wrapper.cpp:99
bool Recover(const std::vector< CBLSSecretKey > &keys, const std::vector< CBLSId > &ids)
void AggregateInsecure(const CBLSSecretKey &o)
Definition: bls_wrapper.cpp:27
bool SecretKeyShare(const std::vector< CBLSSecretKey > &msk, const CBLSId &id)
Definition: bls_wrapper.cpp:70
CBLSSignature Sign(const uint256 &hash) const
void AggregateInsecure(const CBLSSignature &o)
bool VerifyInsecure(const CBLSPublicKey &pubKey, const uint256 &hash) const
static CBLSSignature AggregateSecure(const std::vector< CBLSSignature > &sigs, const std::vector< CBLSPublicKey > &pks, const uint256 &hash)
CBLSSignature(const CBLSSignature &)=default
bool Recover(const std::vector< CBLSSignature > &sigs, const std::vector< CBLSId > &ids)
void SubInsecure(const CBLSSignature &o)
CBLSSignature & operator=(const CBLSSignature &)=default
bool VerifyInsecureAggregated(const std::vector< CBLSPublicKey > &pubKeys, const std::vector< uint256 > &hashes) const
bool VerifySecureAggregated(const std::vector< CBLSPublicKey > &pks, const uint256 &hash) const
uint256 cachedHash
Definition: bls_wrapper.h:47
bool IsValid() const
Definition: bls_wrapper.h:87
bool operator!=(const C &r) const
Definition: bls_wrapper.h:82
void SetByteVector(const std::vector< uint8_t > &vecBytes)
Definition: bls_wrapper.h:97
CBLSWrapper(const CBLSWrapper &ref)=default
std::vector< uint8_t > ToByteVector() const
Definition: bls_wrapper.h:116
bool operator==(const C &r) const
Definition: bls_wrapper.h:78
void Unserialize(Stream &s, bool checkMalleable=true)
Definition: bls_wrapper.h:140
constexpr size_t GetSerSize() const
Definition: bls_wrapper.h:49
ImplType impl
Definition: bls_wrapper.h:45
bool CheckMalleable(const std::vector< uint8_t > &vecBytes) const
Definition: bls_wrapper.h:151
static const size_t SerSize
Definition: bls_wrapper.h:52
std::string ToString() const
Definition: bls_wrapper.h:164
void Reset()
Definition: bls_wrapper.h:92
const uint256 & GetHash() const
Definition: bls_wrapper.h:124
CBLSWrapper & operator=(const CBLSWrapper &ref)=default
CBLSWrapper & operator=(CBLSWrapper &&ref)
Definition: bls_wrapper.h:70
void Serialize(Stream &s) const
Definition: bls_wrapper.h:134
CBLSWrapper(CBLSWrapper &&ref)
Definition: bls_wrapper.h:64
CBLSWrapper(const std::vector< unsigned char > &vecBytes)
Definition: bls_wrapper.h:57
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:216
void write(const char *pch, size_t size)
Definition: hash.h:230
uint256 GetHash()
Definition: hash.h:236
void SetNull()
Definition: uint256.h:44
unsigned char * end()
Definition: uint256.h:68
bool IsNull() const
Definition: uint256.h:36
unsigned char * begin()
Definition: uint256.h:63
256-bit opaque blob.
Definition: uint256.h:138
std::vector< uint8_t > buffer
Definition: fuzz.cpp:71
void * memcpy(void *a, const void *b, size_t c)
uint256 SerializeHash(const T &obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
Compute the 256-bit hash of an object's serialization.
Definition: hash.h:289
@ SER_GETHASH
Definition: serialize.h:176
std::vector< uint8_t > Serialize() const
Definition: bls_wrapper.h:184
CBLSIdImplicit(const uint256 &id)
Definition: bls_wrapper.h:174
static CBLSIdImplicit FromBytes(const uint8_t *buffer)
Definition: bls_wrapper.h:178
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.