From d27f2350a2079644595be83e5e03cb6a0f8ff696 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 15 May 2020 00:45:26 +0800 Subject: [PATCH 1/6] Update BLS test suite to BLS standard draft v2 format 1. Make sure that BLS -Verify APIs would only return `True` or `False` , no exceptions. 2. Use `eth2spec.utils.bls` instead of py_ecc for test generator 3. Add assertions in test generator 4. Add some special test cases for the -Verify APIs 5. Clean up the test format documents --- tests/core/pyspec/eth2spec/utils/bls.py | 26 +++- .../bls/{aggregate_sigs.md => aggregate.md} | 2 +- tests/formats/bls/aggregate_pubkeys.md | 19 --- tests/formats/bls/aggregate_verify.md | 17 +++ tests/formats/bls/fast_aggregate_verify.md | 17 +++ tests/formats/bls/msg_hash_g2_compressed.md | 21 ---- tests/formats/bls/msg_hash_g2_uncompressed.md | 21 ---- tests/formats/bls/priv_to_pub.md | 19 --- tests/formats/bls/{sign_msg.md => sign.md} | 6 - tests/formats/bls/verify.md | 17 +++ tests/generators/bls/main.py | 116 ++++++++++++++---- 11 files changed, 165 insertions(+), 116 deletions(-) rename tests/formats/bls/{aggregate_sigs.md => aggregate.md} (78%) delete mode 100644 tests/formats/bls/aggregate_pubkeys.md create mode 100644 tests/formats/bls/aggregate_verify.md create mode 100644 tests/formats/bls/fast_aggregate_verify.md delete mode 100644 tests/formats/bls/msg_hash_g2_compressed.md delete mode 100644 tests/formats/bls/msg_hash_g2_uncompressed.md delete mode 100644 tests/formats/bls/priv_to_pub.md rename tests/formats/bls/{sign_msg.md => sign.md} (67%) create mode 100644 tests/formats/bls/verify.md diff --git a/tests/core/pyspec/eth2spec/utils/bls.py b/tests/core/pyspec/eth2spec/utils/bls.py index 7f265b555..acf9f99c7 100644 --- a/tests/core/pyspec/eth2spec/utils/bls.py +++ b/tests/core/pyspec/eth2spec/utils/bls.py @@ -25,17 +25,32 @@ def only_with_bls(alt_return=None): @only_with_bls(alt_return=True) def Verify(PK, message, signature): - return bls.Verify(PK, message, signature) + try: + result = bls.Verify(PK, message, signature) + except Exception: + result = False + finally: + return result @only_with_bls(alt_return=True) def AggregateVerify(pubkeys, messages, signature): - return bls.AggregateVerify(pubkeys, messages, signature) + try: + result = bls.AggregateVerify(pubkeys, messages, signature) + except Exception: + result = False + finally: + return result @only_with_bls(alt_return=True) def FastAggregateVerify(pubkeys, message, signature): - return bls.FastAggregateVerify(pubkeys, message, signature) + try: + result = bls.FastAggregateVerify(pubkeys, message, signature) + except Exception: + result = False + finally: + return result @only_with_bls(alt_return=STUB_SIGNATURE) @@ -56,3 +71,8 @@ def signature_to_G2(signature): @only_with_bls(alt_return=STUB_PUBKEY) def AggregatePKs(pubkeys): return bls._AggregatePKs(pubkeys) + + +@only_with_bls(alt_return=STUB_SIGNATURE) +def SkToPk(SK): + return bls.SkToPk(SK) diff --git a/tests/formats/bls/aggregate_sigs.md b/tests/formats/bls/aggregate.md similarity index 78% rename from tests/formats/bls/aggregate_sigs.md rename to tests/formats/bls/aggregate.md index 2252dbaa8..0d7e7c631 100644 --- a/tests/formats/bls/aggregate_sigs.md +++ b/tests/formats/bls/aggregate.md @@ -16,4 +16,4 @@ output: BLS Signature -- expected output, single BLS signature ## Condition -The `aggregate_sigs` handler should aggregate the signatures in the `input`, and the result should match the expected `output`. +The `aggregate` handler should aggregate the signatures in the `input`, and the result should match the expected `output`. diff --git a/tests/formats/bls/aggregate_pubkeys.md b/tests/formats/bls/aggregate_pubkeys.md deleted file mode 100644 index 049ad6991..000000000 --- a/tests/formats/bls/aggregate_pubkeys.md +++ /dev/null @@ -1,19 +0,0 @@ -# Test format: BLS pubkey aggregation - -A BLS pubkey aggregation combines a series of pubkeys into a single pubkey. - -## Test case format - -The test data is declared in a `data.yaml` file: - -```yaml -input: List[BLS Pubkey] -- list of input BLS pubkeys -output: BLS Pubkey -- expected output, single BLS pubkey -``` - -`BLS Pubkey` here is encoded as a string: hexadecimal encoding of 48 bytes (96 nibbles), prefixed with `0x`. - - -## Condition - -The `aggregate_pubkeys` handler should aggregate the keys in the `input`, and the result should match the expected `output`. diff --git a/tests/formats/bls/aggregate_verify.md b/tests/formats/bls/aggregate_verify.md new file mode 100644 index 000000000..3985de9f4 --- /dev/null +++ b/tests/formats/bls/aggregate_verify.md @@ -0,0 +1,17 @@ +# Test format: BLS sign message + +Verify the signature against the given pubkeys and one messages. + +## Test case format + +The test data is declared in a `data.yaml` file: + +```yaml +input: + pubkeys: List[bytes48] -- the pubkeys + messages: List[bytes32] -- the messages + signature: bytes96 -- the signature to verify against pubkeys and messages +output: bool -- VALID or INVALID +``` + +All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`. diff --git a/tests/formats/bls/fast_aggregate_verify.md b/tests/formats/bls/fast_aggregate_verify.md new file mode 100644 index 000000000..7e3899a15 --- /dev/null +++ b/tests/formats/bls/fast_aggregate_verify.md @@ -0,0 +1,17 @@ +# Test format: BLS sign message + +Verify the signature against the given pubkeys and one message. + +## Test case format + +The test data is declared in a `data.yaml` file: + +```yaml +input: + pubkeys: List[bytes48] -- the pubkey + message: bytes32 -- the message + signature: bytes96 -- the signature to verify against pubkeys and message +output: bool -- VALID or INVALID +``` + +All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`. diff --git a/tests/formats/bls/msg_hash_g2_compressed.md b/tests/formats/bls/msg_hash_g2_compressed.md deleted file mode 100644 index 761e819f2..000000000 --- a/tests/formats/bls/msg_hash_g2_compressed.md +++ /dev/null @@ -1,21 +0,0 @@ -# Test format: BLS hash-compressed - -A BLS compressed-hash to G2. - -## Test case format - -The test data is declared in a `data.yaml` file: - -```yaml -input: - message: bytes32 - domain: bytes8 -- the BLS domain -output: List[bytes48] -- length of two -``` - -All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`. - - -## Condition - -The `msg_hash_g2_compressed` handler should hash the `message`, with the given `domain`, to G2 with compression, and the result should match the expected `output`. diff --git a/tests/formats/bls/msg_hash_g2_uncompressed.md b/tests/formats/bls/msg_hash_g2_uncompressed.md deleted file mode 100644 index 5ee535a38..000000000 --- a/tests/formats/bls/msg_hash_g2_uncompressed.md +++ /dev/null @@ -1,21 +0,0 @@ -# Test format: BLS hash-uncompressed - -A BLS uncompressed-hash to G2. - -## Test case format - -The test data is declared in a `data.yaml` file: - -```yaml -input: - message: bytes32 - domain: bytes8 -- the BLS domain -output: List[List[bytes48]] -- 3 lists, each a length of two -``` - -All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`. - - -## Condition - -The `msg_hash_g2_uncompressed` handler should hash the `message`, with the given `domain`, to G2, without compression, and the result should match the expected `output`. diff --git a/tests/formats/bls/priv_to_pub.md b/tests/formats/bls/priv_to_pub.md deleted file mode 100644 index 29c6b216a..000000000 --- a/tests/formats/bls/priv_to_pub.md +++ /dev/null @@ -1,19 +0,0 @@ -# Test format: BLS private key to pubkey - -A BLS private key to public key conversion. - -## Test case format - -The test data is declared in a `data.yaml` file: - -```yaml -input: bytes32 -- the private key -output: bytes48 -- the public key -``` - -All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`. - - -## Condition - -The `priv_to_pub` handler should compute the public key for the given private key `input`, and the result should match the expected `output`. diff --git a/tests/formats/bls/sign_msg.md b/tests/formats/bls/sign.md similarity index 67% rename from tests/formats/bls/sign_msg.md rename to tests/formats/bls/sign.md index 6c4f88cd1..1c328755a 100644 --- a/tests/formats/bls/sign_msg.md +++ b/tests/formats/bls/sign.md @@ -10,13 +10,7 @@ The test data is declared in a `data.yaml` file: input: privkey: bytes32 -- the private key used for signing message: bytes32 -- input message to sign (a hash) - domain: bytes8 -- the BLS domain output: bytes96 -- expected signature ``` All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`. - - -## Condition - -The `sign_msg` handler should sign the given `message`, with `domain`, using the given `privkey`, and the result should match the expected `output`. diff --git a/tests/formats/bls/verify.md b/tests/formats/bls/verify.md new file mode 100644 index 000000000..57ec8a33a --- /dev/null +++ b/tests/formats/bls/verify.md @@ -0,0 +1,17 @@ +# Test format: BLS sign message + +Verify the signature against the given one pubkey and one message. + +## Test case format + +The test data is declared in a `data.yaml` file: + +```yaml +input: + pubkey: bytes48 -- the pubkey + message: bytes32 -- the message + signature: bytes96 -- the signature to verify against pubkey and message +output: bool -- VALID or INVALID +``` + +All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`. diff --git a/tests/generators/bls/main.py b/tests/generators/bls/main.py index 7bb093593..f97be3c90 100644 --- a/tests/generators/bls/main.py +++ b/tests/generators/bls/main.py @@ -10,7 +10,7 @@ from eth_utils import ( ) from gen_base import gen_runner, gen_typing -from py_ecc import bls +from eth2spec.utils import bls from hashlib import sha256 from eth2spec.test.context import PHASE0 @@ -19,11 +19,6 @@ def hash(x): return sha256(x).digest() -F2Q_COEFF_LEN = 48 -G2_COMPRESSED_Z_LEN = 48 -DST = bls.G2ProofOfPossession.DST - - def int_to_hex(n: int, byte_length: int = None) -> str: byte_value = int_to_big_endian(n) if byte_length: @@ -49,11 +44,15 @@ PRIVKEYS = [ hex_to_int('0x00000000000000000000000000000000328388aff0d4a5b7dc9205abd374e7e98f3cd9f3418edb4eafda5fb16473d216'), ] +NO_PUBKEY = b'\x00' * 48 +Z1_PUBKEY = b'\xc0' + b'\x00' * 47 +NO_SIGNATURE = b'\x00' * 96 +Z2_SIGNATURE = b'\xc0' + b'\x00' * 95 def case01_sign(): for privkey in PRIVKEYS: for message in MESSAGES: - sig = bls.G2ProofOfPossession.Sign(privkey, message) + sig = bls.Sign(privkey, message) identifier = f'{int_to_hex(privkey)}_{encode_hex(message)}' yield f'sign_case_{(hash(bytes(identifier, "utf-8"))[:8]).hex()}', { 'input': { @@ -68,9 +67,10 @@ def case02_verify(): for i, privkey in enumerate(PRIVKEYS): for message in MESSAGES: # Valid signature - signature = bls.G2ProofOfPossession.Sign(privkey, message) - pubkey = bls.G2ProofOfPossession.SkToPk(privkey) + signature = bls.Sign(privkey, message) + pubkey = bls.SkToPk(privkey) identifier = f'{encode_hex(pubkey)}_{encode_hex(message)}' + assert bls.Verify(pubkey, message, signature) yield f'verify_valid_case_{(hash(bytes(identifier, "utf-8"))[:8]).hex()}', { 'input': { 'pubkey': encode_hex(pubkey), @@ -81,8 +81,9 @@ def case02_verify(): } # Invalid signatures -- wrong pubkey - wrong_pubkey = bls.G2ProofOfPossession.SkToPk(PRIVKEYS[(i + 1) % len(PRIVKEYS)]) + wrong_pubkey = bls.SkToPk(PRIVKEYS[(i + 1) % len(PRIVKEYS)]) identifier = f'{encode_hex(wrong_pubkey)}_{encode_hex(message)}' + assert not bls.Verify(wrong_pubkey, message, signature) yield f'verify_wrong_pubkey_case_{(hash(bytes(identifier, "utf-8"))[:8]).hex()}', { 'input': { 'pubkey': encode_hex(wrong_pubkey), @@ -95,6 +96,7 @@ def case02_verify(): # Invalid signature -- tampered with signature tampered_signature = signature[:-4] + b'\xFF\xFF\xFF\xFF' identifier = f'{encode_hex(pubkey)}_{encode_hex(message)}' + assert not bls.Verify(pubkey, message, tampered_signature) yield f'verify_tampered_signature_case_{(hash(bytes(identifier, "utf-8"))[:8]).hex()}', { 'input': { 'pubkey': encode_hex(pubkey), @@ -104,26 +106,37 @@ def case02_verify(): 'output': False, } + # Valid pubkey and signature with the point at infinity + assert bls.Verify(Z1_PUBKEY, message, Z2_SIGNATURE) + yield f'verify_infinity_pubkey_and_infinity_signature', { + 'input': { + 'pubkey': encode_hex(Z1_PUBKEY), + 'message': encode_hex(message), + 'signature': encode_hex(Z2_SIGNATURE), + }, + 'output': True, + } def case03_aggregate(): for message in MESSAGES: - sigs = [bls.G2ProofOfPossession.Sign(privkey, message) for privkey in PRIVKEYS] + sigs = [bls.Sign(privkey, message) for privkey in PRIVKEYS] yield f'aggregate_{encode_hex(message)}', { 'input': [encode_hex(sig) for sig in sigs], - 'output': encode_hex(bls.G2ProofOfPossession.Aggregate(sigs)), + 'output': encode_hex(bls.Aggregate(sigs)), } def case04_fast_aggregate_verify(): for i, message in enumerate(MESSAGES): privkeys = PRIVKEYS[:i + 1] - sigs = [bls.G2ProofOfPossession.Sign(privkey, message) for privkey in privkeys] - aggregate_signature = bls.G2ProofOfPossession.Aggregate(sigs) - pubkeys = [bls.G2ProofOfPossession.SkToPk(privkey) for privkey in privkeys] + sigs = [bls.Sign(privkey, message) for privkey in privkeys] + aggregate_signature = bls.Aggregate(sigs) + pubkeys = [bls.SkToPk(privkey) for privkey in privkeys] pubkeys_serial = [encode_hex(pubkey) for pubkey in pubkeys] # Valid signature identifier = f'{pubkeys_serial}_{encode_hex(message)}' + assert bls.FastAggregateVerify(pubkeys, message, aggregate_signature) yield f'fast_aggregate_verify_valid_{(hash(bytes(identifier, "utf-8"))[:8]).hex()}', { 'input': { 'pubkeys': pubkeys_serial, @@ -134,9 +147,10 @@ def case04_fast_aggregate_verify(): } # Invalid signature -- extra pubkey - pubkeys_extra = pubkeys + [bls.G2ProofOfPossession.SkToPk(PRIVKEYS[-1])] + pubkeys_extra = pubkeys + [bls.SkToPk(PRIVKEYS[-1])] pubkeys_extra_serial = [encode_hex(pubkey) for pubkey in pubkeys_extra] identifier = f'{pubkeys_extra_serial}_{encode_hex(message)}' + assert not bls.FastAggregateVerify(pubkeys_extra, message, aggregate_signature) yield f'fast_aggregate_verify_extra_pubkey_{(hash(bytes(identifier, "utf-8"))[:8]).hex()}', { 'input': { 'pubkeys': pubkeys_extra_serial, @@ -149,6 +163,7 @@ def case04_fast_aggregate_verify(): # Invalid signature -- tampered with signature tampered_signature = aggregate_signature[:-4] + b'\xff\xff\xff\xff' identifier = f'{pubkeys_serial}_{encode_hex(message)}' + assert not bls.FastAggregateVerify(pubkeys, message, tampered_signature) yield f'fast_aggregate_verify_tampered_signature_{(hash(bytes(identifier, "utf-8"))[:8]).hex()}', { 'input': { 'pubkeys': pubkeys_serial, @@ -158,37 +173,86 @@ def case04_fast_aggregate_verify(): 'output': False, } + # Invalid pubkeys and signature -- len(pubkey) == 0 and signature == Z1_SIGNATURE + assert not bls.FastAggregateVerify([], message, Z2_SIGNATURE) + yield f'fast_aggregate_verify_na_pubkeys_and_infinity_signature', { + 'input': { + 'pubkeys': [], + 'message': encode_hex(message), + 'signature': encode_hex(Z2_SIGNATURE), + }, + 'output': False, + } + + # Invalid pubkeys and signature -- len(pubkey) == 0 and signature == 0x00... + assert not bls.FastAggregateVerify([], message, NO_SIGNATURE) + yield f'fast_aggregate_verify_na_pubkeys_and_na_signature', { + 'input': { + 'pubkeys': [], + 'message': encode_hex(message), + 'signature': encode_hex(NO_SIGNATURE), + }, + 'output': False, + } def case05_aggregate_verify(): - pairs = [] + pubekys = [] + pubkeys_serial = [] + messages = [] + messages_serial = [] sigs = [] for privkey, message in zip(PRIVKEYS, MESSAGES): - sig = bls.G2ProofOfPossession.Sign(privkey, message) - pubkey = bls.G2ProofOfPossession.SkToPk(privkey) - pairs.append({ - 'pubkey': encode_hex(pubkey), - 'message': encode_hex(message), - }) + sig = bls.Sign(privkey, message) + pubkey = bls.SkToPk(privkey) + pubekys.append(pubkey) + pubkeys_serial.append(encode_hex(pubkey)) + messages.append(message) + messages_serial.append(encode_hex(message)) sigs.append(sig) - aggregate_signature = bls.G2ProofOfPossession.Aggregate(sigs) + aggregate_signature = bls.Aggregate(sigs) + assert bls.AggregateVerify(pubekys, messages, aggregate_signature) yield f'aggregate_verify_valid', { 'input': { - 'pairs': pairs, + 'pubkeys': pubkeys_serial, + 'messages': messages_serial, 'signature': encode_hex(aggregate_signature), }, 'output': True, } tampered_signature = aggregate_signature[:4] + b'\xff\xff\xff\xff' + assert not bls.AggregateVerify(pubkey, messages, tampered_signature) yield f'aggregate_verify_tampered_signature', { 'input': { - 'pairs': pairs, + 'pubkeys': pubkeys_serial, + 'messages': messages_serial, 'signature': encode_hex(tampered_signature), }, 'output': False, } + # Invalid pubkeys and signature -- len(pubkey) == 0 and signature == Z1_SIGNATURE + assert not bls.AggregateVerify([], [], Z2_SIGNATURE) + yield f'aggregate_verify_na_pubkeys_and_infinity_signature', { + 'input': { + 'pubkeys': [], + 'message': [], + 'signature': encode_hex(Z2_SIGNATURE), + }, + 'output': False, + } + + # Invalid pubkeys and signature -- len(pubkey) == 0 and signature == 0x00... + assert not bls.AggregateVerify([], [], NO_SIGNATURE) + yield f'aggregate_verify_na_pubkeys_and_na_signature', { + 'input': { + 'pubkeys': [], + 'messages': [], + 'signature': encode_hex(NO_SIGNATURE), + }, + 'output': False, + } def create_provider(handler_name: str, test_case_fn: Callable[[], Iterable[Tuple[str, Dict[str, Any]]]]) -> gen_typing.TestProvider: From 9a2559857cc862fe42940f1fcb0de3df28b82845 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 15 May 2020 01:17:11 +0800 Subject: [PATCH 2/6] Fix typo and remove unused variable --- tests/generators/bls/main.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/generators/bls/main.py b/tests/generators/bls/main.py index f97be3c90..092f1247b 100644 --- a/tests/generators/bls/main.py +++ b/tests/generators/bls/main.py @@ -15,6 +15,7 @@ from hashlib import sha256 from eth2spec.test.context import PHASE0 + def hash(x): return sha256(x).digest() @@ -44,11 +45,11 @@ PRIVKEYS = [ hex_to_int('0x00000000000000000000000000000000328388aff0d4a5b7dc9205abd374e7e98f3cd9f3418edb4eafda5fb16473d216'), ] -NO_PUBKEY = b'\x00' * 48 Z1_PUBKEY = b'\xc0' + b'\x00' * 47 NO_SIGNATURE = b'\x00' * 96 Z2_SIGNATURE = b'\xc0' + b'\x00' * 95 + def case01_sign(): for privkey in PRIVKEYS: for message in MESSAGES: @@ -117,6 +118,7 @@ def case02_verify(): 'output': True, } + def case03_aggregate(): for message in MESSAGES: sigs = [bls.Sign(privkey, message) for privkey in PRIVKEYS] @@ -195,6 +197,7 @@ def case04_fast_aggregate_verify(): 'output': False, } + def case05_aggregate_verify(): pubekys = [] pubkeys_serial = [] @@ -237,7 +240,7 @@ def case05_aggregate_verify(): yield f'aggregate_verify_na_pubkeys_and_infinity_signature', { 'input': { 'pubkeys': [], - 'message': [], + 'messages': [], 'signature': encode_hex(Z2_SIGNATURE), }, 'output': False, @@ -254,6 +257,7 @@ def case05_aggregate_verify(): 'output': False, } + def create_provider(handler_name: str, test_case_fn: Callable[[], Iterable[Tuple[str, Dict[str, Any]]]]) -> gen_typing.TestProvider: From ea99f0ab10314b4bc236aef90ec39618b7dc24ff Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 15 May 2020 03:03:47 +0800 Subject: [PATCH 3/6] Fix typo Co-authored-by: Danny Ryan --- tests/generators/bls/main.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/generators/bls/main.py b/tests/generators/bls/main.py index 092f1247b..ea7446e9b 100644 --- a/tests/generators/bls/main.py +++ b/tests/generators/bls/main.py @@ -175,7 +175,7 @@ def case04_fast_aggregate_verify(): 'output': False, } - # Invalid pubkeys and signature -- len(pubkey) == 0 and signature == Z1_SIGNATURE + # Invalid pubkeys and signature -- len(pubkeys) == 0 and signature == Z1_SIGNATURE assert not bls.FastAggregateVerify([], message, Z2_SIGNATURE) yield f'fast_aggregate_verify_na_pubkeys_and_infinity_signature', { 'input': { @@ -186,7 +186,7 @@ def case04_fast_aggregate_verify(): 'output': False, } - # Invalid pubkeys and signature -- len(pubkey) == 0 and signature == 0x00... + # Invalid pubkeys and signature -- len(pubkeys) == 0 and signature == 0x00... assert not bls.FastAggregateVerify([], message, NO_SIGNATURE) yield f'fast_aggregate_verify_na_pubkeys_and_na_signature', { 'input': { @@ -235,7 +235,7 @@ def case05_aggregate_verify(): 'output': False, } - # Invalid pubkeys and signature -- len(pubkey) == 0 and signature == Z1_SIGNATURE + # Invalid pubkeys and signature -- len(pubkeys) == 0 and signature == Z1_SIGNATURE assert not bls.AggregateVerify([], [], Z2_SIGNATURE) yield f'aggregate_verify_na_pubkeys_and_infinity_signature', { 'input': { @@ -246,7 +246,7 @@ def case05_aggregate_verify(): 'output': False, } - # Invalid pubkeys and signature -- len(pubkey) == 0 and signature == 0x00... + # Invalid pubkeys and signature -- len(pubkeys) == 0 and signature == 0x00... assert not bls.AggregateVerify([], [], NO_SIGNATURE) yield f'aggregate_verify_na_pubkeys_and_na_signature', { 'input': { From 82073a4a834de77baa44a64c74e608b8b39b50f6 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 15 May 2020 03:05:23 +0800 Subject: [PATCH 4/6] Fix typo --- tests/generators/bls/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/generators/bls/main.py b/tests/generators/bls/main.py index ea7446e9b..4ad42d0a6 100644 --- a/tests/generators/bls/main.py +++ b/tests/generators/bls/main.py @@ -199,7 +199,7 @@ def case04_fast_aggregate_verify(): def case05_aggregate_verify(): - pubekys = [] + pubkeys = [] pubkeys_serial = [] messages = [] messages_serial = [] @@ -207,14 +207,14 @@ def case05_aggregate_verify(): for privkey, message in zip(PRIVKEYS, MESSAGES): sig = bls.Sign(privkey, message) pubkey = bls.SkToPk(privkey) - pubekys.append(pubkey) + pubkeys.append(pubkey) pubkeys_serial.append(encode_hex(pubkey)) messages.append(message) messages_serial.append(encode_hex(message)) sigs.append(sig) aggregate_signature = bls.Aggregate(sigs) - assert bls.AggregateVerify(pubekys, messages, aggregate_signature) + assert bls.AggregateVerify(pubkeys, messages, aggregate_signature) yield f'aggregate_verify_valid', { 'input': { 'pubkeys': pubkeys_serial, From d07e594f92ea41c1ed1899422ebaa15d9f20c85b Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 15 May 2020 23:27:35 +0800 Subject: [PATCH 5/6] Add `Aggregate()` case --- tests/formats/bls/aggregate.md | 6 +++--- tests/generators/bls/main.py | 13 +++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/formats/bls/aggregate.md b/tests/formats/bls/aggregate.md index 0d7e7c631..af8444540 100644 --- a/tests/formats/bls/aggregate.md +++ b/tests/formats/bls/aggregate.md @@ -8,11 +8,11 @@ The test data is declared in a `data.yaml` file: ```yaml input: List[BLS Signature] -- list of input BLS signatures -output: BLS Signature -- expected output, single BLS signature +output: BLS Signature -- expected output, single BLS signature or empty. ``` -`BLS Signature` here is encoded as a string: hexadecimal encoding of 96 bytes (192 nibbles), prefixed with `0x`. - +- `BLS Signature` here is encoded as a string: hexadecimal encoding of 96 bytes (192 nibbles), prefixed with `0x`. +- No output value if the input is invalid. ## Condition diff --git a/tests/generators/bls/main.py b/tests/generators/bls/main.py index 4ad42d0a6..8c6589b36 100644 --- a/tests/generators/bls/main.py +++ b/tests/generators/bls/main.py @@ -127,6 +127,19 @@ def case03_aggregate(): 'output': encode_hex(bls.Aggregate(sigs)), } + # Invalid pubkeys -- len(pubkeys) == 0 + try: + bls.Aggregate([]) + except Exception: + pass + else: + raise Exception("Should have been INVALID") + + yield f'aggregate_na_pubkeys', { + 'input': [], + 'output': None, + } + def case04_fast_aggregate_verify(): for i, message in enumerate(MESSAGES): From fd3cce0d2c791d59237d25a632110405e7d033f1 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 15 May 2020 23:38:25 +0800 Subject: [PATCH 6/6] Update README --- tests/formats/bls/README.md | 11 +++++------ tests/generators/bls/README.md | 18 ++++-------------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/tests/formats/bls/README.md b/tests/formats/bls/README.md index 4d95bdfd7..65154ba1c 100644 --- a/tests/formats/bls/README.md +++ b/tests/formats/bls/README.md @@ -5,11 +5,10 @@ We do not recommend rolling your own crypto or using an untested BLS library. The BLS test suite runner has the following handlers: -- [`aggregate_pubkeys`](./aggregate_pubkeys.md) -- [`aggregate_sigs`](./aggregate_sigs.md) -- [`msg_hash_g2_compressed`](./msg_hash_g2_compressed.md) -- [`msg_hash_g2_uncompressed`](./msg_hash_g2_uncompressed.md) -- [`priv_to_pub`](./priv_to_pub.md) -- [`sign_msg`](./sign_msg.md) +- [`aggregate_verify`](./aggregate_verify.md) +- [`aggregate`](./aggregate.md) +- [`fast_aggregate_verify`](./fast_aggregate_verify.md) +- [`sign`](./sign.md) +- [`verify`](./verify.md) *Note*: Signature-verification and aggregate-verify test cases are not yet supported. diff --git a/tests/generators/bls/README.md b/tests/generators/bls/README.md index 878bb156b..24013f88e 100644 --- a/tests/generators/bls/README.md +++ b/tests/generators/bls/README.md @@ -1,21 +1,11 @@ # BLS Test Generator -Explanation of BLS12-381 type hierarchy -The base unit is bytes48 of which only 381 bits are used +The [BLS Signature APIs](../../../specs/phase0/beacon-chain.md#bls-signatures) -- FQ: uint381 modulo field modulus -- FQ2: (FQ, FQ) -- G2: (FQ2, FQ2, FQ2) +Information on the format of the tests can be found in the [BLS test formats documentation](../../formats/bls/README.md). ## Resources -- [Eth2 spec](../../../specs/phase0/beacon-chain.md#bls-signatures) +- [IETF BLS Signature Scheme](https://datatracker.ietf.org/doc/draft-irtf-cfrg-bls-signature/) - [Finite Field Arithmetic](http://www.springeronline.com/sgw/cda/pageitems/document/cda_downloaddocument/0,11996,0-0-45-110359-0,00.pdf) -- Chapter 2 of [Elliptic Curve Cryptography](http://cacr.uwaterloo.ca/ecc/). Darrel Hankerson, Alfred Menezes, and Scott Vanstone -- [Zcash BLS parameters](https://github.com/zkcrypto/pairing/tree/master/src/bls12_381) -- [Trinity implementation](https://github.com/ethereum/trinity/blob/master/eth2/_utils/bls.py) - -## Comments - -Compared to Zcash, Ethereum specs always requires the compressed form (c_flag / most significant bit always set). -Also note that pubkeys and privkeys are reversed. +- Chapter 2 of [Elliptic Curve Cryptography](http://cacr.uwaterloo.ca/ecc/). Darrel Hankerson, Alfred Menezes, and Scott Vanstone