or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

big-number-arithmetic.mdbit-array-utilities.mdcipher-modes.mddata-encoding.mdelliptic-curve-cryptography.mdhash-functions.mdhigh-level-encryption.mdindex.mdkey-derivation.mdkey-exchange.mdmessage-authentication.mdrandom-number-generation.mdsymmetric-encryption.md

random-number-generation.mddocs/

0

# Random Number Generation

1

2

SJCL provides cryptographically secure pseudo-random number generation with entropy collection from multiple sources, configurable paranoia levels, and both singleton and class-based interfaces for different use cases.

3

4

## Capabilities

5

6

### Global Random Instance

7

8

SJCL provides a pre-configured global random number generator instance with paranoia level 6.

9

10

```javascript { .api }

11

/**

12

* Global PRNG instance with paranoia level 6

13

*/

14

sjcl.random;

15

16

/**

17

* Generate cryptographically secure random words

18

* @param {number} nwords - Number of 32-bit words to generate

19

* @param {number} [paranoia] - Paranoia level override (0-10)

20

* @returns {BitArray} Array of random 32-bit words

21

* @throws {sjcl.exception.notReady} If generator is not sufficiently seeded

22

*/

23

sjcl.random.randomWords(nwords, paranoia);

24

25

/**

26

* Add entropy to the random number generator

27

* @param {number|number[]|string} data - Entropy data

28

* @param {number} estimatedEntropy - Estimated bits of entropy

29

* @param {string} [source] - Source identifier for entropy

30

*/

31

sjcl.random.addEntropy(data, estimatedEntropy, source);

32

33

/**

34

* Check if generator is ready to produce secure random numbers

35

* @param {number} [paranoia] - Paranoia level to check (0-10)

36

* @returns {number} Readiness level (0: not ready, 1: ready, 2: seeded, 3: ready+seeded)

37

*/

38

sjcl.random.isReady(paranoia);

39

40

/**

41

* Get progress toward being ready

42

* @param {number} [paranoia] - Paranoia level to check

43

* @returns {number} Progress value between 0 and 1

44

*/

45

sjcl.random.getProgress(paranoia);

46

```

47

48

**Usage Examples:**

49

50

```javascript

51

const sjcl = require('sjcl');

52

53

// Basic random number generation

54

console.log('Generator ready:', sjcl.random.isReady());

55

56

// Generate random data

57

const randomBytes = sjcl.random.randomWords(4); // 4 * 32 = 128 bits

58

console.log('Random hex:', sjcl.codec.hex.fromBits(randomBytes));

59

60

// Check progress

61

console.log('Progress:', Math.round(sjcl.random.getProgress() * 100) + '%');

62

63

// Add custom entropy

64

sjcl.random.addEntropy(Date.now(), 16, 'timestamp');

65

sjcl.random.addEntropy(Math.random(), 32, 'math-random');

66

67

// Generate different amounts of random data

68

const randomByte = sjcl.random.randomWords(1); // 32 bits

69

const randomKey = sjcl.random.randomWords(8); // 256 bits

70

const randomIV = sjcl.random.randomWords(4); // 128 bits

71

```

72

73

### PRNG Class

74

75

Create custom random number generator instances with specific configurations.

76

77

```javascript { .api }

78

/**

79

* Pseudo-random number generator constructor

80

* @param {number} [defaultParanoia] - Default paranoia level (0-10)

81

*/

82

new sjcl.prng(defaultParanoia);

83

84

/**

85

* Generate random words

86

* @param {number} nwords - Number of 32-bit words to generate

87

* @param {number} [paranoia] - Paranoia level override

88

* @returns {BitArray} Array of random 32-bit words

89

*/

90

sjcl.prng.prototype.randomWords(nwords, paranoia);

91

92

/**

93

* Set default paranoia level

94

* @param {number} paranoia - Paranoia level (0-10)

95

* @param {string} [allowZeroParanoia] - Required string to allow paranoia 0

96

*/

97

sjcl.prng.prototype.setDefaultParanoia(paranoia, allowZeroParanoia);

98

99

/**

100

* Add entropy to the generator

101

* @param {number|number[]|string} data - Entropy data

102

* @param {number} estimatedEntropy - Estimated bits of entropy

103

* @param {string} [source] - Source identifier

104

*/

105

sjcl.prng.prototype.addEntropy(data, estimatedEntropy, source);

106

107

/**

108

* Check generator readiness

109

* @param {number} [paranoia] - Paranoia level to check

110

* @returns {number} Readiness state

111

*/

112

sjcl.prng.prototype.isReady(paranoia);

113

114

/**

115

* Get seeding progress

116

* @param {number} [paranoia] - Paranoia level to check

117

* @returns {number} Progress (0-1)

118

*/

119

sjcl.prng.prototype.getProgress(paranoia);

120

```

121

122

**Usage Examples:**

123

124

```javascript

125

const sjcl = require('sjcl');

126

127

// Create custom PRNG instance

128

const customRNG = new sjcl.prng(8); // High paranoia level

129

130

// Seed the custom RNG

131

customRNG.addEntropy('custom seed data', 64, 'custom');

132

customRNG.addEntropy(Date.now(), 16, 'timestamp');

133

134

// Wait for sufficient entropy

135

while (customRNG.getProgress() < 1.0) {\n customRNG.addEntropy(Math.random(), 32, 'fallback');\n}\n\n// Generate random data\nconst customRandom = customRNG.randomWords(4);\nconsole.log('Custom random:', sjcl.codec.hex.fromBits(customRandom));\n\n// Create low-paranoia RNG for testing\nconst testRNG = new sjcl.prng(0);\ntestRNG.setDefaultParanoia(0, 'Setting paranoia=0 will ruin your security; use it only for testing');\n```\n\n### Entropy Collection\n\nSJCL automatically collects entropy from various browser sources when available.\n\n```javascript { .api }\n/**\n * Start automatic entropy collectors\n */\nsjcl.random.startCollectors();\n\n/**\n * Stop automatic entropy collectors\n */\nsjcl.random.stopCollectors();\n\n/**\n * Add event listener for generator events\n * @param {string} name - Event name ('seeded' or 'progress')\n * @param {Function} callback - Event callback function\n */\nsjcl.random.addEventListener(name, callback);\n\n/**\n * Remove event listener\n * @param {string} name - Event name\n * @param {Function} cb - Callback function to remove\n */\nsjcl.random.removeEventListener(name, cb);\n```\n\n**Usage Examples:**\n\n```javascript\nconst sjcl = require('sjcl');\n\n// Start collecting entropy from browser events\nif (typeof window !== 'undefined') {\n sjcl.random.startCollectors();\n \n // Listen for seeding events\n sjcl.random.addEventListener('seeded', function() {\n console.log('RNG is now seeded and ready!');\n });\n \n sjcl.random.addEventListener('progress', function(progress) {\n console.log('Entropy progress:', Math.round(progress * 100) + '%');\n });\n}\n\n// Manual entropy collection\nfunction collectEntropy() {\n // System time\n sjcl.random.addEntropy(Date.now(), 16, 'time');\n \n // Performance timing (if available)\n if (typeof performance !== 'undefined' && performance.now) {\n sjcl.random.addEntropy(performance.now(), 16, 'performance');\n }\n \n // Math.random as fallback (low entropy)\n sjcl.random.addEntropy(Math.random(), 16, 'math-random');\n \n // User agent string\n if (typeof navigator !== 'undefined') {\n sjcl.random.addEntropy(navigator.userAgent, 8, 'useragent');\n }\n}\n\ncollectEntropy();\n```\n\n## Paranoia Levels\n\nSJCL uses paranoia levels from 0-10 to control entropy requirements:\n\n```javascript\nconst sjcl = require('sjcl');\n\n// Paranoia level meanings:\n// 0: No entropy required (INSECURE - testing only)\n// 1-5: Low to medium entropy requirements\n// 6: Default level (balanced security/performance)\n// 7-10: High entropy requirements (slower but more secure)\n\n// Check requirements for different paranoia levels\nfor (let level = 0; level <= 10; level++) {\n const ready = sjcl.random.isReady(level);\n const progress = sjcl.random.getProgress(level);\n console.log(`Paranoia ${level}: ready=${ready}, progress=${progress.toFixed(2)}`);\n}\n\n// Generate with specific paranoia\nfunction generateSecureRandom(bits, paranoia = 6) {\n const words = Math.ceil(bits / 32);\n \n if (sjcl.random.isReady(paranoia) === 0) {\n throw new sjcl.exception.notReady('Insufficient entropy for paranoia level ' + paranoia);\n }\n \n const random = sjcl.random.randomWords(words, paranoia);\n return sjcl.bitArray.clamp(random, bits);\n}\n\n// Usage\ntry {\n const highSecurityRandom = generateSecureRandom(256, 10);\n const normalRandom = generateSecureRandom(256, 6);\n const fastRandom = generateSecureRandom(256, 2);\n} catch (e) {\n console.error('Not enough entropy:', e.message);\n}\n```\n\n## Cryptographic Key Generation\n\nGenerate cryptographic keys using the secure random number generator:\n\n```javascript\nconst sjcl = require('sjcl');\n\n// AES key generation\nfunction generateAESKey(keySize = 256, paranoia = 6) {\n const words = keySize / 32;\n return sjcl.random.randomWords(words, paranoia);\n}\n\n// Generate keys for different purposes\nfunction generateKeySet() {\n return {\n encryptionKey: generateAESKey(256, 8),\n authKey: generateAESKey(256, 8),\n salt: sjcl.random.randomWords(4, 6), // 128-bit salt\n iv: sjcl.random.randomWords(4, 6), // 128-bit IV\n nonce: sjcl.random.randomWords(3, 6) // 96-bit nonce for GCM\n };\n}\n\n// Secure random password generation\nfunction generateRandomPassword(length = 16) {\n const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*';\n const randomBytes = sjcl.random.randomWords(Math.ceil(length / 4));\n const byteArray = sjcl.codec.bytes.fromBits(randomBytes);\n \n let password = '';\n for (let i = 0; i < length; i++) {\n password += charset[byteArray[i] % charset.length];\n }\n \n return password;\n}\n\n// Usage\nif (sjcl.random.isReady(8)) {\n const keys = generateKeySet();\n const password = generateRandomPassword(20);\n console.log('Generated secure keys and password');\n} else {\n console.log('Waiting for more entropy...');\n}\n```\n\n## Node.js Integration\n\nSJCL automatically uses Node.js crypto.randomBytes when available:\n\n```javascript\nconst sjcl = require('sjcl');\n\n// In Node.js, SJCL automatically uses crypto.randomBytes for seeding\n// This provides high-quality entropy immediately\n\nif (typeof module !== 'undefined' && module.exports) {\n // Running in Node.js\n console.log('Node.js detected - using crypto.randomBytes');\n console.log('Generator ready:', sjcl.random.isReady());\n \n // Can generate secure random numbers immediately\n const nodeRandom = sjcl.random.randomWords(8);\n console.log('Node random:', sjcl.codec.hex.fromBits(nodeRandom));\n} else {\n // Running in browser - may need entropy collection\n console.log('Browser detected - collecting entropy');\n sjcl.random.startCollectors();\n}\n```\n\n## Advanced Usage Patterns\n\n### Deterministic Random for Testing\n\n```javascript\nconst sjcl = require('sjcl');\n\n// Create deterministic RNG for reproducible tests\nfunction createTestRNG(seed) {\n const testRNG = new sjcl.prng(0);\n testRNG.setDefaultParanoia(0, 'Setting paranoia=0 will ruin your security; use it only for testing');\n \n // Seed with deterministic value\n const seedBits = sjcl.codec.utf8String.toBits(seed);\n testRNG.addEntropy(seedBits, 256, 'test-seed');\n \n return testRNG;\n}\n\n// Usage in tests\nconst testRNG = createTestRNG('test-seed-123');\nconst testRandom1 = testRNG.randomWords(4);\nconst testRandom2 = testRNG.randomWords(4);\n\n// Same seed will produce same sequence\nconst testRNG2 = createTestRNG('test-seed-123');\nconst testRandom1Copy = testRNG2.randomWords(4);\nconsole.log('Reproducible:', sjcl.bitArray.equal(testRandom1, testRandom1Copy));\n```\n\n### Entropy Pool Monitoring\n\n```javascript\nconst sjcl = require('sjcl');\n\nclass EntropyMonitor {\n constructor() {\n this.callbacks = [];\n this.monitoring = false;\n }\n \n start() {\n if (this.monitoring) return;\n \n this.monitoring = true;\n sjcl.random.startCollectors();\n \n const checkProgress = () => {\n const progress = sjcl.random.getProgress();\n const ready = sjcl.random.isReady();\n \n this.callbacks.forEach(cb => cb({ progress, ready }));\n \n if (this.monitoring) {\n setTimeout(checkProgress, 1000);\n }\n };\n \n checkProgress();\n }\n \n stop() {\n this.monitoring = false;\n sjcl.random.stopCollectors();\n }\n \n onUpdate(callback) {\n this.callbacks.push(callback);\n }\n}\n\n// Usage\nconst monitor = new EntropyMonitor();\nmonitor.onUpdate(({ progress, ready }) => {\n console.log(`Entropy: ${Math.round(progress * 100)}%, Ready: ${ready}`);\n});\n\nmonitor.start();\n```\n\n## Security Recommendations\n\n1. **Seeding**: Always ensure the generator is properly seeded before use\n2. **Paranoia Levels**: Use higher paranoia levels (6-8) for cryptographic keys\n3. **Entropy Sources**: Combine multiple entropy sources when possible\n4. **Testing**: Use paranoia 0 ONLY for testing, never in production\n5. **Monitoring**: Monitor entropy collection in browser environments\n6. **Node.js**: Leverage crypto.randomBytes in Node.js for better entropy\n\n## Common Pitfalls\n\n1. **Insufficient Entropy**: Using generator before it's properly seeded\n2. **Low Paranoia**: Using paranoia 0 in production\n3. **Predictable Seeds**: Seeding with predictable values\n4. **Entropy Estimation**: Over-estimating entropy from weak sources\n5. **Timing**: Not waiting for sufficient entropy collection in browsers