From 2a32e7f6653959da1f21e2812426cb9d87baf24a Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Sat, 2 Feb 2019 16:41:59 -0800 Subject: [PATCH 01/16] convert int_to_bytes to little endian --- specs/core/0_beacon-chain.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index caaac363f..f67afd8a6 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -710,8 +710,8 @@ def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: if remaining == 1: break - # Read 3-bytes of `source` as a 24-bit big-endian integer. - sample_from_source = int.from_bytes(source[position:position + rand_bytes], 'big') + # Read 3-bytes of `source` as a 24-bit little-endian integer. + sample_from_source = int.from_bytes(source[position:position + rand_bytes], 'little') # Sample values greater than or equal to `sample_max` will cause # modulo bias when mapped into the `remaining` range. @@ -1015,7 +1015,7 @@ def is_power_of_two(value: int) -> bool: ### `int_to_bytes1`, `int_to_bytes2`, ... -`int_to_bytes1(x): return x.to_bytes(1, 'big')`, `int_to_bytes2(x): return x.to_bytes(2, 'big')`, and so on for all integers, particularly 1, 2, 3, 4, 8, 32, 48, 96. +`int_to_bytes1(x): return x.to_bytes(1, 'little')`, `int_to_bytes2(x): return x.to_bytes(2, 'little')`, and so on for all integers, particularly 1, 2, 3, 4, 8, 32, 48, 96. ### `get_effective_balance` From c58410e6ce9904c6619cd925b64fbd04c00b9a89 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Wed, 6 Feb 2019 06:48:46 -0600 Subject: [PATCH 02/16] Introduce swap-or-not shuffle See #563 for discussion. --- specs/core/0_beacon-chain.md | 61 +++++++++--------------------------- 1 file changed, 15 insertions(+), 46 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 44b88d126..3cb1b459f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -697,53 +697,22 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber ```python def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: - """ - Return the shuffled ``values`` with ``seed`` as entropy. - """ - values_count = len(values) + indices = list(range(len(values))) + for round in range(90): + hashvalues = b''.join([ + hash(seed + round.to_bytes(1, 'big') + i.to_bytes(4, 'big')) + for i in range((n + 255) // 256) + ]) + pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'big')), 'big') % n + + def permute(pos): + flip = (pivot - pos) % n + maxpos = max(pos, flip) + bit = (hashvalues[maxpos // 8] >> (maxpos % 8)) % 2 + return flip if bit else pos - # Entropy is consumed from the seed in 3-byte (24 bit) chunks. - rand_bytes = 3 - # The highest possible result of the RNG. - rand_max = 2 ** (rand_bytes * 8) - 1 - - # The range of the RNG places an upper-bound on the size of the list that - # may be shuffled. It is a logic error to supply an oversized list. - assert values_count < rand_max - - output = [x for x in values] - source = seed - index = 0 - while index < values_count - 1: - # Re-hash the `source` to obtain a new pattern of bytes. - source = hash(source) - # Iterate through the `source` bytes in 3-byte chunks. - for position in range(0, 32 - (32 % rand_bytes), rand_bytes): - # Determine the number of indices remaining in `values` and exit - # once the last index is reached. - remaining = values_count - index - if remaining == 1: - break - - # Read 3-bytes of `source` as a 24-bit big-endian integer. - sample_from_source = int.from_bytes(source[position:position + rand_bytes], 'big') - - # Sample values greater than or equal to `sample_max` will cause - # modulo bias when mapped into the `remaining` range. - sample_max = rand_max - rand_max % remaining - - # Perform a swap if the consumed entropy will not cause modulo bias. - if sample_from_source < sample_max: - # Select a replacement index for the current index. - replacement_position = (sample_from_source % remaining) + index - # Swap the current index with the replacement index. - output[index], output[replacement_position] = output[replacement_position], output[index] - index += 1 - else: - # The sample causes modulo bias. A new sample should be read. - pass - - return output + indices = [permute(v) for v in indices] + return [v[index] for index in indices] ``` ### `split` From 37b41a2ce645b644a56c473cba2ded3a49689139 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 6 Feb 2019 18:33:11 -0600 Subject: [PATCH 03/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 1 - 1 file changed, 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 3cb1b459f..5471d76a1 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -704,7 +704,6 @@ def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: for i in range((n + 255) // 256) ]) pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'big')), 'big') % n - def permute(pos): flip = (pivot - pos) % n maxpos = max(pos, flip) From 4ec721f3b7d4459c3db601d9a3bd53511a1dfd31 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 6 Feb 2019 18:33:22 -0600 Subject: [PATCH 04/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 5471d76a1..2e453b061 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -697,6 +697,13 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber ```python def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: + """ + Return the shuffled ``values`` with ``seed`` as entropy. + + Utilizes 'swap or not' shuffling found in + https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf + See the 'generalized domain' algorithm on page 3. + """ indices = list(range(len(values))) for round in range(90): hashvalues = b''.join([ From 6a5b7540da501c976d1e0ec76b44725bb96f7f37 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 6 Feb 2019 18:33:29 -0600 Subject: [PATCH 05/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 2e453b061..1426bb4e8 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -718,7 +718,7 @@ def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: return flip if bit else pos indices = [permute(v) for v in indices] - return [v[index] for index in indices] + return [values[index] for index in indices] ``` ### `split` From 47b00f38dda4336ada69b166f8f288b840c628d3 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Wed, 6 Feb 2019 18:34:05 -0600 Subject: [PATCH 06/16] n -> len(values) --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 1426bb4e8..60bacba63 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -708,7 +708,7 @@ def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: for round in range(90): hashvalues = b''.join([ hash(seed + round.to_bytes(1, 'big') + i.to_bytes(4, 'big')) - for i in range((n + 255) // 256) + for i in range((len(values) + 255) // 256) ]) pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'big')), 'big') % n def permute(pos): From b3db7b03942d2c666952fb94fe01774d15089105 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 6 Feb 2019 20:32:05 -0800 Subject: [PATCH 07/16] big to little in shuffle --- specs/core/0_beacon-chain.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 60bacba63..641ad02ca 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -707,10 +707,10 @@ def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: indices = list(range(len(values))) for round in range(90): hashvalues = b''.join([ - hash(seed + round.to_bytes(1, 'big') + i.to_bytes(4, 'big')) + hash(seed + round.to_bytes(1, 'little') + i.to_bytes(4, 'little')) for i in range((len(values) + 255) // 256) ]) - pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'big')), 'big') % n + pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'little')), 'little') % n def permute(pos): flip = (pivot - pos) % n maxpos = max(pos, flip) From 65255e53c46ac8d2ee520f2845e9869193ae783c Mon Sep 17 00:00:00 2001 From: vbuterin Date: Wed, 6 Feb 2019 23:29:24 -0600 Subject: [PATCH 08/16] shuffle -> get_permuted_index --- specs/core/0_beacon-chain.md | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 641ad02ca..dd58482b3 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -59,7 +59,7 @@ - [`get_epoch_start_slot`](#get_epoch_start_slot) - [`is_active_validator`](#is_active_validator) - [`get_active_validator_indices`](#get_active_validator_indices) - - [`shuffle`](#shuffle) + - [`get_permuted_index`](#get_permuted_index) - [`split`](#split) - [`get_epoch_committee_count`](#get_epoch_committee_count) - [`get_shuffling`](#get_shuffling) @@ -693,32 +693,27 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber return [i for i, v in enumerate(validators) if is_active_validator(v, epoch)] ``` -### `shuffle` +### `get_permuted_index` ```python -def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: +def get_permuted_index(index: int, list_size: int, seed: Bytes32) -> int: """ - Return the shuffled ``values`` with ``seed`` as entropy. + Return a pseudorandom permutation of `0...list_size-1` with ``seed`` as entropy. Utilizes 'swap or not' shuffling found in https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf See the 'generalized domain' algorithm on page 3. """ - indices = list(range(len(values))) for round in range(90): - hashvalues = b''.join([ - hash(seed + round.to_bytes(1, 'little') + i.to_bytes(4, 'little')) - for i in range((len(values) + 255) // 256) - ]) - pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'little')), 'little') % n - def permute(pos): - flip = (pivot - pos) % n - maxpos = max(pos, flip) - bit = (hashvalues[maxpos // 8] >> (maxpos % 8)) % 2 - return flip if bit else pos - - indices = [permute(v) for v in indices] - return [values[index] for index in indices] + pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'little')), 'little') % list_size + + flip = (pivot - index) % list_size + hash_pos = max(index, flip) + h = hash(seed + round.to_bytes(1, 'little') + (hash_pos // 256).to_bytes(4, 'little')) + byte = h[(hash_pos % 256) // 8] + bit = (byte >> (hash_pos % 8)) % 2 + index = flip if bit else index + return index ``` ### `split` @@ -768,7 +763,10 @@ def get_shuffling(seed: Bytes32, committees_per_epoch = get_epoch_committee_count(len(active_validator_indices)) # Shuffle - shuffled_active_validator_indices = shuffle(active_validator_indices, seed) + shuffled_active_validator_indices = [ + active_validator_indices[get_permuted_index(i, len(active_validator_indices), seed)] + for i in active_validator_indices + ] # Split the shuffled list into committees_per_epoch pieces return split(shuffled_active_validator_indices, committees_per_epoch) From 92514716fb77de05637a560ec3f62a0ed5209dc6 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Wed, 6 Feb 2019 23:32:20 -0600 Subject: [PATCH 09/16] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index dd58482b3..2c0fce8c5 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -698,7 +698,7 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber ```python def get_permuted_index(index: int, list_size: int, seed: Bytes32) -> int: """ - Return a pseudorandom permutation of `0...list_size-1` with ``seed`` as entropy. + Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy. Utilizes 'swap or not' shuffling found in https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf From 70e482be28a10ca0d37de34fb3a0b5cd94108ad3 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 7 Feb 2019 19:14:58 +0800 Subject: [PATCH 10/16] Add vbuterin's optimization and some formatting --- specs/core/0_beacon-chain.md | 44 +++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 2c0fce8c5..3da520300 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -59,7 +59,7 @@ - [`get_epoch_start_slot`](#get_epoch_start_slot) - [`is_active_validator`](#is_active_validator) - [`get_active_validator_indices`](#get_active_validator_indices) - - [`get_permuted_index`](#get_permuted_index) + - [`shuffle`](#shuffle) - [`split`](#split) - [`get_epoch_committee_count`](#get_epoch_committee_count) - [`get_shuffling`](#get_shuffling) @@ -693,27 +693,38 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber return [i for i, v in enumerate(validators) if is_active_validator(v, epoch)] ``` -### `get_permuted_index` +### `shuffle` ```python -def get_permuted_index(index: int, list_size: int, seed: Bytes32) -> int: +def shuffle(list_size: int, seed: Bytes32) -> List[int]: """ - Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy. - + Return shuffled indices in a pseudorandom permutation `0...list_size-1` with ``seed`` as entropy. + Utilizes 'swap or not' shuffling found in https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf See the 'generalized domain' algorithm on page 3. """ + indices = list(range(list_size)) + power_of_two_numbers = [1, 2, 4, 8, 16, 32, 64, 128] for round in range(90): - pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'little')), 'little') % list_size - - flip = (pivot - index) % list_size - hash_pos = max(index, flip) - h = hash(seed + round.to_bytes(1, 'little') + (hash_pos // 256).to_bytes(4, 'little')) - byte = h[(hash_pos % 256) // 8] - bit = (byte >> (hash_pos % 8)) % 2 - index = flip if bit else index - return index + hash_bytes = b''.join([ + hash(seed + int_to_bytes1(round) + int_to_bytes4(i)) + for i in range((list_size + 255) // 256) + ]) + + pivot = int.from_bytes(hash(seed + int_to_bytes1(round)), 'little') % list_size + for i in range(list_size): + flip = (pivot - indices[i]) % list_size + hash_position = indices[i] if indices[i] > flip else flip + byte = hash_bytes[hash_position // 8] + mask = power_of_two_numbers[hash_position % 8] + if byte & mask: + indices[i] = flip + else: + # not swap + pass + + return indices ``` ### `split` @@ -763,9 +774,10 @@ def get_shuffling(seed: Bytes32, committees_per_epoch = get_epoch_committee_count(len(active_validator_indices)) # Shuffle + shuffled_indices = shuffle(len(active_validator_indices), seed) shuffled_active_validator_indices = [ - active_validator_indices[get_permuted_index(i, len(active_validator_indices), seed)] - for i in active_validator_indices + active_validator_indices[i] + for i in shuffle(len(active_validator_indices), seed) ] # Split the shuffled list into committees_per_epoch pieces From aa9f9fc9be337ad072e855e5a4132735eea7636b Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 7 Feb 2019 19:18:39 +0800 Subject: [PATCH 11/16] amend --- specs/core/0_beacon-chain.md | 1 - 1 file changed, 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 3da520300..6a4ac6ce5 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -774,7 +774,6 @@ def get_shuffling(seed: Bytes32, committees_per_epoch = get_epoch_committee_count(len(active_validator_indices)) # Shuffle - shuffled_indices = shuffle(len(active_validator_indices), seed) shuffled_active_validator_indices = [ active_validator_indices[i] for i in shuffle(len(active_validator_indices), seed) From 859bf6248467eb8f5a23c28ac721f605185ccfaf Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 8 Feb 2019 05:08:25 +0800 Subject: [PATCH 12/16] Revert and refactor --- specs/core/0_beacon-chain.md | 41 ++++++++++++++---------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 6a4ac6ce5..38d233b23 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -59,7 +59,7 @@ - [`get_epoch_start_slot`](#get_epoch_start_slot) - [`is_active_validator`](#is_active_validator) - [`get_active_validator_indices`](#get_active_validator_indices) - - [`shuffle`](#shuffle) + - [`get_permuted_index`](#get_permuted_index) - [`split`](#split) - [`get_epoch_committee_count`](#get_epoch_committee_count) - [`get_shuffling`](#get_shuffling) @@ -693,38 +693,29 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber return [i for i, v in enumerate(validators) if is_active_validator(v, epoch)] ``` -### `shuffle` +### `get_permuted_index` ```python -def shuffle(list_size: int, seed: Bytes32) -> List[int]: +def get_permuted_index(index: int, list_size: int, seed: Bytes32, round_count: int=90) -> List[int]: """ - Return shuffled indices in a pseudorandom permutation `0...list_size-1` with ``seed`` as entropy. + Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy. + + Note that ``round_count`` is ``90`` in protocol and parameterized for the shuffling tests. Utilizes 'swap or not' shuffling found in https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf See the 'generalized domain' algorithm on page 3. """ - indices = list(range(list_size)) - power_of_two_numbers = [1, 2, 4, 8, 16, 32, 64, 128] - for round in range(90): - hash_bytes = b''.join([ - hash(seed + int_to_bytes1(round) + int_to_bytes4(i)) - for i in range((list_size + 255) // 256) - ]) - + for round in range(round_count): pivot = int.from_bytes(hash(seed + int_to_bytes1(round)), 'little') % list_size - for i in range(list_size): - flip = (pivot - indices[i]) % list_size - hash_position = indices[i] if indices[i] > flip else flip - byte = hash_bytes[hash_position // 8] - mask = power_of_two_numbers[hash_position % 8] - if byte & mask: - indices[i] = flip - else: - # not swap - pass + flip = (pivot - index) % list_size + position = max(index, flip) + source = hash(seed + int_to_bytes1(round) + int_to_bytes4(position // 256)) + byte = source[(position % 256) // 8] + bit = (byte >> (position % 8)) % 2 + index = flip if bit else index - return indices + return index ``` ### `split` @@ -775,8 +766,8 @@ def get_shuffling(seed: Bytes32, # Shuffle shuffled_active_validator_indices = [ - active_validator_indices[i] - for i in shuffle(len(active_validator_indices), seed) + active_validator_indices[get_permuted_index(i, len(active_validator_indices), seed)] + for i in active_validator_indices ] # Split the shuffled list into committees_per_epoch pieces From 911e4f104bde97f4361e78c7e14c9d09d6c6b5da Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 8 Feb 2019 05:12:58 +0800 Subject: [PATCH 13/16] Add `bytes_to_int` --- specs/core/0_beacon-chain.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 38d233b23..c7103b79e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -76,6 +76,7 @@ - [`get_attestation_participants`](#get_attestation_participants) - [`is_power_of_two`](#is_power_of_two) - [`int_to_bytes1`, `int_to_bytes2`, ...](#int_to_bytes1-int_to_bytes2-) + - [`bytes_to_int`](#bytes_to_int) - [`get_effective_balance`](#get_effective_balance) - [`get_total_balance`](#get_total_balance) - [`get_fork_version`](#get_fork_version) @@ -707,7 +708,7 @@ def get_permuted_index(index: int, list_size: int, seed: Bytes32, round_count: i See the 'generalized domain' algorithm on page 3. """ for round in range(round_count): - pivot = int.from_bytes(hash(seed + int_to_bytes1(round)), 'little') % list_size + pivot = bytes_to_int(hash(seed + int_to_bytes1(round))) % list_size flip = (pivot - index) % list_size position = max(index, flip) source = hash(seed + int_to_bytes1(round) + int_to_bytes4(position // 256)) @@ -1007,6 +1008,13 @@ def is_power_of_two(value: int) -> bool: `int_to_bytes1(x): return x.to_bytes(1, 'big')`, `int_to_bytes2(x): return x.to_bytes(2, 'big')`, and so on for all integers, particularly 1, 2, 3, 4, 8, 32, 48, 96. +### `bytes_to_int` + +```python +def bytes_to_int(data: bytes) -> int: + return int.from_bytes(data, 'little') +``` + ### `get_effective_balance` ```python From 89b9894328b6a2060c3fbe61d2079ac400ca1208 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 8 Feb 2019 05:15:42 +0800 Subject: [PATCH 14/16] Fix type hinting --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index c7103b79e..7167b93a6 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -697,7 +697,7 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber ### `get_permuted_index` ```python -def get_permuted_index(index: int, list_size: int, seed: Bytes32, round_count: int=90) -> List[int]: +def get_permuted_index(index: int, list_size: int, seed: Bytes32, round_count: int=90) -> int: """ Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy. From f797826ee29767ef3133a97ec1f28d347553ede7 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 7 Feb 2019 21:51:56 -0600 Subject: [PATCH 15/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 7167b93a6..50daad513 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -708,7 +708,7 @@ def get_permuted_index(index: int, list_size: int, seed: Bytes32, round_count: i See the 'generalized domain' algorithm on page 3. """ for round in range(round_count): - pivot = bytes_to_int(hash(seed + int_to_bytes1(round))) % list_size + pivot = bytes_to_int(hash(seed + int_to_bytes1(round))[0:8]) % list_size flip = (pivot - index) % list_size position = max(index, flip) source = hash(seed + int_to_bytes1(round) + int_to_bytes4(position // 256)) From 1c6ccac8fc1f02079f49bf9fd715b64764c304e0 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 7 Feb 2019 21:55:33 -0600 Subject: [PATCH 16/16] SHUFFLE_ROUND_COUNT as global constant --- specs/core/0_beacon-chain.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 50daad513..a7a21683c 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -185,6 +185,7 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be | `BEACON_CHAIN_SHARD_NUMBER` | `2**64 - 1` | - | | `MAX_INDICES_PER_SLASHABLE_VOTE` | `2**12` (= 4,096) | votes | | `MAX_WITHDRAWALS_PER_EPOCH` | `2**2` (= 4) | withdrawals | +| `SHUFFLE_ROUND_COUNT` | 90 | - | * For the safety of crosslinks `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `EPOCH_LENGTH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) @@ -697,17 +698,15 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber ### `get_permuted_index` ```python -def get_permuted_index(index: int, list_size: int, seed: Bytes32, round_count: int=90) -> int: +def get_permuted_index(index: int, list_size: int, seed: Bytes32) -> int: """ Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy. - Note that ``round_count`` is ``90`` in protocol and parameterized for the shuffling tests. - Utilizes 'swap or not' shuffling found in https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf See the 'generalized domain' algorithm on page 3. """ - for round in range(round_count): + for round in range(SHUFFLE_ROUND_COUNT): pivot = bytes_to_int(hash(seed + int_to_bytes1(round))[0:8]) % list_size flip = (pivot - index) % list_size position = max(index, flip)