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 OsRng wasm support #272

Merged
merged 4 commits into from
Mar 1, 2018
Merged

Add OsRng wasm support #272

merged 4 commits into from
Mar 1, 2018

Conversation

quininer
Copy link
Contributor

:)

Copy link
Contributor

@pitdicker pitdicker left a comment

Choose a reason for hiding this comment

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

Thanks for the PR!

First I have to say that I know nothing about js 😄. But left a couple of comments.

src/os.rs Outdated

#[derive(Debug)]
pub struct OsRng;

impl OsRng {
pub fn new() -> Result<OsRng, Error> {
Err(Error::new(ErrorKind::Unavailable, "not supported on WASM"))
Ok(OsRng)
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice if we could know here if OsRng is available or not. Would it add a lot of overhead to test here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can check if window.crypto.getRandomValuesrequire("crypto") is available, but there is a certain overhead.

Copy link
Member

Choose a reason for hiding this comment

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

I'm not really sure it matters — any of the other system interfaces may succeed with new but fail on try_fill_bytes.

src/os.rs Outdated
HEAPU8.set(array, ptr);
} catch(err) {
if (err instanceof ReferenceError) {
let bytes = require("crypto").randomBytes(len);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a fallback for Node.js or something? Could you maybe add a comment?

src/os.rs Outdated
Ok(())
} else {
let err: WebError = js!{ return @{ result }.error }.try_into().unwrap();
Err(Error::with_cause(ErrorKind::Other, "WASM Error", err))
Copy link
Contributor

@pitdicker pitdicker Feb 27, 2018

Choose a reason for hiding this comment

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

You should probably give a Unavailable error if window.crypto.getRandomValues is not available (can that happen, or does every implementation of webassembly support this?). And do you know when we can get a QuotaExceededError?

b.t.w. Other just got renamed to Unknown Unexpected.

Copy link
Member

Choose a reason for hiding this comment

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

No, to Unexpected. But I agree, it doesn't look like this is recoverable so it should be Unavailable.

Copy link
Contributor

Choose a reason for hiding this comment

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

Found an answer: https://w3c.github.io/webcrypto/Overview.html#dfn-Crypto-method-getRandomValues. QuotaExceededError is returned "If the byteLength of array is greater than 65536". We maybe want to break up larger request, like the implementations of OsRng on other systems (although I would say an error is reasonable...)

let mut v2 = [0u8; 1000];
r.fill_bytes(&mut v2);

assert_ne!(v[..], v2[..]);
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Copy link
Member

@dhardy dhardy left a comment

Choose a reason for hiding this comment

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

Nice work. I also no next-to-nothing about JS; is this expected to work on most WASM platforms?

src/os.rs Outdated
Ok(())
} else {
let err: WebError = js!{ return @{ result }.error }.try_into().unwrap();
Err(Error::with_cause(ErrorKind::Other, "WASM Error", err))
Copy link
Member

Choose a reason for hiding this comment

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

No, to Unexpected. But I agree, it doesn't look like this is recoverable so it should be Unavailable.

src/os.rs Outdated
pub fn try_fill_bytes(&mut self, v: &mut [u8]) -> Result<(), Error> {
Err(Error::new(ErrorKind::Unavailable, "not supported on WASM"))
let len = v.len() as u32;
let ptr = v.as_mut_ptr() as i32;
Copy link
Member

Choose a reason for hiding this comment

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

A 32-bit pointer? Surely that's not going to work on 64-bit platforms?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it is wasm32.

Copy link
Member

Choose a reason for hiding this comment

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

Okay, then could you at least assert_eq!(size_of::<usize>(), 4)?

assert_eq!(&sample_slice(&mut r, empty, 0)[..], []);
assert_eq!(&sample_slice(&mut r, &[42, 2, 42], 0)[..], []);
assert_eq!(&sample_slice(&mut r, empty, 0)[..], [0u8; 0]);
assert_eq!(&sample_slice(&mut r, &[42, 2, 42], 0)[..], [0u8; 0]);
Copy link
Member

Choose a reason for hiding this comment

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

Is the extra verbosity useful?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know, this may seem a rust type inference bug.

screenshot_20180227_224051

Copy link
Member

Choose a reason for hiding this comment

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

Try removing the first &; the function returns a Vec so it's not necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It does not work.

screenshot_20180227_231025

@dhardy dhardy merged commit 48a8f0a into rust-random:master Mar 1, 2018
@dhardy
Copy link
Member

dhardy commented Mar 1, 2018

Merged, with a tweak to the test.

Thanks @quininer.

@tomaka
Copy link

tomaka commented Mar 25, 2018

Sorry for the hostile tone. This PR was done with the best intentions but this shouldn't have been merged. wasm32-unknown-unknown is NOT JavaScript.

As its name says, the environment is unknown and the environment shouldn't be assumed to be the web.

Also wasm32-unknown-unknown is not stdweb or cargo-web. Instead cargo-web should be thought as a subset of wasm32-unknown-unknown.

The stdlib faces the same problem and "solves" it by panicking at runtime in every single function that requires some support from the OS or the environment in general. The stdlib also has an unstable feature flag that assumes the presence of a support function provided by the user. This crate should follow the same idiom.

@quininer
Copy link
Contributor Author

I agree with @tomaka , I neglect this point.

As a remedy, we can provide a stdweb feature. or move out to become rand-stdweb.

@pitdicker
Copy link
Contributor

An stdweb feature seems like a good choice to me. I'll take a stab at it.

@dhardy
Copy link
Member

dhardy commented Mar 26, 2018

Thanks for the review @tomaka; I was hoping for extra review but didn't know who to ask.

I believe however the worst case is this will simply return Error("not supported") or cause build failure. Anyway thanks for putting us right.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants