Skip to content

Commit

Permalink
[Tests] Add unit test for DKG using wrapper/worker
Browse files Browse the repository at this point in the history
  • Loading branch information
random-zebra committed Jul 28, 2021
1 parent 5d7182d commit 5a6d14e
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 0 deletions.
33 changes: 33 additions & 0 deletions src/bls/bls_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,39 @@ CBLSSignature CBLSSecretKey::Sign(const uint256& hash) const
return sigRet;
}

bool CBLSSecretKey::Recover(const std::vector<CBLSSecretKey>& keys, const std::vector<CBLSId>& ids)
{
fValid = false;
cachedHash.SetNull();

if (keys.empty() || ids.empty() || keys.size() != ids.size()) {
return false;
}

std::vector<bls::PrivateKey> keysVec;
std::vector<bls::Bytes> idsVec;
keysVec.reserve(keys.size());
idsVec.reserve(keys.size());

for (size_t i = 0; i < keys.size(); i++) {
if (!keys[i].IsValid() || !ids[i].IsValid()) {
return false;
}
keysVec.emplace_back(keys[i].impl);
idsVec.emplace_back(ids[i].impl.begin(), ids[i].impl.size());
}

try {
impl = bls::Threshold::PrivateKeyRecover(keysVec, idsVec);
} catch (...) {
return false;
}

fValid = true;
cachedHash.SetNull();
return true;
}

void CBLSPublicKey::AggregateInsecure(const CBLSPublicKey& o)
{
assert(IsValid() && o.IsValid());
Expand Down
1 change: 1 addition & 0 deletions src/bls/bls_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ class CBLSSecretKey : public CBLSWrapper<bls::PrivateKey, BLS_CURVE_SECKEY_SIZE,

CBLSPublicKey GetPublicKey() const;
CBLSSignature Sign(const uint256& hash) const;
bool Recover(const std::vector<CBLSSecretKey>& keys, const std::vector<CBLSId>& ids);
};

class CBLSPublicKey : public CBLSWrapper<bls::G1Element, BLS_CURVE_PUBKEY_SIZE, CBLSPublicKey>
Expand Down
110 changes: 110 additions & 0 deletions src/test/bls_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "test/test_pivx.h"
#include "bls/bls_worker.h"
#include "bls/bls_wrapper.h"

#include <boost/test/unit_test.hpp>
Expand Down Expand Up @@ -51,4 +52,113 @@ BOOST_AUTO_TEST_CASE(bls_sig_tests)
BOOST_CHECK(!sig2.VerifyInsecure(sk1.GetPublicKey(), msgHash2));
}

static BLSIdVector GetRandomBLSIds(size_t n)
{
BLSIdVector v;
for (size_t i = 0; i < n; i++) {
v.emplace_back(GetRandHash());
}
return v;
}

std::vector<size_t> GetRandomElements(size_t m, size_t n)
{
assert(m <= n);
std::vector<size_t> idxs;
for (size_t i = 0; i < n; i++) {
idxs.emplace_back(i);
}
std::random_shuffle(idxs.begin(), idxs.end());
return std::vector<size_t>(idxs.begin(), idxs.begin() + m);
}

struct Member
{
CBLSId id;
BLSVerificationVectorPtr vecP;
BLSSecretKeyVector contributions;
CBLSSecretKey skShare;

Member(const CBLSId& _id): id(_id) {}
};

BOOST_AUTO_TEST_CASE(bls_dkg)
{
CBLSWorker worker;
size_t N = 20; // quorum size
size_t M = 12; // threshold
BLSSecretKeyVector allSkShares;

worker.Start();

// Create N Members and send contributions
const BLSIdVector& ids = GetRandomBLSIds(N);
std::vector<Member> quorum;
for (size_t i = 0; i < N; i++) {
Member m(ids[i]);
// Generate contributions
worker.GenerateContributions((int)M, ids, m.vecP, m.contributions);
BOOST_CHECK_EQUAL(m.vecP->size(), M);
BOOST_CHECK_EQUAL(m.contributions.size(), N);
// Verify contributions against verification vector
for (size_t j = 0; j < N; j++) {
BOOST_CHECK(worker.VerifyContributionShare(ids[j], m.vecP, m.contributions[j]));
}
quorum.emplace_back(std::move(m));
}

// Now aggregate received contributions for each Member
for (size_t i = 0; i < N; i++) {
Member& m = quorum[i];
BLSSecretKeyVector rcvContributions;
for (size_t j = 0; j < N; j++) {
rcvContributions.emplace_back(quorum[j].contributions[i]);
}
m.skShare = worker.AggregateSecretKeys(rcvContributions);
allSkShares.emplace_back(m.skShare);
}

// Each member signs a message with its key share producing a signature share
const uint256& msg = GetRandHash();
BLSSignatureVector allSigShares;
for (const Member& m : quorum) {
allSigShares.emplace_back(m.skShare.Sign(msg));
}

// Pick M (random) key shares and recover threshold keys
const auto& idxs = GetRandomElements(M, N);
BLSSecretKeyVector skShares;
BLSIdVector random_ids;
for (size_t i : idxs) {
skShares.emplace_back(quorum[i].skShare);
random_ids.emplace_back(quorum[i].id);
}
CBLSSecretKey thresholdSk;
BOOST_CHECK(thresholdSk.Recover(skShares, random_ids));
const CBLSPublicKey& thresholdPk = thresholdSk.GetPublicKey();

// Check that the recovered threshold public key equals the verification
// vector free coefficient
std::vector<BLSVerificationVectorPtr> v;
for (const Member& m : quorum) v.emplace_back(m.vecP);
CBLSPublicKey pk = worker.BuildQuorumVerificationVector(v)->at(0);
BOOST_CHECK(pk == thresholdPk);

// Pick M (random, different than before) signature shares, and recover threshold signature
const auto& idxs2 = GetRandomElements(M, N);
BLSSignatureVector sigShares;
BLSIdVector random_ids2;
for (size_t i : idxs2) {
sigShares.emplace_back(allSigShares[i]);
random_ids2.emplace_back(quorum[i].id);
}
CBLSSignature thresholdSig;
BOOST_CHECK(thresholdSig.Recover(sigShares, random_ids2));

// Verify threshold signature against threshold public key
BOOST_CHECK(thresholdSig.VerifyInsecure(thresholdPk, msg));

worker.Stop();
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit 5a6d14e

Please sign in to comment.