11use crate :: io;
22use crate :: mem;
3- use crate :: sync ;
3+ use crate :: ptr ;
44use crate :: sys:: c;
55
6- /// The kinds of HashMap RNG that may be available
7- #[ derive( Clone , Copy , Debug , PartialEq ) ]
8- enum HashMapRng {
9- Preferred ,
10- Fallback ,
11- }
12-
136pub fn hashmap_random_keys ( ) -> ( u64 , u64 ) {
14- match get_hashmap_rng ( ) {
15- HashMapRng :: Preferred => {
16- preferred_rng ( ) . expect ( "couldn't generate random bytes with preferred RNG" )
17- }
18- HashMapRng :: Fallback => {
19- fallback_rng ( ) . expect ( "couldn't generate random bytes with fallback RNG" )
20- }
21- }
22- }
23-
24- /// Returns the HashMap RNG that should be used
25- ///
26- /// Panics if they are both broken
27- fn get_hashmap_rng ( ) -> HashMapRng {
28- // Assume that if the preferred RNG is broken the first time we use it, it likely means
29- // that: the DLL has failed to load, there is no point to calling it over-and-over again,
30- // and we should cache the result
31- static VALUE : sync:: OnceLock < HashMapRng > = sync:: OnceLock :: new ( ) ;
32- * VALUE . get_or_init ( choose_hashmap_rng)
33- }
34-
35- /// Test whether we should use the preferred or fallback RNG
36- ///
37- /// If the preferred RNG is successful, we choose it. Otherwise, if the fallback RNG is successful,
38- /// we choose that
39- ///
40- /// Panics if both the preferred and the fallback RNG are both non-functional
41- fn choose_hashmap_rng ( ) -> HashMapRng {
42- let preferred_error = match preferred_rng ( ) {
43- Ok ( _) => return HashMapRng :: Preferred ,
44- Err ( e) => e,
45- } ;
46-
47- match fallback_rng ( ) {
48- Ok ( _) => return HashMapRng :: Fallback ,
49- Err ( fallback_error) => panic ! (
50- "preferred RNG broken: `{}`, fallback RNG broken: `{}`" ,
51- preferred_error, fallback_error
52- ) ,
53- }
54- }
55-
56- /// Generate random numbers using the preferred RNG function (BCryptGenRandom)
57- fn preferred_rng ( ) -> Result < ( u64 , u64 ) , io:: Error > {
58- use crate :: ptr;
59-
607 let mut v = ( 0 , 0 ) ;
618 let ret = unsafe {
629 c:: BCryptGenRandom (
@@ -66,22 +13,23 @@ fn preferred_rng() -> Result<(u64, u64), io::Error> {
6613 c:: BCRYPT_USE_SYSTEM_PREFERRED_RNG ,
6714 )
6815 } ;
69-
70- if ret == 0 { Ok ( v) } else { Err ( io:: Error :: last_os_error ( ) ) }
16+ if ret != 0 { fallback_rng ( ) } else { v }
7117}
7218
7319/// Generate random numbers using the fallback RNG function (RtlGenRandom)
7420#[ cfg( not( target_vendor = "uwp" ) ) ]
75- fn fallback_rng ( ) -> Result < ( u64 , u64 ) , io:: Error > {
21+ #[ inline( never) ]
22+ fn fallback_rng ( ) -> ( u64 , u64 ) {
7623 let mut v = ( 0 , 0 ) ;
7724 let ret =
7825 unsafe { c:: RtlGenRandom ( & mut v as * mut _ as * mut u8 , mem:: size_of_val ( & v) as c:: ULONG ) } ;
7926
80- if ret != 0 { Ok ( v ) } else { Err ( io:: Error :: last_os_error ( ) ) }
27+ if ret != 0 { v } else { panic ! ( "fallback RNG broken: {}" , io:: Error :: last_os_error( ) ) }
8128}
8229
8330/// We can't use RtlGenRandom with UWP, so there is no fallback
8431#[ cfg( target_vendor = "uwp" ) ]
85- fn fallback_rng ( ) -> Result < ( u64 , u64 ) , io:: Error > {
86- Err ( io:: const_io_error!( io:: ErrorKind :: Unsupported , "RtlGenRandom() not supported on UWP" ) )
32+ #[ inline( never) ]
33+ fn fallback_rng ( ) -> ( u64 , u64 ) {
34+ panic ! ( "fallback RNG broken: RtlGenRandom() not supported on UWP" ) ;
8735}
0 commit comments