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