Skip to content
This repository was archived by the owner on Jul 1, 2021. It is now read-only.
This repository was archived by the owner on Jul 1, 2021. It is now read-only.

Swappable BLS backend #746

@ChihChengLiang

Description

@ChihChengLiang

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

  1. Defined an interface and create classes for each BLS implementation (Let's call them backends). As the bottommost sample code shows.
  2. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions