From 502ee295379c1f3c5c3649e12330fb5be5d7a83b Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Tue, 17 Dec 2019 12:04:56 +0200 Subject: [PATCH 01/17] Phase 0 new BLS --- scripts/build_spec.py | 23 +-- specs/bls_signature.md | 148 ------------------ specs/core/0_beacon-chain.md | 64 +++++--- specs/validator/0_beacon-chain-validator.md | 16 +- .../eth2spec/test/helpers/attestations.py | 17 +- .../pyspec/eth2spec/test/helpers/block.py | 24 +-- .../eth2spec/test/helpers/block_header.py | 10 +- .../pyspec/eth2spec/test/helpers/custody.py | 51 ++---- .../pyspec/eth2spec/test/helpers/deposits.py | 10 +- .../test/helpers/phase1/attestations.py | 18 +-- .../test/helpers/phase1/shard_block.py | 14 +- .../eth2spec/test/helpers/voluntary_exits.py | 14 +- .../eth2spec/test/sanity/test_blocks.py | 23 +-- test_libs/pyspec/eth2spec/utils/bls.py | 26 +-- 14 files changed, 136 insertions(+), 322 deletions(-) delete mode 100644 specs/bls_signature.md diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 834a2dcf76..ca8bbb6dd8 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -11,7 +11,7 @@ PHASE0_IMPORTS = '''from typing import ( - Any, Dict, Set, Sequence, Tuple, Optional + Any, Dict, Set, Sequence, Tuple, Optional, TypeVar ) from dataclasses import ( @@ -21,20 +21,23 @@ from eth2spec.utils.ssz.ssz_impl import hash_tree_root from eth2spec.utils.ssz.ssz_typing import ( - boolean, Container, List, Vector, uint64, + boolean, Container, List, Vector, uint64, SSZType, Bytes1, Bytes4, Bytes8, Bytes32, Bytes48, Bytes96, Bitlist, Bitvector, ) from eth2spec.utils.bls import ( - bls_aggregate_signatures, + Verify, + Sign, + Aggregate, + FastAggregateVerify, bls_aggregate_pubkeys, - bls_verify, - bls_sign, ) from eth2spec.utils.hash_function import hash + +SSZObject = TypeVar('SSZObject', bound=SSZType) ''' PHASE1_IMPORTS = '''from typing import ( - Any, Dict, Set, Sequence, MutableSequence, NewType, Tuple, Union, + Any, Dict, Set, Sequence, MutableSequence, NewType, Tuple, Union, TypeVar ) from math import ( log2, @@ -56,10 +59,11 @@ uint64, bit, boolean, byte, ) from eth2spec.utils.bls import ( + Verify, + Sign, + Aggregate, + FastAggregateVerify, bls_aggregate_pubkeys, - bls_verify, - bls_verify_multiple, - bls_signature_to_G2, ) from eth2spec.utils.hash_function import hash @@ -67,6 +71,7 @@ SSZVariableName = str GeneralizedIndex = NewType('GeneralizedIndex', int) +SSZObject = TypeVar('SSZObject', bound=SSZType) ''' SUNDRY_CONSTANTS_FUNCTIONS = ''' def ceillog2(x: uint64) -> int: diff --git a/specs/bls_signature.md b/specs/bls_signature.md deleted file mode 100644 index aafeeb54d4..0000000000 --- a/specs/bls_signature.md +++ /dev/null @@ -1,148 +0,0 @@ -# BLS signature verification - -**Notice**: This document is a placeholder to facilitate the emergence of cross-client testnets. Substantive changes are postponed until [BLS standardisation](https://github.com/cfrg/draft-irtf-cfrg-bls-signature) is finalized. - -**Warning**: The constructions in this document should not be considered secure. In particular, the `hash_to_G2` function is known to be unsecure. - -## Table of contents - - - - - -- [Curve parameters](#curve-parameters) -- [Point representations](#point-representations) - - [G1 points](#g1-points) - - [G2 points](#g2-points) -- [Helpers](#helpers) - - [`hash_to_G2`](#hash_to_g2) - - [`modular_squareroot`](#modular_squareroot) -- [Aggregation operations](#aggregation-operations) - - [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys) - - [`bls_aggregate_signatures`](#bls_aggregate_signatures) -- [Signature verification](#signature-verification) - - [`bls_verify`](#bls_verify) - - [`bls_verify_multiple`](#bls_verify_multiple) - - - - -## Curve parameters - -The BLS12-381 curve parameters are defined [here](https://z.cash/blog/new-snark-curve). - -## Point representations - -We represent points in the groups G1 and G2 following [zkcrypto/pairing](https://github.com/zkcrypto/pairing/tree/master/src/bls12_381). We denote by `q` the field modulus and by `i` the imaginary unit. - -### G1 points - -A point in G1 is represented as a 384-bit integer `z` decomposed as a 381-bit integer `x` and three 1-bit flags in the top bits: - -* `x = z % 2**381` -* `a_flag = (z % 2**382) // 2**381` -* `b_flag = (z % 2**383) // 2**382` -* `c_flag = (z % 2**384) // 2**383` - -Respecting bit ordering, `z` is decomposed as `(c_flag, b_flag, a_flag, x)`. - -We require: - -* `x < q` -* `c_flag == 1` -* if `b_flag == 1` then `a_flag == x == 0` and `z` represents the point at infinity -* if `b_flag == 0` then `z` represents the point `(x, y)` where `y` is the valid coordinate such that `(y * 2) // q == a_flag` - -### G2 points - -A point in G2 is represented as a pair of 384-bit integers `(z1, z2)`. We decompose `z1` as above into `x1`, `a_flag1`, `b_flag1`, `c_flag1` and `z2` into `x2`, `a_flag2`, `b_flag2`, `c_flag2`. - -We require: - -* `x1 < q` and `x2 < q` -* `a_flag2 == b_flag2 == c_flag2 == 0` -* `c_flag1 == 1` -* if `b_flag1 == 1` then `a_flag1 == x1 == x2 == 0` and `(z1, z2)` represents the point at infinity -* if `b_flag1 == 0` then `(z1, z2)` represents the point `(x1 * i + x2, y)` where `y` is the valid coordinate such that the imaginary part `y_im` of `y` satisfies `(y_im * 2) // q == a_flag1` - -## Helpers - -### `hash_to_G2` - -```python -G2_cofactor = 305502333931268344200999753193121504214466019254188142667664032982267604182971884026507427359259977847832272839041616661285803823378372096355777062779109 -q = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 - -def hash_to_G2(message_hash: Bytes32, domain: Bytes8) -> Tuple[uint384, uint384]: - # Initial candidate x coordinate - 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 - while 1: - y_coordinate_squared = x_coordinate ** 3 + Fq2([4, 4]) # The curve is y^2 = x^3 + 4(i + 1) - y_coordinate = modular_squareroot(y_coordinate_squared) - if y_coordinate is not None: # Check if quadratic residue found - return multiply_in_G2((x_coordinate, y_coordinate), G2_cofactor) - x_coordinate += Fq2([1, 0]) # Add 1 and try again -``` - -### `modular_squareroot` - -`modular_squareroot(x)` returns a solution `y` to `y**2 % q == x`, and `None` if none exists. If there are two solutions, the one with higher imaginary component is favored; if both solutions have equal imaginary component, the one with higher real component is favored (note that this is equivalent to saying that the single solution with either imaginary component > p/2 or imaginary component zero and real component > p/2 is favored). - -The following is a sample implementation; implementers are free to implement modular square roots as they wish. Note that `x2 = -x1` is an _additive modular inverse_ so real and imaginary coefficients remain in `[0 .. q-1]`. `coerce_to_int(element: Fq) -> int` is a function that takes Fq element `element` (i.e. integers `mod q`) and converts it to a regular integer. - -```python -Fq2_order = q ** 2 - 1 -eighth_roots_of_unity = [Fq2([1,1]) ** ((Fq2_order * k) // 8) for k in range(8)] - -def modular_squareroot(value: Fq2) -> Fq2: - candidate_squareroot = value ** ((Fq2_order + 8) // 16) - check = candidate_squareroot ** 2 / value - if check in eighth_roots_of_unity[::2]: - x1 = candidate_squareroot / eighth_roots_of_unity[eighth_roots_of_unity.index(check) // 2] - x2 = -x1 - x1_re, x1_im = coerce_to_int(x1.coeffs[0]), coerce_to_int(x1.coeffs[1]) - x2_re, x2_im = coerce_to_int(x2.coeffs[0]), coerce_to_int(x2.coeffs[1]) - return x1 if (x1_im > x2_im or (x1_im == x2_im and x1_re > x2_re)) else x2 - return None -``` - -## Aggregation operations - -### `bls_aggregate_pubkeys` - -Let `bls_aggregate_pubkeys(pubkeys: List[Bytes48]) -> Bytes48` return `pubkeys[0] + .... + pubkeys[len(pubkeys)-1]`, where `+` is the elliptic curve addition operation over the G1 curve. (When `len(pubkeys) == 0` the empty sum is the G1 point at infinity.) - -### `bls_aggregate_signatures` - -Let `bls_aggregate_signatures(signatures: List[Bytes96]) -> Bytes96` return `signatures[0] + .... + signatures[len(signatures)-1]`, where `+` is the elliptic curve addition operation over the G2 curve. (When `len(signatures) == 0` the empty sum is the G2 point at infinity.) - -## Signature verification - -In the following, `e` is the pairing function and `g` is the G1 generator with the following coordinates (see [here](https://github.com/zkcrypto/pairing/tree/master/src/bls12_381#g1)): - -```python -g_x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507 -g_y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569 -g = Fq2([g_x, g_y]) -``` - -### `bls_verify` - -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: Bytes8) -> bool`: - -* Verify that each `pubkey` in `pubkeys` is a valid G1 point. -* Verify that `signature` is a valid G2 point. -* Verify that `len(pubkeys)` equals `len(message_hashes)` and denote the length `L`. -* Verify that `e(pubkeys[0], hash_to_G2(message_hashes[0], domain)) * ... * e(pubkeys[L-1], hash_to_G2(message_hashes[L-1], domain)) == e(g, signature)`. diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 20087c0695..71980e88cf 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -379,6 +379,14 @@ class BeaconBlockHeader(Container): body_root: Root ``` +#### `DomainWrapper` + +```python +class DomainWrapper(Container): + root: Root + domain: Domain +``` + ### Beacon operations #### `ProposerSlashing` @@ -575,13 +583,17 @@ def bytes_to_int(data: bytes) -> uint64: `def hash_tree_root(object: SSZSerializable) -> Root` is a function for hashing objects into a single root by utilizing a hash tree structure, as defined in the [SSZ spec](../simple-serialize.md#merkleization). -#### `bls_verify` +#### BLS Signatures -`bls_verify` is a function for verifying a BLS signature, as defined in the [BLS Signature spec](../bls_signature.md#bls_verify). +Eth2 makes use of BLS signatures as specified in the [IETF draft BLS specification](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-00). -#### `bls_aggregate_pubkeys` +Specifically, eth2 uses the `BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_POP_` ciphersuite where it makes use of the following functions: -`bls_aggregate_pubkeys` is a function for aggregating multiple BLS public keys into a single aggregate key, as defined in the [BLS Signature spec](../bls_signature.md#bls_aggregate_pubkeys). +* `def Sign(SK: int, message: Bytes) -> BLSSignature` +* `def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool` +* `def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature` +* `def bls_aggregate_pubkeys(PKs: Sequence[BLSPubkey]) -> BLSPubkey` +* `def FastAggregateVerify(PKs: Sequence[BLSSignature], message: Bytes, signature: BLSSignature) -> bool` ### Predicates @@ -664,14 +676,10 @@ def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: Indexe if not indices == sorted(set(indices)): return False # Verify aggregate signature - if not bls_verify( - pubkey=bls_aggregate_pubkeys([state.validators[i].pubkey for i in indices]), - message_hash=hash_tree_root(indexed_attestation.data), - signature=indexed_attestation.signature, - domain=get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch), - ): - return False - return True + pubkeys = [state.validators[i].pubkey for i in indices] + domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch) + message = compute_domain_wrapper_root(indexed_attestation.data, domain) + return FastAggregateVerify(pubkeys, message, indexed_attestation.signature) ``` #### `is_valid_merkle_branch` @@ -789,6 +797,17 @@ def compute_domain(domain_type: DomainType, fork_version: Version=Version()) -> return Domain(domain_type + fork_version) ``` +### `compute_domain_wrapper_root` + +```python +def compute_domain_wrapper_root(object: SSZObject, domain: Domain) -> Root: + domain_wrapped_object = DomainWrapper( + root=hash_tree_root(object), + domain=domain, + ) + return hash_tree_root(domain_wrapped_object) +``` + ### Beacon state accessors #### `get_current_epoch` @@ -1131,8 +1150,8 @@ def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, valida ```python def verify_block_signature(state: BeaconState, signed_block: SignedBeaconBlock) -> bool: proposer = state.validators[get_beacon_proposer_index(state)] - domain = get_domain(state, DOMAIN_BEACON_PROPOSER) - return bls_verify(proposer.pubkey, hash_tree_root(signed_block.message), signed_block.signature, domain) + message = compute_domain_wrapper_root(signed_block.message, get_domain(state, DOMAIN_BEACON_PROPOSER)) + return Verify(proposer.pubkey, message, signed_block.signature) ``` ```python @@ -1431,7 +1450,8 @@ def process_randao(state: BeaconState, body: BeaconBlockBody) -> None: epoch = get_current_epoch(state) # Verify RANDAO reveal proposer = state.validators[get_beacon_proposer_index(state)] - assert bls_verify(proposer.pubkey, hash_tree_root(epoch), body.randao_reveal, get_domain(state, DOMAIN_RANDAO)) + message = compute_domain_wrapper_root(epoch, get_domain(state, DOMAIN_RANDAO)) + assert Verify(proposer.pubkey, message, body.randao_reveal) # Mix in RANDAO reveal mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal)) state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] = mix @@ -1478,8 +1498,11 @@ def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSla assert is_slashable_validator(proposer, get_current_epoch(state)) # Signatures are valid for signed_header in (proposer_slashing.signed_header_1, proposer_slashing.signed_header_2): - domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot)) - assert bls_verify(proposer.pubkey, hash_tree_root(signed_header.message), signed_header.signature, domain) + message = compute_domain_wrapper_root( + object=signed_header.message, + domain=get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot)), + ) + assert Verify(proposer.pubkey, message, signed_header.signature) slash_validator(state, proposer_slashing.proposer_index) ``` @@ -1557,12 +1580,12 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: # Verify the deposit signature (proof of possession) for new validators. # Note: The deposit contract does not check signatures. # Note: Deposits are valid across forks, thus the deposit domain is retrieved directly from `compute_domain`. - domain = compute_domain(DOMAIN_DEPOSIT) deposit_message = DepositMessage( pubkey=deposit.data.pubkey, withdrawal_credentials=deposit.data.withdrawal_credentials, amount=deposit.data.amount) - if not bls_verify(pubkey, hash_tree_root(deposit_message), deposit.data.signature, domain): + message = compute_domain_wrapper_root(deposit_message, compute_domain(DOMAIN_DEPOSIT)) + if not Verify(pubkey, message, deposit.data.signature): return # Add validator and balance entries @@ -1598,7 +1621,8 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu assert get_current_epoch(state) >= validator.activation_epoch + PERSISTENT_COMMITTEE_PERIOD # Verify signature domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch) - assert bls_verify(validator.pubkey, hash_tree_root(voluntary_exit), signed_voluntary_exit.signature, domain) + message = compute_domain_wrapper_root(voluntary_exit, domain) + assert Verify(validator.pubkey, message, signed_voluntary_exit.signature) # Initiate exit initiate_validator_exit(state, voluntary_exit.validator_index) ``` diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index 76bcc3b7d8..5e80e84a6f 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -117,7 +117,7 @@ To submit a deposit: - Set `deposit_data.withdrawal_credentials` to `withdrawal_credentials`. - Set `deposit_data.amount` to `amount`. - Let `deposit_message` be a `DepositMessage` with all the `DepositData` contents except the `signature`. -- Let `signature` be the result of `bls_sign` of the `hash_tree_root(deposit_message)` with `domain=compute_domain(DOMAIN_DEPOSIT)`. (Deposits are valid regardless of fork version, `compute_domain` will default to zeroes there). +- Let `signature` be the result of `Sign` of the `compute_domain_wrapper_root(deposit_message, domain)` with `domain=compute_domain(DOMAIN_DEPOSIT)`. (Deposits are valid regardless of fork version, `compute_domain` will default to zeroes there). - Let `deposit_data_root` be `hash_tree_root(deposit_data)`. - Send a transaction on the Ethereum 1.0 chain to `DEPOSIT_CONTRACT_ADDRESS` executing `def deposit(pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96], deposit_data_root: bytes32)` along with a deposit of `amount` Gwei. @@ -234,7 +234,8 @@ Set `block.body.randao_reveal = epoch_signature` where `epoch_signature` is obta ```python def get_epoch_signature(state: BeaconState, block: BeaconBlock, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_RANDAO, compute_epoch_at_slot(block.slot)) - return bls_sign(privkey, hash_tree_root(compute_epoch_at_slot(block.slot)), domain) + message = compute_domain_wrapper_root(compute_epoch_at_slot(block.slot), domain) + return Sign(privkey, message) ``` ##### Eth1 Data @@ -311,7 +312,8 @@ def compute_new_state_root(state: BeaconState, block: BeaconBlock) -> Root: ```python def get_block_signature(state: BeaconState, header: BeaconBlockHeader, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(header.slot)) - return bls_sign(privkey, hash_tree_root(header), domain) + message = compute_domain_wrapper_root(compute_epoch_at_slot(header), domain) + return Sign(privkey, message) ``` ### Attesting @@ -369,7 +371,8 @@ Set `attestation.signature = signed_attestation_data` where `signed_attestation_ ```python def get_signed_attestation_data(state: BeaconState, attestation: IndexedAttestation, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_ATTESTER, attestation.data.target.epoch) - return bls_sign(privkey, hash_tree_root(attestation.data), domain) + message = compute_domain_wrapper_root(attestation.data, domain) + return Sign(privkey, message) ``` #### Broadcast attestation @@ -387,7 +390,8 @@ A validator is selected to aggregate based upon the return value of `is_aggregat ```python def get_slot_signature(state: BeaconState, slot: Slot, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_ATTESTER, compute_epoch_at_slot(slot)) - return bls_sign(privkey, hash_tree_root(slot), domain) + message = compute_domain_wrapper_root(slot, domain) + return Sign(privkey, message) ``` ```python @@ -418,7 +422,7 @@ Set `aggregate_attestation.signature = aggregate_signature` where `aggregate_sig ```python def get_aggregate_signature(attestations: Sequence[Attestation]) -> BLSSignature: signatures = [attestation.signature for attestation in attestations] - return bls_aggregate_signatures(signatures) + return Aggregate(signatures) ``` #### Broadcast aggregate diff --git a/test_libs/pyspec/eth2spec/test/helpers/attestations.py b/test_libs/pyspec/eth2spec/test/helpers/attestations.py index 3ed54888f4..03ebb7b9b6 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/attestations.py +++ b/test_libs/pyspec/eth2spec/test/helpers/attestations.py @@ -3,7 +3,7 @@ from eth2spec.test.helpers.block import build_empty_block_for_next_slot, transition_unsigned_block, \ build_empty_block from eth2spec.test.helpers.keys import privkeys -from eth2spec.utils.bls import bls_sign, bls_aggregate_signatures +from eth2spec.utils.bls import Sign, Aggregate from eth2spec.utils.ssz.ssz_typing import Bitlist @@ -77,8 +77,7 @@ def sign_aggregate_attestation(spec, state, attestation_data, participants: List privkey ) ) - - return bls_aggregate_signatures(signatures) + return Aggregate(signatures) def sign_indexed_attestation(spec, state, indexed_attestation): @@ -97,15 +96,9 @@ def sign_attestation(spec, state, attestation): def get_attestation_signature(spec, state, attestation_data, privkey): - return bls_sign( - message_hash=attestation_data.hash_tree_root(), - privkey=privkey, - domain=spec.get_domain( - state=state, - domain_type=spec.DOMAIN_BEACON_ATTESTER, - message_epoch=attestation_data.target.epoch, - ) - ) + domain = spec.get_domain(state, spec.DOMAIN_BEACON_ATTESTER, attestation_data.target.epoch) + message = spec.compute_domain_wrapper_root(attestation_data, domain) + return Sign(privkey, message) def fill_aggregate_attestation(spec, state, attestation, signed=False): diff --git a/test_libs/pyspec/eth2spec/test/helpers/block.py b/test_libs/pyspec/eth2spec/test/helpers/block.py index b8c514eb4f..2dac70d8dd 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/block.py +++ b/test_libs/pyspec/eth2spec/test/helpers/block.py @@ -1,7 +1,7 @@ from copy import deepcopy from eth2spec.test.helpers.keys import privkeys -from eth2spec.utils.bls import bls_sign, only_with_bls +from eth2spec.utils.bls import Sign, only_with_bls from eth2spec.utils.ssz.ssz_impl import hash_tree_root @@ -28,15 +28,9 @@ def apply_randao_reveal(spec, state, block, proposer_index=None): proposer_index = get_proposer_index_maybe(spec, state, block.slot, proposer_index) privkey = privkeys[proposer_index] - block.body.randao_reveal = bls_sign( - privkey=privkey, - message_hash=hash_tree_root(spec.compute_epoch_at_slot(block.slot)), - domain=spec.get_domain( - state, - message_epoch=spec.compute_epoch_at_slot(block.slot), - domain_type=spec.DOMAIN_RANDAO, - ) - ) + domain = spec.get_domain(state, spec.DOMAIN_RANDAO, spec.compute_epoch_at_slot(block.slot)) + message = spec.compute_domain_wrapper_root(spec.compute_epoch_at_slot(block.slot), domain) + block.body.randao_reveal = Sign(privkey, message) # Fully ignore the function if BLS is off, beacon-proposer index calculation is slow. @@ -46,14 +40,10 @@ def apply_sig(spec, state, signed_block, proposer_index=None): proposer_index = get_proposer_index_maybe(spec, state, block.slot, proposer_index) privkey = privkeys[proposer_index] + domain = spec.get_domain(state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot)) + message = compute_domain_wrapper_root(block, domain) - signed_block.signature = bls_sign( - message_hash=hash_tree_root(block), - privkey=privkey, - domain=spec.get_domain( - state, - spec.DOMAIN_BEACON_PROPOSER, - spec.compute_epoch_at_slot(block.slot))) + signed_block.signature = Sign(privkey, message) def sign_block(spec, state, block, proposer_index=None): diff --git a/test_libs/pyspec/eth2spec/test/helpers/block_header.py b/test_libs/pyspec/eth2spec/test/helpers/block_header.py index a9c8145ae0..5f439b6a2b 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/block_header.py +++ b/test_libs/pyspec/eth2spec/test/helpers/block_header.py @@ -1,4 +1,4 @@ -from eth2spec.utils.bls import bls_sign +from eth2spec.utils.bls import Sign from eth2spec.utils.ssz.ssz_impl import hash_tree_root @@ -7,8 +7,6 @@ def sign_block_header(spec, state, header, privkey): state=state, domain_type=spec.DOMAIN_BEACON_PROPOSER, ) - return spec.SignedBeaconBlockHeader(message=header, signature=bls_sign( - message_hash=hash_tree_root(header), - privkey=privkey, - domain=domain, - )) + message = spec.compute_domain_wrapper_root(header, domain) + signature = Sign(privkey, message) + return spec.SignedBeaconBlockHeader(message=header, signature=signature) diff --git a/test_libs/pyspec/eth2spec/test/helpers/custody.py b/test_libs/pyspec/eth2spec/test/helpers/custody.py index f6ca8ecd9a..517cd9545f 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/custody.py +++ b/test_libs/pyspec/eth2spec/test/helpers/custody.py @@ -1,5 +1,5 @@ from eth2spec.test.helpers.keys import privkeys -from eth2spec.utils.bls import bls_sign, bls_aggregate_signatures +from eth2spec.utils.bls import Sign, Aggregate from eth2spec.utils.hash_function import hash from eth2spec.utils.ssz.ssz_typing import Bitlist, ByteVector, Bitvector from eth2spec.utils.ssz.ssz_impl import chunkify, pack, hash_tree_root @@ -17,28 +17,15 @@ def get_valid_early_derived_secret_reveal(spec, state, epoch=None): epoch = current_epoch + spec.CUSTODY_PERIOD_TO_RANDAO_PADDING # Generate the secret that is being revealed - reveal = bls_sign( - message_hash=hash_tree_root(spec.Epoch(epoch)), - privkey=privkeys[revealed_index], - domain=spec.get_domain( - state=state, - domain_type=spec.DOMAIN_RANDAO, - message_epoch=epoch, - ), - ) + domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch) + message = spec.compute_domain_wrapper_root(spec.Epoch(epoch), domain) + reveal = Sign(privkeys[revealed_index], message) # Generate the mask (any random 32 bytes that don't reveal the masker's secret will do) mask = hash(reveal) # Generate masker's signature on the mask - masker_signature = bls_sign( - message_hash=mask, - privkey=privkeys[masker_index], - domain=spec.get_domain( - state=state, - domain_type=spec.DOMAIN_RANDAO, - message_epoch=epoch, - ), - ) - masked_reveal = bls_aggregate_signatures([reveal, masker_signature]) + message = spec.compute_domain_wrapper_root(mask, domain) + masker_signature = Sign(privkeys[masker_index], message) + masked_reveal = Aggregate([reveal, masker_signature]) return spec.EarlyDerivedSecretReveal( revealed_index=revealed_index, @@ -60,15 +47,9 @@ def get_valid_custody_key_reveal(spec, state, period=None): epoch_to_sign = spec.get_randao_epoch_for_custody_period(period, revealer_index) # Generate the secret that is being revealed - reveal = bls_sign( - message_hash=hash_tree_root(spec.Epoch(epoch_to_sign)), - privkey=privkeys[revealer_index], - domain=spec.get_domain( - state=state, - domain_type=spec.DOMAIN_RANDAO, - message_epoch=epoch_to_sign, - ), - ) + domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch_to_sign) + message = spec.compute_domain_wrapper_root(spec.Epoch(epoch_to_sign), domain) + reveal = Sign(privkeys[revealer_index], message) return spec.CustodyKeyReveal( revealer_index=revealer_index, reveal=reveal, @@ -92,15 +73,9 @@ def get_valid_bit_challenge(spec, state, attestation, invalid_custody_bit=False) responder_index) # Generate the responder key - responder_key = bls_sign( - message_hash=hash_tree_root(spec.Epoch(epoch)), - privkey=privkeys[responder_index], - domain=spec.get_domain( - state=state, - domain_type=spec.DOMAIN_RANDAO, - message_epoch=epoch, - ), - ) + domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch) + message = spec.compute_domain_wrapper_root(spec.compute_domain_wrapper_root, domain) + responder_key = Sign(privkeys[responder_index], message) chunk_count = spec.get_custody_chunk_count(attestation.data.crosslink) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index fdab01ca9f..90a3ac8f0a 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -1,5 +1,5 @@ from eth2spec.test.helpers.keys import pubkeys, privkeys -from eth2spec.utils.bls import bls_sign +from eth2spec.utils.bls import Sign from eth2spec.utils.merkle_minimal import calc_merkle_tree_from_leaves, get_merkle_proof from eth2spec.utils.ssz.ssz_impl import hash_tree_root from eth2spec.utils.ssz.ssz_typing import List @@ -30,12 +30,8 @@ def sign_deposit_data(spec, deposit_data, privkey, state=None): pubkey=deposit_data.pubkey, withdrawal_credentials=deposit_data.withdrawal_credentials, amount=deposit_data.amount) - signature = bls_sign( - message_hash=hash_tree_root(deposit_message), - privkey=privkey, - domain=domain, - ) - deposit_data.signature = signature + message = spec.compute_domain_wrapper_root(deposit_message, domain) + deposit_data.signature = Sign(privkey, message) def build_deposit(spec, diff --git a/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py b/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py index 4f0a9fb0aa..c6983e71bf 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py +++ b/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py @@ -1,7 +1,7 @@ from eth2spec.test.helpers.keys import privkeys from eth2spec.utils.bls import ( - bls_aggregate_signatures, - bls_sign, + Aggregate, + Sign, ) @@ -25,16 +25,10 @@ def sign_shard_attestation(spec, beacon_state, shard_state, block, participants) ) ) - return bls_aggregate_signatures(signatures) + return Aggregate(signatures) def get_attestation_signature(spec, beacon_state, shard_state, message_hash, block_epoch, privkey): - return bls_sign( - message_hash=message_hash, - privkey=privkey, - domain=spec.get_domain( - state=beacon_state, - domain_type=spec.DOMAIN_SHARD_ATTESTER, - message_epoch=block_epoch, - ) - ) + domain=spec.get_domain(beacon_state, spec.DOMAIN_SHARD_ATTESTER, block_epoch) + message = spec.compute_domain_wrapper(message_hash, domain) + return Sign(privkey, message) diff --git a/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py b/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py index 8d12110e7b..d8a4bcc60a 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py +++ b/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py @@ -2,7 +2,7 @@ from eth2spec.test.helpers.keys import privkeys from eth2spec.utils.bls import ( - bls_sign, + Sign, only_with_bls, ) from eth2spec.utils.ssz.ssz_impl import ( @@ -21,15 +21,9 @@ def sign_shard_block(spec, beacon_state, shard_state, block, proposer_index=None privkey = privkeys[proposer_index] - block.signature = bls_sign( - message_hash=hash_tree_root(block), - privkey=privkey, - domain=spec.get_domain( - beacon_state, - spec.DOMAIN_SHARD_PROPOSER, - spec.compute_epoch_of_shard_slot(block.slot), - ) - ) + domain=spec.get_domain(beacon_state, spec.DOMAIN_SHARD_PROPOSER, compute_epoch_of_shard_slot(block.slot)) + message = spec.compute_domain_wrapper(block, domain) + block.signature = Sign(privkey, message) def build_empty_shard_block(spec, diff --git a/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py b/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py index 62d8f13baa..4f9fc7c30e 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py @@ -1,17 +1,11 @@ -from eth2spec.utils.bls import bls_sign +from eth2spec.utils.bls import Sign from eth2spec.utils.ssz.ssz_impl import hash_tree_root def sign_voluntary_exit(spec, state, voluntary_exit, privkey): + domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch) + message = spec.compute_domain_wrapper_root(voluntary_exit, domain) return spec.SignedVoluntaryExit( message=voluntary_exit, - signature=bls_sign( - message_hash=hash_tree_root(voluntary_exit), - privkey=privkey, - domain=spec.get_domain( - state=state, - domain_type=spec.DOMAIN_VOLUNTARY_EXIT, - message_epoch=voluntary_exit.epoch, - ) - ) + signature=Sign(privkey, message) ) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index c2f980ba07..c13bab9032 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -1,7 +1,7 @@ from copy import deepcopy from eth2spec.utils.ssz.ssz_impl import hash_tree_root -from eth2spec.utils.bls import bls_sign +from eth2spec.utils.bls import Sign from eth2spec.test.helpers.state import get_balance, state_transition_and_sign_block, next_slot from eth2spec.test.helpers.block import build_empty_block_for_next_slot, build_empty_block, sign_block, \ @@ -104,15 +104,11 @@ def test_zero_block_sig(spec, state): @always_bls def test_invalid_block_sig(spec, state): block = build_empty_block_for_next_slot(spec, state) + domain = spec.get_domain(state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot)) + message = spec.compute_domain_wrapper_root(block, domain) invalid_signed_block = spec.SignedBeaconBlock( message=block, - signature=bls_sign( - message_hash=hash_tree_root(block), - privkey=123456, - domain=spec.get_domain( - state, - spec.DOMAIN_BEACON_PROPOSER, - spec.compute_epoch_at_slot(block.slot))) + signature=Sign(123456, message) ) expect_assertion_error(lambda: spec.state_transition(state, invalid_signed_block)) @@ -417,16 +413,11 @@ def test_voluntary_exit(spec, state): epoch=spec.get_current_epoch(state), validator_index=validator_index, ) + domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT) + message = spec.compute_domain_wrapper_root(voluntary_exit, domain) signed_voluntary_exit = spec.SignedVoluntaryExit( message=voluntary_exit, - signature=bls_sign( - message_hash=hash_tree_root(voluntary_exit), - privkey=privkeys[validator_index], - domain=spec.get_domain( - state=state, - domain_type=spec.DOMAIN_VOLUNTARY_EXIT, - ) - ) + signature=Sign(privkeys[validator_index], message) ) # Add to state via block transition diff --git a/test_libs/pyspec/eth2spec/utils/bls.py b/test_libs/pyspec/eth2spec/utils/bls.py index f40e5ab048..580d4e75b7 100644 --- a/test_libs/pyspec/eth2spec/utils/bls.py +++ b/test_libs/pyspec/eth2spec/utils/bls.py @@ -23,31 +23,35 @@ 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) +def Verify(PK, message, signature): + return bls.verify(message_hash=message, pubkey=PK, signature=signature, domain=b'') + + +# @only_with_bls(alt_return=True) +# def AggregateVerify(PKs, messages, signature): +# return bls.verify_multiple(pubkeys=pubkeys, message_hashes=messages, signature=signature, domain=b'') @only_with_bls(alt_return=True) -def bls_verify_multiple(pubkeys, message_hashes, signature, domain): - return bls.verify_multiple(pubkeys=pubkeys, message_hashes=message_hashes, - signature=signature, domain=domain) +def FastAggregateVerify(PKs, message, signature): + aggregate_pubkey = bls.aggregate_pubkeys(PKs) + return bls.verify(pubkey=aggregate_pubkey, message_hash=message, signature=signature, domain=b'') @only_with_bls(alt_return=STUB_PUBKEY) -def bls_aggregate_pubkeys(pubkeys): +def bls_aggregate_pubkeys(PKs): return bls.aggregate_pubkeys(pubkeys) @only_with_bls(alt_return=STUB_SIGNATURE) -def bls_aggregate_signatures(signatures): +def Aggregate(signatures): return 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) +def Sign(SK, message): + return bls.sign(message_hash=message, privkey=SK, + domain=b'') @only_with_bls(alt_return=STUB_COORDINATES) From 80eb721895339802bbe00b501ce16ea13a9c098d Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Tue, 17 Dec 2019 12:20:34 +0200 Subject: [PATCH 02/17] Domains are bytes --- scripts/build_spec.py | 2 +- specs/core/0_beacon-chain.md | 12 +++++------- specs/core/1_custody-game.md | 2 +- specs/core/1_shard-data-chains.md | 4 ++-- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index ca8bbb6dd8..0baa487c3e 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -169,7 +169,7 @@ 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[k] = f"DomainType(bytes.fromhex('{constants[k]}'[2:]))" if k == "BLS12_381_Q": constants[k] += " # noqa: E501" constants_spec = '\n'.join(map(lambda x: '%s = %s' % (x, constants[x]), constants)) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 71980e88cf..271be3ef77 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -249,15 +249,13 @@ The following values are (non-configurable) constants used throughout the specif ### Domain types -The following types are defined, mapping into `DomainType` (little endian): - | Name | Value | | - | - | -| `DOMAIN_BEACON_PROPOSER` | `0` | -| `DOMAIN_BEACON_ATTESTER` | `1` | -| `DOMAIN_RANDAO` | `2` | -| `DOMAIN_DEPOSIT` | `3` | -| `DOMAIN_VOLUNTARY_EXIT` | `4` | +| `DOMAIN_BEACON_PROPOSER` | `0x00000000` | +| `DOMAIN_BEACON_ATTESTER` | `0x01000000` | +| `DOMAIN_RANDAO` | `0x02000000` | +| `DOMAIN_DEPOSIT` | `0x03000000` | +| `DOMAIN_VOLUNTARY_EXIT` | `0x04000000` | ## Containers diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index 017e2a22a6..4f3b26c7cf 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -131,7 +131,7 @@ The following types are defined, mapping into `DomainType` (little endian): | Name | Value | | - | - | -| `DOMAIN_CUSTODY_BIT_CHALLENGE` | `6` | +| `DOMAIN_CUSTODY_BIT_CHALLENGE` | `0x05000000` | ### TODO PLACEHOLDER diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index d5964fe7d4..9d537a789f 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -101,8 +101,8 @@ This document describes the shard transition function (data layer only) and the | Name | Value | | - | - | -| `DOMAIN_SHARD_PROPOSER` | `128` | -| `DOMAIN_SHARD_ATTESTER` | `129` | +| `DOMAIN_SHARD_PROPOSER` | `0x80000000` | +| `DOMAIN_SHARD_ATTESTER` | `0x81000000` | ## Containers From c239ffb78cf2cfc2bf2cafbce2dcfda82f3151aa Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Tue, 17 Dec 2019 12:30:46 +0200 Subject: [PATCH 03/17] Linting fixes --- scripts/build_spec.py | 3 +-- specs/core/0_beacon-chain.md | 2 +- test_libs/pyspec/eth2spec/test/helpers/block.py | 2 +- test_libs/pyspec/eth2spec/test/helpers/block_header.py | 1 - test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py | 3 +-- test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py | 3 +-- test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py | 1 - test_libs/pyspec/eth2spec/test/sanity/test_blocks.py | 1 - test_libs/pyspec/eth2spec/utils/bls.py | 2 +- 9 files changed, 6 insertions(+), 12 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 0baa487c3e..caae39533e 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -25,11 +25,10 @@ Bytes1, Bytes4, Bytes8, Bytes32, Bytes48, Bytes96, Bitlist, Bitvector, ) from eth2spec.utils.bls import ( - Verify, Sign, + Verify, Aggregate, FastAggregateVerify, - bls_aggregate_pubkeys, ) from eth2spec.utils.hash_function import hash diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 271be3ef77..f2dd8d96c0 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1499,7 +1499,7 @@ def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSla message = compute_domain_wrapper_root( object=signed_header.message, domain=get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot)), - ) + ) assert Verify(proposer.pubkey, message, signed_header.signature) slash_validator(state, proposer_slashing.proposer_index) diff --git a/test_libs/pyspec/eth2spec/test/helpers/block.py b/test_libs/pyspec/eth2spec/test/helpers/block.py index 2dac70d8dd..6d22dd5453 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/block.py +++ b/test_libs/pyspec/eth2spec/test/helpers/block.py @@ -41,7 +41,7 @@ def apply_sig(spec, state, signed_block, proposer_index=None): proposer_index = get_proposer_index_maybe(spec, state, block.slot, proposer_index) privkey = privkeys[proposer_index] domain = spec.get_domain(state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot)) - message = compute_domain_wrapper_root(block, domain) + message = spec.compute_domain_wrapper_root(block, domain) signed_block.signature = Sign(privkey, message) diff --git a/test_libs/pyspec/eth2spec/test/helpers/block_header.py b/test_libs/pyspec/eth2spec/test/helpers/block_header.py index 5f439b6a2b..926cebee9b 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/block_header.py +++ b/test_libs/pyspec/eth2spec/test/helpers/block_header.py @@ -1,5 +1,4 @@ from eth2spec.utils.bls import Sign -from eth2spec.utils.ssz.ssz_impl import hash_tree_root def sign_block_header(spec, state, header, privkey): diff --git a/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py b/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py index c6983e71bf..cbb6cde754 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py +++ b/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py @@ -24,11 +24,10 @@ def sign_shard_attestation(spec, beacon_state, shard_state, block, participants) privkey, ) ) - return Aggregate(signatures) def get_attestation_signature(spec, beacon_state, shard_state, message_hash, block_epoch, privkey): - domain=spec.get_domain(beacon_state, spec.DOMAIN_SHARD_ATTESTER, block_epoch) + domain = spec.get_domain(beacon_state, spec.DOMAIN_SHARD_ATTESTER, block_epoch) message = spec.compute_domain_wrapper(message_hash, domain) return Sign(privkey, message) diff --git a/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py b/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py index d8a4bcc60a..b0fe39209a 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py +++ b/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py @@ -20,8 +20,7 @@ def sign_shard_block(spec, beacon_state, shard_state, block, proposer_index=None proposer_index = spec.get_shard_proposer_index(beacon_state, shard_state.shard, block.slot) privkey = privkeys[proposer_index] - - domain=spec.get_domain(beacon_state, spec.DOMAIN_SHARD_PROPOSER, compute_epoch_of_shard_slot(block.slot)) + domain = spec.get_domain(beacon_state, spec.DOMAIN_SHARD_PROPOSER, spec.compute_epoch_of_shard_slot(block.slot)) message = spec.compute_domain_wrapper(block, domain) block.signature = Sign(privkey, message) diff --git a/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py b/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py index 4f9fc7c30e..5c88f07e6f 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py @@ -1,5 +1,4 @@ from eth2spec.utils.bls import Sign -from eth2spec.utils.ssz.ssz_impl import hash_tree_root def sign_voluntary_exit(spec, state, voluntary_exit, privkey): diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index c13bab9032..8103f7be2d 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -1,6 +1,5 @@ from copy import deepcopy -from eth2spec.utils.ssz.ssz_impl import hash_tree_root from eth2spec.utils.bls import Sign from eth2spec.test.helpers.state import get_balance, state_transition_and_sign_block, next_slot diff --git a/test_libs/pyspec/eth2spec/utils/bls.py b/test_libs/pyspec/eth2spec/utils/bls.py index 580d4e75b7..e5f6d8d00e 100644 --- a/test_libs/pyspec/eth2spec/utils/bls.py +++ b/test_libs/pyspec/eth2spec/utils/bls.py @@ -40,7 +40,7 @@ def FastAggregateVerify(PKs, message, signature): @only_with_bls(alt_return=STUB_PUBKEY) def bls_aggregate_pubkeys(PKs): - return bls.aggregate_pubkeys(pubkeys) + return bls.aggregate_pubkeys(PKs) @only_with_bls(alt_return=STUB_SIGNATURE) From 995c895b9c27b8bd59ee860b5b501e99dc138b5c Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Tue, 17 Dec 2019 15:33:37 +0200 Subject: [PATCH 04/17] New BLS in Phase 1 --- scripts/build_spec.py | 7 ++--- specs/core/1_custody-game.md | 38 ++++++++------------------ specs/core/1_shard-data-chains.md | 7 +++-- test_libs/pyspec/eth2spec/utils/bls.py | 12 ++++---- 4 files changed, 24 insertions(+), 40 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index caae39533e..56b128b452 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -59,10 +59,9 @@ ) from eth2spec.utils.bls import ( Verify, - Sign, - Aggregate, + AggregateVerify, FastAggregateVerify, - bls_aggregate_pubkeys, + bls_signature_to_G2, ) from eth2spec.utils.hash_function import hash @@ -86,7 +85,7 @@ def get_eth1_data(distance: uint64) -> Bytes32: return hash(distance) -def hash(x: bytes) -> Bytes32: # type: ignore +def hash(x: bytes) -> Bytes32: if x not in hash_cache: hash_cache[x] = Bytes32(_hash(x)) return hash_cache[x] diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index 4f3b26c7cf..0e3138a29d 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -429,16 +429,9 @@ def process_custody_key_reveal(state: BeaconState, reveal: CustodyKeyReveal) -> assert is_slashable_validator(revealer, get_current_epoch(state)) # Verify signature - assert bls_verify( - pubkey=revealer.pubkey, - message_hash=hash_tree_root(epoch_to_sign), - signature=reveal.reveal, - domain=get_domain( - state=state, - domain_type=DOMAIN_RANDAO, - message_epoch=epoch_to_sign, - ), - ) + domain = get_domain(state, DOMAIN_RANDAO, epoch_to_sign) + message = compute_domain_wrapper_root(epoch_to_sign, domain) + assert Verify(revealer.pubkey, message, reveal.reveal) # Decrement max reveal lateness if response is timely if epoch_to_sign + EPOCHS_PER_CUSTODY_PERIOD >= get_current_epoch(state): @@ -487,21 +480,12 @@ def process_early_derived_secret_reveal(state: BeaconState, reveal: EarlyDerived # Verify signature correctness masker = state.validators[reveal.masker_index] pubkeys = [revealed_validator.pubkey, masker.pubkey] - message_hashes = [ - hash_tree_root(reveal.epoch), - reveal.mask, - ] - - assert bls_verify_multiple( - pubkeys=pubkeys, - message_hashes=message_hashes, - signature=reveal.reveal, - domain=get_domain( - state=state, - domain_type=DOMAIN_RANDAO, - message_epoch=reveal.epoch, - ), - ) + + domain = get_domain(state, DOMAIN_RANDAO, reveal.epoch) + messages = [compute_domain_wrapper_root(message, domain) + for message in [hash_tree_root(reveal.epoch), reveal.mask]] + + assert AggregateVerify(pubkeys, messages, reveal.reveal) if reveal.epoch >= get_current_epoch(state) + CUSTODY_PERIOD_TO_RANDAO_PADDING: # Full slashing when the secret was revealed so early it may be a valid custody @@ -598,7 +582,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) -> challenger = state.validators[challenge.challenger_index] domain = get_domain(state, DOMAIN_CUSTODY_BIT_CHALLENGE, get_current_epoch(state)) # TODO incorrect hash-tree-root, but this changes with phase 1 PR #1483 - assert bls_verify(challenger.pubkey, hash_tree_root(challenge), challenge.signature, domain) + assert Verify(challenger.pubkey, compute_domain_wrapper_root(challenge, domain), challenge.signature) # Verify challenger is slashable assert is_slashable_validator(challenger, get_current_epoch(state)) # Verify attestation @@ -622,7 +606,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) -> challenge.responder_index, ) domain = get_domain(state, DOMAIN_RANDAO, epoch_to_sign) - assert bls_verify(responder.pubkey, hash_tree_root(epoch_to_sign), challenge.responder_key, domain) + assert Verify(responder.pubkey, compute_domain_wrapper_root(epoch_to_sign, domain), challenge.responder_key) # Verify the chunk count chunk_count = get_custody_chunk_count(attestation.data.crosslink) assert chunk_count == len(challenge.chunk_bits) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 9d537a789f..806da26f31 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -386,7 +386,7 @@ def process_shard_block_header(beacon_state: BeaconState, shard_state: ShardStat assert not proposer.slashed # Verify proposer signature domain = get_domain(beacon_state, DOMAIN_SHARD_PROPOSER, compute_epoch_of_shard_slot(block.slot)) - assert bls_verify(proposer.pubkey, hash_tree_root(block), block.signature, domain) + assert Verify(proposer.pubkey, compute_domain_wrapper_root(block, domain), block.signature) ``` #### Attestations @@ -406,8 +406,9 @@ def process_shard_attestations(beacon_state: BeaconState, shard_state: ShardStat assert block.aggregation_bits[i] == 0b0 # Verify attester aggregate signature domain = get_domain(beacon_state, DOMAIN_SHARD_ATTESTER, compute_epoch_of_shard_slot(block.slot)) - message = hash_tree_root(ShardAttestationData(slot=shard_state.slot, parent_root=block.parent_root)) - assert bls_verify(bls_aggregate_pubkeys(pubkeys), message, block.attestations, domain) + shard_attestation_data = ShardAttestationData(slot=shard_state.slot, parent_root=block.parent_root) + message = compute_domain_wrapper_root(shard_attestation_data, domain) + assert FastAggregateVerify(pubkeys, message, block.attestations) # Proposer micro-reward proposer_index = get_shard_proposer_index(beacon_state, shard_state.shard, block.slot) reward = attestation_count * get_base_reward(beacon_state, proposer_index) // PROPOSER_REWARD_QUOTIENT diff --git a/test_libs/pyspec/eth2spec/utils/bls.py b/test_libs/pyspec/eth2spec/utils/bls.py index e5f6d8d00e..6aba2c35a2 100644 --- a/test_libs/pyspec/eth2spec/utils/bls.py +++ b/test_libs/pyspec/eth2spec/utils/bls.py @@ -27,9 +27,9 @@ def Verify(PK, message, signature): return bls.verify(message_hash=message, pubkey=PK, signature=signature, domain=b'') -# @only_with_bls(alt_return=True) -# def AggregateVerify(PKs, messages, signature): -# return bls.verify_multiple(pubkeys=pubkeys, message_hashes=messages, signature=signature, domain=b'') +@only_with_bls(alt_return=True) +def AggregateVerify(PKs, messages, signature): + return bls.verify_multiple(pubkeys=PKs, message_hashes=messages, signature=signature, domain=b'') @only_with_bls(alt_return=True) @@ -38,9 +38,9 @@ def FastAggregateVerify(PKs, message, signature): return bls.verify(pubkey=aggregate_pubkey, message_hash=message, signature=signature, domain=b'') -@only_with_bls(alt_return=STUB_PUBKEY) -def bls_aggregate_pubkeys(PKs): - return bls.aggregate_pubkeys(PKs) +# @only_with_bls(alt_return=STUB_PUBKEY) +# def bls_aggregate_pubkeys(PKs): +# return bls.aggregate_pubkeys(PKs) @only_with_bls(alt_return=STUB_SIGNATURE) From 177ec939f099bc27d549996ab99ce986ba5566c7 Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Tue, 17 Dec 2019 15:40:26 +0200 Subject: [PATCH 05/17] Update ToC --- specs/core/0_beacon-chain.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index f2dd8d96c0..f3e10c9be4 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -34,6 +34,7 @@ - [`DepositMessage`](#depositmessage) - [`DepositData`](#depositdata) - [`BeaconBlockHeader`](#beaconblockheader) + - [`DomainWrapper`](#domainwrapper) - [Beacon operations](#beacon-operations) - [`ProposerSlashing`](#proposerslashing) - [`AttesterSlashing`](#attesterslashing) @@ -58,8 +59,7 @@ - [Crypto](#crypto) - [`hash`](#hash) - [`hash_tree_root`](#hash_tree_root) - - [`bls_verify`](#bls_verify) - - [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys) + - [BLS Signatures](#bls-signatures) - [Predicates](#predicates) - [`is_active_validator`](#is_active_validator) - [`is_eligible_for_activation_queue`](#is_eligible_for_activation_queue) @@ -76,6 +76,7 @@ - [`compute_start_slot_at_epoch`](#compute_start_slot_at_epoch) - [`compute_activation_exit_epoch`](#compute_activation_exit_epoch) - [`compute_domain`](#compute_domain) + - [`compute_domain_wrapper_root`](#compute_domain_wrapper_root) - [Beacon state accessors](#beacon-state-accessors) - [`get_current_epoch`](#get_current_epoch) - [`get_previous_epoch`](#get_previous_epoch) From 3dc78e0905355c2c744d08ccf1ec6cc4513f40a5 Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Tue, 17 Dec 2019 15:57:00 +0200 Subject: [PATCH 06/17] kick CI cache --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 19ab1543aa..5bf94b1940 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,13 +35,13 @@ commands: description: "Restore the cache with pyspec keys" steps: - restore_cached_venv: - venv_name: v4-pyspec + venv_name: v5-pyspec reqs_checksum: cache-{{ checksum "test_libs/pyspec/requirements.txt" }}-{{ checksum "test_libs/pyspec/requirements-testing.txt" }} save_pyspec_cached_venv: description: Save a venv into a cache with pyspec keys" steps: - save_cached_venv: - venv_name: v4-pyspec + venv_name: v5-pyspec reqs_checksum: cache-{{ checksum "test_libs/pyspec/requirements.txt" }}-{{ checksum "test_libs/pyspec/requirements-testing.txt" }} venv_path: ./test_libs/pyspec/venv restore_deposit_contract_cached_venv: From d3f74ea0d9749065f217607fb85eaecdb6333b5b Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Tue, 17 Dec 2019 16:22:46 +0200 Subject: [PATCH 07/17] Realise #1517 was a thing --- .circleci/config.yml | 4 ++-- scripts/build_spec.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5bf94b1940..19ab1543aa 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,13 +35,13 @@ commands: description: "Restore the cache with pyspec keys" steps: - restore_cached_venv: - venv_name: v5-pyspec + venv_name: v4-pyspec reqs_checksum: cache-{{ checksum "test_libs/pyspec/requirements.txt" }}-{{ checksum "test_libs/pyspec/requirements-testing.txt" }} save_pyspec_cached_venv: description: Save a venv into a cache with pyspec keys" steps: - save_cached_venv: - venv_name: v5-pyspec + venv_name: v4-pyspec reqs_checksum: cache-{{ checksum "test_libs/pyspec/requirements.txt" }}-{{ checksum "test_libs/pyspec/requirements-testing.txt" }} venv_path: ./test_libs/pyspec/venv restore_deposit_contract_cached_venv: diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 56b128b452..dcb5303023 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -85,7 +85,7 @@ def get_eth1_data(distance: uint64) -> Bytes32: return hash(distance) -def hash(x: bytes) -> Bytes32: +def hash(x: bytes) -> Bytes32: # type: ignore if x not in hash_cache: hash_cache[x] = Bytes32(_hash(x)) return hash_cache[x] From 42a3dd4ab1b435cda8f77c8820b93f2545dbb3b7 Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Thu, 19 Dec 2019 15:47:42 +0200 Subject: [PATCH 08/17] Implement @djrtwo's review suggestions --- specs/core/0_beacon-chain.md | 11 ++++------- specs/light_client/sync_protocol.md | 5 +++-- specs/validator/0_beacon-chain-validator.md | 2 +- test_libs/pyspec/eth2spec/utils/bls.py | 8 +------- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index f3e10c9be4..d1371483aa 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -591,7 +591,6 @@ Specifically, eth2 uses the `BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_POP_` ciphersuit * `def Sign(SK: int, message: Bytes) -> BLSSignature` * `def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool` * `def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature` -* `def bls_aggregate_pubkeys(PKs: Sequence[BLSPubkey]) -> BLSPubkey` * `def FastAggregateVerify(PKs: Sequence[BLSSignature], message: Bytes, signature: BLSSignature) -> bool` ### Predicates @@ -799,9 +798,9 @@ def compute_domain(domain_type: DomainType, fork_version: Version=Version()) -> ### `compute_domain_wrapper_root` ```python -def compute_domain_wrapper_root(object: SSZObject, domain: Domain) -> Root: +def compute_domain_wrapper_root(ssz_object: SSZObject, domain: Domain) -> Root: domain_wrapped_object = DomainWrapper( - root=hash_tree_root(object), + root=hash_tree_root(ssz_object), domain=domain, ) return hash_tree_root(domain_wrapped_object) @@ -1497,10 +1496,8 @@ def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSla assert is_slashable_validator(proposer, get_current_epoch(state)) # Signatures are valid for signed_header in (proposer_slashing.signed_header_1, proposer_slashing.signed_header_2): - message = compute_domain_wrapper_root( - object=signed_header.message, - domain=get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot)), - ) + domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot)) + message = compute_domain_wrapper_root(signed_header.message, domain) assert Verify(proposer.pubkey, message, signed_header.signature) slash_validator(state, proposer_slashing.proposer_index) diff --git a/specs/light_client/sync_protocol.md b/specs/light_client/sync_protocol.md index 05180516bf..fd3fe2eb56 100644 --- a/specs/light_client/sync_protocol.md +++ b/specs/light_client/sync_protocol.md @@ -135,9 +135,10 @@ def update_memory(memory: LightClientMemory, update: LightClientUpdate) -> None: assert 3 * sum(filter(lambda i: update.aggregation_bits[i], balances)) > 2 * sum(balances) # Verify shard attestations - pubkey = bls_aggregate_pubkeys(filter(lambda i: update.aggregation_bits[i], pubkeys)) + pubkeys = filter(lambda i: update.aggregation_bits[i], pubkeys) domain = compute_domain(DOMAIN_SHARD_ATTESTER, update.fork_version) - assert bls_verify(pubkey, update.shard_block_root, update.signature, domain) + message = compute_domain_wrapper_root(update.shard_block_root, domain) + assert FastAggregateVerify(pubkey, message, update.signature) # Update period committees if entering a new period if next_period == current_period + 1: diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index 5e80e84a6f..bb53946e0b 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -312,7 +312,7 @@ def compute_new_state_root(state: BeaconState, block: BeaconBlock) -> Root: ```python def get_block_signature(state: BeaconState, header: BeaconBlockHeader, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(header.slot)) - message = compute_domain_wrapper_root(compute_epoch_at_slot(header), domain) + message = compute_domain_wrapper_root(header, domain) return Sign(privkey, message) ``` diff --git a/test_libs/pyspec/eth2spec/utils/bls.py b/test_libs/pyspec/eth2spec/utils/bls.py index 6aba2c35a2..4b0ed64459 100644 --- a/test_libs/pyspec/eth2spec/utils/bls.py +++ b/test_libs/pyspec/eth2spec/utils/bls.py @@ -38,11 +38,6 @@ def FastAggregateVerify(PKs, message, signature): return bls.verify(pubkey=aggregate_pubkey, message_hash=message, signature=signature, domain=b'') -# @only_with_bls(alt_return=STUB_PUBKEY) -# def bls_aggregate_pubkeys(PKs): -# return bls.aggregate_pubkeys(PKs) - - @only_with_bls(alt_return=STUB_SIGNATURE) def Aggregate(signatures): return bls.aggregate_signatures(signatures) @@ -50,8 +45,7 @@ def Aggregate(signatures): @only_with_bls(alt_return=STUB_SIGNATURE) def Sign(SK, message): - return bls.sign(message_hash=message, privkey=SK, - domain=b'') + return bls.sign(message_hash=message, privkey=SK, domain=b'') @only_with_bls(alt_return=STUB_COORDINATES) From 62cbd0e7da372317a333df6a88337314d74d1cc8 Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Thu, 19 Dec 2019 15:49:10 +0200 Subject: [PATCH 09/17] Revert domain 6 -> 5 to prevent confusion --- specs/core/1_custody-game.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index 0e3138a29d..d6c79c96d6 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -131,7 +131,7 @@ The following types are defined, mapping into `DomainType` (little endian): | Name | Value | | - | - | -| `DOMAIN_CUSTODY_BIT_CHALLENGE` | `0x05000000` | +| `DOMAIN_CUSTODY_BIT_CHALLENGE` | `0x06000000` | ### TODO PLACEHOLDER From 1e410a1290aac7fbe118cfb3b2577fa4f3b4cdc9 Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Fri, 20 Dec 2019 08:12:43 +0200 Subject: [PATCH 10/17] Fix typo due to change of interface Co-Authored-By: Danny Ryan --- specs/light_client/sync_protocol.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/light_client/sync_protocol.md b/specs/light_client/sync_protocol.md index fd3fe2eb56..ff1ab0f0c6 100644 --- a/specs/light_client/sync_protocol.md +++ b/specs/light_client/sync_protocol.md @@ -138,7 +138,7 @@ def update_memory(memory: LightClientMemory, update: LightClientUpdate) -> None: pubkeys = filter(lambda i: update.aggregation_bits[i], pubkeys) domain = compute_domain(DOMAIN_SHARD_ATTESTER, update.fork_version) message = compute_domain_wrapper_root(update.shard_block_root, domain) - assert FastAggregateVerify(pubkey, message, update.signature) + assert FastAggregateVerify(pubkeys, message, update.signature) # Update period committees if entering a new period if next_period == current_period + 1: From 7af4429011dd12c3e4102a55f4bee1a0ba85da52 Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Fri, 20 Dec 2019 08:41:46 +0200 Subject: [PATCH 11/17] Make bls a module --- scripts/build_spec.py | 14 ++------------ specs/core/0_beacon-chain.md | 18 +++++++++--------- specs/core/1_custody-game.md | 10 +++++----- specs/core/1_shard-data-chains.md | 4 ++-- specs/light_client/sync_protocol.md | 2 +- specs/validator/0_beacon-chain-validator.md | 10 +++++----- .../eth2spec/test/helpers/attestations.py | 6 +++--- .../pyspec/eth2spec/test/helpers/block.py | 7 ++++--- .../eth2spec/test/helpers/block_header.py | 4 ++-- .../pyspec/eth2spec/test/helpers/custody.py | 12 ++++++------ .../pyspec/eth2spec/test/helpers/deposits.py | 4 ++-- .../test/helpers/phase1/attestations.py | 9 +++------ .../test/helpers/phase1/shard_block.py | 8 +++----- .../eth2spec/test/helpers/voluntary_exits.py | 4 ++-- .../pyspec/eth2spec/test/sanity/test_blocks.py | 6 +++--- test_libs/pyspec/eth2spec/utils/bls.py | 2 +- 16 files changed, 53 insertions(+), 67 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index dcb5303023..42d5a81d07 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -24,12 +24,7 @@ boolean, Container, List, Vector, uint64, SSZType, Bytes1, Bytes4, Bytes8, Bytes32, Bytes48, Bytes96, Bitlist, Bitvector, ) -from eth2spec.utils.bls import ( - Sign, - Verify, - Aggregate, - FastAggregateVerify, -) +from eth2spec.utils import bls from eth2spec.utils.hash_function import hash @@ -57,12 +52,7 @@ Bytes1, Bytes4, Bytes8, Bytes32, Bytes48, Bytes96, uint64, bit, boolean, byte, ) -from eth2spec.utils.bls import ( - Verify, - AggregateVerify, - FastAggregateVerify, - bls_signature_to_G2, -) +from eth2spec.utils import bls from eth2spec.utils.hash_function import hash diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index d1371483aa..9c39801a69 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -584,15 +584,15 @@ def bytes_to_int(data: bytes) -> uint64: #### BLS Signatures -Eth2 makes use of BLS signatures as specified in the [IETF draft BLS specification](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-00). - -Specifically, eth2 uses the `BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_POP_` ciphersuite where it makes use of the following functions: +Eth2 makes use of BLS signatures as specified in the [IETF draft BLS specification](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-00). Specifically, eth2 uses the `BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_POP_` ciphersuite which implements the following interfaces: * `def Sign(SK: int, message: Bytes) -> BLSSignature` * `def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool` * `def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature` * `def FastAggregateVerify(PKs: Sequence[BLSSignature], message: Bytes, signature: BLSSignature) -> bool` +Within these specifications, BLS signatures are treated as a module for notational clarity, thus to verify a signature `bls.Verify(...)` is used. + ### Predicates #### `is_active_validator` @@ -677,7 +677,7 @@ def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: Indexe pubkeys = [state.validators[i].pubkey for i in indices] domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch) message = compute_domain_wrapper_root(indexed_attestation.data, domain) - return FastAggregateVerify(pubkeys, message, indexed_attestation.signature) + return bls.FastAggregateVerify(pubkeys, message, indexed_attestation.signature) ``` #### `is_valid_merkle_branch` @@ -1149,7 +1149,7 @@ def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, valida def verify_block_signature(state: BeaconState, signed_block: SignedBeaconBlock) -> bool: proposer = state.validators[get_beacon_proposer_index(state)] message = compute_domain_wrapper_root(signed_block.message, get_domain(state, DOMAIN_BEACON_PROPOSER)) - return Verify(proposer.pubkey, message, signed_block.signature) + return bls.Verify(proposer.pubkey, message, signed_block.signature) ``` ```python @@ -1449,7 +1449,7 @@ def process_randao(state: BeaconState, body: BeaconBlockBody) -> None: # Verify RANDAO reveal proposer = state.validators[get_beacon_proposer_index(state)] message = compute_domain_wrapper_root(epoch, get_domain(state, DOMAIN_RANDAO)) - assert Verify(proposer.pubkey, message, body.randao_reveal) + assert bls.Verify(proposer.pubkey, message, body.randao_reveal) # Mix in RANDAO reveal mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal)) state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] = mix @@ -1498,7 +1498,7 @@ def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSla for signed_header in (proposer_slashing.signed_header_1, proposer_slashing.signed_header_2): domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot)) message = compute_domain_wrapper_root(signed_header.message, domain) - assert Verify(proposer.pubkey, message, signed_header.signature) + assert bls.Verify(proposer.pubkey, message, signed_header.signature) slash_validator(state, proposer_slashing.proposer_index) ``` @@ -1581,7 +1581,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: withdrawal_credentials=deposit.data.withdrawal_credentials, amount=deposit.data.amount) message = compute_domain_wrapper_root(deposit_message, compute_domain(DOMAIN_DEPOSIT)) - if not Verify(pubkey, message, deposit.data.signature): + if not bls.Verify(pubkey, message, deposit.data.signature): return # Add validator and balance entries @@ -1618,7 +1618,7 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu # Verify signature domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch) message = compute_domain_wrapper_root(voluntary_exit, domain) - assert Verify(validator.pubkey, message, signed_voluntary_exit.signature) + assert bls.Verify(validator.pubkey, message, signed_voluntary_exit.signature) # Initiate exit initiate_validator_exit(state, voluntary_exit.validator_index) ``` diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index d6c79c96d6..7f94706e06 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -353,7 +353,7 @@ def custody_subchunkify(bytez: bytes) -> Sequence[bytes]: ```python def get_custody_chunk_bit(key: BLSSignature, chunk: bytes) -> bool: - full_G2_element = bls_signature_to_G2(key) + full_G2_element = bls.signature_to_G2(key) s = full_G2_element[0].coeffs bits = [legendre_bit((i + 1) * s[i % 2] + int.from_bytes(subchunk, "little"), BLS12_381_Q) for i, subchunk in enumerate(custody_subchunkify(chunk))] @@ -431,7 +431,7 @@ def process_custody_key_reveal(state: BeaconState, reveal: CustodyKeyReveal) -> # Verify signature domain = get_domain(state, DOMAIN_RANDAO, epoch_to_sign) message = compute_domain_wrapper_root(epoch_to_sign, domain) - assert Verify(revealer.pubkey, message, reveal.reveal) + assert bls.Verify(revealer.pubkey, message, reveal.reveal) # Decrement max reveal lateness if response is timely if epoch_to_sign + EPOCHS_PER_CUSTODY_PERIOD >= get_current_epoch(state): @@ -485,7 +485,7 @@ def process_early_derived_secret_reveal(state: BeaconState, reveal: EarlyDerived messages = [compute_domain_wrapper_root(message, domain) for message in [hash_tree_root(reveal.epoch), reveal.mask]] - assert AggregateVerify(pubkeys, messages, reveal.reveal) + assert bls.AggregateVerify(pubkeys, messages, reveal.reveal) if reveal.epoch >= get_current_epoch(state) + CUSTODY_PERIOD_TO_RANDAO_PADDING: # Full slashing when the secret was revealed so early it may be a valid custody @@ -582,7 +582,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) -> challenger = state.validators[challenge.challenger_index] domain = get_domain(state, DOMAIN_CUSTODY_BIT_CHALLENGE, get_current_epoch(state)) # TODO incorrect hash-tree-root, but this changes with phase 1 PR #1483 - assert Verify(challenger.pubkey, compute_domain_wrapper_root(challenge, domain), challenge.signature) + assert bls.Verify(challenger.pubkey, compute_domain_wrapper_root(challenge, domain), challenge.signature) # Verify challenger is slashable assert is_slashable_validator(challenger, get_current_epoch(state)) # Verify attestation @@ -606,7 +606,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) -> challenge.responder_index, ) domain = get_domain(state, DOMAIN_RANDAO, epoch_to_sign) - assert Verify(responder.pubkey, compute_domain_wrapper_root(epoch_to_sign, domain), challenge.responder_key) + assert bls.Verify(responder.pubkey, compute_domain_wrapper_root(epoch_to_sign, domain), challenge.responder_key) # Verify the chunk count chunk_count = get_custody_chunk_count(attestation.data.crosslink) assert chunk_count == len(challenge.chunk_bits) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 806da26f31..44d14ec8c2 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -386,7 +386,7 @@ def process_shard_block_header(beacon_state: BeaconState, shard_state: ShardStat assert not proposer.slashed # Verify proposer signature domain = get_domain(beacon_state, DOMAIN_SHARD_PROPOSER, compute_epoch_of_shard_slot(block.slot)) - assert Verify(proposer.pubkey, compute_domain_wrapper_root(block, domain), block.signature) + assert bls.Verify(proposer.pubkey, compute_domain_wrapper_root(block, domain), block.signature) ``` #### Attestations @@ -408,7 +408,7 @@ def process_shard_attestations(beacon_state: BeaconState, shard_state: ShardStat domain = get_domain(beacon_state, DOMAIN_SHARD_ATTESTER, compute_epoch_of_shard_slot(block.slot)) shard_attestation_data = ShardAttestationData(slot=shard_state.slot, parent_root=block.parent_root) message = compute_domain_wrapper_root(shard_attestation_data, domain) - assert FastAggregateVerify(pubkeys, message, block.attestations) + assert bls.FastAggregateVerify(pubkeys, message, block.attestations) # Proposer micro-reward proposer_index = get_shard_proposer_index(beacon_state, shard_state.shard, block.slot) reward = attestation_count * get_base_reward(beacon_state, proposer_index) // PROPOSER_REWARD_QUOTIENT diff --git a/specs/light_client/sync_protocol.md b/specs/light_client/sync_protocol.md index ff1ab0f0c6..de4f0be7ca 100644 --- a/specs/light_client/sync_protocol.md +++ b/specs/light_client/sync_protocol.md @@ -138,7 +138,7 @@ def update_memory(memory: LightClientMemory, update: LightClientUpdate) -> None: pubkeys = filter(lambda i: update.aggregation_bits[i], pubkeys) domain = compute_domain(DOMAIN_SHARD_ATTESTER, update.fork_version) message = compute_domain_wrapper_root(update.shard_block_root, domain) - assert FastAggregateVerify(pubkeys, message, update.signature) + assert bls.FastAggregateVerify(pubkeys, message, update.signature) # Update period committees if entering a new period if next_period == current_period + 1: diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index bb53946e0b..3bd3e1f22d 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -235,7 +235,7 @@ Set `block.body.randao_reveal = epoch_signature` where `epoch_signature` is obta def get_epoch_signature(state: BeaconState, block: BeaconBlock, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_RANDAO, compute_epoch_at_slot(block.slot)) message = compute_domain_wrapper_root(compute_epoch_at_slot(block.slot), domain) - return Sign(privkey, message) + return bls.Sign(privkey, message) ``` ##### Eth1 Data @@ -313,7 +313,7 @@ def compute_new_state_root(state: BeaconState, block: BeaconBlock) -> Root: def get_block_signature(state: BeaconState, header: BeaconBlockHeader, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(header.slot)) message = compute_domain_wrapper_root(header, domain) - return Sign(privkey, message) + return bls.Sign(privkey, message) ``` ### Attesting @@ -372,7 +372,7 @@ Set `attestation.signature = signed_attestation_data` where `signed_attestation_ def get_signed_attestation_data(state: BeaconState, attestation: IndexedAttestation, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_ATTESTER, attestation.data.target.epoch) message = compute_domain_wrapper_root(attestation.data, domain) - return Sign(privkey, message) + return bls.Sign(privkey, message) ``` #### Broadcast attestation @@ -391,7 +391,7 @@ A validator is selected to aggregate based upon the return value of `is_aggregat def get_slot_signature(state: BeaconState, slot: Slot, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_ATTESTER, compute_epoch_at_slot(slot)) message = compute_domain_wrapper_root(slot, domain) - return Sign(privkey, message) + return bls.Sign(privkey, message) ``` ```python @@ -422,7 +422,7 @@ Set `aggregate_attestation.signature = aggregate_signature` where `aggregate_sig ```python def get_aggregate_signature(attestations: Sequence[Attestation]) -> BLSSignature: signatures = [attestation.signature for attestation in attestations] - return Aggregate(signatures) + return bls.Aggregate(signatures) ``` #### Broadcast aggregate diff --git a/test_libs/pyspec/eth2spec/test/helpers/attestations.py b/test_libs/pyspec/eth2spec/test/helpers/attestations.py index 03ebb7b9b6..1082b70452 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/attestations.py +++ b/test_libs/pyspec/eth2spec/test/helpers/attestations.py @@ -3,7 +3,7 @@ from eth2spec.test.helpers.block import build_empty_block_for_next_slot, transition_unsigned_block, \ build_empty_block from eth2spec.test.helpers.keys import privkeys -from eth2spec.utils.bls import Sign, Aggregate +from eth2spec.utils import bls from eth2spec.utils.ssz.ssz_typing import Bitlist @@ -77,7 +77,7 @@ def sign_aggregate_attestation(spec, state, attestation_data, participants: List privkey ) ) - return Aggregate(signatures) + return bls.Aggregate(signatures) def sign_indexed_attestation(spec, state, indexed_attestation): @@ -98,7 +98,7 @@ def sign_attestation(spec, state, attestation): def get_attestation_signature(spec, state, attestation_data, privkey): domain = spec.get_domain(state, spec.DOMAIN_BEACON_ATTESTER, attestation_data.target.epoch) message = spec.compute_domain_wrapper_root(attestation_data, domain) - return Sign(privkey, message) + return bls.Sign(privkey, message) def fill_aggregate_attestation(spec, state, attestation, signed=False): diff --git a/test_libs/pyspec/eth2spec/test/helpers/block.py b/test_libs/pyspec/eth2spec/test/helpers/block.py index 6d22dd5453..13669049f7 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/block.py +++ b/test_libs/pyspec/eth2spec/test/helpers/block.py @@ -1,7 +1,8 @@ from copy import deepcopy from eth2spec.test.helpers.keys import privkeys -from eth2spec.utils.bls import Sign, only_with_bls +from eth2spec.utils import bls +from eth2spec.utils.bls import only_with_bls from eth2spec.utils.ssz.ssz_impl import hash_tree_root @@ -30,7 +31,7 @@ def apply_randao_reveal(spec, state, block, proposer_index=None): domain = spec.get_domain(state, spec.DOMAIN_RANDAO, spec.compute_epoch_at_slot(block.slot)) message = spec.compute_domain_wrapper_root(spec.compute_epoch_at_slot(block.slot), domain) - block.body.randao_reveal = Sign(privkey, message) + block.body.randao_reveal = bls.Sign(privkey, message) # Fully ignore the function if BLS is off, beacon-proposer index calculation is slow. @@ -43,7 +44,7 @@ def apply_sig(spec, state, signed_block, proposer_index=None): domain = spec.get_domain(state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot)) message = spec.compute_domain_wrapper_root(block, domain) - signed_block.signature = Sign(privkey, message) + signed_block.signature = bls.Sign(privkey, message) def sign_block(spec, state, block, proposer_index=None): diff --git a/test_libs/pyspec/eth2spec/test/helpers/block_header.py b/test_libs/pyspec/eth2spec/test/helpers/block_header.py index 926cebee9b..4f9f88644d 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/block_header.py +++ b/test_libs/pyspec/eth2spec/test/helpers/block_header.py @@ -1,4 +1,4 @@ -from eth2spec.utils.bls import Sign +from eth2spec.utils import bls def sign_block_header(spec, state, header, privkey): @@ -7,5 +7,5 @@ def sign_block_header(spec, state, header, privkey): domain_type=spec.DOMAIN_BEACON_PROPOSER, ) message = spec.compute_domain_wrapper_root(header, domain) - signature = Sign(privkey, message) + signature = bls.Sign(privkey, message) return spec.SignedBeaconBlockHeader(message=header, signature=signature) diff --git a/test_libs/pyspec/eth2spec/test/helpers/custody.py b/test_libs/pyspec/eth2spec/test/helpers/custody.py index 517cd9545f..80b341526f 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/custody.py +++ b/test_libs/pyspec/eth2spec/test/helpers/custody.py @@ -1,5 +1,5 @@ from eth2spec.test.helpers.keys import privkeys -from eth2spec.utils.bls import Sign, Aggregate +from eth2spec.utils import bls from eth2spec.utils.hash_function import hash from eth2spec.utils.ssz.ssz_typing import Bitlist, ByteVector, Bitvector from eth2spec.utils.ssz.ssz_impl import chunkify, pack, hash_tree_root @@ -19,13 +19,13 @@ def get_valid_early_derived_secret_reveal(spec, state, epoch=None): # Generate the secret that is being revealed domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch) message = spec.compute_domain_wrapper_root(spec.Epoch(epoch), domain) - reveal = Sign(privkeys[revealed_index], message) + reveal = bls.Sign(privkeys[revealed_index], message) # Generate the mask (any random 32 bytes that don't reveal the masker's secret will do) mask = hash(reveal) # Generate masker's signature on the mask message = spec.compute_domain_wrapper_root(mask, domain) - masker_signature = Sign(privkeys[masker_index], message) - masked_reveal = Aggregate([reveal, masker_signature]) + masker_signature = bls.Sign(privkeys[masker_index], message) + masked_reveal = bls.Aggregate([reveal, masker_signature]) return spec.EarlyDerivedSecretReveal( revealed_index=revealed_index, @@ -49,7 +49,7 @@ def get_valid_custody_key_reveal(spec, state, period=None): # Generate the secret that is being revealed domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch_to_sign) message = spec.compute_domain_wrapper_root(spec.Epoch(epoch_to_sign), domain) - reveal = Sign(privkeys[revealer_index], message) + reveal = bls.Sign(privkeys[revealer_index], message) return spec.CustodyKeyReveal( revealer_index=revealer_index, reveal=reveal, @@ -75,7 +75,7 @@ def get_valid_bit_challenge(spec, state, attestation, invalid_custody_bit=False) # Generate the responder key domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch) message = spec.compute_domain_wrapper_root(spec.compute_domain_wrapper_root, domain) - responder_key = Sign(privkeys[responder_index], message) + responder_key = bls.Sign(privkeys[responder_index], message) chunk_count = spec.get_custody_chunk_count(attestation.data.crosslink) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index 90a3ac8f0a..a307f524be 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -1,5 +1,5 @@ from eth2spec.test.helpers.keys import pubkeys, privkeys -from eth2spec.utils.bls import Sign +from eth2spec.utils import bls from eth2spec.utils.merkle_minimal import calc_merkle_tree_from_leaves, get_merkle_proof from eth2spec.utils.ssz.ssz_impl import hash_tree_root from eth2spec.utils.ssz.ssz_typing import List @@ -31,7 +31,7 @@ def sign_deposit_data(spec, deposit_data, privkey, state=None): withdrawal_credentials=deposit_data.withdrawal_credentials, amount=deposit_data.amount) message = spec.compute_domain_wrapper_root(deposit_message, domain) - deposit_data.signature = Sign(privkey, message) + deposit_data.signature = bls.Sign(privkey, message) def build_deposit(spec, diff --git a/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py b/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py index cbb6cde754..e521bd6c56 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py +++ b/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py @@ -1,8 +1,5 @@ from eth2spec.test.helpers.keys import privkeys -from eth2spec.utils.bls import ( - Aggregate, - Sign, -) +from eth2spec.utils import bls def sign_shard_attestation(spec, beacon_state, shard_state, block, participants): @@ -24,10 +21,10 @@ def sign_shard_attestation(spec, beacon_state, shard_state, block, participants) privkey, ) ) - return Aggregate(signatures) + return bls.Aggregate(signatures) def get_attestation_signature(spec, beacon_state, shard_state, message_hash, block_epoch, privkey): domain = spec.get_domain(beacon_state, spec.DOMAIN_SHARD_ATTESTER, block_epoch) message = spec.compute_domain_wrapper(message_hash, domain) - return Sign(privkey, message) + return bls.Sign(privkey, message) diff --git a/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py b/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py index b0fe39209a..f7275b88aa 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py +++ b/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py @@ -1,10 +1,8 @@ from copy import deepcopy from eth2spec.test.helpers.keys import privkeys -from eth2spec.utils.bls import ( - Sign, - only_with_bls, -) +from eth2spec.utils import bls +from eth2spec.utils.bls import only_with_bls from eth2spec.utils.ssz.ssz_impl import ( hash_tree_root, ) @@ -22,7 +20,7 @@ def sign_shard_block(spec, beacon_state, shard_state, block, proposer_index=None privkey = privkeys[proposer_index] domain = spec.get_domain(beacon_state, spec.DOMAIN_SHARD_PROPOSER, spec.compute_epoch_of_shard_slot(block.slot)) message = spec.compute_domain_wrapper(block, domain) - block.signature = Sign(privkey, message) + block.signature = bls.Sign(privkey, message) def build_empty_shard_block(spec, diff --git a/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py b/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py index 5c88f07e6f..286f85e9f9 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py @@ -1,4 +1,4 @@ -from eth2spec.utils.bls import Sign +from eth2spec.utils import bls def sign_voluntary_exit(spec, state, voluntary_exit, privkey): @@ -6,5 +6,5 @@ def sign_voluntary_exit(spec, state, voluntary_exit, privkey): message = spec.compute_domain_wrapper_root(voluntary_exit, domain) return spec.SignedVoluntaryExit( message=voluntary_exit, - signature=Sign(privkey, message) + signature=bls.Sign(privkey, message) ) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index 8103f7be2d..da89ef0705 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -1,6 +1,6 @@ from copy import deepcopy -from eth2spec.utils.bls import Sign +from eth2spec.utils import bls from eth2spec.test.helpers.state import get_balance, state_transition_and_sign_block, next_slot from eth2spec.test.helpers.block import build_empty_block_for_next_slot, build_empty_block, sign_block, \ @@ -107,7 +107,7 @@ def test_invalid_block_sig(spec, state): message = spec.compute_domain_wrapper_root(block, domain) invalid_signed_block = spec.SignedBeaconBlock( message=block, - signature=Sign(123456, message) + signature=bls.Sign(123456, message) ) expect_assertion_error(lambda: spec.state_transition(state, invalid_signed_block)) @@ -416,7 +416,7 @@ def test_voluntary_exit(spec, state): message = spec.compute_domain_wrapper_root(voluntary_exit, domain) signed_voluntary_exit = spec.SignedVoluntaryExit( message=voluntary_exit, - signature=Sign(privkeys[validator_index], message) + signature=bls.Sign(privkeys[validator_index], message) ) # Add to state via block transition diff --git a/test_libs/pyspec/eth2spec/utils/bls.py b/test_libs/pyspec/eth2spec/utils/bls.py index 4b0ed64459..3cfc6121e8 100644 --- a/test_libs/pyspec/eth2spec/utils/bls.py +++ b/test_libs/pyspec/eth2spec/utils/bls.py @@ -49,5 +49,5 @@ def Sign(SK, message): @only_with_bls(alt_return=STUB_COORDINATES) -def bls_signature_to_G2(signature): +def signature_to_G2(signature): return bls.api.signature_to_G2(signature) From 51bcb29e2820f3e4477f693506569905f92d55f8 Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Fri, 3 Jan 2020 07:46:27 +0100 Subject: [PATCH 12/17] 'DomainWrapper' -> 'SigningRoot' --- specs/core/0_beacon-chain.md | 38 +++++++++---------- specs/core/1_custody-game.md | 8 ++-- specs/core/1_shard-data-chains.md | 4 +- specs/light_client/sync_protocol.md | 2 +- specs/validator/0_beacon-chain-validator.md | 10 ++--- .../eth2spec/test/helpers/attestations.py | 2 +- .../pyspec/eth2spec/test/helpers/block.py | 4 +- .../eth2spec/test/helpers/block_header.py | 2 +- .../pyspec/eth2spec/test/helpers/custody.py | 8 ++-- .../pyspec/eth2spec/test/helpers/deposits.py | 2 +- .../test/helpers/phase1/attestations.py | 2 +- .../test/helpers/phase1/shard_block.py | 2 +- .../eth2spec/test/helpers/voluntary_exits.py | 2 +- .../eth2spec/test/sanity/test_blocks.py | 4 +- 14 files changed, 45 insertions(+), 45 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 090738bc09..681d4b92bf 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -34,7 +34,7 @@ - [`DepositMessage`](#depositmessage) - [`DepositData`](#depositdata) - [`BeaconBlockHeader`](#beaconblockheader) - - [`DomainWrapper`](#domainwrapper) + - [`SigningRoot`](#signingroot) - [Beacon operations](#beacon-operations) - [`ProposerSlashing`](#proposerslashing) - [`AttesterSlashing`](#attesterslashing) @@ -76,7 +76,7 @@ - [`compute_start_slot_at_epoch`](#compute_start_slot_at_epoch) - [`compute_activation_exit_epoch`](#compute_activation_exit_epoch) - [`compute_domain`](#compute_domain) - - [`compute_domain_wrapper_root`](#compute_domain_wrapper_root) + - [`compute_signing_root`](#compute_signing_root) - [Beacon state accessors](#beacon-state-accessors) - [`get_current_epoch`](#get_current_epoch) - [`get_previous_epoch`](#get_previous_epoch) @@ -378,11 +378,11 @@ class BeaconBlockHeader(Container): body_root: Root ``` -#### `DomainWrapper` +#### `SigningRoot` ```python -class DomainWrapper(Container): - root: Root +class SigningRoot(Container): + object_root: Root domain: Domain ``` @@ -586,10 +586,10 @@ def bytes_to_int(data: bytes) -> uint64: Eth2 makes use of BLS signatures as specified in the [IETF draft BLS specification](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-00). Specifically, eth2 uses the `BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_POP_` ciphersuite which implements the following interfaces: -* `def Sign(SK: int, message: Bytes) -> BLSSignature` -* `def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool` -* `def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature` -* `def FastAggregateVerify(PKs: Sequence[BLSSignature], message: Bytes, signature: BLSSignature) -> bool` +- `def Sign(SK: int, message: Bytes) -> BLSSignature` +- `def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool` +- `def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature` +- `def FastAggregateVerify(PKs: Sequence[BLSSignature], message: Bytes, signature: BLSSignature) -> bool` Within these specifications, BLS signatures are treated as a module for notational clarity, thus to verify a signature `bls.Verify(...)` is used. @@ -676,7 +676,7 @@ def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: Indexe # Verify aggregate signature pubkeys = [state.validators[i].pubkey for i in indices] domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch) - message = compute_domain_wrapper_root(indexed_attestation.data, domain) + message = compute_signing_root(indexed_attestation.data, domain) return bls.FastAggregateVerify(pubkeys, message, indexed_attestation.signature) ``` @@ -795,12 +795,12 @@ def compute_domain(domain_type: DomainType, fork_version: Version=Version()) -> return Domain(domain_type + fork_version) ``` -### `compute_domain_wrapper_root` +### `compute_signing_root` ```python -def compute_domain_wrapper_root(ssz_object: SSZObject, domain: Domain) -> Root: - domain_wrapped_object = DomainWrapper( - root=hash_tree_root(ssz_object), +def compute_signing_root(ssz_object: SSZObject, domain: Domain) -> Root: + domain_wrapped_object = SigningRoot( + object_root=hash_tree_root(ssz_object), domain=domain, ) return hash_tree_root(domain_wrapped_object) @@ -1148,7 +1148,7 @@ def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, valida ```python def verify_block_signature(state: BeaconState, signed_block: SignedBeaconBlock) -> bool: proposer = state.validators[get_beacon_proposer_index(state)] - message = compute_domain_wrapper_root(signed_block.message, get_domain(state, DOMAIN_BEACON_PROPOSER)) + message = compute_signing_root(signed_block.message, get_domain(state, DOMAIN_BEACON_PROPOSER)) return bls.Verify(proposer.pubkey, message, signed_block.signature) ``` @@ -1448,7 +1448,7 @@ def process_randao(state: BeaconState, body: BeaconBlockBody) -> None: epoch = get_current_epoch(state) # Verify RANDAO reveal proposer = state.validators[get_beacon_proposer_index(state)] - message = compute_domain_wrapper_root(epoch, get_domain(state, DOMAIN_RANDAO)) + message = compute_signing_root(epoch, get_domain(state, DOMAIN_RANDAO)) assert bls.Verify(proposer.pubkey, message, body.randao_reveal) # Mix in RANDAO reveal mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal)) @@ -1497,7 +1497,7 @@ def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSla # Signatures are valid for signed_header in (proposer_slashing.signed_header_1, proposer_slashing.signed_header_2): domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot)) - message = compute_domain_wrapper_root(signed_header.message, domain) + message = compute_signing_root(signed_header.message, domain) assert bls.Verify(proposer.pubkey, message, signed_header.signature) slash_validator(state, proposer_slashing.proposer_index) @@ -1580,7 +1580,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: pubkey=deposit.data.pubkey, withdrawal_credentials=deposit.data.withdrawal_credentials, amount=deposit.data.amount) - message = compute_domain_wrapper_root(deposit_message, compute_domain(DOMAIN_DEPOSIT)) + message = compute_signing_root(deposit_message, compute_domain(DOMAIN_DEPOSIT)) if not bls.Verify(pubkey, message, deposit.data.signature): return @@ -1617,7 +1617,7 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu assert get_current_epoch(state) >= validator.activation_epoch + PERSISTENT_COMMITTEE_PERIOD # Verify signature domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch) - message = compute_domain_wrapper_root(voluntary_exit, domain) + message = compute_signing_root(voluntary_exit, domain) assert bls.Verify(validator.pubkey, message, signed_voluntary_exit.signature) # Initiate exit initiate_validator_exit(state, voluntary_exit.validator_index) diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index a87ac17f1e..273f27455f 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -430,7 +430,7 @@ def process_custody_key_reveal(state: BeaconState, reveal: CustodyKeyReveal) -> # Verify signature domain = get_domain(state, DOMAIN_RANDAO, epoch_to_sign) - message = compute_domain_wrapper_root(epoch_to_sign, domain) + message = compute_signing_root(epoch_to_sign, domain) assert bls.Verify(revealer.pubkey, message, reveal.reveal) # Decrement max reveal lateness if response is timely @@ -482,7 +482,7 @@ def process_early_derived_secret_reveal(state: BeaconState, reveal: EarlyDerived pubkeys = [revealed_validator.pubkey, masker.pubkey] domain = get_domain(state, DOMAIN_RANDAO, reveal.epoch) - messages = [compute_domain_wrapper_root(message, domain) + messages = [compute_signing_root(message, domain) for message in [hash_tree_root(reveal.epoch), reveal.mask]] assert bls.AggregateVerify(pubkeys, messages, reveal.reveal) @@ -582,7 +582,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) -> challenger = state.validators[challenge.challenger_index] domain = get_domain(state, DOMAIN_CUSTODY_BIT_CHALLENGE, get_current_epoch(state)) # TODO incorrect hash-tree-root, but this changes with phase 1 PR #1483 - assert bls.Verify(challenger.pubkey, compute_domain_wrapper_root(challenge, domain), challenge.signature) + assert bls.Verify(challenger.pubkey, compute_signing_root(challenge, domain), challenge.signature) # Verify challenger is slashable assert is_slashable_validator(challenger, get_current_epoch(state)) # Verify attestation @@ -606,7 +606,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) -> challenge.responder_index, ) domain = get_domain(state, DOMAIN_RANDAO, epoch_to_sign) - assert bls.Verify(responder.pubkey, compute_domain_wrapper_root(epoch_to_sign, domain), challenge.responder_key) + assert bls.Verify(responder.pubkey, compute_signing_root(epoch_to_sign, domain), challenge.responder_key) # Verify the chunk count chunk_count = get_custody_chunk_count(attestation.data.crosslink) assert chunk_count == len(challenge.chunk_bits) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index bae1d2a807..765655f743 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -386,7 +386,7 @@ def process_shard_block_header(beacon_state: BeaconState, shard_state: ShardStat assert not proposer.slashed # Verify proposer signature domain = get_domain(beacon_state, DOMAIN_SHARD_PROPOSER, compute_epoch_of_shard_slot(block.slot)) - assert bls.Verify(proposer.pubkey, compute_domain_wrapper_root(block, domain), block.signature) + assert bls.Verify(proposer.pubkey, compute_signing_root(block, domain), block.signature) ``` #### Attestations @@ -407,7 +407,7 @@ def process_shard_attestations(beacon_state: BeaconState, shard_state: ShardStat # Verify attester aggregate signature domain = get_domain(beacon_state, DOMAIN_SHARD_ATTESTER, compute_epoch_of_shard_slot(block.slot)) shard_attestation_data = ShardAttestationData(slot=shard_state.slot, parent_root=block.parent_root) - message = compute_domain_wrapper_root(shard_attestation_data, domain) + message = compute_signing_root(shard_attestation_data, domain) assert bls.FastAggregateVerify(pubkeys, message, block.attestations) # Proposer micro-reward proposer_index = get_shard_proposer_index(beacon_state, shard_state.shard, block.slot) diff --git a/specs/light_client/sync_protocol.md b/specs/light_client/sync_protocol.md index de4f0be7ca..744f87ea58 100644 --- a/specs/light_client/sync_protocol.md +++ b/specs/light_client/sync_protocol.md @@ -137,7 +137,7 @@ def update_memory(memory: LightClientMemory, update: LightClientUpdate) -> None: # Verify shard attestations pubkeys = filter(lambda i: update.aggregation_bits[i], pubkeys) domain = compute_domain(DOMAIN_SHARD_ATTESTER, update.fork_version) - message = compute_domain_wrapper_root(update.shard_block_root, domain) + message = compute_signing_root(update.shard_block_root, domain) assert bls.FastAggregateVerify(pubkeys, message, update.signature) # Update period committees if entering a new period diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index d6366f920e..ec70976174 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -117,7 +117,7 @@ To submit a deposit: - Set `deposit_data.withdrawal_credentials` to `withdrawal_credentials`. - Set `deposit_data.amount` to `amount`. - Let `deposit_message` be a `DepositMessage` with all the `DepositData` contents except the `signature`. -- Let `signature` be the result of `Sign` of the `compute_domain_wrapper_root(deposit_message, domain)` with `domain=compute_domain(DOMAIN_DEPOSIT)`. (Deposits are valid regardless of fork version, `compute_domain` will default to zeroes there). +- Let `signature` be the result of `Sign` of the `compute_signing_root(deposit_message, domain)` with `domain=compute_domain(DOMAIN_DEPOSIT)`. (Deposits are valid regardless of fork version, `compute_domain` will default to zeroes there). - Let `deposit_data_root` be `hash_tree_root(deposit_data)`. - Send a transaction on the Ethereum 1.0 chain to `DEPOSIT_CONTRACT_ADDRESS` executing `def deposit(pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96], deposit_data_root: bytes32)` along with a deposit of `amount` Gwei. @@ -234,7 +234,7 @@ Set `block.body.randao_reveal = epoch_signature` where `epoch_signature` is obta ```python def get_epoch_signature(state: BeaconState, block: BeaconBlock, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_RANDAO, compute_epoch_at_slot(block.slot)) - message = compute_domain_wrapper_root(compute_epoch_at_slot(block.slot), domain) + message = compute_signing_root(compute_epoch_at_slot(block.slot), domain) return bls.Sign(privkey, message) ``` @@ -312,7 +312,7 @@ def compute_new_state_root(state: BeaconState, block: BeaconBlock) -> Root: ```python def get_block_signature(state: BeaconState, header: BeaconBlockHeader, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(header.slot)) - message = compute_domain_wrapper_root(header, domain) + message = compute_signing_root(header, domain) return bls.Sign(privkey, message) ``` @@ -371,7 +371,7 @@ Set `attestation.signature = signed_attestation_data` where `signed_attestation_ ```python def get_signed_attestation_data(state: BeaconState, attestation: IndexedAttestation, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_ATTESTER, attestation.data.target.epoch) - message = compute_domain_wrapper_root(attestation.data, domain) + message = compute_signing_root(attestation.data, domain) return bls.Sign(privkey, message) ``` @@ -390,7 +390,7 @@ A validator is selected to aggregate based upon the return value of `is_aggregat ```python def get_slot_signature(state: BeaconState, slot: Slot, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_ATTESTER, compute_epoch_at_slot(slot)) - message = compute_domain_wrapper_root(slot, domain) + message = compute_signing_root(slot, domain) return bls.Sign(privkey, message) ``` diff --git a/test_libs/pyspec/eth2spec/test/helpers/attestations.py b/test_libs/pyspec/eth2spec/test/helpers/attestations.py index 1082b70452..52479fd754 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/attestations.py +++ b/test_libs/pyspec/eth2spec/test/helpers/attestations.py @@ -97,7 +97,7 @@ def sign_attestation(spec, state, attestation): def get_attestation_signature(spec, state, attestation_data, privkey): domain = spec.get_domain(state, spec.DOMAIN_BEACON_ATTESTER, attestation_data.target.epoch) - message = spec.compute_domain_wrapper_root(attestation_data, domain) + message = spec.compute_signing_root(attestation_data, domain) return bls.Sign(privkey, message) diff --git a/test_libs/pyspec/eth2spec/test/helpers/block.py b/test_libs/pyspec/eth2spec/test/helpers/block.py index 13669049f7..9b2cc5d03a 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/block.py +++ b/test_libs/pyspec/eth2spec/test/helpers/block.py @@ -30,7 +30,7 @@ def apply_randao_reveal(spec, state, block, proposer_index=None): privkey = privkeys[proposer_index] domain = spec.get_domain(state, spec.DOMAIN_RANDAO, spec.compute_epoch_at_slot(block.slot)) - message = spec.compute_domain_wrapper_root(spec.compute_epoch_at_slot(block.slot), domain) + message = spec.compute_signing_root(spec.compute_epoch_at_slot(block.slot), domain) block.body.randao_reveal = bls.Sign(privkey, message) @@ -42,7 +42,7 @@ def apply_sig(spec, state, signed_block, proposer_index=None): proposer_index = get_proposer_index_maybe(spec, state, block.slot, proposer_index) privkey = privkeys[proposer_index] domain = spec.get_domain(state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot)) - message = spec.compute_domain_wrapper_root(block, domain) + message = spec.compute_signing_root(block, domain) signed_block.signature = bls.Sign(privkey, message) diff --git a/test_libs/pyspec/eth2spec/test/helpers/block_header.py b/test_libs/pyspec/eth2spec/test/helpers/block_header.py index 4f9f88644d..bb5fe692f7 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/block_header.py +++ b/test_libs/pyspec/eth2spec/test/helpers/block_header.py @@ -6,6 +6,6 @@ def sign_block_header(spec, state, header, privkey): state=state, domain_type=spec.DOMAIN_BEACON_PROPOSER, ) - message = spec.compute_domain_wrapper_root(header, domain) + message = spec.compute_signing_root(header, domain) signature = bls.Sign(privkey, message) return spec.SignedBeaconBlockHeader(message=header, signature=signature) diff --git a/test_libs/pyspec/eth2spec/test/helpers/custody.py b/test_libs/pyspec/eth2spec/test/helpers/custody.py index 80b341526f..f75cb96071 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/custody.py +++ b/test_libs/pyspec/eth2spec/test/helpers/custody.py @@ -18,12 +18,12 @@ def get_valid_early_derived_secret_reveal(spec, state, epoch=None): # Generate the secret that is being revealed domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch) - message = spec.compute_domain_wrapper_root(spec.Epoch(epoch), domain) + message = spec.compute_signing_root(spec.Epoch(epoch), domain) reveal = bls.Sign(privkeys[revealed_index], message) # Generate the mask (any random 32 bytes that don't reveal the masker's secret will do) mask = hash(reveal) # Generate masker's signature on the mask - message = spec.compute_domain_wrapper_root(mask, domain) + message = spec.compute_signing_root(mask, domain) masker_signature = bls.Sign(privkeys[masker_index], message) masked_reveal = bls.Aggregate([reveal, masker_signature]) @@ -48,7 +48,7 @@ def get_valid_custody_key_reveal(spec, state, period=None): # Generate the secret that is being revealed domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch_to_sign) - message = spec.compute_domain_wrapper_root(spec.Epoch(epoch_to_sign), domain) + message = spec.compute_signing_root(spec.Epoch(epoch_to_sign), domain) reveal = bls.Sign(privkeys[revealer_index], message) return spec.CustodyKeyReveal( revealer_index=revealer_index, @@ -74,7 +74,7 @@ def get_valid_bit_challenge(spec, state, attestation, invalid_custody_bit=False) # Generate the responder key domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch) - message = spec.compute_domain_wrapper_root(spec.compute_domain_wrapper_root, domain) + message = spec.compute_signing_root(spec.compute_signing_root, domain) responder_key = bls.Sign(privkeys[responder_index], message) chunk_count = spec.get_custody_chunk_count(attestation.data.crosslink) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index a307f524be..720704576b 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -30,7 +30,7 @@ def sign_deposit_data(spec, deposit_data, privkey, state=None): pubkey=deposit_data.pubkey, withdrawal_credentials=deposit_data.withdrawal_credentials, amount=deposit_data.amount) - message = spec.compute_domain_wrapper_root(deposit_message, domain) + message = spec.compute_signing_root(deposit_message, domain) deposit_data.signature = bls.Sign(privkey, message) diff --git a/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py b/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py index e521bd6c56..7947ba8110 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py +++ b/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py @@ -26,5 +26,5 @@ def sign_shard_attestation(spec, beacon_state, shard_state, block, participants) def get_attestation_signature(spec, beacon_state, shard_state, message_hash, block_epoch, privkey): domain = spec.get_domain(beacon_state, spec.DOMAIN_SHARD_ATTESTER, block_epoch) - message = spec.compute_domain_wrapper(message_hash, domain) + message = spec.compute_signing_root(message_hash, domain) return bls.Sign(privkey, message) diff --git a/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py b/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py index f7275b88aa..a72a506498 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py +++ b/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py @@ -19,7 +19,7 @@ def sign_shard_block(spec, beacon_state, shard_state, block, proposer_index=None privkey = privkeys[proposer_index] domain = spec.get_domain(beacon_state, spec.DOMAIN_SHARD_PROPOSER, spec.compute_epoch_of_shard_slot(block.slot)) - message = spec.compute_domain_wrapper(block, domain) + message = spec.compute_signing_root(block, domain) block.signature = bls.Sign(privkey, message) diff --git a/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py b/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py index 286f85e9f9..f186f15331 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py @@ -3,7 +3,7 @@ def sign_voluntary_exit(spec, state, voluntary_exit, privkey): domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch) - message = spec.compute_domain_wrapper_root(voluntary_exit, domain) + message = spec.compute_signing_root(voluntary_exit, domain) return spec.SignedVoluntaryExit( message=voluntary_exit, signature=bls.Sign(privkey, message) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index 5a7f654cf7..ae02d8c1ac 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -108,7 +108,7 @@ def test_invalid_block_sig(spec, state): block = build_empty_block_for_next_slot(spec, state) domain = spec.get_domain(state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot)) - message = spec.compute_domain_wrapper_root(block, domain) + message = spec.compute_signing_root(block, domain) invalid_signed_block = spec.SignedBeaconBlock( message=block, signature=bls.Sign(123456, message) @@ -417,7 +417,7 @@ def test_voluntary_exit(spec, state): validator_index=validator_index, ) domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT) - message = spec.compute_domain_wrapper_root(voluntary_exit, domain) + message = spec.compute_signing_root(voluntary_exit, domain) signed_voluntary_exit = spec.SignedVoluntaryExit( message=voluntary_exit, signature=bls.Sign(privkeys[validator_index], message) From 8580ec33f286895f4d30b56b7377e268e8f1260c Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Fri, 3 Jan 2020 08:18:34 +0100 Subject: [PATCH 13/17] 'message' -> 'signing_root' --- specs/core/0_beacon-chain.md | 24 ++++++++++----------- specs/core/1_custody-game.md | 4 ++-- specs/core/1_shard-data-chains.md | 4 ++-- specs/light_client/sync_protocol.md | 4 ++-- specs/validator/0_beacon-chain-validator.md | 16 +++++++------- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 681d4b92bf..4ba4a91bfd 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -676,8 +676,8 @@ def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: Indexe # Verify aggregate signature pubkeys = [state.validators[i].pubkey for i in indices] domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch) - message = compute_signing_root(indexed_attestation.data, domain) - return bls.FastAggregateVerify(pubkeys, message, indexed_attestation.signature) + signing_root = compute_signing_root(indexed_attestation.data, domain) + return bls.FastAggregateVerify(pubkeys, signing_root, indexed_attestation.signature) ``` #### `is_valid_merkle_branch` @@ -1148,8 +1148,8 @@ def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, valida ```python def verify_block_signature(state: BeaconState, signed_block: SignedBeaconBlock) -> bool: proposer = state.validators[get_beacon_proposer_index(state)] - message = compute_signing_root(signed_block.message, get_domain(state, DOMAIN_BEACON_PROPOSER)) - return bls.Verify(proposer.pubkey, message, signed_block.signature) + signing_root = compute_signing_root(signed_block.message, get_domain(state, DOMAIN_BEACON_PROPOSER)) + return bls.Verify(proposer.pubkey, signing_root, signed_block.signature) ``` ```python @@ -1448,8 +1448,8 @@ def process_randao(state: BeaconState, body: BeaconBlockBody) -> None: epoch = get_current_epoch(state) # Verify RANDAO reveal proposer = state.validators[get_beacon_proposer_index(state)] - message = compute_signing_root(epoch, get_domain(state, DOMAIN_RANDAO)) - assert bls.Verify(proposer.pubkey, message, body.randao_reveal) + signing_root = compute_signing_root(epoch, get_domain(state, DOMAIN_RANDAO)) + assert bls.Verify(proposer.pubkey, signing_root, body.randao_reveal) # Mix in RANDAO reveal mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal)) state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] = mix @@ -1497,8 +1497,8 @@ def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSla # Signatures are valid for signed_header in (proposer_slashing.signed_header_1, proposer_slashing.signed_header_2): domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot)) - message = compute_signing_root(signed_header.message, domain) - assert bls.Verify(proposer.pubkey, message, signed_header.signature) + signing_root = compute_signing_root(signed_header.message, domain) + assert bls.Verify(proposer.pubkey, signing_root, signed_header.signature) slash_validator(state, proposer_slashing.proposer_index) ``` @@ -1580,8 +1580,8 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: pubkey=deposit.data.pubkey, withdrawal_credentials=deposit.data.withdrawal_credentials, amount=deposit.data.amount) - message = compute_signing_root(deposit_message, compute_domain(DOMAIN_DEPOSIT)) - if not bls.Verify(pubkey, message, deposit.data.signature): + signing_root = compute_signing_root(deposit_message, compute_domain(DOMAIN_DEPOSIT)) + if not bls.Verify(pubkey, signing_root, deposit.data.signature): return # Add validator and balance entries @@ -1617,8 +1617,8 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu assert get_current_epoch(state) >= validator.activation_epoch + PERSISTENT_COMMITTEE_PERIOD # Verify signature domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch) - message = compute_signing_root(voluntary_exit, domain) - assert bls.Verify(validator.pubkey, message, signed_voluntary_exit.signature) + signing_root = compute_signing_root(voluntary_exit, domain) + assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature) # Initiate exit initiate_validator_exit(state, voluntary_exit.validator_index) ``` diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index 273f27455f..23f9f3f4dc 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -430,8 +430,8 @@ def process_custody_key_reveal(state: BeaconState, reveal: CustodyKeyReveal) -> # Verify signature domain = get_domain(state, DOMAIN_RANDAO, epoch_to_sign) - message = compute_signing_root(epoch_to_sign, domain) - assert bls.Verify(revealer.pubkey, message, reveal.reveal) + signing_root = compute_signing_root(epoch_to_sign, domain) + assert bls.Verify(revealer.pubkey, signing_root, reveal.reveal) # Decrement max reveal lateness if response is timely if epoch_to_sign + EPOCHS_PER_CUSTODY_PERIOD >= get_current_epoch(state): diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 765655f743..e04e3ba5e4 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -407,8 +407,8 @@ def process_shard_attestations(beacon_state: BeaconState, shard_state: ShardStat # Verify attester aggregate signature domain = get_domain(beacon_state, DOMAIN_SHARD_ATTESTER, compute_epoch_of_shard_slot(block.slot)) shard_attestation_data = ShardAttestationData(slot=shard_state.slot, parent_root=block.parent_root) - message = compute_signing_root(shard_attestation_data, domain) - assert bls.FastAggregateVerify(pubkeys, message, block.attestations) + signing_root = compute_signing_root(shard_attestation_data, domain) + assert bls.FastAggregateVerify(pubkeys, signing_root, block.attestations) # Proposer micro-reward proposer_index = get_shard_proposer_index(beacon_state, shard_state.shard, block.slot) reward = attestation_count * get_base_reward(beacon_state, proposer_index) // PROPOSER_REWARD_QUOTIENT diff --git a/specs/light_client/sync_protocol.md b/specs/light_client/sync_protocol.md index 744f87ea58..5a74101800 100644 --- a/specs/light_client/sync_protocol.md +++ b/specs/light_client/sync_protocol.md @@ -137,8 +137,8 @@ def update_memory(memory: LightClientMemory, update: LightClientUpdate) -> None: # Verify shard attestations pubkeys = filter(lambda i: update.aggregation_bits[i], pubkeys) domain = compute_domain(DOMAIN_SHARD_ATTESTER, update.fork_version) - message = compute_signing_root(update.shard_block_root, domain) - assert bls.FastAggregateVerify(pubkeys, message, update.signature) + signing_root = compute_signing_root(update.shard_block_root, domain) + assert bls.FastAggregateVerify(pubkeys, signing_root, update.signature) # Update period committees if entering a new period if next_period == current_period + 1: diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index ec70976174..063cda12f5 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -234,8 +234,8 @@ Set `block.body.randao_reveal = epoch_signature` where `epoch_signature` is obta ```python def get_epoch_signature(state: BeaconState, block: BeaconBlock, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_RANDAO, compute_epoch_at_slot(block.slot)) - message = compute_signing_root(compute_epoch_at_slot(block.slot), domain) - return bls.Sign(privkey, message) + signing_root = compute_signing_root(compute_epoch_at_slot(block.slot), domain) + return bls.Sign(privkey, signing_root) ``` ##### Eth1 Data @@ -312,8 +312,8 @@ def compute_new_state_root(state: BeaconState, block: BeaconBlock) -> Root: ```python def get_block_signature(state: BeaconState, header: BeaconBlockHeader, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(header.slot)) - message = compute_signing_root(header, domain) - return bls.Sign(privkey, message) + signing_root = compute_signing_root(header, domain) + return bls.Sign(privkey, signing_root) ``` ### Attesting @@ -371,8 +371,8 @@ Set `attestation.signature = signed_attestation_data` where `signed_attestation_ ```python def get_signed_attestation_data(state: BeaconState, attestation: IndexedAttestation, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_ATTESTER, attestation.data.target.epoch) - message = compute_signing_root(attestation.data, domain) - return bls.Sign(privkey, message) + signing_root = compute_signing_root(attestation.data, domain) + return bls.Sign(privkey, signing_root) ``` #### Broadcast attestation @@ -390,8 +390,8 @@ A validator is selected to aggregate based upon the return value of `is_aggregat ```python def get_slot_signature(state: BeaconState, slot: Slot, privkey: int) -> BLSSignature: domain = get_domain(state, DOMAIN_BEACON_ATTESTER, compute_epoch_at_slot(slot)) - message = compute_signing_root(slot, domain) - return bls.Sign(privkey, message) + signing_root = compute_signing_root(slot, domain) + return bls.Sign(privkey, signing_root) ``` ```python From 8948393e7699cdbee1492f22bbd9a360b8afc807 Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Tue, 7 Jan 2020 13:07:09 +0100 Subject: [PATCH 14/17] Remove references to BLS messages --- specs/core/0_beacon-chain.md | 7 +++++-- specs/core/1_custody-game.md | 6 ++---- .../pyspec/eth2spec/test/helpers/attestations.py | 4 ++-- test_libs/pyspec/eth2spec/test/helpers/block.py | 8 ++++---- .../pyspec/eth2spec/test/helpers/block_header.py | 4 ++-- .../pyspec/eth2spec/test/helpers/custody.py | 16 ++++++++-------- .../pyspec/eth2spec/test/helpers/deposits.py | 4 ++-- .../eth2spec/test/helpers/phase1/attestations.py | 4 ++-- .../eth2spec/test/helpers/phase1/shard_block.py | 4 ++-- .../eth2spec/test/helpers/voluntary_exits.py | 4 ++-- .../pyspec/eth2spec/test/sanity/test_blocks.py | 8 ++++---- 11 files changed, 35 insertions(+), 34 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 4ba4a91bfd..2bd7f23b7c 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -799,6 +799,9 @@ def compute_domain(domain_type: DomainType, fork_version: Version=Version()) -> ```python def compute_signing_root(ssz_object: SSZObject, domain: Domain) -> Root: + """ + Return the signing root of an object by calculating the root of the object-domain tree. + """ domain_wrapped_object = SigningRoot( object_root=hash_tree_root(ssz_object), domain=domain, @@ -959,11 +962,11 @@ def get_total_active_balance(state: BeaconState) -> Gwei: #### `get_domain` ```python -def get_domain(state: BeaconState, domain_type: DomainType, message_epoch: Epoch=None) -> Domain: +def get_domain(state: BeaconState, domain_type: DomainType, epoch: Epoch=None) -> Domain: """ Return the signature domain (fork version concatenated with domain type) of a message. """ - epoch = get_current_epoch(state) if message_epoch is None else message_epoch + epoch = get_current_epoch(state) if epoch is None else epoch fork_version = state.fork.previous_version if epoch < state.fork.epoch else state.fork.current_version return compute_domain(domain_type, fork_version) ``` diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index 23f9f3f4dc..4df9c3352b 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -482,10 +482,8 @@ def process_early_derived_secret_reveal(state: BeaconState, reveal: EarlyDerived pubkeys = [revealed_validator.pubkey, masker.pubkey] domain = get_domain(state, DOMAIN_RANDAO, reveal.epoch) - messages = [compute_signing_root(message, domain) - for message in [hash_tree_root(reveal.epoch), reveal.mask]] - - assert bls.AggregateVerify(pubkeys, messages, reveal.reveal) + signing_roots = [compute_signing_root(root, domain) for root in [hash_tree_root(reveal.epoch), reveal.mask]] + assert bls.AggregateVerify(pubkeys, signing_roots, reveal.reveal) if reveal.epoch >= get_current_epoch(state) + CUSTODY_PERIOD_TO_RANDAO_PADDING: # Full slashing when the secret was revealed so early it may be a valid custody diff --git a/test_libs/pyspec/eth2spec/test/helpers/attestations.py b/test_libs/pyspec/eth2spec/test/helpers/attestations.py index 52479fd754..cb3e863203 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/attestations.py +++ b/test_libs/pyspec/eth2spec/test/helpers/attestations.py @@ -97,8 +97,8 @@ def sign_attestation(spec, state, attestation): def get_attestation_signature(spec, state, attestation_data, privkey): domain = spec.get_domain(state, spec.DOMAIN_BEACON_ATTESTER, attestation_data.target.epoch) - message = spec.compute_signing_root(attestation_data, domain) - return bls.Sign(privkey, message) + signing_root = spec.compute_signing_root(attestation_data, domain) + return bls.Sign(privkey, signing_root) def fill_aggregate_attestation(spec, state, attestation, signed=False): diff --git a/test_libs/pyspec/eth2spec/test/helpers/block.py b/test_libs/pyspec/eth2spec/test/helpers/block.py index 9b2cc5d03a..dda03cbf13 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/block.py +++ b/test_libs/pyspec/eth2spec/test/helpers/block.py @@ -30,8 +30,8 @@ def apply_randao_reveal(spec, state, block, proposer_index=None): privkey = privkeys[proposer_index] domain = spec.get_domain(state, spec.DOMAIN_RANDAO, spec.compute_epoch_at_slot(block.slot)) - message = spec.compute_signing_root(spec.compute_epoch_at_slot(block.slot), domain) - block.body.randao_reveal = bls.Sign(privkey, message) + signing_root = spec.compute_signing_root(spec.compute_epoch_at_slot(block.slot), domain) + block.body.randao_reveal = bls.Sign(privkey, signing_root) # Fully ignore the function if BLS is off, beacon-proposer index calculation is slow. @@ -42,9 +42,9 @@ def apply_sig(spec, state, signed_block, proposer_index=None): proposer_index = get_proposer_index_maybe(spec, state, block.slot, proposer_index) privkey = privkeys[proposer_index] domain = spec.get_domain(state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot)) - message = spec.compute_signing_root(block, domain) + signing_root = spec.compute_signing_root(block, domain) - signed_block.signature = bls.Sign(privkey, message) + signed_block.signature = bls.Sign(privkey, signing_root) def sign_block(spec, state, block, proposer_index=None): diff --git a/test_libs/pyspec/eth2spec/test/helpers/block_header.py b/test_libs/pyspec/eth2spec/test/helpers/block_header.py index bb5fe692f7..c1bc746ccc 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/block_header.py +++ b/test_libs/pyspec/eth2spec/test/helpers/block_header.py @@ -6,6 +6,6 @@ def sign_block_header(spec, state, header, privkey): state=state, domain_type=spec.DOMAIN_BEACON_PROPOSER, ) - message = spec.compute_signing_root(header, domain) - signature = bls.Sign(privkey, message) + signing_root = spec.compute_signing_root(header, domain) + signature = bls.Sign(privkey, signing_root) return spec.SignedBeaconBlockHeader(message=header, signature=signature) diff --git a/test_libs/pyspec/eth2spec/test/helpers/custody.py b/test_libs/pyspec/eth2spec/test/helpers/custody.py index f75cb96071..e00d64a172 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/custody.py +++ b/test_libs/pyspec/eth2spec/test/helpers/custody.py @@ -18,13 +18,13 @@ def get_valid_early_derived_secret_reveal(spec, state, epoch=None): # Generate the secret that is being revealed domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch) - message = spec.compute_signing_root(spec.Epoch(epoch), domain) - reveal = bls.Sign(privkeys[revealed_index], message) + signing_root = spec.compute_signing_root(spec.Epoch(epoch), domain) + reveal = bls.Sign(privkeys[revealed_index], signing_root) # Generate the mask (any random 32 bytes that don't reveal the masker's secret will do) mask = hash(reveal) # Generate masker's signature on the mask - message = spec.compute_signing_root(mask, domain) - masker_signature = bls.Sign(privkeys[masker_index], message) + signing_root = spec.compute_signing_root(mask, domain) + masker_signature = bls.Sign(privkeys[masker_index], signing_root) masked_reveal = bls.Aggregate([reveal, masker_signature]) return spec.EarlyDerivedSecretReveal( @@ -48,8 +48,8 @@ def get_valid_custody_key_reveal(spec, state, period=None): # Generate the secret that is being revealed domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch_to_sign) - message = spec.compute_signing_root(spec.Epoch(epoch_to_sign), domain) - reveal = bls.Sign(privkeys[revealer_index], message) + signing_root = spec.compute_signing_root(spec.Epoch(epoch_to_sign), domain) + reveal = bls.Sign(privkeys[revealer_index], signing_root) return spec.CustodyKeyReveal( revealer_index=revealer_index, reveal=reveal, @@ -74,8 +74,8 @@ def get_valid_bit_challenge(spec, state, attestation, invalid_custody_bit=False) # Generate the responder key domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch) - message = spec.compute_signing_root(spec.compute_signing_root, domain) - responder_key = bls.Sign(privkeys[responder_index], message) + signing_root = spec.compute_signing_root(spec.Epoch(epoch), domain) + responder_key = bls.Sign(privkeys[responder_index], signing_root) chunk_count = spec.get_custody_chunk_count(attestation.data.crosslink) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index 720704576b..337ad7d827 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -30,8 +30,8 @@ def sign_deposit_data(spec, deposit_data, privkey, state=None): pubkey=deposit_data.pubkey, withdrawal_credentials=deposit_data.withdrawal_credentials, amount=deposit_data.amount) - message = spec.compute_signing_root(deposit_message, domain) - deposit_data.signature = bls.Sign(privkey, message) + signing_root = spec.compute_signing_root(deposit_message, domain) + deposit_data.signature = bls.Sign(privkey, signing_root) def build_deposit(spec, diff --git a/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py b/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py index 7947ba8110..622183fe92 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py +++ b/test_libs/pyspec/eth2spec/test/helpers/phase1/attestations.py @@ -26,5 +26,5 @@ def sign_shard_attestation(spec, beacon_state, shard_state, block, participants) def get_attestation_signature(spec, beacon_state, shard_state, message_hash, block_epoch, privkey): domain = spec.get_domain(beacon_state, spec.DOMAIN_SHARD_ATTESTER, block_epoch) - message = spec.compute_signing_root(message_hash, domain) - return bls.Sign(privkey, message) + signing_root = spec.compute_signing_root(message_hash, domain) + return bls.Sign(privkey, signing_root) diff --git a/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py b/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py index a72a506498..6e1fba8dc2 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py +++ b/test_libs/pyspec/eth2spec/test/helpers/phase1/shard_block.py @@ -19,8 +19,8 @@ def sign_shard_block(spec, beacon_state, shard_state, block, proposer_index=None privkey = privkeys[proposer_index] domain = spec.get_domain(beacon_state, spec.DOMAIN_SHARD_PROPOSER, spec.compute_epoch_of_shard_slot(block.slot)) - message = spec.compute_signing_root(block, domain) - block.signature = bls.Sign(privkey, message) + signing_root = spec.compute_signing_root(block, domain) + block.signature = bls.Sign(privkey, signing_root) def build_empty_shard_block(spec, diff --git a/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py b/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py index f186f15331..55310ef7d5 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/voluntary_exits.py @@ -3,8 +3,8 @@ def sign_voluntary_exit(spec, state, voluntary_exit, privkey): domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch) - message = spec.compute_signing_root(voluntary_exit, domain) + signing_root = spec.compute_signing_root(voluntary_exit, domain) return spec.SignedVoluntaryExit( message=voluntary_exit, - signature=bls.Sign(privkey, message) + signature=bls.Sign(privkey, signing_root) ) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index ae02d8c1ac..b386d36b40 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -108,10 +108,10 @@ def test_invalid_block_sig(spec, state): block = build_empty_block_for_next_slot(spec, state) domain = spec.get_domain(state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot)) - message = spec.compute_signing_root(block, domain) + signing_root = spec.compute_signing_root(block, domain) invalid_signed_block = spec.SignedBeaconBlock( message=block, - signature=bls.Sign(123456, message) + signature=bls.Sign(123456, signing_root) ) expect_assertion_error(lambda: spec.state_transition(state, invalid_signed_block)) @@ -417,10 +417,10 @@ def test_voluntary_exit(spec, state): validator_index=validator_index, ) domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT) - message = spec.compute_signing_root(voluntary_exit, domain) + signing_root = spec.compute_signing_root(voluntary_exit, domain) signed_voluntary_exit = spec.SignedVoluntaryExit( message=voluntary_exit, - signature=bls.Sign(privkeys[validator_index], message) + signature=bls.Sign(privkeys[validator_index], signing_root) ) # Add to state via block transition From 12ea891ce5b6716918e9c65afffcd3e92f427bfb Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Tue, 7 Jan 2020 20:52:20 +0100 Subject: [PATCH 15/17] `py_ecc` 2.0.0 baby! --- specs/core/0_beacon-chain.md | 1 + specs/core/1_custody-game.md | 2 +- .../pyspec/eth2spec/test/helpers/keys.py | 4 ++-- test_libs/pyspec/eth2spec/utils/bls.py | 20 +++++++++---------- test_libs/pyspec/requirements.txt | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 2bd7f23b7c..afa1ea657a 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -590,6 +590,7 @@ Eth2 makes use of BLS signatures as specified in the [IETF draft BLS specificati - `def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool` - `def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature` - `def FastAggregateVerify(PKs: Sequence[BLSSignature], message: Bytes, signature: BLSSignature) -> bool` +- `def AggregateVerify(pairs: Sequence[PK: BLSSignature, message: Bytes], signature: BLSSignature) -> bool` Within these specifications, BLS signatures are treated as a module for notational clarity, thus to verify a signature `bls.Verify(...)` is used. diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index 4df9c3352b..fdaf9af423 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -483,7 +483,7 @@ def process_early_derived_secret_reveal(state: BeaconState, reveal: EarlyDerived domain = get_domain(state, DOMAIN_RANDAO, reveal.epoch) signing_roots = [compute_signing_root(root, domain) for root in [hash_tree_root(reveal.epoch), reveal.mask]] - assert bls.AggregateVerify(pubkeys, signing_roots, reveal.reveal) + assert bls.AggregateVerify(zip(pubkeys, signing_roots), reveal.reveal) if reveal.epoch >= get_current_epoch(state) + CUSTODY_PERIOD_TO_RANDAO_PADDING: # Full slashing when the secret was revealed so early it may be a valid custody diff --git a/test_libs/pyspec/eth2spec/test/helpers/keys.py b/test_libs/pyspec/eth2spec/test/helpers/keys.py index f47cd7c10b..23bb95131f 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/keys.py +++ b/test_libs/pyspec/eth2spec/test/helpers/keys.py @@ -1,6 +1,6 @@ -from py_ecc import bls +from py_ecc.bls import G2ProofOfPossession as bls from eth2spec.phase0 import spec privkeys = [i + 1 for i in range(spec.SLOTS_PER_EPOCH * 16)] -pubkeys = [bls.privtopub(privkey) for privkey in privkeys] +pubkeys = [bls.PrivToPub(privkey) for privkey in privkeys] pubkey_to_privkey = {pubkey: privkey for privkey, pubkey in zip(privkeys, pubkeys)} diff --git a/test_libs/pyspec/eth2spec/utils/bls.py b/test_libs/pyspec/eth2spec/utils/bls.py index 3cfc6121e8..83371ac628 100644 --- a/test_libs/pyspec/eth2spec/utils/bls.py +++ b/test_libs/pyspec/eth2spec/utils/bls.py @@ -1,11 +1,12 @@ -from py_ecc import bls +from py_ecc.bls import G2ProofOfPossession as bls +from py_ecc.bls.g2_primatives import signature_to_G2 as _signature_to_G2 # Flag to make BLS active or not. Used for testing, do not ignore BLS in production unless you know what you are doing. bls_active = True STUB_SIGNATURE = b'\x11' * 96 STUB_PUBKEY = b'\x22' * 48 -STUB_COORDINATES = bls.api.signature_to_G2(bls.sign(b"", 0, b"\0" * 8)) +STUB_COORDINATES = _signature_to_G2(bls.Sign(0, b"")) def only_with_bls(alt_return=None): @@ -24,30 +25,29 @@ def entry(*args, **kw): @only_with_bls(alt_return=True) def Verify(PK, message, signature): - return bls.verify(message_hash=message, pubkey=PK, signature=signature, domain=b'') + return bls.Verify(PK, message, signature) @only_with_bls(alt_return=True) -def AggregateVerify(PKs, messages, signature): - return bls.verify_multiple(pubkeys=PKs, message_hashes=messages, signature=signature, domain=b'') +def AggregateVerify(pairs, signature): + return bls.AggregateVerify(pairs, signature) @only_with_bls(alt_return=True) def FastAggregateVerify(PKs, message, signature): - aggregate_pubkey = bls.aggregate_pubkeys(PKs) - return bls.verify(pubkey=aggregate_pubkey, message_hash=message, signature=signature, domain=b'') + return bls.FastAggregateVerify(PKs, message, signature) @only_with_bls(alt_return=STUB_SIGNATURE) def Aggregate(signatures): - return bls.aggregate_signatures(signatures) + return bls.Aggregate(signatures) @only_with_bls(alt_return=STUB_SIGNATURE) def Sign(SK, message): - return bls.sign(message_hash=message, privkey=SK, domain=b'') + return bls.Sign(SK, message) @only_with_bls(alt_return=STUB_COORDINATES) def signature_to_G2(signature): - return bls.api.signature_to_G2(signature) + return _signature_to_G2(signature) diff --git a/test_libs/pyspec/requirements.txt b/test_libs/pyspec/requirements.txt index 8dfbccf660..60acb5d354 100644 --- a/test_libs/pyspec/requirements.txt +++ b/test_libs/pyspec/requirements.txt @@ -1,6 +1,6 @@ eth-utils>=1.3.0,<2 eth-typing>=2.1.0,<3.0.0 pycryptodome==3.9.4 -py_ecc==1.7.1 +py_ecc==2.0.0 dataclasses==0.6 ssz==0.1.3 From 1f70d3eb975334e1c3ea6dd9ad552172064462a6 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 7 Jan 2020 15:12:24 -0700 Subject: [PATCH 16/17] add additional upgrade to py_ecc 2.0.0 to packages --- test_generators/bls/requirements.txt | 2 +- test_libs/pyspec/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test_generators/bls/requirements.txt b/test_generators/bls/requirements.txt index 84a28d357f..8a72affe01 100644 --- a/test_generators/bls/requirements.txt +++ b/test_generators/bls/requirements.txt @@ -1,3 +1,3 @@ -py_ecc==1.7.1 +py_ecc==2.0.0 eth-utils==1.6.0 ../../test_libs/gen_helpers diff --git a/test_libs/pyspec/setup.py b/test_libs/pyspec/setup.py index d41412eb8b..5be0db7f82 100644 --- a/test_libs/pyspec/setup.py +++ b/test_libs/pyspec/setup.py @@ -8,7 +8,7 @@ "eth-utils>=1.3.0,<2", "eth-typing>=2.1.0,<3.0.0", "pycryptodome==3.9.4", - "py_ecc==1.7.1", + "py_ecc==2.0.0", "ssz==0.1.3", "dataclasses==0.6", ] From 19ca7af5ed65896c4fe3f6effadca0f176cb00cf Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 7 Jan 2020 15:15:51 -0700 Subject: [PATCH 17/17] bump circleci cache versions --- .circleci/config.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 26b2597382..f3870d9227 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,26 +35,26 @@ commands: description: "Restore the cache with pyspec keys" steps: - restore_cached_venv: - venv_name: v4-pyspec + venv_name: v5-pyspec reqs_checksum: cache-{{ checksum "test_libs/pyspec/requirements.txt" }}-{{ checksum "test_libs/pyspec/requirements-testing.txt" }} save_pyspec_cached_venv: description: Save a venv into a cache with pyspec keys" steps: - save_cached_venv: - venv_name: v4-pyspec + venv_name: v5-pyspec reqs_checksum: cache-{{ checksum "test_libs/pyspec/requirements.txt" }}-{{ checksum "test_libs/pyspec/requirements-testing.txt" }} venv_path: ./test_libs/pyspec/venv restore_deposit_contract_cached_venv: description: "Restore the cache with deposit_contract keys" steps: - restore_cached_venv: - venv_name: v7-deposit-contract + venv_name: v8-deposit-contract reqs_checksum: cache-{{ checksum "test_libs/pyspec/requirements.txt" }}-{{ checksum "deposit_contract/requirements-testing.txt" }} save_deposit_contract_cached_venv: description: Save a venv into a cache with deposit_contract keys" steps: - save_cached_venv: - venv_name: v7-deposit-contract + venv_name: v8-deposit-contract reqs_checksum: cache-{{ checksum "test_libs/pyspec/requirements.txt" }}-{{ checksum "deposit_contract/requirements-testing.txt" }} venv_path: ./deposit_contract/venv jobs: