A Verifiable Random Function (VRF) is a cryptographic public-key primitive that, from a secret key and a given input, produces a unique pseudorandom output, along with a proof that the output was correctly computed. Only the secret key holder can generate the output–proof pair, but anyone with the corresponding public key can verify the proof.
libvrf-js is a TypeScript/JavaScript implementation of several VRFs for Node.js (v18+) and browsers (EC VRF only).
- Multiple VRF algorithms: RSA-FDH, RSA-PSS-NOSALT, and EC VRF (RFC 9381)
- Node.js & Browsers: EC VRF works in both Node.js and browsers; RSA VRFs work in Node.js only
- Type-safe: Written in TypeScript with full type definitions
- Well-tested: Comprehensive test suite ported from C++ implementation
- Production-ready: Professional-grade cryptographic library
npm install libvrfRequirements:
- Node.js v18.0.0 or later
- npm v9+ (or compatible package manager)
Dependencies:
node-rsa(^1.1.1) - Used for RSA-based VRF operations only. EC VRF uses Node.js built-in crypto.
âś… Browser Support: EC VRF now works in browsers using WebCrypto API! RSA-based VRFs still require Node.js.
Current Status:
- âś… EC VRF: Works in browsers using async APIs and WebCrypto
- ❌ RSA VRFs: Do not work in browsers (requires
node-rsaand Node.js crypto) - âś… Node.js: All VRF types work correctly
The library is available via CDN:
jsDelivr (latest version):
<script src="https://cdn.jsdelivr.net/npm/libvrf/dist/browser/libvrf.min.js"></script>unpkg (latest version):
<script src="https://unpkg.com/libvrf/dist/browser/libvrf.min.js"></script>Usage in browser:
<script src="https://unpkg.com/libvrf/dist/browser/libvrf.min.js"></script>
<script>
// After loading the script, use the global 'libvrf' object
// Note: Browser APIs are async
(async () => {
// Create a secret key (async)
const secretKey = await libvrf.VRF.createAsync(libvrf.VRFType.EC_VRF_P256_SHA256_TAI);
// Get the public key (async)
const publicKey = await secretKey.getPublicKeyAsync();
// Generate a VRF proof (async)
const input = new TextEncoder().encode('hello');
const proof = await secretKey.getVRFProofAsync(input);
// Verify the proof (async)
const [success, vrfValue] = await publicKey.verifyVRFProofAsync(input, proof);
console.log('Verification:', success);
console.log('VRF Value:', Array.from(vrfValue).map(b => b.toString(16).padStart(2, '0')).join(''));
})();
</script>Important Notes:
- EC VRF only: Only
EC_VRF_P256_SHA256_TAIworks in browsers - Async APIs: Browser code must use
createAsync(),getPublicKeyAsync(),getVRFProofAsync(), andverifyVRFProofAsync() - Node.js compatibility: Node.js can also use the async APIs, or continue using the sync APIs
RSA_FDH_VRF_RSA2048_SHA256- RSA-FDH with 2048-bit key and SHA-256RSA_FDH_VRF_RSA3072_SHA256- RSA-FDH with 3072-bit key and SHA-256RSA_FDH_VRF_RSA4096_SHA384- RSA-FDH with 4096-bit key and SHA-384RSA_FDH_VRF_RSA4096_SHA512- RSA-FDH with 4096-bit key and SHA-512
RSA_PSS_NOSALT_VRF_RSA2048_SHA256- RSA-PSS (no salt) with 2048-bit key and SHA-256RSA_PSS_NOSALT_VRF_RSA3072_SHA256- RSA-PSS (no salt) with 3072-bit key and SHA-256RSA_PSS_NOSALT_VRF_RSA4096_SHA384- RSA-PSS (no salt) with 4096-bit key and SHA-384RSA_PSS_NOSALT_VRF_RSA4096_SHA512- RSA-PSS (no salt) with 4096-bit key and SHA-512
EC_VRF_P256_SHA256_TAI- ECVRF with P-256 curve and SHA-256 (RFC 9381)
import { VRF, VRFType } from 'libvrf';
// 1. Choose a VRF type and generate a key pair
const type = VRFType.RSA_FDH_VRF_RSA2048_SHA256;
const secretKey = VRF.create(type)!;
// 2. Get the public key
const publicKey = secretKey.getPublicKey()!;
// 3. Generate a VRF proof for some input
const input = new TextEncoder().encode('hello world');
const proof = secretKey.getVRFProof(input)!;
// 4. Verify the proof and get the VRF value
const [success, vrfValue] = publicKey.verifyVRFProof(input, proof);
console.log('Proof verified:', success);
console.log('VRF Value:', Buffer.from(vrfValue).toString('hex'));import { VRF, VRFType } from 'libvrf';
const type = VRFType.EC_VRF_P256_SHA256_TAI;
const secretKey = VRF.create(type)!;
const publicKey = secretKey.getPublicKey()!;
// Serialize public key (DER-encoded SPKI)
const publicKeyBytes = publicKey.toBytes();
console.log('Public key size:', publicKeyBytes.length, 'bytes');
// Deserialize public key
const loadedPublicKey = VRF.publicKeyFromBytes(type, publicKeyBytes)!;
// Serialize proof
const input = new Uint8Array([1, 2, 3, 4, 5]);
const proof = secretKey.getVRFProof(input)!;
const proofBytes = proof.toBytes();
// Deserialize proof
const loadedProof = VRF.proofFromBytes(type, proofBytes)!;
// Verify with loaded key and proof
const [success, vrfValue] = loadedPublicKey.verifyVRFProof(input, loadedProof);
console.log('Verification:', success);
console.log('VRF Value:', Buffer.from(vrfValue).toString('hex'));import { VRF, VRFType } from 'libvrf';
// EC VRF (fastest, smallest keys)
const ecKey = VRF.create(VRFType.EC_VRF_P256_SHA256_TAI)!;
// RSA-FDH VRF (widely compatible)
const rsaFdhKey = VRF.create(VRFType.RSA_FDH_VRF_RSA2048_SHA256)!;
// RSA-PSS VRF (based on RSA-PSS signatures)
const rsaPssKey = VRF.create(VRFType.RSA_PSS_NOSALT_VRF_RSA2048_SHA256)!;The main class providing static methods for VRF operations.
Creates a new VRF secret key for the specified VRF type.
Deserializes a VRF proof from bytes.
Deserializes a VRF public key from bytes.
Represents a VRF secret key.
getVRFProof(input: Uint8Array): Proof | null- Generates a VRF proofgetPublicKey(): PublicKey | null- Returns the corresponding public keyclone(): SecretKey- Creates a deep copyisInitialized(): boolean- Checks if properly initializedgetType(): VRFType- Returns the VRF type
Represents a VRF public key.
verifyVRFProof(input: Uint8Array, proof: Proof): [boolean, Uint8Array]- Verifies a prooftoBytes(): Uint8Array- Serializes the public keyfromBytes(type: VRFType, data: Uint8Array): boolean- Deserializes from bytesclone(): PublicKey- Creates a deep copyisInitialized(): boolean- Checks if properly initializedgetType(): VRFType- Returns the VRF type
Represents a VRF proof.
getVRFValue(): Uint8Array- Extracts the VRF valuetoBytes(): Uint8Array- Serializes the prooffromBytes(type: VRFType, data: Uint8Array): boolean- Deserializes from bytesclone(): Proof- Creates a deep copyisInitialized(): boolean- Checks if properly initializedgetType(): VRFType- Returns the VRF type
Important Security Notes:
-
EC VRF RFC 9381 Compliance: The EC VRF implementation (
EC_VRF_P256_SHA256_TAI) uses a simplified deterministic construction and is NOT RFC 9381 compliant. EC VRF proofs are NOT interoperable with RFC 9381 compliant implementations (including the C++ libvrf). -
Browser Support: Only EC VRF works in browsers. RSA-based VRFs require Node.js. Browser code must use async APIs (
createAsync,getPublicKeyAsync,getVRFProofAsync,verifyVRFProofAsync). -
Key Generation Trust: RSA-based VRFs are not secure unless the key generation process is trusted. For more details, see RFC 9381.
-
Cryptographic Primitives: This library uses Node.js's built-in
cryptomodule and browser's WebCrypto API for cryptographic operations. -
Production Use: This is a JavaScript port with simplified EC VRF implementation. For production systems requiring RFC 9381 compliance or interoperability, use the original C++ libvrf.
-
VRF Value: The VRF value is deterministic for a given key and input. The same key and input will always produce the same VRF value.
This JavaScript implementation has several important limitations compared to the original C++ libvrf:
- NOT RFC 9381 Compliant: The EC VRF implementation (
EC_VRF_P256_SHA256_TAI) uses a simplified deterministic construction and does not implement the full RFC 9381 specification. - NOT Interoperable: EC VRF proofs generated by this library cannot be verified by RFC 9381 compliant implementations (including the C++ libvrf), and vice versa.
- Different Proof Format: The proof structure and VRF output values differ from RFC 9381 compliant implementations.
- Self-Consistent Only: Proofs generated by this library can only be verified by this library.
- EC VRF Browser Support: EC VRF (
EC_VRF_P256_SHA256_TAI) works in browsers using WebCrypto API with async methods (createAsync(),getPublicKeyAsync(),getVRFProofAsync(),verifyVRFProofAsync()) - RSA VRFs: RSA-based VRFs require
node-rsaand Node.js crypto APIs, which are not available in browsers - Node.js Compatibility: Node.js supports both sync and async APIs for EC VRF - use sync methods for backward compatibility or async methods for consistency with browser code
- No Standard Test Vectors: This implementation does not include RFC 9381 test vectors and has not been tested for compatibility with the C++ libvrf test vectors.
- RSA VRF Compatibility: RSA-FDH and RSA-PSS-NOSALT VRFs are likely compatible with the C++ implementation but have not been tested against C++ test vectors.
- EC VRF: Not compatible with other RFC 9381 implementations or the C++ libvrf.
- RSA VRFs: Compatibility with other implementations is untested and may vary.
- For RFC 9381 Compliance: Use the original C++ libvrf or another RFC 9381 compliant implementation.
- For Interoperability: Do not use this library's EC VRF in systems that need to interoperate with other VRF implementations.
- For Self-Contained Systems: This library works well for systems where all components use
libvrf-jsexclusively.
This library works in modern browsers that support:
- WebCrypto API
- ES2020 features
- Uint8Array
Tested browsers:
- Chrome/Edge 80+
- Firefox 75+
- Safari 14+
# Install dependencies
npm install
# Build for Node.js and browser
npm run build
# Build only for Node.js
npm run build:node
# Build only for browser
npm run build:browser
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Lint code
npm run lintSee the examples directory for more usage examples:
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
This project is licensed under the MIT License - see the LICENSE file for details.
This is a JavaScript/TypeScript port of the official libvrf C++ library.
The original C++ implementation by Microsoft Corporation provides a robust, production-ready VRF library with comprehensive test coverage and full RFC 9381 compliance. This JavaScript port brings similar functionality to Node.js and browser environments while maintaining API compatibility with the original design.
Note: The EC VRF implementation in this JavaScript port uses a simplified deterministic construction and is NOT RFC 9381 compliant. For RFC 9381 compliance and interoperability, use the original C++ implementation.
- RFC 9381 - Verifiable Random Functions (VRFs)
- libvrf - Official C++ implementation
- Microsoft libvrf GitHub Repository
- Original C++ Library: https://github.com/Microsoft/libvrf
- This JavaScript/TypeScript port aims to provide the same API and functionality for web and Node.js applications
For issues, questions, or contributions related to:
- This JavaScript port: Please open issues in this repository
- The original C++ library: Visit https://github.com/Microsoft/libvrf