Package: chinillablspy
BLS Signatures implementationNOTE: THIS LIBRARY IS NOT YET FORMALLY REVIEWED FOR SECURITYNOTE: THIS LIBRARY WAS SHIFTED TO THE IETF BLS SPECIFICATION ON 7/16/20Implements BLS signatures with aggregation usingrelic toolkitfor cryptographic primitives (pairings, EC, hashing) according to theIETF BLS RFCwiththese curve parametersfor BLS12-381.Features:Non-interactive signature aggregation following IETF specificationWorks on Windows, Mac, Linux, BSDEfficient verification using Proof of Posssesion (only one pairing per distinct message)Aggregate public keys and private keysEIP-2333key derivation (including unhardened BIP-32-like keys)Key and signature serializationBatch verificationPython bindingsPure python bls12-381 and signaturesJavaScript bindingsBefore you startThis library uses minimum public key sizes (MPL). A G2Element is a signature (96 bytes), and a G1Element is a public key (48 bytes). A private key is a 32 byte integer. There are three schemes: Basic, Augmented, and ProofOfPossession. Augmented should be enough for most use cases, and ProofOfPossession can be used where verification must be fast.Import the library#include"bls.hpp"usingnamespacebls;Creating keys and signatures// Example seed, used to generate private key. Always use// a secure RNG with sufficient entropy to generate a seed (at least 32 bytes).vector<uint8_t>seed={0,50,6,244,24,199,1,25,52,88,192,19,18,12,89,6,220,18,102,58,209,82,12,62,89,110,182,9,44,20,254,22};PrivateKeysk=AugSchemeMPL().KeyGen(seed);G1Elementpk=sk.GetG1Element();vector<uint8_t>message={1,2,3,4,5};// Message is passed in as a byte vectorG2Elementsignature=AugSchemeMPL().Sign(sk,message);// Verify the signatureboolok=AugSchemeMPL().Verify(pk,message,signature);Serializing keys and signatures to bytesvector<uint8_t>skBytes=sk.Serialize();vector<uint8_t>pkBytes=pk.Serialize();vector<uint8_t>signatureBytes=signature.Serialize();cout<<Util::HexStr(skBytes)<<endl;// 32 bytes printed in hexcout<<Util::HexStr(pkBytes)<<endl;// 48 bytes printed in hexcout<<Util::HexStr(signatureBytes)<<endl;// 96 bytes printed in hexLoading keys and signatures from bytes// Takes vector of 32 bytesPrivateKeyskc=PrivateKey::FromByteVector(skBytes);// Takes vector of 48 bytespk=G1Element::FromByteVector(pkBytes);// Takes vector of 96 bytessignature=G2Element::FromByteVector(signatureBytes);Create aggregate signatures// Generate some more private keysseed[0]=1;PrivateKeysk1=AugSchemeMPL().KeyGen(seed);seed[0]=2;PrivateKeysk2=AugSchemeMPL().KeyGen(seed);vector<uint8_t>message2={1,2,3,4,5,6,7};// Generate first sigG1Elementpk1=sk1.GetG1Element();G2Elementsig1=AugSchemeMPL().Sign(sk1,message);// Generate second sigG1Elementpk2=sk2.GetG1Element();G2Elementsig2=AugSchemeMPL().Sign(sk2,message2);// Signatures can be non-interactively combined by anyoneG2ElementaggSig=AugSchemeMPL().Aggregate({sig1,sig2});ok=AugSchemeMPL().AggregateVerify({pk1,pk2},{message,message2},aggSig);Arbitrary trees of aggregatesseed[0]=3;PrivateKeysk3=AugSchemeMPL().KeyGen(seed);G1Elementpk3=sk3.GetG1Element();vector<uint8_t>message3={100,2,254,88,90,45,23};G2Elementsig3=AugSchemeMPL().Sign(sk3,message3);G2ElementaggSigFinal=AugSchemeMPL().Aggregate({aggSig,sig3});ok=AugSchemeMPL().AggregateVerify({pk1,pk2,pk3},{message,message2,message3},aggSigFinal);Very fast verification with Proof of Possession scheme// If the same message is signed, you can use Proof of Posession (PopScheme) for efficiency// A proof of possession MUST be passed around with the PK to ensure security.G2ElementpopSig1=PopSchemeMPL().Sign(sk1,message);G2ElementpopSig2=PopSchemeMPL().Sign(sk2,message);G2ElementpopSig3=PopSchemeMPL().Sign(sk3,message);G2Elementpop1=PopSchemeMPL().PopProve(sk1);G2Elementpop2=PopSchemeMPL().PopProve(sk2);G2Elementpop3=PopSchemeMPL().PopProve(sk3);ok=PopSchemeMPL().PopVerify(pk1,pop1);ok=PopSchemeMPL().PopVerify(pk2,pop2);ok=PopSchemeMPL().PopVerify(pk3,pop3);G2ElementpopSigAgg=PopSchemeMPL().Aggregate({popSig1,popSig2,popSig3});ok=PopSchemeMPL().FastAggregateVerify({pk1,pk2,pk3},message,popSigAgg);// Aggregate public key, indistinguishable from a single public keyG1ElementpopAggPk=pk1+pk2+pk3;ok=PopSchemeMPL().Verify(popAggPk,message,popSigAgg);// Aggregate private keysPrivateKeyaggSk=PrivateKey::Aggregate({sk1,sk2,sk3});ok=(PopSchemeMPL().Sign(aggSk,message)==popSigAgg);HD keys usingEIP-2333// You can derive 'child' keys from any key, to create arbitrary trees. 4 byte indeces are used.// Hardened (more secure, but no parent pk -> child pk)PrivateKeymasterSk=AugSchemeMPL().KeyGen(seed);PrivateKeychild=AugSchemeMPL().DeriveChildSk(masterSk,152);PrivateKeygrandChild=AugSchemeMPL().DeriveChildSk(child,952)// Unhardened (less secure, but can go from parent pk -> child pk), BIP32 styleG1ElementmasterPk=masterSk.GetG1Element();PrivateKeychildU=AugSchemeMPL().DeriveChildSkUnhardened(masterSk,22);PrivateKeygrandchildU=AugSchemeMPL().DeriveChildSkUnhardened(childU,0);G1ElementchildUPk=AugSchemeMPL().DeriveChildPkUnhardened(masterPk,22);G1ElementgrandchildUPk=AugSchemeMPL().DeriveChildPkUnhardened(childUPk,0);ok=(grandchildUPk==grandchildU.GetG1Element();BuildCmake 3.14+, a c++ compiler, and python3 (for bindings) are required for building.mkdirbuildcdbuild
cmake../
cmake--build.---j6Run tests./build/src/runtestRun benchmarks./build/src/runbenchOn a 3.5 GHz i7 Mac, verification takes about 1.1ms per signature, and signing takes 1.3ms.Link the library to use itg++-Wl,-no_pie-std=c++11-Ibls-signatures/build/_deps/relic-src/include-Ibls-signatures/build/_deps/relic-build/include-Ibls-signatures/src-L./bls-signatures/build/-lblsyourapp.cppNotes on dependenciesWe use Libsodium and have GMP as an optional dependency: libsodium gives secure memory
allocation, and GMP speeds up the library by ~ 3x. MPIR is used on Windows via
GitHub Actions instead. To install them, either download them from github and
follow the instructions for each repo, or use a package manager like APT or
brew. You can follow the recipe used to build python wheels for multiple
platforms in.github/workflows/.DiscussionDiscussion about this library and other Chinilla related development is in the #dev
channel of Chinilla'spublic Keybase channels.Code styleAlways use vector<uint8_t> for bytesUse size_t for size variablesUppercase method namesPrefer static constructorsAvoid using templatesObjects allocate and free their own memoryUse cpplint with default rulesUse SecAlloc and SecFree when handling secretsci BuildingThe primary build process for this repository is to use GitHub Actions to
build binary wheels for MacOS, Linux (x64 and aarch64), and Windows and publish
them with a source wheel on PyPi. MacOS ARM64 is supported but not automated
due to a lack of M1 CI runners. See.github/workflows/build.yml. CMake usesFetchContentto downloadpybind11for the Python
bindings and relic from a chinilla relic forked repository for Windows. Building
is then managed bycibuildwheel.
Further installation is then available viapip install chinillablspye.g. The ci
builds include GMP and a statically linked libsodium.Contributing and workflowContributions are welcome and more details are available in chinilla-blockchain'sCONTRIBUTING.md.The main branch is usually the currently released latest version on PyPI.
Note that at times bls-signatures/chinillablspy will be ahead of the release version
that chinilla-blockchain requires in it's main/release version in preparation
for a new chinilla-blockchain release. Please branch or fork main and then create
a pull request to the main branch. Linear merging is enforced on main and
merging requires a completed review. PRs will kick off a GitHub actions ci
build and analysis of bls-signatures atlgtm.com.
Please make sure your build is passing and that it does not increase alerts
at lgtm.Specification and test vectorsTheIETF bls draftis followed. Test vectors can also be seen in the python and cpp test files.Libsodium licenseThe libsodium static library is licensed under the ISC license which requires
the following copyright notice.ISC LicenseCopyright (c) 2013-2020
Frank Denis <j at pureftpd dot org>Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.GMP licenseGMP is distributed under theGNU LGPL v3 licenseRelic licenseRelic is used with theApache 2.0 license