@@ -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