diff --git a/cosmpy/crypto/keypairs_bls.py b/cosmpy/crypto/keypairs_bls.py deleted file mode 100644 index d60a7169..00000000 --- a/cosmpy/crypto/keypairs_bls.py +++ /dev/null @@ -1,230 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2022 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""BLS Crypto KeyPairs (Public Key and Private Key) and utility functions.""" -import base64 -import hashlib -from typing import Callable, List, Optional - -from blspy import ( # type: ignore # pylint: disable=no-name-in-module - AugSchemeMPL, - G1Element, - G2Element, -) -from blspy import PrivateKey as BLSPrivateKey # pylint: disable=no-name-in-module -from ecdsa.curves import NIST256p -from ecdsa.keys import SigningKey - -from cosmpy.crypto.interface import Signer - - -class PublicKey: - """BLS public key class.""" - - HASH_FUNCTION: Callable = hashlib.sha256 - - def __init__(self, public_key: bytes): - """ - Initialize. - - :param public_key: bytes. - """ - self._public_key_bytes = public_key - self._public_key = base64.b64encode(self._public_key_bytes).decode() - self._verifying_key = G1Element.from_bytes(self._public_key_bytes) - - @property - def public_key(self) -> str: - """ - Get public key. - - :return: str public key. - """ - return self._public_key - - @property - def public_key_hex(self) -> str: - """ - Get public key hex. - - :return: str public key hex. - """ - return self.public_key_bytes.hex() - - @property - def public_key_bytes(self) -> bytes: - """ - Get bytes public key. - - :return: bytes public key. - """ - return self._public_key_bytes - - def verify(self, message: bytes, signature: bytes) -> bool: - """ - Verify message and signature. - - :param message: bytes message content. - :param signature: bytes signature. - :return: bool is message and signature valid. - """ - digest = self.HASH_FUNCTION(message).digest() - return self.verify_digest(digest, signature) - - def verify_digest(self, digest: bytes, signature: bytes) -> bool: - """ - Verify digest. - - :param digest: bytes digest. - :param signature: bytes signature. - :return: bool is digest valid. - """ - return AugSchemeMPL.verify( - self._verifying_key, digest, G2Element.from_bytes(signature) - ) - - -class PrivateKey(Signer, PublicKey): - """BLS private key class.""" - - HASH_FUNCTION: Callable = hashlib.sha256 - - def __init__(self, private_key: Optional[bytes] = None): - """ - Initialize. - - :param private_key: the private key. Defaults to None.. - """ - self._private_key_bytes = private_key or self._generate_bytes() - self._private_key = base64.b64encode(self._private_key_bytes).decode() - self._signing_key: BLSPrivateKey = AugSchemeMPL.key_gen(self._private_key_bytes) - PublicKey.__init__(self, public_key=bytes(self._signing_key.get_g1())) - - @property - def private_key(self) -> str: - """ - Get private key. - - :return: str private key. - """ - return self._private_key - - @property - def private_key_hex(self) -> str: - """ - Get private key hex. - - :return: str private key hex. - """ - return self.private_key_bytes.hex() - - @property - def private_key_bytes(self) -> bytes: - """ - Get bytes private key. - - :return: bytes private key. - """ - return self._private_key_bytes - - @staticmethod - def _generate_bytes() -> bytes: - """ - Generate random bytes sequence 32 bytes long. - - :return: bytes - """ - return SigningKey.generate(curve=NIST256p).to_string() - - def sign( - self, message: bytes, deterministic: bool = True, canonicalise: bool = True - ) -> bytes: - """ - Sign message. - - :param message: bytes message content. - :param deterministic: bool is deterministic. - :param canonicalise: bool is canonicalise. - - :return: bytes signed message. - """ - digest = self.HASH_FUNCTION(message).digest() - return self.sign_digest(digest) - - def sign_digest( - self, digest: bytes, deterministic=True, canonicalise: bool = True - ) -> bytes: - """ - Sign digest. - - :param digest: bytes digest content. - :param deterministic: bool is deterministic. - :param canonicalise: bool is canonicalise. - - :return: bytes signed digest. - """ - return bytes(AugSchemeMPL.sign(self._signing_key, digest)) - - -def aggregate_signatures(*sigs: List[bytes]) -> bytes: - """ - Combine signatures into one. - - :param *sigs: list of signatures bytes. - :return: bytes - """ - return bytes(AugSchemeMPL.aggregate([G2Element.from_bytes(i) for i in sigs])) - - -def verify_aggregated_signatures( - pks: List[PublicKey], - msgs: List[bytes], - aggregated_signature: bytes, - hashfunc=hashlib.sha256, -): - """ - Verify signatures with pub keys and messages. - - :param pks: list of public keys - :param msgs: list of messages - :param aggregated_signature: aggregated signature bytes - :param hashfunc: hash method from hashlib. default is hashlib.sha256 - :return: bool - """ - return verify_aggregated_signatures_digests( - pks, [hashfunc(i).digest() for i in msgs], aggregated_signature - ) - - -def verify_aggregated_signatures_digests( - pks: List[PublicKey], digests: List[bytes], aggregated_signature: bytes -): - """ - Verify signatures with pub keys and messages. - - :param pks: list of public keys - :param digests: list of digests calculated - :param aggregated_signature: aggregated signature bytes - :return: bool - """ - return AugSchemeMPL.aggregate_verify( - [G1Element.from_bytes(pk.public_key_bytes) for pk in pks], - digests, - G2Element.from_bytes(aggregated_signature), - ) diff --git a/poetry.lock b/poetry.lock index b8837e6d..fa316154 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.0 and should not be changed by hand. [[package]] name = "astroid" @@ -105,43 +105,6 @@ d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] -[[package]] -name = "blspy" -version = "2.0.2" -description = "BLS signatures in c++ (python bindings)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "blspy-2.0.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:c053733d674ff92fcb4059b36b75c29337d34afbd900a0bc2113ad86fc447b77"}, - {file = "blspy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dbb053ccb1b48584cc4d357f29c770a2cf3e05faa8b184bd9294e8ed01a565b5"}, - {file = "blspy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a0b208b80fa76c9adf296a77aa805127840cf5ca8f1af6e8c223f803d1770c5"}, - {file = "blspy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc615db0f93911c24bb6512140e8f098f506d455c44fa1830fdb98e2590bc9f0"}, - {file = "blspy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c5581b44d0a4e01ba55183cadfc0139b9a97620c7910a5487023918f07b85271"}, - {file = "blspy-2.0.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:fdb1dfc95c2563a7c3faa31e729ef972f5be04bcfd4478cc40e97e7df6c81bfb"}, - {file = "blspy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ebff8fdecf5ce5d4fabd9f39d0a1a5bce66e560f7bd7126f300cfebe69ca5aff"}, - {file = "blspy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29731d2f8203bee252bc8b80347486a17c278bf7ab6e0956a44a45a91e2d595d"}, - {file = "blspy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67fe57111005f2ea19536b526c92e70567118fbba1f5bfc5aa59949a52127852"}, - {file = "blspy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:7347d140e0f2082f311b944385db2bacbe01363622754a237e9024e417b35f8c"}, - {file = "blspy-2.0.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:e0c7c685aed512adf8691be054c0c0cc87a66b0323f2434a6341fe49076d78ab"}, - {file = "blspy-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:368da188d7eb4298e4ca59d253e8a11639534af045959c85f58f4c188fa361c1"}, - {file = "blspy-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9555039e51281ffe34bcb06215512721b5cd509102db68267eab8b314258c41"}, - {file = "blspy-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:e31a1a9adbf04b5f09321c5fa6b9fdc50bdc685d2f4c8335444e95513d81090e"}, - {file = "blspy-2.0.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:b2988f1ac4fa5063d3fb30ff5272ba5b51877d551120085dc9e1257d3228e89c"}, - {file = "blspy-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c51b2be0b81b786e6bc786c41735fbda0e335d31e2e163ef735ae56c6d3adb7f"}, - {file = "blspy-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0e8fd5f7729e08451e7ef66134f377e4bf88a9ea25a010f27bcf881e89541ee"}, - {file = "blspy-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5603dc3fb30e622be31dd8d1bbfdd5624291f8c56f076a1d177836959c733cff"}, - {file = "blspy-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:bf30732ac316b8cafaeaeefa694a96ea4a92922fb86dd3d30f79d48a202e1d51"}, - {file = "blspy-2.0.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:286a684b1f645d3c38ccc7882a305ed1b038a0e603ff2f482e493c91ab0f0b58"}, - {file = "blspy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:744043f6e4192f3b431f1433b07144bd198294fd129c9b4a19e0c122474df32b"}, - {file = "blspy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fb12e7158230f7169781fddf6a4c15dd4366de26d1531a09df986f9706332a"}, - {file = "blspy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b7183ef57f8675c9d29f4f66ba3a65280fd3742200fc4d8f2f7a53b98b77136"}, - {file = "blspy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:21df21e27b5f7ed56e37f8a6272adb9273ba88d0570d26315e28a41e14c37f43"}, - {file = "blspy-2.0.2.tar.gz", hash = "sha256:9b12d685f3c104d3fe0faf3618f6b824272d131b8ea3843190ad670618736775"}, -] - -[package.dependencies] -wheel = "*" - [[package]] name = "build" version = "0.10.0" @@ -2180,20 +2143,6 @@ files = [ [package.extras] watchmedo = ["PyYAML (>=3.10)"] -[[package]] -name = "wheel" -version = "0.40.0" -description = "A built-package format for Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "wheel-0.40.0-py3-none-any.whl", hash = "sha256:d236b20e7cb522daf2390fa84c55eea81c5c30190f90f29ae2ca1ad8355bf247"}, - {file = "wheel-0.40.0.tar.gz", hash = "sha256:cd1196f3faee2b31968d626e1731c94f99cbdb67cf5a46e4f5656cbee7738873"}, -] - -[package.extras] -test = ["pytest (>=6.0.0)"] - [[package]] name = "wrapt" version = "1.15.0" @@ -2312,4 +2261,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.8,<3.12" -content-hash = "79d04c2689c954ca66052ff56a0b9ad5c2402e9dc40f32b9fb7492289d9f3f8f" +content-hash = "9d3dbda776e9c315c98bff97aeac1987bca83e6299a373a0f958f60d4cf15f6f" diff --git a/pyproject.toml b/pyproject.toml index c5d9ce96..7895fd3c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,6 @@ bech32 = "*" requests = "*" protobuf = ">=4.21.6,<5.0dev" grpcio = "==1.51.1" -blspy = "*" jsonschema = ">=3.2.0,<5" python-dateutil = "*" pycryptodome = "^3.18.0" diff --git a/strategy.ini b/strategy.ini index 46965e8d..62e2f0f0 100644 --- a/strategy.ini +++ b/strategy.ini @@ -87,5 +87,4 @@ unauthorized_licenses: [Authorized Packages] pathspec: >=0.9.0 certifi: >=2019.11.28 -blspy: >=1.0.14 pycryptodome: >=3.15.0 diff --git a/tests/unit/test_crypto/test_keypairs_bls.py b/tests/unit/test_crypto/test_keypairs_bls.py deleted file mode 100644 index 600e2f83..00000000 --- a/tests/unit/test_crypto/test_keypairs_bls.py +++ /dev/null @@ -1,109 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2022 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""Tests for BLS KeyPair module of the Crypto Package.""" -from cosmpy.crypto.keypairs_bls import ( - PrivateKey, - PublicKey, - aggregate_signatures, - verify_aggregated_signatures, -) - - -def test_basic_usecase(): - """Test common BLS keys and signatures use case.""" - msg = b"some" - pk1 = PrivateKey() - signature1 = pk1.sign(msg) - assert pk1.verify(msg, signature1) - pk2 = PrivateKey() - signature2 = pk2.sign(msg) - assert pk2.verify(msg, signature2) - - pk3 = PrivateKey() - signature3 = pk3.sign(msg) - assert pk3.verify(msg, signature3) - - assert not pk3.verify(msg, signature2) - - aggregated_signature = aggregate_signatures(signature1, signature2) - - assert verify_aggregated_signatures([pk1, pk2], [msg] * 2, aggregated_signature) - - assert not verify_aggregated_signatures([pk1, pk3], [msg] * 2, aggregated_signature) - - -def test_private_key(): - """Test BLS private key class.""" - priv_key = PrivateKey() - assert priv_key.private_key - assert len(priv_key.private_key_bytes) == 32 - assert len(priv_key.private_key_hex) == 64 - - new_priv_key = PrivateKey(priv_key.private_key_bytes) - assert priv_key.public_key_bytes == new_priv_key.public_key_bytes - - message = b"some" - assert priv_key.sign(message) != priv_key.sign_digest(message) - - -def test_public_key(): - """Test BLS public key class.""" - priv_key = PrivateKey() - pub_key = PublicKey(priv_key.public_key_bytes) - assert pub_key.public_key - assert len(pub_key.public_key_bytes) == 48 - assert len(pub_key.public_key_hex) == 96 - - message = b"some" - signature = priv_key.sign(message) - signature_for_digest = priv_key.sign_digest(message) - - assert pub_key.verify(message, signature) - assert pub_key.verify_digest(message, signature_for_digest) - - assert not pub_key.verify(message, signature_for_digest) - assert not pub_key.verify_digest(message, signature) - - -def test_pub_key_hardcoded_signature_check(): - """Check signature of the pub key provided.""" - pub_key = PublicKey( - b"\x92\x08eo\xb9\x03\xf1\\\x05\xd4\x8fa\xfd}-\x913\\\x1e~\xe6\xbd\xd3Eu\xf43\x05\x88\xfc\x1f\x18\x08\xf8B\x98\xf6-v\xc0\xcbQvpb\xcf\xe0q" - ) - message = b"random message" - signature = b"\x87\xcd\xf8z\xfe|P\xe6\x93\x15H\xdd\x9e&\xbf(\xaa\x06\xb7\xce3\xba\x1e \x0e\xea3\x8f3\xdc$.\x04V\xa9,\xd7\xa1\xf5^\x13\x13\xfeNd\xa8\xcb,\x14\xc3p|Zy\xe8\x95\xf5'%Q\x82\xc9,\xe4\x88x\xae\xd3?\xd0\\D]\xcfQ:\xf6\xb9\xdbK\xf5\xbeS\x16\x05\x06\x15\xfff\x1b\x0f\xf4\x1a\xc4\xeb\xf0" - - assert pub_key.verify(message, signature) - - -def test_aggregated_signature_hardcoded(): - """Check hardcoded aggregated signature.""" - msg = b"some" - pub_key1 = PublicKey( - b"\x84}\x9d\xa2\x90\xa78%?\xb9\x1c\x86/:4\xa4b\x12\x95\xff1\xde\xc6L'P\xd9\x8e\xd0\x0b \x7f \xcd\xfc\xeeO'\xc8d\xbd\x06\x9d\xbb\xb2\xcd\x16R" - ) - pub_key2 = PublicKey( - b"\xac\xa7\xf3\x02JSsv\xbf*f\xde\x8c\xec\xa1\x83|\x84\xcc\tU2\xfb /\xce\xb8\xd3$hY\r\xbf\x99/\xa1\xccU\x12\x027z\x1a\xa549\x88\\" - ) - aggregated_signature = b"\x93\xd9\x80l3[\xaa\xb3\xfa|\xf0\x84\x04O\xac\xe7H\xd6\xa7\xbc \t\x8bB\xdfO\x886\xdbW\xda5F \xfb\x91\xd9\x85x \xab\xeb\xb3\xb3\x10\xc0$M\x02\xcf\x06\xb0L|W\xbb\x1a\xed0\xf6\x17[\xd8\x01\xb5\x96\xf3\xe5\xfbC\x17'\xaf\xe5\xa5\x8e\xc1\xbe\xa1) \xac\x8cC\x1f\xbd\xb8\xfb\x9b\x14!g\xbec\r>" - - assert verify_aggregated_signatures( - [pub_key1, pub_key2], [msg] * 2, aggregated_signature - )