Giter Club home page Giter Club logo

hfzjcl / libbls Goto Github PK

View Code? Open in Web Editor NEW

This project forked from skalenetwork/libbls

0.0 1.0 0.0 1.37 MB

Top-performance BLS threshold 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)

Home Page: https://skale.network

License: GNU Affero General Public License v3.0

CMake 2.78% C++ 94.38% Shell 0.27% C 0.34% Python 2.22%

libbls's Introduction

libBLS: a C++ library for BLS Threshold Signatures

Build Status codecov Discord

A mathematical library written in C++ that supports BLS threshold signatures, Distributed Key Generation (DKG) and Threshold Encryption (TE).

This libBLS library is developed by SKALE Labs and uses SCIPR-LAB's libff and PBC library by Ben Lynn (see Libraries below).

An important note about production readiness

This libBLS library is still in active development and therefore should be regarded as alpha software. The development is still subject to security hardening, further testing, and breaking changes. This library has not yet been reviewed or audited for security.

Overview

libBLS is a C++ library for BLS signatures and DKG that supports both threshold signatures and multi-signatures. Also it supports Threshold Encryption.

The signature process proceeds in 4 steps:

  1. Key generation
  2. Hashing
  3. Signing
  4. Verification

libBLS uses the alt_bn128 (Barreto-Naehrig curve) elliptic curve to be compatible with Ethereum's cryptography and provides 128 bits of security. Also, it provides opportunity to generate secret keys with DKG algorithm that supports the same curve.

libBLS for the most part corresponds to BLS signature standard. This work is still in progress and is going to be improved in the next couple of months.

Encryption process is running running as follows:

  1. Key generation
  2. Encryption
  3. Decryption
  4. Verifying and combining shares

You can learn more about the algebraic structures used in this algorithm in Ben Lynn’s PhD Dissertation. libBLS uses a modified Ben Lynn's pbc library with memory corruption bug fixed and the TYPE A curve for symmetric billinear pairing.

Perfomance Specifications

libBLS allows to sign about 3000 messages per second on a single thread (Intel® Core™ i3-4160 CPU @ 3.60GHz). However, for our solution we have implemented constant time signing (0.01 sec for sign) to avoid timing attacks.

Installation Requirements

libBLS has been built and tested on Ubuntu and Mac.

GitHub is used to maintain this source code. Clone this repository by:

git clone https://github.com/skalenetwork/libBLS.git
cd libBLS

Building Dependencies

Ensure that required packages listed below are installed.

Build libBLS's dependencies by:

cd deps
bash ./build.sh
cd ..

Building from source on Mac

brew install flex bison glibtool automake cmake pkg-config yasm
# Configure the project and create a build directory.
cmake -H. -Bbuild

# Build all default targets using all cores.
cmake --build build -- -j$(sysctl -n hw.ncpu)

Building from source on Ubuntu

Ensure that the required packages are installed by executing:

sudo apt-get update
sudo apt-get install -y automake cmake build-essential libprocps-dev libtool\
                        pkg-config yasm texinfo autoconf flex bison

Configure the project build with the following commands.

# Configure the project and create a build directory.
cmake -H. -Bbuild

# Build all default targets using all cores.
cmake --build build -- -j$(nproc)

Include the library

#include <libBLS.h>

Run tests

./build/dkg_unit_test                           # run all dkg unit tests
./build/bls_test                                # run all bls tests
./build/bls_unit_test                           # run all bls unit tests
./build/bls_unit_test --list_content            # show all test cases
./build/bls_unit_test -t libBLS/<TestCaseName>  # run single test case
./build/threshold_encryption/dkg_te_unit_test   # run all dkg tests corresponds to the algebraic
                                                # structures used in TE algroithm
./build/threshold_encryption/te_unit_test       # run all te unit tests
./build/threshold_encryption/te_test            # run all te tests

Classes for BLS threshold signatures

BLSPrivateKeyShare - class for private key for each participant. Has methods sign and signWithHelper to sign hashed message.

BLSPrivateKey - class for common private key

BLSPublicKeyShare - class for public key for each participant. Has methods VerifySig and VerifySigWithHelper to Verify a piece of signature.

BLSPublicKey - class for common public key. Has method VerifySig and VerifySigWithHelper for verifying common signature.

BLSSigShare - class for a piece of common signature.

BLSSigShareSet - class for a set of pieces of signature. Has methods Add (to add a piece of signature) and merge ( to get common signature, if enough pieces of signature added)

BLSSignature - class for common signature.

All these classes (except BLSSigShareSet) can be created from shared_ptr to string(or to vector of strings) and converted to shared_ptr to string(or to vector of strings) with the method toString().

How to use BLS threshold signatures

  1. Choose total number of participants in your group (n), give an index to each participant and choose a threshold number (t) for your case. (t <= n).

  2. Generate private keys. Create common public key. You may use DKG. For test you can use

std::shared_ptr<std::pair
<std::shared_ptr<std::vector<std::shared_ptr<BLSPrivateKeyShare>>>, std::shared_ptr<BLSPublicKey>>> keys =
                                                            BLSPrivateKeyShare::generateSampleKeys(t, n);

You will get a pair, which first component is shared_ptr to vector of private keys, and second component is shared_ptr to common public key;

  1. Hash the message you want to sign. Hash should be std::array<uint8_t, 32>
  2. Sign the hashed message with each private key(which is an instance of PrivateKeyShare). You will get a piece of signature (shared_ptr to BLSSigShare instance)

If you need to be compatible with Ethereum

 std::shared_ptr<BLSSigShare> sigShare_ptr = key.signWithHelper(hash_ptr, signer_index);

where key is an instance of BLSPrivateKeyShare, hash_ptr is shared_ptr to std::array<uint8_t, 32>, signer index is an index of a participant whose key is used to sign

If you are not using Ethereum then for each key call

std::shared_ptr<BLSSigShare> sigShare_ptr = key.sign(hash_ptr, signer_index)

where key is an instance of BLSPrivateKeyShare, hash_ptr is shared_ptr to std::array<uint8_t, 32>, signer index is an index of a participant whose key is used to sign

  1. Create an instance of BLSSigShareSet.
BLSSigShareSet SigSet(t,n);

Add shared_ptr to pieces of signature ( BLSSigShare instances ) to BLSSigShareSet.

SigSet.add(sigShare_ptr1);

If you have enough pieces you will be able to merge them and to get common signature(shared_ptr to BLSSignature instance)

std::shared_ptr<BLSSignature> signature_ptr = SigSet.merge();
  1. Verify common signature with common public key

If you need to be compatible with Ethereum

 assert( publicKey.VerifySigWithHelper(hash_ptr, signature_ptr, t, n);

If you need not to be compatible with Ethereum

 assert( publicKey.VerifySig(hash_ptr, signature_ptr, t, n );

Here is an example of BLS threshold signatures algorithm with t = 3, n = 4.

  size_t num_all = 4;
  size_t num_signed = 3;

  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

  std::shared_ptr<std::vector<std::shared_ptr<BLSPrivateKeyShare>>> Skeys =
                                     LSPrivateKeyShare::generateSampleKeys(num_signed, num_all)->first;

  std::default_random_engine rand_gen((unsigned int) time(0));
  std::array<uint8_t, 32> hash_byte_arr;
  for ( size_t i = 0; i < 32 ; i++){        //generate random hash
    hash_byte_arr.at(i) = rand_gen() % 255;
  }
  std::shared_ptr<std::array<uint8_t, 32>> hash_ptr =
                                            std::make_shared< std::array<uint8_t, 32> >(hash_byte_arr);

  BLSSigShareSet sigSet(num_signed, num_all);

  for (size_t i = 0; i < num_signed; ++i) {
    std::shared_ptr<BLSPrivateKeyShare> skey = Skeys->at(i);

    // sign with private key of each participant
    std::shared_ptr<BLSSigShare> sigShare = skey->sign(hash_ptr, participants.at(i));

    sigSet.addSigShare(sigShare);
  }

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

  //create common private key from private keys of each participant
  BLSPrivateKey common_skey
   (Skeys, std::make_shared<std::vector<size_t>>(participants), num_signed, num_all);

  //create common public key from common private key
  BLSPublicKey common_pkey(*(common_skey.getPrivateKey()), num_signed, num_all);

   // verify common signature with common public key
  assert(common_pkey.VerifySig(hash_ptr, common_sig_ptr, num_signed, num_all));

Classes for Threshold Encryption

TEPrivateKey - class for common private key

TEPublicKey - class for common public key. Has method encrypt to encrypt the message. (Message length should be 64) .

TEPrivateKeyShare - class for private key for each participant. Has method decrypt to decrypt CipherText and to get a part of decrypted message.

TEPublicKeyShare - class for public key for each participant. Has methods Verify to verify if given CipherText matches given decrypted piece of message.

TEDecryptSet - class for set of decrypted pieces of message. Has methods addDecrypt (to add a piece of decrypted message) and merge to get a decrypted message ( if enough pieces are added).

All these classes (except TEDecryptSet) can be created from shared_ptr to string(or to vector of strings) and converted to shared_ptr to string(or to vector of strings) with the method toString().

How to use Threshold encryption

  1. Choose total number of participants in your group (n), give index to each participant and choose a threshold number (t) for your case. (t <= n).

  2. Generate private key for each participant. Create common public key. You may use DKG. For test you can use

std::pair
<std::shared_ptr<std::vector<std::shared_ptr<TEPrivateKeyShare>>>, std::shared_ptr<TEPublicKey>> keys =
                                                             TEPrivateKeyShare::generateSampleKeys(t, n);

You will get a pair, which first component is shared_ptr to a vector of private keys, and second component is shared_ptr to common public key;

  1. Create public key from private key for each participant.
 TEPrivateKeyShare privateKeyShare = *keys.first->at(i);
 TEPublicKeyShare publicKeyShare ( privateKeyShare, t, n);

where i is an index of a participant.

  1. Decrypt message with common public key. Message length should be 64.
 TEPublic publicKey = *keys.second;
 encryption::Ciphertext cipher = publicKey.encrypt(message_ptr);

Where message_ptr is shared_ptr to string, cipher is encrypted message.

  1. Get pieces of decrypted message with private key of each participant and cipher got in step 4. Verify every piece with public key of corresponding participant.
 encryption::element_wrapper piece = privateKey.decrypt(cipher);
 assert ( publicKeyShare.Verify(cipher, piece) ) ;
  1. Create DecryptSet and add to it each piece of decrypted message.
   TEDecryptSet decrSet(t, n);
   decrSet.addDecrypt(signerIndex, piece_ptr);

where piece_ptr is shared_ptr to piece, signerIndex is an index of a participant, which created this piece.

  1. If you have enough pieces you will be able to merge them and to get decrypted message.
std::string message = decrSet.merge();

DKG algorithm for BLS threshold signatures and Threshold Encryption

  1. Choose total number of participants in your group (n), give index to each participant and choose a threshold number (t) for your case. (t <= n).

  2. Each participant of DKG creates an instance of dkg class with parameters t and n; For BLS

 DKGBLSWrapper dkg_obj(t, n);

For TE

 DKGTEWrapper dkg_obj(t, n);

When created dkg_obj generates secret polynomial, but if you want you can set your own one with the method setDKGSecret

  1. Each participant generates a vector of public shares coefficients and broadcasts it.

For BLS

std::shared_ptr < std::vector <libff::alt_bn128_G2>>  public_shares = dkg_obj.createDKGPublicShares();

For TE

std::shared_ptr <std::vector <encryption::element_wrapper>>  public_shares =
                                                                      dkg_obj.createDKGPublicShares();
  1. Each participant generates vector of secret shares coefficients. And sends to j-th participant j-th component of secret shares coefficients vector. ( j = 1 .. n and not equal to current participant index).

For BLS

 std::shared_ptr <std::vector <libff::alt_bn128_Fr>>  private_shares = dkg_obj.createDKGSecretShares();

For TE

 std::shared_ptr < std::vector <encryption::element_wrapper>>  private_shares =
                                                                       dkg_obj.createDKGSecretShares();
  1. Each participant verifies that for data recieved other participants secret share matches vector of public shares
  assert(dkg_obj. VerifyDKGShare( signerIndex, secret_share, public_shares_vector));

where public_shares_vector is shared_ptr to vector of public shares, signerIndex is index of participant from which secret and public shares were recieved.

  1. If verification passed each participant may create private key from secret shares that it received

For BLS

   BLSPrivateKeyShare privateKeyShare = dkg_obj.CreateBLSPrivateKeyShare(secret_shares_vector);

For TE

   TEPrivateKeyShare privateKeyShare = dkg_obj.CreateTEPrivateKeyShare(secret_shares_vector);

Also in DKGTEWrapper there is a static function that creates common public key

   TEPublicKey publicKey = DKGTEWrapper::CreateTEPublicKey( public_shares_all, t, n);

where public_shares_all is shared_ptr to matrix of all public shares ( its type is std::shared_ptr<std::vector<std::vectorencryption::element_wrapper>>).

Here is an example of Threshold Encryption algorithm with DKG simulation for t = 3, n = 4.

size_t num_signed = 3;
size_t num_all = 4;
std::vector<std::vector<encryption::element_wrapper>> secret_shares_all; // matrix of all secret shares
std::vector<std::vector<encryption::element_wrapper>> public_shares_all; //// matrix of all public shares
std::vector<DKGTEWrapper> dkgs; // instances of DKGTEWrapper for each participant
std::vector<TEPrivateKeyShare> skeys; // private keys of participants
std::vector<TEPublicKeyShare> pkeys;  // public keys of participants

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

  // create secret shares for each participant
  std::shared_ptr<std::vector<encryption::element_wrapper>> secret_shares_ptr =
                                                                      dkg_wrap.createDKGSecretShares();

 // create public shares for each participant
 std::shared_ptr<std::vector<encryption::element_wrapper>> public_shares_ptr =
                                                                      dkg_wrap.createDKGPublicShares();

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

for (size_t i = 0; i < num_all; i++)      // Verifying shares for each participant
 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<encryption::element_wrapper>>(public_shares_all.at(i))));
 }
 std::vector<std::vector<encryption::element_wrapper>> secret_key_shares;

 for (size_t i = 0; i < num_all; i++) {          // collect got secret shares in a vector
   std::vector<encryption::element_wrapper> 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++) {
   TEPrivateKeyShare pkey_share = dkgs.at(i).CreateTEPrivateKeyShare(
                                             i + 1,
                                             std::make_shared<std::vector<encryption::element_wrapper>>(
                                                                              secret_key_shares.at(i)));
   skeys.push_back(pkey_share);
   pkeys.push_back(TEPublicKeyShare(pkey_share, num_signed, num_all));
 }

 TEPublicKey common_public = DKGTEWrapper::CreateTEPublicKey(
             std::make_shared< std::vector<std::vector<encryption::element_wrapper>>>(public_shares_all),
             num_signed,
             num_all);

 std::string message;    // Generating random message
 size_t msg_length = 64;
 for (size_t length = 0; length < msg_length; ++length) {
   message += char(rand_gen() % 128);
 }

 std::shared_ptr msg_ptr = std::make_shared<std::string>(message);
 encryption::Ciphertext cypher = common_public.encrypt(msg_ptr);

// removing 1 random participant ( because only 3 of 4 will participate)
 size_t ind4del = rand_gen() % secret_shares_all.size();
 auto pos4del = secret_shares_all.begin();
 advance(pos4del, ind4del);
 secret_shares_all.erase(pos4del);
 auto pos2 = public_shares_all.begin();
 advance(pos2, ind4del);
 public_shares_all.erase(pos2);

 TEDecryptSet decr_set(num_signed, num_all);
 for (size_t i = 0; i < num_signed; i++) {
   encryption::element_wrapper decrypt = skeys.at(i).decrypt(cypher);
   assert(pkeys.at(i).Verify(cypher, decrypt.el_));
   std::shared_ptr decr_ptr = std::make_shared<encryption::element_wrapper>(decrypt);
   decr_set.addDecrypt(skeys.at(i).getSignerIndex(), decr_ptr);
 }

 std::string message_decrypted = decr_set.merge(cypher);
}

Libraries

Contributing

If you have any questions please ask our development community on Discord.

Discord

Otherwise see our CONTRIBUTING.md for more information.

License

License

Copyright (C) 2018-present SKALE Labs

libbls's People

Contributors

olehnikolaiev avatar svetaro avatar sergiy-skalelabs avatar kladkogex avatar cstrangedk avatar sergiy-ezlo avatar dimastebaev avatar dimalit avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.