11//! Implementation for WASM based on Web and Node.js
2+
23use crate :: Error ;
34use core:: mem:: MaybeUninit ;
45
@@ -7,52 +8,47 @@ pub use crate::util::{inner_u32, inner_u64};
78#[ cfg( not( all( target_arch = "wasm32" , any( target_os = "unknown" , target_os = "none" ) ) ) ) ]
89compile_error ! ( "`wasm_js` backend can be enabled only for OS-less WASM targets!" ) ;
910
10- use js_sys:: { global , Uint8Array } ;
11- use wasm_bindgen:: { prelude:: wasm_bindgen, JsCast , JsValue } ;
11+ use js_sys:: Uint8Array ;
12+ use wasm_bindgen:: { prelude:: wasm_bindgen, JsValue } ;
1213
1314// Size of our temporary Uint8Array buffer used with WebCrypto methods
1415// Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
1516const CRYPTO_BUFFER_SIZE : u16 = 256 ;
1617
1718pub fn fill_inner ( dest : & mut [ MaybeUninit < u8 > ] ) -> Result < ( ) , Error > {
18- let global : Global = global ( ) . unchecked_into ( ) ;
19- let crypto = global . crypto ( ) ;
20-
21- if !crypto . is_object ( ) {
22- return Err ( Error :: WEB_CRYPTO ) ;
23- }
24-
25- // getRandomValues does not work with all types of WASM memory,
26- // so we initially write to browser memory to avoid exceptions.
27- let buf = Uint8Array :: new_with_length ( CRYPTO_BUFFER_SIZE . into ( ) ) ;
28- for chunk in dest . chunks_mut ( CRYPTO_BUFFER_SIZE . into ( ) ) {
29- let chunk_len : u32 = chunk
30- . len ( )
31- . try_into ( )
32- . expect ( "chunk length is bounded by CRYPTO_BUFFER_SIZE" ) ;
33- // The chunk can be smaller than buf's length, so we call to
34- // JS to create a smaller view of buf without allocation.
35- let sub_buf = buf . subarray ( 0 , chunk_len ) ;
36-
37- if crypto . get_random_values ( & sub_buf) . is_err ( ) {
38- return Err ( Error :: WEB_GET_RANDOM_VALUES ) ;
19+ CRYPTO . with ( |crypto| {
20+ let crypto = crypto. as_ref ( ) . ok_or ( Error :: WEB_CRYPTO ) ? ;
21+
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 = buf . subarray ( 0 , chunk_len ) ;
33+
34+ if crypto . get_random_values ( & sub_buf ) . is_err ( ) {
35+ return Err ( Error :: WEB_GET_RANDOM_VALUES ) ;
36+ }
37+
38+ // SAFETY: ` sub_buf`'s length is the same length as `chunk`
39+ unsafe { sub_buf . raw_copy_to_ptr ( chunk . as_mut_ptr ( ) . cast :: < u8 > ( ) ) } ;
3940 }
40-
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 > ( ) ) } ;
43- }
44- Ok ( ( ) )
41+ Ok ( ( ) )
42+ } )
4543}
4644
4745#[ wasm_bindgen]
4846extern "C" {
49- // Return type of js_sys::global()
50- type Global ;
5147 // Web Crypto API: Crypto interface (https://www.w3.org/TR/WebCryptoAPI/)
5248 type Crypto ;
53- // Getters for the Crypto API
54- #[ wasm_bindgen( method , getter ) ]
55- fn crypto ( this : & Global ) -> Crypto ;
49+ // Holds the global ` Crypto` object.
50+ #[ wasm_bindgen( thread_local_v2 , js_name = crypto ) ]
51+ static CRYPTO : Option < Crypto > ;
5652 // Crypto.getRandomValues()
5753 #[ wasm_bindgen( method, js_name = getRandomValues, catch) ]
5854 fn get_random_values ( this : & Crypto , buf : & Uint8Array ) -> Result < ( ) , JsValue > ;
0 commit comments