use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha20Rng;
use sha2::{Sha256, *};
use std::collections::HashMap;
pub trait Shuffle<T> {
fn fastrand_shuffle(&mut self);
fn fastrand_shuffle_from_seed(&mut self, seed: Vec<u8>);
fn modern_shuffle(&mut self) -> Vec<T>;
fn modern_shuffle_from_seed(&mut self, seed: Vec<u8>) -> Vec<T>;
fn crypto_modern_shuffle(&mut self) -> Vec<T>;
fn crypto_modern_shuffle_from_seed(&mut self, seed: Vec<u8>) -> Vec<T>;
fn predictive_shuffle(&mut self, positions: Vec<usize>) -> HashMap<usize, usize>;
fn predictive_shuffle_from_seed(
&mut self,
positions: Vec<usize>,
seed: Vec<u8>,
) -> HashMap<usize, usize>;
fn crypto_predictive_shuffle(&mut self, positions: Vec<usize>) -> HashMap<usize, usize>;
fn crypto_predictive_shuffle_from_seed(
&mut self,
positions: Vec<usize>,
seed: Vec<u8>,
) -> HashMap<usize, usize>;
fn batch_predictive_shuffle(
&mut self,
batch: usize,
positions: Vec<usize>,
) -> HashMap<usize, usize>;
fn batch_predictive_shuffle_from_seed(
&mut self,
batch: usize,
positions: Vec<usize>,
seed: Vec<u8>,
) -> HashMap<usize, usize>;
fn crypto_batch_predictive_shuffle(
&mut self,
batch: usize,
positions: Vec<usize>,
) -> HashMap<usize, usize>;
fn crypto_batch_predictive_shuffle_from_seed(
&mut self,
batch: usize,
positions: Vec<usize>,
seed: Vec<u8>,
) -> HashMap<usize, usize>;
}
impl<T> Shuffle<T> for Vec<T> {
fn fastrand_shuffle(&mut self) {
let mut rng: fastrand::Rng = fastrand::Rng::new();
rng.shuffle(self.as_mut_slice());
}
fn fastrand_shuffle_from_seed(&mut self, seed: Vec<u8>) {
let mut rng: fastrand::Rng = fastrand::Rng::new();
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
rng.seed(seed_int);
rng.shuffle(self.as_mut_slice());
}
fn modern_shuffle(&mut self) -> Vec<T> {
let size = self.len();
let mut rng = fastrand::Rng::new();
let mut new_vec = vec![];
for i in (0..size).rev() {
let x: usize = rng.usize(0..=i);
new_vec.push(self.swap_remove(x));
}
new_vec
}
fn crypto_modern_shuffle(&mut self) -> Vec<T> {
let size = self.len();
let mut rng = ChaCha20Rng::from_entropy();
let mut new_vec = vec![];
for i in (0..size).rev() {
let x: usize = rng.gen_range(0..=i);
new_vec.push(self.swap_remove(x));
}
new_vec
}
fn modern_shuffle_from_seed(&mut self, seed: Vec<u8>) -> Vec<T> {
let size = self.len();
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
let mut rng = fastrand::Rng::new();
rng.seed(seed_int);
let mut new_vec = vec![];
for i in (0..size).rev() {
let x: usize = rng.usize(0..=i);
new_vec.push(self.swap_remove(x));
}
new_vec
}
fn crypto_modern_shuffle_from_seed(&mut self, seed: Vec<u8>) -> Vec<T> {
let size = self.len();
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
let mut rng = ChaCha20Rng::seed_from_u64(seed_int);
let mut new_vec = vec![];
for i in (0..size).rev() {
let x: usize = rng.gen_range(0..=i);
new_vec.push(self.swap_remove(x));
}
new_vec
}
fn predictive_shuffle(&mut self, positions: Vec<usize>) -> HashMap<usize, usize> {
let size = self.len();
let mut rand: fastrand::Rng = fastrand::Rng::new();
let mut vec: Vec<Option<usize>> = vec![None; self.len()];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
for i in (0..size).rev() {
let x: usize = rand.usize(0..=i);
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
fn predictive_shuffle_from_seed(
&mut self,
positions: Vec<usize>,
seed: Vec<u8>,
) -> HashMap<usize, usize> {
let size = self.len();
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
let mut rand: fastrand::Rng = fastrand::Rng::new();
rand.seed(seed_int);
let mut vec: Vec<Option<usize>> = vec![None; self.len()];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
for i in (0..size).rev() {
let x: usize = rand.usize(0..=i);
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
fn crypto_predictive_shuffle(&mut self, positions: Vec<usize>) -> HashMap<usize, usize> {
let size = self.len();
let mut rng = ChaCha20Rng::from_entropy();
let mut vec: Vec<Option<usize>> = vec![None; self.len()];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
for i in (0..size).rev() {
let x: usize = rng.gen_range(0..=i);
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
fn crypto_predictive_shuffle_from_seed(
&mut self,
positions: Vec<usize>,
seed: Vec<u8>,
) -> HashMap<usize, usize> {
let size = self.len();
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
let mut rng = ChaCha20Rng::seed_from_u64(seed_int);
let mut vec: Vec<Option<usize>> = vec![None; self.len()];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
for i in (0..size).rev() {
let x: usize = rng.gen_range(0..i);
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
fn batch_predictive_shuffle(
&mut self,
batch: usize,
positions: Vec<usize>,
) -> HashMap<usize, usize> {
let size = self.len();
let mut rand: fastrand::Rng = fastrand::Rng::new();
let mut vec: Vec<Option<usize>> = vec![None; self.len()];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
let range = size / batch;
let mut randoms: Vec<usize> = (0..range).collect();
rand.shuffle(randoms.as_mut_slice());
for i in (0..size).rev() {
let x: usize = if i == 0 {
0
} else {
randoms[i % randoms.len()] % i
};
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
fn batch_predictive_shuffle_from_seed(
&mut self,
batch: usize,
positions: Vec<usize>,
seed: Vec<u8>,
) -> HashMap<usize, usize> {
let size = self.len();
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
let mut rand: fastrand::Rng = fastrand::Rng::new();
rand.seed(seed_int);
let mut vec: Vec<Option<usize>> = vec![None; self.len()];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
let range = size / batch;
let mut randoms: Vec<usize> = (0..range).collect();
rand.shuffle(randoms.as_mut_slice());
for i in (0..size).rev() {
let x: usize = if i == 0 {
0
} else {
randoms[i % randoms.len()] % i
};
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
fn crypto_batch_predictive_shuffle(
&mut self,
batch: usize,
positions: Vec<usize>,
) -> HashMap<usize, usize> {
let size = self.len();
let mut rng = ChaCha20Rng::from_entropy();
let mut vec: Vec<Option<usize>> = vec![None; self.len()];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
let range = size / batch;
let mut randoms: Vec<usize> = vec![];
for i in (0..size).rev() {
let x: usize = if i > size - range {
let x = rng.gen_range(0..=i);
randoms.push(x);
x
} else if i == 0 {
0
} else {
randoms[i % randoms.len()] % i
};
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
fn crypto_batch_predictive_shuffle_from_seed(
&mut self,
batch: usize,
positions: Vec<usize>,
seed: Vec<u8>,
) -> HashMap<usize, usize> {
let size = self.len();
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
let mut rng = ChaCha20Rng::seed_from_u64(seed_int);
let mut vec: Vec<Option<usize>> = vec![None; self.len()];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
let range = size / batch;
let mut randoms: Vec<usize> = vec![];
for i in (0..size).rev() {
let x: usize = if i > size - range {
let x = rng.gen_range(0..=i);
randoms.push(x);
x
} else if i == 0 {
0
} else {
randoms[i % randoms.len()] % i
};
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
}
pub fn gen_fastrand_shuffle(size: usize) -> Vec<usize> {
let mut vec: Vec<usize> = (0..size).collect();
let mut rng: fastrand::Rng = fastrand::Rng::new();
rng.shuffle(vec.as_mut_slice());
vec
}
pub fn gen_fastrand_shuffle_from_seed(size: usize, seed: Vec<u8>) -> Vec<usize> {
let mut vec: Vec<usize> = (0..size).collect();
let mut rng: fastrand::Rng = fastrand::Rng::new();
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
rng.seed(seed_int);
rng.shuffle(vec.as_mut_slice());
vec
}
pub fn gen_modern_shuffle(size: usize) -> Vec<usize> {
let mut rng = fastrand::Rng::new();
let mut vec: Vec<usize> = (0..size).collect();
let mut new_vec = vec![];
for i in (0..size).rev() {
let x: usize = rng.usize(0..=i);
new_vec.push(vec.swap_remove(x));
}
new_vec
}
pub fn gen_crypto_modern_shuffle(size: usize) -> Vec<usize> {
let mut vec: Vec<usize> = (0..size).collect();
let mut rng = ChaCha20Rng::from_entropy();
let mut new_vec = vec![];
for i in (0..size).rev() {
let x: usize = rng.gen_range(0..=i);
new_vec.push(vec.swap_remove(x));
}
new_vec
}
pub fn gen_modern_shuffle_from_seed(size: usize, seed: Vec<u8>) -> Vec<usize> {
let mut vec: Vec<usize> = (0..size).collect();
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
let mut rng = fastrand::Rng::new();
rng.seed(seed_int);
let mut new_vec = vec![];
for i in (0..size).rev() {
let x: usize = rng.usize(0..=i);
new_vec.push(vec.swap_remove(x));
}
new_vec
}
pub fn gen_crypto_modern_shuffle_from_seed(size: usize, seed: Vec<u8>) -> Vec<usize> {
let mut vec: Vec<usize> = (0..10).collect();
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
let mut rng = ChaCha20Rng::seed_from_u64(seed_int);
let mut new_vec = vec![];
for i in (0..size).rev() {
let x: usize = rng.gen_range(0..=i);
new_vec.push(vec.swap_remove(x));
}
new_vec
}
pub fn gen_predictive_shuffle(size: usize, positions: Vec<usize>) -> HashMap<usize, usize> {
let mut rand: fastrand::Rng = fastrand::Rng::new();
let mut vec: Vec<Option<usize>> = vec![None; size];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
for i in (0..size).rev() {
let x: usize = rand.usize(0..=i);
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
pub fn gen_predictive_shuffle_from_seed(
size: usize,
positions: Vec<usize>,
seed: Vec<u8>,
) -> HashMap<usize, usize> {
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
let mut rand: fastrand::Rng = fastrand::Rng::new();
rand.seed(seed_int);
let mut vec: Vec<Option<usize>> = vec![None; size];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
for i in (0..size).rev() {
let x: usize = rand.usize(0..=i);
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
pub fn gen_crypto_predictive_shuffle(size: usize, positions: Vec<usize>) -> HashMap<usize, usize> {
let mut rng = ChaCha20Rng::from_entropy();
let mut vec: Vec<Option<usize>> = vec![None; size];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
for i in (0..size).rev() {
let x: usize = rng.gen_range(0..=i);
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
pub fn gen_crypto_predictive_shuffle_from_seed(
size: usize,
positions: Vec<usize>,
seed: Vec<u8>,
) -> HashMap<usize, usize> {
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
let mut rng = ChaCha20Rng::seed_from_u64(seed_int);
let mut vec: Vec<Option<usize>> = vec![None; size];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
for i in (0..size).rev() {
let x: usize = rng.gen_range(0..i);
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
pub fn gen_batch_predictive_shuffle(
size: usize,
batch: usize,
positions: Vec<usize>,
) -> HashMap<usize, usize> {
let mut rand: fastrand::Rng = fastrand::Rng::new();
let mut vec: Vec<Option<usize>> = vec![None; size];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
let range = size / batch;
let mut randoms: Vec<usize> = (0..range).collect();
rand.shuffle(randoms.as_mut_slice());
for i in (0..size).rev() {
let x: usize = if i == 0 {
0
} else {
randoms[i % randoms.len()] % i
};
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
pub fn gen_batch_predictive_shuffle_from_seed(
size: usize,
batch: usize,
positions: Vec<usize>,
seed: Vec<u8>,
) -> HashMap<usize, usize> {
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
let mut rand: fastrand::Rng = fastrand::Rng::new();
rand.seed(seed_int);
let mut vec: Vec<Option<usize>> = vec![None; size];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
let range = size / batch;
let mut randoms: Vec<usize> = (0..range).collect();
rand.shuffle(randoms.as_mut_slice());
for i in (0..size).rev() {
let x: usize = if i == 0 {
0
} else {
randoms[i % randoms.len()] % i
};
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
pub fn gen_crypto_batch_predictive_shuffle(
size: usize,
batch: usize,
positions: Vec<usize>,
) -> HashMap<usize, usize> {
let mut rng = ChaCha20Rng::from_entropy();
let mut vec: Vec<Option<usize>> = vec![None; size];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
let range = size / batch;
let mut randoms: Vec<usize> = vec![];
for i in (0..size).rev() {
let x: usize = if i > size - range {
let x = rng.gen_range(0..=i);
randoms.push(x);
x
} else if i == 0 {
0
} else {
randoms[i % randoms.len()] % i
};
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
pub fn gen_crypto_batch_predictive_shuffle_from_seed(
size: usize,
batch: usize,
positions: Vec<usize>,
seed: Vec<u8>,
) -> HashMap<usize, usize> {
let seed = byte_array(&seed);
let seed_int = u64::from_be_bytes(seed);
let mut rng = ChaCha20Rng::seed_from_u64(seed_int);
let mut vec: Vec<Option<usize>> = vec![None; size];
let mut peers = positions.len();
for i in positions {
vec[i] = Some(i)
}
let mut new_map = HashMap::new();
let range = size / batch;
let mut randoms: Vec<usize> = vec![];
for i in (0..size).rev() {
let x: usize = if i > size - range {
let x = rng.gen_range(0..=i);
randoms.push(x);
x
} else if i == 0 {
0
} else {
randoms[i % randoms.len()] % i
};
if let Some(item) = vec[x] {
new_map.insert(item, i);
peers -= 1;
vec[x] = None;
if peers == 0 {
break;
}
}
if let Some(item) = vec[i] {
vec[x] = Some(item);
vec[i] = None
}
}
new_map
}
pub fn hash(seed: &Vec<u8>) -> Vec<u8> {
let mut hasher = Sha256::new();
hasher.update(seed);
let result = hasher.finalize();
format!("{:x}", result).as_bytes().to_vec()
}
pub fn byte_array(v: &Vec<u8>) -> [u8; 8] {
let mut hash = hash(v);
hash.truncate(8);
hash.try_into().unwrap_or_else(|v: Vec<u8>| {
panic!("Expected a Vec of length {} but it was {}", 8, v.len())
})
}