@@ -11,10 +11,20 @@ extern crate std;
1111use std:: thread_local;
1212
1313use wasm_bindgen:: prelude:: * ;
14+ use js_sys:: Uint8Array ;
15+
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+
19+ struct BrowserCryptoContext {
20+ crypto : BrowserCrypto ,
21+ // A temporary buffer backed by browser memory to avoid multithreaded wasm exception. See issue #164
22+ buf : Uint8Array ,
23+ }
1424
1525enum RngSource {
1626 Node ( NodeCrypto ) ,
17- Browser ( BrowserCrypto ) ,
27+ Browser ( BrowserCryptoContext ) ,
1828}
1929
2030// JsValues are always per-thread, so we initialize RngSource for each thread.
@@ -33,17 +43,12 @@ pub(crate) fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
3343 return Err ( Error :: NODE_RANDOM_FILL_SYNC ) ;
3444 }
3545 }
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 ( ) {
46+ RngSource :: Browser ( ctx) => {
47+ for chunk in dest. chunks_mut ( BROWSER_CRYPTO_BUFFER_SIZE ) {
48+ if ctx. crypto . get_random_values ( & ctx. buf ) . is_err ( ) {
4549 return Err ( Error :: WEB_GET_RANDOM_VALUES ) ;
4650 }
51+ ctx. buf . copy_to ( chunk) ;
4752 }
4853 }
4954 } ;
@@ -63,7 +68,15 @@ 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+
74+ let ctx = BrowserCryptoContext {
75+ crypto,
76+ buf,
77+ } ;
78+
79+ return Ok ( RngSource :: Browser ( ctx) ) ;
6780 }
6881
6982 let crypto = MODULE . require ( "crypto" ) . map_err ( |_| Error :: NODE_CRYPTO ) ?;
@@ -84,7 +97,7 @@ extern "C" {
8497
8598 type BrowserCrypto ;
8699 #[ wasm_bindgen( method, js_name = getRandomValues, catch) ]
87- fn get_random_values ( me : & BrowserCrypto , buf : & mut [ u8 ] ) -> Result < ( ) , JsValue > ;
100+ fn get_random_values ( me : & BrowserCrypto , buf : & Uint8Array ) -> Result < ( ) , JsValue > ;
88101
89102 #[ wasm_bindgen( js_name = module) ]
90103 static MODULE : NodeModule ;
0 commit comments