@bsv/sdk
Version:
BSV Blockchain Software Development Kit
102 lines (90 loc) • 2.96 kB
text/typescript
/**
* Random number generator that works across modern JavaScript environments.
*
* This implementation uses the Web Crypto API which is available in:
* - Node.js 6+ via require('crypto').randomBytes()
* - Node.js 18+ via globalThis.crypto
* - Modern browsers via globalThis.crypto, self.crypto, or window.crypto
* - Web Workers and Service Workers via self.crypto
* - Deno and Bun via globalThis.crypto
*
* @throws {Error} If no secure random number generator is available
*/
class Rand {
_rand: (n: number) => number[] // ✅ Explicit function type
getRandomValues (obj: any, n: number): number[] {
const arr = new Uint8Array(n)
obj.crypto.getRandomValues(arr)
return Array.from(arr)
}
constructor () {
const noRand = (): never => {
throw new Error(
'No secure random number generator is available in this environment.'
)
}
this._rand = noRand // Assign the function
// Try globalThis.crypto (works in Node.js 18+, modern browsers, and Deno)
if (typeof globalThis !== 'undefined' && typeof (globalThis as any).crypto?.getRandomValues === 'function') {
this._rand = (n) => {
/* eslint-disable-next-line */
return this.getRandomValues(globalThis as any, n)
}
return
}
// Node.js fallback for versions < 18
if (typeof process !== 'undefined' && process.release?.name === 'node') {
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const crypto = require('crypto')
if (typeof crypto.randomBytes === 'function') {
this._rand = (n) => {
return Array.from(crypto.randomBytes(n))
}
return
}
} catch (e) {
// crypto module not available, continue to other checks
}
}
// Try self.crypto (Web Workers and Service Workers)
if (typeof self !== 'undefined' && typeof self.crypto?.getRandomValues === 'function') {
this._rand = (n) => {
/* eslint-disable-next-line */
return this.getRandomValues(self as any, n)
}
return
}
// Try window.crypto (browsers)
if (typeof window !== 'undefined' && typeof (window as any).crypto?.getRandomValues === 'function') {
this._rand = (n) => {
/* eslint-disable-next-line */
return this.getRandomValues(window as any, n)
}
return
}
// No crypto available
this._rand = noRand
}
generate (len: number): number[] {
return this._rand(len)
}
}
let ayn: Rand | null = null
/**
* Generates a sequence of pseudo-random bytes with the given length.
*
* @param len - The number of bytes to generate
*
* @returns The generated bytes
*
* @example
* import Random from '@bsv/sdk/primitives/Random'
* const bytes = Random(32) // Produces 32 random bytes
*/
export default (len: number): number[] => {
if (ayn == null) {
ayn = new Rand()
}
return ayn.generate(len)
}