Skip to main content

tfhe_csprng/seeders/implem/
rdseed.rs

1use crate::seeders::{Seed, Seeder};
2
3/// A seeder which uses the `rdseed` x86_64 instruction.
4///
5/// The `rdseed` instruction allows to deliver seeds from a hardware source of entropy see
6/// <https://www.felixcloutier.com/x86/rdseed> .
7pub struct RdseedSeeder(());
8
9impl RdseedSeeder {
10    pub fn new() -> Self {
11        if Self::is_available() {
12            Self(())
13        } else {
14            panic!("Tried to use RdSeedSeeder but rdseed instruction is not enabled on the current machine");
15        }
16    }
17}
18
19impl Default for RdseedSeeder {
20    fn default() -> Self {
21        Self::new()
22    }
23}
24
25impl Seeder for RdseedSeeder {
26    fn seed(&mut self) -> Seed {
27        Seed(unsafe { rdseed_random_m128() })
28    }
29
30    fn is_available() -> bool {
31        is_x86_feature_detected!("rdseed")
32    }
33}
34
35// Generates a random 128 bits value from rdseed
36#[target_feature(enable = "rdseed")]
37unsafe fn rdseed_random_m128() -> u128 {
38    let mut rand1: u64 = 0;
39    let mut rand2: u64 = 0;
40    let mut output_bytes = [0u8; 16];
41
42    loop {
43        if core::arch::x86_64::_rdseed64_step(&mut rand1) == 1 {
44            break;
45        }
46    }
47    loop {
48        if core::arch::x86_64::_rdseed64_step(&mut rand2) == 1 {
49            break;
50        }
51    }
52
53    output_bytes[0..8].copy_from_slice(&rand1.to_ne_bytes());
54    output_bytes[8..16].copy_from_slice(&rand2.to_ne_bytes());
55    u128::from_ne_bytes(output_bytes)
56}
57
58#[cfg(test)]
59mod test {
60    use super::*;
61    use crate::seeders::generic_tests::check_seeder_fixed_sequences_different;
62
63    #[test]
64    fn check_bounded_sequence_difference() {
65        check_seeder_fixed_sequences_different(|_| RdseedSeeder::new());
66    }
67}