CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-polkadot--wasm-crypto

WebAssembly interface layer providing high-performance cryptographic functions for blockchain applications in the Polkadot ecosystem.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

vrf.mddocs/

VRF (Verifiable Random Functions)

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.

Capabilities

VRF Sign (Generate Random Output with Proof)

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 bytes

VRF Verify

Verifies 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); // false

VRF Use Cases and Examples

Blockchain Random Beacon

import { 
  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();

Lottery System

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();

Deterministic Random Selection

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 Security Properties

VRF provides three key security properties:

  1. Uniqueness: Each input produces exactly one valid output and proof
  2. Verifiability: Anyone can verify the output was correctly generated from the input
  3. Pseudorandomness: Without the secret key, outputs are indistinguishable from random

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

docs

bip39.md

ed25519.md

hashing.md

index.md

key-derivation.md

secp256k1.md

sr25519.md

vrf.md

tile.json