From b6346a2f68b3d8c3d8045b7b71697e3e345b4a9a Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Thu, 17 Jan 2019 15:57:38 +0100 Subject: [PATCH] Implement CBLSInsecureBatchVerifier for convenient batch verification --- src/Makefile.am | 1 + src/bls/bls_batchverifier.h | 148 ++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 src/bls/bls_batchverifier.h diff --git a/src/Makefile.am b/src/Makefile.am index 0b61f12adb801..409bbf7073b91 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -445,6 +445,7 @@ libdash_common_a_SOURCES = \ libdash_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libdash_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libdash_util_a_SOURCES = \ + bls/bls_batchverifier.h \ bls/bls_ies.cpp \ bls/bls_ies.h \ bls/bls_worker.cpp \ diff --git a/src/bls/bls_batchverifier.h b/src/bls/bls_batchverifier.h new file mode 100644 index 0000000000000..47a23360560e7 --- /dev/null +++ b/src/bls/bls_batchverifier.h @@ -0,0 +1,148 @@ +// Copyright (c) 2018 The Dash Core developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DASH_CRYPTO_BLS_BATCHVERIFIER_H +#define DASH_CRYPTO_BLS_BATCHVERIFIER_H + +#include "bls.h" + +#include +#include + +template +class CBLSInsecureBatchVerifier +{ +private: + struct Message { + MessageId msgId; + uint256 msgHash; + CBLSSignature sig; + CBLSPublicKey pubKey; + }; + + typedef std::map MessageMap; + typedef typename MessageMap::iterator MessageMapIterator; + typedef std::map> MessagesBySourceMap; + + MessageMap messages; + MessagesBySourceMap messagesBySource; + +public: + std::set badSources; + std::set badMessages; + +public: + void PushMessage(const SourceId& sourceId, const MessageId& msgId, const uint256& msgHash, const CBLSSignature& sig, const CBLSPublicKey& pubKey) + { + assert(sig.IsValid() && pubKey.IsValid()); + + auto it = messages.emplace(msgId, Message{msgId, msgHash, sig, pubKey}).first; + messagesBySource[sourceId].emplace_back(it); + } + + void Verify(bool perMessageFallback) + { + std::map> byMessageHash; + + for (auto it = messages.begin(); it != messages.end(); ++it) { + byMessageHash[it->second.msgHash].emplace_back(it); + } + + if (VerifyBatch(byMessageHash)) { + // full batch is valid + return; + } + + // revert to per-source verification + for (const auto& p : messagesBySource) { + bool batchValid = false; + + // no need to verify it again if there was just one source + if (messagesBySource.size() != 1) { + byMessageHash.clear(); + for (auto it = p.second.begin(); it != p.second.end(); ++it) { + byMessageHash[(*it)->second.msgHash].emplace_back(*it); + } + batchValid = VerifyBatch(byMessageHash); + } + if (!batchValid) { + badSources.emplace(p.first); + + if (perMessageFallback) { + // revert to per-message verification + if (p.second.size() == 1) { + // no need to re-verify a single message + badMessages.emplace(p.second[0]->second.msgId); + } else { + for (const auto& msgIt : p.second) { + if (badMessages.count(msgIt->first)) { + // same message might be invalid from different source, so no need to re-verify it + continue; + } + + const auto& msg = msgIt->second; + if (!msg.sig.VerifyInsecure(msg.pubKey, msg.msgHash)) { + badMessages.emplace(msg.msgId); + } + } + } + } + } + } + } + +private: + bool VerifyBatch(const std::map>& byMessageHash) + { + CBLSSignature aggSig; + std::vector msgHashes; + std::vector pubKeys; + std::set dups; + + msgHashes.reserve(messages.size()); + pubKeys.reserve(messages.size()); + + for (const auto& p : byMessageHash) { + const auto& msgHash = p.first; + + CBLSPublicKey aggPubKey; + + for (const auto& msgIt : p.second) { + const auto& msg = msgIt->second; + + if (!dups.emplace(msg.msgId).second) { + continue; + } + + if (!aggSig.IsValid()) { + aggSig = msg.sig; + } else { + aggSig.AggregateInsecure(msg.sig); + } + + if (!aggPubKey.IsValid()) { + aggPubKey = msg.pubKey; + } else { + aggPubKey.AggregateInsecure(msg.pubKey); + } + } + + if (!aggSig.IsValid()) { + // only duplicates for this msgHash + continue; + } + + msgHashes.emplace_back(msgHash); + pubKeys.emplace_back(aggPubKey); + } + + if (msgHashes.empty()) { + return true; + } + + return aggSig.VerifyInsecureAggregated(pubKeys, msgHashes); + } +}; + +#endif //DASH_CRYPTO_BLS_BATCHVERIFIER_H