@@ -6,7 +6,8 @@ use getrandom::{Error, register_custom_getrandom};
66use  core:: arch:: { asm,  global_asm} ; 
77use  std:: { 
88    alloc:: { Layout ,  alloc_zeroed} , 
9-     ptr:: null, 
9+     ptr, 
10+     sync:: atomic:: { AtomicU32 ,  Ordering } , 
1011} ; 
1112
1213#[ cfg( target_arch = "riscv32" ) ]  
@@ -37,7 +38,7 @@ pub extern "C" fn sys_alloc_words(nwords: usize) -> *mut u32 {
3738#[ unsafe( no_mangle) ]  
3839#[ linkage = "weak" ]  
3940pub  extern  "C"  fn  sys_getenv ( _name :  * const  u8 )  -> * const  u8  { 
40-     null ( ) 
41+     ptr :: null ( ) 
4142} 
4243
4344/// Generates random bytes. 
@@ -49,26 +50,37 @@ pub extern "C" fn sys_getenv(_name: *const u8) -> *const u8 {
4950#[ unsafe( no_mangle) ]  
5051#[ linkage = "weak" ]  
5152pub  unsafe  extern  "C"  fn  sys_rand ( recv_buf :  * mut  u8 ,  words :  usize )  { 
52-     unsafe  fn  step ( )  -> u32  { 
53-         static  mut  X :  u32  = 0xae569764 ; 
54-         // We are stealing Borland Delphi's random number generator. 
55-         // The random numbers here are only good enough to make eg 
56-         // HashMap work. 
53+     // We are stealing Borland Delphi's random number generator. 
54+     // The random numbers here are only good enough to make eg 
55+     // HashMap work. 
56+     fn  step ( )  -> u32  { 
57+         static  X :  AtomicU32  = AtomicU32 :: new ( 0xae569764 ) ; 
58+         let  rslt = X . fetch_update ( Ordering :: Relaxed ,  Ordering :: Relaxed ,  |x| { 
59+             Some ( x. wrapping_mul ( 134775813 ) . wrapping_add ( 1 ) ) 
60+         } ) ; 
61+         match  rslt { 
62+             Ok ( el)  => el, 
63+             Err ( err)  => err, 
64+         } 
65+     } 
66+     let  mut  idx = 0 ; 
67+     let  steps = words / 4 ; 
68+     let  rest = words % 4 ; 
69+     for  _ in  0 ..steps { 
70+         let  bytes = step ( ) . to_le_bytes ( ) ; 
71+         // SAFETY: Up to the caller 
5772        unsafe  { 
58-             X  = X . wrapping_mul ( 134775813 )  + 1 ; 
59-             X 
73+             ptr:: copy_nonoverlapping ( bytes. as_ptr ( ) ,  recv_buf. add ( idx) ,  4 ) ; 
6074        } 
75+         idx = idx. wrapping_add ( 4 ) ; 
6176    } 
62-     // TODO(Matthias): this is a bit inefficient, 
63-     // we could fill whole u32 words at a time. 
64-     // But it's just for testing. 
65-     for  i in  0 ..words { 
77+     let  [ a,  b,  c,  _]  = step ( ) . to_le_bytes ( ) ; 
78+     for  ( _,  el)  in  ( 0 ..rest) . zip ( [ a,  b,  c] )  { 
79+         // SAFETY: Up to the caller 
6680        unsafe  { 
67-             let  element = recv_buf. add ( i) ; 
68-             // The lower bits ain't really random, so might as well take 
69-             // the higher order ones, if we are only using 8 bits. 
70-             * element = step ( ) . to_le_bytes ( ) [ 3 ] ; 
81+             * recv_buf. add ( idx)  = el; 
7182        } 
83+         idx = idx. wrapping_add ( 1 ) ; 
7284    } 
7385} 
7486
@@ -153,3 +165,17 @@ unsafe extern "C" {
153165    // The address of this variable is the start of the stack (growing downwards). 
154166    static  _stack_start:  u8 ; 
155167} 
168+ 
169+ #[ cfg( test) ]  
170+ mod  tests { 
171+     use  crate :: sys_rand; 
172+ 
173+     #[ test]  
174+     fn  fills_with_random_bytes ( )  { 
175+         let  mut  buf = [ 0u8 ;  65 ] ; 
176+         unsafe  { 
177+             sys_rand ( buf. as_mut_ptr ( ) ,  buf. len ( ) ) ; 
178+         } 
179+         assert_ne ! ( buf,  [ 0u8 ;  65 ] ) ; 
180+     } 
181+ } 
0 commit comments