@@ -13,15 +13,22 @@ use core::cell::RefCell;
1313use core:: mem;
1414use std:: thread_local;
1515
16+ use js_sys:: Uint8Array ;
17+ // We have to rename wasm_bindgen to bindgen in the Cargo.toml for backwards
18+ // compatibility. We have to rename it back here or else the macros will break.
19+ extern crate bindgen as wasm_bindgen;
1620use wasm_bindgen:: prelude:: * ;
1721
1822use crate :: error:: { BINDGEN_CRYPTO_UNDEF , BINDGEN_GRV_UNDEF } ;
1923use crate :: Error ;
2024
25+ // Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
26+ const BROWSER_CRYPTO_BUFFER_SIZE : usize = 256 ;
27+
2128#[ derive( Clone , Debug ) ]
2229enum RngSource {
2330 Node ( NodeCrypto ) ,
24- Browser ( BrowserCrypto ) ,
31+ Browser ( BrowserCrypto , Uint8Array ) ,
2532}
2633
2734// JsValues are always per-thread, so we initialize RngSource for each thread.
@@ -41,15 +48,16 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
4148
4249 match source. as_ref ( ) . unwrap ( ) {
4350 RngSource :: Node ( n) => n. random_fill_sync ( dest) ,
44- RngSource :: Browser ( n) => {
45- // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
46- //
47- // where it says:
48- //
49- // > A QuotaExceededError DOMException is thrown if the
50- // > requested length is greater than 65536 bytes.
51- for chunk in dest. chunks_mut ( 65536 ) {
52- n. get_random_values ( chunk)
51+ RngSource :: Browser ( crypto, buf) => {
52+ // getRandomValues does not work with all types of WASM memory,
53+ // so we initially write to browser memory to avoid exceptions.
54+ for chunk in dest. chunks_mut ( BROWSER_CRYPTO_BUFFER_SIZE ) {
55+ // The chunk can be smaller than buf's length, so we call to
56+ // JS to create a smaller view of buf without allocation.
57+ let sub_buf = buf. subarray ( 0 , chunk. len ( ) as u32 ) ;
58+
59+ crypto. get_random_values ( & sub_buf) ;
60+ sub_buf. copy_to ( chunk) ;
5361 }
5462 }
5563 } ;
@@ -75,7 +83,8 @@ fn getrandom_init() -> Result<RngSource, Error> {
7583 return Err ( BINDGEN_GRV_UNDEF ) ;
7684 }
7785
78- return Ok ( RngSource :: Browser ( crypto) ) ;
86+ let buf = Uint8Array :: new_with_length ( BROWSER_CRYPTO_BUFFER_SIZE as u32 ) ;
87+ return Ok ( RngSource :: Browser ( crypto, buf) ) ;
7988 }
8089
8190 return Ok ( RngSource :: Node ( MODULE . require ( "crypto" ) ) ) ;
@@ -102,7 +111,7 @@ extern "C" {
102111 #[ wasm_bindgen( method, js_name = getRandomValues, structural, getter) ]
103112 fn get_random_values_fn ( me : & BrowserCrypto ) -> JsValue ;
104113 #[ wasm_bindgen( method, js_name = getRandomValues, structural) ]
105- fn get_random_values ( me : & BrowserCrypto , buf : & mut [ u8 ] ) ;
114+ fn get_random_values ( me : & BrowserCrypto , buf : & Uint8Array ) ;
106115
107116 #[ derive( Clone , Debug ) ]
108117 type NodeCrypto ;
0 commit comments