summaryrefslogtreecommitdiff
path: root/vendor/getrandom/src/backends/wasm_js.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/getrandom/src/backends/wasm_js.rs')
-rw-r--r--vendor/getrandom/src/backends/wasm_js.rs72
1 files changed, 72 insertions, 0 deletions
diff --git a/vendor/getrandom/src/backends/wasm_js.rs b/vendor/getrandom/src/backends/wasm_js.rs
new file mode 100644
index 00000000..1320d9fc
--- /dev/null
+++ b/vendor/getrandom/src/backends/wasm_js.rs
@@ -0,0 +1,72 @@
+//! Implementation for WASM based on Web and Node.js
+use crate::Error;
+use core::mem::MaybeUninit;
+
+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 wasm_bindgen::{prelude::wasm_bindgen, JsValue};
+
+// 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: usize = 65536;
+
+#[cfg(not(target_feature = "atomics"))]
+#[inline]
+pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
+ for chunk in dest.chunks_mut(MAX_BUFFER_SIZE) {
+ if get_random_values(chunk).is_err() {
+ return Err(Error::WEB_CRYPTO);
+ }
+ }
+ Ok(())
+}
+
+#[cfg(target_feature = "atomics")]
+pub fn fill_inner(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_len = usize::min(dest.len(), MAX_BUFFER_SIZE);
+ let buf_len_u32 = buf_len
+ .try_into()
+ .expect("buffer length is bounded by MAX_BUFFER_SIZE");
+ let buf = js_sys::Uint8Array::new_with_length(buf_len_u32);
+ for chunk in dest.chunks_mut(buf_len) {
+ let chunk_len = chunk
+ .len()
+ .try_into()
+ .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 = if chunk_len == buf_len_u32 {
+ &buf
+ } else {
+ &buf.subarray(0, chunk_len)
+ };
+
+ if get_random_values(sub_buf).is_err() {
+ return Err(Error::WEB_CRYPTO);
+ }
+
+ sub_buf.copy_to_uninit(chunk);
+ }
+ Ok(())
+}
+
+#[wasm_bindgen]
+extern "C" {
+ // Crypto.getRandomValues()
+ #[cfg(not(target_feature = "atomics"))]
+ #[wasm_bindgen(js_namespace = ["globalThis", "crypto"], js_name = getRandomValues, catch)]
+ fn get_random_values(buf: &mut [MaybeUninit<u8>]) -> Result<(), JsValue>;
+ #[cfg(target_feature = "atomics")]
+ #[wasm_bindgen(js_namespace = ["globalThis", "crypto"], js_name = getRandomValues, catch)]
+ fn get_random_values(buf: &js_sys::Uint8Array) -> Result<(), JsValue>;
+}
+
+impl Error {
+ /// The environment does not support the Web Crypto API.
+ pub(crate) const WEB_CRYPTO: Error = Self::new_internal(10);
+}