Phase 0 new BLS
This commit is contained in:
parent
88e954a9c7
commit
502ee29537
|
@ -11,7 +11,7 @@ from typing import (
|
|||
|
||||
|
||||
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 dataclasses import (
|
|||
|
||||
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 @@ from eth2spec.utils.ssz.ssz_typing import (
|
|||
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 @@ from eth2spec.utils.hash_function import hash
|
|||
|
||||
SSZVariableName = str
|
||||
GeneralizedIndex = NewType('GeneralizedIndex', int)
|
||||
SSZObject = TypeVar('SSZObject', bound=SSZType)
|
||||
'''
|
||||
SUNDRY_CONSTANTS_FUNCTIONS = '''
|
||||
def ceillog2(x: uint64) -> int:
|
||||
|
|
|
@ -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
|
||||
<!-- TOC -->
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
|
||||
- [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)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- /TOC -->
|
||||
|
||||
## 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)`.
|
|
@ -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)
|
||||
```
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -3,7 +3,7 @@ from typing import List
|
|||
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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -2,7 +2,7 @@ from copy import deepcopy
|
|||
|
||||
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,
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -23,31 +23,35 @@ def only_with_bls(alt_return=None):
|
|||
|
||||
|
||||
@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)
|
||||
|
|
Loading…
Reference in New Issue