Improve RNG (#602)

* Fix RNG without RDRAND

* Add RDRAND retry

* Rename random to rng

* Display warning when RDRAND is not available

* Change debug wording

* Optimize FileIO for Random

* Refactor RdRand code

* Use hash function

* Seed RNG only once
This commit is contained in:
Vincent Ollivier 2024-03-23 08:51:06 +01:00 committed by GitHub
parent ed945d585d
commit 1ff8d5d39c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 105 additions and 81 deletions

View File

@ -89,7 +89,7 @@ pub mod fs;
pub mod io;
pub mod process;
pub mod prompt;
pub mod random;
pub mod rng;
pub mod regex;
pub mod syscall;
pub mod time;

View File

@ -36,6 +36,7 @@ pub fn init(boot_info: &'static BootInfo) {
sys::mem::init(boot_info);
sys::acpi::init(); // Require MEM
sys::cpu::init();
sys::rng::init();
sys::pci::init(); // Require MEM
sys::net::init(); // Require PCI
sys::ata::init();

View File

@ -9,7 +9,7 @@ use crate::sys::cmos::RTC;
use crate::sys::console::Console;
use crate::sys::net::socket::tcp::TcpSocket;
use crate::sys::net::socket::udp::UdpSocket;
use crate::sys::random::Random;
use crate::sys::rng::Random;
use alloc::vec;
use alloc::vec::Vec;

View File

@ -54,7 +54,7 @@ pub mod net;
pub mod pci;
pub mod pic;
pub mod process;
pub mod random;
pub mod rng;
pub mod serial;
pub mod syscall;
pub mod time;

View File

@ -16,7 +16,7 @@ lazy_static! {
}
fn random_port() -> u16 {
49152 + sys::random::get_u16() % 16384
49152 + sys::rng::get_u16() % 16384
}
fn wait(duration: Duration) {

View File

@ -1,68 +0,0 @@
use crate::api::fs::{FileIO, IO};
use crate::sys;
use rand::{RngCore, SeedableRng};
use rand_hc::Hc128Rng;
use x86_64::instructions::random::RdRand;
#[derive(Debug, Clone)]
pub struct Random;
impl Random {
pub fn new() -> Self {
Self {}
}
}
impl FileIO for Random {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()> {
let n = buf.len();
for i in 0..n {
buf[i] = get_u64() as u8;
}
Ok(n)
}
fn write(&mut self, _buf: &[u8]) -> Result<usize, ()> {
unimplemented!();
}
fn close(&mut self) {}
fn poll(&mut self, event: IO) -> bool {
match event {
IO::Read => true,
IO::Write => false,
}
}
}
pub fn get_u64() -> u64 {
let mut seed = [0u8; 32];
if let Some(rdrand) = RdRand::new() {
for i in 0..4 {
if let Some(rand) = rdrand.get_u64() {
let bytes = rand.to_be_bytes();
for j in 0..8 {
seed[8 * i + j] = bytes[j];
}
}
}
} else {
// FIXME: RDRAND instruction is not available on old CPUs
seed[0..8].clone_from_slice(&sys::time::ticks().to_be_bytes());
seed[8..16].clone_from_slice(&sys::clock::realtime().to_be_bytes());
seed[16..24].clone_from_slice(&sys::clock::uptime().to_be_bytes());
seed[24..32].clone_from_slice(&sys::time::ticks().to_be_bytes());
}
let mut rng = Hc128Rng::from_seed(seed);
rng.next_u64()
}
pub fn get_u32() -> u32 {
get_u64() as u32
}
pub fn get_u16() -> u16 {
get_u64() as u16
}

91
src/sys/rng.rs Normal file
View File

@ -0,0 +1,91 @@
use crate::api::fs::{FileIO, IO};
use crate::sys;
use lazy_static::lazy_static;
use rand::{RngCore, SeedableRng};
use rand_hc::Hc128Rng;
use sha2::{Digest, Sha256};
use spin::Mutex;
use x86_64::instructions::random::RdRand;
lazy_static! {
static ref RNG: Mutex<Hc128Rng> = Mutex::new(Hc128Rng::from_seed([0; 32]));
}
#[derive(Debug, Clone)]
pub struct Random;
impl Random {
pub fn new() -> Self {
Self {}
}
}
impl FileIO for Random {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()> {
let n = buf.len();
for chunk in buf.chunks_mut(8) {
let bytes = get_u64().to_le_bytes();
let count = chunk.len();
chunk.clone_from_slice(&bytes[..count]);
}
Ok(n)
}
fn write(&mut self, _buf: &[u8]) -> Result<usize, ()> {
unimplemented!();
}
fn close(&mut self) {}
fn poll(&mut self, event: IO) -> bool {
match event {
IO::Read => true,
IO::Write => false,
}
}
}
pub fn get_u64() -> u64 {
RNG.lock().next_u64()
}
pub fn get_u32() -> u32 {
get_u64() as u32
}
pub fn get_u16() -> u16 {
get_u64() as u16
}
pub fn init() {
let mut seed = [0; 32];
if let Some(rng) = RdRand::new() {
log!("RNG RDRAND available");
for chunk in seed.chunks_mut(8) {
// NOTE: Intel's Software Developer's Manual, Volume 1, 7.3.17.1
let mut retry = true;
for _ in 0..10 { // Retry up to 10 times
if let Some(num) = rng.get_u64() {
chunk.clone_from_slice(&num.to_be_bytes());
retry = false;
break;
} else {
//debug!("RDRAND: read failed");
}
}
if retry {
//debug!("RDRAND: retry failed");
}
}
} else {
log!("RNG RDRAND unavailable");
let mut hasher = Sha256::new();
hasher.update(&sys::time::ticks().to_be_bytes());
hasher.update(&sys::clock::realtime().to_be_bytes());
hasher.update(&sys::clock::uptime().to_be_bytes());
seed = hasher.finalize().into();
}
*RNG.lock() = Hc128Rng::from_seed(seed);
}

View File

@ -1,6 +1,6 @@
use crate::api::console::Style;
use crate::api::process::ExitCode;
use crate::api::random;
use crate::api::rng;
use crate::api::syscall;
use crate::sys::fs::OpenFlag;
use crate::usr;
@ -61,7 +61,7 @@ impl Message {
pub fn query(qname: &str, qtype: QueryType, qclass: QueryClass) -> Self {
let mut datagram = Vec::new();
let id = random::get_u16();
let id = rng::get_u16();
for b in id.to_be_bytes().iter() {
datagram.push(*b); // Transaction ID
}

View File

@ -2,7 +2,7 @@ use crate::{api, sys};
use crate::api::console::Style;
use crate::api::fs;
use crate::api::process::ExitCode;
use crate::api::random;
use crate::api::rng;
use crate::sys::console;
use alloc::collections::BTreeSet;
@ -109,8 +109,8 @@ impl Game {
fn seed(&mut self) {
let n = self.seed_population;
for _ in 0..n {
let x = (random::get_u64() % (self.cols as u64)) as i64;
let y = (random::get_u64() % (self.rows as u64)) as i64;
let x = (rng::get_u64() % (self.cols as u64)) as i64;
let y = (rng::get_u64() % (self.rows as u64)) as i64;
self.grid.insert((x, y));
}
}

View File

@ -1,6 +1,6 @@
use crate::api::console::Style;
use crate::api::process::ExitCode;
use crate::api::{console, io, random};
use crate::api::{console, io, rng};
use alloc::format;
use alloc::string::ToString;
@ -52,7 +52,7 @@ impl Game {
let zeros: Vec<_> = (0..16).filter(|i| self.board[*i] == 0).collect();
if !zeros.is_empty() {
let i = (random::get_u64() as usize) % zeros.len();
let i = (rng::get_u64() as usize) % zeros.len();
self.board[zeros[i]] = 2;
}
}

View File

@ -2,7 +2,7 @@ use crate::api::console::Style;
use crate::api::fs;
use crate::api::io;
use crate::api::process::ExitCode;
use crate::api::random;
use crate::api::rng;
use crate::api::syscall;
use crate::{api, sys, usr};
use alloc::collections::btree_map::BTreeMap;
@ -165,7 +165,7 @@ pub fn hash(password: &str) -> String {
// Generating salt
for i in 0..2 {
let num = random::get_u64();
let num = rng::get_u64();
let buf = num.to_be_bytes();
let n = buf.len();
for j in 0..n {