From e53063c08d5cab0c2304213b9cb57b9fa2218e4c Mon Sep 17 00:00:00 2001 From: protolambda Date: Sun, 30 Jun 2019 22:12:02 +0200 Subject: [PATCH 1/5] type BLS domain and domain type --- configs/constant_presets/mainnet.yaml | 12 ++++++------ configs/constant_presets/minimal.yaml | 12 ++++++------ scripts/build_spec.py | 12 +++++++++--- specs/bls_signature.md | 10 +++++----- specs/core/0_beacon-chain.md | 12 ++++++++---- specs/core/1_custody-game.md | 4 +++- specs/core/1_shard-data-chains.md | 4 +++- test_libs/pyspec/eth2spec/utils/bls.py | 6 ++++-- test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py | 5 +++++ 9 files changed, 49 insertions(+), 28 deletions(-) diff --git a/configs/constant_presets/mainnet.yaml b/configs/constant_presets/mainnet.yaml index 629badcee1..269e96b23b 100644 --- a/configs/constant_presets/mainnet.yaml +++ b/configs/constant_presets/mainnet.yaml @@ -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 diff --git a/configs/constant_presets/minimal.yaml b/configs/constant_presets/minimal.yaml index 1d0ad015db..d0fb988b81 100644 --- a/configs/constant_presets/minimal.yaml +++ b/configs/constant_presets/minimal.yaml @@ -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 +DOMAIN_RANDAO: 0x01000000 +DOMAIN_ATTESTATION: 0x02000000 +DOMAIN_DEPOSIT: 0x03000000 +DOMAIN_VOLUNTARY_EXIT: 0x04000000 +DOMAIN_TRANSFER: 0x05000000 \ No newline at end of file diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 1542973f29..d5b0c9aaf6 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -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, @@ -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, @@ -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'] = slot_to_epoch(GENESIS_SLOT) @@ -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 = ( diff --git a/specs/bls_signature.md b/specs/bls_signature.md index b901b9345f..652279cd7f 100644 --- a/specs/bls_signature.md +++ b/specs/bls_signature.md @@ -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 @@ -130,7 +130,7 @@ 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. @@ -138,7 +138,7 @@ Let `bls_verify(pubkey: Bytes48, message_hash: Bytes32, signature: Bytes96, doma ### `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. diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 7dd6a71bfa..3918fda06e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -147,6 +147,8 @@ We define the following Python custom types for type hinting and readability: | `ValidatorIndex` | `uint64` | a validator registry index | | `Gwei` | `uint64` | an amount in Gwei | | `Version` | `Bytes4` | a fork version number | +| `DomainType` | `Bytes4` | a signature domain type | +| `Domain` | `Bytes8` | a signature domain | | `Hash` | `Bytes32` | a hash | | `BLSPubkey` | `Bytes48` | a BLS12-381 public key | | `BLSSignature` | `Bytes96` | a BLS12-381 signature | @@ -249,7 +251,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 | | - | - | @@ -767,11 +771,11 @@ def compute_activation_exit_epoch(epoch: Epoch) -> Epoch: #### `bls_domain` ```python -def bls_domain(domain_type: uint64, fork_version: bytes=b'\x00' * 4) -> int: +def bls_domain(domain_type: DomainType, fork_version: bytes=b'\x00' * 4) -> Domain: """ Return the BLS 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 @@ -997,7 +1001,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. """ diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index babe4f991e..cdca249d9c 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -107,7 +107,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 | | - | - | diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 745d437c20..e212c97a56 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -62,7 +62,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 | | - | - | diff --git a/test_libs/pyspec/eth2spec/utils/bls.py b/test_libs/pyspec/eth2spec/utils/bls.py index 52f1fed632..b687458666 100644 --- a/test_libs/pyspec/eth2spec/utils/bls.py +++ b/test_libs/pyspec/eth2spec/utils/bls.py @@ -23,7 +23,8 @@ 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) @@ -43,4 +44,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')) diff --git a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py index d87a223994..7b57985294 100644 --- a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py +++ b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py @@ -497,6 +497,11 @@ 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] + + +class DomainType(Bytes4): + pass From d45b73389e5d9e4410907fdd9aee990eb862733c Mon Sep 17 00:00:00 2001 From: protolambda Date: Sun, 30 Jun 2019 22:18:52 +0200 Subject: [PATCH 2/5] update BLS test generator and format to reflect spec change in BLS --- specs/test_formats/bls/msg_hash_g2_compressed.md | 4 ++-- specs/test_formats/bls/msg_hash_g2_uncompressed.md | 2 +- specs/test_formats/bls/sign_msg.md | 2 +- test_generators/bls/main.py | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/specs/test_formats/bls/msg_hash_g2_compressed.md b/specs/test_formats/bls/msg_hash_g2_compressed.md index 44ea8ded77..bbc1b82fef 100644 --- a/specs/test_formats/bls/msg_hash_g2_compressed.md +++ b/specs/test_formats/bls/msg_hash_g2_compressed.md @@ -6,8 +6,8 @@ A BLS compressed-hash to G2. ```yaml input: - message: bytes32, - domain: uint64 -- the BLS domain + message: bytes32 + domain: bytes8 -- the BLS domain output: List[bytes48] -- length of two ``` diff --git a/specs/test_formats/bls/msg_hash_g2_uncompressed.md b/specs/test_formats/bls/msg_hash_g2_uncompressed.md index 847b5f61d4..8337baaab4 100644 --- a/specs/test_formats/bls/msg_hash_g2_uncompressed.md +++ b/specs/test_formats/bls/msg_hash_g2_uncompressed.md @@ -7,7 +7,7 @@ A BLS uncompressed-hash to G2. ```yaml input: message: bytes32 - domain: uint64 -- the BLS domain + domain: bytes8 -- the BLS domain output: List[List[bytes48]] -- 3 lists, each a length of two ``` diff --git a/specs/test_formats/bls/sign_msg.md b/specs/test_formats/bls/sign_msg.md index b17e6246de..8c6b8cdd0f 100644 --- a/specs/test_formats/bls/sign_msg.md +++ b/specs/test_formats/bls/sign_msg.md @@ -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 BLS domain + domain: bytes8 -- the BLS domain output: bytes96 -- expected signature ``` diff --git a/test_generators/bls/main.py b/test_generators/bls/main.py index a792dda9ad..284cf68b0e 100644 --- a/test_generators/bls/main.py +++ b/test_generators/bls/main.py @@ -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) } @@ -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) } @@ -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() } From bde73b59fc89fad461fba55e7b3571d68a1bac98 Mon Sep 17 00:00:00 2001 From: protolambda Date: Mon, 1 Jul 2019 00:00:54 +0200 Subject: [PATCH 3/5] fix bls_verify_multiple --- test_libs/pyspec/eth2spec/utils/bls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test_libs/pyspec/eth2spec/utils/bls.py b/test_libs/pyspec/eth2spec/utils/bls.py index b687458666..ab2327f438 100644 --- a/test_libs/pyspec/eth2spec/utils/bls.py +++ b/test_libs/pyspec/eth2spec/utils/bls.py @@ -29,7 +29,8 @@ def bls_verify(pubkey, message_hash, signature, domain): @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) From 7f2eb813cbcbfa10e3e2f47b205a73524dfbfb2e Mon Sep 17 00:00:00 2001 From: protolambda Date: Mon, 1 Jul 2019 00:05:40 +0200 Subject: [PATCH 4/5] minor BLS domain type related improvements --- specs/core/0_beacon-chain.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 3918fda06e..433b3d3d40 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -146,10 +146,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 | +| `Hash` | `Bytes32` | a hash | | `Version` | `Bytes4` | a fork version number | | `DomainType` | `Bytes4` | a signature domain type | | `Domain` | `Bytes8` | a signature domain | -| `Hash` | `Bytes32` | a hash | | `BLSPubkey` | `Bytes48` | a BLS12-381 public key | | `BLSSignature` | `Bytes96` | a BLS12-381 signature | @@ -771,7 +771,7 @@ def compute_activation_exit_epoch(epoch: Epoch) -> Epoch: #### `bls_domain` ```python -def bls_domain(domain_type: DomainType, fork_version: bytes=b'\x00' * 4) -> Domain: +def bls_domain(domain_type: DomainType, fork_version: Version=Version()) -> Domain: """ Return the BLS domain for the ``domain_type`` and ``fork_version``. """ From 5b2b3cfe33a99f96d8f2eba15ecbda18597ba9d1 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 1 Jul 2019 09:03:35 +0800 Subject: [PATCH 5/5] class DomainType would be added in build_spec --- test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py index 7b57985294..50b6a3386a 100644 --- a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py +++ b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py @@ -501,7 +501,3 @@ def is_fixed_size(cls): Bytes32: BytesType = BytesN[32] Bytes48: BytesType = BytesN[48] Bytes96: BytesType = BytesN[96] - - -class DomainType(Bytes4): - pass