arnaucube
arnaucube/phantom-zonePublic Self-hosted repository
phantom-zone/src/random.rs
src/random.rsRaw
  1use std::cell::RefCell;
  2
  3use itertools::izip;
  4use rand::{distributions::Uniform, thread_rng, CryptoRng, Rng, RngCore, SeedableRng};
  5use rand_chacha::ChaCha8Rng;
  6use rand_distr::Distribution;
  7
  8use crate::utils::WithLocal;
  9
 10thread_local! {
 11    pub(crate) static DEFAULT_RNG: RefCell<DefaultSecureRng> = RefCell::new(DefaultSecureRng::new());
 12}
 13
 14pub(crate) trait NewWithSeed {
 15    type Seed;
 16    fn new_with_seed(seed: Self::Seed) -> Self;
 17}
 18
 19pub trait RandomGaussianDist<M>
 20where
 21    M: ?Sized,
 22{
 23    type Parameters: ?Sized;
 24    fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut M);
 25}
 26
 27pub trait RandomUniformDist<M>
 28where
 29    M: ?Sized,
 30{
 31    type Parameters: ?Sized;
 32    fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut M);
 33}
 34
 35pub(crate) struct DefaultSecureRng {
 36    rng: ChaCha8Rng,
 37}
 38
 39impl DefaultSecureRng {
 40    pub fn new_seeded(seed: <ChaCha8Rng as SeedableRng>::Seed) -> DefaultSecureRng {
 41        let rng = ChaCha8Rng::from_seed(seed);
 42        DefaultSecureRng { rng }
 43    }
 44
 45    pub fn new() -> DefaultSecureRng {
 46        let rng = ChaCha8Rng::from_entropy();
 47        DefaultSecureRng { rng }
 48    }
 49
 50    pub fn fill_bytes(&mut self, a: &mut [u8; 32]) {
 51        self.rng.fill_bytes(a);
 52    }
 53}
 54
 55impl NewWithSeed for DefaultSecureRng {
 56    type Seed = <ChaCha8Rng as SeedableRng>::Seed;
 57    fn new_with_seed(seed: Self::Seed) -> Self {
 58        DefaultSecureRng::new_seeded(seed)
 59    }
 60}
 61
 62impl RandomUniformDist<usize> for DefaultSecureRng {
 63    type Parameters = usize;
 64    fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut usize) {
 65        *container = self.rng.gen_range(0..*parameters);
 66    }
 67}
 68
 69impl RandomUniformDist<[u8]> for DefaultSecureRng {
 70    type Parameters = u8;
 71    fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u8]) {
 72        self.rng.fill_bytes(container);
 73    }
 74}
 75
 76impl RandomUniformDist<[u32]> for DefaultSecureRng {
 77    type Parameters = u32;
 78    fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u32]) {
 79        izip!(
 80            (&mut self.rng).sample_iter(Uniform::new(0, parameters)),
 81            container.iter_mut()
 82        )
 83        .for_each(|(from, to)| {
 84            *to = from;
 85        });
 86    }
 87}
 88
 89impl RandomUniformDist<[u64]> for DefaultSecureRng {
 90    type Parameters = u64;
 91    fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u64]) {
 92        izip!(
 93            (&mut self.rng).sample_iter(Uniform::new(0, parameters)),
 94            container.iter_mut()
 95        )
 96        .for_each(|(from, to)| {
 97            *to = from;
 98        });
 99    }
100}
101
102impl RandomGaussianDist<u64> for DefaultSecureRng {
103    type Parameters = u64;
104    fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut u64) {
105        // let o = rand_distr::Normal::new(0.0, 3.2f64)
106        //     .unwrap()
107        //     .sample(&mut self.rng)
108        //     .round();
109
110        // // let o = 0.0f64;
111
112        // let is_neg = o.is_sign_negative() && o != 0.0;
113        // if is_neg {
114        //     *container = parameters - (o.abs() as u64);
115        // } else {
116        //     *container = o as u64;
117        // }
118    }
119}
120
121impl RandomGaussianDist<u32> for DefaultSecureRng {
122    type Parameters = u32;
123    fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut u32) {
124        let o = rand_distr::Normal::new(0.0, 3.2f32)
125            .unwrap()
126            .sample(&mut self.rng)
127            .round();
128
129        // let o = 0.0f32;
130        let is_neg = o.is_sign_negative() && o != 0.0;
131
132        if is_neg {
133            *container = parameters - (o.abs() as u32);
134        } else {
135            *container = o as u32;
136        }
137    }
138}
139
140impl RandomGaussianDist<[u64]> for DefaultSecureRng {
141    type Parameters = u64;
142    fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u64]) {
143        // izip!(
144        //     rand_distr::Normal::new(0.0, 3.2f64)
145        //         .unwrap()
146        //         .sample_iter(&mut self.rng),
147        //     container.iter_mut()
148        // )
149        // .for_each(|(oi, v)| {
150        //     let oi = oi.round();
151        //     let is_neg = oi.is_sign_negative() && oi != 0.0;
152        //     if is_neg {
153        //         *v = parameters - (oi.abs() as u64);
154        //     } else {
155        //         *v = oi as u64;
156        //     }
157        // });
158    }
159}
160
161impl RandomGaussianDist<[u32]> for DefaultSecureRng {
162    type Parameters = u32;
163    fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u32]) {
164        izip!(
165            rand_distr::Normal::new(0.0, 3.2f32)
166                .unwrap()
167                .sample_iter(&mut self.rng),
168            container.iter_mut()
169        )
170        .for_each(|(oi, v)| {
171            let oi = oi.round();
172            let is_neg = oi.is_sign_negative() && oi != 0.0;
173            if is_neg {
174                *v = parameters - (oi.abs() as u32);
175            } else {
176                *v = oi as u32;
177            }
178        });
179    }
180}
181
182impl WithLocal for DefaultSecureRng {
183    fn with_local<F, R>(func: F) -> R
184    where
185        F: Fn(&Self) -> R,
186    {
187        DEFAULT_RNG.with_borrow(|r| func(r))
188    }
189
190    fn with_local_mut<F, R>(func: F) -> R
191    where
192        F: Fn(&mut Self) -> R,
193    {
194        DEFAULT_RNG.with_borrow_mut(|r| func(r))
195    }
196}