Skip to content

Commit 6965655

Browse files
committed
Backport rust-random#165
Solves rust-random#164 for the v0.1 branch Signed-off-by: Joe Richey <joerichey@google.com>
1 parent 48dfdb5 commit 6965655

2 files changed

Lines changed: 25 additions & 13 deletions

File tree

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: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,22 @@ 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+
// Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
26+
const BROWSER_CRYPTO_BUFFER_SIZE: usize = 256;
27+
2128
#[derive(Clone, Debug)]
2229
enum RngSource {
2330
Node(NodeCrypto),
24-
Browser(BrowserCrypto),
31+
Browser(BrowserCrypto, Uint8Array),
2532
}
2633

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

4249
match source.as_ref().unwrap() {
4350
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)
51+
RngSource::Browser(crypto, buf) => {
52+
// getRandomValues does not work with all types of WASM memory,
53+
// so we initially write to browser memory to avoid exceptions.
54+
for chunk in dest.chunks_mut(BROWSER_CRYPTO_BUFFER_SIZE) {
55+
// The chunk can be smaller than buf's length, so we call to
56+
// JS to create a smaller view of buf without allocation.
57+
let sub_buf = buf.subarray(0, chunk.len() as u32);
58+
59+
crypto.get_random_values(&sub_buf);
60+
sub_buf.copy_to(chunk);
5361
}
5462
}
5563
};
@@ -75,7 +83,8 @@ fn getrandom_init() -> Result<RngSource, Error> {
7583
return Err(BINDGEN_GRV_UNDEF);
7684
}
7785

78-
return Ok(RngSource::Browser(crypto));
86+
let buf = Uint8Array::new_with_length(BROWSER_CRYPTO_BUFFER_SIZE as u32);
87+
return Ok(RngSource::Browser(crypto, buf));
7988
}
8089

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

107116
#[derive(Clone, Debug)]
108117
type NodeCrypto;

0 commit comments

Comments
 (0)