730efde109
795660db76 chore: bump version to 1.3.0 (#84) e8743b0139 Merge pull request #83 from UdjinM6/bp_370_371 72f0ad2d37 fix: add missing destructor for CoreMPL and final for nested classes (#371) 2f05059c60 Fix a typo in class PrivateKey testcase. (#370) 851c2c8f68 fix: reading unitialized memory from Util::HasOnlyZeros in G2Element deserialization (#77) 4dd28e9016 fix: js bindings build (#82) 3697c51521 fix: dash is no more pretending being a 'libdashbls' (#76) 37c53141d3 feat: implement memory-copy only of G1Element and G2Element (#74) 97ac99e8e6 build(bls-dash-sys): ignore wasm32 target arch (#70) 2d494d351e Merge pull request #71 from dashpay/feat/threshold_bindings 67fb70d40b chore: revert permission changes in bcce0b214876c0d9e668baaa30a48542b496cda2 5a58fce0ea fix: resolve rust-bindings compilation failure 8604e03761 build: fix cmake build error c25957edf0 Merge remote-tracking branch 'dash/develop' into feat/threshold_bindings2 198e246f07 added a helper for verifying a message a4b8a5dd6e added a helper for verifying a message 2d783c985e added a helper for signing from the private key 16f7873d6a changed to using a slice for recovery a23d9708c0 feat: clone 0cf8a8eb96 feat: serde 47829e3e75 threshold_recovery functions a5589e6fc8 fix: bls extended private key size 1ceaab56e3 [add cpp targts] 86eb28e2d7 [fix linker path for cpp] 85debcab29 [include 'src' into build] f956c66b90 [switch into cc] 9ecb59bf9b [test linker] 3651a0fd79 [linker change] d8564679eb [fix: iossim] c829d4b6f1 [fix: aarch64-apple-darwin trigger] fc3509e901 [chore: silence warning] 79ce6ded50 [feat: apple build for single platform+arch] e580cb76db [feat: build for apple target] 17b2168955 feat: verifySecure method for BasicSchemeMPL in js bindings (#69) 4613425b60 chore: silence rust warnings 136d762607 [fix: target_arch] 0d8c8e9d41 [try to use ios.toolchain] bd441623df [back] 8137f48897 [change relic src] bdcba81d41 test: check patched relic 32b7f56d94 Merge pull request #1 from dashevo/rust-bindings-enhancement 6d359c6201 chore: test for extended private key from short seed 1cbeffe159 chore: add binding dace793a1a fix: same as previous: BIP32ExtendedPrivateKeyFromSeed with len 65c84d063c fix: ok now add second blank line 24b25bac2d fix: now try from typing import Union fe16287182 fix: try Union[Fq2, None] 3ffc96d409 fix: None 2d669a2cf8 chore: up version fbb5a43b19 fix: pass length PrivateKeyFromSeedBIP32 5822076d1a chore: cargo:fmt a8d3a7e956 test: add keys multiplication test 4b85f08937 fix: exchange keys when multiply 0bcefc68cb chore: add imports 7380332123 [chore: add binding for G1ElementMul] 881e6d7676 patch relic to be compatible with wasm bcce0b2148 chore: fix mode 02801cf973 add deeper checks to example project 6d25c60ee5 compilation fixes a4cebb4025 refactor: remove "C" prefix 995ef3796f refactor: bip32 feature 7ea0c34938 style: remove `get` prefix from getters e316c00f7b add VerifySecure da5536e1c5 feat: introduce PrivateKey::from_bip32_seed 4f03a1a1ae export legacy scheme 5c19e314d4 add extended private key cc081c0956 feat: add G1 element's fingerprint and generate methods f3e85b46d0 refactor: move back re-exports e8155b4bdb refactor: move legacy code to submodule f6e173242e add extendedpublickey 4f823249fb feat: legacy serialize and deserialize methods 90fd9f9c2c fix: comparison int with size_t 57237e5e87 Merge branch 'rust-bindings' of github.com:dashevo/bls-signatures into rust-bindings a1f862480b refactor: implement Deref trait for SecureBox 0b6f94e41f add LegacySchemeMPL aa19a77a40 refactor: small refactoring dae8b31042 make schemes public 827d1ed162 add hdkeys 7b4ffae5ec improve agg sig test 18057687be add basic scheme 3e4fdda2bd aggregates 61a4d791c9 elements ser/de 8b5b6301f3 wip 126b7becea wip c49514176e chore: remove autocxx variant 477c014bb7 refactor: increase `c_err_to_result` readability 5d52d0e59d Merge remote-tracking branch 'dashevo/rust-bindings' into rust-bindings 31724b39d1 chore: add example crate c04c2941db safe wrappers for simple case 844779cd81 chore: remove cdylib from bls-signatures d622625de4 chore: move all rust stuff into one 0d3c51106a Merge remote-tracking branch 'dashevo/rust-bindings' into rust-bindings ecf0271950 revert: bring back necessary c binding files :) 20e1cfe37b wip 654fc5e6a6 chore: remove unnecessary files from c binding 92ffd63c28 refactor: cargo build script 1d4d76fb05 chore: remove wrapper.h 20cc668708 qfix abb38804c7 Merge remote-tracking branch 'dashevo/rust-bindings' into rust-bindings 760a267ab7 build: fix mac related issues 8b083794a4 add destructors to bls-dash-sys basic test 6c54f0a01a Merge remote-tracking branch 'dashevo/rust-bindings' into rust-bindings fd526ab0db build: pass gmp lib path to build.rs a8aaccb510 rust-bindings sign and verify test simple 8447c1c112 wip bindings test 9390162e3c wip add rust-bindings tests 26ab7216c0 revert: bls header path db55e40cb0 rename to sys 96188a6d52 build qfix 965ac58df4 build: automate build process part 2 05636207a0 build: automate build process part 1 73b146a961 experiment cross compiling with autocxx and bindgen 969e5e2102 experiment cross compiling with autocxx and bindgen 88ee9d0519 chore: WIP 525b4d49d9 feat: rust bindings git-subtree-dir: src/dashbls git-subtree-split: 795660db76636c92bea3bfccfee621f1aba371a3 |
||
---|---|---|
.github/workflows | ||
build-aux/m4 | ||
cmake_modules | ||
contrib/gmp-patch-6.2.1 | ||
depends | ||
go-bindings | ||
include/dashbls | ||
js-bindings | ||
python-bindings | ||
python-impl | ||
rust-bindings | ||
src | ||
.clang-format | ||
.flake8 | ||
.gitignore | ||
apple.rust.deps.sh | ||
apple.rust.sh | ||
apple.rust.single.sh | ||
autogen.sh | ||
CMakeLists.txt | ||
configure.ac | ||
emsdk_build.sh | ||
js_build_docker.sh | ||
js_build.sh | ||
js_test.sh | ||
lgtm.yml | ||
LICENSE | ||
Makefile.am | ||
Makefile.bench.include | ||
Makefile.bls.include | ||
Makefile.mimalloc.include | ||
Makefile.relic.include | ||
Makefile.test.include | ||
MANIFEST.in | ||
mypi.ini | ||
pyproject.toml | ||
README.md | ||
setjmp_patch.diff | ||
setup.py |
BLS Signatures implementation
NOTE: THIS LIBRARY IS NOT YET FORMALLY REVIEWED FOR SECURITY
NOTE: THIS LIBRARY WAS SHIFTED TO THE IETF BLS SPECIFICATION ON 7/16/20
Implements BLS signatures with aggregation using relic toolkit for cryptographic primitives (pairings, EC, hashing) according to the IETF BLS RFC with these curve parameters for BLS12-381.
Features:
- Non-interactive signature aggregation following IETF specification
- Works on Windows, Mac, Linux, BSD
- Efficient verification using Proof of Posssesion (only one pairing per distinct message)
- Aggregate public keys and private keys
- EIP-2333 key derivation (including unhardened BIP-32-like keys)
- Key and signature serialization
- Batch verification
- Python bindings
- Pure python bls12-381 and signatures
- JavaScript bindings
Before you start
This 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"
using namespace bls;
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};
PrivateKey sk = AugSchemeMPL().KeyGen(seed);
G1Element pk = sk.GetG1Element();
vector<uint8_t> message = {1, 2, 3, 4, 5}; // Message is passed in as a byte vector
G2Element signature = AugSchemeMPL().Sign(sk, message);
// Verify the signature
bool ok = AugSchemeMPL().Verify(pk, message, signature);
Serializing keys and signatures to bytes
vector<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 hex
cout << Util::HexStr(pkBytes) << endl; // 48 bytes printed in hex
cout << Util::HexStr(signatureBytes) << endl; // 96 bytes printed in hex
Loading keys and signatures from bytes
// Takes vector of 32 bytes
PrivateKey skc = PrivateKey::FromByteVector(skBytes);
// Takes vector of 48 bytes
pk = G1Element::FromByteVector(pkBytes);
// Takes vector of 96 bytes
signature = G2Element::FromByteVector(signatureBytes);
Create aggregate signatures
// Generate some more private keys
seed[0] = 1;
PrivateKey sk1 = AugSchemeMPL().KeyGen(seed);
seed[0] = 2;
PrivateKey sk2 = AugSchemeMPL().KeyGen(seed);
vector<uint8_t> message2 = {1, 2, 3, 4, 5, 6, 7};
// Generate first sig
G1Element pk1 = sk1.GetG1Element();
G2Element sig1 = AugSchemeMPL().Sign(sk1, message);
// Generate second sig
G1Element pk2 = sk2.GetG1Element();
G2Element sig2 = AugSchemeMPL().Sign(sk2, message2);
// Signatures can be non-interactively combined by anyone
G2Element aggSig = AugSchemeMPL().Aggregate({sig1, sig2});
ok = AugSchemeMPL().AggregateVerify({pk1, pk2}, {message, message2}, aggSig);
Arbitrary trees of aggregates
seed[0] = 3;
PrivateKey sk3 = AugSchemeMPL().KeyGen(seed);
G1Element pk3 = sk3.GetG1Element();
vector<uint8_t> message3 = {100, 2, 254, 88, 90, 45, 23};
G2Element sig3 = AugSchemeMPL().Sign(sk3, message3);
G2Element aggSigFinal = 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.
G2Element popSig1 = PopSchemeMPL().Sign(sk1, message);
G2Element popSig2 = PopSchemeMPL().Sign(sk2, message);
G2Element popSig3 = PopSchemeMPL().Sign(sk3, message);
G2Element pop1 = PopSchemeMPL().PopProve(sk1);
G2Element pop2 = PopSchemeMPL().PopProve(sk2);
G2Element pop3 = PopSchemeMPL().PopProve(sk3);
ok = PopSchemeMPL().PopVerify(pk1, pop1);
ok = PopSchemeMPL().PopVerify(pk2, pop2);
ok = PopSchemeMPL().PopVerify(pk3, pop3);
G2Element popSigAgg = PopSchemeMPL().Aggregate({popSig1, popSig2, popSig3});
ok = PopSchemeMPL().FastAggregateVerify({pk1, pk2, pk3}, message, popSigAgg);
// Aggregate public key, indistinguishable from a single public key
G1Element popAggPk = pk1 + pk2 + pk3;
ok = PopSchemeMPL().Verify(popAggPk, message, popSigAgg);
// Aggregate private keys
PrivateKey aggSk = PrivateKey::Aggregate({sk1, sk2, sk3});
ok = (PopSchemeMPL().Sign(aggSk, message) == popSigAgg);
HD keys using EIP-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)
PrivateKey masterSk = AugSchemeMPL().KeyGen(seed);
PrivateKey child = AugSchemeMPL().DeriveChildSk(masterSk, 152);
PrivateKey grandChild = AugSchemeMPL().DeriveChildSk(child, 952)
// Unhardened (less secure, but can go from parent pk -> child pk), BIP32 style
G1Element masterPk = masterSk.GetG1Element();
PrivateKey childU = AugSchemeMPL().DeriveChildSkUnhardened(masterSk, 22);
PrivateKey grandchildU = AugSchemeMPL().DeriveChildSkUnhardened(childU, 0);
G1Element childUPk = AugSchemeMPL().DeriveChildPkUnhardened(masterPk, 22);
G1Element grandchildUPk = AugSchemeMPL().DeriveChildPkUnhardened(childUPk, 0);
ok = (grandchildUPk == grandchildU.GetG1Element();
Build
Cmake 3.14+, a c++ compiler, and python3 (for bindings) are required for building.
mkdir build
cd build
cmake ../
cmake --build . -- -j 6
Run tests
./build/src/runtest
Run benchmarks
./build/src/runbench
On a 3.5 GHz i7 Mac, verification takes about 1.1ms per signature, and signing takes 1.3ms.
Link the library to use it
g++ -Wl,-no_pie -std=c++11 -Ibls-signatures/depends/relic/include -Ibls-signatures/build/depends/relic/include -Ibls-signatures/src -L./bls-signatures/build/ -l bls yourapp.cpp
Notes on dependencies
We 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/
.
Discussion
Discussion about this library and other Chia related development is in the #dev channel of Chia's public Keybase channels.
Code style
- Always use vector<uint8_t> for bytes
- Use size_t for size variables
- Uppercase method names
- Prefer static constructors
- Avoid using templates
- Objects allocate and free their own memory
- Use cpplint with default rules
- Use SecAlloc and SecFree when handling secrets
ci Building
The 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 uses
FetchContent
to download pybind11 for the Python
bindings and relic from a chia relic forked repository for Windows. Building
is then managed by cibuildwheel.
Further installation is then available via pip install blspy
e.g. The ci
builds include GMP and a statically linked libsodium.
Contributing and workflow
Contributions are welcome and more details are available in chia-blockchain's CONTRIBUTING.md.
The main branch is usually the currently released latest version on PyPI. Note that at times bls-signatures/blspy will be ahead of the release version that chia-blockchain requires in it's main/release version in preparation for a new chia-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 at lgtm.com. Please make sure your build is passing and that it does not increase alerts at lgtm.
Specification and test vectors
The IETF bls draft is followed. Test vectors can also be seen in the python and cpp test files.
Libsodium license
The libsodium static library is licensed under the ISC license which requires the following copyright notice.
ISC License
Copyright (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 license
GMP is distributed under the GNU LGPL v3 license
Relic license
Relic is used with the Apache 2.0 license