dash/python-bindings
Odysseas Gabrielides 02107450d0 Squashed 'src/dashbls/' changes from 795660db76..4e070243ae
4e070243ae chore: bump version to 1.3.3 (#99)
d93956254e ci: disable Go bindings CI for macos for now (#98)
ae40c5c86d Merge pull request #97 from PastaPastaPasta/refac/pybind-bump-2.13.6
e835ece935 refactor: bump pybind version to 2.13.6
eda5d6a402 chore: change of gmp source (#95)
61f95aa80e chore: cleanup 6.2.1 left overs (#96)
adbd094409 Merge pull request #92 from kwvg/darwin_gmp
062ee6726b Merge pull request #90 from UdjinM6/fix_aarch_arch
3538d8b033 fix: aarch64 is not supported, should set ARCH to RELIC_NONE
e27a62f4a2 revert: disable gmp if targeting darwin on aarch64 when on 'auto'
bb2fe6ee55 build: enforce minimum version of libgmp based on arch and platform
9832b7a132 build: replace deprecated macros `AC_PROG_CC_C99` and `AM_PROG_CC_C_O`
b2428718b9 Merge pull request #91 from UdjinM6/fix_macos_test_build
3ffa7fa2b6 chore: bump version to 1.3.2 (#94)
0f4efc9327 Merge pull request #88 from HashEngineering/feat/support-android
a181889489 fix: rust bindings build for macos (#89)
738d187359 fix: detect gmp via brew earlier
ce4d6a47b6 fix: install libtool
4fa46ccaff fix: use macos-latest for test build
69bdc1aac7 Merge pull request #85 from kwvg/debug
39791d4e31 build: print build options after configure
73106a0121 build: use `-mbranch-protection=bti` on supporting `aarch64` compilers
6a3c28f6ca build: use stricter `-Werror` when testing compile flags
7a1b227637 build: rename {`NO`}`WARN_CFLAGS` to {`NO`}`WARN_FLAGS`, use with C{++}
28bea63838 build: set {`NO`}`WARN_CFLAGS` flags if not overridden and uniformly
32c2f0f5f8 trivial: rename `CORE_CXXFLAGS` to `CORE_FLAGS`, use with C{++}
b630c2c323 build: append `HARDENED_FLAGS` to `AM_CFLAGS`
e6008148e4 trivial: rename `HARDENED_CXXFLAGS` to `HARDENED_FLAGS`
af0e3daef5 build: subsume `PI{C,E}_FLAGS` into `HARDENED_CXXFLAGS`
9ff8618a1b build: expand `--disable-optimizations` to include `-O0` and `-fwrapv`
3036b83181 build: expand `--enable-debug` to include `-O0`, `-ftrapv` and dbg info
c90d43d43b build: add check to see if `CFLAGS` has been overridden
2d77f7ae49 build: remove vestigial `LIBTOOL_{CXX,CPP,LD}FLAGS`, `HARDENED_CPPFLAGS`
883a098868 build: autodetect i?86 and arm as 32-bit
deb3269820 build: don't specify exact `{CPU_}ARCH` if optimizations are disabled
720d49a44b trivial: fix indentation for `want_backend` check
f9328320af build: use `easy` backend if optimizations are disabled unless specified
3687cd59e0 build: define new flag `--enable-optimizations`
f82bfee5dd build: ensure help string format matches Autotool defaults
d68920063e build: define arguments as `--enable-[term]` instead of `--disable-[term]`
7f41e7dd16 fix: support android
1c2fc79c19 feat(rust): allow to move G1 and G2 elements between threads (#87)
3540b8bbed feat: debug with data hex (#86)

git-subtree-dir: src/dashbls
git-subtree-split: 4e070243aed142bc458472f8807ab77527dd879a
2024-10-09 17:25:18 +03:00
..
benchmark.py Squashed 'src/dashbls/' content from commit 66ee820fbc 2022-12-30 00:59:17 +05:30
CMakeLists.txt Squashed 'src/dashbls/' changes from 795660db76..4e070243ae 2024-10-09 17:25:18 +03:00
pythonbindings.cpp Squashed 'src/dashbls/' content from commit 66ee820fbc 2022-12-30 00:59:17 +05:30
README.md Squashed 'src/dashbls/' content from commit 66ee820fbc 2022-12-30 00:59:17 +05:30
test.py Squashed 'src/dashbls/' content from commit 66ee820fbc 2022-12-30 00:59:17 +05:30

Python bindings

Use the full power and efficiency of the C++ bls library, but in a few lines of python!

Install

pip3 install blspy

Alternatively, to install from source, run the following, in the project root directory:

pip3 install .

Cmake, a c++ compiler, and a recent version of pip3 (v18) are required for source install. GMP(speed) is an optional dependency. Public keys are G1Elements, and signatures are G2Elements.

Then, to use:

Import the library

from blspy import (PrivateKey, Util, AugSchemeMPL, PopSchemeMPL,
                   G1Element, G2Element)

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).
seed: bytes = bytes([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])
sk: PrivateKey = AugSchemeMPL.key_gen(seed)
pk: G1Element = sk.get_g1()

message: bytes = bytes([1, 2, 3, 4, 5])
signature: G2Element = AugSchemeMPL.sign(sk, message)

# Verify the signature
ok: bool = AugSchemeMPL.verify(pk, message, signature)
assert ok

Serializing keys and signatures to bytes

sk_bytes: bytes = bytes(sk)  # 32 bytes
pk_bytes: bytes = bytes(pk)  # 48 bytes
signature_bytes: bytes = bytes(signature)  # 96 bytes

print(sk_bytes.hex(), pk_bytes.hex(), signature_bytes.hex())

Loading keys and signatures from bytes

sk = PrivateKey.from_bytes(sk_bytes)
pk = G1Element.from_bytes(pk_bytes)
signature = G2Element.from_bytes(signature_bytes)

Create aggregate signatures

# Generate some more private keys
seed = bytes([1]) + seed[1:]
sk1: PrivateKey = AugSchemeMPL.key_gen(seed)
seed = bytes([2]) + seed[1:]
sk2: PrivateKey = AugSchemeMPL.key_gen(seed)
message2: bytes = bytes([1, 2, 3, 4, 5, 6, 7])

# Generate first sig
pk1: G1Element = sk1.get_g1()
sig1: G2Element = AugSchemeMPL.sign(sk1, message)

# Generate second sig
pk2: G1Element = sk2.get_g1()
sig2: G2Element = AugSchemeMPL.sign(sk2, message2)

# Signatures can be non-interactively combined by anyone
agg_sig: G2Element = AugSchemeMPL.aggregate([sig1, sig2])

ok = AugSchemeMPL.aggregate_verify([pk1, pk2], [message, message2], agg_sig)

Arbitrary trees of aggregates

seed = bytes([3]) + seed[1:]
sk3: PrivateKey = AugSchemeMPL.key_gen(seed)
pk3: G1Element = sk3.get_g1()
message3: bytes = bytes([100, 2, 254, 88, 90, 45, 23])
sig3: G2Element = AugSchemeMPL.sign(sk3, message3)

agg_sig_final: G2Element = AugSchemeMPL.aggregate([agg_sig, sig3])
ok = AugSchemeMPL.aggregate_verify([pk1, pk2, pk3], [message, message2, message3], agg_sig_final)

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.
pop_sig1: G2Element = PopSchemeMPL.sign(sk1, message)
pop_sig2: G2Element = PopSchemeMPL.sign(sk2, message)
pop_sig3: G2Element = PopSchemeMPL.sign(sk3, message)
pop1: G2Element = PopSchemeMPL.pop_prove(sk1)
pop2: G2Element = PopSchemeMPL.pop_prove(sk2)
pop3: G2Element = PopSchemeMPL.pop_prove(sk3)

ok = PopSchemeMPL.pop_verify(pk1, pop1)
ok = PopSchemeMPL.pop_verify(pk2, pop2)
ok = PopSchemeMPL.pop_verify(pk3, pop3)

pop_sig_agg: G2Element = PopSchemeMPL.aggregate([pop_sig1, pop_sig2, pop_sig3])

ok = PopSchemeMPL.fast_aggregate_verify([pk1, pk2, pk3], message, pop_sig_agg)

# Aggregate public key, indistinguishable from a single public key
pop_agg_pk: G1Element = pk1 + pk2 + pk3
ok = PopSchemeMPL.verify(pop_agg_pk, message, pop_sig_agg)

# Aggregate private keys
pop_agg_sk: PrivateKey = PrivateKey.aggregate([sk1, sk2, sk3])
ok = PopSchemeMPL.sign(pop_agg_sk, message) == pop_sig_agg

HD keys using EIP-2333

master_sk: PrivateKey = AugSchemeMPL.key_gen(seed)
child: PrivateKey = AugSchemeMPL.derive_child_sk(master_sk, 152)
grandchild: PrivateKey = AugSchemeMPL.derive_child_sk(child, 952)

master_pk: G1Element = master_sk.get_g1()
child_u: PrivateKey = AugSchemeMPL.derive_child_sk_unhardened(master_sk, 22)
grandchild_u: PrivateKey = AugSchemeMPL.derive_child_sk_unhardened(child_u, 0)

child_u_pk: G1Element = AugSchemeMPL.derive_child_pk_unhardened(master_pk, 22)
grandchild_u_pk: G1Element = AugSchemeMPL.derive_child_pk_unhardened(child_u_pk, 0)

ok = (grandchild_u_pk == grandchild_u.get_g1())