-
Notifications
You must be signed in to change notification settings - Fork 248
Web optimizations #559
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Web optimizations #559
Changes from 5 commits
1dbda17
d804258
b2ab9a1
02507fe
dcd8f4a
e024029
6feb9b7
65ba727
055a7c2
ec6f289
cf72d6c
e5d68a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,32 +7,48 @@ pub use crate::util::{inner_u32, inner_u64}; | |
| #[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))] | ||
| compile_error!("`wasm_js` backend can be enabled only for OS-less WASM targets!"); | ||
|
|
||
| use js_sys::{global, Uint8Array}; | ||
| use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}; | ||
| #[cfg(target_feature = "atomics")] | ||
| use js_sys::Uint8Array; | ||
newpavlov marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; | ||
|
|
||
| // Size of our temporary Uint8Array buffer used with WebCrypto methods | ||
| // Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues | ||
| const CRYPTO_BUFFER_SIZE: u16 = 256; | ||
| // Maximum buffer size allowed in `Crypto.getRandomValuesSize` is 65536 bytes. | ||
| // See https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues | ||
| const MAX_BUFFER_SIZE: u16 = 256; | ||
daxpedda marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> { | ||
| let global: Global = global().unchecked_into(); | ||
| let crypto = global.crypto(); | ||
| CRYPTO.with(|crypto| { | ||
| let crypto = crypto.as_ref().ok_or(Error::WEB_CRYPTO)?; | ||
| inner(crypto, dest) | ||
| }) | ||
| } | ||
|
|
||
| if !crypto.is_object() { | ||
| return Err(Error::WEB_CRYPTO); | ||
| #[cfg(not(target_feature = "atomics"))] | ||
| fn inner(crypto: &Crypto, dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> { | ||
| for chunk in dest.chunks_mut(MAX_BUFFER_SIZE.into()) { | ||
| if crypto.get_random_values(chunk).is_err() { | ||
| return Err(Error::WEB_GET_RANDOM_VALUES); | ||
| } | ||
| } | ||
| Ok(()) | ||
| } | ||
|
|
||
| #[cfg(target_feature = "atomics")] | ||
| fn inner(crypto: &Crypto, dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> { | ||
| // getRandomValues does not work with all types of WASM memory, | ||
| // so we initially write to browser memory to avoid exceptions. | ||
| let buf = Uint8Array::new_with_length(CRYPTO_BUFFER_SIZE.into()); | ||
| for chunk in dest.chunks_mut(CRYPTO_BUFFER_SIZE.into()) { | ||
| let buf = Uint8Array::new_with_length(MAX_BUFFER_SIZE.into()); | ||
| for chunk in dest.chunks_mut(MAX_BUFFER_SIZE.into()) { | ||
| let chunk_len: u32 = chunk | ||
| .len() | ||
| .try_into() | ||
| .expect("chunk length is bounded by CRYPTO_BUFFER_SIZE"); | ||
| .expect("chunk length is bounded by MAX_BUFFER_SIZE"); | ||
| // The chunk can be smaller than buf's length, so we call to | ||
| // JS to create a smaller view of buf without allocation. | ||
| let sub_buf = buf.subarray(0, chunk_len); | ||
| let sub_buf = if chunk_len == u32::from(MAX_BUFFER_SIZE) { | ||
| buf.clone() | ||
daxpedda marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } else { | ||
| buf.subarray(0, chunk_len) | ||
| }; | ||
|
|
||
| if crypto.get_random_values(&sub_buf).is_err() { | ||
| return Err(Error::WEB_GET_RANDOM_VALUES); | ||
|
|
@@ -46,14 +62,16 @@ pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> { | |
|
|
||
| #[wasm_bindgen] | ||
| extern "C" { | ||
| // Return type of js_sys::global() | ||
| type Global; | ||
| // Web Crypto API: Crypto interface (https://www.w3.org/TR/WebCryptoAPI/) | ||
| type Crypto; | ||
| // Getters for the Crypto API | ||
| #[wasm_bindgen(method, getter)] | ||
| fn crypto(this: &Global) -> Crypto; | ||
| // Holds the global `Crypto` object. | ||
| #[wasm_bindgen(thread_local_v2, js_name = crypto)] | ||
|
||
| static CRYPTO: Option<Crypto>; | ||
| // Crypto.getRandomValues() | ||
| #[cfg(not(target_feature = "atomics"))] | ||
| #[wasm_bindgen(method, js_name = getRandomValues, catch)] | ||
|
||
| fn get_random_values(this: &Crypto, buf: &mut [MaybeUninit<u8>]) -> Result<(), JsValue>; | ||
| #[cfg(target_feature = "atomics")] | ||
| #[wasm_bindgen(method, js_name = getRandomValues, catch)] | ||
| fn get_random_values(this: &Crypto, buf: &Uint8Array) -> Result<(), JsValue>; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.