WebAssembly interface layer providing high-performance cryptographic functions for blockchain applications in the Polkadot ecosystem.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Verifiable Random Function implementation for generating and verifying cryptographically secure random values with proof of correctness. VRFs are used in blockchain consensus mechanisms and other applications requiring provably random values.
Creates a VRF signature that produces a random output along with a proof of correctness.
/**
* Creates VRF signature with random output and proof
* @param secret - 32-byte secret key as Uint8Array
* @param context - Context data as Uint8Array (domain separation)
* @param message - Message/input data as Uint8Array
* @param extra - Additional data as Uint8Array (can be empty)
* @returns VRF output and proof as Uint8Array (96 bytes: 32-byte output + 64-byte proof)
*/
function vrfSign(secret: Uint8Array, context: Uint8Array, message: Uint8Array, extra: Uint8Array): Uint8Array;Usage Example:
import { waitReady, vrfSign, sr25519KeypairFromSeed } from "@polkadot/wasm-crypto";
await waitReady();
// Generate VRF keypair (uses Sr25519)
const seed = new Uint8Array(32).fill(1);
const keypair = sr25519KeypairFromSeed(seed);
const secretKey = keypair.slice(0, 32);
// VRF inputs
const context = new TextEncoder().encode("vrf-context");
const message = new TextEncoder().encode("block-123");
const extra = new Uint8Array(0); // No extra data
const vrfOutput = vrfSign(secretKey, context, message, extra);
console.log("VRF output length:", vrfOutput.length); // 96
console.log("Random output:", vrfOutput.slice(0, 32)); // First 32 bytes
console.log("Proof:", vrfOutput.slice(32, 96)); // Last 64 bytesVerifies a VRF signature and proof against the original inputs and public key.
/**
* Verifies VRF signature and proof
* @param pubkey - 32-byte public key as Uint8Array
* @param context - Context data as Uint8Array (must match signing context)
* @param message - Message/input data as Uint8Array (must match signing message)
* @param extra - Additional data as Uint8Array (must match signing extra)
* @param outAndProof - 96-byte VRF output and proof as Uint8Array
* @returns true if VRF signature is valid, false otherwise
*/
function vrfVerify(pubkey: Uint8Array, context: Uint8Array, message: Uint8Array, extra: Uint8Array, outAndProof: Uint8Array): boolean;Usage Example:
import {
waitReady,
vrfSign,
vrfVerify,
sr25519KeypairFromSeed
} from "@polkadot/wasm-crypto";
await waitReady();
// Generate VRF keypair
const seed = new Uint8Array(32).fill(1);
const keypair = sr25519KeypairFromSeed(seed);
const secretKey = keypair.slice(0, 32);
const publicKey = keypair.slice(32, 64);
// VRF signing
const context = new TextEncoder().encode("lottery-draw");
const message = new TextEncoder().encode("round-456");
const extra = new Uint8Array(0);
const vrfOutput = vrfSign(secretKey, context, message, extra);
// VRF verification
const isValid = vrfVerify(publicKey, context, message, extra, vrfOutput);
console.log("VRF signature is valid:", isValid); // true
// Test with wrong context
const wrongContext = new TextEncoder().encode("wrong-context");
const isInvalid = vrfVerify(publicKey, wrongContext, message, extra, vrfOutput);
console.log("Wrong context signature is valid:", isInvalid); // falseimport {
waitReady,
vrfSign,
vrfVerify,
sr25519KeypairFromSeed
} from "@polkadot/wasm-crypto";
async function blockchainRandomBeacon() {
await waitReady();
// Validator's keypair
const validatorSeed = new Uint8Array(32);
crypto.getRandomValues(validatorSeed);
const validatorKeypair = sr25519KeypairFromSeed(validatorSeed);
const validatorSecret = validatorKeypair.slice(0, 32);
const validatorPublic = validatorKeypair.slice(32, 64);
// Block production
const context = new TextEncoder().encode("block-production");
const blockHeight = 12345;
const message = new Uint8Array(4);
new DataView(message.buffer).setUint32(0, blockHeight, false); // Big-endian block height
const vrfOutput = vrfSign(validatorSecret, context, message, new Uint8Array(0));
const randomValue = vrfOutput.slice(0, 32);
const proof = vrfOutput.slice(32, 96);
// Anyone can verify the randomness
const isValidRandom = vrfVerify(validatorPublic, context, message, new Uint8Array(0), vrfOutput);
console.log(`Block ${blockHeight} random beacon:`);
console.log("Random value:", Array.from(randomValue.slice(0, 8)).map(b => b.toString(16).padStart(2, '0')).join(''));
console.log("Proof valid:", isValidRandom);
return { randomValue, proof, isValidRandom };
}
blockchainRandomBeacon();import {
waitReady,
vrfSign,
vrfVerify,
sr25519KeypairFromSeed
} from "@polkadot/wasm-crypto";
async function vrfLotterySystem() {
await waitReady();
// Lottery organizer's keypair
const organizerSeed = new Uint8Array(32);
crypto.getRandomValues(organizerSeed);
const organizerKeypair = sr25519KeypairFromSeed(organizerSeed);
const organizerSecret = organizerKeypair.slice(0, 32);
const organizerPublic = organizerKeypair.slice(32, 64);
// Lottery parameters
const lotteryId = "lottery-2024-001";
const drawDate = "2024-12-31";
const participants = 1000;
const context = new TextEncoder().encode(`lottery:${lotteryId}`);
const message = new TextEncoder().encode(`draw:${drawDate}:participants:${participants}`);
// Generate verifiable random winner
const vrfOutput = vrfSign(organizerSecret, context, message, new Uint8Array(0));
const randomBytes = vrfOutput.slice(0, 32);
// Convert random bytes to winner index
const randomValue = new DataView(randomBytes.buffer).getUint32(0, false);
const winnerIndex = randomValue % participants;
// Verify the lottery result
const isValidDraw = vrfVerify(organizerPublic, context, message, new Uint8Array(0), vrfOutput);
console.log(`Lottery ${lotteryId} results:`);
console.log(`Winner index: ${winnerIndex} (out of ${participants} participants)`);
console.log("Draw is verifiable:", isValidDraw);
return {
lotteryId,
winnerIndex,
vrfOutput,
isValidDraw,
organizerPublic
};
}
vrfLotterySystem();import {
waitReady,
vrfSign,
vrfVerify,
sr25519KeypairFromSeed
} from "@polkadot/wasm-crypto";
async function deterministicSelection() {
await waitReady();
// Authority keypair
const authoritySeed = new Uint8Array(32).fill(42); // Fixed seed for reproducible example
const authorityKeypair = sr25519KeypairFromSeed(authoritySeed);
const authoritySecret = authorityKeypair.slice(0, 32);
const authorityPublic = authorityKeypair.slice(32, 64);
// Selection parameters
const context = new TextEncoder().encode("committee-selection");
const epoch = 100;
const candidates = ["Alice", "Bob", "Charlie", "Dave", "Eve"];
// Generate VRF for each candidate
const selections = candidates.map((candidate, index) => {
const message = new TextEncoder().encode(`epoch:${epoch}:candidate:${candidate}`);
const vrfOutput = vrfSign(authoritySecret, context, message, new Uint8Array(0));
const randomValue = vrfOutput.slice(0, 32);
// Convert to selection score
const score = new DataView(randomValue.buffer).getUint32(0, false);
return {
candidate,
score,
vrfOutput,
isValid: vrfVerify(authorityPublic, context, message, new Uint8Array(0), vrfOutput)
};
});
// Sort by VRF score and select top candidates
const sortedSelections = selections.sort((a, b) => b.score - a.score);
const selectedCommittee = sortedSelections.slice(0, 3);
console.log(`Committee selection for epoch ${epoch}:`);
selectedCommittee.forEach((selection, index) => {
console.log(`${index + 1}. ${selection.candidate} (score: ${selection.score}, valid: ${selection.isValid})`);
});
return { selectedCommittee, allSelections: sortedSelections };
}
deterministicSelection();VRF provides three key security properties:
These properties make VRF ideal for applications requiring transparent, verifiable randomness in decentralized systems.
Install with Tessl CLI
npx tessl i tessl/npm-polkadot--wasm-crypto