CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sjcl

Stanford JavaScript Crypto Library providing comprehensive cryptographic operations including AES encryption, hash functions, key derivation, and elliptic curve cryptography.

Pending
Overview
Eval results
Files

random-number-generation.mddocs/

Random Number Generation

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.

Capabilities

Global Random Instance

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

/**
 * Global PRNG instance with paranoia level 6
 */
sjcl.random;

/**
 * Generate cryptographically secure random words
 * @param {number} nwords - Number of 32-bit words to generate
 * @param {number} [paranoia] - Paranoia level override (0-10)
 * @returns {BitArray} Array of random 32-bit words
 * @throws {sjcl.exception.notReady} If generator is not sufficiently seeded
 */
sjcl.random.randomWords(nwords, paranoia);

/**
 * Add entropy to the random number generator
 * @param {number|number[]|string} data - Entropy data
 * @param {number} estimatedEntropy - Estimated bits of entropy
 * @param {string} [source] - Source identifier for entropy
 */
sjcl.random.addEntropy(data, estimatedEntropy, source);

/**
 * Check if generator is ready to produce secure random numbers
 * @param {number} [paranoia] - Paranoia level to check (0-10)
 * @returns {number} Readiness level (0: not ready, 1: ready, 2: seeded, 3: ready+seeded)
 */
sjcl.random.isReady(paranoia);

/**
 * Get progress toward being ready
 * @param {number} [paranoia] - Paranoia level to check
 * @returns {number} Progress value between 0 and 1
 */
sjcl.random.getProgress(paranoia);

Usage Examples:

const sjcl = require('sjcl');

// Basic random number generation
console.log('Generator ready:', sjcl.random.isReady());

// Generate random data
const randomBytes = sjcl.random.randomWords(4); // 4 * 32 = 128 bits
console.log('Random hex:', sjcl.codec.hex.fromBits(randomBytes));

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

// Add custom entropy
sjcl.random.addEntropy(Date.now(), 16, 'timestamp');
sjcl.random.addEntropy(Math.random(), 32, 'math-random');

// Generate different amounts of random data
const randomByte = sjcl.random.randomWords(1); // 32 bits
const randomKey = sjcl.random.randomWords(8);  // 256 bits
const randomIV = sjcl.random.randomWords(4);   // 128 bits

PRNG Class

Create custom random number generator instances with specific configurations.

/**
 * Pseudo-random number generator constructor
 * @param {number} [defaultParanoia] - Default paranoia level (0-10)
 */
new sjcl.prng(defaultParanoia);

/**
 * Generate random words
 * @param {number} nwords - Number of 32-bit words to generate
 * @param {number} [paranoia] - Paranoia level override
 * @returns {BitArray} Array of random 32-bit words
 */
sjcl.prng.prototype.randomWords(nwords, paranoia);

/**
 * Set default paranoia level
 * @param {number} paranoia - Paranoia level (0-10)
 * @param {string} [allowZeroParanoia] - Required string to allow paranoia 0
 */
sjcl.prng.prototype.setDefaultParanoia(paranoia, allowZeroParanoia);

/**
 * Add entropy to the generator
 * @param {number|number[]|string} data - Entropy data
 * @param {number} estimatedEntropy - Estimated bits of entropy
 * @param {string} [source] - Source identifier
 */
sjcl.prng.prototype.addEntropy(data, estimatedEntropy, source);

/**
 * Check generator readiness
 * @param {number} [paranoia] - Paranoia level to check
 * @returns {number} Readiness state
 */
sjcl.prng.prototype.isReady(paranoia);

/**
 * Get seeding progress
 * @param {number} [paranoia] - Paranoia level to check
 * @returns {number} Progress (0-1)
 */
sjcl.prng.prototype.getProgress(paranoia);

Usage Examples:

const sjcl = require('sjcl');

// Create custom PRNG instance
const customRNG = new sjcl.prng(8); // High paranoia level

// Seed the custom RNG
customRNG.addEntropy('custom seed data', 64, 'custom');
customRNG.addEntropy(Date.now(), 16, 'timestamp');

// Wait for sufficient entropy
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

Install with Tessl CLI

npx tessl i tessl/npm-sjcl

docs

big-number-arithmetic.md

bit-array-utilities.md

cipher-modes.md

data-encoding.md

elliptic-curve-cryptography.md

hash-functions.md

high-level-encryption.md

index.md

key-derivation.md

key-exchange.md

message-authentication.md

random-number-generation.md

symmetric-encryption.md

tile.json