@@ -10,11 +10,15 @@ use crate::Error;
10
10
extern crate std;
11
11
use std:: thread_local;
12
12
13
+ use js_sys:: Uint8Array ;
13
14
use wasm_bindgen:: prelude:: * ;
14
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
+
15
19
enum RngSource {
16
20
Node ( NodeCrypto ) ,
17
- Browser ( BrowserCrypto ) ,
21
+ Browser ( BrowserCrypto , Uint8Array ) ,
18
22
}
19
23
20
24
// 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> {
33
37
return Err ( Error :: NODE_RANDOM_FILL_SYNC ) ;
34
38
}
35
39
}
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 ( ) {
45
49
return Err ( Error :: WEB_GET_RANDOM_VALUES ) ;
46
50
}
51
+ sub_buf. copy_to ( chunk) ;
47
52
}
48
53
}
49
54
} ;
@@ -63,7 +68,9 @@ fn getrandom_init() -> Result<RngSource, Error> {
63
68
( _, crypto) if !crypto. is_undefined ( ) => crypto,
64
69
_ => return Err ( Error :: WEB_CRYPTO ) ,
65
70
} ;
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) ) ;
67
74
}
68
75
69
76
let crypto = MODULE . require ( "crypto" ) . map_err ( |_| Error :: NODE_CRYPTO ) ?;
@@ -84,7 +91,7 @@ extern "C" {
84
91
85
92
type BrowserCrypto ;
86
93
#[ 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 > ;
88
95
89
96
#[ wasm_bindgen( js_name = module) ]
90
97
static MODULE : NodeModule ;
0 commit comments