@@ -13,15 +13,21 @@ 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+ const CHUNK_SIZE : usize = 256 ;
26+
2127#[ derive( Clone , Debug ) ]
2228enum RngSource {
2329 Node ( NodeCrypto ) ,
24- Browser ( BrowserCrypto ) ,
30+ Browser ( BrowserCrypto , Uint8Array ) ,
2531}
2632
2733// JsValues are always per-thread, so we initialize RngSource for each thread.
@@ -41,15 +47,16 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
4147
4248 match source. as_ref ( ) . unwrap ( ) {
4349 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)
50+ RngSource :: Browser ( crypto, buf) => {
51+ // getRandomValues does not work with all types of WASM memory,
52+ // so we initially write to browser memory to avoid exceptions.
53+ for chunk in dest. chunks_mut ( CHUNK_SIZE ) {
54+ // The chunk can be smaller than buf's length, so we call to
55+ // JS to create a smaller view of buf without allocation.
56+ let sub_buf = buf. subarray ( 0 , chunk. len ( ) as u32 ) ;
57+
58+ crypto. get_random_values ( & sub_buf) ;
59+ sub_buf. copy_to ( chunk) ;
5360 }
5461 }
5562 } ;
@@ -75,7 +82,8 @@ fn getrandom_init() -> Result<RngSource, Error> {
7582 return Err ( BINDGEN_GRV_UNDEF ) ;
7683 }
7784
78- return Ok ( RngSource :: Browser ( crypto) ) ;
85+ let buf = Uint8Array :: new_with_length ( CHUNK_SIZE as u32 ) ;
86+ return Ok ( RngSource :: Browser ( crypto, buf) ) ;
7987 }
8088
8189 return Ok ( RngSource :: Node ( MODULE . require ( "crypto" ) ) ) ;
@@ -102,7 +110,7 @@ extern "C" {
102110 #[ wasm_bindgen( method, js_name = getRandomValues, structural, getter) ]
103111 fn get_random_values_fn ( me : & BrowserCrypto ) -> JsValue ;
104112 #[ wasm_bindgen( method, js_name = getRandomValues, structural) ]
105- fn get_random_values ( me : & BrowserCrypto , buf : & mut [ u8 ] ) ;
113+ fn get_random_values ( me : & BrowserCrypto , buf : & Uint8Array ) ;
106114
107115 #[ derive( Clone , Debug ) ]
108116 type NodeCrypto ;
0 commit comments