This repository was archived by the owner on Jul 1, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 147
This repository was archived by the owner on Jul 1, 2021. It is now read-only.
Swappable BLS backend #746
Copy link
Copy link
Closed
Labels
Description
What is wrong?
After #708 we have a fast BLS API based on Chia's implementation. But we might want the freedom to switch between different implementation for different use cases.
For example,
- To try out a new verification scheme, we might still want py_ecc.
- To make the testnet fast, we want Chia's implementation.
- Some state test we just want a dummy verification function that returns True, when the correctness of signature is not a concern.
How can it be fixed
- Defined an interface and create classes for each BLS implementation (Let's call them backends). As the bottommost sample code shows.
- There are two possible ways to apply these backends:
Option 1: Pass as an argument to functions that need BLS methods
For example,
def foo(..., bls: BaseBLSBackend):
...
bls.sign(...)
This makes inserting the desired backend to production code and testing code very easy. The downside is the diffs will bubble up to lots of functions and we need to reason that ultimately which class should hold these backends as their property (Chain, StateMachine, or StateTransition?).
Option 2: Import and mock in test
For example,
from eth2._utils.bls import (
PyECCBackend as bls,
)
def foo(...):
...
bls.sign(...)
This is more like the current status. The pros and cons are opposite to option 1. Need inputs from @pipermerriam @cburgdorf @hwwhww
# eth2/_utils/bls.py
from abc import (
ABC,
abstractstaticmethod,
)
from typing import (
Sequence,
)
from eth_typing import (
BLSPubkey,
BLSSignature,
Hash32,
)
from py_ecc import (
bls as py_ecc_api,
)
from .bls_bindings.chia_network import (
api as chia_api,
)
class BaseBLSBackend(ABC):
@abstractstaticmethod
def privtopub(k: int) -> BLSPubkey:
pass
@abstractstaticmethod
def sign(message_hash: Hash32,
privkey: int,
domain: int) -> BLSSignature:
pass
@abstractstaticmethod
def verify(message_hash: Hash32,
pubkey: BLSPubkey,
signature: BLSSignature,
domain: int) -> bool:
pass
@abstractstaticmethod
def aggregate_signatures(signatures: Sequence[BLSSignature]) -> BLSSignature:
pass
@abstractstaticmethod
def aggregate_pubkeys(pubkeys: Sequence[BLSPubkey]) -> BLSPubkey:
pass
@abstractstaticmethod
def verify_multiple(pubkeys: Sequence[BLSPubkey],
message_hashes: Sequence[Hash32],
signature: BLSSignature,
domain: int) -> bool:
pass
class PyECCBackend(BaseBLSBackend):
privtopub = py_ecc_api.privtopub
sign = py_ecc_api.sign
verify = py_ecc_api.verify
aggregate_signatures = py_ecc_api.aggregate_signatures
aggregate_pubkeys = py_ecc_api.aggregate_pubkeys
verify_multiple = py_ecc_api.verify_multiple
class ChiaBackend(BaseBLSBackend):
privtopub = chia_api.privtopub
sign = chia_api.sign
verify = chia_api.verify
aggregate_signatures = chia_api.aggregate_signatures
aggregate_pubkeys = chia_api.aggregate_pubkeys
verify_multiple = chia_api.verify_multiple
class TrueBackend(BaseBLSBackend):
"""
Only for test
"""
def privtopub(k: int) -> BLSPubkey:
raise NotImplementedError
def sign(message_hash: Hash32,
privkey: int,
domain: int) -> BLSSignature:
raise NotImplementedError
def verify(message_hash: Hash32,
pubkey: BLSPubkey,
signature: BLSSignature,
domain: int) -> bool:
return True
def aggregate_signatures(signatures: Sequence[BLSSignature]) -> BLSSignature:
raise NotImplementedError
def aggregate_pubkeys(pubkeys: Sequence[BLSPubkey]) -> BLSPubkey:
raise NotImplementedError
def verify_multiple(pubkeys: Sequence[BLSPubkey],
message_hashes: Sequence[Hash32],
signature: BLSSignature,
domain: int) -> bool:
return True