@@ -288,7 +288,7 @@ use prng::Isaac64Rng as IsaacWordRng;
288
288
289
289
use distributions:: { Range , IndependentSample } ;
290
290
use distributions:: range:: SampleRange ;
291
- #[ cfg( feature="std" ) ] use reseeding:: { ReseedingRng , ReseedWithNew } ;
291
+ #[ cfg( feature="std" ) ] use reseeding:: ReseedingRng ;
292
292
293
293
// public modules
294
294
pub mod distributions;
@@ -844,29 +844,7 @@ pub trait NewRng: SeedableRng {
844
844
#[ cfg( feature="std" ) ]
845
845
impl < R : SeedableRng > NewRng for R {
846
846
fn new ( ) -> Result < Self , Error > {
847
- // Note: error handling would be easier with try/catch blocks
848
- fn new_os < T : SeedableRng > ( ) -> Result < T , Error > {
849
- let mut r = OsRng :: new ( ) ?;
850
- T :: from_rng ( & mut r)
851
- }
852
-
853
- fn new_jitter < T : SeedableRng > ( ) -> Result < T , Error > {
854
- let mut r = JitterRng :: new ( ) ?;
855
- T :: from_rng ( & mut r)
856
- }
857
-
858
- trace ! ( "Seeding new RNG" ) ;
859
- new_os ( ) . or_else ( |e1| {
860
- warn ! ( "OsRng failed [falling back to JitterRng]: {:?}" , e1) ;
861
- new_jitter ( ) . map_err ( |_e2| {
862
- warn ! ( "JitterRng failed: {:?}" , _e2) ;
863
- // TODO: can we somehow return both error sources?
864
- Error :: with_cause (
865
- ErrorKind :: Unavailable ,
866
- "seeding a new RNG failed: both OS and Jitter entropy sources failed" ,
867
- e1)
868
- } )
869
- } )
847
+ R :: from_rng ( EntropyRng :: new ( ) )
870
848
}
871
849
}
872
850
@@ -964,20 +942,19 @@ pub fn weak_rng() -> XorShiftRng {
964
942
#[ cfg( feature="std" ) ]
965
943
#[ derive( Clone , Debug ) ]
966
944
pub struct ThreadRng {
967
- rng : Rc < RefCell < ReseedingRng < StdRng , ReseedWithNew > > > ,
945
+ rng : Rc < RefCell < ReseedingRng < StdRng , EntropyRng > > > ,
968
946
}
969
947
970
948
#[ cfg( feature="std" ) ]
971
949
thread_local ! (
972
- static THREAD_RNG_KEY : Rc <RefCell <ReseedingRng <StdRng , ReseedWithNew >>> = {
950
+ static THREAD_RNG_KEY : Rc <RefCell <ReseedingRng <StdRng , EntropyRng >>> = {
973
951
const THREAD_RNG_RESEED_THRESHOLD : u64 = 32_768 ;
974
- let r = match StdRng :: new( ) {
975
- Ok ( r) => r,
976
- Err ( e) => panic!( "could not initialize thread_rng: {:?}" , e)
977
- } ;
952
+ let mut entropy_source = EntropyRng :: new( ) ;
953
+ let r = StdRng :: from_rng( & mut entropy_source)
954
+ . expect( "could not initialize thread_rng" ) ;
978
955
let rng = ReseedingRng :: new( r,
979
956
THREAD_RNG_RESEED_THRESHOLD ,
980
- ReseedWithNew ) ;
957
+ entropy_source ) ;
981
958
Rc :: new( RefCell :: new( rng) )
982
959
}
983
960
) ;
@@ -1018,6 +995,127 @@ impl Rng for ThreadRng {
1018
995
}
1019
996
}
1020
997
998
+ /// An RNG provided specifically for seeding PRNG's.
999
+ ///
1000
+ /// `EntropyRng` uses the interface for random numbers provided by the operating
1001
+ /// system ([`OsRng`]). If that returns an error, it will fall back to the
1002
+ /// [`JitterRng`] entropy collector. Every time it will then check if `OsRng`
1003
+ /// is still not available, and switch back if possible.
1004
+ ///
1005
+ /// [`OsRng`]: os/struct.OsRng.html
1006
+ /// [`JitterRng`]: jitter/struct.JitterRng.html
1007
+ #[ cfg( feature="std" ) ]
1008
+ #[ derive( Debug ) ]
1009
+ pub struct EntropyRng {
1010
+ rng : EntropySource ,
1011
+ }
1012
+
1013
+ #[ cfg( feature="std" ) ]
1014
+ #[ derive( Debug ) ]
1015
+ enum EntropySource {
1016
+ Os ( OsRng ) ,
1017
+ Jitter ( JitterRng ) ,
1018
+ None ,
1019
+ }
1020
+
1021
+ #[ cfg( feature="std" ) ]
1022
+ impl EntropyRng {
1023
+ /// Create a new `EntropyRng`.
1024
+ ///
1025
+ /// This method will do no system calls or other initialization routines,
1026
+ /// those are done on first use. This is done to make `new` infallible,
1027
+ /// and `try_fill_bytes` the only place to report errors.
1028
+ pub fn new ( ) -> Self {
1029
+ EntropyRng { rng : EntropySource :: None }
1030
+ }
1031
+ }
1032
+
1033
+ #[ cfg( feature="std" ) ]
1034
+ impl Rng for EntropyRng {
1035
+ fn next_u32 ( & mut self ) -> u32 {
1036
+ impls:: next_u32_via_fill ( self )
1037
+ }
1038
+
1039
+ fn next_u64 ( & mut self ) -> u64 {
1040
+ impls:: next_u64_via_fill ( self )
1041
+ }
1042
+
1043
+ fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
1044
+ self . try_fill_bytes ( dest) . unwrap ( ) ;
1045
+ }
1046
+
1047
+ fn try_fill_bytes ( & mut self , dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
1048
+ fn try_os_new ( dest : & mut [ u8 ] ) -> Result < OsRng , Error >
1049
+ {
1050
+ let mut rng = OsRng :: new ( ) ?;
1051
+ rng. try_fill_bytes ( dest) ?;
1052
+ Ok ( rng)
1053
+ }
1054
+
1055
+ fn try_jitter_new ( dest : & mut [ u8 ] ) -> Result < JitterRng , Error >
1056
+ {
1057
+ let mut rng = JitterRng :: new ( ) ?;
1058
+ rng. try_fill_bytes ( dest) ?;
1059
+ Ok ( rng)
1060
+ }
1061
+
1062
+ let mut switch_rng = None ;
1063
+ match self . rng {
1064
+ EntropySource :: None => {
1065
+ let os_rng_result = try_os_new ( dest) ;
1066
+ match os_rng_result {
1067
+ Ok ( os_rng) => {
1068
+ switch_rng = Some ( EntropySource :: Os ( os_rng) ) ;
1069
+ }
1070
+ Err ( os_rng_error) => {
1071
+ warn ! ( "EntropyRng: OsRng failed [falling back to JitterRng]: {}" ,
1072
+ os_rng_error) ;
1073
+ match try_jitter_new ( dest) {
1074
+ Ok ( jitter_rng) => {
1075
+ switch_rng = Some ( EntropySource :: Jitter ( jitter_rng) ) ;
1076
+ }
1077
+ Err ( _jitter_error) => {
1078
+ warn ! ( "EntropyRng: JitterRng failed: {}" ,
1079
+ _jitter_error) ;
1080
+ return Err ( os_rng_error) ;
1081
+ }
1082
+ }
1083
+ }
1084
+ }
1085
+ }
1086
+ EntropySource :: Os ( ref mut rng) => {
1087
+ let os_rng_result = rng. try_fill_bytes ( dest) ;
1088
+ if let Err ( os_rng_error) = os_rng_result {
1089
+ warn ! ( "EntropyRng: OsRng failed [falling back to JitterRng]: {}" ,
1090
+ os_rng_error) ;
1091
+ match try_jitter_new ( dest) {
1092
+ Ok ( jitter_rng) => {
1093
+ switch_rng = Some ( EntropySource :: Jitter ( jitter_rng) ) ;
1094
+ }
1095
+ Err ( _jitter_error) => {
1096
+ warn ! ( "EntropyRng: JitterRng failed: {}" ,
1097
+ _jitter_error) ;
1098
+ return Err ( os_rng_error) ;
1099
+ }
1100
+ }
1101
+ }
1102
+ }
1103
+ EntropySource :: Jitter ( ref mut rng) => {
1104
+ if let Ok ( os_rng) = try_os_new ( dest) {
1105
+ info ! ( "EntropyRng: OsRng available [switching back from JitterRng]" ) ;
1106
+ switch_rng = Some ( EntropySource :: Os ( os_rng) ) ;
1107
+ } else {
1108
+ return rng. try_fill_bytes ( dest) ; // use JitterRng
1109
+ }
1110
+ }
1111
+ }
1112
+ if let Some ( rng) = switch_rng {
1113
+ self . rng = rng;
1114
+ }
1115
+ Ok ( ( ) )
1116
+ }
1117
+ }
1118
+
1021
1119
/// Generates a random value using the thread-local random number generator.
1022
1120
///
1023
1121
/// `random()` can generate various types of random things, and so may require
0 commit comments