Merge pull request #2539 from ethereum/altair-bls-tests
Add tests for the Altair BLS helpers
This commit is contained in:
commit
94e7d13f0e
|
@ -46,6 +46,9 @@ def eth_aggregate_pubkeys(pubkeys: Sequence[BLSPubkey]) -> BLSPubkey:
|
||||||
Refer to the BLS signature draft standard for more information.
|
Refer to the BLS signature draft standard for more information.
|
||||||
"""
|
"""
|
||||||
assert len(pubkeys) > 0
|
assert len(pubkeys) > 0
|
||||||
|
# Ensure that the given inputs are valid pubkeys
|
||||||
|
assert all(bls.KeyValidate(pubkey) for pubkey in pubkeys)
|
||||||
|
|
||||||
result = copy(pubkeys[0])
|
result = copy(pubkeys[0])
|
||||||
for pubkey in pubkeys[1:]:
|
for pubkey in pubkeys[1:]:
|
||||||
result += pubkey
|
result += pubkey
|
||||||
|
|
|
@ -647,6 +647,7 @@ The [IETF BLS signature draft standard v4](https://tools.ietf.org/html/draft-irt
|
||||||
- `def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature`
|
- `def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature`
|
||||||
- `def FastAggregateVerify(pubkeys: Sequence[BLSPubkey], message: Bytes, signature: BLSSignature) -> bool`
|
- `def FastAggregateVerify(pubkeys: Sequence[BLSPubkey], message: Bytes, signature: BLSSignature) -> bool`
|
||||||
- `def AggregateVerify(pubkeys: Sequence[BLSPubkey], messages: Sequence[Bytes], signature: BLSSignature) -> bool`
|
- `def AggregateVerify(pubkeys: Sequence[BLSPubkey], messages: Sequence[Bytes], signature: BLSSignature) -> bool`
|
||||||
|
- `def KeyValidate(pubkey: BLSPubkey) -> bool`
|
||||||
|
|
||||||
The above functions are accessed through the `bls` module, e.g. `bls.Verify`.
|
The above functions are accessed through the `bls` module, e.g. `bls.Verify`.
|
||||||
|
|
||||||
|
|
|
@ -306,7 +306,7 @@ def test_att1_empty_indices(spec, state):
|
||||||
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True)
|
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True)
|
||||||
|
|
||||||
attester_slashing.attestation_1.attesting_indices = []
|
attester_slashing.attestation_1.attesting_indices = []
|
||||||
attester_slashing.attestation_1.signature = spec.bls.Z2_SIGNATURE
|
attester_slashing.attestation_1.signature = spec.bls.G2_POINT_AT_INFINITY
|
||||||
|
|
||||||
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
|
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
|
||||||
|
|
||||||
|
@ -318,7 +318,7 @@ def test_att2_empty_indices(spec, state):
|
||||||
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=False)
|
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=False)
|
||||||
|
|
||||||
attester_slashing.attestation_2.attesting_indices = []
|
attester_slashing.attestation_2.attesting_indices = []
|
||||||
attester_slashing.attestation_2.signature = spec.bls.Z2_SIGNATURE
|
attester_slashing.attestation_2.signature = spec.bls.G2_POINT_AT_INFINITY
|
||||||
|
|
||||||
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
|
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
|
||||||
|
|
||||||
|
@ -330,10 +330,10 @@ def test_all_empty_indices(spec, state):
|
||||||
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=False)
|
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=False)
|
||||||
|
|
||||||
attester_slashing.attestation_1.attesting_indices = []
|
attester_slashing.attestation_1.attesting_indices = []
|
||||||
attester_slashing.attestation_1.signature = spec.bls.Z2_SIGNATURE
|
attester_slashing.attestation_1.signature = spec.bls.G2_POINT_AT_INFINITY
|
||||||
|
|
||||||
attester_slashing.attestation_2.attesting_indices = []
|
attester_slashing.attestation_2.attesting_indices = []
|
||||||
attester_slashing.attestation_2.signature = spec.bls.Z2_SIGNATURE
|
attester_slashing.attestation_2.signature = spec.bls.G2_POINT_AT_INFINITY
|
||||||
|
|
||||||
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
|
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,8 @@ bls = py_ecc_bls
|
||||||
|
|
||||||
STUB_SIGNATURE = b'\x11' * 96
|
STUB_SIGNATURE = b'\x11' * 96
|
||||||
STUB_PUBKEY = b'\x22' * 48
|
STUB_PUBKEY = b'\x22' * 48
|
||||||
Z1_PUBKEY = b'\xc0' + b'\x00' * 47
|
G2_POINT_AT_INFINITY = b'\xc0' + b'\x00' * 95
|
||||||
Z2_SIGNATURE = b'\xc0' + b'\x00' * 95
|
STUB_COORDINATES = _signature_to_G2(G2_POINT_AT_INFINITY)
|
||||||
STUB_COORDINATES = _signature_to_G2(Z2_SIGNATURE)
|
|
||||||
|
|
||||||
|
|
||||||
def use_milagro():
|
def use_milagro():
|
||||||
|
@ -95,6 +94,12 @@ def signature_to_G2(signature):
|
||||||
|
|
||||||
@only_with_bls(alt_return=STUB_PUBKEY)
|
@only_with_bls(alt_return=STUB_PUBKEY)
|
||||||
def AggregatePKs(pubkeys):
|
def AggregatePKs(pubkeys):
|
||||||
|
if bls == py_ecc_bls:
|
||||||
|
assert all(bls.KeyValidate(pubkey) for pubkey in pubkeys)
|
||||||
|
elif bls == milagro_bls:
|
||||||
|
# milagro_bls._AggregatePKs checks KeyValidate internally
|
||||||
|
pass
|
||||||
|
|
||||||
return bls._AggregatePKs(list(pubkeys))
|
return bls._AggregatePKs(list(pubkeys))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ The BLS test suite runner has the following handlers:
|
||||||
|
|
||||||
- [`aggregate_verify`](./aggregate_verify.md)
|
- [`aggregate_verify`](./aggregate_verify.md)
|
||||||
- [`aggregate`](./aggregate.md)
|
- [`aggregate`](./aggregate.md)
|
||||||
|
- [`eth_aggregate_pubkeys`](./eth_aggregate_pubkeys.md)
|
||||||
|
- [`eth_fast_aggregate_verify`](./eth_fast_aggregate_verify.md)
|
||||||
- [`fast_aggregate_verify`](./fast_aggregate_verify.md)
|
- [`fast_aggregate_verify`](./fast_aggregate_verify.md)
|
||||||
- [`sign`](./sign.md)
|
- [`sign`](./sign.md)
|
||||||
- [`verify`](./verify.md)
|
- [`verify`](./verify.md)
|
||||||
|
|
|
@ -14,6 +14,8 @@ 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.
|
- No output value if the input is invalid.
|
||||||
|
|
||||||
|
All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`.
|
||||||
|
|
||||||
## Condition
|
## Condition
|
||||||
|
|
||||||
The `aggregate` 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`.
|
||||||
|
|
|
@ -8,10 +8,17 @@ The test data is declared in a `data.yaml` file:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
input:
|
input:
|
||||||
pubkeys: List[bytes48] -- the pubkeys
|
pubkeys: List[BLS Pubkey] -- the pubkeys
|
||||||
messages: List[bytes32] -- the messages
|
messages: List[bytes32] -- the messages
|
||||||
signature: bytes96 -- the signature to verify against pubkeys and messages
|
signature: BLS Signature -- the signature to verify against pubkeys and messages
|
||||||
output: bool -- VALID or INVALID
|
output: bool -- true (VALID) or false (INVALID)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- `BLS Pubkey` here is encoded as a string: hexadecimal encoding of 48 bytes (96 nibbles), prefixed with `0x`.
|
||||||
|
- `BLS Signature` here is encoded as a string: hexadecimal encoding of 96 bytes (192 nibbles), prefixed with `0x`.
|
||||||
|
|
||||||
All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`.
|
All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`.
|
||||||
|
|
||||||
|
## Condition
|
||||||
|
|
||||||
|
The `aggregate_verify` handler should verify the signature with pubkeys and messages in the `input`, and the result should match the expected `output`.
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Test format: Ethereum-customized 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: BLSPubkey -- expected output, single BLS pubkeys or empty.
|
||||||
|
```
|
||||||
|
|
||||||
|
- `BLS Pubkey` here is encoded as a string: hexadecimal encoding of 48 bytes (96 nibbles), prefixed with `0x`.
|
||||||
|
- No output value if the input is invalid.
|
||||||
|
|
||||||
|
## Condition
|
||||||
|
|
||||||
|
The `eth_aggregate_pubkeys` handler should aggregate the signatures in the `input`, and the result should match the expected `output`.
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Test format: Ethereum-customized BLS fast aggregate verify
|
||||||
|
|
||||||
|
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[BLS Pubkey] -- list of input BLS pubkeys
|
||||||
|
message: bytes32 -- the message
|
||||||
|
signature: BLS Signature -- the signature to verify against pubkeys and message
|
||||||
|
output: bool -- true (VALID) or false (INVALID)
|
||||||
|
```
|
||||||
|
|
||||||
|
- `BLS Pubkey` here is encoded as a string: hexadecimal encoding of 48 bytes (96 nibbles), prefixed with `0x`.
|
||||||
|
- `BLS Signature` here is encoded as a string: hexadecimal encoding of 96 bytes (192 nibbles), prefixed with `0x`.
|
||||||
|
|
||||||
|
All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`.
|
||||||
|
|
||||||
|
## Condition
|
||||||
|
|
||||||
|
The `eth_fast_aggregate_verify` handler should verify the signature with pubkeys and message in the `input`, and the result should match the expected `output`.
|
|
@ -1,4 +1,4 @@
|
||||||
# Test format: BLS sign message
|
# Test format: BLS fast aggregate verify
|
||||||
|
|
||||||
Verify the signature against the given pubkeys and one message.
|
Verify the signature against the given pubkeys and one message.
|
||||||
|
|
||||||
|
@ -8,10 +8,17 @@ The test data is declared in a `data.yaml` file:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
input:
|
input:
|
||||||
pubkeys: List[bytes48] -- the pubkey
|
pubkeys: List[BLS Pubkey] -- list of input BLS pubkeys
|
||||||
message: bytes32 -- the message
|
message: bytes32 -- the message
|
||||||
signature: bytes96 -- the signature to verify against pubkeys and message
|
signature: BLS Signature -- the signature to verify against pubkeys and message
|
||||||
output: bool -- VALID or INVALID
|
output: bool -- true (VALID) or false (INVALID)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- `BLS Pubkey` here is encoded as a string: hexadecimal encoding of 48 bytes (96 nibbles), prefixed with `0x`.
|
||||||
|
- `BLS Signature` here is encoded as a string: hexadecimal encoding of 96 bytes (192 nibbles), prefixed with `0x`.
|
||||||
|
|
||||||
All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`.
|
All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`.
|
||||||
|
|
||||||
|
## Condition
|
||||||
|
|
||||||
|
The `fast_aggregate_verify` handler should verify the signature with pubkeys and message in the `input`, and the result should match the expected `output`.
|
||||||
|
|
|
@ -12,8 +12,10 @@ from eth_utils import (
|
||||||
import milagro_bls_binding as milagro_bls
|
import milagro_bls_binding as milagro_bls
|
||||||
|
|
||||||
from eth2spec.utils import bls
|
from eth2spec.utils import bls
|
||||||
from eth2spec.test.helpers.constants import PHASE0
|
from eth2spec.test.helpers.constants import PHASE0, ALTAIR
|
||||||
|
from eth2spec.test.helpers.typing import SpecForkName
|
||||||
from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing
|
from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing
|
||||||
|
from eth2spec.altair import spec
|
||||||
|
|
||||||
|
|
||||||
def to_bytes(i):
|
def to_bytes(i):
|
||||||
|
@ -51,9 +53,12 @@ PRIVKEYS = [
|
||||||
]
|
]
|
||||||
PUBKEYS = [bls.SkToPk(privkey) for privkey in PRIVKEYS]
|
PUBKEYS = [bls.SkToPk(privkey) for privkey in PRIVKEYS]
|
||||||
|
|
||||||
Z1_PUBKEY = b'\xc0' + b'\x00' * 47
|
ZERO_PUBKEY = b'\x00' * 48
|
||||||
NO_SIGNATURE = b'\x00' * 96
|
G1_POINT_AT_INFINITY = b'\xc0' + b'\x00' * 47
|
||||||
Z2_SIGNATURE = b'\xc0' + b'\x00' * 95
|
|
||||||
|
ZERO_SIGNATURE = b'\x00' * 96
|
||||||
|
G2_POINT_AT_INFINITY = b'\xc0' + b'\x00' * 95
|
||||||
|
|
||||||
ZERO_PRIVKEY = 0
|
ZERO_PRIVKEY = 0
|
||||||
ZERO_PRIVKEY_BYTES = b'\x00' * 32
|
ZERO_PRIVKEY_BYTES = b'\x00' * 32
|
||||||
|
|
||||||
|
@ -146,13 +151,13 @@ def case02_verify():
|
||||||
}
|
}
|
||||||
|
|
||||||
# Invalid pubkey and signature with the point at infinity
|
# Invalid pubkey and signature with the point at infinity
|
||||||
assert not bls.Verify(Z1_PUBKEY, SAMPLE_MESSAGE, Z2_SIGNATURE)
|
assert not bls.Verify(G1_POINT_AT_INFINITY, SAMPLE_MESSAGE, G2_POINT_AT_INFINITY)
|
||||||
assert not milagro_bls.Verify(Z1_PUBKEY, SAMPLE_MESSAGE, Z2_SIGNATURE)
|
assert not milagro_bls.Verify(G1_POINT_AT_INFINITY, SAMPLE_MESSAGE, G2_POINT_AT_INFINITY)
|
||||||
yield f'verify_infinity_pubkey_and_infinity_signature', {
|
yield f'verify_infinity_pubkey_and_infinity_signature', {
|
||||||
'input': {
|
'input': {
|
||||||
'pubkey': encode_hex(Z1_PUBKEY),
|
'pubkey': encode_hex(G1_POINT_AT_INFINITY),
|
||||||
'message': encode_hex(SAMPLE_MESSAGE),
|
'message': encode_hex(SAMPLE_MESSAGE),
|
||||||
'signature': encode_hex(Z2_SIGNATURE),
|
'signature': encode_hex(G2_POINT_AT_INFINITY),
|
||||||
},
|
},
|
||||||
'output': False,
|
'output': False,
|
||||||
}
|
}
|
||||||
|
@ -178,10 +183,10 @@ def case03_aggregate():
|
||||||
}
|
}
|
||||||
|
|
||||||
# Valid to aggregate G2 point at infinity
|
# Valid to aggregate G2 point at infinity
|
||||||
aggregate_sig = bls.Aggregate([Z2_SIGNATURE])
|
aggregate_sig = bls.Aggregate([G2_POINT_AT_INFINITY])
|
||||||
assert aggregate_sig == milagro_bls.Aggregate([Z2_SIGNATURE]) == Z2_SIGNATURE
|
assert aggregate_sig == milagro_bls.Aggregate([G2_POINT_AT_INFINITY]) == G2_POINT_AT_INFINITY
|
||||||
yield f'aggregate_infinity_signature', {
|
yield f'aggregate_infinity_signature', {
|
||||||
'input': [encode_hex(Z2_SIGNATURE)],
|
'input': [encode_hex(G2_POINT_AT_INFINITY)],
|
||||||
'output': encode_hex(aggregate_sig),
|
'output': encode_hex(aggregate_sig),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,32 +242,32 @@ def case04_fast_aggregate_verify():
|
||||||
}
|
}
|
||||||
|
|
||||||
# Invalid pubkeys and signature -- len(pubkeys) == 0 and signature == Z1_SIGNATURE
|
# Invalid pubkeys and signature -- len(pubkeys) == 0 and signature == Z1_SIGNATURE
|
||||||
assert not bls.FastAggregateVerify([], message, Z2_SIGNATURE)
|
assert not bls.FastAggregateVerify([], message, G2_POINT_AT_INFINITY)
|
||||||
assert not milagro_bls.FastAggregateVerify([], message, Z2_SIGNATURE)
|
assert not milagro_bls.FastAggregateVerify([], message, G2_POINT_AT_INFINITY)
|
||||||
yield f'fast_aggregate_verify_na_pubkeys_and_infinity_signature', {
|
yield f'fast_aggregate_verify_na_pubkeys_and_infinity_signature', {
|
||||||
'input': {
|
'input': {
|
||||||
'pubkeys': [],
|
'pubkeys': [],
|
||||||
'message': encode_hex(message),
|
'message': encode_hex(message),
|
||||||
'signature': encode_hex(Z2_SIGNATURE),
|
'signature': encode_hex(G2_POINT_AT_INFINITY),
|
||||||
},
|
},
|
||||||
'output': False,
|
'output': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Invalid pubkeys and signature -- len(pubkeys) == 0 and signature == 0x00...
|
# Invalid pubkeys and signature -- len(pubkeys) == 0 and signature == 0x00...
|
||||||
assert not bls.FastAggregateVerify([], message, NO_SIGNATURE)
|
assert not bls.FastAggregateVerify([], message, ZERO_SIGNATURE)
|
||||||
assert not milagro_bls.FastAggregateVerify([], message, NO_SIGNATURE)
|
assert not milagro_bls.FastAggregateVerify([], message, ZERO_SIGNATURE)
|
||||||
yield f'fast_aggregate_verify_na_pubkeys_and_na_signature', {
|
yield f'fast_aggregate_verify_na_pubkeys_and_zero_signature', {
|
||||||
'input': {
|
'input': {
|
||||||
'pubkeys': [],
|
'pubkeys': [],
|
||||||
'message': encode_hex(message),
|
'message': encode_hex(message),
|
||||||
'signature': encode_hex(NO_SIGNATURE),
|
'signature': encode_hex(ZERO_SIGNATURE),
|
||||||
},
|
},
|
||||||
'output': False,
|
'output': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Invalid pubkeys and signature -- pubkeys contains point at infinity
|
# Invalid pubkeys and signature -- pubkeys contains point at infinity
|
||||||
pubkeys = PUBKEYS.copy()
|
pubkeys = PUBKEYS.copy()
|
||||||
pubkeys_with_infinity = pubkeys + [Z1_PUBKEY]
|
pubkeys_with_infinity = pubkeys + [G1_POINT_AT_INFINITY]
|
||||||
signatures = [bls.Sign(privkey, SAMPLE_MESSAGE) for privkey in PRIVKEYS]
|
signatures = [bls.Sign(privkey, SAMPLE_MESSAGE) for privkey in PRIVKEYS]
|
||||||
aggregate_signature = bls.Aggregate(signatures)
|
aggregate_signature = bls.Aggregate(signatures)
|
||||||
assert not bls.FastAggregateVerify(pubkeys_with_infinity, SAMPLE_MESSAGE, aggregate_signature)
|
assert not bls.FastAggregateVerify(pubkeys_with_infinity, SAMPLE_MESSAGE, aggregate_signature)
|
||||||
|
@ -317,31 +322,31 @@ def case05_aggregate_verify():
|
||||||
}
|
}
|
||||||
|
|
||||||
# Invalid pubkeys and signature -- len(pubkeys) == 0 and signature == Z1_SIGNATURE
|
# Invalid pubkeys and signature -- len(pubkeys) == 0 and signature == Z1_SIGNATURE
|
||||||
assert not bls.AggregateVerify([], [], Z2_SIGNATURE)
|
assert not bls.AggregateVerify([], [], G2_POINT_AT_INFINITY)
|
||||||
assert not milagro_bls.AggregateVerify([], [], Z2_SIGNATURE)
|
assert not milagro_bls.AggregateVerify([], [], G2_POINT_AT_INFINITY)
|
||||||
yield f'aggregate_verify_na_pubkeys_and_infinity_signature', {
|
yield f'aggregate_verify_na_pubkeys_and_infinity_signature', {
|
||||||
'input': {
|
'input': {
|
||||||
'pubkeys': [],
|
'pubkeys': [],
|
||||||
'messages': [],
|
'messages': [],
|
||||||
'signature': encode_hex(Z2_SIGNATURE),
|
'signature': encode_hex(G2_POINT_AT_INFINITY),
|
||||||
},
|
},
|
||||||
'output': False,
|
'output': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Invalid pubkeys and signature -- len(pubkeys) == 0 and signature == 0x00...
|
# Invalid pubkeys and signature -- len(pubkeys) == 0 and signature == 0x00...
|
||||||
assert not bls.AggregateVerify([], [], NO_SIGNATURE)
|
assert not bls.AggregateVerify([], [], ZERO_SIGNATURE)
|
||||||
assert not milagro_bls.AggregateVerify([], [], NO_SIGNATURE)
|
assert not milagro_bls.AggregateVerify([], [], ZERO_SIGNATURE)
|
||||||
yield f'aggregate_verify_na_pubkeys_and_na_signature', {
|
yield f'aggregate_verify_na_pubkeys_and_zero_signature', {
|
||||||
'input': {
|
'input': {
|
||||||
'pubkeys': [],
|
'pubkeys': [],
|
||||||
'messages': [],
|
'messages': [],
|
||||||
'signature': encode_hex(NO_SIGNATURE),
|
'signature': encode_hex(ZERO_SIGNATURE),
|
||||||
},
|
},
|
||||||
'output': False,
|
'output': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Invalid pubkeys and signature -- pubkeys contains point at infinity
|
# Invalid pubkeys and signature -- pubkeys contains point at infinity
|
||||||
pubkeys_with_infinity = pubkeys + [Z1_PUBKEY]
|
pubkeys_with_infinity = pubkeys + [G1_POINT_AT_INFINITY]
|
||||||
messages_with_sample = messages + [SAMPLE_MESSAGE]
|
messages_with_sample = messages + [SAMPLE_MESSAGE]
|
||||||
assert not bls.AggregateVerify(pubkeys_with_infinity, messages_with_sample, aggregate_signature)
|
assert not bls.AggregateVerify(pubkeys_with_infinity, messages_with_sample, aggregate_signature)
|
||||||
assert not milagro_bls.AggregateVerify(pubkeys_with_infinity, messages_with_sample, aggregate_signature)
|
assert not milagro_bls.AggregateVerify(pubkeys_with_infinity, messages_with_sample, aggregate_signature)
|
||||||
|
@ -355,7 +360,150 @@ def case05_aggregate_verify():
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def create_provider(handler_name: str,
|
def case06_eth_aggregate_pubkeys():
|
||||||
|
for pubkey in PUBKEYS:
|
||||||
|
encoded_pubkey = encode_hex(pubkey)
|
||||||
|
aggregate_pubkey = spec.eth_aggregate_pubkeys([pubkey])
|
||||||
|
# Should be unchanged
|
||||||
|
assert aggregate_pubkey == milagro_bls._AggregatePKs([pubkey]) == pubkey
|
||||||
|
# Valid pubkey
|
||||||
|
yield f'eth_aggregate_pubkeys_valid_{(hash(bytes(encoded_pubkey, "utf-8"))[:8]).hex()}', {
|
||||||
|
'input': [encode_hex(pubkey)],
|
||||||
|
'output': encode_hex(aggregate_pubkey),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Valid pubkeys
|
||||||
|
aggregate_pubkey = spec.eth_aggregate_pubkeys(PUBKEYS)
|
||||||
|
assert aggregate_pubkey == milagro_bls._AggregatePKs(PUBKEYS)
|
||||||
|
yield f'eth_aggregate_pubkeys_valid_pubkeys', {
|
||||||
|
'input': [encode_hex(pubkey) for pubkey in PUBKEYS],
|
||||||
|
'output': encode_hex(aggregate_pubkey),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Invalid pubkeys -- len(pubkeys) == 0
|
||||||
|
expect_exception(spec.eth_aggregate_pubkeys, [])
|
||||||
|
expect_exception(milagro_bls._AggregatePKs, [])
|
||||||
|
yield f'eth_aggregate_pubkeys_empty_list', {
|
||||||
|
'input': [],
|
||||||
|
'output': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Invalid pubkeys -- [ZERO_PUBKEY]
|
||||||
|
expect_exception(spec.eth_aggregate_pubkeys, [ZERO_PUBKEY])
|
||||||
|
expect_exception(milagro_bls._AggregatePKs, [ZERO_PUBKEY])
|
||||||
|
yield f'eth_aggregate_pubkeys_zero_pubkey', {
|
||||||
|
'input': [encode_hex(ZERO_PUBKEY)],
|
||||||
|
'output': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Invalid pubkeys -- G1 point at infinity
|
||||||
|
expect_exception(spec.eth_aggregate_pubkeys, [G1_POINT_AT_INFINITY])
|
||||||
|
expect_exception(milagro_bls._AggregatePKs, [G1_POINT_AT_INFINITY])
|
||||||
|
yield f'eth_aggregate_pubkeys_infinity_pubkey', {
|
||||||
|
'input': [encode_hex(G1_POINT_AT_INFINITY)],
|
||||||
|
'output': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Invalid pubkeys -- b'\x40\x00\x00\x00....\x00' pubkey
|
||||||
|
x40_pubkey = b'\x40' + b'\00' * 47
|
||||||
|
expect_exception(spec.eth_aggregate_pubkeys, [x40_pubkey])
|
||||||
|
expect_exception(milagro_bls._AggregatePKs, [x40_pubkey])
|
||||||
|
yield f'eth_aggregate_pubkeys_x40_pubkey', {
|
||||||
|
'input': [encode_hex(x40_pubkey)],
|
||||||
|
'output': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def case07_eth_fast_aggregate_verify():
|
||||||
|
"""
|
||||||
|
Similar to `case04_fast_aggregate_verify` except for the empty case
|
||||||
|
"""
|
||||||
|
for i, message in enumerate(MESSAGES):
|
||||||
|
privkeys = PRIVKEYS[:i + 1]
|
||||||
|
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 spec.eth_fast_aggregate_verify(pubkeys, message, aggregate_signature)
|
||||||
|
yield f'eth_fast_aggregate_verify_valid_{(hash(bytes(identifier, "utf-8"))[:8]).hex()}', {
|
||||||
|
'input': {
|
||||||
|
'pubkeys': pubkeys_serial,
|
||||||
|
'message': encode_hex(message),
|
||||||
|
'signature': encode_hex(aggregate_signature),
|
||||||
|
},
|
||||||
|
'output': True,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Invalid signature -- extra pubkey
|
||||||
|
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 spec.eth_fast_aggregate_verify(pubkeys_extra, message, aggregate_signature)
|
||||||
|
yield f'eth_fast_aggregate_verify_extra_pubkey_{(hash(bytes(identifier, "utf-8"))[:8]).hex()}', {
|
||||||
|
'input': {
|
||||||
|
'pubkeys': pubkeys_extra_serial,
|
||||||
|
'message': encode_hex(message),
|
||||||
|
'signature': encode_hex(aggregate_signature),
|
||||||
|
},
|
||||||
|
'output': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Invalid signature -- tampered with signature
|
||||||
|
tampered_signature = aggregate_signature[:-4] + b'\xff\xff\xff\xff'
|
||||||
|
identifier = f'{pubkeys_serial}_{encode_hex(message)}'
|
||||||
|
assert not spec.eth_fast_aggregate_verify(pubkeys, message, tampered_signature)
|
||||||
|
yield f'eth_fast_aggregate_verify_tampered_signature_{(hash(bytes(identifier, "utf-8"))[:8]).hex()}', {
|
||||||
|
'input': {
|
||||||
|
'pubkeys': pubkeys_serial,
|
||||||
|
'message': encode_hex(message),
|
||||||
|
'signature': encode_hex(tampered_signature),
|
||||||
|
},
|
||||||
|
'output': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
# NOTE: Unlike `FastAggregateVerify`, len(pubkeys) == 0 and signature == G2_POINT_AT_INFINITY is VALID
|
||||||
|
assert spec.eth_fast_aggregate_verify([], message, G2_POINT_AT_INFINITY)
|
||||||
|
yield f'eth_fast_aggregate_verify_na_pubkeys_and_infinity_signature', {
|
||||||
|
'input': {
|
||||||
|
'pubkeys': [],
|
||||||
|
'message': encode_hex(message),
|
||||||
|
'signature': encode_hex(G2_POINT_AT_INFINITY),
|
||||||
|
},
|
||||||
|
'output': True,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Invalid pubkeys and signature -- len(pubkeys) == 0 and signature == 0x00...
|
||||||
|
assert not spec.eth_fast_aggregate_verify([], message, ZERO_SIGNATURE)
|
||||||
|
yield f'eth_fast_aggregate_verify_na_pubkeys_and_zero_signature', {
|
||||||
|
'input': {
|
||||||
|
'pubkeys': [],
|
||||||
|
'message': encode_hex(message),
|
||||||
|
'signature': encode_hex(ZERO_SIGNATURE),
|
||||||
|
},
|
||||||
|
'output': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Invalid pubkeys and signature -- pubkeys contains point at infinity
|
||||||
|
pubkeys = PUBKEYS.copy()
|
||||||
|
pubkeys_with_infinity = pubkeys + [G1_POINT_AT_INFINITY]
|
||||||
|
signatures = [bls.Sign(privkey, SAMPLE_MESSAGE) for privkey in PRIVKEYS]
|
||||||
|
aggregate_signature = bls.Aggregate(signatures)
|
||||||
|
assert not spec.eth_fast_aggregate_verify(pubkeys_with_infinity, SAMPLE_MESSAGE, aggregate_signature)
|
||||||
|
yield f'eth_fast_aggregate_verify_infinity_pubkey', {
|
||||||
|
'input': {
|
||||||
|
'pubkeys': [encode_hex(pubkey) for pubkey in pubkeys_with_infinity],
|
||||||
|
'message': encode_hex(SAMPLE_MESSAGE),
|
||||||
|
'signature': encode_hex(aggregate_signature),
|
||||||
|
},
|
||||||
|
'output': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def create_provider(fork_name: SpecForkName,
|
||||||
|
handler_name: str,
|
||||||
test_case_fn: Callable[[], Iterable[Tuple[str, Dict[str, Any]]]]) -> gen_typing.TestProvider:
|
test_case_fn: Callable[[], Iterable[Tuple[str, Dict[str, Any]]]]) -> gen_typing.TestProvider:
|
||||||
|
|
||||||
def prepare_fn() -> None:
|
def prepare_fn() -> None:
|
||||||
|
@ -368,7 +516,7 @@ def create_provider(handler_name: str,
|
||||||
print(data)
|
print(data)
|
||||||
(case_name, case_content) = data
|
(case_name, case_content) = data
|
||||||
yield gen_typing.TestCase(
|
yield gen_typing.TestCase(
|
||||||
fork_name=PHASE0,
|
fork_name=fork_name,
|
||||||
preset_name='general',
|
preset_name='general',
|
||||||
runner_name='bls',
|
runner_name='bls',
|
||||||
handler_name=handler_name,
|
handler_name=handler_name,
|
||||||
|
@ -383,9 +531,13 @@ def create_provider(handler_name: str,
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
bls.use_py_ecc() # Py-ecc is chosen instead of Milagro, since the code is better understood to be correct.
|
bls.use_py_ecc() # Py-ecc is chosen instead of Milagro, since the code is better understood to be correct.
|
||||||
gen_runner.run_generator("bls", [
|
gen_runner.run_generator("bls", [
|
||||||
create_provider('sign', case01_sign),
|
# PHASE0
|
||||||
create_provider('verify', case02_verify),
|
create_provider(PHASE0, 'sign', case01_sign),
|
||||||
create_provider('aggregate', case03_aggregate),
|
create_provider(PHASE0, 'verify', case02_verify),
|
||||||
create_provider('fast_aggregate_verify', case04_fast_aggregate_verify),
|
create_provider(PHASE0, 'aggregate', case03_aggregate),
|
||||||
create_provider('aggregate_verify', case05_aggregate_verify),
|
create_provider(PHASE0, 'fast_aggregate_verify', case04_fast_aggregate_verify),
|
||||||
|
create_provider(PHASE0, 'aggregate_verify', case05_aggregate_verify),
|
||||||
|
# ALTAIR
|
||||||
|
create_provider(ALTAIR, 'eth_aggregate_pubkeys', case06_eth_aggregate_pubkeys),
|
||||||
|
create_provider(ALTAIR, 'eth_fast_aggregate_verify', case07_eth_fast_aggregate_verify),
|
||||||
])
|
])
|
||||||
|
|
Loading…
Reference in New Issue