Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: bls key generation #141

Merged
merged 20 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,27 @@ jobs:
strategy:
max-parallel: 4
matrix:
# python-version: ["3.10"]
ItsANameToo marked this conversation as resolved.
Show resolved Hide resolved
ItsANameToo marked this conversation as resolved.
Show resolved Hide resolved
python-version: ["3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v1
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: true
ref: ${{ github.head_ref }}

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: install dependencies
run: |
python3 -m venv venv
. venv/bin/activate
pip install .[test]

- name: run tests
run: |
. venv/bin/activate
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "thirdparty/bls-signatures"]
path = thirdparty/bls-signatures
url = https://github.com/ArkEcosystem/bls-signatures
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@
## Guide for contributing

1. Fork the repository on GitHub.
2. Run the tests to confirm they all pass on your system. If they don’t, you’ll need to investigate why they fail. If you’re unable to diagnose this yourself raise it as a bug report.
3. Make your change.
4. Write tests that demonstrate your bug or feature.
5. Run the entire test suite again, confirming that all tests pass including the ones you just added.
6. Send a GitHub Pull Request. GitHub Pull Requests are the expected method of code collaboration on this project.
2. Clone locally (making sure to load submodules): `git clone --recurse-submodules [email protected]:ArkEcosystem/python-crypto.git`
3. Run the tests to confirm they all pass on your system. If they don’t, you’ll need to investigate why they fail. If you’re unable to diagnose this yourself raise it as a bug report.
4. Make your change.
5. Write tests that demonstrate your bug or feature.
6. Run the entire test suite again, confirming that all tests pass including the ones you just added.
7. Send a GitHub Pull Request. GitHub Pull Requests are the expected method of code collaboration on this project.

If you have any questions, requests or ideas open an issue or ask us in #developers channel on the [ArkEcosystem Discord](https://discord.ark.io/).

Expand Down
37 changes: 37 additions & 0 deletions crypto/identity/bls_private_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from btclib.mnemonic import bip39

import sys
import os
from os.path import dirname

sys.path.append(os.path.join(dirname(dirname(dirname(__file__))), 'thirdparty/bls-signatures/python-impl'))

from schemes import BasicSchemeMPL

class BLSPrivateKey(object):
def __init__(self, private_key: bytes):
self.private_key = private_key

def to_hex(self):
"""Returns a private key in hex format

Returns:
str: private key in hex format
"""
return self.private_key.hex()

@classmethod
def from_passphrase(cls, passphrase: str):
"""Create PrivateKey object from a given passphrase

Args:
passphrase (str):

Returns:
PrivateKey: Private key object
"""
seed = bip39.seed_from_mnemonic(passphrase, '')

sk = BasicSchemeMPL.key_gen(seed)

return cls(bytes(BasicSchemeMPL.derive_child_sk(sk, 0)))
22 changes: 22 additions & 0 deletions crypto/identity/bls_public_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import sys
import os
from os.path import dirname

sys.path.append(os.path.join(dirname(dirname(dirname(__file__))), 'thirdparty/bls-signatures/python-impl'))

from schemes import PrivateKey

from crypto.identity.bls_private_key import BLSPrivateKey

class BLSPublicKey:
def __init__(self, public_key: bytes):
self.public_key = public_key

def to_hex(self) -> str:
return self.public_key.hex()

@classmethod
def from_passphrase(cls, passphrase: str):
private_key = BLSPrivateKey.from_passphrase(passphrase)

return cls(bytes(PrivateKey.from_bytes(private_key.private_key).get_g1()))
3 changes: 3 additions & 0 deletions crypto/transactions/builder/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ def multi_sign(self, passphrase, index):
if not self.transaction.signatures:
self.transaction.signatures = []

if self.transaction.senderPublicKey is None:
raise Exception('Sender Public Key is required for multi signature')

index = len(self.transaction.signatures) if index == -1 else index

msg = self.transaction.to_bytes()
Expand Down
12 changes: 9 additions & 3 deletions crypto/transactions/builder/validator_registration.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
from typing import Optional

import blspy

from crypto.constants import TRANSACTION_VALIDATOR_REGISTRATION
from crypto.transactions.builder.base import BaseTransactionBuilder

import sys
import os
from os.path import dirname

sys.path.append(os.path.join(dirname(dirname(dirname(__file__))), 'thirdparty/bls-signatures/python-impl'))

from ec import G1FromBytes

class ValidatorRegistration(BaseTransactionBuilder):
transaction_type = TRANSACTION_VALIDATOR_REGISTRATION

Expand Down Expand Up @@ -34,6 +40,6 @@ def validate_bls_public_key(self, public_key: str):
raise ValueError('Invalid BLS public key')

try:
blspy.PublicKeyMPL.from_bytes(bytes.fromhex(public_key))
G1FromBytes(bytes.fromhex(public_key)).check_valid()
except Exception:
raise ValueError('Invalid BLS public key')
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ attrs==23.2.0
base58==2.1.1
beautifulsoup4==4.12.3
binary-helpers==0.0.4
blspy==2.0.3
btclib==2023.7.12
btclib_libsecp256k1==0.4.0
cached-property==1.5.2
Expand All @@ -14,6 +13,7 @@ charset-normalizer==3.3.2
coincurve==20.0.0
commonmark==0.9.1
coverage==7.5.4
cryptography==43.0.0
cytoolz==0.12.3
eth-hash==0.7.0
eth-typing==4.4.0
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
requires = [
'base58',
'binary-helpers',
'blspy',
'coincurve',
'pycryptodomex',
'btclib',
'cryptography',
]

tests_require = [
Expand Down
117 changes: 117 additions & 0 deletions tests/identity/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,120 @@ def identity():
'passphrase': 'my super secret passphrase'
}
return data

@pytest.fixture
def validator():
"""Validator fixture
"""
return {
'bls_public_key': 'b0093ac8f37588e15df7cfb04d0722dc5486cec062233136d3b6a16d41946577a1f332c4c29c0601ccefac1905dbb611',
'bls_private_key': '3c0e55f46009b02bd739a16945babe797e6cbd096294dcc2550bce4baea2bde9',
'passphrase': 'bless organ december boring ill obvious unaware dinosaur broccoli build hamster rebuild skin airport stay entry denial agent october thought duck trouble decorate way',
}

@pytest.fixture
def bls_keys():
"""BLS private keys fixture
"""
return [
{
'bls_public_key': '90507d5a1a4cde6729f61a0e8fcc34f854113faf05f995b3ffd320639c4ffd118c335099350c92daa58e9ba22ca71af1',
'bls_private_key': '710b0de2981d407d144161a5123f498a88355e3b0a559aa7942d90d49d0d5b34',
'passphrase': 'famous dolphin salad photo spend stock portion outdoor print fiscal element smoke silent ritual verify current better raw visual mom real bubble certain banana',
},
{
'bls_public_key': 'af7f00ec30273a99411aa940ecf40646fa684f82d7d70e536a76c7c02e8ee6f3ffd297c42ad3775922938a31925bc1ab',
'bls_private_key': '5a010d4c79c01fc4d26fcce16a601da683bd2dcb67aa09d6d4ab29042020e62b',
'passphrase': 'good copper economy hope purity budget mistake achieve tail endless travel vibrant office cement inmate gospel effort desert garbage fiscal direct siege bright habit',
},
{
'bls_public_key': '84e79b94cc89e0a95b8aaa57949f04986f00ac3c28518af5e85152cd3806159dce3a3cd371b7a9c07568c43de6c3f621',
'bls_private_key': '311886ef722406cdad272e4930679fb06b0bbe2ba12593cc48fa93547c60ba46',
'passphrase': 'hidden soap wall giant abuse force raw coral spy assault key parade churn reflect lounge fly yellow awkward air ocean young melody cake decide',
},
{
'bls_public_key': 'aab82e8feea3ece5b7ccf99d820dc13b28f443d387ef371c8556671f2359469a5952d610624b85747ac4ba8ae9cbfb6b',
'bls_private_key': '5432d15659b8a75a692e5800bd9c2d8f2515e45716ccb1d4b1b366447a7c1451',
'passphrase': 'salt refuse nothing ordinary rigid exile fitness acoustic enjoy top pole miracle stem clinic range multiply worry jump question broken whip hidden annual umbrella',
},
{
'bls_public_key': 'a18dfb7ba3053845bf26f9e4038cb1b964670140b855c2558d329a4a7df0ad81f413d24deb9e6edf87780b3ab2ba1f4b',
'bls_private_key': '46180073978c64b90b062759408ed18729ee2031944cca65b0bdfa2789116949',
'passphrase': 'bounce salon piece fire vacuum laundry welcome solution ribbon ivory street smoke birth library announce duck case refuse cry first camp what turn canal',
},
{
'bls_public_key': '85caef761ec3845f5f835ea749e274ca90e3515d485219e8a3b469358f1cbf796926ef438e813db684e8f3a05b0210d8',
'bls_private_key': '20d999f46f2d25e3338c4509faab59177310e648503e6f86818bb4a5a71b1a1f',
'passphrase': 'always predict vocal eager pluck food check today obscure cancel coil begin muscle mistake onion fruit forget extra cousin shoulder cradle chase toss short',
},
{
'bls_public_key': 'b79975e1f4eefea36eef216295b8b9d46fac639943bc5e1a8aa5815f1593b592466e0df424d5a2136e05cf3ae8e75b15',
'bls_private_key': '2acea7bda926715a45f327a3d686bb35105b88dce85be9c80218e148402eff0a',
'passphrase': 'slam peanut energy bright network gas subway have aerobic scare planet depth lazy claim render civil capable green panel loud venue warfare melt jelly',
},
{
'bls_public_key': 'b0c002ade13cbff5f6c696e86b27ccca2ea396ccf2c7a686ab82f07ea3b38234ffd7eb6858cad6cdc09a6032e5653115',
'bls_private_key': '03d12d4ed66ea5866cc5fd998958a3dd02d5605a34294a57ad300860c1c21b27',
'passphrase': 'essence giant awful mixed mistake task vocal prevent room spot weird car safe mom gorilla reopen ability syrup step omit column shell rotate crumble',
},
{
'bls_public_key': 'a158a42fb1862f16cdc59fa69a57d57bd86931ad856030dd28550377e69ebc586dc5cb3444c5d89a92de05cb7f5467ad',
'bls_private_key': '664b966a562ebf45125834dd5b9505221d40bf712f679442281dd3d380b8c56a',
'passphrase': 'this fix sort sword knee more hill into innocent idea bargain have phrase fall zebra manage casino apology leisure arch shrimp target patrol cradle',
},
{
'bls_public_key': '9720ffa79fc8e9f04c153653c5cbc5bb1d2f1fc387d2640f6023585da3f3344374367240249e667d7f640fd1e0828202',
'bls_private_key': '6237b95b32b77331fa0fc760d607f104b0bc975e789f226853d8e3f0daf985e1',
'passphrase': 'paper ghost fatigue citizen broom radar honey success mother toilet insane all filter dutch excite kid dignity gaze exist layer elegant nerve lake silver',
},
{
'bls_public_key': '870b7c4db4ca1902e3d1aaf82e993e8c78f1b66b59febf7c41aceba45abe1403136c8b32a2ab3ad66d6fa2c40a724935',
'bls_private_key': '0bb418ef9a25dc1f4cb1568c6b29abdc262b86d6589027b002b47f65fa4fd454',
'passphrase': 'aisle orbit train among zero correct task sell scheme combine harsh gasp scissors addict tank key trust mirror immense common barely accident industry road',
},
{
'bls_public_key': '8bc136c71bd8fbb02c01ef2b90c7d0ade4f82d6275117e21e7794861487c9ce74c9e6f6470ab06a25d41b650f140a304',
'bls_private_key': '183894353dc05c1c2bb7d3030d7638cadb951c07f560a4af79ab1a4057fccf57',
'passphrase': 'trend exotic educate fantasy truck day amateur worth home more spice display jelly ivory swift mind assume what total often grace process dizzy payment',
},
{
'bls_public_key': 'a97a89995be26a0dce2e6b53b08453eb37b6705210527cf39c40fa928fdb31b62b580794f794c52d273d650fe066bf60',
'bls_private_key': '46c042254f22e5d779faa8c799c1b1f6673468195a367a4b328344c8fdc4572d',
'passphrase': 'cabbage rhythm rice pelican vintage benefit soccer stove pioneer bleak fossil emerge tell pretty champion depart today lobster into abandon dignity perfect scissors silly',
},
{
'bls_public_key': '8925b5568d5f97be7ba52d39c96cae06133b1deffa4b030529205ca8548e6ae0df91875aa34d59cc6fe1787f9e05f42b',
'bls_private_key': '6191cad0ba2f8c4bc3fe148d0f4e119c117f31c3b8320bd976db5f631b761b62',
'passphrase': 'romance eyebrow capital dinner apple video extend puppy rely pistol tissue color dynamic parade ketchup mother giraffe vintage basic risk orchard paddle another disagree',
},
{
'bls_public_key': '8aefc9325c182ddc2ae8fd6825871481b28966ff6e876da7bb72db86cc8fc8df7d01e6b52b01bd5c0478f3006cdf819f',
'bls_private_key': '1e0a8618b7e867c46ce04e1b1071977340d3a2175241878c899dceeda4fad764',
'passphrase': 'stereo tank target husband local retreat liquid zero master shy control viable ceiling negative universe glove tomato neglect rain motion cage early cherry sock',
},
{
'bls_public_key': 'b1186f7dee7d5dad1e451eb5c18ade0d9d706dd0ceea7d8407ee6e6656caadf6426f08ce8e0f31260892e685c3f4c4e1',
'bls_private_key': '56d24d247c4cb234ce3e18a61ad94484d8c949e4df1211d28caa8115d300da2d',
'passphrase': 'ladder where left grid stand code exercise cattle success rent air keep enhance news time six often fat similar quantum open rain bag code',
},
{
'bls_public_key': '8942eb575dd8a1e0145125471eb594b7724574f92f604415d8b0c5e3056ee183e304797c033a6ad81c6c5a18de7647fd',
'bls_private_key': '5313dc4c76303f43ad04d25274ba776268efd95dcf960ea671684a9f91fd5f7d',
'passphrase': 'huge sorry trash price oxygen sheriff hello purchase era enrich life pole basket infant wing release injury punch inflict good much bargain pair biology',
},
{
'bls_public_key': '8cacf7a6fdca95d05261ae074fb108e014022393f636a02890c27b8c3235624650f5d357cde2fc037f312a956f2a9b1b',
'bls_private_key': '139341609069795a42a2fbbb3dcc335fdc80b86f1c473f2c7d270ed8a580467b',
'passphrase': 'increase garbage input leaf accuse hold proud begin copy wire sell immense crop slide coach nerve food assume attack matrix text announce appear mobile',
},
{
'bls_public_key': 'afe1816457e64227fb1a3da8a3141caaa4cd03937b5ba5e2b454801f4f058d1536d8e64adbb2f1a9b5e2956dcfdbe101',
'bls_private_key': '30f661095ecd42a5e5ea0685e56accb26ebf99c635720a253139177e5acde38d',
'passphrase': 'wine apology crew sick pet fork twelve fluid flavor perfect phrase love crime attack simple emotion smart visa keen saddle unlock foil crush neck',
},
{
'bls_public_key': '84950d69eeb3d84552a61a1a4e4eaa0bf3f3c924abe9cd84f5673cdbc79bc0d664a56478b0faedce995d4367b57331cf',
'bls_private_key': '305430a7d6571049cea36418c65c150314b6a0787af701a5a4a38237307eae5e',
'passphrase': 'simple capital style robot duck police dose life bacon library figure wonder involve glory gallery cattle hockey balance home rigid arrive buyer crouch whale',
},
]
14 changes: 14 additions & 0 deletions tests/identity/test_bls_private_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from crypto.identity.bls_public_key import BLSPrivateKey


def test_private_key_from_passphrase(validator):
private_key = BLSPrivateKey.from_passphrase(validator['passphrase']).to_hex()

assert private_key == validator['bls_private_key']


def test_many_private_keys_from_passphrase(bls_keys):
for bls_private_key in bls_keys:
private_key = BLSPrivateKey.from_passphrase(bls_private_key['passphrase']).to_hex()

assert private_key == bls_private_key['bls_private_key']
14 changes: 14 additions & 0 deletions tests/identity/test_bls_public_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from crypto.identity.bls_public_key import BLSPublicKey


def test_public_key_from_passphrase(validator):
public_key = BLSPublicKey.from_passphrase(validator['passphrase']).to_hex()

assert public_key == validator['bls_public_key']


def test_many_public_keys_from_passphrase(bls_keys):
for bls_public_key in bls_keys:
private_key = BLSPublicKey.from_passphrase(bls_public_key['passphrase']).to_hex()

assert private_key == bls_public_key['bls_public_key']
1 change: 1 addition & 0 deletions thirdparty/bls-signatures
Submodule bls-signatures added at 239f9f