Skip to content

Commit

Permalink
Revert G_t element optimization
Browse files Browse the repository at this point in the history
This needs its own ethresearch post, and some additional analysis to see if we can do the shuffle ZKP in the allowed
timeframe.

This reverts commit 8517aca.
  • Loading branch information
asn-d6 authored and nalinbhardwaj committed Jan 12, 2023
1 parent bfd2976 commit 48f11f5
Showing 1 changed file with 72 additions and 11 deletions.
83 changes: 72 additions & 11 deletions specs/whisk/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,23 @@
| - | - | - |
| `BLSScalar` | `Bytes48` | BLS12-381 scalar |
| `BLSG1Point` | `Bytes48` | compressed BLS12-381 G1 point |
| `BLSGtPoint` | `Vector[Bytes48, 4]` | compressed BLS12-381 Gt point |

*Note*: A subgroup check MUST be performed when deserializing a `BLSG1Point` for use in any of the functions below.

#### Whisk (TODO)
```python
def BLSG1PointFromAffine(x: int, y: int) -> BLSG1Point


def BLSG1ScalarMultiply(scalar: BLSScalar, point: BLSG1Point) -> BLSG1Point
```

| Name | Value |
| - | - |
| `BLS_G1_GENERATOR_X` | `0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb` |
| `BLS_G1_GENERATOR_Y` | `0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1` |
| `BLS_G1_GENERATOR` | `BLSG1PointFromAffine(BLS_G1_GENERATOR_X, BLS_G1_GENERATOR_Y)` |

#### Whisk

```python
class WhiskShuffleProof:
Expand All @@ -42,26 +54,31 @@ def IsValidWhiskShuffleProof(pre_shuffle_trackers: Sequence[WhiskTracker],
"""


def IsValidWhiskOpeningProof(pubkey: BLSPubkey, tracker: WhiskTracker, opening_proof: WhiskOpeningProof) -> bool:
def IsValidWhiskOpeningProof(tracker: WhiskTracker, k_commitment: BLSG1Point, tracker_proof: WhiskTrackerProof) -> bool:
"""
Verify the `privkey` for `pubkey` satisfies `tracker.Gt_point == e(privkey * tracker.G1_point, BLS_G2_SAMPLE)`.
Verify knowledge of `k` such that `tracker.k_r_G == k * tracker.r_G` and `k_commitment == k * BLS_G1_GENERATOR`.
"""
```

### Epoch processing

```python
class WhiskTracker(Container):
G1_point: BLSG1Point # r * BLS_G1_GENERATOR
Gt_point: BLSGtPoint # r * e(privkey * BLS_G1_GENERATOR, BLS_G2_SAMPLE)
r_G: BLSG1Point # r * G
k_r_G: BLSG1Point # k * r * G

class Validator(Container):
# ...
# Whisk
whisk_tracker: WhiskTracker # Whisk tracker (r * G, k * r * G) [New in Whisk]
whisk_k_commitment: BLSG1Point # Whisk k commitment k * BLS_G1_GENERATOR [New in Whisk]

class BeaconState(Container):
# ...
# Whisk
whisk_candidate_trackers: Vector[WhiskTracker, WHISK_CANDIDATE_TRACKERS_COUNT] # [New in Whisk]
whisk_proposer_trackers: Vector[WhiskTracker, WHISK_PROPOSER_TRACKERS_COUNT] # [New in Whisk]


def select_whisk_trackers(state: BeaconState, epoch: Epoch) -> None:
# Select proposer trackers from candidate trackers
proposer_seed = get_seed(state, epoch - WHISK_PROPOSER_SELECTION_GAP, DOMAIN_WHISK_PROPOSER_SELECTION)
Expand All @@ -74,7 +91,7 @@ def select_whisk_trackers(state: BeaconState, epoch: Epoch) -> None:
for i in range(WHISK_CANDIDATE_TRACKERS_COUNT):
seed = hash(get_seed(state, epoch, DOMAIN_WHISK_CANDIDATE_SELECTION) + uint_to_bytes(i))
candidate_index = compute_proposer_index(state, active_validator_indices, seed) # sample by effective balance
state.whisk_candidate_trackers[i] = WhiskTracker(state[index].pubkey, BLS_GT_GENERATOR)
state.whisk_candidate_trackers[i] = state.validators[candidate_index].whisk_tracker


def process_whisk_updates(state: BeaconState) -> None:
Expand All @@ -100,9 +117,9 @@ class BeaconBlock(Container):
# ...

def process_whisk_opening_proof(state: BeaconState, block: BeaconBlock) -> None:
pubkey = state.validators[block.proposer_index].pubkey
tracker = state.whisk_proposer_trackers[state.slot % WHISK_PROPOSER_TRACKERS_COUNT]
assert whisk.IsValidWhiskOpeningProof(pubkey, tracker, block.whisk_opening_proof)
k_commitment = state.validators[block.proposer_index].whisk_k_commitment
assert whisk.IsValidWhiskOpeningProof(tracker, k_commitment, block.whisk_opening_proof)


def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
Expand All @@ -121,6 +138,9 @@ class BeaconBlockBody(Container):
# Whisk
whisk_post_shuffle_trackers: Vector[WhiskTracker, WHISK_VALIDATORS_PER_SHUFFLE] # [New in Whisk]
whisk_shuffle_proof: WhiskShuffleProof # [New in Whisk]
whisk_registration_proof: WhiskTrackerProof # [New in Whisk]
whisk_tracker: WhiskTracker # [New in Whisk]
whisk_k_commitment: BLSG1Point # [New in Whisk]

def get_feistel_encryption(index: uint64, rounds: uin64, K: uint64) -> uint64:
def F(x):
Expand All @@ -142,7 +162,7 @@ def get_shuffle_indices(state: BeaconState, epoch: Epoch) -> Sequence[uint64]:
return [get_feistel_encryption(index, shuffle_round, WHISK_VALIDATORS_PER_SHUFFLE) for index in row_indices]


def process_whisk(state: BeaconState, body: BeaconBlockBody) -> None:
def whisk_process_shuffled_trackers(state: BeaconState, body: BeaconBlockBody) -> None:
# Check the shuffle proof
shuffle_indices = get_shuffle_indices(state, get_current_epoch(state))
pre_shuffle_trackers = [state.whisk_candidate_trackers[i] for i in shuffle_indices]
Expand All @@ -159,11 +179,52 @@ def process_whisk(state: BeaconState, body: BeaconBlockBody) -> None:
state.whisk_candidate_trackers[shuffle_index] = post_shuffle_trackers[i]


def is_k_commitment_unique(state: BeaconState, k_commitment: BLSG1Point) -> bool:
return all([validator.whisk_k_commitment != k_commitment for validator in state.validators])


def process_whisk(state: BeaconState, body: BeaconBlockBody) -> None:
whisk_process_shuffled_trackers(state, body)

# Overwrite all validator Whisk fields (first Whisk proposal) or just the permutation commitment (next proposals)
proposer = state.validators[get_beacon_proposer_index(state)]
if proposer.whisk_tracker.r_G == BLS_G1_GENERATOR: # first Whisk proposal
assert body.whisk_tracker.r_G != BLS_G1_GENERATOR
assert is_k_commitment_unique(state, body.whisk_k_commitment)
assert whisk.IsValidWhiskOpeningProof(body.whisk_tracker, body.whisk_k_commitment, body.whisk_registration_proof)
proposer.whisk_tracker = body.whisk_tracker
proposer.whisk_k_commitment = body.whisk_k_commitment
else: # next Whisk proposals
assert body.whisk_registration_proof == WhiskTrackerProof()
assert body.whisk_tracker == WhiskTracker()
assert body.whisk_k_commitment == BLSG1Point()


def process_block(state: BeaconState, block: BeaconBlock) -> None:
# ...
process_whisk(state, block.body) # [New in Whisk]
```

#### Deposits

```python
def get_unique_whisk_k(state: BeaconState, validator_index: ValidatorIndex) -> BLSScalar:
counter = 0
while True:
k = BLSScalar(hash(uint_to_bytes(validator_index) + uint_to_bytes(counter))) # hash `validator_index || counter`
if is_k_commitment_unique(state, bls.BLSG1ScalarMultiply(k, BLS_G1_GENERATOR)):
return k # unique by trial and error
counter += 1


def get_validator_from_deposit(state: BeaconState, deposit: Deposit) -> Validator:
validator = bellatrix.get_validator_from_deposit(state, deposit)
k = get_unique_whisk_k(state, len(state.validators))
validator.whisk_tracker = WhiskTracker(BLS_G1_GENERATOR, bls.BLSG1ScalarMultiply(k, BLS_G1_GENERATOR))
validator.whisk_k_commitment = bls.BLSG1ScalarMultiply(k, BLS_G1_GENERATOR)
return validator
```

#### `get_beacon_proposer_index`

```python
Expand Down

0 comments on commit 48f11f5

Please sign in to comment.