use crate::{ArcisType, Reveal};
use rand::{thread_rng, Rng};
use std::cell::Cell;
thread_local! {
static GENERATED_BOOLS: Cell<Vec<bool>> = const {Cell::new(Vec::new()) };
}
pub fn generated_bools() -> Vec<bool> {
GENERATED_BOOLS.take()
}
pub struct ArcisRNG;
impl ArcisRNG {
pub fn bool() -> bool {
let mut rng = thread_rng();
let b = rng.gen_bool(0.5);
let mut v = GENERATED_BOOLS.take();
v.push(b);
GENERATED_BOOLS.replace(v);
b
}
pub fn gen_integer_from_width(width: usize) -> u128 {
assert!(width <= u128::BITS as usize);
let mut integer: u128 = 0;
for i in 0..width {
integer += (Self::bool() as u128) << i;
}
integer
}
pub fn gen_public_integer_from_width(width: usize) -> u128 {
Self::gen_integer_from_width(width).reveal()
}
pub fn shuffle<T>(data: &mut [T]) {
let n = data.len();
let randomness_width = if n < 2 {
0
} else {
2 * (n.ilog2() as usize) + 64
};
let mut random_nums = Vec::with_capacity(n);
for i in 0..n {
random_nums.push((Self::gen_integer_from_width(randomness_width), i));
}
random_nums.sort();
let final_perm = random_nums.into_iter().map(|(_, x)| x).collect::<Vec<_>>();
apply_perm(data, &final_perm);
}
pub fn gen_uniform<T: ArcisType>() -> T {
let bools = (0..T::n_bools())
.map(|_| ArcisRNG::bool())
.collect::<Vec<_>>();
T::from_bools(&bools)
}
}
fn apply_perm<T>(data: &mut [T], perm: &[usize]) {
let n = data.len();
let mut current_perm: Vec<_> = (0..n).collect();
let mut positions: Vec<_> = (0..n).collect();
for i in 0..(n - 1) {
let val_to_transfer = perm[i];
let other_i = positions[val_to_transfer];
if i == other_i {
continue;
}
let i_val = current_perm[i];
assert_eq!(current_perm[i], i_val);
assert_eq!(current_perm[other_i], val_to_transfer);
assert_eq!(positions[i_val], i);
assert_eq!(positions[val_to_transfer], other_i);
data.swap(i, other_i);
current_perm.swap(i, other_i);
positions.swap(i_val, val_to_transfer);
}
assert_eq!(current_perm.as_slice(), perm);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_apply_perm() {
let final_perm = [1, 2, 0, 5, 4, 3];
let init_data = [10, 11, 12, 13, 14, 15];
let mut data = init_data;
apply_perm(&mut data, &final_perm);
assert_eq!(data, [11, 12, 10, 15, 14, 13]);
for i in 0..init_data.len() {
assert_eq!(data[i], init_data[final_perm[i]]);
}
}
}