@@ -1015,6 +1015,106 @@ impl Rng for ThreadRng {
1015
1015
}
1016
1016
}
1017
1017
1018
+ /// An RNG provided specifically for seeding PRNG's.
1019
+ ///
1020
+ /// `EntropySource` uses the interface for random numbers provided by the
1021
+ /// operating system (`OsRng`). If that returns an error, it will fall back to
1022
+ /// the `JitterRng` entropy collector. Occasionally it will then check if
1023
+ /// `OsRng` is still not available, and switch back if possible.
1024
+ #[ cfg( feature="std" ) ]
1025
+ #[ derive( Debug ) ]
1026
+ pub struct EntropySource {
1027
+ rng : EntropySourceInner ,
1028
+ counter : u32 ,
1029
+ }
1030
+
1031
+ #[ cfg( feature="std" ) ]
1032
+ #[ derive( Debug ) ]
1033
+ enum EntropySourceInner {
1034
+ Os ( OsRng ) ,
1035
+ Jitter ( JitterRng ) ,
1036
+ }
1037
+
1038
+ #[ cfg( feature="std" ) ]
1039
+ impl EntropySource {
1040
+ pub fn new ( ) -> Result < Self , Error > {
1041
+ match OsRng :: new ( ) {
1042
+ Ok ( r) =>
1043
+ Ok ( EntropySource { rng : EntropySourceInner :: Os ( r) ,
1044
+ counter : 0u32 } ) ,
1045
+ Err ( e1) => {
1046
+ match JitterRng :: new ( ) {
1047
+ Ok ( r) =>
1048
+ Ok ( EntropySource { rng : EntropySourceInner :: Jitter ( r) ,
1049
+ counter : 0 } ) ,
1050
+ Err ( _) =>
1051
+ Err ( Error :: with_cause (
1052
+ ErrorKind :: Unavailable ,
1053
+ "Both OS and Jitter entropy sources are unavailable" ,
1054
+ e1) )
1055
+ }
1056
+ }
1057
+ }
1058
+ }
1059
+ }
1060
+
1061
+ #[ cfg( feature="std" ) ]
1062
+ impl Rng for EntropySource {
1063
+ fn next_u32 ( & mut self ) -> u32 {
1064
+ impls:: next_u32_via_fill ( self )
1065
+ }
1066
+
1067
+ fn next_u64 ( & mut self ) -> u64 {
1068
+ impls:: next_u64_via_fill ( self )
1069
+ }
1070
+
1071
+ fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
1072
+ self . try_fill_bytes ( dest) . unwrap ( ) ;
1073
+ }
1074
+
1075
+ fn try_fill_bytes ( & mut self , dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
1076
+ let mut switch_rng = None ;
1077
+ let mut result;
1078
+ match self . rng {
1079
+ EntropySourceInner :: Os ( ref mut rng) => {
1080
+ result = rng. try_fill_bytes ( dest) ;
1081
+ if result. is_err ( ) {
1082
+ // Fall back to JitterRng.
1083
+ let mut rng2_result = JitterRng :: new ( ) ;
1084
+ if let Ok ( mut rng2) = rng2_result {
1085
+ result = rng2. try_fill_bytes ( dest) ; // Can't fail
1086
+ switch_rng = Some ( EntropySourceInner :: Jitter ( rng2) ) ;
1087
+ }
1088
+ }
1089
+ }
1090
+ EntropySourceInner :: Jitter ( ref mut rng) => {
1091
+ if self . counter < 8 {
1092
+ result = rng. try_fill_bytes ( dest) ; // use JitterRng
1093
+ self . counter = ( self . counter + 1 ) % 8 ;
1094
+ } else {
1095
+ // Try if OsRng is still unavailable
1096
+ let os_rng_result = OsRng :: new ( ) ;
1097
+ if let Ok ( mut os_rng) = os_rng_result {
1098
+ result = os_rng. try_fill_bytes ( dest) ;
1099
+ if result. is_ok ( ) {
1100
+ switch_rng = Some ( EntropySourceInner :: Os ( os_rng) ) ;
1101
+ } else {
1102
+ result = rng. try_fill_bytes ( dest) ; // use JitterRng
1103
+ }
1104
+ } else {
1105
+ result = rng. try_fill_bytes ( dest) ; // use JitterRng
1106
+ }
1107
+ }
1108
+ }
1109
+ }
1110
+ if let Some ( rng) = switch_rng {
1111
+ self . rng = rng;
1112
+ self . counter = 0 ;
1113
+ }
1114
+ result
1115
+ }
1116
+ }
1117
+
1018
1118
/// Generates a random value using the thread-local random number generator.
1019
1119
///
1020
1120
/// `random()` can generate various types of random things, and so may require
0 commit comments