1
1
use crate :: io;
2
2
use crate :: mem;
3
- use crate :: sync ;
3
+ use crate :: ptr ;
4
4
use crate :: sys:: c;
5
5
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
-
13
6
pub 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
-
60
7
let mut v = ( 0 , 0 ) ;
61
8
let ret = unsafe {
62
9
c:: BCryptGenRandom (
@@ -66,22 +13,23 @@ fn preferred_rng() -> Result<(u64, u64), io::Error> {
66
13
c:: BCRYPT_USE_SYSTEM_PREFERRED_RNG ,
67
14
)
68
15
} ;
69
-
70
- if ret == 0 { Ok ( v) } else { Err ( io:: Error :: last_os_error ( ) ) }
16
+ if ret != 0 { fallback_rng ( ) } else { v }
71
17
}
72
18
73
19
/// Generate random numbers using the fallback RNG function (RtlGenRandom)
74
20
#[ cfg( not( target_vendor = "uwp" ) ) ]
75
- fn fallback_rng ( ) -> Result < ( u64 , u64 ) , io:: Error > {
21
+ #[ inline( never) ]
22
+ fn fallback_rng ( ) -> ( u64 , u64 ) {
76
23
let mut v = ( 0 , 0 ) ;
77
24
let ret =
78
25
unsafe { c:: RtlGenRandom ( & mut v as * mut _ as * mut u8 , mem:: size_of_val ( & v) as c:: ULONG ) } ;
79
26
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( ) ) }
81
28
}
82
29
83
30
/// We can't use RtlGenRandom with UWP, so there is no fallback
84
31
#[ 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" ) ;
87
35
}
0 commit comments