Skip to content

Commit

Permalink
fast-verification-of-multiple-bls-signatures
Browse files Browse the repository at this point in the history
  • Loading branch information
ChihChengLiang committed May 6, 2019
1 parent 2088796 commit 026b2f5
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 1 deletion.
1 change: 1 addition & 0 deletions py_ecc/bls/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
sign,
verify,
verify_multiple,
verify_multiple_multiple,
)
49 changes: 49 additions & 0 deletions py_ecc/bls/api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import (
Sequence,
Tuple,
)

from eth_typing import (
Expand Down Expand Up @@ -31,6 +32,9 @@
pubkey_to_G1,
signature_to_G2,
)
from secrets import (
randbelow,
)


def sign(message_hash: Hash32,
Expand Down Expand Up @@ -109,3 +113,48 @@ def verify_multiple(pubkeys: Sequence[BLSPubkey],
return final_exponentiation == FQ12.one()
except (ValidationError, ValueError, AssertionError):
return False


def verify_multiple_multiple(
signatures: Sequence[BLSSignature],
pubkeys_and_messages: Tuple[Sequence[BLSPubkey], Sequence[Hash32]],
domain: int)-> bool:
if len(signatures) != len(pubkeys_and_messages):
raise ValidationError(
"len(signatures) (%s) should be equal to len(pubkeys_and_messages) (%s)" % (
len(signatures), len(pubkeys_and_messages)
)
)
try:
random_ints = tuple(2**randbelow(64) for _ in range(len(signatures)))
o = FQ12.one()
for index, pm in enumerate(pubkeys_and_messages):
pubkeys, message_hashes = pm # type: ignore
len_msgs = len(message_hashes)
if len(pubkeys) != len_msgs:
raise ValidationError(
"len(pubkeys) (%s) should be equal to len(message_hashes) (%s)" % (
len(pubkeys), len_msgs
)
)
for m_pubs in set(message_hashes):

# aggregate the pubs
group_pub = Z1
for i in range(len_msgs):
if message_hashes[i] == m_pubs:
group_pub = add(group_pub, pubkey_to_G1(pubkeys[i]))
o *= pairing(
multiply(hash_to_G2(m_pubs, domain), random_ints[index]),
group_pub,
final_exponentiate=False,
)
agg_sig = Z2
for index, sig in enumerate(signatures):
agg_sig = add(agg_sig, multiply(signature_to_G2(sig), random_ints[index]))
o *= pairing(agg_sig, neg(G1), final_exponentiate=False)

final_exponentiation = final_exponentiate(o)
return final_exponentiation == FQ12.one()
except (ValidationError, ValueError, AssertionError):
return False
2 changes: 1 addition & 1 deletion py_ecc/bls/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def G1_to_pubkey(pt: G1Uncompressed) -> BLSPubkey:


def pubkey_to_G1(pubkey: BLSPubkey) -> G1Uncompressed:
z = big_endian_to_int(pubkey)
z = G1Compressed(big_endian_to_int(pubkey))
return decompress_G1(z)

#
Expand Down
37 changes: 37 additions & 0 deletions tests/test_bls.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
sign,
verify,
verify_multiple,
verify_multiple_multiple,
)
from py_ecc.bls.hash import (
hash_eth2,
Expand Down Expand Up @@ -44,6 +45,7 @@
normalize,
field_modulus as q,
)
from random import sample


@pytest.mark.parametrize(
Expand Down Expand Up @@ -238,3 +240,38 @@ def test_multi_aggregation(msg_1, msg_2, privkeys_1, privkeys_2):
signature=aggsig,
domain=domain,
)


def test_multi_multi():
domain = 0
validator_indices = tuple(range(10))
privkeys = tuple(2**i for i in validator_indices)
pubkeys = [privtopub(k) for k in privkeys]

class Attestation:
def __init__(self, msg_1, msg_2):
msg_1_validators = sample(validator_indices, 3)
msg_2_validators = sample(validator_indices, 3)
self.agg_pubkeys = [
aggregate_pubkeys([pubkeys[i] for i in msg_1_validators]),
aggregate_pubkeys([pubkeys[i] for i in msg_2_validators]),
]
self.msgs = [msg_1, msg_2]
msg_1_sigs = [sign(msg_1, privkeys[i], domain) for i in msg_1_validators]
msg_2_sigs = [sign(msg_2, privkeys[i], domain) for i in msg_2_validators]
self.sig = aggregate_signatures([
aggregate_signatures(msg_1_sigs),
aggregate_signatures(msg_2_sigs),
])

msgs = (
(b'\x12' * 32, b'\x34' * 32),
(b'\x56' * 32, b'\x78' * 32),
(b'\x90' * 32, b'\xab' * 32),
)
atts = [Attestation(msg_1, msg_2) for msg_1, msg_2 in msgs]
assert verify_multiple_multiple(
signatures=[att.sig for att in atts],
pubkeys_and_messages=[[att.agg_pubkeys, att.msgs] for att in atts],
domain=domain,
)

0 comments on commit 026b2f5

Please sign in to comment.