From a9cc9f4cdff567747cb6470fecf75696e7546455 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 26 Mar 2024 18:18:25 -0600 Subject: [PATCH 1/2] implement optimized index shuffling and add support in spec tests --- ethereum-consensus/src/altair/spec/mod.rs | 86 +++++++++++++++++-- ethereum-consensus/src/bellatrix/spec/mod.rs | 88 ++++++++++++++++++-- ethereum-consensus/src/capella/spec/mod.rs | 88 ++++++++++++++++++-- ethereum-consensus/src/deneb/spec/mod.rs | 88 ++++++++++++++++++-- ethereum-consensus/src/phase0/helpers.rs | 81 +++++++++++++++++- ethereum-consensus/src/phase0/spec/mod.rs | 6 +- ethereum-consensus/src/primitives.rs | 2 + spec-tests/runners/shuffling.rs | 14 +++- 8 files changed, 413 insertions(+), 40 deletions(-) diff --git a/ethereum-consensus/src/altair/spec/mod.rs b/ethereum-consensus/src/altair/spec/mod.rs index 30531f863..36035a032 100644 --- a/ethereum-consensus/src/altair/spec/mod.rs +++ b/ethereum-consensus/src/altair/spec/mod.rs @@ -1154,6 +1154,69 @@ pub fn compute_shuffled_index( } Ok(index) } +pub fn compute_shuffled_indices( + indices: &[ValidatorIndex], + seed: &Bytes32, + context: &Context, +) -> ShuffledIndices { + let mut input = indices.to_vec(); + if input.is_empty() { + return input; + } + let index_count = input.len(); + let mut pivot_input = [0u8; 33]; + pivot_input[..32].copy_from_slice(seed.as_ref()); + let mut source_input = [0u8; 37]; + source_input[..32].copy_from_slice(seed.as_ref()); + for current_round in (0..=context.shuffle_round_count - 1).rev() { + pivot_input[32] = current_round as u8; + let pivot_bytes: [u8; 8] = hash(pivot_input).as_ref()[..8].try_into().unwrap(); + let pivot = u64::from_le_bytes(pivot_bytes) as usize % index_count; + source_input[32] = current_round as u8; + let position = (pivot >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + let mut source = hash(source_input); + let mut byte_source = source[(pivot & 0xff) >> 3]; + let mirror = (pivot + 1) >> 1; + for i in 0..mirror { + let j = pivot - i; + if j & 0xff == 0xff { + let position = (j >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + } + if j & 0x07 == 0x07 { + byte_source = source[(j & 0xff) >> 3]; + } + let bit_source = (byte_source >> (j & 0x07)) & 0x01; + if bit_source == 1 { + input.swap(i, j); + } + } + let end = index_count - 1; + let position = (end >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + byte_source = source[(end & 0xff) >> 3]; + let mirror = (pivot + index_count + 1) >> 1; + for (k, i) in ((pivot + 1)..mirror).enumerate() { + let j = end - k; + if j & 0xff == 0xff { + let position = (j >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + } + if j & 0x07 == 0x07 { + byte_source = source[(j & 0xff) >> 3]; + } + let bit_source = (byte_source >> (j & 0x07)) & 0x01; + if bit_source == 1 { + input.swap(i, j); + } + } + } + input +} pub fn compute_proposer_index< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -1206,14 +1269,23 @@ pub fn compute_committee( count: usize, context: &Context, ) -> Result> { - let start = (indices.len() * index) / count; - let end = (indices.len()) * (index + 1) / count; - let mut committee = vec![0usize; end - start]; - for i in start..end { - let index = compute_shuffled_index(i, indices.len(), seed, context)?; - committee[i - start] = indices[index]; + if cfg!(feature = "shuffling") { + let index_count = indices.len(); + let shuffled_indices = compute_shuffled_indices(indices, seed, context); + let start = index_count * index / count; + let end = index_count * (index + 1) / count; + let committee = shuffled_indices[start..end].to_vec(); + Ok(committee) + } else { + let start = indices.len() * index / count; + let end = indices.len() * (index + 1) / count; + let mut committee = vec![0usize; end - start]; + for i in start..end { + let index = compute_shuffled_index(i, indices.len(), seed, context)?; + committee[i - start] = indices[index]; + } + Ok(committee) } - Ok(committee) } pub fn compute_epoch_at_slot(slot: Slot, context: &Context) -> Epoch { slot / context.slots_per_epoch diff --git a/ethereum-consensus/src/bellatrix/spec/mod.rs b/ethereum-consensus/src/bellatrix/spec/mod.rs index 719e43142..46c57ef46 100644 --- a/ethereum-consensus/src/bellatrix/spec/mod.rs +++ b/ethereum-consensus/src/bellatrix/spec/mod.rs @@ -2103,6 +2103,69 @@ pub fn compute_shuffled_index( } Ok(index) } +pub fn compute_shuffled_indices( + indices: &[ValidatorIndex], + seed: &Bytes32, + context: &Context, +) -> ShuffledIndices { + let mut input = indices.to_vec(); + if input.is_empty() { + return input; + } + let index_count = input.len(); + let mut pivot_input = [0u8; 33]; + pivot_input[..32].copy_from_slice(seed.as_ref()); + let mut source_input = [0u8; 37]; + source_input[..32].copy_from_slice(seed.as_ref()); + for current_round in (0..=context.shuffle_round_count - 1).rev() { + pivot_input[32] = current_round as u8; + let pivot_bytes: [u8; 8] = hash(pivot_input).as_ref()[..8].try_into().unwrap(); + let pivot = u64::from_le_bytes(pivot_bytes) as usize % index_count; + source_input[32] = current_round as u8; + let position = (pivot >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + let mut source = hash(source_input); + let mut byte_source = source[(pivot & 0xff) >> 3]; + let mirror = (pivot + 1) >> 1; + for i in 0..mirror { + let j = pivot - i; + if j & 0xff == 0xff { + let position = (j >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + } + if j & 0x07 == 0x07 { + byte_source = source[(j & 0xff) >> 3]; + } + let bit_source = (byte_source >> (j & 0x07)) & 0x01; + if bit_source == 1 { + input.swap(i, j); + } + } + let end = index_count - 1; + let position = (end >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + byte_source = source[(end & 0xff) >> 3]; + let mirror = (pivot + index_count + 1) >> 1; + for (k, i) in ((pivot + 1)..mirror).enumerate() { + let j = end - k; + if j & 0xff == 0xff { + let position = (j >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + } + if j & 0x07 == 0x07 { + byte_source = source[(j & 0xff) >> 3]; + } + let bit_source = (byte_source >> (j & 0x07)) & 0x01; + if bit_source == 1 { + input.swap(i, j); + } + } + } + input +} pub fn compute_proposer_index< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -2159,14 +2222,23 @@ pub fn compute_committee( count: usize, context: &Context, ) -> Result> { - let start = (indices.len() * index) / count; - let end = (indices.len()) * (index + 1) / count; - let mut committee = vec![0usize; end - start]; - for i in start..end { - let index = compute_shuffled_index(i, indices.len(), seed, context)?; - committee[i - start] = indices[index]; - } - Ok(committee) + if cfg!(feature = "shuffling") { + let index_count = indices.len(); + let shuffled_indices = compute_shuffled_indices(indices, seed, context); + let start = index_count * index / count; + let end = index_count * (index + 1) / count; + let committee = shuffled_indices[start..end].to_vec(); + Ok(committee) + } else { + let start = indices.len() * index / count; + let end = indices.len() * (index + 1) / count; + let mut committee = vec![0usize; end - start]; + for i in start..end { + let index = compute_shuffled_index(i, indices.len(), seed, context)?; + committee[i - start] = indices[index]; + } + Ok(committee) + } } pub fn compute_epoch_at_slot(slot: Slot, context: &Context) -> Epoch { slot / context.slots_per_epoch diff --git a/ethereum-consensus/src/capella/spec/mod.rs b/ethereum-consensus/src/capella/spec/mod.rs index dca142a6a..48340bb4b 100644 --- a/ethereum-consensus/src/capella/spec/mod.rs +++ b/ethereum-consensus/src/capella/spec/mod.rs @@ -2366,6 +2366,69 @@ pub fn compute_shuffled_index( } Ok(index) } +pub fn compute_shuffled_indices( + indices: &[ValidatorIndex], + seed: &Bytes32, + context: &Context, +) -> ShuffledIndices { + let mut input = indices.to_vec(); + if input.is_empty() { + return input; + } + let index_count = input.len(); + let mut pivot_input = [0u8; 33]; + pivot_input[..32].copy_from_slice(seed.as_ref()); + let mut source_input = [0u8; 37]; + source_input[..32].copy_from_slice(seed.as_ref()); + for current_round in (0..=context.shuffle_round_count - 1).rev() { + pivot_input[32] = current_round as u8; + let pivot_bytes: [u8; 8] = hash(pivot_input).as_ref()[..8].try_into().unwrap(); + let pivot = u64::from_le_bytes(pivot_bytes) as usize % index_count; + source_input[32] = current_round as u8; + let position = (pivot >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + let mut source = hash(source_input); + let mut byte_source = source[(pivot & 0xff) >> 3]; + let mirror = (pivot + 1) >> 1; + for i in 0..mirror { + let j = pivot - i; + if j & 0xff == 0xff { + let position = (j >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + } + if j & 0x07 == 0x07 { + byte_source = source[(j & 0xff) >> 3]; + } + let bit_source = (byte_source >> (j & 0x07)) & 0x01; + if bit_source == 1 { + input.swap(i, j); + } + } + let end = index_count - 1; + let position = (end >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + byte_source = source[(end & 0xff) >> 3]; + let mirror = (pivot + index_count + 1) >> 1; + for (k, i) in ((pivot + 1)..mirror).enumerate() { + let j = end - k; + if j & 0xff == 0xff { + let position = (j >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + } + if j & 0x07 == 0x07 { + byte_source = source[(j & 0xff) >> 3]; + } + let bit_source = (byte_source >> (j & 0x07)) & 0x01; + if bit_source == 1 { + input.swap(i, j); + } + } + } + input +} pub fn compute_proposer_index< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -2422,14 +2485,23 @@ pub fn compute_committee( count: usize, context: &Context, ) -> Result> { - let start = (indices.len() * index) / count; - let end = (indices.len()) * (index + 1) / count; - let mut committee = vec![0usize; end - start]; - for i in start..end { - let index = compute_shuffled_index(i, indices.len(), seed, context)?; - committee[i - start] = indices[index]; - } - Ok(committee) + if cfg!(feature = "shuffling") { + let index_count = indices.len(); + let shuffled_indices = compute_shuffled_indices(indices, seed, context); + let start = index_count * index / count; + let end = index_count * (index + 1) / count; + let committee = shuffled_indices[start..end].to_vec(); + Ok(committee) + } else { + let start = indices.len() * index / count; + let end = indices.len() * (index + 1) / count; + let mut committee = vec![0usize; end - start]; + for i in start..end { + let index = compute_shuffled_index(i, indices.len(), seed, context)?; + committee[i - start] = indices[index]; + } + Ok(committee) + } } pub fn compute_epoch_at_slot(slot: Slot, context: &Context) -> Epoch { slot / context.slots_per_epoch diff --git a/ethereum-consensus/src/deneb/spec/mod.rs b/ethereum-consensus/src/deneb/spec/mod.rs index 1c080cfb1..d29237512 100644 --- a/ethereum-consensus/src/deneb/spec/mod.rs +++ b/ethereum-consensus/src/deneb/spec/mod.rs @@ -2437,6 +2437,69 @@ pub fn compute_shuffled_index( } Ok(index) } +pub fn compute_shuffled_indices( + indices: &[ValidatorIndex], + seed: &Bytes32, + context: &Context, +) -> ShuffledIndices { + let mut input = indices.to_vec(); + if input.is_empty() { + return input; + } + let index_count = input.len(); + let mut pivot_input = [0u8; 33]; + pivot_input[..32].copy_from_slice(seed.as_ref()); + let mut source_input = [0u8; 37]; + source_input[..32].copy_from_slice(seed.as_ref()); + for current_round in (0..=context.shuffle_round_count - 1).rev() { + pivot_input[32] = current_round as u8; + let pivot_bytes: [u8; 8] = hash(pivot_input).as_ref()[..8].try_into().unwrap(); + let pivot = u64::from_le_bytes(pivot_bytes) as usize % index_count; + source_input[32] = current_round as u8; + let position = (pivot >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + let mut source = hash(source_input); + let mut byte_source = source[(pivot & 0xff) >> 3]; + let mirror = (pivot + 1) >> 1; + for i in 0..mirror { + let j = pivot - i; + if j & 0xff == 0xff { + let position = (j >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + } + if j & 0x07 == 0x07 { + byte_source = source[(j & 0xff) >> 3]; + } + let bit_source = (byte_source >> (j & 0x07)) & 0x01; + if bit_source == 1 { + input.swap(i, j); + } + } + let end = index_count - 1; + let position = (end >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + byte_source = source[(end & 0xff) >> 3]; + let mirror = (pivot + index_count + 1) >> 1; + for (k, i) in ((pivot + 1)..mirror).enumerate() { + let j = end - k; + if j & 0xff == 0xff { + let position = (j >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + } + if j & 0x07 == 0x07 { + byte_source = source[(j & 0xff) >> 3]; + } + let bit_source = (byte_source >> (j & 0x07)) & 0x01; + if bit_source == 1 { + input.swap(i, j); + } + } + } + input +} pub fn compute_proposer_index< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -2493,14 +2556,23 @@ pub fn compute_committee( count: usize, context: &Context, ) -> Result> { - let start = (indices.len() * index) / count; - let end = (indices.len()) * (index + 1) / count; - let mut committee = vec![0usize; end - start]; - for i in start..end { - let index = compute_shuffled_index(i, indices.len(), seed, context)?; - committee[i - start] = indices[index]; - } - Ok(committee) + if cfg!(feature = "shuffling") { + let index_count = indices.len(); + let shuffled_indices = compute_shuffled_indices(indices, seed, context); + let start = index_count * index / count; + let end = index_count * (index + 1) / count; + let committee = shuffled_indices[start..end].to_vec(); + Ok(committee) + } else { + let start = indices.len() * index / count; + let end = indices.len() * (index + 1) / count; + let mut committee = vec![0usize; end - start]; + for i in start..end { + let index = compute_shuffled_index(i, indices.len(), seed, context)?; + committee[i - start] = indices[index]; + } + Ok(committee) + } } pub fn compute_epoch_at_slot(slot: Slot, context: &Context) -> Epoch { slot / context.slots_per_epoch diff --git a/ethereum-consensus/src/phase0/helpers.rs b/ethereum-consensus/src/phase0/helpers.rs index 0bb7c9a51..54244f1b7 100644 --- a/ethereum-consensus/src/phase0/helpers.rs +++ b/ethereum-consensus/src/phase0/helpers.rs @@ -10,8 +10,8 @@ use crate::{ validator::Validator, }, primitives::{ - Bytes32, CommitteeIndex, Domain, DomainType, Epoch, ForkDigest, Gwei, Root, Slot, - ValidatorIndex, Version, FAR_FUTURE_EPOCH, GENESIS_EPOCH, + Bytes32, CommitteeIndex, Domain, DomainType, Epoch, ForkDigest, Gwei, Root, + ShuffledIndices, Slot, ValidatorIndex, Version, FAR_FUTURE_EPOCH, GENESIS_EPOCH, }, signing::compute_signing_root, ssz::prelude::*, @@ -283,6 +283,83 @@ pub fn compute_shuffled_index( Ok(index) } +// Compute the consensus shuffling across an entire list of `indices`. +// NOTE: cribbed from `lighthouse` implementation +pub fn compute_shuffled_indices( + indices: &[ValidatorIndex], + seed: &Bytes32, + context: &Context, +) -> ShuffledIndices { + let mut input = indices.to_vec(); + if input.is_empty() { + return input + } + + let index_count = input.len(); + + let mut pivot_input = [0u8; 33]; + pivot_input[..32].copy_from_slice(seed.as_ref()); + + let mut source_input = [0u8; 37]; + source_input[..32].copy_from_slice(seed.as_ref()); + + for current_round in (0..=context.shuffle_round_count - 1).rev() { + pivot_input[32] = current_round as u8; + let pivot_bytes: [u8; 8] = hash(pivot_input).as_ref()[..8].try_into().unwrap(); + let pivot = u64::from_le_bytes(pivot_bytes) as usize % index_count; + source_input[32] = current_round as u8; + + let position = (pivot >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + let mut source = hash(source_input); + + let mut byte_source = source[(pivot & 0xff) >> 3]; + + let mirror = (pivot + 1) >> 1; + for i in 0..mirror { + let j = pivot - i; + if j & 0xff == 0xff { + let position = (j >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + } + if j & 0x07 == 0x07 { + byte_source = source[(j & 0xff) >> 3]; + } + let bit_source = (byte_source >> (j & 0x07)) & 0x01; + + if bit_source == 1 { + input.swap(i, j); + } + } + + let end = index_count - 1; + let position = (end >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + byte_source = source[(end & 0xff) >> 3]; + + let mirror = (pivot + index_count + 1) >> 1; + for (k, i) in ((pivot + 1)..mirror).enumerate() { + let j = end - k; + if j & 0xff == 0xff { + let position = (j >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + } + if j & 0x07 == 0x07 { + byte_source = source[(j & 0xff) >> 3]; + } + let bit_source = (byte_source >> (j & 0x07)) & 0x01; + + if bit_source == 1 { + input.swap(i, j); + } + } + } + input +} + pub fn compute_proposer_index< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, diff --git a/ethereum-consensus/src/phase0/spec/mod.rs b/ethereum-consensus/src/phase0/spec/mod.rs index c76d15268..a9b92e634 100644 --- a/ethereum-consensus/src/phase0/spec/mod.rs +++ b/ethereum-consensus/src/phase0/spec/mod.rs @@ -34,9 +34,9 @@ pub use crate::{ helpers::{ compute_activation_exit_epoch, compute_committee, compute_domain, compute_epoch_at_slot, compute_fork_data_root, compute_fork_digest, - compute_proposer_index, compute_shuffled_index, compute_start_slot_at_epoch, - decrease_balance, get_active_validator_indices, get_attesting_indices, - get_beacon_committee, get_beacon_proposer_index, get_block_root, + compute_proposer_index, compute_shuffled_index, compute_shuffled_indices, + compute_start_slot_at_epoch, decrease_balance, get_active_validator_indices, + get_attesting_indices, get_beacon_committee, get_beacon_proposer_index, get_block_root, get_block_root_at_slot, get_committee_count_per_slot, get_current_epoch, get_domain, get_eligible_validator_indices, get_indexed_attestation, get_previous_epoch, get_randao_mix, get_seed, get_total_active_balance, get_total_balance, diff --git a/ethereum-consensus/src/primitives.rs b/ethereum-consensus/src/primitives.rs index 818f3d6d1..69593dec7 100644 --- a/ethereum-consensus/src/primitives.rs +++ b/ethereum-consensus/src/primitives.rs @@ -30,6 +30,8 @@ pub type Bytes32 = ByteVector<32>; pub type ParticipationFlags = u8; +pub type ShuffledIndices = Vec; + // Coordinate refers to a unique location in the block tree #[derive(serde::Serialize, serde::Deserialize)] pub struct Coordinate { diff --git a/spec-tests/runners/shuffling.rs b/spec-tests/runners/shuffling.rs index a463193c3..a4a1aef90 100644 --- a/spec-tests/runners/shuffling.rs +++ b/spec-tests/runners/shuffling.rs @@ -30,10 +30,16 @@ pub fn dispatch(test: &TestCase) -> Result<(), Error> { test, load_test, |data: ShufflingTestData, context| { - for index in 0..data.count { - let result = spec::compute_shuffled_index(index, data.count, &data.seed, context).unwrap(); - assert_eq!(result, data.mapping[index]); - } + // test `compute_shuffled_index`, following the spec which goes index by index + let result = (0..data.count).into_iter().map(|index| { + spec::compute_shuffled_index(index, data.count, &data.seed, context).unwrap() + }).collect::>(); + assert_eq!(result, data.mapping); + + // test `compute_shuffled_indices`, an optimization that shuffles the entire list at once + let indices = (0..data.count).collect::>(); + let shuffled_indices = spec::compute_shuffled_indices(&indices, &data.seed, context); + assert_eq!(shuffled_indices, data.mapping); Ok(()) } } From 60f09ff8e0fcd7c350d9113f9a36a1e4cc7287b4 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 26 Mar 2024 18:59:38 -0600 Subject: [PATCH 2/2] use optimized shuffling in `compute_committee` and add feature flag --- ethereum-consensus/Cargo.toml | 2 ++ ethereum-consensus/src/altair/spec/mod.rs | 2 +- ethereum-consensus/src/bellatrix/spec/mod.rs | 2 +- ethereum-consensus/src/capella/spec/mod.rs | 2 +- ethereum-consensus/src/deneb/spec/mod.rs | 2 +- ethereum-consensus/src/phase0/helpers.rs | 23 ++++++++++++++------ 6 files changed, 22 insertions(+), 11 deletions(-) diff --git a/ethereum-consensus/Cargo.toml b/ethereum-consensus/Cargo.toml index 085638967..1438c071a 100644 --- a/ethereum-consensus/Cargo.toml +++ b/ethereum-consensus/Cargo.toml @@ -9,6 +9,8 @@ license = "MIT OR Apache-2.0" default = ["serde", "async"] serde = ["hex", "serde_json", "serde_yaml"] async = ["tokio", "tokio-stream", "async-stream"] +optimized = ["shuffling"] +shuffling = [] # supports optimized shuffling routines secret-key-debug = [ ] # enable if you want to be able to print `crypto::SecretKey` spec-tests = [] # enable extra features for testing diff --git a/ethereum-consensus/src/altair/spec/mod.rs b/ethereum-consensus/src/altair/spec/mod.rs index 36035a032..3b47be766 100644 --- a/ethereum-consensus/src/altair/spec/mod.rs +++ b/ethereum-consensus/src/altair/spec/mod.rs @@ -1270,8 +1270,8 @@ pub fn compute_committee( context: &Context, ) -> Result> { if cfg!(feature = "shuffling") { - let index_count = indices.len(); let shuffled_indices = compute_shuffled_indices(indices, seed, context); + let index_count = indices.len(); let start = index_count * index / count; let end = index_count * (index + 1) / count; let committee = shuffled_indices[start..end].to_vec(); diff --git a/ethereum-consensus/src/bellatrix/spec/mod.rs b/ethereum-consensus/src/bellatrix/spec/mod.rs index 46c57ef46..5f1b724d7 100644 --- a/ethereum-consensus/src/bellatrix/spec/mod.rs +++ b/ethereum-consensus/src/bellatrix/spec/mod.rs @@ -2223,8 +2223,8 @@ pub fn compute_committee( context: &Context, ) -> Result> { if cfg!(feature = "shuffling") { - let index_count = indices.len(); let shuffled_indices = compute_shuffled_indices(indices, seed, context); + let index_count = indices.len(); let start = index_count * index / count; let end = index_count * (index + 1) / count; let committee = shuffled_indices[start..end].to_vec(); diff --git a/ethereum-consensus/src/capella/spec/mod.rs b/ethereum-consensus/src/capella/spec/mod.rs index 48340bb4b..b1a5aa9ca 100644 --- a/ethereum-consensus/src/capella/spec/mod.rs +++ b/ethereum-consensus/src/capella/spec/mod.rs @@ -2486,8 +2486,8 @@ pub fn compute_committee( context: &Context, ) -> Result> { if cfg!(feature = "shuffling") { - let index_count = indices.len(); let shuffled_indices = compute_shuffled_indices(indices, seed, context); + let index_count = indices.len(); let start = index_count * index / count; let end = index_count * (index + 1) / count; let committee = shuffled_indices[start..end].to_vec(); diff --git a/ethereum-consensus/src/deneb/spec/mod.rs b/ethereum-consensus/src/deneb/spec/mod.rs index d29237512..c993cce7e 100644 --- a/ethereum-consensus/src/deneb/spec/mod.rs +++ b/ethereum-consensus/src/deneb/spec/mod.rs @@ -2557,8 +2557,8 @@ pub fn compute_committee( context: &Context, ) -> Result> { if cfg!(feature = "shuffling") { - let index_count = indices.len(); let shuffled_indices = compute_shuffled_indices(indices, seed, context); + let index_count = indices.len(); let start = index_count * index / count; let end = index_count * (index + 1) / count; let committee = shuffled_indices[start..end].to_vec(); diff --git a/ethereum-consensus/src/phase0/helpers.rs b/ethereum-consensus/src/phase0/helpers.rs index 54244f1b7..57f7ac7b3 100644 --- a/ethereum-consensus/src/phase0/helpers.rs +++ b/ethereum-consensus/src/phase0/helpers.rs @@ -416,14 +416,23 @@ pub fn compute_committee( count: usize, context: &Context, ) -> Result> { - let start = (indices.len() * index) / count; - let end = (indices.len()) * (index + 1) / count; - let mut committee = vec![0usize; end - start]; - for i in start..end { - let index = compute_shuffled_index(i, indices.len(), seed, context)?; - committee[i - start] = indices[index]; + if cfg!(feature = "shuffling") { + let shuffled_indices = compute_shuffled_indices(indices, seed, context); + let index_count = indices.len(); + let start = index_count * index / count; + let end = index_count * (index + 1) / count; + let committee = shuffled_indices[start..end].to_vec(); + Ok(committee) + } else { + let start = indices.len() * index / count; + let end = indices.len() * (index + 1) / count; + let mut committee = vec![0usize; end - start]; + for i in start..end { + let index = compute_shuffled_index(i, indices.len(), seed, context)?; + committee[i - start] = indices[index]; + } + Ok(committee) } - Ok(committee) } pub fn compute_epoch_at_slot(slot: Slot, context: &Context) -> Epoch {