@@ -7,39 +7,51 @@ pub use crate::util::{inner_u32, inner_u64};
7
7
#[ cfg( not( all( target_arch = "wasm32" , any( target_os = "unknown" , target_os = "none" ) ) ) ) ]
8
8
compile_error ! ( "`wasm_js` backend can be enabled only for OS-less WASM targets!" ) ;
9
9
10
+ #[ cfg( target_feature = "atomics" ) ]
10
11
use js_sys:: Uint8Array ;
11
12
use wasm_bindgen:: { prelude:: wasm_bindgen, JsValue } ;
12
13
13
- // Size of our temporary Uint8Array buffer used with WebCrypto methods
14
- // Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
15
- const CRYPTO_BUFFER_SIZE : u16 = 256 ;
14
+ // Maximum buffer size allowed in `Crypto.getRandomValuesSize` is 65536 bytes.
15
+ // See https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
16
+ const MAX_BUFFER_SIZE : u16 = 256 ;
16
17
17
18
pub fn fill_inner ( dest : & mut [ MaybeUninit < u8 > ] ) -> Result < ( ) , Error > {
18
19
CRYPTO . with ( |crypto| {
19
20
let crypto = crypto. as_ref ( ) . ok_or ( Error :: WEB_CRYPTO ) ?;
20
21
21
- // getRandomValues does not work with all types of WASM memory,
22
- // so we initially write to browser memory to avoid exceptions.
23
- let buf = Uint8Array :: new_with_length ( CRYPTO_BUFFER_SIZE . into ( ) ) ;
24
- for chunk in dest. chunks_mut ( CRYPTO_BUFFER_SIZE . into ( ) ) {
25
- let chunk_len: u32 = chunk
26
- . len ( )
27
- . try_into ( )
28
- . expect ( "chunk length is bounded by CRYPTO_BUFFER_SIZE" ) ;
29
- // The chunk can be smaller than buf's length, so we call to
30
- // JS to create a smaller view of buf without allocation.
31
- let sub_buf = if chunk_len == u32:: from ( CRYPTO_BUFFER_SIZE ) {
32
- buf. clone ( )
33
- } else {
34
- buf. subarray ( 0 , chunk_len)
35
- } ;
36
-
37
- if crypto. get_random_values ( & sub_buf) . is_err ( ) {
38
- return Err ( Error :: WEB_GET_RANDOM_VALUES ) ;
22
+ #[ cfg( not( target_feature = "atomics" ) ) ]
23
+ {
24
+ for chunk in dest. chunks_mut ( MAX_BUFFER_SIZE . into ( ) ) {
25
+ if crypto. get_random_values ( chunk) . is_err ( ) {
26
+ return Err ( Error :: WEB_GET_RANDOM_VALUES ) ;
27
+ }
39
28
}
29
+ }
30
+ #[ cfg( target_feature = "atomics" ) ]
31
+ {
32
+ // getRandomValues does not work with all types of WASM memory,
33
+ // so we initially write to browser memory to avoid exceptions.
34
+ let buf = Uint8Array :: new_with_length ( MAX_BUFFER_SIZE . into ( ) ) ;
35
+ for chunk in dest. chunks_mut ( MAX_BUFFER_SIZE . into ( ) ) {
36
+ let chunk_len: u32 = chunk
37
+ . len ( )
38
+ . try_into ( )
39
+ . expect ( "chunk length is bounded by MAX_BUFFER_SIZE" ) ;
40
+ // The chunk can be smaller than buf's length, so we call to
41
+ // JS to create a smaller view of buf without allocation.
42
+ let sub_buf = if chunk_len == u32:: from ( MAX_BUFFER_SIZE ) {
43
+ buf. clone ( )
44
+ } else {
45
+ buf. subarray ( 0 , chunk_len)
46
+ } ;
47
+
48
+ if crypto. get_random_values ( & sub_buf) . is_err ( ) {
49
+ return Err ( Error :: WEB_GET_RANDOM_VALUES ) ;
50
+ }
40
51
41
- // SAFETY: `sub_buf`'s length is the same length as `chunk`
42
- unsafe { sub_buf. raw_copy_to_ptr ( chunk. as_mut_ptr ( ) . cast :: < u8 > ( ) ) } ;
52
+ // SAFETY: `sub_buf`'s length is the same length as `chunk`
53
+ unsafe { sub_buf. raw_copy_to_ptr ( chunk. as_mut_ptr ( ) . cast :: < u8 > ( ) ) } ;
54
+ }
43
55
}
44
56
Ok ( ( ) )
45
57
} )
@@ -53,6 +65,10 @@ extern "C" {
53
65
#[ wasm_bindgen( thread_local_v2, js_name = crypto) ]
54
66
static CRYPTO : Option < Crypto > ;
55
67
// Crypto.getRandomValues()
68
+ #[ cfg( not( target_feature = "atomics" ) ) ]
69
+ #[ wasm_bindgen( method, js_name = getRandomValues, catch) ]
70
+ fn get_random_values ( this : & Crypto , buf : & mut [ MaybeUninit < u8 > ] ) -> Result < ( ) , JsValue > ;
71
+ #[ cfg( target_feature = "atomics" ) ]
56
72
#[ wasm_bindgen( method, js_name = getRandomValues, catch) ]
57
73
fn get_random_values ( this : & Crypto , buf : & Uint8Array ) -> Result < ( ) , JsValue > ;
58
74
}
0 commit comments