# Secret Single Leader Election (SSLE) in Eth2
### Parameters
| Name | Value |
| - | - |
| `SHUFFLE_INDICES` | `[i for i in range(16)] + [(16 + i % 16) * 2**(i // 16) for i in range(112)]` |
| `SHUFFLE_SIZE` | `len(SHUFFLE_INDICES)` |
| `MAX_SHUFFLE_POOL_SIZE` | `2048` |
| `MAX_SHUFFLE_REGISTRATIONS` | `8` |
| `DOMAIN_SHUFFLE_REGISTRATION` | `???` |
### Type aliases
* alias `G1Point` to `Bytes48`
* alias `BLSPubkey` to `G1Point` (removing the alias to `Bytes48`)
* alias `ShuffleCommitment` to `G1Point`
* alias `ShuffleProof` to `???`
### New containers
##### `ShufflePair`
```python
class ShufflePair(Container):
base: G1Point # blinding base
key: G1Point # equal to `base * shuffle_secret` for some `shuffle_secret`
```
##### `ShuffleSecretSeed`
```python
class ShuffleSecretSeed(Container):
index: ValidatorIndex
commitment: ShuffleCommitment # shuffle permutation commitment
```
##### `ShuffleRegistration`
```python
class ShuffleRegistration(Container):
slot: Slot # slot at which validator was eligible for the shuffle pool
key: G1Point # equal to `bls.G1 * shuffle_secret` for some `shuffle_secret`
```
##### `ShuffleReveal`
```python
class ShuffleReveal(Container):
commitment: ShuffleCommitment # shuffle permutation commitment
pairs: Vector[ShufflePair, SHUFFLE_SIZE] # shuffled pairs
proof: ShuffleProof # zero-knowledge shuffle proof
```
##### `SignedShuffleRegistration`
```python
class SignedShuffleRegistration(Container):
message: ShuffleRegistration
signature: BLSSignature
```
### New container properties
##### `BeaconBlockBody`
```py
shuffle_reveal: ShuffleReveal
shuffle_registrations: List[SignedShuffleRegistration, MAX_SHUFFLE_REGISTRATIONS]
```
##### `BeaconState`
```py
shuffle_pool: List[ShufflePair, MAX_SHUFFLE_POOL_SIZE]
```
##### `Validator`
```py
in_shuffle_pool: bool
```
### Process shuffle registrations
Add the line `for_ops(body.shuffle_registrations, process_shuffle_registration)` in `process_operations`.
```python
def get_shuffle_pool_registrant_index(state: BeaconState, slot: Slot) -> ValidatorIndex:
# Generalize `get_beacon_proposer_index` to slots other than the current one
def process_shuffle_registration(state: BeaconState, signed_registration: SignedShuffleRegistration) -> None:
registration = signed_registration.message
# Validators have `MAX_SHUFFLE_POOL_SIZE // 2` slots to submit their shuffle registration
assert state.slot - MAX_SHUFFLE_POOL_SIZE // 2 < registration.slot <= state.slot
# Verify the registrant is not already in the shuffle pool
registrant_index = get_shuffle_pool_registrant_index(state, registration.slot)
registrant = state.validators[registrant_index]
assert registrant.in_shuffle_pool == False
# Verify the shuffle registration
assert registration.key != bls.Z1
domain = get_domain(state, DOMAIN_SHUFFLE_REGISTRATION, compute_epoch_at_slot(registration.slot))
signing_root = compute_signing_root(registration, domain)
assert bls.Verify(registrant.pubkey, signing_root, signed_registration.signature)
# Add the registrant shuffle pair to the shuffle pool
state.shuffle_pool.append(ShufflePair(base=bls.G1, key=registration.key))
registrant.in_shuffle_pool = True
```
### Process shuffle reveal
```python
def process_shuffle_reveal(state: BeaconState, block: BeaconBlock) -> None:
# Fetch and remove the proposer shuffle pair (zeroth shuffle pair) from the shuffle pool
proposer_shuffle_pair = state.shuffle_pool.pop(0)
state.validators[block.proposer_index].in_shuffle_pool = False
# Compute shuffle secret from proposer index and shuffle commitment
shuffle_secret = bytes_to_uint256(hash_tree_root(ShuffleSecretSeed(
index=block.proposer_index,
commitment=block.body.shuffle_reveal.commitment,
)))
# Verify the proposer shuffle pair and secret are consistent
assert bls.multiply(proposer_shuffle_pair.base, secret) == proposer_shuffle_pair.key
# Verify the shuffle proof
target_shuffle_pairs = [state.shuffle_pool[i] for i in SHUFFLE_INDICES if i < len(state.shuffle_pool)]
dummy_shuffle_pairs = [ShufflePair(base=bls.G1, key=bls.Z1)]*(SHUFFLE_SIZE - len(target_shuffle_pairs))
assert is_valid_shuffle_proof(
non_shuffled_pairs=target_shuffle_pairs + dummy_shuffle_pairs,
shuffle_reveal=block.body.shuffle_reveal,
)
# Record the shuffled pairs to the shuffle pool
dummy_shuffle_pairs_counter = 0
for i in range(SHUFFLE_SIZE):
if block.body.shuffle_reveal.pairs[i].key == bls.Z1:
dummy_shuffle_pairs_counter += 1
else:
shuffle_index = SHUFFLE_INDICES[i - dummy_shuffle_pairs_counter]
state.shuffle_pool[shuffle_index] = block.body.shuffle_reveal.pairs[i]
```
### Beacon proposer selection
In `process_block_header` replace the line
```python
assert block.proposer_index == get_beacon_proposer_index(state)
```
by
```python
if len(state.shuffle_pool) < MAX_SHUFFLE_POOL_SIZE // 2:
# If the shuffle pool is too small the propooser is not secret
assert block.proposer_index == get_beacon_proposer_index(state)
# Verify the shuffle reveal is zero
assert block.body.shuffle_reveal == ShuffleReveal()
else:
process_shuffle_reveal(state, block)
```