UNPKG

remeda

Version:

A utility library for JavaScript and Typescript.

1 lines 4.18 kB
{"version":3,"file":"randomBigInt.cjs","names":[],"sources":["../src/randomBigInt.ts"],"sourcesContent":["/* eslint-disable no-bitwise, @typescript-eslint/no-magic-numbers --\n * We randomize the bigint using randomized bitmaps, we have to use bitwise\n * operations to manipulate them.\n */\n\n/**\n * Generate a random `bigint` between `from` and `to` (inclusive).\n *\n * ! Important: In most environments this function uses\n * [`crypto.getRandomValues()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues)\n * under-the-hood which **is** cryptographically strong. When the WebCrypto API\n * isn't available (Node 18) we fallback to an implementation that uses\n * [`Math.random()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random)\n * which is **NOT** cryptographically secure.\n *\n * @param from - The minimum value.\n * @param to - The maximum value.\n * @returns The random integer.\n * @signature\n * R.randomBigInt(from, to)\n * @example\n * R.randomBigInt(1n, 10n) // => 5n\n * @dataFirst\n * @category Number\n */\nexport function randomBigInt(from: bigint, to: bigint): bigint {\n if (to < from) {\n throw new RangeError(\n `randomBigInt: The range [${from.toString()},${to.toString()}] is empty.`,\n );\n }\n\n const range = to - from;\n\n // Get the max number of bits needed to encode the result. We will generate\n // this number of random bits. A radix of 2 would give us the binary\n // representation of the number.\n const { length: maxBits } = range.toString(2 /* radix */);\n\n // We can only generate random data in bytes, not bits, so we need to generate\n // enough bytes to cover the required number of bits.\n const maxBytes = Math.ceil(maxBits / 8);\n\n // The number of bits we need to ignore in the random bitmap we generate.\n const excessBits = BigInt(8 - (maxBits % 8));\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- It's more readable than using a do..while loop.\n while (true) {\n // We use `crypto` for our RNG, it should be supported in all modern\n // environments we support.\n const randomBytes = random(maxBytes);\n\n const raw = asBigInt(randomBytes);\n\n // Shift the number back to our range, this effectively sets the excess bits\n // to 0.\n const result = raw >> excessBits;\n\n // The generated number might overflow when `range < 2 ** maxBits - 1`, so\n // it can't be returned. To ensure that all possible results have the same\n // probability, we ignore the value entirely and try again (instead of\n // trying to adapt it to the output range somehow).\n if (result <= range) {\n return result + from;\n }\n }\n}\n\nfunction asBigInt(bytes: Iterable<number>): bigint {\n let result = 0n;\n for (const byte of bytes) {\n // We build the bigint by shifting the current value by a byte, and putting\n // the next byte in that \"slot\".\n result = (result << 8n) + BigInt(byte);\n }\n return result;\n}\n\nfunction random(numBytes: number): Uint8Array {\n const output = new Uint8Array(numBytes);\n\n if (typeof crypto === \"undefined\") {\n // Polyfill for environments without `crypto` support. The only env which\n // requires this and we support is Node 18; once we drop support for it we\n // can drop the polyfill.\n for (let index = 0; index < numBytes; index += 1) {\n output[index] = Math.floor(Math.random() * 256);\n }\n } else {\n crypto.getRandomValues(output);\n }\n\n return output;\n}\n"],"mappings":"AAyBA,SAAgB,EAAa,EAAc,EAAoB,CAC7D,GAAI,EAAK,EACP,MAAU,WACR,4BAA4B,EAAK,UAAU,CAAC,GAAG,EAAG,UAAU,CAAC,aAC9D,CAGH,IAAM,EAAQ,EAAK,EAKb,CAAE,OAAQ,GAAY,EAAM,SAAS,EAAc,CAInD,EAAW,KAAK,KAAK,EAAU,EAAE,CAGjC,EAAa,OAAO,EAAK,EAAU,EAAG,CAG5C,OAAa,CASX,IAAM,EAJM,EAFQ,EAAO,EAAS,CAEH,EAIX,EAMtB,GAAI,GAAU,EACZ,OAAO,EAAS,GAKtB,SAAS,EAAS,EAAiC,CACjD,IAAI,EAAS,GACb,IAAK,IAAM,KAAQ,EAGjB,GAAU,GAAU,IAAM,OAAO,EAAK,CAExC,OAAO,EAGT,SAAS,EAAO,EAA8B,CAC5C,IAAM,EAAS,IAAI,WAAW,EAAS,CAEvC,GAAI,OAAO,OAAW,IAIpB,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAU,GAAS,EAC7C,EAAO,GAAS,KAAK,MAAM,KAAK,QAAQ,CAAG,IAAI,MAGjD,OAAO,gBAAgB,EAAO,CAGhC,OAAO"}