Skip to content
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

Add support for Custom RNGs #109

Merged
merged 4 commits into from
Jan 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,12 @@ matrix:
# wasi tests
- cargo test --target wasm32-wasi
# stdweb tests (Node, Chrome)
- cargo web test --nodejs --target=wasm32-unknown-unknown --features=stdweb
- cargo web test --target=wasm32-unknown-unknown --features=stdweb
- cd custom/stdweb
- cargo web test --nodejs --target=wasm32-unknown-unknown
- cargo web test --target=wasm32-unknown-unknown
# wasm-bindgen tests (Node, Firefox, Chrome)
- cargo test --target wasm32-unknown-unknown --features=wasm-bindgen
- cd ../wasm-bindgen
- cargo test --target wasm32-unknown-unknown
- GECKODRIVER=$HOME/geckodriver cargo test --target wasm32-unknown-unknown --features=test-in-browser
- CHROMEDRIVER=$HOME/chromedriver cargo test --target wasm32-unknown-unknown --features=test-in-browser

Expand All @@ -83,6 +85,7 @@ matrix:
rust: nightly
os: linux
install:
- rustup target add wasm32-unknown-unknown
- cargo --list | egrep "^\s*deadlinks$" -q || cargo install cargo-deadlinks
- cargo deadlinks -V
script:
Expand All @@ -91,13 +94,15 @@ matrix:
- cargo test --benches
# Check that setting various features does not break the build
- cargo build --features=std
- cargo build --features=custom
# remove cached documentation, otherwise files from previous PRs can get included
- rm -rf target/doc
- cargo doc --no-deps --features=std
- cargo doc --no-deps --features=std,custom
- cargo doc --no-deps --manifest-path=custom/wasm-bindgen/Cargo.toml --target=wasm32-unknown-unknown
- cargo deadlinks --dir target/doc
# also test minimum dependency versions are usable
- cargo generate-lockfile -Z minimal-versions
- cargo test --features=std
- cargo test --features=std,custom

- <<: *nightly_and_docs
name: "OSX, nightly, docs"
Expand Down
19 changes: 9 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ exclude = ["utils/*", ".*", "appveyor.yml"]
travis-ci = { repository = "rust-random/getrandom" }
appveyor = { repository = "rust-random/getrandom" }

[workspace]
members = [
"custom/stdweb",
"custom/wasm-bindgen",
]

[dependencies]
cfg-if = "0.1.2"

Expand All @@ -27,19 +33,12 @@ libc = { version = "0.2.64", default-features = false }
[target.'cfg(target_os = "wasi")'.dependencies]
wasi = "0.9"

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

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

[features]
std = []
# Feature to enable custom RNG implementations
custom = []
# Unstable feature to support being a libstd dependency
rustc-dep-of-std = ["compiler_builtins", "core"]
# Unstable feature for testing
test-in-browser = ["wasm-bindgen"]

[package.metadata.docs.rs]
features = ["std"]
features = ["std", "custom"]
26 changes: 26 additions & 0 deletions custom/stdweb/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "stdweb-getrandom"
version = "0.1.0"
edition = "2018"
authors = ["The Rand Project Developers"]
license = "MIT OR Apache-2.0"
description = "Custom shim for using getrandom with stdweb"
documentation = "https://docs.rs/stdweb-getrandom"
repository = "https://github.com/rust-random/getrandom"
categories = ["wasm"]

[dependencies]
getrandom = { path = "../..", version = "0.2", features = ["custom"] }
stdweb = "0.4.18"

# Test-only features allowing us to reuse most of the code in common.rs
[features]
default = ["test-stdweb"]
josephlr marked this conversation as resolved.
Show resolved Hide resolved
test-stdweb = []

[[test]]
name = "common"
path = "../../tests/common.rs"
Copy link
Member

@newpavlov newpavlov Sep 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need it? IIUC we already test stdweb and wasm-bindgen via getrandom. Or is it for moving WASM-related test features to the custom crates?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do need this. When we move the wasm/stdweb functionality to Custom RNGs, they can no longer be tested by getrandom main test code. These [[test]]s simply restore the old testing behavior.


[package.metadata.docs.rs]
default-target = "wasm32-unknown-unknown"
11 changes: 7 additions & 4 deletions src/wasm32_stdweb.rs → custom/stdweb/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,26 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for WASM via stdweb
extern crate std;
#![recursion_limit = "128"]
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
compile_error!("This crate is only for the `wasm32-unknown-unknown` target");

use core::mem;
use std::sync::Once;

use stdweb::js;

use crate::Error;
use getrandom::{register_custom_getrandom, Error};

#[derive(Clone, Copy, Debug)]
enum RngSource {
Browser,
Node,
}

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
register_custom_getrandom!(getrandom_inner);

fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
assert_eq!(mem::size_of::<usize>(), 4);
static ONCE: Once = Once::new();
static mut RNG_SOURCE: Result<RngSource, Error> = Ok(RngSource::Node);
Expand Down
30 changes: 30 additions & 0 deletions custom/wasm-bindgen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "wasm-bindgen-getrandom"
version = "0.1.0"
edition = "2018"
authors = ["The Rand Project Developers"]
license = "MIT OR Apache-2.0"
description = "Custom shim for using getrandom with wasm-bindgen"
documentation = "https://docs.rs/wasm-bindgen-getrandom"
repository = "https://github.com/rust-random/getrandom"
categories = ["wasm"]

[dependencies]
getrandom = { path = "../..", version = "0.2", features = ["custom"] }
wasm-bindgen = "0.2.29"

[dev-dependencies]
wasm-bindgen-test = "0.2"

# Test-only features allowing us to reuse most of the code in common.rs
[features]
default = ["test-bindgen"]
test-bindgen = []
test-in-browser = ["test-bindgen"]

[[test]]
name = "common"
path = "../../tests/common.rs"

[package.metadata.docs.rs]
default-target = "wasm32-unknown-unknown"
10 changes: 6 additions & 4 deletions src/wasm32_bindgen.rs → custom/wasm-bindgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for WASM via wasm-bindgen
extern crate std;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
compile_error!("This crate is only for the `wasm32-unknown-unknown` target");

use core::cell::RefCell;
use core::mem;
use std::thread_local;

use wasm_bindgen::prelude::*;

use crate::Error;
use getrandom::{register_custom_getrandom, Error};

#[derive(Clone, Debug)]
enum RngSource {
Expand All @@ -29,7 +29,9 @@ thread_local!(
static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
register_custom_getrandom!(getrandom_inner);

fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
assert_eq!(mem::size_of::<usize>(), 4);

RNG_SOURCE.with(|f| {
Expand Down
45 changes: 45 additions & 0 deletions src/custom.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An implementation which calls out to an externally defined function.
use crate::Error;
use core::num::NonZeroU32;

/// Register a function to be invoked by `getrandom` on custom targets.
///
/// This function will only be invoked on targets not supported by `getrandom`.
/// This prevents crate dependencies from either inadvertently or maliciously
/// overriding the secure RNG implementations in `getrandom`.
///
/// *This API requires the following crate features to be activated: `custom`*
#[macro_export]
macro_rules! register_custom_getrandom {
($path:path) => {
// We use an extern "C" function to get the guarantees of a stable ABI.
#[no_mangle]
extern "C" fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 {
let slice = unsafe { ::std::slice::from_raw_parts_mut(dest, len) };
match $path(slice) {
Ok(()) => 0,
Err(e) => e.code().get(),
}
}
};
}

#[allow(dead_code)]
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
extern "C" {
fn __getrandom_custom(dest: *mut u8, len: usize) -> u32;
}
let ret = unsafe { __getrandom_custom(dest.as_mut_ptr(), dest.len()) };
match NonZeroU32::new(ret) {
None => Ok(()),
Some(code) => Err(Error::from(code)),
}
}
21 changes: 6 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,17 @@
html_root_url = "https://rust-random.github.io/rand/"
)]
#![no_std]
#![cfg_attr(feature = "stdweb", recursion_limit = "128")]
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]

#[macro_use]
extern crate cfg_if;

mod error;
mod util;

// To prevent a breaking change when targets are added, we always export the
// register_custom_getrandom macro, so old Custom RNG crates continue to build.
#[cfg(feature = "custom")]
mod custom;
#[cfg(feature = "std")]
mod error_impls;

Expand Down Expand Up @@ -188,19 +190,8 @@ cfg_if! {
target_env = "sgx",
)))] {
#[path = "rdrand.rs"] mod imp;
} else if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] {
cfg_if! {
if #[cfg(feature = "wasm-bindgen")] {
#[path = "wasm32_bindgen.rs"] mod imp;
} else if #[cfg(feature = "stdweb")] {
#[path = "wasm32_stdweb.rs"] mod imp;
} else {
compile_error!("\
Enable crate features to use the wasm32-unknown-unknown target, see: \
https://docs.rs/getrandom/#support-for-webassembly-and-asmjs\
");
}
}
} else if #[cfg(feature = "custom")] {
use custom as imp;
} else {
compile_error!("\
target is not supported, for more information see: \
Expand Down
14 changes: 10 additions & 4 deletions tests/common.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
#[cfg(feature = "wasm-bindgen")]
// Explicitly use the Custom RNG crates to link them in.
#[cfg(feature = "test-stdweb")]
use stdweb_getrandom as _;
#[cfg(feature = "test-bindgen")]
use wasm_bindgen_getrandom as _;

#[cfg(feature = "test-bindgen")]
use wasm_bindgen_test::*;

use getrandom::getrandom;

#[cfg(feature = "test-in-browser")]
wasm_bindgen_test_configure!(run_in_browser);

#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen_test)]
#[cfg_attr(feature = "test-bindgen", wasm_bindgen_test)]
#[test]
fn test_zero() {
// Test that APIs are happy with zero-length requests
getrandom(&mut [0u8; 0]).unwrap();
}

#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen_test)]
#[cfg_attr(feature = "test-bindgen", wasm_bindgen_test)]
#[test]
fn test_diff() {
let mut v1 = [0u8; 1000];
Expand All @@ -31,7 +37,7 @@ fn test_diff() {
assert!(n_diff_bits >= v1.len() as u32);
}

#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen_test)]
#[cfg_attr(feature = "test-bindgen", wasm_bindgen_test)]
#[test]
fn test_huge() {
let mut huge = [0u8; 100_000];
Expand Down