@@ -10,11 +10,15 @@ use crate::Error;
1010extern crate std;
1111use std:: thread_local;
1212
13+ use js_sys:: Uint8Array ;
1314use wasm_bindgen:: prelude:: * ;
1415
16+ // Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
17+ const BROWSER_CRYPTO_BUFFER_SIZE : usize = 256 ;
18+
1519enum RngSource {
1620 Node ( NodeCrypto ) ,
17- Browser ( BrowserCrypto ) ,
21+ Browser ( BrowserCrypto , Uint8Array ) ,
1822}
1923
2024// JsValues are always per-thread, so we initialize RngSource for each thread.
@@ -33,17 +37,18 @@ pub(crate) fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
3337 return Err ( Error :: NODE_RANDOM_FILL_SYNC ) ;
3438 }
3539 }
36- RngSource :: Browser ( n ) => {
37- // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/ getRandomValues
38- //
39- // where it says:
40- //
41- // > A QuotaExceededError DOMException is thrown if the
42- // > requested length is greater than 65536 bytes.
43- for chunk in dest . chunks_mut ( 65536 ) {
44- if n . get_random_values ( chunk ) . is_err ( ) {
40+ RngSource :: Browser ( crypto , buf ) => {
41+ // getRandomValues does not work with all types of WASM memory,
42+ // so we initially write to browser memory to avoid exceptions.
43+ for chunk in dest . chunks_mut ( BROWSER_CRYPTO_BUFFER_SIZE ) {
44+ // The chunk can be smaller than buf's length, so we call to
45+ // JS to create a smaller view of buf without allocation.
46+ let sub_buf = buf . subarray ( 0 , chunk . len ( ) as u32 ) ;
47+
48+ if crypto . get_random_values ( & sub_buf ) . is_err ( ) {
4549 return Err ( Error :: WEB_GET_RANDOM_VALUES ) ;
4650 }
51+ sub_buf. copy_to ( chunk) ;
4752 }
4853 }
4954 } ;
@@ -63,7 +68,9 @@ fn getrandom_init() -> Result<RngSource, Error> {
6368 ( _, crypto) if !crypto. is_undefined ( ) => crypto,
6469 _ => return Err ( Error :: WEB_CRYPTO ) ,
6570 } ;
66- return Ok ( RngSource :: Browser ( crypto) ) ;
71+
72+ let buf = Uint8Array :: new_with_length ( BROWSER_CRYPTO_BUFFER_SIZE as u32 ) ;
73+ return Ok ( RngSource :: Browser ( crypto, buf) ) ;
6774 }
6875
6976 let crypto = MODULE . require ( "crypto" ) . map_err ( |_| Error :: NODE_CRYPTO ) ?;
@@ -84,7 +91,7 @@ extern "C" {
8491
8592 type BrowserCrypto ;
8693 #[ wasm_bindgen( method, js_name = getRandomValues, catch) ]
87- fn get_random_values ( me : & BrowserCrypto , buf : & mut [ u8 ] ) -> Result < ( ) , JsValue > ;
94+ fn get_random_values ( me : & BrowserCrypto , buf : & Uint8Array ) -> Result < ( ) , JsValue > ;
8895
8996 #[ wasm_bindgen( js_name = module) ]
9097 static MODULE : NodeModule ;
0 commit comments