Skip to content

Commit

Permalink
Add initial eddsa multisig signer implementation
Browse files Browse the repository at this point in the history
Integrated EdDSA multisig to conconrd-bft's key generation
and to commit path threshold signature collection
Added unittests for EdDSA multisig interface
  • Loading branch information
WildFireFlum authored and Pankaj committed Oct 25, 2022
1 parent 32a04c1 commit 4d27255
Show file tree
Hide file tree
Showing 30 changed files with 769 additions and 53 deletions.
11 changes: 7 additions & 4 deletions bftengine/src/bftengine/CollectorOfThresholdSignatures.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ class CollectorOfThresholdSignatures {
// TODO(GG): can utilize several threads (discuss with Alin)

const uint16_t bufferSize = (uint16_t)verifier->requiredLengthForSignedData();
size_t fullSignedDataLength = bufferSize;
std::vector<char> bufferForSigComputations(bufferSize);

const auto& span_context_of_last_message =
Expand All @@ -377,18 +378,20 @@ class CollectorOfThresholdSignatures {
std::unique_ptr<IThresholdAccumulator> acc{verifier->newAccumulator(false)};
for (uint16_t i = 0; i < reqDataItems; i++) acc->add(sigDataItems[i].sigBody, sigDataItems[i].sigLength);
acc->setExpectedDigest(reinterpret_cast<unsigned char*>(expectedDigest.content()), DIGEST_SIZE);
acc->getFullSignedData(bufferForSigComputations.data(), bufferSize);
fullSignedDataLength = acc->getFullSignedData(bufferForSigComputations.data(), bufferSize);
}

if (!verifier->verify((char*)&expectedDigest, sizeof(Digest), bufferForSigComputations.data(), bufferSize)) {
if (!verifier->verify(
(char*)&expectedDigest, sizeof(Digest), bufferForSigComputations.data(), fullSignedDataLength)) {
// if verification failed, use accumulator with share verification enabled.
// this still can succeed if there're enough valid shares.
// at least replica with bad signatures will be identified.
std::unique_ptr<IThresholdAccumulator> acc{verifier->newAccumulator(true)};
for (uint16_t i = 0; i < reqDataItems; i++) acc->add(sigDataItems[i].sigBody, sigDataItems[i].sigLength);
acc->setExpectedDigest(reinterpret_cast<unsigned char*>(expectedDigest.content()), DIGEST_SIZE);
acc->getFullSignedData(bufferForSigComputations.data(), bufferSize);
if (!verifier->verify((char*)&expectedDigest, sizeof(Digest), bufferForSigComputations.data(), bufferSize)) {
fullSignedDataLength = acc->getFullSignedData(bufferForSigComputations.data(), bufferSize);
if (!verifier->verify(
(char*)&expectedDigest, sizeof(Digest), bufferForSigComputations.data(), fullSignedDataLength)) {
// if verification failed again
// signer index starts with 1, therefore shareId-1
std::set<uint16_t> replicasWithBadSigs;
Expand Down
2 changes: 1 addition & 1 deletion bftengine/tests/messages/helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class IThresholdAccumulatorDummy : public IThresholdAccumulator {
void setExpectedDigest(const unsigned char *msg, int len) override {}
bool hasShareVerificationEnabled() const override { return true; }
int getNumValidShares() const override { return 0; }
void getFullSignedData(char *outThreshSig, int threshSigLen) override {}
size_t getFullSignedData(char *outThreshSig, int threshSigLen) override {}
std::set<ShareID> getInvalidShareIds() const override { return {}; }
};

Expand Down
2 changes: 1 addition & 1 deletion threshsign/include/threshsign/IThresholdAccumulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,5 @@ class IThresholdAccumulator {
*
* TODO: rename to getThresholdSignature()
*/
virtual void getFullSignedData(char* outThreshSig, int threshSigLen) = 0;
virtual size_t getFullSignedData(char* outThreshSig, int threshSigLen) = 0;
};
18 changes: 9 additions & 9 deletions threshsign/include/threshsign/ThresholdSignaturesTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@

/**
* The current implementation sends the share ID (i.e., the signer ID) with the share signature.
* Here we define its data type so that we can easily support an arbitray number of signers.
* Here we define its data type so that we can easily support an arbitrary number of signers.
*
* WARNING: Do not set this to an unsigned type! You will run into C/C++ signed vs unsigned problems
* (see http://soundsoftware.ac.uk/c-pitfall-unsigned)
*/
typedef int ShareID;
typedef ShareID NumSharesType;
using ShareID = int;
using NumSharesType = ShareID;

#define MAX_NUM_OF_SHARES 2048

#define MULTISIG_BLS_SCHEME "multisig-bls"
#define THRESHOLD_BLS_SCHEME "threshold-bls"
constexpr int MAX_NUM_OF_SHARES = 2048;
constexpr const char* MULTISIG_BLS_SCHEME = "multisig-bls";
constexpr const char* THRESHOLD_BLS_SCHEME = "threshold-bls";
constexpr const char* MULTISIG_EDDSA_SCHEME = "multisig-eddsa";

class IThresholdFactory;
class IThresholdSigner;
Expand Down Expand Up @@ -297,13 +297,13 @@ class Cryptosystem {
* Get a list of supported cryptosystem types and descriptions of what
* type-specific parameters they require.
*
* @param ret A vector to which to append this functions output, as pairs of
* @return A vector to which to append this functions output, as pairs of
* strings. The first string in each pair is the name for a
* supported cryptosystem type, and the second string is a
* description of what the type-specific subtype parameter
* specifies for that cryptosytem type.
*/
static void getAvailableCryptosystemTypes(std::vector<std::pair<std::string, std::string>>& ret);
static const std::vector<std::pair<std::string, std::string>>& getAvailableCryptosystemTypes();
/**
* Output configuration to stream
*/
Expand Down
3 changes: 2 additions & 1 deletion threshsign/include/threshsign/bls/relic/BlsAccumulatorBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,9 @@ class BlsAccumulatorBase : public ThresholdAccumulatorBase<BlsPublicKey, G1T, Bl
*
* @param buf buffer to store the threshold signature
* @param len capacity of the buffer
* @return The amount of occupied bytes in the buffer
*/
virtual void sigToBytes(unsigned char* buf, int len) const { threshSig.toBytes(buf, len); }
virtual size_t sigToBytes(unsigned char* buf, int len) const { return threshSig.toBytes(buf, len); }

virtual void aggregateShares() = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ class BlsMultisigAccumulator : public BlsAccumulatorBase {

// IThresholdAccumulator overloads.
public:
virtual void getFullSignedData(char* outThreshSig, int threshSigLen);
virtual size_t getFullSignedData(char* outThreshSig, int threshSigLen);

virtual bool hasShareVerificationEnabled() const { return shareVerificationEnabled; }

// Used internally or for testing
public:
virtual void aggregateShares();

virtual void sigToBytes(unsigned char* buf, int len) const;
virtual size_t sigToBytes(unsigned char* buf, int len) const;
};

} /* namespace Relic */
Expand Down
2 changes: 1 addition & 1 deletion threshsign/include/threshsign/bls/relic/BlsNumTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ class G1T {
public:
int getByteCount() const { return g1_size_bin(n, 1); }

void toBytes(unsigned char *buf, int size) const;
size_t toBytes(unsigned char *buf, int size) const;
void fromBytes(const unsigned char *buf, int size);

std::string toString() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ class BlsThresholdAccumulator : public BlsAccumulatorBase {

// IThresholdAccumulator overloads.
public:
virtual void getFullSignedData(char* outThreshSig, int threshSigLen) {
virtual size_t getFullSignedData(char* outThreshSig, int threshSigLen) {
computeLagrangeCoeff();
exponentiateLagrangeCoeff();
aggregateShares();

sigToBytes(reinterpret_cast<unsigned char*>(outThreshSig), threshSigLen);
return sigToBytes(reinterpret_cast<unsigned char*>(outThreshSig), threshSigLen);
}

virtual bool hasShareVerificationEnabled() const { return shareVerificationEnabled; }
Expand Down
21 changes: 21 additions & 0 deletions threshsign/include/threshsign/eddsa/EdDSAMultisigFactory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Created by yflum on 26/04/2022.
//
#pragma once

#include "../IThresholdFactory.h"
#include "../IThresholdSigner.h"
#include "../IThresholdVerifier.h"

class EdDSAMultisigFactory : public IThresholdFactory {
public:
IThresholdVerifier *newVerifier(ShareID reqSigners,
ShareID totalSigners,
const char *publicKeyStr,
const std::vector<std::string> &verifKeysHex) const override;
IThresholdSigner *newSigner(ShareID id, const char *secretKeyStr) const override;
std::tuple<std::vector<IThresholdSigner *>, IThresholdVerifier *> newRandomSigners(
NumSharesType reqSigners, NumSharesType numSigners) const override;
std::pair<std::unique_ptr<IShareSecretKey>, std::unique_ptr<IShareVerificationKey>> newKeyPair() const override;
~EdDSAMultisigFactory() override = default;
};
24 changes: 24 additions & 0 deletions threshsign/include/threshsign/eddsa/EdDSAMultisigSigner.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// Created by yflum on 26/04/2022.
//
#pragma once

#include "../IThresholdSigner.h"
#include "SSLEdDSAPrivateKey.h"
#include "SSLEdDSAPublicKey.h"

class EdDSAMultisigSigner : public IThresholdSigner {
public:
EdDSAMultisigSigner(const SSLEdDSAPrivateKey &privateKey, const uint32_t id);
int requiredLengthForSignedData() const override;

void signData(const char *hash, int hashLen, char *outSig, int outSigLen) override;
const IShareSecretKey &getShareSecretKey() const override;
const IShareVerificationKey &getShareVerificationKey() const override;
~EdDSAMultisigSigner() override = default;

private:
SSLEdDSAPrivateKey privateKey_;
SSLEdDSAPublicKey publicKey_;
uint32_t id_;
};
45 changes: 45 additions & 0 deletions threshsign/include/threshsign/eddsa/EdDSAMultisigVerifier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// Created by yflum on 27/04/2022.
//
#pragma once
#include "threshsign/IThresholdVerifier.h"
#include "SSLEdDSAPublicKey.h"
#include "SingleEdDSASignature.h"

class EdDSAMultisigVerifier;

class EdDSASignatureAccumulator : public IThresholdAccumulator {
public:
EdDSASignatureAccumulator(const EdDSAMultisigVerifier &verifier);
int add(const char *sigShareWithId, int len) override;
void setExpectedDigest(const unsigned char *msg, int len) override;
size_t getFullSignedData(char *outThreshSig, int threshSigLen) override;
bool hasShareVerificationEnabled() const override;
int getNumValidShares() const override;
std::set<ShareID> getInvalidShareIds() const override;

private:
std::unordered_map<uint32_t, SingleEdDSASignature> signatures_;
std::string msgDigest_;
// const EdDSAMultisigVerifier& verifier_;
};

class EdDSAMultisigVerifier : public IThresholdVerifier {
public:
EdDSAMultisigVerifier(const std::vector<SSLEdDSAPublicKey> &publicKeys,
const size_t signersCount,
const size_t threshold);
IThresholdAccumulator *newAccumulator(bool withShareVerification) const override;

bool verify(const char *msg, int msgLen, const char *sig, int sigLen) const override;

int requiredLengthForSignedData() const override;
const IPublicKey &getPublicKey() const override;
const IShareVerificationKey &getShareVerificationKey(ShareID signer) const override;
~EdDSAMultisigVerifier() override = default;

private:
std::vector<SSLEdDSAPublicKey> publicKeys_;
const size_t signersCount_;
const size_t threshold_;
};
30 changes: 30 additions & 0 deletions threshsign/include/threshsign/eddsa/SSLEdDSAPrivateKey.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// Created by yflum on 26/04/2022.
//

#pragma once
#include "../ISecretKey.h"
#include <array>

class SSLEdDSAPrivateKey : public IShareSecretKey {
public:
static constexpr const size_t KeyByteSize = 32;
static constexpr const size_t SignatureByteSize = 64;
using EdDSAPrivateKeyBytes = std::array<uint8_t, KeyByteSize>;
using EdDSASignatureBytes = std::array<uint8_t, SignatureByteSize>;

SSLEdDSAPrivateKey(const EdDSAPrivateKeyBytes& bytes);
~SSLEdDSAPrivateKey() override = default;

std::string sign(const std::string& message) const;
std::string sign(const uint8_t* msg, size_t len) const;
void sign(const uint8_t* msg, size_t len, uint8_t* signature, size_t& signatureLength) const;
std::string toString() const override;

static SSLEdDSAPrivateKey fromHexString(const std::string& hexString);

private:
SSLEdDSAPrivateKey() = default;

EdDSAPrivateKeyBytes bytes_;
};
29 changes: 29 additions & 0 deletions threshsign/include/threshsign/eddsa/SSLEdDSAPublicKey.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// Created by yflum on 26/04/2022.
//
#pragma once
#include "../IPublicKey.h"
#include <array>

class SSLEdDSAPublicKey : public IShareVerificationKey {
public:
static constexpr const size_t KeyByteSize = 32;
using EdDSAPublicKeyBytes = std::array<uint8_t, KeyByteSize>;

SSLEdDSAPublicKey(const EdDSAPublicKeyBytes& bytes);
~SSLEdDSAPublicKey() override = default;

std::string serialize() const;
bool verify(const uint8_t* message,
const size_t messageLen,
const uint8_t* signature,
const size_t signatureLen) const;
bool verify(const std::string& message, const std::string& signature) const;
std::string toString() const override;

static SSLEdDSAPublicKey fromHexString(const std::string& hexString);

private:
SSLEdDSAPublicKey() = default;
EdDSAPublicKeyBytes bytes_;
};
19 changes: 19 additions & 0 deletions threshsign/include/threshsign/eddsa/SingleEdDSASignature.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Concord
//
// Copyright (c) 2018-2022 VMware, Inc. All Rights Reserved.
//
// This product is licensed to you under the Apache 2.0 license (the "License").
// You may not use this product except in compliance with the Apache 2.0 License.
//
// This product may include a number of subcomponents with separate copyright
// notices and license terms. Your use of these subcomponents is subject to the
// terms and conditions of the subcomponent's license, as noted in the
// LICENSE file.
#pragma once
#include <array>
#include <cstdint>

struct SingleEdDSASignature {
uint64_t id;
std::array<uint8_t, 64> signatureBytes;
};
7 changes: 6 additions & 1 deletion threshsign/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ set(common_source_files
IThresholdVerifier.cpp
VectorOfShares.cpp
ThresholdSignaturesTypes.cpp
)
# TODO: create a separate target
eddsa/EdDSAMultisigFactory.cpp
eddsa/SSLEdDSAPublicKey.cpp
eddsa/SSLEdDSAPrivateKey.cpp
eddsa/EdDSAMultisigSigner.cpp
eddsa/EdDSAMultisigVerifier.cpp)

add_library(common OBJECT ${common_source_files})

Expand Down
Loading

0 comments on commit 4d27255

Please sign in to comment.