1
1
//! Implementation for WASM based on Web and Node.js
2
+
2
3
use crate :: Error ;
3
4
use core:: mem:: MaybeUninit ;
4
5
@@ -7,52 +8,47 @@ pub use crate::util::{inner_u32, inner_u64};
7
8
#[ cfg( not( all( target_arch = "wasm32" , any( target_os = "unknown" , target_os = "none" ) ) ) ) ]
8
9
compile_error ! ( "`wasm_js` backend can be enabled only for OS-less WASM targets!" ) ;
9
10
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 } ;
12
13
13
14
// Size of our temporary Uint8Array buffer used with WebCrypto methods
14
15
// Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
15
16
const CRYPTO_BUFFER_SIZE : u16 = 256 ;
16
17
17
18
pub 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 > ( ) ) } ;
39
40
}
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
+ } )
45
43
}
46
44
47
45
#[ wasm_bindgen]
48
46
extern "C" {
49
- // Return type of js_sys::global()
50
- type Global ;
51
47
// Web Crypto API: Crypto interface (https://www.w3.org/TR/WebCryptoAPI/)
52
48
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 > ;
56
52
// Crypto.getRandomValues()
57
53
#[ wasm_bindgen( method, js_name = getRandomValues, catch) ]
58
54
fn get_random_values ( this : & Crypto , buf : & Uint8Array ) -> Result < ( ) , JsValue > ;
0 commit comments