skalenetwork / libBLS

Solidity-compatible BLS signatures, threshold encryption, distributed key generation library in modern C++. Actively maintained and used by SKALE for consensus, distributed random number gen, inter-chain communication and protection of transactions. BLS threshold signatures can be verified in Solidity, and used as random beacon (common coin)
https://skale.space
GNU Affero General Public License v3.0
143 stars 45 forks source link

Got empty common public key while invoking BLSPrivateKeyShare::generateSampleKeys #182

Closed gaoweihe closed 2 years ago

gaoweihe commented 2 years ago

I am trying to generate sample keys with BLSPrivateKeyShare::generateSampleKeys following step 2 in using-threshold-signatures.md. However, the two assertions in the code below failed, where keys_->second->getRequiredSigners() and keys_->second->getTotalSigners() both returned 0.

My code:


#include "libBLS.h"

int main()
{
    auto keys_ = BLSPrivateKeyShare::generateSampleKeys(20, 20);
    assert(keys_->second->getRequiredSigners() == 20); // Assertion `keys_->second->getRequiredSigners() == 20' failed
    assert(keys_->second->getTotalSigners() == 20); // Assertion `keys_->second->getTotalSigners() == 20' failed
    return 0;
}

For your convenience, keys_ is of type


std::shared_ptr< std::pair < 
    std::shared_ptr< std::vector< std::shared_ptr< BLSPrivateKeyShare > > >,
    std::shared_ptr< BLSPublicKey > 
> >

My CMake linking configuration is


target_link_libraries(project-name
    libsodium.a
    libbls.a
    libff.a
    libgmpxx.a
    libgmp.a
    libgcov.a
    libssl.a
    libcrypto.a
    libz.so
    libpthread.so
    libdl.so
) 

Am I using the BLSPrivateKeyShare::generateSampleKeys function correctly? Thanks!

gaoweihe commented 2 years ago

Thanks for your reply the other day, @olehnikolaiev . It has been confirmed that the library does not update t and n fields properly.

According to the information above, I have tried the following code. This segment of code below conforms to the instructions in using-distributed-key-generation.md and using-threshold-signatures.md. Unfortunately, another problem was spotted.


#include "libBLS.h"

int main(int argc, char* argv[])
{
    constexpr size_t num_signed = 3;
    constexpr size_t num_all = 4;

    std::vector<std::vector<libff::alt_bn128_Fr>> secret_shares_all; // matrix of all secret shares
    std::vector<std::vector<libff::alt_bn128_G2>> public_shares_all; // matrix of all public shares
    std::vector<DKGBLSWrapper> dkgs; // instances of DKGTEWrapper for each participant
    std::shared_ptr<std::vector<std::shared_ptr<BLSPrivateKeyShare>>> skeys =
            std::make_shared<std::vector<std::shared_ptr<BLSPrivateKeyShare>>>(); // private keys of participants
    std::vector<BLSPublicKeyShare> pkeys;  // public keys of participants

    for (size_t i = 0; i < num_all; i++) {
        DKGBLSWrapper dkg_wrap(num_signed, num_all);
        dkgs.push_back(dkg_wrap);

        std::shared_ptr<std::vector<libff::alt_bn128_Fr>> secret_shares_ptr =
            dkg_wrap.createDKGSecretShares();

        std::shared_ptr<std::vector<libff::alt_bn128_G2>> public_shares_ptr =
            dkg_wrap.createDKGPublicShares();

        secret_shares_all.push_back(*secret_shares_ptr);
        public_shares_all.push_back(*public_shares_ptr);
    }

    // verify shares for each participant
    for (size_t i = 0; i < num_all; i++) {
        for (size_t j = 0; j < num_all; j++) {
            assert(dkgs.at(i).VerifyDKGShare(
                    j,
                    secret_shares_all.at(i).at(j),

                    std::make_shared<std::vector<libff::alt_bn128_G2>>(public_shares_all.at(i))
                    )); // Assertions passed 
        }
    }

    std::vector<std::vector<libff::alt_bn128_Fr>> secret_key_shares;
    for (size_t i = 0; i < num_all; i++) { // collect got secret shares in a vector
        std::vector<libff::alt_bn128_Fr> secret_key_contribution;
        for (size_t j = 0; j < num_all; j++) {
            secret_key_contribution.push_back(secret_shares_all.at(j).at(i));
        }
        secret_key_shares.push_back(secret_key_contribution);
    }

    for (size_t i = 0; i < num_all; i++) {
        BLSPrivateKeyShare pkey_share = dkgs.at(i).CreateBLSPrivateKeyShare(
            std::make_shared<std::vector<libff::alt_bn128_Fr>>(
                secret_key_shares.at(i)));
        skeys->push_back(std::make_shared<BLSPrivateKeyShare>(pkey_share));
        pkeys.push_back(BLSPublicKeyShare(
                *pkey_share.getPrivateKey(),
                num_signed,
                num_all
                ));
    }

    // generate random message
    std::default_random_engine rand_gen((unsigned int) time(0));
    std::string message;
    size_t msg_length = 32;
    for (size_t length = 0; length < msg_length; ++length) {
        message += char(rand_gen() % 128);
    }

    BLSSigShareSet sigSet(num_signed, num_all);

    std::shared_ptr<std::array<uint8_t, 32>> byteArray = std::make_shared<std::array<uint8_t, 32>>();
    std::copy(message.begin(), message.end(), byteArray->begin());
    for (size_t i = 0; i < num_signed; ++i) {
        std::shared_ptr<BLSPrivateKeyShare> skey = skeys->at(i + 1);

        // sign with private key of each participant
        std::shared_ptr<BLSSigShare> sigShare = skey->sign(
                byteArray,
                i + 1
                );

        sigSet.addSigShare(sigShare);
    }

    std::shared_ptr<BLSSignature> common_sig_ptr = sigSet.merge(); // create common signature

    std::vector<size_t> participants(num_all);
    for (size_t i = 0; i < num_signed; ++i) participants.at(i) = i + 1; // set participants indices 1,2,3

    BLSPrivateKey common_skey(
            skeys,
            std::make_shared<std::vector<size_t>>(participants),
            num_signed,
            num_all
            );
    BLSPublicKey common_pkey(*(common_skey.getPrivateKey()));

    assert(common_pkey.VerifySig(byteArray, common_sig_ptr)); // Assertion failed

    return 0;
}

The assertion of merged signature failed at the end, whereas the assertions passed during verification of participant shares.

Is this also caused by the problem of updating t and n? If so, is there a workaround to use DKG and BLS-TSS at the same time? Thanks!

olehnikolaiev commented 2 years ago

hello @gaoweihe ! thanks for reporting the issue. when creating BLSPublicKey object from private or public key it doesn't fill the t and n fields. to use t and n fields you should use another constructor BLSPublicKey( std::shared_ptr< std::map< size_t, std::shared_ptr< BLSPublicKeyShare > > > map_pkeys_koefs, size_t _requiredSigners, size_t _totalSigners ); reagrding the second issue - std::shared_ptr<BLSPrivateKeyShare> skey = skeys->at(i + 1);. here you should use skeys->at(i)

gaoweihe commented 2 years ago

Thanks for your reply, @olehnikolaiev ! Your suggestions helped a lot. I'm now closing this issue as the problem has been solved.