use rand::Rng;
use rand_chacha::ChaCha20Rng;
use rand::SeedableRng;
pub use crate::stego::ghost::permute::select_and_permute;
#[derive(Clone)]
pub struct CoeffPos {
pub flat_idx: u32,
pub cost: f32,
}
fn shuffle_portable(positions: &mut [CoeffPos], seed: &[u8; 32]) {
let mut rng = ChaCha20Rng::from_seed(*seed);
let n = positions.len();
for i in (1..n).rev() {
let j = rng.gen_range(0..=(i as u32)) as usize;
positions.swap(i, j);
}
}
pub fn permute_positions(positions: &mut [CoeffPos], seed: &[u8; 32]) {
shuffle_portable(positions, seed);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn shuffle_deterministic() {
let mut a = vec![
CoeffPos { flat_idx: 0, cost: 1.0 },
CoeffPos { flat_idx: 1, cost: 2.0 },
CoeffPos { flat_idx: 2, cost: 3.0 },
CoeffPos { flat_idx: 3, cost: 4.0 },
];
let mut b = a.clone();
let seed = [42u8; 32];
permute_positions(&mut a, &seed);
permute_positions(&mut b, &seed);
let a_idx: Vec<_> = a.iter().map(|p| p.flat_idx).collect();
let b_idx: Vec<_> = b.iter().map(|p| p.flat_idx).collect();
assert_eq!(a_idx, b_idx);
}
#[test]
fn different_seeds_produce_different_order() {
let mut a = (0..20).map(|i| CoeffPos { flat_idx: i, cost: 1.0 }).collect::<Vec<_>>();
let mut b = a.clone();
permute_positions(&mut a, &[1u8; 32]);
permute_positions(&mut b, &[2u8; 32]);
let a_idx: Vec<_> = a.iter().map(|p| p.flat_idx).collect();
let b_idx: Vec<_> = b.iter().map(|p| p.flat_idx).collect();
assert_ne!(a_idx, b_idx);
}
}