Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

bls_batchverifier.h
Go to the documentation of this file.
1 // Copyright (c) 2018-2019 The Dash Core developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #ifndef DASH_CRYPTO_BLS_BATCHVERIFIER_H
6 #define DASH_CRYPTO_BLS_BATCHVERIFIER_H
7 
8 #include <bls/bls.h>
9 
10 #include <map>
11 #include <vector>
12 
13 template<typename SourceId, typename MessageId>
15 {
16 private:
17  struct Message {
18  MessageId msgId;
22  };
23 
24  typedef std::map<MessageId, Message> MessageMap;
25  typedef typename MessageMap::iterator MessageMapIterator;
26  typedef std::map<SourceId, std::vector<MessageMapIterator>> MessagesBySourceMap;
27 
30  size_t subBatchSize;
31 
34 
35 public:
36  std::set<SourceId> badSources;
37  std::set<MessageId> badMessages;
38 
39 public:
40  CBLSBatchVerifier(bool _secureVerification, bool _perMessageFallback, size_t _subBatchSize = 0) :
41  secureVerification(_secureVerification),
42  perMessageFallback(_perMessageFallback),
43  subBatchSize(_subBatchSize)
44  {
45  }
46 
47  void PushMessage(const SourceId& sourceId, const MessageId& msgId, const uint256& msgHash, const CBLSSignature& sig, const CBLSPublicKey& pubKey)
48  {
49  assert(sig.IsValid() && pubKey.IsValid());
50 
51  auto it = messages.emplace(msgId, Message{msgId, msgHash, sig, pubKey}).first;
52  messagesBySource[sourceId].emplace_back(it);
53 
54  if (subBatchSize != 0 && messages.size() >= subBatchSize) {
55  Verify();
56  ClearMessages();
57  }
58  }
59 
61  {
62  messages.clear();
63  messagesBySource.clear();
64  }
65 
66  size_t GetUniqueSourceCount() const
67  {
68  return messagesBySource.size();
69  }
70 
71  void Verify()
72  {
73  std::map<uint256, std::vector<MessageMapIterator>> byMessageHash;
74 
75  for (auto it = messages.begin(); it != messages.end(); ++it) {
76  byMessageHash[it->second.msgHash].emplace_back(it);
77  }
78 
79  if (VerifyBatch(byMessageHash)) {
80  // full batch is valid
81  return;
82  }
83 
84  // revert to per-source verification
85  for (const auto& p : messagesBySource) {
86  bool batchValid = false;
87 
88  // no need to verify it again if there was just one source
89  if (messagesBySource.size() != 1) {
90  byMessageHash.clear();
91  for (auto it = p.second.begin(); it != p.second.end(); ++it) {
92  byMessageHash[(*it)->second.msgHash].emplace_back(*it);
93  }
94  batchValid = VerifyBatch(byMessageHash);
95  }
96  if (!batchValid) {
97  badSources.emplace(p.first);
98 
99  if (perMessageFallback) {
100  // revert to per-message verification
101  if (p.second.size() == 1) {
102  // no need to re-verify a single message
103  badMessages.emplace(p.second[0]->second.msgId);
104  } else {
105  for (const auto& msgIt : p.second) {
106  if (badMessages.count(msgIt->first)) {
107  // same message might be invalid from different source, so no need to re-verify it
108  continue;
109  }
110 
111  const auto& msg = msgIt->second;
112  if (!msg.sig.VerifyInsecure(msg.pubKey, msg.msgHash)) {
113  badMessages.emplace(msg.msgId);
114  }
115  }
116  }
117  }
118  }
119  }
120  }
121 
122 private:
123  // All Verify methods take ownership of the passed byMessageHash map and thus might modify the map. This is to avoid
124  // unnecessary copies
125 
126  bool VerifyBatch(std::map<uint256, std::vector<MessageMapIterator>>& byMessageHash)
127  {
128  if (secureVerification) {
129  return VerifyBatchSecure(byMessageHash);
130  } else {
131  return VerifyBatchInsecure(byMessageHash);
132  }
133  }
134 
135  bool VerifyBatchInsecure(const std::map<uint256, std::vector<MessageMapIterator>>& byMessageHash)
136  {
137  CBLSSignature aggSig;
138  std::vector<uint256> msgHashes;
139  std::vector<CBLSPublicKey> pubKeys;
140  std::set<MessageId> dups;
141 
142  msgHashes.reserve(messages.size());
143  pubKeys.reserve(messages.size());
144 
145  for (const auto& p : byMessageHash) {
146  const auto& msgHash = p.first;
147 
148  CBLSPublicKey aggPubKey;
149 
150  for (const auto& msgIt : p.second) {
151  const auto& msg = msgIt->second;
152 
153  if (!dups.emplace(msg.msgId).second) {
154  continue;
155  }
156 
157  if (!aggSig.IsValid()) {
158  aggSig = msg.sig;
159  } else {
160  aggSig.AggregateInsecure(msg.sig);
161  }
162 
163  if (!aggPubKey.IsValid()) {
164  aggPubKey = msg.pubKey;
165  } else {
166  aggPubKey.AggregateInsecure(msg.pubKey);
167  }
168  }
169 
170  if (!aggPubKey.IsValid()) {
171  // only duplicates for this msgHash
172  continue;
173  }
174 
175  msgHashes.emplace_back(msgHash);
176  pubKeys.emplace_back(aggPubKey);
177  }
178 
179  if (msgHashes.empty()) {
180  return true;
181  }
182 
183  return aggSig.VerifyInsecureAggregated(pubKeys, msgHashes);
184  }
185 
186  bool VerifyBatchSecure(std::map<uint256, std::vector<MessageMapIterator>>& byMessageHash)
187  {
188  // Loop until the byMessageHash map is empty, which means that all messages were verified
189  // The secure form of verification will only aggregate one message for the same message hash, even if multiple
190  // exist (signed with different keys). This avoids the rogue public key attack.
191  // This is slower than the insecure form as it requires more pairings
192  while (!byMessageHash.empty()) {
193  if (!VerifyBatchSecureStep(byMessageHash)) {
194  return false;
195  }
196  }
197  return true;
198  }
199 
200  bool VerifyBatchSecureStep(std::map<uint256, std::vector<MessageMapIterator>>& byMessageHash)
201  {
202  CBLSSignature aggSig;
203  std::vector<uint256> msgHashes;
204  std::vector<CBLSPublicKey> pubKeys;
205  std::set<MessageId> dups;
206 
207  msgHashes.reserve(messages.size());
208  pubKeys.reserve(messages.size());
209 
210  for (auto it = byMessageHash.begin(); it != byMessageHash.end(); ) {
211  const auto& msgHash = it->first;
212  auto& messageIts = it->second;
213  const auto& msg = messageIts.back()->second;
214 
215  if (dups.emplace(msg.msgId).second) {
216  msgHashes.emplace_back(msgHash);
217  pubKeys.emplace_back(msg.pubKey);
218 
219  if (!aggSig.IsValid()) {
220  aggSig = msg.sig;
221  } else {
222  aggSig.AggregateInsecure(msg.sig);
223  }
224  }
225 
226  messageIts.pop_back();
227  if (messageIts.empty()) {
228  it = byMessageHash.erase(it);
229  } else {
230  ++it;
231  }
232  }
233 
234  assert(!msgHashes.empty());
235 
236  return aggSig.VerifyInsecureAggregated(pubKeys, msgHashes);
237  }
238 };
239 
240 #endif //DASH_CRYPTO_BLS_BATCHVERIFIER_H
void PushMessage(const SourceId &sourceId, const MessageId &msgId, const uint256 &msgHash, const CBLSSignature &sig, const CBLSPublicKey &pubKey)
std::set< MessageId > badMessages
bool VerifyBatch(std::map< uint256, std::vector< MessageMapIterator >> &byMessageHash)
bool VerifyBatchInsecure(const std::map< uint256, std::vector< MessageMapIterator >> &byMessageHash)
bool VerifyInsecureAggregated(const std::vector< CBLSPublicKey > &pubKeys, const std::vector< uint256 > &hashes) const
Definition: bls.cpp:348
bool VerifyBatchSecure(std::map< uint256, std::vector< MessageMapIterator >> &byMessageHash)
std::map< SourceId, std::vector< MessageMapIterator > > MessagesBySourceMap
std::map< MessageId, Message > MessageMap
size_t GetUniqueSourceCount() const
std::set< SourceId > badSources
MessagesBySourceMap messagesBySource
bool VerifyBatchSecureStep(std::map< uint256, std::vector< MessageMapIterator >> &byMessageHash)
256-bit opaque blob.
Definition: uint256.h:123
void AggregateInsecure(const CBLSPublicKey &o)
Definition: bls.cpp:191
void AggregateInsecure(const CBLSSignature &o)
Definition: bls.cpp:277
CBLSBatchVerifier(bool _secureVerification, bool _perMessageFallback, size_t _subBatchSize=0)
MessageMap::iterator MessageMapIterator
bool IsValid() const
Definition: bls.h:94
Released under the MIT license