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

make rand/getrandom dependency explicit with a feature #37

Merged
merged 3 commits into from Jan 14, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 8 additions & 7 deletions Cargo.toml
Expand Up @@ -11,23 +11,24 @@ categories = ["cryptography"]
include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
license = "MIT/Apache-2.0"
edition = "2018"
resolver = "2"

[dependencies]
rand = { version = "0.8", default-features = false, features = ["std_rng"] }
rand = { version = "0.8", default-features = false, features = ["std_rng"]}
rayon = { version = "1", optional = true }
colored = { version = "2", optional = true }
num-traits = { version = "0.2", default-features = false }

[dev-dependencies]
rand = { version = "0.8", features = ["std"]}


[features]
default = [ "std" ]
std = [ "rand/std" ]
std = []
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason to disable rand/std when std is on? That's not supported in wasm anyway, right? Or does wasm support std?

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 haven't done any in-depth research, but, while working on this wasm contract, I can tell you that many things from std are compatible with wasm.

  • std::collections like Vec or Hashmap are ok
  • Option and Result work just fine
  • So far, never hit any issue working withString and str
  • array and slices are 👌

AFAIK there isn't any particular issue using std in wasm environment, except probably IO and multi-thread stuff.

The issue with using the current version of ark-std in wasm for smart contracts is getrandom crate: there is no way a blockchain EVM can provide you with functions that generate randomness.
This change aims at making the dependency over getrandom optional. So crates that sit above ark-std like all the algebra crates, crypto-primitives , crates in curve, etc..., they can still rely on re-exported traits from ark_std::rand, while gaining wasm compatibility for free.

Side Note: all the no-std gears are dedicated more to the embedded world, rather than to wasm.

parallel = [ "rayon", "std" ]
print-trace = [ "std", "colored" ]

[profile.release]
opt-level = 3
lto = "thin"
incremental = true
getrandom = ["rand/std"]

[profile.bench]
opt-level = 3
Expand Down
28 changes: 20 additions & 8 deletions src/rand_helper.rs
@@ -1,10 +1,10 @@
#[cfg(feature = "std")]
use rand::RngCore;
use rand::{
distributions::{Distribution, Standard},
prelude::StdRng,
Rng,
};
#[cfg(feature = "std")]
use rand::{prelude::ThreadRng, RngCore};

pub use rand;

Expand Down Expand Up @@ -41,20 +41,28 @@ pub fn test_rng() -> impl rand::Rng {
/// Should be used only for tests, not for any real world usage.
#[cfg(feature = "std")]
pub fn test_rng() -> impl rand::Rng {
let is_deterministic =
std::env::vars().any(|(key, val)| key == "DETERMINISTIC_TEST_RNG" && val == "1");
if is_deterministic {
#[cfg(any(feature = "getrandom", test))]
{
let is_deterministic =
std::env::vars().any(|(key, val)| key == "DETERMINISTIC_TEST_RNG" && val == "1");
if is_deterministic {
RngWrapper::Deterministic(test_rng_helper())
} else {
RngWrapper::Randomized(rand::thread_rng())
}
}
#[cfg(not(any(feature = "getrandom", test)))]
{
RngWrapper::Deterministic(test_rng_helper())
} else {
RngWrapper::Randomized(rand::thread_rng())
}
}

/// Helper wrapper to enable `test_rng` to return `impl::Rng`.
#[cfg(feature = "std")]
enum RngWrapper {
Deterministic(StdRng),
Randomized(ThreadRng),
#[cfg(any(feature = "getrandom", test))]
Randomized(rand::rngs::ThreadRng),
}

#[cfg(feature = "std")]
Expand All @@ -63,6 +71,7 @@ impl RngCore for RngWrapper {
fn next_u32(&mut self) -> u32 {
match self {
Self::Deterministic(rng) => rng.next_u32(),
#[cfg(any(feature = "getrandom", test))]
Self::Randomized(rng) => rng.next_u32(),
}
}
Expand All @@ -71,6 +80,7 @@ impl RngCore for RngWrapper {
fn next_u64(&mut self) -> u64 {
match self {
Self::Deterministic(rng) => rng.next_u64(),
#[cfg(any(feature = "getrandom", test))]
Self::Randomized(rng) => rng.next_u64(),
}
}
Expand All @@ -79,6 +89,7 @@ impl RngCore for RngWrapper {
fn fill_bytes(&mut self, dest: &mut [u8]) {
match self {
Self::Deterministic(rng) => rng.fill_bytes(dest),
#[cfg(any(feature = "getrandom", test))]
Self::Randomized(rng) => rng.fill_bytes(dest),
}
}
Expand All @@ -87,6 +98,7 @@ impl RngCore for RngWrapper {
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
match self {
Self::Deterministic(rng) => rng.try_fill_bytes(dest),
#[cfg(any(feature = "getrandom", test))]
Self::Randomized(rng) => rng.try_fill_bytes(dest),
}
}
Expand Down