Skip to content

Commit

Permalink
Add algorithm metadata to chain upon initial main key exchange
Browse files Browse the repository at this point in the history
  • Loading branch information
WildFireFlum authored and Pankaj committed Oct 25, 2022
1 parent 370bca0 commit d746272
Show file tree
Hide file tree
Showing 23 changed files with 153 additions and 86 deletions.
23 changes: 21 additions & 2 deletions bftengine/include/bftengine/CryptoManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "ReplicaConfig.hpp"
#include "IKeyExchanger.hpp"
#include "Logger.hpp"
#include "crypto/crypto.h"

namespace bftEngine {
typedef std::int64_t SeqNum; // TODO [TK] redefinition
Expand Down Expand Up @@ -51,11 +52,29 @@ class CryptoManager : public IKeyExchanger, public IMultiSigKeyGenerator {
std::shared_ptr<IThresholdVerifier> thresholdVerifierForOptimisticCommit(const SeqNum sn) const {
return get(sn)->thresholdVerifierForOptimisticCommit_;
}

std::unique_ptr<Cryptosystem>& getLatestCryptoSystem() const { return cryptoSystems_.rbegin()->second->cryptosys_; }

/**
* @return An algorithm identifier for the latest threshold signature scheme
*/
concord::crypto::SignatureAlgorithm getLatestSignatureAlgorithm() const {
const std::unordered_map<std::string, concord::crypto::SignatureAlgorithm> typeToAlgorithm{
{MULTISIG_BLS_SCHEME, concord::crypto::SignatureAlgorithm::BLS},
{THRESHOLD_BLS_SCHEME, concord::crypto::SignatureAlgorithm::BLS},
{MULTISIG_EDDSA_SCHEME, concord::crypto::SignatureAlgorithm::EdDSA},
};
auto currentType = getLatestCryptoSystem()->getType();
return typeToAlgorithm.at(currentType);
}

// IMultiSigKeyGenerator methods
std::pair<std::string, std::string> generateMultisigKeyPair() override {
std::tuple<std::string, std::string, concord::crypto::SignatureAlgorithm> generateMultisigKeyPair() override {
LOG_INFO(logger(), "Generating new multisig key pair");
return cryptoSystems_.rbegin()->second->cryptosys_->generateNewKeyPair();
auto [priv, pub] = getLatestCryptoSystem()->generateNewKeyPair();
return {priv, pub, getLatestSignatureAlgorithm()};
}

// IKeyExchanger methods
// onPrivateKeyExchange and onPublicKeyExchange callbacks for a given checkpoint may be called in a different order.
// Therefore the first called will create a CryptoSys
Expand Down
4 changes: 3 additions & 1 deletion bftengine/include/bftengine/IKeyExchanger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "crypto.hpp"
#include <string>
#include <cstdint>
#include <tuple>
#include <crypto/crypto.h>

// Interface for objects that need to be notified on key rotation
class IKeyExchanger {
Expand All @@ -25,7 +27,7 @@ class IKeyExchanger {
class IMultiSigKeyGenerator {
public:
virtual ~IMultiSigKeyGenerator() {}
virtual std::pair<std::string, std::string> generateMultisigKeyPair() = 0;
virtual std::tuple<std::string, std::string, concord::crypto::SignatureAlgorithm> generateMultisigKeyPair() = 0;
};

class IClientPublicKeyStore {
Expand Down
9 changes: 7 additions & 2 deletions bftengine/include/bftengine/KeyExchangeManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "SysConsts.hpp"
#include "crypto.hpp"
#include <future>

namespace bftEngine::impl {

class IInternalBFTClient;
Expand All @@ -30,7 +31,7 @@ class KeyExchangeManager {
public:
void exchangeTlsKeys(const SeqNum& bft_sn);
// Generates and publish key to consensus
void sendKeyExchange(const SeqNum&);
void generateConsensusKeyAndSendInternalClientMsg(const SeqNum& sn);
// Send the current main public key of the replica to consensus
void sendMainPublicKey();
// Generates and publish the first replica's key,
Expand All @@ -48,7 +49,7 @@ class KeyExchangeManager {
uint32_t liveClusterSize = ReplicaConfig::instance().waitForFullCommOnStartup ? clusterSize_ : quorumSize_;
bool exchange_self_keys = publicKeys_.keyExists(ReplicaConfig::instance().replicaId);
return ReplicaConfig::instance().getkeyExchangeOnStart()
? (publicKeys_.numOfExchangedReplicas() >= liveClusterSize - 1) && exchange_self_keys
? (publicKeys_.numOfExchangedReplicas() + 1 >= liveClusterSize) && exchange_self_keys
: true;
}
const std::string kInitialKeyExchangeCid = "KEY-EXCHANGE-";
Expand Down Expand Up @@ -92,11 +93,15 @@ class KeyExchangeManager {
std::string cid;
// seqnum of key exchange request
SeqNum sn;
// Key algorithm
concord::crypto::SignatureAlgorithm algorithm;

void clear() {
priv.clear();
pub.clear();
cid.clear();
sn = 0;
algorithm = concord::crypto::SignatureAlgorithm::Uninitialized;
}
} generated;
// seqnum -> private key
Expand Down
8 changes: 6 additions & 2 deletions bftengine/include/bftengine/KeyExchangeMsg.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ struct KeyExchangeMsg : public concord::serialize::SerializableFactory<KeyExchan
uint16_t repID;
uint64_t generated_sn;
uint64_t epoch;
uint16_t algorithm;

std::string toString() const {
std::stringstream ss;
ss << "pubkey [" << pubkey << "] replica id [" << repID << "] generate sequence number [" << generated_sn
<< "] epoch [" << epoch << "]";
<< "] epoch [" << epoch << "]"
<< " algorithm [" << algorithm << "]";
return ss.str();
}
static KeyExchangeMsg deserializeMsg(const char* serializedMsg, const int& size) {
Expand All @@ -38,19 +40,21 @@ struct KeyExchangeMsg : public concord::serialize::SerializableFactory<KeyExchan
}

protected:
const std::string getVersion() const override { return "1"; }
const std::string getVersion() const override { return "2"; }
void serializeDataMembers(std::ostream& outStream) const override {
serialize(outStream, op);
serialize(outStream, pubkey);
serialize(outStream, repID);
serialize(outStream, generated_sn);
serialize(outStream, epoch);
serialize(outStream, algorithm);
}
void deserializeDataMembers(std::istream& inStream) override {
deserialize(inStream, op);
deserialize(inStream, pubkey);
deserialize(inStream, repID);
deserialize(inStream, generated_sn);
deserialize(inStream, epoch);
deserialize(inStream, algorithm);
}
};
4 changes: 4 additions & 0 deletions bftengine/src/bftengine/CollectorOfThresholdSignatures.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ class CollectorOfThresholdSignatures {
RepInfo info = {partialSigMsg, SigState::Unknown};
replicasInfo[repId] = info;

/*if ((((InternalReplicaApi*)this->context)->getReplicaConfig().numReplicas) == 1) {
return true;
}*/

numberOfUnknownSignatures++;
LOG_TRACE(THRESHSIGN_LOG,
KVLOG(partialSigMsg->seqNumber(), partialSigMsg->viewNumber(), numberOfUnknownSignatures));
Expand Down
8 changes: 8 additions & 0 deletions bftengine/src/bftengine/InternalBFTClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,11 @@ uint64_t InternalBFTClient::sendRequest(uint64_t flags,
LOG_DEBUG(GL, "Sent internal consensus: seq num [" << sn << "] client id [" << getClientId() << "]");
return sn;
}
uint64_t IInternalBFTClient::sendRequest(uint64_t flags,
const concord::serialize::Serializable& msg,
const string& cid) {
std::stringstream ss;
concord::serialize::Serializable::serialize(ss, msg);
auto strMsg = ss.str();
return sendRequest(flags, strMsg.size(), strMsg.c_str(), cid);
}
1 change: 1 addition & 0 deletions bftengine/src/bftengine/InternalBFTClient.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class IInternalBFTClient {
// Note: users should be aware that if they push a request from the consumer/replica thread(s), the given callback
// will be called in the same thread.
virtual uint64_t sendRequest(uint64_t flags, uint32_t requestLength, const char* request, const std::string& cid) = 0;
uint64_t sendRequest(uint64_t flags, const concord::serialize::Serializable& msg, const std::string& cid);
virtual uint64_t sendRequest(uint64_t flags,
uint32_t requestLength,
const char* request,
Expand Down
71 changes: 31 additions & 40 deletions bftengine/src/bftengine/KeyExchangeManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ std::string KeyExchangeManager::onKeyExchange(const KeyExchangeMsg& kemsg,
auto liveQuorumSize = ReplicaConfig::instance().waitForFullCommOnStartup ? clusterSize_ : quorumSize_;
if (ReplicaConfig::instance().getkeyExchangeOnStart() && (publicKeys_.numOfExchangedReplicas() <= liveQuorumSize))
LOG_INFO(KEY_EX_LOG,
"Exchanged [" << publicKeys_.numOfExchangedReplicas() << "] out of [" << liveQuorumSize << "]");
"Exchanged [" << publicKeys_.numOfExchangedReplicas() << "] out of [" << liveQuorumSize << "]"
<< KVLOG(kemsg.repID));
if (!initial_exchange_ && exchanged()) {
initial_exchange_ = true;
if (ReplicaConfig::instance().getkeyExchangeOnStart() &&
Expand Down Expand Up @@ -221,7 +222,10 @@ void KeyExchangeManager::sendMainPublicKey() {
concord::messages::ReconfigurationRequest req;
req.sender = repID_;
req.command =
concord::messages::ReplicaMainKeyUpdate{repID_, SigManager::instance()->getPublicKeyOfVerifier(repID_), "hex"};
concord::messages::ReplicaMainKeyUpdate{repID_,
SigManager::instance()->getPublicKeyOfVerifier(repID_),
"hex",
static_cast<uint8_t>(SigManager::instance()->getMainKeyAlgorithm())};
// Mark this request as an internal one
std::vector<uint8_t> data_vec;
concord::messages::serialize(data_vec, req);
Expand All @@ -236,51 +240,37 @@ void KeyExchangeManager::sendMainPublicKey() {
LOG_INFO(KEY_EX_LOG, "Replica has published its main public key to the consensus");
}

void KeyExchangeManager::sendKeyExchange(const SeqNum& sn) {
void KeyExchangeManager::generateConsensusKeyAndSendInternalClientMsg(const SeqNum& sn) {
if (private_keys_.lastGeneratedSeqnum() && // if not initial
(sn - private_keys_.lastGeneratedSeqnum()) / checkpointWindowSize < 2) {
LOG_INFO(KEY_EX_LOG, "ignore request - already exchanged keys for seqnum: " << private_keys_.lastGeneratedSeqnum());
return;
}
KeyExchangeMsg msg;
if (!candidate_private_keys_.generated.cid.empty()) {
// In some cases, we may try to send another key exchange message before the previous one has been committed (i.e,
// initial key exchange after VC/ST, two consecutive key exchange commands). In this case, we want to reuse the old
// generated key-exchange message
LOG_INFO(KEY_EX_LOG, "we already have a candidate for this sequence number, trying to send it again");
msg.pubkey = candidate_private_keys_.generated.pub;
msg.repID = repID_;
SeqNum new_sn = sn;
if ((sn - candidate_private_keys_.generated.sn) / checkpointWindowSize < 2)
new_sn = candidate_private_keys_.generated.sn;
candidate_private_keys_.generated.sn = new_sn;
msg.generated_sn = candidate_private_keys_.generated.sn;
msg.epoch = EpochManager::instance().getSelfEpochNumber();
std::stringstream ss;
concord::serialize::Serializable::serialize(ss, msg);
auto strMsg = ss.str();
client_->sendRequest(
bftEngine::KEY_EXCHANGE_FLAG, strMsg.size(), strMsg.c_str(), candidate_private_keys_.generated.cid);
metrics_->sent_key_exchange_counter++;
LOG_INFO(KEY_EX_LOG,
"ignore request - already exchanged consensus keys for seqnum: " << private_keys_.lastGeneratedSeqnum());
return;
}

auto cid = generateCid(kInitialKeyExchangeCid);
auto [prv, pub] = multiSigKeyHdlr_->generateMultisigKeyPair();
candidate_private_keys_.generated.priv = prv;
candidate_private_keys_.generated.pub = pub;
candidate_private_keys_.generated.cid = cid;
candidate_private_keys_.generated.sn = sn;

LOG_INFO(KEY_EX_LOG, "Sending key exchange :" << KVLOG(cid, pub));
msg.pubkey = pub;
auto& candidate = candidate_private_keys_.generated;
bool generateNewPair = sn != candidate.sn || candidate.cid.empty();
KeyExchangeMsg msg;
msg.repID = repID_;
msg.generated_sn = sn;
msg.epoch = EpochManager::instance().getSelfEpochNumber();
std::stringstream ss;
concord::serialize::Serializable::serialize(ss, msg);
auto strMsg = ss.str();
client_->sendRequest(bftEngine::KEY_EXCHANGE_FLAG, strMsg.size(), strMsg.c_str(), cid);

if (generateNewPair) {
auto cid = generateCid(kInitialKeyExchangeCid);
auto [prv, pub, algorithm] = multiSigKeyHdlr_->generateMultisigKeyPair();
candidate.algorithm = algorithm;
candidate.priv = prv;
candidate.pub = pub;
candidate.cid = cid;
candidate.sn = sn;
} else {
LOG_INFO(KEY_EX_LOG, "we already have a candidate for this sequence number, trying to send it again");
}

msg.pubkey = candidate.pub;
msg.algorithm = candidate.algorithm;
LOG_INFO(KEY_EX_LOG, "Sending consensus key exchange :" << KVLOG(candidate.cid, msg.pubkey, msg.algorithm));
client_->sendRequest(bftEngine::KEY_EXCHANGE_FLAG, msg, candidate.cid);
metrics_->sent_key_exchange_counter++;
}

Expand Down Expand Up @@ -339,7 +329,8 @@ void KeyExchangeManager::sendInitialKey(const ReplicaImp* repImpInstance, const
} else {
waitForFullCommunication();
}
sendKeyExchange(s);

generateConsensusKeyAndSendInternalClientMsg(s);
metrics_->sent_key_exchange_on_start_status.Get().Set("True");
}

Expand Down
6 changes: 5 additions & 1 deletion bftengine/src/bftengine/ReplicaImp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2193,14 +2193,18 @@ void ReplicaImp::onFastPathCommitCombinedSigSucceeded(SeqNum seqNumber,

SeqNumInfo &seqNumInfo = mainLog->get(seqNumber);

FullCommitProofMsg *fcp = seqNumInfo.getFastPathFullCommitProofMsg();
// One replica produces FullCommitProofMsg Immediately
ConcordAssert(fcp == nullptr || config_.numReplicas != 1);

seqNumInfo.onCompletionOfCommitSignaturesProcessing(
seqNumber, view, cPath, combinedSig, combinedSigLen, span_context);

ConcordAssert(seqNumInfo.hasPrePrepareMsg());
seqNumInfo.forceComplete(); // TODO(GG): remove forceComplete() (we know that seqNumInfo is committed because
// of the FullCommitProofMsg message)

FullCommitProofMsg *fcp = seqNumInfo.getFastPathFullCommitProofMsg();
fcp = seqNumInfo.getFastPathFullCommitProofMsg();
ConcordAssert(fcp != nullptr);

if (ps_) {
Expand Down
4 changes: 2 additions & 2 deletions bftengine/src/bftengine/SeqNumInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,14 +387,14 @@ bool SeqNumInfo::addFastPathPartialCommitMsg(PartialCommitProofMsg* m) {

bool SeqNumInfo::addFastPathFullCommitMsg(FullCommitProofMsg* m, bool directAdd) {
ConcordAssert(m != nullptr);

if (hasFastPathFullCommitProof()) return false;

PartialCommitProofMsg* myPCP = getFastPathSelfPartialCommitProofMsg();

if (myPCP == nullptr) {
// TODO(GG): can be improved (we can keep the FullCommitProof message until myPCP!=nullptr
LOG_WARN(CNSUS, "FullCommitProofMsg arrived before PrePrepare. TODO(GG): should be handled to avoid delays. ");
LOG_WARN(CNSUS,
"FullCommitProofMsg arrived before PartialCommitProofMsg. TODO(GG): should be handled to avoid delays. ");
return false;
}

Expand Down
2 changes: 2 additions & 0 deletions bftengine/src/bftengine/SigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,5 +272,7 @@ void SigManager::setClientPublicKey(const std::string& key, PrincipalId id, KeyF
}
bool SigManager::hasVerifier(PrincipalId pid) { return verifiers_.find(pid) != verifiers_.end(); }

concord::crypto::SignatureAlgorithm SigManager::getMainKeyAlgorithm() const { return concord::crypto::EdDSA; }

} // namespace impl
} // namespace bftEngine
21 changes: 11 additions & 10 deletions bftengine/src/bftengine/SigManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ using concordMetrics::AtomicCounterHandle;
namespace bftEngine {
namespace impl {

using concord::crypto::KeyFormat;

class ReplicasInfo;

Expand All @@ -54,9 +53,9 @@ class SigManager {
static SigManager* init(ReplicaId myId,
const Key& mySigPrivateKey,
const std::set<std::pair<PrincipalId, const std::string>>& publicKeysOfReplicas,
KeyFormat replicasKeysFormat,
concord::util::crypto::KeyFormat replicasKeysFormat,
const std::set<std::pair<const std::string, std::set<uint16_t>>>* publicKeysOfClients,
KeyFormat clientsKeysFormat,
concord::util::crypto::KeyFormat clientsKeysFormat,
ReplicasInfo& replicasInfo);

// returns 0 if pid is invalid - caller might consider throwing an exception
Expand All @@ -69,13 +68,15 @@ class SigManager {
void SetAggregator(std::shared_ptr<concordMetrics::Aggregator> aggregator) {
metrics_component_.SetAggregator(aggregator);
}
void setClientPublicKey(const std::string& key, PrincipalId, KeyFormat);
void setClientPublicKey(const std::string& key, PrincipalId, concord::util::crypto::KeyFormat);
bool hasVerifier(PrincipalId pid);
SigManager(const SigManager&) = delete;
SigManager& operator=(const SigManager&) = delete;
SigManager(SigManager&&) = delete;
SigManager& operator=(SigManager&&) = delete;

concord::crypto::SignatureAlgorithm getMainKeyAlgorithm() const;

std::string getClientsPublicKeys();
std::string getPublicKeyOfVerifier(uint32_t id) const {
if (!verifiers_.count(id)) return std::string();
Expand All @@ -88,18 +89,18 @@ class SigManager {

SigManager(PrincipalId myId,
uint16_t numReplicas,
const std::pair<Key, KeyFormat>& mySigPrivateKey,
const std::vector<std::pair<Key, KeyFormat>>& publickeys,
const std::pair<Key, concord::util::crypto::KeyFormat>& mySigPrivateKey,
const std::vector<std::pair<Key, concord::util::crypto::KeyFormat>>& publickeys,
const std::map<PrincipalId, KeyIndex>& publicKeysMapping,
bool clientTransactionSigningEnabled,
ReplicasInfo& replicasInfo);

static SigManager* initImpl(ReplicaId myId,
const Key& mySigPrivateKey,
const std::set<std::pair<PrincipalId, const std::string>>& publicKeysOfReplicas,
KeyFormat replicasKeysFormat,
concord::util::crypto::KeyFormat replicasKeysFormat,
const std::set<std::pair<const std::string, std::set<uint16_t>>>* publicKeysOfClients,
KeyFormat clientsKeysFormat,
concord::util::crypto::KeyFormat clientsKeysFormat,
ReplicasInfo& replicasInfo);

const PrincipalId myId_;
Expand Down Expand Up @@ -130,9 +131,9 @@ class SigManager {
ReplicaId myId,
const Key& mySigPrivateKey,
const std::set<std::pair<PrincipalId, const std::string>>& publicKeysOfReplicas,
KeyFormat replicasKeysFormat,
concord::util::crypto::KeyFormat replicasKeysFormat,
const std::set<std::pair<const std::string, std::set<uint16_t>>>* publicKeysOfClients,
KeyFormat clientsKeysFormat,
concord::util::crypto::KeyFormat clientsKeysFormat,
ReplicasInfo& replicasInfo) {
return initImpl(myId,
mySigPrivateKey,
Expand Down
Loading

0 comments on commit d746272

Please sign in to comment.