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