PIVX Core  5.6.99
P2P Digital Currency
bls_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019-2020 The Dash Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include "test/test_pivx.h"
6 
8 #include "bls/bls_ies.h"
9 #include "bls/bls_worker.h"
10 #include "bls/bls_wrapper.h"
11 #include "bls/key_io.h"
12 #include "random.h"
13 
14 #include <boost/test/unit_test.hpp>
15 
17 
18 BOOST_AUTO_TEST_CASE(bls_sig_tests)
19 {
20  CBLSSecretKey sk1, sk2;
21  sk1.MakeNewKey();
22  sk2.MakeNewKey();
23 
24  uint256 msgHash1 = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
25  uint256 msgHash2 = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
26 
27  auto sig1 = sk1.Sign(msgHash1);
28  auto sig2 = sk2.Sign(msgHash1);
29 
30  BOOST_CHECK(sig1.VerifyInsecure(sk1.GetPublicKey(), msgHash1));
31  BOOST_CHECK(!sig1.VerifyInsecure(sk1.GetPublicKey(), msgHash2));
32 
33  BOOST_CHECK(sig2.VerifyInsecure(sk2.GetPublicKey(), msgHash1));
34  BOOST_CHECK(!sig2.VerifyInsecure(sk2.GetPublicKey(), msgHash2));
35 
36  BOOST_CHECK(!sig1.VerifyInsecure(sk2.GetPublicKey(), msgHash1));
37  BOOST_CHECK(!sig1.VerifyInsecure(sk2.GetPublicKey(), msgHash2));
38  BOOST_CHECK(!sig2.VerifyInsecure(sk1.GetPublicKey(), msgHash1));
39  BOOST_CHECK(!sig2.VerifyInsecure(sk1.GetPublicKey(), msgHash2));
40 }
41 
42 static BLSIdVector GetRandomBLSIds(size_t n)
43 {
44  BLSIdVector v;
45  for (size_t i = 0; i < n; i++) {
46  v.emplace_back(GetRandHash());
47  }
48  return v;
49 }
50 
51 std::vector<size_t> GetRandomElements(size_t m, size_t n)
52 {
53  assert(m <= n);
54  std::vector<size_t> idxs;
55  for (size_t i = 0; i < n; i++) {
56  idxs.emplace_back(i);
57  }
58  Shuffle(idxs.begin(), idxs.end(), FastRandomContext());
59  return std::vector<size_t>(idxs.begin(), idxs.begin() + m);
60 }
61 
62 struct Member
63 {
64  CBLSId id;
68 
69  // member (operator) keys for encryption/decryption of contributions
72 
73  explicit Member(const CBLSId& _id): id(_id)
74  {
75  sk.MakeNewKey();
76  pk = sk.GetPublicKey();
77  }
78 };
79 
81 {
82  CBLSWorker worker;
83  const size_t N = 40; // quorum size
84  const size_t M = 30; // threshold
85 
86  worker.Start();
87 
88  // Create N Members first
89  const BLSIdVector& ids = GetRandomBLSIds(N);
90  std::vector<Member> quorum;
91  for (const auto& id : ids) {
92  quorum.emplace_back(Member(id));
93  }
94 
95  // Then generate contributions for each one
96  for (Member& m : quorum) {
97  // Generate contributions (plain text)
98  BLSSecretKeyVector pt_contributions;
99  worker.GenerateContributions((int)M, ids, m.vecP, pt_contributions);
100  BOOST_CHECK_EQUAL(m.vecP->size(), M);
101  BOOST_CHECK_EQUAL(pt_contributions.size(), N);
102  // Init encrypted multi-recipient object
103  m.contributions.InitEncrypt(N);
104  for (size_t j = 0; j < N; j++) {
105  const CBLSSecretKey& plaintext = pt_contributions[j];
106  // Verify contribution against verification vector
107  BOOST_CHECK(worker.VerifyContributionShare(ids[j], m.vecP, plaintext));
108  // Encrypt each contribution with the recipient pk
109  BOOST_CHECK(m.contributions.Encrypt(j, quorum[j].pk, plaintext, PROTOCOL_VERSION));
110  }
111  }
112 
113  // Aggregate received contributions for each Member to produce key shares
114  for (size_t i = 0; i < N; i++) {
115  Member& m = quorum[i];
116  // Decrypt contributions received by m with m's secret key
117  BLSSecretKeyVector rcvSkContributions;
118  for (size_t j = 0; j < N; j++) {
119  CBLSSecretKey contribution;
120  BOOST_CHECK(quorum[j].contributions.Decrypt(i, m.sk, contribution, PROTOCOL_VERSION));
121  rcvSkContributions.emplace_back(std::move(contribution));
122  }
123  m.skShare = worker.AggregateSecretKeys(rcvSkContributions);
124  // Recover public key share for m, and check against the secret key share
125  BLSPublicKeyVector rcvPkContributions;
126  for (size_t j = 0; j < N; j++) {
127  CBLSPublicKey pkContribution = worker.BuildPubKeyShare(quorum[j].vecP, m.id);
128  // This is implied by VerifyContributionShare, but let's double check
129  BOOST_CHECK(rcvSkContributions[j].GetPublicKey() == pkContribution);
130  rcvPkContributions.emplace_back(pkContribution);
131  }
132  CBLSPublicKey pkShare = worker.AggregatePublicKeys(rcvPkContributions);
133  BOOST_CHECK(m.skShare.GetPublicKey() == pkShare);
134  }
135 
136  // Each member signs a message with its key share producing a signature share
137  const uint256& msg = GetRandHash();
138  BLSSignatureVector allSigShares;
139  for (const Member& m : quorum) {
140  allSigShares.emplace_back(m.skShare.Sign(msg));
141  }
142 
143  // Pick M (random) key shares and recover threshold secret/public key
144  const auto& idxs = GetRandomElements(M, N);
145  BLSSecretKeyVector skShares;
146  BLSIdVector random_ids;
147  for (size_t i : idxs) {
148  skShares.emplace_back(quorum[i].skShare);
149  random_ids.emplace_back(quorum[i].id);
150  }
151  CBLSSecretKey thresholdSk;
152  BOOST_CHECK(thresholdSk.Recover(skShares, random_ids));
153  const CBLSPublicKey& thresholdPk = thresholdSk.GetPublicKey();
154 
155  // Check that the recovered threshold public key equals the verification
156  // vector free coefficient
157  std::vector<BLSVerificationVectorPtr> v;
158  for (const Member& m : quorum) v.emplace_back(m.vecP);
159  CBLSPublicKey pk = worker.BuildQuorumVerificationVector(v)->at(0);
160  BOOST_CHECK(pk == thresholdPk);
161 
162  // Pick M (random, different BLSids than before) signature shares, and recover
163  // the threshold signature
164  const auto& idxs2 = GetRandomElements(M, N);
165  BLSSignatureVector sigShares;
166  BLSIdVector random_ids2;
167  for (size_t i : idxs2) {
168  sigShares.emplace_back(allSigShares[i]);
169  random_ids2.emplace_back(quorum[i].id);
170  }
171  CBLSSignature thresholdSig;
172  BOOST_CHECK(thresholdSig.Recover(sigShares, random_ids2));
173 
174  // Verify threshold signature against threshold public key
175  BOOST_CHECK(thresholdSig.VerifyInsecure(thresholdPk, msg));
176 
177  // Now replace a signature share with an invalid signature, recover the threshold
178  // signature again, and check that verification fails with the threshold public key
179  CBLSSecretKey dummy_sk;
180  dummy_sk.MakeNewKey();
181  CBLSSignature dummy_sig = dummy_sk.Sign(msg);
182  BOOST_CHECK(dummy_sig != sigShares[0]);
183  sigShares[0] = dummy_sig;
184  BOOST_CHECK(thresholdSig.Recover(sigShares, random_ids2));
185  BOOST_CHECK(!thresholdSig.VerifyInsecure(thresholdPk, msg));
186 
187  worker.Stop();
188 }
189 
190 BOOST_AUTO_TEST_CASE(bls_ies_tests)
191 {
192  // Test basic encryption and decryption of the BLS Integrated Encryption Scheme.
193  CBLSSecretKey aliceSk;
194  aliceSk.MakeNewKey();
195  const CBLSPublicKey alicePk = aliceSk.GetPublicKey();
196  BOOST_CHECK(aliceSk.IsValid());
197 
198  CBLSSecretKey bobSk;
199  bobSk.MakeNewKey();
200  const CBLSPublicKey bobPk = bobSk.GetPublicKey();
201  BOOST_CHECK(bobSk.IsValid());
202 
203  // Encrypt a std::string object
205 
206  // Since no pad is allowed, serialized length must be a multiple of AES_BLOCKSIZE (16)
207  BOOST_CHECK(!iesEnc.Encrypt(bobPk, "message of length 20", PROTOCOL_VERSION));
208 
209  // Message of valid length (15 + 1 byte for the total len in serialization)
210  std::string message = ".mess of len 15";
211  BOOST_CHECK(iesEnc.Encrypt(bobPk, message, PROTOCOL_VERSION));
212 
213  // valid decryption.
214  std::string decrypted_message;
215  BOOST_CHECK(iesEnc.Decrypt(bobSk, decrypted_message, PROTOCOL_VERSION));
216  BOOST_CHECK_EQUAL(decrypted_message, message);
217 
218  // Invalid decryption sk
219  std::string decrypted_message2;
220  iesEnc.Decrypt(aliceSk, decrypted_message2, PROTOCOL_VERSION);
221  BOOST_CHECK(decrypted_message2 != message);
222 
223  // Invalid ephemeral pubkey
224  decrypted_message2.clear();
225  auto iesEphemeralPk = iesEnc.ephemeralPubKey;
226  iesEnc.ephemeralPubKey = alicePk;
227  iesEnc.Decrypt(bobSk, decrypted_message2, PROTOCOL_VERSION);
228  BOOST_CHECK(decrypted_message2 != message);
229  iesEnc.ephemeralPubKey = iesEphemeralPk;
230 
231  // Invalid iv
232  decrypted_message2.clear();
233  GetRandBytes(iesEnc.iv, sizeof(iesEnc.iv));
234  iesEnc.Decrypt(bobSk, decrypted_message2, PROTOCOL_VERSION);
235  BOOST_CHECK(decrypted_message2 != message);
236 }
237 
238 template<typename BLSKey>
239 BLSKey FromHex(const std::string& str)
240 {
241  BLSKey k;
242  k.SetByteVector(ParseHex(str));
243  return k;
244 }
245 
246 BOOST_AUTO_TEST_CASE(bls_sk_io_tests)
247 {
248  const auto& params = Params();
249 
250  CBLSSecretKey sk = FromHex<CBLSSecretKey>("2eb071f4c520b3102e8cb9f520783da252d33993dba0313b501d69d113af9d39");
251  BOOST_ASSERT(sk.IsValid());
252 
253  // Basic encoding-decoding roundtrip
254  std::string encodedSk = bls::EncodeSecret(params, sk);
255  auto opSk2 = bls::DecodeSecret(params, encodedSk);
256  BOOST_CHECK(opSk2 != nullopt);
257  CBLSSecretKey sk2 = *opSk2;
258  BOOST_CHECK(sk == sk2);
259 
260  // Invalid sk, one extra char
261  encodedSk.push_back('f');
262  auto opSk3 = bls::DecodeSecret(params, encodedSk);
263  BOOST_CHECK(opSk3 == nullopt);
264 
265  // Invalid sk, one less char
266  encodedSk.pop_back();
267  encodedSk.pop_back();
268  auto opSk4 = bls::DecodeSecret(params, encodedSk);
269  BOOST_CHECK(opSk4 == nullopt);
270 }
271 
272 BOOST_AUTO_TEST_CASE(bls_pk_io_tests)
273 {
274  const auto& params = Params();
275 
276  CBLSPublicKey pk = FromHex<CBLSPublicKey>("901138a12a352c7e30408c071b1ec097f32ab735a12c8dbb43c637612a3f805668a6bb73894982366d287cf0b02aaf5b");
277  BOOST_ASSERT(pk.IsValid());
278 
279  // Basic encoding-decoding roundtrip
280  std::string encodedPk = bls::EncodePublic(params, pk);
281  auto opPk2 = bls::DecodePublic(params, encodedPk);
282  BOOST_CHECK(opPk2 != nullopt);
283  CBLSPublicKey pk2 = *opPk2;
284  BOOST_CHECK(pk == pk2);
285 
286  // Invalid pk, one extra char
287  encodedPk.push_back('f');
288  auto oppk3 = bls::DecodePublic(params, encodedPk);
289  BOOST_CHECK(oppk3 == nullopt);
290 
291  // Invalid pk, one less char
292  encodedPk.pop_back();
293  encodedPk.pop_back();
294  auto oppk4 = bls::DecodePublic(params, encodedPk);
295  BOOST_CHECK(oppk4 == nullopt);
296 }
297 
298 struct Message {
299  uint32_t sourceId;
300  uint32_t msgId;
305  bool valid;
306 };
307 
308 static void AddMessage(std::vector<Message>& vec, uint32_t sourceId, uint32_t msgId, uint32_t msgHash, bool valid)
309 {
310  Message m;
311  m.sourceId = sourceId;
312  m.msgId = msgId;
313  *((uint32_t*)m.msgHash.begin()) = msgHash;
314  m.sk.MakeNewKey();
315  m.pk = m.sk.GetPublicKey();
316  m.sig = m.sk.Sign(m.msgHash);
317  m.valid = valid;
318 
319  if (!valid) {
320  CBLSSecretKey tmp;
321  tmp.MakeNewKey();
322  m.sig = tmp.Sign(m.msgHash);
323  }
324 
325  vec.emplace_back(m);
326 }
327 
328 static void Verify(std::vector<Message>& vec, bool secureVerification, bool perMessageFallback)
329 {
330  CBLSBatchVerifier<uint32_t, uint32_t> batchVerifier(secureVerification, perMessageFallback);
331 
332  std::set<uint32_t> expectedBadMessages;
333  std::set<uint32_t> expectedBadSources;
334  for (auto& m : vec) {
335  if (!m.valid) {
336  expectedBadMessages.emplace(m.msgId);
337  expectedBadSources.emplace(m.sourceId);
338  }
339 
340  batchVerifier.PushMessage(m.sourceId, m.msgId, m.msgHash, m.sig, m.pk);
341  }
342 
343  batchVerifier.Verify();
344 
345  BOOST_CHECK(batchVerifier.badSources == expectedBadSources);
346 
347  if (perMessageFallback) {
348  BOOST_CHECK(batchVerifier.badMessages == expectedBadMessages);
349  } else {
350  BOOST_CHECK(batchVerifier.badMessages.empty());
351  }
352 }
353 
354 static void Verify(std::vector<Message>& vec)
355 {
356  Verify(vec, false, false);
357  Verify(vec, true, false);
358  Verify(vec, false, true);
359  Verify(vec, true, true);
360 }
361 
362 BOOST_AUTO_TEST_CASE(batch_verifier_tests)
363 {
364  std::vector<Message> msgs;
365 
366  // distinct messages from distinct sources
367  AddMessage(msgs, 1, 1, 1, true);
368  AddMessage(msgs, 2, 2, 2, true);
369  AddMessage(msgs, 3, 3, 3, true);
370  Verify(msgs);
371 
372  // distinct messages from same source
373  AddMessage(msgs, 4, 4, 4, true);
374  AddMessage(msgs, 4, 5, 5, true);
375  AddMessage(msgs, 4, 6, 6, true);
376  Verify(msgs);
377 
378  // invalid sig
379  AddMessage(msgs, 7, 7, 7, false);
380  Verify(msgs);
381 
382  // same message as before, but from another source and with valid sig
383  AddMessage(msgs, 8, 8, 7, true);
384  Verify(msgs);
385 
386  // same message as before, but from another source and signed with another key
387  AddMessage(msgs, 9, 9, 7, true);
388  Verify(msgs);
389 
390  msgs.clear();
391  // same message, signed by multiple keys
392  AddMessage(msgs, 1, 1, 1, true);
393  AddMessage(msgs, 1, 2, 1, true);
394  AddMessage(msgs, 1, 3, 1, true);
395  AddMessage(msgs, 2, 4, 1, true);
396  AddMessage(msgs, 2, 5, 1, true);
397  AddMessage(msgs, 2, 6, 1, true);
398  Verify(msgs);
399 
400  // last message invalid from one source
401  AddMessage(msgs, 1, 7, 1, false);
402  Verify(msgs);
403 }
404 
BOOST_AUTO_TEST_CASE(bls_sig_tests)
Definition: bls_tests.cpp:18
BLSKey FromHex(const std::string &str)
Definition: bls_tests.cpp:239
std::vector< size_t > GetRandomElements(size_t m, size_t n)
Definition: bls_tests.cpp:51
std::vector< CBLSId > BLSIdVector
Definition: bls_wrapper.h:408
std::vector< CBLSPublicKey > BLSPublicKeyVector
Definition: bls_wrapper.h:410
std::shared_ptr< BLSVerificationVector > BLSVerificationVectorPtr
Definition: bls_wrapper.h:415
std::vector< CBLSSecretKey > BLSSecretKeyVector
Definition: bls_wrapper.h:411
std::vector< CBLSSignature > BLSSignatureVector
Definition: bls_wrapper.h:412
#define M(x)
const CChainParams & Params()
Return the currently selected parameters.
CBLSPublicKey ephemeralPubKey
Definition: bls_ies.h:17
unsigned char iv[16]
Definition: bls_ies.h:18
bool Decrypt(const CBLSSecretKey &secretKey, Object &objRet, int nVersion) const
Definition: bls_ies.h:58
bool Encrypt(const CBLSPublicKey &peerPubKey, const Object &obj, int nVersion)
Definition: bls_ies.h:47
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)
CBLSSignature Sign(const uint256 &hash) const
bool VerifyInsecure(const CBLSPublicKey &pubKey, const uint256 &hash) const
bool Recover(const std::vector< CBLSSignature > &sigs, const std::vector< CBLSId > &ids)
CBLSSecretKey AggregateSecretKeys(const BLSSecretKeyVector &secKeys, size_t start=0, size_t count=0, bool parallel=true)
Definition: bls_worker.cpp:675
bool VerifyContributionShare(const CBLSId &forId, const BLSVerificationVectorPtr &vvec, const CBLSSecretKey &skContribution)
Definition: bls_worker.cpp:775
CBLSPublicKey BuildPubKeyShare(const BLSVerificationVectorPtr &vvec, const CBLSId &id)
Definition: bls_worker.cpp:724
BLSVerificationVectorPtr BuildQuorumVerificationVector(const std::vector< BLSVerificationVectorPtr > &vvecs, size_t start=0, size_t count=0, bool parallel=true)
Definition: bls_worker.cpp:633
CBLSPublicKey AggregatePublicKeys(const BLSPublicKeyVector &pubKeys, size_t start=0, size_t count=0, bool parallel=true)
Definition: bls_worker.cpp:696
void Start()
Definition: bls_worker.cpp:63
void Stop()
Definition: bls_worker.cpp:71
bool GenerateContributions(int threshold, const BLSIdVector &ids, BLSVerificationVectorPtr &vvecRet, BLSSecretKeyVector &skShares)
Definition: bls_worker.cpp:77
bool IsValid() const
Definition: bls_wrapper.h:87
Fast randomness source.
Definition: random.h:107
unsigned char * begin()
Definition: uint256.h:63
256-bit opaque blob.
Definition: uint256.h:138
BOOST_AUTO_TEST_SUITE_END()
Optional< CBLSSecretKey > DecodeSecret(const CChainParams &params, const std::string &keyStr)
Definition: key_io.cpp:63
std::string EncodeSecret(const CChainParams &params, const CBLSSecretKey &key)
Definition: key_io.cpp:50
Optional< CBLSPublicKey > DecodePublic(const CChainParams &params, const std::string &keyStr)
Definition: key_io.cpp:68
std::string EncodePublic(const CChainParams &params, const CBLSPublicKey &pk)
Definition: key_io.cpp:55
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK(expr)
Definition: object.cpp:17
void GetRandBytes(unsigned char *buf, int num) noexcept
Overall design of the RNG and entropy sources.
Definition: random.cpp:579
uint256 GetRandHash() noexcept
Definition: random.cpp:596
void Shuffle(I first, I last, R &&rng)
More efficient than using std::shuffle on a FastRandomContext.
Definition: random.h:217
Basic testing setup.
Definition: test_pivx.h:51
CBLSSecretKey sk
Definition: bls_tests.cpp:70
CBLSPublicKey pk
Definition: bls_tests.cpp:71
CBLSSecretKey skShare
Definition: bls_tests.cpp:67
Member(const CBLSId &_id)
Definition: bls_tests.cpp:73
BLSVerificationVectorPtr vecP
Definition: bls_tests.cpp:65
CBLSId id
Definition: bls_dkg.cpp:13
CBLSIESMultiRecipientObjects< CBLSSecretKey > contributions
Definition: bls_tests.cpp:66
uint32_t msgId
Definition: bls_tests.cpp:300
CBLSPublicKey pk
Definition: bls_tests.cpp:303
bool valid
Definition: bls_tests.cpp:305
CBLSSignature sig
Definition: bls_tests.cpp:304
CBLSSecretKey sk
Definition: bls_tests.cpp:302
uint32_t sourceId
Definition: bls_tests.cpp:299
uint256 msgHash
Definition: bls_tests.cpp:301
uint256 uint256S(const char *str)
Definition: uint256.h:157
std::vector< unsigned char > ParseHex(const char *psz)