VRF-WASM
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.
ECVRF implementation following draft-irtf-cfrg-vrf-15.
Installation
To use vrf-wasm, you must explicitly enable a feature flag for your target environment.
Browser/Web Applications
[]
= { = "0.9.1", = ["browser"] }
NEAR Smart Contracts
[]
= { = "0.9.1", = false, = ["near"] }
If no feature is selected, you will get a compile-time error with instructions.
Usage
Basic VRF Operations
use ECVRFKeyPair;
use ;
use WasmRng;
// Generate a keypair
let mut rng = default;
let keypair = generate;
// Create VRF proof for input
let input = b"Hello, VRF!";
let = keypair.output;
// Verify the proof
assert!;
// The hash is deterministic for the same key and input
let = keypair.output;
assert_eq!;
println!;
Deterministic KeyPair Generation
use ECVRFKeyPair;
use VRFKeyPair;
use WasmRngFromSeed;
use SeedableRng;
// Generate deterministic keypair from seed
let seed = ;
let mut rng = from_seed;
let keypair = generate;
// Same seed always generates same keypair
let mut rng2 = from_seed;
let keypair2 = generate;
// Prove this by generating same VRF output
let input = b"test";
let = keypair.output;
let = keypair2.output;
assert_eq!;
Serialization
use ;
use VRFKeyPair;
// All types implement Serialize/Deserialize
let mut rng = default;
let keypair = generate;
let input = b"data";
let proof = keypair.prove;
// Serialize to bytes
let public_key_bytes = serialize.unwrap;
let proof_bytes = serialize.unwrap;
// Deserialize
let public_key: ECVRFPublicKey = deserialize.unwrap;
let deserialized_proof: ECVRFProof = deserialize.unwrap;
// Verify still works
assert!;
VRF Component Extraction
For cross-verification scenarios where you need to inspect or reconstruct VRF proofs:
use ;
use VRFKeyPair;
use WasmRng;
let mut rng = default;
let keypair = generate;
let proof = keypair.prove;
// 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 = proof.to_components;
// Reconstruct proof from components (for cross-verification)
let reconstructed = from_components.unwrap;
assert!;
Conditional Compilation & Feature Flags
VRF-WASM uses conditional compilation to provide optimized RNG implementations for different target environments:
Available Features
| 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 |
Note: you would only ever use the near vrf-wasm in a contract for verifying VRF output and proofs generated by vrf-wasm on the client, there is no point generating VRF outputs onchain as keypairs would be exposed.
- Alternatively, use the
vrf-contract-verifierfor a lightweight VRF proof/output verifier you can use to verifyvrf-wasmgenerated outputs and proofs, onchain. - If you want onchain randomness, use
env:random_seed()in NEAR contracts (it is itself a VRF based RNG).
Building for Different Targets
Browser/JavaScript (Default)
# Default build - includes browser RNG
# WASM for web
NEAR Smart Contracts
# NEAR-specific build (NEAR features only)
# With cargo-near (recommended for NEAR contracts)
Environment-Specific RNG Usage
// Generic usage (works with any feature configuration)
use WasmRng;
let mut rng = default;
// Browser-specific (when browser feature is enabled)
use BrowserWasmRng;
let mut rng = default;
// NEAR-specific (when near feature is enabled)
use NearWasmRng;
let mut rng = default;
Binary Size
| Target | Binary Size | Notes |
|---|---|---|
| Native (release) | ~2MB | Full Rust binary |
| WASM (release) | ~143KB | Optimized for web |
| WASM (compressed) | ~58KB | With Brotli compression |
Attribution
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/
Advanced: Using with NEAR Smart Contracts
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.
The Problem: Feature Unification
If your Cargo.toml has this:
# In [dependencies]
= { = "0.9.1", = false, = ["near"] }
# In [dev-dependencies]
= { = "0.9.1", = ["browser"] }
Cargo will enable both near and browser features for all builds, which can cause conflicts.
The Solution: Target-Specific Dev-Dependencies
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
[]
# This will be used for your smart contract build
= { = "0.9.1", = false, = ["near"] }
[]
# This will be used for your native tests (`cargo test`)
= { = "0.9.1", = ["browser"] }
This configuration ensures:
cargo build --target wasm32-unknown-unknown: Compilesvrf-wasmwith only thenearfeature.cargo test: Compilesvrf-wasmwith thebrowserfeature 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.