@@ -8,39 +8,51 @@ pub use crate::util::{inner_u32, inner_u64};
88#[ cfg( not( all( target_arch = "wasm32" , any( target_os = "unknown" , target_os = "none" ) ) ) ) ]
99compile_error ! ( "`wasm_js` backend can be enabled only for OS-less WASM targets!" ) ;
1010
11+ #[ cfg( target_feature = "atomics" ) ]
1112use js_sys:: Uint8Array ;
1213use wasm_bindgen:: { prelude:: wasm_bindgen, JsValue } ;
1314
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 ;
1718
1819pub fn fill_inner ( dest : & mut [ MaybeUninit < u8 > ] ) -> Result < ( ) , Error > {
1920 CRYPTO . with ( |crypto| {
2021 let crypto = crypto. as_ref ( ) . ok_or ( Error :: WEB_CRYPTO ) ?;
2122
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+ }
4029 }
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+ }
4152
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+ }
4456 }
4557 Ok ( ( ) )
4658 } )
@@ -54,6 +66,10 @@ extern "C" {
5466 #[ wasm_bindgen( thread_local_v2, js_name = crypto) ]
5567 static CRYPTO : Option < Crypto > ;
5668 // 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" ) ]
5773 #[ wasm_bindgen( method, js_name = getRandomValues, catch) ]
5874 fn get_random_values ( this : & Crypto , buf : & Uint8Array ) -> Result < ( ) , JsValue > ;
5975}
0 commit comments