{"id":18683515,"url":"https://github.com/narasimha1997/bls-server","last_synced_at":"2026-05-06T03:31:42.774Z","repository":{"id":104766636,"uuid":"541924811","full_name":"Narasimha1997/bls-server","owner":"Narasimha1997","description":"A gRPC server written in python that provides BLS (Boneh–Lynn–Shacham) signatures related functionalities like signing, verification and signatures aggregation - used in production at some places.","archived":false,"fork":false,"pushed_at":"2022-10-10T09:00:52.000Z","size":44,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-18T17:14:18.939Z","etag":null,"topics":["bls-signature","bls12-381","elliptic-curve-cryptography","elliptic-curves","grpc","microservices","python","python3"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Narasimha1997.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-27T05:54:27.000Z","updated_at":"2024-09-25T04:34:08.000Z","dependencies_parsed_at":"2023-05-29T16:15:25.448Z","dependency_job_id":null,"html_url":"https://github.com/Narasimha1997/bls-server","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Narasimha1997/bls-server","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Narasimha1997%2Fbls-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Narasimha1997%2Fbls-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Narasimha1997%2Fbls-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Narasimha1997%2Fbls-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Narasimha1997","download_url":"https://codeload.github.com/Narasimha1997/bls-server/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Narasimha1997%2Fbls-server/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32677894,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-06T02:33:58.958Z","status":"ssl_error","status_checked_at":"2026-05-06T02:33:39.611Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bls-signature","bls12-381","elliptic-curve-cryptography","elliptic-curves","grpc","microservices","python","python3"],"created_at":"2024-11-07T10:14:49.665Z","updated_at":"2026-05-06T03:31:42.753Z","avatar_url":"https://github.com/Narasimha1997.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# bls-server\nA gRPC server written in python that provides BLS (Boneh–Lynn–Shacham) signatures related functionalities like signing, verification and signatures aggregation - used in production at some places. The core BLS implementation is taken from [BLS12-381 C++ library used in Chia-blockchain](https://github.com/Chia-Network/bls-signatures). You can read more about BLS12-381 here - [BLS12-381: New zk-SNARK Elliptic Curve Construction](https://electriccoin.co/blog/new-snark-curve/) and [Pairing-Friendly Curves](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-02). \n\n## Using bls-server as a microservice\nThe `Dockerfile` used in this repository can be used to build and deploy the server as a container. The server is also completely stateless and can be scaled up and down whenever required without having to worry about the state management.\n\nTo build the container image using docker:\n```\ndocker build . -t bls-server:latest\n```\n\nTo run:\n```\ndocker run --rm -p 8000:8000 -v $PWD/keydir:/keydir --env='KEY_STORAGE_PARAMETERS=file_path=/keydir/keys.json' bls-server:latest\n```\n\n## List of available gRPC calls\n###  1. Generate a new key-pair (private and public key)\nRequest format:\n```\n// get the public key as hex-string\nmessage GenerateKeypairRequestHex {\n    bytes seed = 1;\n    string key_id = 2;\n}\n\n// get the public key as bytes\nmessage GenerateKeypairRequestRaw {\n    bytes seed = 1;\n    string key_id = 2;\n}\n```\n`seed` is a 32-byte random bytes which is used to generate the private key, if seed is empty server will use `os.urandom()` to generate a random byte sequence as seed.\n`key_id` is the unique identifier with which the key can be identified, if `key_id` already exists, instead of generating a new key-pair, the public key will be derived from the existing key and returned.\n\nThe keys created using this RPC call will be stored in the key-store (look at key-backend section).\n\nResponse format:\n```\n// response when GenerateKeypairRaw is invoked\nmessage GenerateKeypairResponseRaw {\n    bool success = 1;\n    bytes public_key = 2;\n    string error_message = 3;\n}\n\n// response when GenerateKeypairHex is invoked\nmessage GenerateKeypairResponseHex {\n    bool success = 1;\n    string public_key = 2;\n    string error_message = 3;\n}\n```\n`error_message` is non-empty when `success` is `false`.\n\ngRPC calls:\n```\n// raw\nrpc GenerateKeypairRaw (bls_proto.GenerateKeypairRequestRaw) returns(bls_proto.GenerateKeypairResponseRaw);\n// hex\nrpc GenerateKeypairHex (bls_proto.GenerateKeypairRequestHex) returns(bls_proto.GenerateKeypairResponseHex);\n```\n\n### 2. Sign messages using the private key\nRequest format:\n```\n// sign a raw bytes message, returns a bytes signature\nmessage SignRequestRaw {\n    string key_identity = 1;\n    bytes message = 2;\n}\n\n// sign a hex message, returns a hex signature\nmessage SignRequestHex {\n    string key_identity = 1;\n    string message = 2;\n}\n```\nHere the `key_identity` is a unique key which we used when creating calling `GenerateKeypairRaw` or `GenerateKeypairHex` to identify a private key.\n\nResponse format:\n```\n// response when SignRaw is invoked\nmessage SignResponseRaw {\n    bool success = 1;\n    bytes signature = 2;\n    string error_message = 3;\n}\n\n// response when SignHex is invoked\nmessage SignResponseHex {\n    bool success = 1;\n    string signature = 2;\n    string error_message = 3;\n}\n```\n`error_message` is non-empty when `success` is `false`.\n\ngRPC calls:\n```\n// raw\nrpc SignRaw (bls_proto.SignRequestRaw) returns(bls_proto.SignResponseRaw);\n// hex\nrpc SignHex (bls_proto.SignRequestHex) returns(bls_proto.SignResponseHex);\n```\n\n### 3. Verifying signatures\nRequest format:\n```\n// all the fields in bytes\nmessage VerifyRequestRaw {\n    bytes public_key = 1;\n    bytes message = 2;\n    bytes signature = 3;\n}\n\n// all the fields in hex\nmessage VerifyRequestHex {\n    string public_key = 1;\n    string message = 2;\n    string signature = 3;\n}\n```\n`public_key` is the public key of the private key used for signing, `message` is the message which was signed and `signature` is the signature obtained as a result of signing `message` using the private key by the server (response of `SignRaw` or `SignHex `).\n\nResponse format:\n```\nmessage VerifyResponse {\n    bool success = 1;\n    bool is_verified = 2;\n    string error_message = 3;\n}\n```\n`error_message` is non-empty when `success` is `false`.\n\ngRPC calls:\n```\n// raw\nrpc VerifyRaw (bls_proto.VerifyRequestRaw) returns(bls_proto.VerifyResponse);\n// hex\nrpc VerifyHex (bls_proto.VerifyRequestHex) returns(bls_proto.VerifyResponse);\n```\n\n### 4. Create aggregate signatures\nRequest format:\n```\n// send signatures as bytes, the aggregated signature will also be returned as bytes\nmessage AggregateRequestRaw {\n    repeated bytes signatures = 1;\n}\n\n// send signatures as hex, the aggregated signature will also be returned as hex\nmessage AggregateRequestHex {\n    repeated string signatures = 2;\n}\n```\n`signatures` is an array of signatures that needs to be aggregated into a single signature.\n\nResponse format:\n```\n// returned when AggregateRaw is called\nmessage AggregateResponseRaw {\n    bool success = 1;\n    bytes signature = 2;\n    string error_message = 3;\n}\n\n// returned when AggregateHex is called\nmessage AggregateResponseHex {\n    bool success = 1;\n    string signature = 2;\n    string error_message = 3;\n}\n```\n`error_message` is non-empty when `success` is `false`.\n\ngRPC calls:\n```\n// raw\nrpc AggregateRaw (bls_proto.AggregateRequestRaw) returns(bls_proto.AggregateResponseRaw);// hex\n// hex\nrpc AggregateHex (bls_proto.AggregateRequestHex) returns(bls_proto.AggregateResponseHex);\n```\n\n### 5. Verify aggregated signatures\nRequest format:\n```\n// all the fields are in bytes\nmessage VerifyAggregateRequestRaw {\n    repeated bytes public_keys = 1;\n    repeated bytes messages = 2; \n    bytes aggregate_signature = 3;\n}\n\n// all the fields are in hex\nmessage VerifyAggregateRequestHex {\n    repeated string public_keys = 1;\n    repeated string messages = 2; \n    string aggregate_signature = 3;\n}\n```\n`public_keys` contains list of public keys whose private keys were used for signing the messages - the public keys has to be passed per each message in the `messages` field. `aggregate_signature` is the aggregated signature (usually obtained when calling `AggregateRaw` and `AggregateHex`.\n\nResponse format:\n```\nmessage VerifyAggregateResponse {\n    bool success = 1;\n    bool is_verified = 2;\n    string error_message = 3;\n}\n```\n\ngRPC calls:\n```\n// raw\nrpc VerifyAggregatedRaw (bls_proto.VerifyAggregateRequestRaw) returns (bls_proto.VerifyAggregateResponse);\n// hex\nrpc VerifyAggregatedHex (bls_proto.VerifyAggregateRequestHex) returns (bls_proto.VerifyAggregateResponse);\n```\n\n## Private-Key storage backend\nThe server doesn't provide any de-factor storage for private keys because different people might expect different levels of security while storing the keys. The codebase in the repository provides `FileStorageBackend` which stores all the private keys un-encrypted in a JSON file - this is not recommended to be used in production and must be considered only for the sake of reference. The backend provides a simple base class that any storage implementation has to override to implement it's own functionality. The base class is shown below:\n\n```python3\nclass PrivateKeyBackend:\n\n    # the custom parameters provided in the  env will be passed during the init\n    def __init__(self, **kwargs):\n        pass\n\n    # `put` will be called when a new key needs to be saved, return `PrivateKeyBackendPutException` if something fails while put\n    def put(self, key_id: str, key: str):\n        pass\n\n    # `get` will be called when obtaining the private key from the storage, return `PrivateKeyBackendGetException` if something fails while get\n    def get(self, key_id):\n        pass\n```\nThe definitions of `PrivateKeyBackendPutException` and `PrivateKeyBackendGetException` are as shown below:\n```python3\nclass PrivateKeyBackendPutException(Exception):\n    def __init__(self, *args: object) -\u003e None:\n        super().__init__(*args)\n        self.cause = self.args[0]\n        self.key = self.args[1]\n\n    def __str__(self) -\u003e str:\n        return \"put_error={}\".format(self.cause)\n\n\nclass PrivateKeyBackendGetException(Exception):\n    def __init__(self, *args: object) -\u003e None:\n        super().__init__(*args)\n        self.cause = self.args[0]\n\n    def __str__(self) -\u003e str:\n        return \"get_error={}\".format(self.cause)\n```\nThe `PrivateKeyBackendPutException` can also be used to supply the existing `key` if the `key_id` is already present. Look at the implementation of `FileStorageBackend` for more.\n\n## Running tests\nTests can be executed locally to validate the functionalities, you have to install `pytest` package and `pytest-dependency` plugin to run tests.\n```\npip3 install pytest pytest-dependency\n```\nNow run the tests:\n```\npytest server/test.py\n```\n\n## Contributing\nFeel free to raise issues, make PRs and suggest any changes.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnarasimha1997%2Fbls-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnarasimha1997%2Fbls-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnarasimha1997%2Fbls-server/lists"}