Skip to content

Commit 445e929

Browse files
authored
Backport #165 (#171)
Solves #164 for the v0.1 branch
1 parent 48dfdb5 commit 445e929

File tree

2 files changed

+24
-13
lines changed

2 files changed

+24
-13
lines changed

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,17 @@ libc = { version = "0.2.64", default-features = false }
2929
wasi = "0.9"
3030

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

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

3839
[features]
3940
std = []
41+
# Enables wasm-bindgen implementation
42+
wasm-bindgen = ["bindgen", "js-sys"]
4043
# Enables dummy implementation for unsupported targets
4144
dummy = []
4245
# Unstable feature to support being a libstd dependency

src/wasm32_bindgen.rs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,21 @@ use core::cell::RefCell;
1313
use core::mem;
1414
use std::thread_local;
1515

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

1822
use crate::error::{BINDGEN_CRYPTO_UNDEF, BINDGEN_GRV_UNDEF};
1923
use crate::Error;
2024

25+
const CHUNK_SIZE: usize = 256;
26+
2127
#[derive(Clone, Debug)]
2228
enum RngSource {
2329
Node(NodeCrypto),
24-
Browser(BrowserCrypto),
30+
Browser(BrowserCrypto, Uint8Array),
2531
}
2632

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

4248
match source.as_ref().unwrap() {
4349
RngSource::Node(n) => n.random_fill_sync(dest),
44-
RngSource::Browser(n) => {
45-
// see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
46-
//
47-
// where it says:
48-
//
49-
// > A QuotaExceededError DOMException is thrown if the
50-
// > requested length is greater than 65536 bytes.
51-
for chunk in dest.chunks_mut(65536) {
52-
n.get_random_values(chunk)
50+
RngSource::Browser(crypto, buf) => {
51+
// getRandomValues does not work with all types of WASM memory,
52+
// so we initially write to browser memory to avoid exceptions.
53+
for chunk in dest.chunks_mut(CHUNK_SIZE) {
54+
// The chunk can be smaller than buf's length, so we call to
55+
// JS to create a smaller view of buf without allocation.
56+
let sub_buf = buf.subarray(0, chunk.len() as u32);
57+
58+
crypto.get_random_values(&sub_buf);
59+
sub_buf.copy_to(chunk);
5360
}
5461
}
5562
};
@@ -75,7 +82,8 @@ fn getrandom_init() -> Result<RngSource, Error> {
7582
return Err(BINDGEN_GRV_UNDEF);
7683
}
7784

78-
return Ok(RngSource::Browser(crypto));
85+
let buf = Uint8Array::new_with_length(CHUNK_SIZE as u32);
86+
return Ok(RngSource::Browser(crypto, buf));
7987
}
8088

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

107115
#[derive(Clone, Debug)]
108116
type NodeCrypto;

0 commit comments

Comments
 (0)