UNPKG

@schukai/monster

Version:

Monster is a simple library for creating fast, robust and lightweight websites.

117 lines (97 loc) 2.84 kB
/** * Copyright © Volker Schukai and all contributing authors, {{copyRightYear}}. All rights reserved. * Node module: @schukai/monster * * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3). * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html * * For those who do not wish to adhere to the AGPLv3, a commercial license is available. * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms. * For more information about purchasing a commercial license, please contact Volker Schukai. * * SPDX-License-Identifier: AGPL-3.0 */ import { getGlobal } from "../types/global.mjs"; export { random }; /** * this function uses crypt and returns a random number. * * @param {number} min starting value of the definition set (default is 0) * @param {number} max end value of the definition set (default is 1000000000) * @return {number} * @throws {Error} missing crypt * @throws {Error} we cannot generate numbers larger than 53 bits. * @throws {Error} the distance is too small to create a random number. * @license AGPLv3 * @since 1.0.0 * @copyright Volker Schukai */ function random(min, max) { if (min === undefined) { min = 0; } if (max === undefined) { max = MAX; } if (max < min) { throw new Error("max must be greater than min"); } return Math.round(create(min, max)); } /** * @private * @type {number} */ const MAX = 1000000000; Math.log2 = Math.log2 || function (n) { return Math.log(n) / Math.log(2); }; /** * * @param {number} min * @param {number} max * @return {number} * @private * @throws {Error} missing crypt * @throws {Error} we cannot generate numbers larger than 53 bits. * @throws {Error} the distance is too small to create a random number. */ function create(min, max) { const globalReference = getGlobal(); const crypt = globalReference?.["crypto"] || globalReference?.["msCrypto"] || globalReference?.["crypto"] || undefined; if (typeof crypt === "undefined") { throw new Error("missing crypt"); } let rval = 0; const range = max - min; if (range < 2) { throw new Error("the distance is too small to create a random number."); } const bitsNeeded = Math.ceil(Math.log2(range)); if (bitsNeeded > 53) { throw new Error("we cannot generate numbers larger than 53 bits."); } const bytesNeeded = Math.ceil(bitsNeeded / 8); const mask = Math.pow(2, bitsNeeded) - 1; const byteArray = new Uint8Array(bytesNeeded); crypt.getRandomValues(byteArray); let p = (bytesNeeded - 1) * 8; for (let i = 0; i < bytesNeeded; i++) { rval += byteArray[i] * Math.pow(2, p); p -= 8; } rval = rval & mask; if (rval >= range) { return create(min, max); } if (rval < min) { rval += min; } return rval; }