| Crates.io | vrf-wasm |
| lib.rs | vrf-wasm |
| version | 0.8.2 |
| created_at | 2025-06-18 06:03:05.13035+00 |
| updated_at | 2025-06-21 11:12:46.284031+00 |
| description | VRF for WASM environments |
| homepage | |
| repository | https://github.com/web3-authn/vrf-wasm |
| max_upload_size | |
| id | 1716647 |
| size | 135,089 |
A WASM-compatible Verifiable Random Function (VRF) implementation based on FastCrypto.
FastCrypto has C dependencies (secp256k1-sys, blst) that prevent WASM compilation even when compiling with wasm feature flags. This library extracts only the VRF module which uses pure Rust dependencies.
To use vrf-wasm, you must explicitly enable a feature flag for your target environment.
[dependencies]
vrf-wasm = { version = "0.8", features = ["browser"] }
[dependencies]
vrf-wasm = { version = "0.8", default-features = false, features = ["near"] }
If no feature is selected, you will get a compile-time error with instructions.
use vrf_wasm::ecvrf::ECVRFKeyPair;
use vrf_wasm::vrf::{VRFKeyPair, VRFProof};
use vrf_wasm::rng::WasmRng;
// Generate a keypair
let mut rng = WasmRng::default();
let keypair = ECVRFKeyPair::generate(&mut rng);
// Create VRF proof for input
let input = b"Hello, VRF!";
let (hash, proof) = keypair.output(input);
// Verify the proof
assert!(proof.verify(input, &keypair.pk).is_ok());
// The hash is deterministic for the same key and input
let (hash2, _) = keypair.output(input);
assert_eq!(hash, hash2);
println!("VRF Hash: {}", hex::encode(hash));
use vrf_wasm::ecvrf::ECVRFKeyPair;
use vrf_wasm::vrf::VRFKeyPair;
use vrf_wasm::rng::WasmRngFromSeed;
use rand_core::SeedableRng;
// Generate deterministic keypair from seed
let seed = [42u8; 32];
let mut rng = WasmRngFromSeed::from_seed(seed);
let keypair = ECVRFKeyPair::generate(&mut rng);
// Same seed always generates same keypair
let mut rng2 = WasmRngFromSeed::from_seed(seed);
let keypair2 = ECVRFKeyPair::generate(&mut rng2);
// Prove this by generating same VRF output
let input = b"test";
let (hash1, _) = keypair.output(input);
let (hash2, _) = keypair2.output(input);
assert_eq!(hash1, hash2);
use vrf_wasm::ecvrf::{ECVRFKeyPair, ECVRFProof, ECVRFPublicKey};
use vrf_wasm::vrf::VRFKeyPair;
// All types implement Serialize/Deserialize
let mut rng = vrf_wasm::rng::WasmRng::default();
let keypair = ECVRFKeyPair::generate(&mut rng);
let input = b"data";
let proof = keypair.prove(input);
// Serialize to bytes
let public_key_bytes = bincode::serialize(&keypair.pk).unwrap();
let proof_bytes = bincode::serialize(&proof).unwrap();
// Deserialize
let public_key: ECVRFPublicKey = bincode::deserialize(&public_key_bytes).unwrap();
let deserialized_proof: ECVRFProof = bincode::deserialize(&proof_bytes).unwrap();
// Verify still works
assert!(deserialized_proof.verify(input, &public_key).is_ok());
For cross-verification scenarios where you need to inspect or reconstruct VRF proofs:
use vrf_wasm::ecvrf::{ECVRFKeyPair, ECVRFProof};
use vrf_wasm::vrf::VRFKeyPair;
use vrf_wasm::rng::WasmRng;
let mut rng = WasmRng::default();
let keypair = ECVRFKeyPair::generate(&mut rng);
let proof = keypair.prove(b"input");
// Extract individual components
let gamma_bytes = proof.gamma_bytes(); // [u8; 32] - compressed point
let challenge_bytes = proof.challenge_bytes(); // [u8; 16] - challenge
let scalar_bytes = proof.scalar_bytes(); // [u8; 32] - scalar
// Extract all at once
let (gamma, challenge, scalar) = proof.to_components();
// Reconstruct proof from components (for cross-verification)
let reconstructed = ECVRFProof::from_components(&gamma, &challenge, &scalar).unwrap();
assert!(reconstructed.verify(b"input", &keypair.pk).is_ok());
VRF-WASM uses conditional compilation to provide optimized RNG implementations for different target environments:
| Feature | Target Environment | RNG Implementation | Default |
|---|---|---|---|
browser |
Web browsers, JavaScript | crypto.getRandomValues() via getrandom |
✅ Yes |
near |
NEAR smart contracts | env::random_seed() + block-based entropy + ChaCha20 |
❌ No |
# Default build - includes browser RNG
cargo build
# WASM for web
wasm-pack build --target web
# NEAR-specific build (NEAR features only)
cargo build --no-default-features --features near --target wasm32-unknown-unknown
# With cargo-near (recommended for NEAR contracts)
cargo install cargo-near
cargo near build
// Generic usage (works with any feature configuration)
use vrf_wasm::rng::WasmRng;
let mut rng = WasmRng::default();
// Browser-specific (when browser feature is enabled)
use vrf_wasm::rng::BrowserWasmRng;
let mut rng = BrowserWasmRng::default();
// NEAR-specific (when near feature is enabled)
use vrf_wasm::rng::NearWasmRng;
let mut rng = NearWasmRng::default();
| Target | Binary Size | Notes |
|---|---|---|
| Native (release) | ~2MB | Full Rust binary |
| WASM (release) | ~143KB | Optimized for web |
| WASM (compressed) | ~58KB | With Brotli compression |
This project is derived from FastCrypto by Mysten Labs, Inc.
Original Copyright: Copyright (c) 2022, Mysten Labs, Inc. License: Apache License 2.0 Original Repository: https://github.com/MystenLabs/fastcrypto/
When building a project that uses vrf-wasm for both on-chain (NEAR) and off-chain (testing) purposes, you need to handle Cargo's feature unification.
If your Cargo.toml has this:
# In [dependencies]
vrf-wasm = { version = "0.8", default-features = false, features = ["near"] }
# In [dev-dependencies]
vrf-wasm = { version = "0.8", features = ["browser"] }
Cargo will enable both near and browser features for all builds, which can cause conflicts.
To solve this, use a [target] configuration in your project's Cargo.toml to specify that the browser version of vrf-wasm should only be used for native testing environments, not for the wasm32 smart contract build.
# In your project's Cargo.toml
[dependencies]
# This will be used for your smart contract build
vrf-wasm = { version = "0.8", default-features = false, features = ["near"] }
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
# This will be used for your native tests (`cargo test`)
vrf-wasm = { version = "0.8", features = ["browser"] }
This configuration ensures:
cargo build --target wasm32-unknown-unknown: Compiles vrf-wasm with only the near feature.cargo test: Compiles vrf-wasm with the browser feature for your test suite.This approach prevents feature conflicts and allows you to test your NEAR smart contracts with a browser-compatible version of the VRF library.