Update curdleproofs usage
This commit is contained in:
parent
c0c453df2a
commit
211376e35c
|
@ -11,6 +11,7 @@ class WhiskSpecBuilder(BaseSpecBuilder):
|
|||
return f'''
|
||||
from eth2spec.capella import {preset_name} as capella
|
||||
import curdleproofs
|
||||
from py_arkworks_bls12381 import G1Point
|
||||
'''
|
||||
|
||||
@classmethod
|
||||
|
|
2
setup.py
2
setup.py
|
@ -263,7 +263,7 @@ def get_spec(file_name: Path, preset: Dict[str, str], config: Dict[str, str], pr
|
|||
constant_vars['CURDLEPROOFS_CRS_G1'] = VariableDefinition(constant_vars['CURDLEPROOFS_CRS_G1'].value, str(ALL_KZG_SETUPS['mainnet'][0][0:crs_len]), "noqa: E501", None)
|
||||
constant_vars['CURDLEPROOFS_CRS'] = VariableDefinition(
|
||||
None,
|
||||
"curdleproofs.CurdleproofsCrs.from_points_compressed(WHISK_VALIDATORS_PER_SHUFFLE, CURDLEPROOFS_N_BLINDERS, CURDLEPROOFS_CRS_G1)",
|
||||
"curdleproofs.CurdleproofsCrs.from_random_points(WHISK_VALIDATORS_PER_SHUFFLE, CURDLEPROOFS_N_BLINDERS, [G1Point.from_compressed_bytes_unchecked(p) for p in CURDLEPROOFS_CRS_G1])",
|
||||
"noqa: E501", None
|
||||
)
|
||||
constant_vars['BLS_G1_GENERATOR'] = VariableDefinition(
|
||||
|
|
|
@ -100,7 +100,6 @@ Note that Curdleproofs (Whisk Shuffle Proofs), the tracker opening proofs and al
|
|||
```python
|
||||
def IsValidWhiskShuffleProof(pre_shuffle_trackers: Sequence[WhiskTracker],
|
||||
post_shuffle_trackers: Sequence[WhiskTracker],
|
||||
M: BLSG1Point,
|
||||
shuffle_proof: WhiskShuffleProof) -> bool:
|
||||
"""
|
||||
Verify `post_shuffle_trackers` is a permutation of `pre_shuffle_trackers`.
|
||||
|
@ -110,7 +109,6 @@ def IsValidWhiskShuffleProof(pre_shuffle_trackers: Sequence[WhiskTracker],
|
|||
CURDLEPROOFS_CRS,
|
||||
pre_shuffle_trackers,
|
||||
post_shuffle_trackers,
|
||||
M,
|
||||
shuffle_proof,
|
||||
)
|
||||
```
|
||||
|
@ -299,7 +297,6 @@ class BeaconBlockBody(Container):
|
|||
whisk_opening_proof: WhiskTrackerProof # [New in Whisk]
|
||||
whisk_post_shuffle_trackers: Vector[WhiskTracker, WHISK_VALIDATORS_PER_SHUFFLE] # [New in Whisk]
|
||||
whisk_shuffle_proof: WhiskShuffleProof # [New in Whisk]
|
||||
whisk_shuffle_proof_M_commitment: BLSG1Point # [New in Whisk]
|
||||
whisk_registration_proof: WhiskTrackerProof # [New in Whisk]
|
||||
whisk_tracker: WhiskTracker # [New in Whisk]
|
||||
whisk_k_commitment: BLSG1Point # k * BLS_G1_GENERATOR [New in Whisk]
|
||||
|
@ -330,7 +327,6 @@ def process_shuffled_trackers(state: BeaconState, body: BeaconBlockBody) -> None
|
|||
if shuffle_epoch + WHISK_PROPOSER_SELECTION_GAP + 1 >= WHISK_EPOCHS_PER_SHUFFLING_PHASE:
|
||||
# Require trackers set to zero during cooldown
|
||||
assert body.whisk_post_shuffle_trackers == Vector[WhiskTracker, WHISK_VALIDATORS_PER_SHUFFLE]()
|
||||
assert body.whisk_shuffle_proof_M_commitment == BLSG1Point()
|
||||
assert body.whisk_shuffle_proof == WhiskShuffleProof()
|
||||
post_shuffle_trackers = pre_shuffle_trackers
|
||||
else:
|
||||
|
@ -338,7 +334,6 @@ def process_shuffled_trackers(state: BeaconState, body: BeaconBlockBody) -> None
|
|||
assert IsValidWhiskShuffleProof(
|
||||
pre_shuffle_trackers,
|
||||
body.whisk_post_shuffle_trackers,
|
||||
body.whisk_shuffle_proof_M_commitment,
|
||||
body.whisk_shuffle_proof,
|
||||
)
|
||||
post_shuffle_trackers = body.whisk_post_shuffle_trackers
|
||||
|
|
|
@ -22,6 +22,7 @@ from eth2spec.test.helpers.whisk import (
|
|||
is_first_proposal,
|
||||
resolve_known_tracker
|
||||
)
|
||||
from py_arkworks_bls12381 import Scalar
|
||||
|
||||
PointProjective = Optimized_Point3D[Optimized_Field]
|
||||
|
||||
|
@ -139,7 +140,7 @@ def build_empty_block(spec, state, slot=None, proposer_index=None):
|
|||
if not is_whisk_proposer(proposer_tracker, k_initial):
|
||||
raise Exception("k proposer_index does not match proposer_tracker")
|
||||
|
||||
empty_block.body.whisk_opening_proof = GenerateWhiskTrackerProof(proposer_tracker, k_initial)
|
||||
empty_block.body.whisk_opening_proof = GenerateWhiskTrackerProof(proposer_tracker, Scalar(k_initial))
|
||||
if not IsValidWhiskOpeningProof(proposer_tracker, proposer_k_commitment, empty_block.body.whisk_opening_proof):
|
||||
raise Exception(
|
||||
"produced opening proof is not valid",
|
||||
|
@ -154,23 +155,20 @@ def build_empty_block(spec, state, slot=None, proposer_index=None):
|
|||
shuffle_indices = spec.get_shuffle_indices(empty_block.body.randao_reveal)
|
||||
pre_shuffle_trackers = [state.whisk_candidate_trackers[i] for i in shuffle_indices]
|
||||
|
||||
post_trackers, m, shuffle_proof = GenerateWhiskShuffleProof(spec.CURDLEPROOFS_CRS, pre_shuffle_trackers)
|
||||
post_trackers, shuffle_proof = GenerateWhiskShuffleProof(spec.CURDLEPROOFS_CRS, pre_shuffle_trackers)
|
||||
empty_block.body.whisk_post_shuffle_trackers = post_trackers
|
||||
empty_block.body.whisk_shuffle_proof = shuffle_proof
|
||||
empty_block.body.whisk_shuffle_proof_M_commitment = m
|
||||
|
||||
if not IsValidWhiskShuffleProof(
|
||||
spec.CURDLEPROOFS_CRS,
|
||||
pre_shuffle_trackers,
|
||||
empty_block.body.whisk_post_shuffle_trackers,
|
||||
empty_block.body.whisk_shuffle_proof_M_commitment,
|
||||
empty_block.body.whisk_shuffle_proof,
|
||||
):
|
||||
raise Exception(
|
||||
"produced shuffle proof is not valid",
|
||||
pre_shuffle_trackers,
|
||||
empty_block.body.whisk_post_shuffle_trackers,
|
||||
empty_block.body.whisk_shuffle_proof_M_commitment,
|
||||
empty_block.body.whisk_shuffle_proof,
|
||||
)
|
||||
|
||||
|
@ -184,7 +182,7 @@ def build_empty_block(spec, state, slot=None, proposer_index=None):
|
|||
# TODO: Actual logic should pick a random r, but may need to do something fancy to locate trackers quickly
|
||||
r = 2
|
||||
tracker, k_commitment = compute_whisk_tracker_and_commitment(k_final, r)
|
||||
empty_block.body.whisk_registration_proof = GenerateWhiskTrackerProof(tracker, k_final)
|
||||
empty_block.body.whisk_registration_proof = GenerateWhiskTrackerProof(tracker, Scalar(k_final))
|
||||
empty_block.body.whisk_tracker = tracker
|
||||
empty_block.body.whisk_k_commitment = k_commitment
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
from typing import Tuple, Optional
|
||||
from eth_typing import BLSPubkey
|
||||
from py_ecc.optimized_bls12_381.optimized_curve import G1, multiply
|
||||
from py_ecc.bls.g2_primitives import G1_to_pubkey as py_ecc_G1_to_bytes48
|
||||
from curdleproofs import GenerateWhiskTrackerProof, WhiskTracker
|
||||
from eth2spec.test.helpers.keys import whisk_ks_initial
|
||||
from py_arkworks_bls12381 import G1Point, Scalar
|
||||
|
||||
|
||||
# Map of validator index to initial WhiskTracker (r = 1, k = index)
|
||||
|
@ -14,6 +13,9 @@ whisk_initial_k_commitment_cache_by_index = {}
|
|||
whisk_initial_tracker_cache_by_k_r_G = {}
|
||||
INITIAL_R = 1
|
||||
|
||||
# Generator
|
||||
G1 = G1Point()
|
||||
|
||||
|
||||
def compute_whisk_initial_tracker_cached(i: int) -> WhiskTracker:
|
||||
if i in whisk_initial_tracker_cache_by_index:
|
||||
|
@ -41,39 +43,50 @@ def resolve_known_tracker(tracker: WhiskTracker) -> Optional[int]:
|
|||
return None
|
||||
|
||||
|
||||
def g1point_to_bytes(point: G1Point) -> bytes:
|
||||
return bytes(point.to_compressed_bytes())
|
||||
|
||||
|
||||
def compute_whisk_k_commitment(k: int) -> BLSPubkey:
|
||||
return py_ecc_G1_to_bytes48(multiply(G1, int(k)))
|
||||
return g1point_to_bytes(G1 * Scalar(k))
|
||||
|
||||
|
||||
def compute_whisk_tracker(k: int, r: int) -> WhiskTracker:
|
||||
r_G = multiply(G1, int(r))
|
||||
k_r_G = multiply(r_G, int(k))
|
||||
return WhiskTracker(py_ecc_G1_to_bytes48(r_G), py_ecc_G1_to_bytes48(k_r_G))
|
||||
r_G = G1 * Scalar(r)
|
||||
k_r_G = r_G * Scalar(k)
|
||||
return WhiskTracker(g1point_to_bytes(r_G), g1point_to_bytes(k_r_G))
|
||||
|
||||
|
||||
def compute_whisk_tracker_and_commitment(k: int, r: int) -> Tuple[WhiskTracker, BLSPubkey]:
|
||||
k_G = multiply(G1, int(k))
|
||||
r_G = multiply(G1, int(r))
|
||||
k_r_G = multiply(r_G, int(k))
|
||||
tracker = WhiskTracker(py_ecc_G1_to_bytes48(r_G), py_ecc_G1_to_bytes48(k_r_G))
|
||||
commitment = py_ecc_G1_to_bytes48(k_G)
|
||||
k_G = G1 * Scalar(k)
|
||||
r_G = G1 * Scalar(r)
|
||||
k_r_G = r_G * Scalar(k)
|
||||
tracker = WhiskTracker(g1point_to_bytes(r_G), g1point_to_bytes(k_r_G))
|
||||
commitment = g1point_to_bytes(k_G)
|
||||
return tracker, commitment
|
||||
|
||||
|
||||
# Trigger condition for first proposal
|
||||
def set_as_first_proposal(spec, state, proposer_index: int):
|
||||
# Ensure tracker is empty to prevent breaking it
|
||||
assert state.whisk_trackers[proposer_index].r_G == spec.BLSG1Point()
|
||||
state.whisk_trackers[proposer_index].r_G = spec.BLS_G1_GENERATOR
|
||||
if state.whisk_trackers[proposer_index].r_G != spec.BLS_G1_GENERATOR:
|
||||
# Ensure tracker is empty to prevent breaking it
|
||||
assert state.whisk_trackers[proposer_index].r_G == spec.BLSG1Point()
|
||||
state.whisk_trackers[proposer_index].r_G = spec.BLS_G1_GENERATOR
|
||||
|
||||
|
||||
def is_first_proposal(spec, state, proposer_index: int) -> bool:
|
||||
return state.whisk_trackers[proposer_index].r_G == spec.BLS_G1_GENERATOR
|
||||
|
||||
|
||||
def register_tracker(state, proposer_index: int, k: int, r: int):
|
||||
tracker, k_commitment = compute_whisk_tracker_and_commitment(k, r)
|
||||
state.whisk_trackers[proposer_index] = tracker
|
||||
state.whisk_k_commitments[proposer_index] = k_commitment
|
||||
|
||||
|
||||
def set_registration(body, k: int, r: int):
|
||||
tracker, k_commitment = compute_whisk_tracker_and_commitment(k, r)
|
||||
body.whisk_registration_proof = GenerateWhiskTrackerProof(tracker, k)
|
||||
body.whisk_registration_proof = GenerateWhiskTrackerProof(tracker, Scalar(k))
|
||||
body.whisk_tracker = tracker
|
||||
body.whisk_k_commitment = k_commitment
|
||||
|
||||
|
@ -83,4 +96,4 @@ def set_opening_proof(spec, state, block, proposer_index: int, k: int, r: int):
|
|||
state.whisk_proposer_trackers[state.slot % spec.WHISK_PROPOSER_TRACKERS_COUNT] = tracker
|
||||
state.whisk_k_commitments[proposer_index] = k_commitment
|
||||
block.proposer_index = proposer_index
|
||||
block.body.whisk_opening_proof = GenerateWhiskTrackerProof(tracker, k)
|
||||
block.body.whisk_opening_proof = GenerateWhiskTrackerProof(tracker, Scalar(k))
|
||||
|
|
|
@ -7,10 +7,9 @@ from curdleproofs import GenerateWhiskShuffleProof
|
|||
def set_correct_shuffle_proofs(spec, state, body):
|
||||
pre_shuffle_trackers = get_and_populate_pre_shuffle_trackers(spec, state, body)
|
||||
|
||||
post_trackers, m, shuffle_proof = GenerateWhiskShuffleProof(spec.CURDLEPROOFS_CRS, pre_shuffle_trackers)
|
||||
post_trackers, shuffle_proof = GenerateWhiskShuffleProof(spec.CURDLEPROOFS_CRS, pre_shuffle_trackers)
|
||||
body.whisk_post_shuffle_trackers = post_trackers
|
||||
body.whisk_shuffle_proof = shuffle_proof
|
||||
body.whisk_shuffle_proof_M_commitment = m
|
||||
|
||||
|
||||
def get_and_populate_pre_shuffle_trackers(spec, state, body):
|
||||
|
@ -87,20 +86,10 @@ def test_shuffle_during_selection_gap(spec, state):
|
|||
yield from run_process_shuffled_trackers(spec, state, body, valid=False)
|
||||
|
||||
# Invalid cases on shuffle
|
||||
# - wrong m
|
||||
# - wrong proof
|
||||
# - wrong post shuffle
|
||||
|
||||
|
||||
@with_whisk_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_shuffle_bad_m(spec, state):
|
||||
body = empty_block_body(spec)
|
||||
set_correct_shuffle_proofs(spec, state, body)
|
||||
body.whisk_shuffle_proof_M_commitment = spec.BLSG1Point()
|
||||
yield from run_process_shuffled_trackers(spec, state, body, valid=False)
|
||||
|
||||
|
||||
@with_whisk_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_shuffle_bad_proof(spec, state):
|
||||
|
@ -132,21 +121,9 @@ def test_invalid_shuffle_bad_trackers_zero(spec, state):
|
|||
|
||||
# Invalid things on gap
|
||||
# - not empty shuffle trackers
|
||||
# - not empty m
|
||||
# - not empty proof
|
||||
|
||||
|
||||
@with_whisk_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_gap_non_zero_m(spec, state):
|
||||
body = empty_block_body(spec)
|
||||
body.whisk_shuffle_proof_M_commitment = spec.BLSG1Point(
|
||||
'0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
|
||||
)
|
||||
set_state_epoch_selection_gap(spec, state)
|
||||
yield from run_process_shuffled_trackers(spec, state, body, valid=False)
|
||||
|
||||
|
||||
@with_whisk_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_gap_non_zero_proof(spec, state):
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
from eth2spec.test.context import spec_state_test, with_whisk_and_later, expect_assertion_error
|
||||
from eth2spec.test.helpers.whisk import set_as_first_proposal, compute_whisk_k_commitment, set_registration
|
||||
from eth2spec.test.helpers.whisk import (
|
||||
set_as_first_proposal,
|
||||
compute_whisk_k_commitment,
|
||||
set_registration,
|
||||
register_tracker
|
||||
)
|
||||
|
||||
|
||||
def empty_block_body(spec):
|
||||
|
@ -26,10 +31,10 @@ def run_process_whisk_registration(spec, state, body, valid=True):
|
|||
|
||||
|
||||
IDENTITY_R = 1
|
||||
OTHER_R = 2
|
||||
OTHER_R = 100_000_2 # Large enough values to not collide with initial k values
|
||||
OTHER_K = 100_000_2
|
||||
PROPOSER_INDEX = 0
|
||||
OTHER_INDEX = 1
|
||||
OTHER_K = 2
|
||||
|
||||
# First proposal
|
||||
|
||||
|
@ -88,6 +93,9 @@ def test_first_proposal_invalid_proof(spec, state):
|
|||
@spec_state_test
|
||||
def test_second_proposal_ok(spec, state):
|
||||
body = empty_block_body(spec)
|
||||
# An empty body has the correct values for a second proposal
|
||||
# Set tracker to != G1 generator for second proposal condition
|
||||
register_tracker(state, PROPOSER_INDEX, OTHER_K, OTHER_R)
|
||||
yield from run_process_whisk_registration(spec, state, body)
|
||||
|
||||
|
||||
|
@ -96,4 +104,5 @@ def test_second_proposal_ok(spec, state):
|
|||
def test_second_proposal_not_zero(spec, state):
|
||||
body = empty_block_body(spec)
|
||||
set_registration(body, OTHER_K, OTHER_R)
|
||||
register_tracker(state, PROPOSER_INDEX, OTHER_K, OTHER_R)
|
||||
yield from run_process_whisk_registration(spec, state, body, valid=False)
|
||||
|
|
Loading…
Reference in New Issue