Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bls domain type #1246

Merged
merged 6 commits into from
Jul 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions configs/constant_presets/mainnet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ MAX_TRANSFERS: 0

# Signature domains
# ---------------------------------------------------------------
DOMAIN_BEACON_PROPOSER: 0
DOMAIN_RANDAO: 1
DOMAIN_ATTESTATION: 2
DOMAIN_DEPOSIT: 3
DOMAIN_VOLUNTARY_EXIT: 4
DOMAIN_TRANSFER: 5
DOMAIN_BEACON_PROPOSER: 0x00000000
DOMAIN_RANDAO: 0x01000000
DOMAIN_ATTESTATION: 0x02000000
DOMAIN_DEPOSIT: 0x03000000
DOMAIN_VOLUNTARY_EXIT: 0x04000000
DOMAIN_TRANSFER: 0x05000000
12 changes: 6 additions & 6 deletions configs/constant_presets/minimal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ MAX_TRANSFERS: 0

# Signature domains
# ---------------------------------------------------------------
DOMAIN_BEACON_PROPOSER: 0
DOMAIN_RANDAO: 1
DOMAIN_ATTESTATION: 2
DOMAIN_DEPOSIT: 3
DOMAIN_VOLUNTARY_EXIT: 4
DOMAIN_TRANSFER: 5
DOMAIN_BEACON_PROPOSER: 0x00000000
protolambda marked this conversation as resolved.
Show resolved Hide resolved
DOMAIN_RANDAO: 0x01000000
DOMAIN_ATTESTATION: 0x02000000
DOMAIN_DEPOSIT: 0x03000000
DOMAIN_VOLUNTARY_EXIT: 0x04000000
DOMAIN_TRANSFER: 0x05000000
12 changes: 9 additions & 3 deletions scripts/build_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
)
from eth2spec.utils.ssz.ssz_typing import (
bit, boolean, Container, List, Vector, uint64,
Bytes4, Bytes32, Bytes48, Bytes96, Bitlist, Bitvector,
Bytes4, Bytes8, Bytes32, Bytes48, Bytes96, Bitlist, Bitvector,
)
from eth2spec.utils.bls import (
bls_aggregate_pubkeys,
Expand All @@ -52,7 +52,7 @@
)
from eth2spec.utils.ssz.ssz_typing import (
bit, boolean, Container, List, Vector, Bytes, uint64,
Bytes4, Bytes32, Bytes48, Bytes96, Bitlist, Bitvector,
Bytes4, Bytes8, Bytes32, Bytes48, Bytes96, Bitlist, Bitvector,
)
from eth2spec.utils.bls import (
bls_aggregate_pubkeys,
Expand Down Expand Up @@ -94,7 +94,10 @@ def compute_committee(indices: Sequence[ValidatorIndex], # type: ignore
def apply_constants_preset(preset: Dict[str, Any]) -> None:
global_vars = globals()
for k, v in preset.items():
global_vars[k] = v
if k.startswith('DOMAIN_'):
global_vars[k] = DomainType(v) # domain types are defined as bytes in the configs
else:
global_vars[k] = v

# Deal with derived constants
global_vars['GENESIS_EPOCH'] = compute_epoch_of_slot(GENESIS_SLOT)
Expand Down Expand Up @@ -135,6 +138,9 @@ def objects_to_spec(functions: Dict[str, str],
)
)
functions_spec = '\n\n'.join(functions.values())
for k in list(constants.keys()):
if k.startswith('DOMAIN_'):
constants[k] = f"DomainType(({constants[k]}).to_bytes(length=4, byteorder='little'))"
constants_spec = '\n'.join(map(lambda x: '%s = %s' % (x, constants[x]), constants))
ssz_objects_instantiation_spec = '\n\n'.join(ssz_objects.values())
ssz_objects_reinitialization_spec = (
Expand Down
10 changes: 5 additions & 5 deletions specs/bls_signature.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ We require:
G2_cofactor = 305502333931268344200999753193121504214466019254188142667664032982267604182971884026507427359259977847832272839041616661285803823378372096355777062779109
q = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787

def hash_to_G2(message_hash: Bytes32, domain: uint64) -> Tuple[uint384, uint384]:
def hash_to_G2(message_hash: Bytes32, domain: Bytes8) -> Tuple[uint384, uint384]:
# Initial candidate x coordinate
x_re = int.from_bytes(hash(message_hash + bytes8(domain) + b'\x01'), 'big')
x_im = int.from_bytes(hash(message_hash + bytes8(domain) + b'\x02'), 'big')
x_re = int.from_bytes(hash(message_hash + domain + b'\x01'), 'big')
x_im = int.from_bytes(hash(message_hash + domain + b'\x02'), 'big')
x_coordinate = Fq2([x_re, x_im]) # x = x_re + i * x_im

# Test candidate y coordinates until a one is found
Expand Down Expand Up @@ -130,15 +130,15 @@ g = Fq2([g_x, g_y])

### `bls_verify`

Let `bls_verify(pubkey: Bytes48, message_hash: Bytes32, signature: Bytes96, domain: uint64) -> bool`:
Let `bls_verify(pubkey: Bytes48, message_hash: Bytes32, signature: Bytes96, domain: Bytes8) -> bool`:

* Verify that `pubkey` is a valid G1 point.
* Verify that `signature` is a valid G2 point.
* Verify that `e(pubkey, hash_to_G2(message_hash, domain)) == e(g, signature)`.

### `bls_verify_multiple`

Let `bls_verify_multiple(pubkeys: List[Bytes48], message_hashes: List[Bytes32], signature: Bytes96, domain: uint64) -> bool`:
Let `bls_verify_multiple(pubkeys: List[Bytes48], message_hashes: List[Bytes32], signature: Bytes96, domain: Bytes8) -> bool`:

* Verify that each `pubkey` in `pubkeys` is a valid G1 point.
* Verify that `signature` is a valid G2 point.
Expand Down
14 changes: 9 additions & 5 deletions specs/core/0_beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,10 @@ We define the following Python custom types for type hinting and readability:
| `Shard` | `uint64` | a shard number |
| `ValidatorIndex` | `uint64` | a validator registry index |
| `Gwei` | `uint64` | an amount in Gwei |
| `Version` | `Bytes4` | a fork version number |
| `Hash` | `Bytes32` | a hash |
| `Version` | `Bytes4` | a fork version number |
| `DomainType` | `Bytes4` | a signature domain type |
| `Domain` | `Bytes8` | a signature domain |
| `BLSPubkey` | `Bytes48` | a BLS12-381 public key |
| `BLSSignature` | `Bytes96` | a BLS12-381 signature |

Expand Down Expand Up @@ -250,7 +252,9 @@ The following values are (non-configurable) constants used throughout the specif
| `MAX_VOLUNTARY_EXITS` | `2**4` (= 16) |
| `MAX_TRANSFERS` | `0` |

### Signature domains
### Signature domain types

The following types are defined, mapping into `DomainType` (little endian):

| Name | Value |
| - | - |
Expand Down Expand Up @@ -775,11 +779,11 @@ def compute_activation_exit_epoch(epoch: Epoch) -> Epoch:
#### `compute_domain`

```python
def compute_domain(domain_type: uint64, fork_version: bytes=b'\x00' * 4) -> int:
def compute_domain(domain_type: DomainType, fork_version: Version=Version()) -> Domain:
"""
Return the domain for the ``domain_type`` and ``fork_version``.
"""
return bytes_to_int(int_to_bytes(domain_type, length=4) + fork_version)
return Domain(domain_type + fork_version)
```

### Beacon state accessors
Expand Down Expand Up @@ -1004,7 +1008,7 @@ def get_total_active_balance(state: BeaconState) -> Gwei:
#### `get_domain`

```python
def get_domain(state: BeaconState, domain_type: uint64, message_epoch: Epoch=None) -> int:
def get_domain(state: BeaconState, domain_type: DomainType, message_epoch: Epoch=None) -> Domain:
"""
Return the signature domain (fork version concatenated with domain type) of a message.
"""
Expand Down
4 changes: 3 additions & 1 deletion specs/core/1_custody-game.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ This document details the beacon chain additions and changes in Phase 1 of Ether
| - | - |
| `EARLY_DERIVED_SECRET_REVEAL_SLOT_REWARD_MULTIPLE` | `2**1` (= 2) |

### Signature domains
### Signature domain types

The following types are defined, mapping into `DomainType` (little endian):

| Name | Value |
| - | - |
Expand Down
4 changes: 3 additions & 1 deletion specs/core/1_shard-data-chains.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ This document describes the shard data layer and the shard fork choice rule in P
| `CROSSLINK_LOOKBACK` | `2**0` (= 1) | epochs | 6.2 minutes |
| `PERSISTENT_COMMITTEE_PERIOD` | `2**11` (= 2,048) | epochs | ~9 days |

### Signature domains
### Signature domain types

The following types are defined, mapping into `DomainType` (little endian):

| Name | Value |
| - | - |
Expand Down
6 changes: 3 additions & 3 deletions specs/test_formats/bls/msg_hash_g2_compressed.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ A BLS compressed-hash to G2.
## Test case format

```yaml
input:
message: bytes32,
domain: uint64 -- the domain
input:
message: bytes32
domain: bytes8 -- the BLS domain
output: List[bytes48] -- length of two
```

Expand Down
2 changes: 1 addition & 1 deletion specs/test_formats/bls/msg_hash_g2_uncompressed.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ A BLS uncompressed-hash to G2.
```yaml
input:
message: bytes32
domain: uint64 -- the domain
domain: bytes8 -- the BLS domain
output: List[List[bytes48]] -- 3 lists, each a length of two
```

Expand Down
2 changes: 1 addition & 1 deletion specs/test_formats/bls/sign_msg.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Message signing with BLS should produce a signature.
input:
privkey: bytes32 -- the private key used for signing
message: bytes32 -- input message to sign (a hash)
domain: uint64 -- the domain
domain: bytes8 -- the BLS domain
output: bytes96 -- expected signature
```

Expand Down
6 changes: 3 additions & 3 deletions test_generators/bls/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def case01_message_hash_G2_uncompressed():
yield {
'input': {
'message': '0x' + msg.hex(),
'domain': domain
'domain': int_to_hex(domain, byte_length=8)
},
'output': hash_message(msg, domain)
}
Expand All @@ -101,7 +101,7 @@ def case02_message_hash_G2_compressed():
yield {
'input': {
'message': '0x' + msg.hex(),
'domain': domain
'domain': int_to_hex(domain, byte_length=8)
},
'output': hash_message_compressed(msg, domain)
}
Expand All @@ -126,7 +126,7 @@ def case04_sign_messages():
'input': {
'privkey': int_to_hex(privkey),
'message': '0x' + message.hex(),
'domain': domain
'domain': int_to_hex(domain, byte_length=8)
},
'output': '0x' + sig.hex()
}
Expand Down
9 changes: 6 additions & 3 deletions test_libs/pyspec/eth2spec/utils/bls.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ def entry(*args, **kw):

@only_with_bls(alt_return=True)
def bls_verify(pubkey, message_hash, signature, domain):
return bls.verify(message_hash=message_hash, pubkey=pubkey, signature=signature, domain=domain)
return bls.verify(message_hash=message_hash, pubkey=pubkey,
signature=signature, domain=int.from_bytes(domain, byteorder='little'))


@only_with_bls(alt_return=True)
def bls_verify_multiple(pubkeys, message_hashes, signature, domain):
return bls.verify_multiple(pubkeys, message_hashes, signature, domain)
return bls.verify_multiple(pubkeys=pubkeys, message_hashes=message_hashes,
signature=signature, domain=int.from_bytes(domain, byteorder='little'))


@only_with_bls(alt_return=STUB_PUBKEY)
Expand All @@ -43,4 +45,5 @@ def bls_aggregate_signatures(signatures):

@only_with_bls(alt_return=STUB_SIGNATURE)
def bls_sign(message_hash, privkey, domain):
return bls.sign(message_hash=message_hash, privkey=privkey, domain=domain)
return bls.sign(message_hash=message_hash, privkey=privkey,
domain=int.from_bytes(domain, byteorder='little'))
1 change: 1 addition & 0 deletions test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ def is_fixed_size(cls):

# Helpers for common BytesN types.
Bytes4: BytesType = BytesN[4]
Bytes8: BytesType = BytesN[8]
Bytes32: BytesType = BytesN[32]
Bytes48: BytesType = BytesN[48]
Bytes96: BytesType = BytesN[96]