0
# VRF (Verifiable Random Functions)
1
2
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.
3
4
## Capabilities
5
6
### VRF Sign (Generate Random Output with Proof)
7
8
Creates a VRF signature that produces a random output along with a proof of correctness.
9
10
```typescript { .api }
11
/**
12
* Creates VRF signature with random output and proof
13
* @param secret - 32-byte secret key as Uint8Array
14
* @param context - Context data as Uint8Array (domain separation)
15
* @param message - Message/input data as Uint8Array
16
* @param extra - Additional data as Uint8Array (can be empty)
17
* @returns VRF output and proof as Uint8Array (96 bytes: 32-byte output + 64-byte proof)
18
*/
19
function vrfSign(secret: Uint8Array, context: Uint8Array, message: Uint8Array, extra: Uint8Array): Uint8Array;
20
```
21
22
**Usage Example:**
23
24
```typescript
25
import { waitReady, vrfSign, sr25519KeypairFromSeed } from "@polkadot/wasm-crypto";
26
27
await waitReady();
28
29
// Generate VRF keypair (uses Sr25519)
30
const seed = new Uint8Array(32).fill(1);
31
const keypair = sr25519KeypairFromSeed(seed);
32
const secretKey = keypair.slice(0, 32);
33
34
// VRF inputs
35
const context = new TextEncoder().encode("vrf-context");
36
const message = new TextEncoder().encode("block-123");
37
const extra = new Uint8Array(0); // No extra data
38
39
const vrfOutput = vrfSign(secretKey, context, message, extra);
40
41
console.log("VRF output length:", vrfOutput.length); // 96
42
console.log("Random output:", vrfOutput.slice(0, 32)); // First 32 bytes
43
console.log("Proof:", vrfOutput.slice(32, 96)); // Last 64 bytes
44
```
45
46
### VRF Verify
47
48
Verifies a VRF signature and proof against the original inputs and public key.
49
50
```typescript { .api }
51
/**
52
* Verifies VRF signature and proof
53
* @param pubkey - 32-byte public key as Uint8Array
54
* @param context - Context data as Uint8Array (must match signing context)
55
* @param message - Message/input data as Uint8Array (must match signing message)
56
* @param extra - Additional data as Uint8Array (must match signing extra)
57
* @param outAndProof - 96-byte VRF output and proof as Uint8Array
58
* @returns true if VRF signature is valid, false otherwise
59
*/
60
function vrfVerify(pubkey: Uint8Array, context: Uint8Array, message: Uint8Array, extra: Uint8Array, outAndProof: Uint8Array): boolean;
61
```
62
63
**Usage Example:**
64
65
```typescript
66
import {
67
waitReady,
68
vrfSign,
69
vrfVerify,
70
sr25519KeypairFromSeed
71
} from "@polkadot/wasm-crypto";
72
73
await waitReady();
74
75
// Generate VRF keypair
76
const seed = new Uint8Array(32).fill(1);
77
const keypair = sr25519KeypairFromSeed(seed);
78
const secretKey = keypair.slice(0, 32);
79
const publicKey = keypair.slice(32, 64);
80
81
// VRF signing
82
const context = new TextEncoder().encode("lottery-draw");
83
const message = new TextEncoder().encode("round-456");
84
const extra = new Uint8Array(0);
85
86
const vrfOutput = vrfSign(secretKey, context, message, extra);
87
88
// VRF verification
89
const isValid = vrfVerify(publicKey, context, message, extra, vrfOutput);
90
console.log("VRF signature is valid:", isValid); // true
91
92
// Test with wrong context
93
const wrongContext = new TextEncoder().encode("wrong-context");
94
const isInvalid = vrfVerify(publicKey, wrongContext, message, extra, vrfOutput);
95
console.log("Wrong context signature is valid:", isInvalid); // false
96
```
97
98
## VRF Use Cases and Examples
99
100
### Blockchain Random Beacon
101
102
```typescript
103
import {
104
waitReady,
105
vrfSign,
106
vrfVerify,
107
sr25519KeypairFromSeed
108
} from "@polkadot/wasm-crypto";
109
110
async function blockchainRandomBeacon() {
111
await waitReady();
112
113
// Validator's keypair
114
const validatorSeed = new Uint8Array(32);
115
crypto.getRandomValues(validatorSeed);
116
117
const validatorKeypair = sr25519KeypairFromSeed(validatorSeed);
118
const validatorSecret = validatorKeypair.slice(0, 32);
119
const validatorPublic = validatorKeypair.slice(32, 64);
120
121
// Block production
122
const context = new TextEncoder().encode("block-production");
123
const blockHeight = 12345;
124
const message = new Uint8Array(4);
125
new DataView(message.buffer).setUint32(0, blockHeight, false); // Big-endian block height
126
127
const vrfOutput = vrfSign(validatorSecret, context, message, new Uint8Array(0));
128
const randomValue = vrfOutput.slice(0, 32);
129
const proof = vrfOutput.slice(32, 96);
130
131
// Anyone can verify the randomness
132
const isValidRandom = vrfVerify(validatorPublic, context, message, new Uint8Array(0), vrfOutput);
133
134
console.log(`Block ${blockHeight} random beacon:`);
135
console.log("Random value:", Array.from(randomValue.slice(0, 8)).map(b => b.toString(16).padStart(2, '0')).join(''));
136
console.log("Proof valid:", isValidRandom);
137
138
return { randomValue, proof, isValidRandom };
139
}
140
141
blockchainRandomBeacon();
142
```
143
144
### Lottery System
145
146
```typescript
147
import {
148
waitReady,
149
vrfSign,
150
vrfVerify,
151
sr25519KeypairFromSeed
152
} from "@polkadot/wasm-crypto";
153
154
async function vrfLotterySystem() {
155
await waitReady();
156
157
// Lottery organizer's keypair
158
const organizerSeed = new Uint8Array(32);
159
crypto.getRandomValues(organizerSeed);
160
161
const organizerKeypair = sr25519KeypairFromSeed(organizerSeed);
162
const organizerSecret = organizerKeypair.slice(0, 32);
163
const organizerPublic = organizerKeypair.slice(32, 64);
164
165
// Lottery parameters
166
const lotteryId = "lottery-2024-001";
167
const drawDate = "2024-12-31";
168
const participants = 1000;
169
170
const context = new TextEncoder().encode(`lottery:${lotteryId}`);
171
const message = new TextEncoder().encode(`draw:${drawDate}:participants:${participants}`);
172
173
// Generate verifiable random winner
174
const vrfOutput = vrfSign(organizerSecret, context, message, new Uint8Array(0));
175
const randomBytes = vrfOutput.slice(0, 32);
176
177
// Convert random bytes to winner index
178
const randomValue = new DataView(randomBytes.buffer).getUint32(0, false);
179
const winnerIndex = randomValue % participants;
180
181
// Verify the lottery result
182
const isValidDraw = vrfVerify(organizerPublic, context, message, new Uint8Array(0), vrfOutput);
183
184
console.log(`Lottery ${lotteryId} results:`);
185
console.log(`Winner index: ${winnerIndex} (out of ${participants} participants)`);
186
console.log("Draw is verifiable:", isValidDraw);
187
188
return {
189
lotteryId,
190
winnerIndex,
191
vrfOutput,
192
isValidDraw,
193
organizerPublic
194
};
195
}
196
197
vrfLotterySystem();
198
```
199
200
### Deterministic Random Selection
201
202
```typescript
203
import {
204
waitReady,
205
vrfSign,
206
vrfVerify,
207
sr25519KeypairFromSeed
208
} from "@polkadot/wasm-crypto";
209
210
async function deterministicSelection() {
211
await waitReady();
212
213
// Authority keypair
214
const authoritySeed = new Uint8Array(32).fill(42); // Fixed seed for reproducible example
215
const authorityKeypair = sr25519KeypairFromSeed(authoritySeed);
216
const authoritySecret = authorityKeypair.slice(0, 32);
217
const authorityPublic = authorityKeypair.slice(32, 64);
218
219
// Selection parameters
220
const context = new TextEncoder().encode("committee-selection");
221
const epoch = 100;
222
const candidates = ["Alice", "Bob", "Charlie", "Dave", "Eve"];
223
224
// Generate VRF for each candidate
225
const selections = candidates.map((candidate, index) => {
226
const message = new TextEncoder().encode(`epoch:${epoch}:candidate:${candidate}`);
227
const vrfOutput = vrfSign(authoritySecret, context, message, new Uint8Array(0));
228
const randomValue = vrfOutput.slice(0, 32);
229
230
// Convert to selection score
231
const score = new DataView(randomValue.buffer).getUint32(0, false);
232
233
return {
234
candidate,
235
score,
236
vrfOutput,
237
isValid: vrfVerify(authorityPublic, context, message, new Uint8Array(0), vrfOutput)
238
};
239
});
240
241
// Sort by VRF score and select top candidates
242
const sortedSelections = selections.sort((a, b) => b.score - a.score);
243
const selectedCommittee = sortedSelections.slice(0, 3);
244
245
console.log(`Committee selection for epoch ${epoch}:`);
246
selectedCommittee.forEach((selection, index) => {
247
console.log(`${index + 1}. ${selection.candidate} (score: ${selection.score}, valid: ${selection.isValid})`);
248
});
249
250
return { selectedCommittee, allSelections: sortedSelections };
251
}
252
253
deterministicSelection();
254
```
255
256
## VRF Security Properties
257
258
VRF provides three key security properties:
259
260
1. **Uniqueness**: Each input produces exactly one valid output and proof
261
2. **Verifiability**: Anyone can verify the output was correctly generated from the input
262
3. **Pseudorandomness**: Without the secret key, outputs are indistinguishable from random
263
264
These properties make VRF ideal for applications requiring transparent, verifiable randomness in decentralized systems.