or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bip39.mded25519.mdhashing.mdindex.mdkey-derivation.mdsecp256k1.mdsr25519.mdvrf.md

vrf.mddocs/

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.