use argon2::Argon2;
use rand::RngCore;
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;
use rand_xoshiro::Xoshiro256PlusPlus;
use std::str::FromStr;
#[derive(Debug, Clone, PartialEq)]
pub enum Random {
System(System),
Null(Null),
Xoshiro(Xoshiro),
ChaCha20(ChaCha20),
}
impl Default for Random {
fn default() -> Self {
Self::System(System)
}
}
impl Random {
pub fn from_master_pass(pass: &str, salt: &str) -> Self {
let mut seed = [0; 32];
Argon2::new_with_secret(
b"passgen",
Default::default(),
Default::default(),
Default::default(),
)
.unwrap()
.hash_password_into(pass.as_bytes(), salt.as_bytes(), &mut seed)
.unwrap();
Self::ChaCha20(ChaCha20(seed))
}
}
#[derive(thiserror::Error, Debug)]
pub enum ParseError {}
impl FromStr for Random {
type Err = ParseError;
fn from_str(input: &str) -> Result<Self, Self::Err> {
match input {
"system" => return Ok(Self::System(System)),
"null" => return Ok(Self::Null(Null)),
_ => {}
}
if let Some((name, params)) = input.split_once(':') {
if name == "xoshiro" {
return Ok(Self::Xoshiro(Xoshiro(params.parse().unwrap())));
}
}
todo!()
}
}
pub trait RandomSource {
type Rng: RngCore;
fn get_rng(&self, index: usize) -> Self::Rng;
}
pub trait BoxedRandomSource {
fn get_rng_boxed(&self, index: usize) -> Box<dyn RngCore>;
}
impl<S: RandomSource> BoxedRandomSource for S
where
S::Rng: 'static,
{
fn get_rng_boxed(&self, index: usize) -> Box<dyn RngCore> {
Box::new(RandomSource::get_rng(self, index))
}
}
impl BoxedRandomSource for Random {
fn get_rng_boxed(&self, index: usize) -> Box<dyn RngCore> {
match self {
Self::System(random) => random.get_rng_boxed(index),
Self::Null(random) => random.get_rng_boxed(index),
Self::Xoshiro(random) => random.get_rng_boxed(index),
Self::ChaCha20(random) => random.get_rng_boxed(index),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct System;
impl RandomSource for System {
type Rng = rand::rngs::ThreadRng;
fn get_rng(&self, _index: usize) -> Self::Rng {
rand::thread_rng()
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Null;
impl RandomSource for Null {
type Rng = rand::rngs::mock::StepRng;
fn get_rng(&self, _index: usize) -> Self::Rng {
rand::rngs::mock::StepRng::new(0, 0)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Xoshiro(u64);
impl RandomSource for Xoshiro {
type Rng = Xoshiro256PlusPlus;
fn get_rng(&self, index: usize) -> Self::Rng {
let mut rng = Xoshiro256PlusPlus::seed_from_u64(self.0);
for _ in 0..index {
rng.jump();
}
rng
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ChaCha20([u8; 32]);
impl RandomSource for ChaCha20 {
type Rng = ChaCha20Rng;
fn get_rng(&self, index: usize) -> Self::Rng {
let mut rng = ChaCha20Rng::from_seed(self.0);
rng.set_stream(index as u64);
rng
}
}