Skip to content

Commit

Permalink
Backport #165 (#171)
Browse files Browse the repository at this point in the history
Solves #164 for the v0.1 branch
  • Loading branch information
josephlr committed Dec 7, 2020
1 parent 48dfdb5 commit 445e929
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 13 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,17 @@ libc = { version = "0.2.64", default-features = false }
wasi = "0.9"

[target.wasm32-unknown-unknown.dependencies]
wasm-bindgen = { version = "0.2.29", optional = true }
bindgen = { package = "wasm-bindgen", version = "0.2.29", optional = true }
js-sys = { version = "0.3", optional = true }
stdweb = { version = "0.4.18", optional = true }

[target.wasm32-unknown-unknown.dev-dependencies]
wasm-bindgen-test = "0.2"

[features]
std = []
# Enables wasm-bindgen implementation
wasm-bindgen = ["bindgen", "js-sys"]
# Enables dummy implementation for unsupported targets
dummy = []
# Unstable feature to support being a libstd dependency
Expand Down
32 changes: 20 additions & 12 deletions src/wasm32_bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,21 @@ use core::cell::RefCell;
use core::mem;
use std::thread_local;

use js_sys::Uint8Array;
// We have to rename wasm_bindgen to bindgen in the Cargo.toml for backwards
// compatibility. We have to rename it back here or else the macros will break.
extern crate bindgen as wasm_bindgen;
use wasm_bindgen::prelude::*;

use crate::error::{BINDGEN_CRYPTO_UNDEF, BINDGEN_GRV_UNDEF};
use crate::Error;

const CHUNK_SIZE: usize = 256;

#[derive(Clone, Debug)]
enum RngSource {
Node(NodeCrypto),
Browser(BrowserCrypto),
Browser(BrowserCrypto, Uint8Array),
}

// JsValues are always per-thread, so we initialize RngSource for each thread.
Expand All @@ -41,15 +47,16 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {

match source.as_ref().unwrap() {
RngSource::Node(n) => n.random_fill_sync(dest),
RngSource::Browser(n) => {
// see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
//
// where it says:
//
// > A QuotaExceededError DOMException is thrown if the
// > requested length is greater than 65536 bytes.
for chunk in dest.chunks_mut(65536) {
n.get_random_values(chunk)
RngSource::Browser(crypto, buf) => {
// getRandomValues does not work with all types of WASM memory,
// so we initially write to browser memory to avoid exceptions.
for chunk in dest.chunks_mut(CHUNK_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() as u32);

crypto.get_random_values(&sub_buf);
sub_buf.copy_to(chunk);
}
}
};
Expand All @@ -75,7 +82,8 @@ fn getrandom_init() -> Result<RngSource, Error> {
return Err(BINDGEN_GRV_UNDEF);
}

return Ok(RngSource::Browser(crypto));
let buf = Uint8Array::new_with_length(CHUNK_SIZE as u32);
return Ok(RngSource::Browser(crypto, buf));
}

return Ok(RngSource::Node(MODULE.require("crypto")));
Expand All @@ -102,7 +110,7 @@ extern "C" {
#[wasm_bindgen(method, js_name = getRandomValues, structural, getter)]
fn get_random_values_fn(me: &BrowserCrypto) -> JsValue;
#[wasm_bindgen(method, js_name = getRandomValues, structural)]
fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]);
fn get_random_values(me: &BrowserCrypto, buf: &Uint8Array);

#[derive(Clone, Debug)]
type NodeCrypto;
Expand Down

0 comments on commit 445e929

Please sign in to comment.