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