randBitsSync

This commit is contained in:
juanelas 2020-04-07 19:29:23 +02:00
parent 66b4d7fad1
commit c52d54f66b
10 changed files with 1097 additions and 59 deletions

110
README.md
View File

@ -226,6 +226,116 @@ Finds the smallest positive element that is congruent to a in modulo n
| a | <code>number</code> \| <code>bigint</code> | An integer |
| n | <code>number</code> \| <code>bigint</code> | The modulo |
<a name="isProbablyPrime"></a>
### isProbablyPrime(w, [iterations]) ⇒ <code>Promise.&lt;boolean&gt;</code>
The test first tries if any of the first 250 small primes are a factor of the input number and then passes several
iterations of Miller-Rabin Probabilistic Primality Test (FIPS 186-4 C.3.1)
**Kind**: global function
**Returns**: <code>Promise.&lt;boolean&gt;</code> - A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| w | <code>number</code> \| <code>bigint</code> | | An integer to be tested for primality |
| [iterations] | <code>number</code> | <code>16</code> | The number of iterations for the primality test. The value shall be consistent with Table C.1, C.2 or C.3 |
<a name="prime"></a>
### prime(bitLength, [iterations]) ⇒ <code>Promise.&lt;bigint&gt;</code>
A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator.
The browser version uses web workers to parallelise prime look up. Therefore, it does not lock the UI
main process, and it can be much faster (if several cores or cpu are available).
The node version can also use worker_threads if they are available (enabled by default with Node 11 and
and can be enabled at runtime executing node --experimental-worker with node >=10.5.0).
**Kind**: global function
**Returns**: <code>Promise.&lt;bigint&gt;</code> - A promise that resolves to a bigint probable prime of bitLength bits.
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| bitLength | <code>number</code> | | The required bit length for the generated prime |
| [iterations] | <code>number</code> | <code>16</code> | The number of iterations for the Miller-Rabin Probabilistic Primality Test |
<a name="primeSync"></a>
### primeSync(bitLength, [iterations]) ⇒ <code>bigint</code>
A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator.
The sync version is NOT RECOMMENDED since it won't use workers and thus it'll be slower and may freeze thw window in browser's javascript. Please consider using prime() instead.
**Kind**: global function
**Returns**: <code>bigint</code> - A bigint probable prime of bitLength bits.
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| bitLength | <code>number</code> | | The required bit length for the generated prime |
| [iterations] | <code>number</code> | <code>16</code> | The number of iterations for the Miller-Rabin Probabilistic Primality Test |
<a name="randBetween"></a>
### randBetween(max, [min]) ⇒ <code>bigint</code>
Returns a cryptographically secure random integer between [min,max]
**Kind**: global function
**Returns**: <code>bigint</code> - A cryptographically secure random bigint between [min,max]
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| max | <code>bigint</code> | | Returned value will be <= max |
| [min] | <code>bigint</code> | <code>BigInt(1)</code> | Returned value will be >= min |
<a name="randBits"></a>
### randBits(bitLength, [forceLength]) ⇒ <code>Promise.&lt;(Buffer\|Uint8Array)&gt;</code>
Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
**Kind**: global function
**Returns**: <code>Promise.&lt;(Buffer\|Uint8Array)&gt;</code> - A Promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bits
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| bitLength | <code>number</code> | | The desired number of random bits |
| [forceLength] | <code>boolean</code> | <code>false</code> | If we want to force the output to have a specific bit length. It basically forces the msb to be 1 |
<a name="randBitsSync"></a>
### randBitsSync(bitLength, [forceLength]) ⇒ <code>Buffer</code> \| <code>Uint8Array</code>
Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
**Kind**: global function
**Returns**: <code>Buffer</code> \| <code>Uint8Array</code> - A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bits
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| bitLength | <code>number</code> | | The desired number of random bits |
| [forceLength] | <code>boolean</code> | <code>false</code> | If we want to force the output to have a specific bit length. It basically forces the msb to be 1 |
<a name="randBytes"></a>
### randBytes(byteLength, [forceLength]) ⇒ <code>Promise.&lt;(Buffer\|Uint8Array)&gt;</code>
Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
**Kind**: global function
**Returns**: <code>Promise.&lt;(Buffer\|Uint8Array)&gt;</code> - A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| byteLength | <code>number</code> | | The desired number of random bytes |
| [forceLength] | <code>boolean</code> | <code>false</code> | If we want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1 |
<a name="randBytesSync"></a>
### randBytesSync(byteLength, [forceLength]) ⇒ <code>Buffer</code> \| <code>Uint8Array</code>
Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
**Kind**: global function
**Returns**: <code>Buffer</code> \| <code>Uint8Array</code> - A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| byteLength | <code>number</code> | | The desired number of random bytes |
| [forceLength] | <code>boolean</code> | <code>false</code> | If we want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1 |
<a name="egcdReturn"></a>
### egcdReturn : <code>Object</code>

View File

@ -8,17 +8,19 @@ const pkgJson = require('../package.json')
const rootDir = path.join(__dirname, '..')
const template = path.join(rootDir, pkgJson.directories.src, 'doc', 'readme-template.md')
const input = path.join(rootDir, pkgJson.directories.lib, 'index.node.js')
const input = path.join(rootDir, pkgJson.directories.lib, 'index.browser.bundle.mod.js')
const source = fs.readFileSync(input, { encoding: 'UTF-8' }).replace(/([0-9]+)n([,\s\n)])/g, '$1$2')
const options = {
source: fs.readFileSync(input, { encoding: 'UTF-8' }), // we need to use this instead of files in order to avoid issues with esnext features
source, // we need to use this instead of files in order to avoid issues with esnext features
template: fs.readFileSync(template, { encoding: 'UTF-8' }),
'heading-depth': 3, // The initial heading depth. For example, with a value of 2 the top-level markdown headings look like "## The heading"
'global-index-format': 'none' // none, grouped, table, dl.
}
const readmeContents = jsdoc2md.renderSync(options)
jsdoc2md.clear().then(() => {
const readmeContents = jsdoc2md.renderSync(options)
const readmeFile = path.join(rootDir, 'README.md')
fs.writeFileSync(readmeFile, readmeContents)
const readmeFile = path.join(rootDir, 'README.md')
fs.writeFileSync(readmeFile, readmeContents)
})

View File

@ -29,7 +29,7 @@ module.exports = [
input: input,
output: [
{
file: path.join(dstDir, 'index.browser.mod.js'),
file: path.join(rootDir, pkgJson.browser),
format: 'esm'
}
],
@ -46,7 +46,17 @@ module.exports = [
{
file: path.join(dstDir, 'index.browser.bundle.js'),
format: 'iife',
name: pkgCamelisedName
name: pkgCamelisedName,
plugins: [
terser()
]
},
{
file: path.join(dstDir, 'index.browser.bundle.min.mod.js'),
format: 'es',
plugins: [
terser()
]
},
{
file: path.join(dstDir, 'index.browser.bundle.mod.js'),
@ -59,10 +69,6 @@ module.exports = [
}),
resolve({
browser: true
}),
terser({
// mangle: false,
// compress: false
})
]
},

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -65,7 +65,7 @@ function prime (bitLength, iterations = 16) {
}
resolve(msg.value)
} else { // if a composite is found, make the worker test another random number
const buf = randBits(bitLength, true)
const buf = randBitsSync(bitLength, true)
const rnd = fromBuffer(buf)
try {
newWorker.postMessage({
@ -89,7 +89,7 @@ function prime (bitLength, iterations = 16) {
}
/* eslint-enable no-lone-blocks */
for (let i = 0; i < workerList.length; i++) {
const buf = randBits(bitLength, true)
const buf = randBitsSync(bitLength, true)
const rnd = fromBuffer(buf)
workerList[i].postMessage({
rnd: rnd,
@ -131,12 +131,40 @@ function randBetween (max, min = 1n) {
const bitLen = bitLength(interval)
let rnd
do {
const buf = randBits(bitLen)
const buf = randBitsSync(bitLen)
rnd = fromBuffer(buf)
} while (rnd > interval)
return rnd + min
}
/**
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
*
* @param {number} bitLength The desired number of random bits
* @param {boolean} [forceLength = false] If we want to force the output to have a specific bit length. It basically forces the msb to be 1
*
* @returns {Promise<Buffer | Uint8Array>} A Promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bits
*/
async function randBits (bitLength, forceLength = false) {
if (bitLength < 1) {
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
}
const byteLength = Math.ceil(bitLength / 8)
const bitLengthMod8 = bitLength % 8
const rndBytes = await randBytes(byteLength, false)
if (bitLengthMod8) {
// Fill with 0's the extra bits
rndBytes[0] = rndBytes[0] & (2 ** bitLengthMod8 - 1)
}
if (forceLength) {
const mask = bitLengthMod8 ? 2 ** (bitLengthMod8 - 1) : 128
rndBytes[0] = rndBytes[0] | mask
}
return rndBytes
}
/**
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
*
@ -145,7 +173,7 @@ function randBetween (max, min = 1n) {
*
* @returns {Buffer | Uint8Array} A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bits
*/
function randBits (bitLength, forceLength = false) {
function randBitsSync (bitLength, forceLength = false) {
if (bitLength < 1) {
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
}
@ -175,18 +203,17 @@ function randBits (bitLength, forceLength = false) {
function randBytes (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf
/* eslint-disable no-lone-blocks */
{ // browser
return new Promise(function (resolve) {
buf = new Uint8Array(byteLength)
const buf = new Uint8Array(byteLength)
self.crypto.getRandomValues(buf)
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 }
resolve(buf)
})
}
/* eslint-disable no-lone-blocks */
/* eslint-enable no-lone-blocks */
}
/**
@ -200,14 +227,15 @@ function randBytes (byteLength, forceLength = false) {
function randBytesSync (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf
/* eslint-disable no-lone-blocks */
{ // browser
buf = new Uint8Array(byteLength)
const buf = new Uint8Array(byteLength)
self.crypto.getRandomValues(buf)
}
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 }
return buf
}
/* eslint-enable no-lone-blocks */
}
/* HELPER FUNCTIONS */
@ -223,7 +251,7 @@ function fromBuffer (buf) {
function _isProbablyPrimeWorkerUrl () {
// Let's us first add all the required functions
let workerCode = `'use strict';const ${eGcd.name}=${eGcd.toString()};const ${modInv.name}=${modInv.toString()};const ${modPow.name}=${modPow.toString()};const ${toZn.name}=${toZn.toString()};const ${randBits.name}=${randBits.toString()};const ${randBytesSync.name}=${randBytesSync.toString()};const ${randBetween.name}=${randBetween.toString()};const ${isProbablyPrime.name}=${_isProbablyPrime.toString()};${bitLength.toString()}${fromBuffer.toString()}`
let workerCode = `'use strict';const ${eGcd.name}=${eGcd.toString()};const ${modInv.name}=${modInv.toString()};const ${modPow.name}=${modPow.toString()};const ${toZn.name}=${toZn.toString()};const ${randBitsSync.name}=${randBitsSync.toString()};const ${randBytesSync.name}=${randBytesSync.toString()};const ${randBetween.name}=${randBetween.toString()};const ${isProbablyPrime.name}=${_isProbablyPrime.toString()};${bitLength.toString()}${fromBuffer.toString()}`
const onmessage = async function (event) { // Let's start once we are called
// event.data = {rnd: <bigint>, iterations: <number>}
@ -581,4 +609,4 @@ function _isProbablyPrime (w, iterations = 16) {
return true
}
export { isProbablyPrime, prime, primeSync, randBetween, randBits, randBytes, randBytesSync }
export { isProbablyPrime, prime, primeSync, randBetween, randBits, randBitsSync, randBytes, randBytesSync }

View File

@ -82,7 +82,7 @@ function prime (bitLength, iterations = 16) {
}
resolve(msg.value)
} else { // if a composite is found, make the worker test another random number
const buf = randBits(bitLength, true)
const buf = randBitsSync(bitLength, true)
const rnd = fromBuffer(buf)
try {
newWorker.postMessage({
@ -107,7 +107,7 @@ function prime (bitLength, iterations = 16) {
}
/* eslint-enable no-lone-blocks */
for (let i = 0; i < workerList.length; i++) {
const buf = randBits(bitLength, true)
const buf = randBitsSync(bitLength, true)
const rnd = fromBuffer(buf)
workerList[i].postMessage({
rnd: rnd,
@ -149,12 +149,40 @@ function randBetween (max, min = 1n) {
const bitLen = bigintModArith.bitLength(interval)
let rnd
do {
const buf = randBits(bitLen)
const buf = randBitsSync(bitLen)
rnd = fromBuffer(buf)
} while (rnd > interval)
return rnd + min
}
/**
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
*
* @param {number} bitLength The desired number of random bits
* @param {boolean} [forceLength = false] If we want to force the output to have a specific bit length. It basically forces the msb to be 1
*
* @returns {Promise<Buffer | Uint8Array>} A Promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bits
*/
async function randBits (bitLength, forceLength = false) {
if (bitLength < 1) {
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
}
const byteLength = Math.ceil(bitLength / 8)
const bitLengthMod8 = bitLength % 8
const rndBytes = await randBytes(byteLength, false)
if (bitLengthMod8) {
// Fill with 0's the extra bits
rndBytes[0] = rndBytes[0] & (2 ** bitLengthMod8 - 1)
}
if (forceLength) {
const mask = bitLengthMod8 ? 2 ** (bitLengthMod8 - 1) : 128
rndBytes[0] = rndBytes[0] | mask
}
return rndBytes
}
/**
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
*
@ -163,7 +191,7 @@ function randBetween (max, min = 1n) {
*
* @returns {Buffer | Uint8Array} A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bits
*/
function randBits (bitLength, forceLength = false) {
function randBitsSync (bitLength, forceLength = false) {
if (bitLength < 1) {
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
}
@ -193,18 +221,17 @@ function randBits (bitLength, forceLength = false) {
function randBytes (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf
/* eslint-disable no-lone-blocks */
{ // node
const crypto = require('crypto')
buf = Buffer.alloc(byteLength)
const buf = Buffer.alloc(byteLength)
return crypto.randomFill(buf, function (resolve) {
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 }
resolve(buf)
})
}
/* eslint-disable no-lone-blocks */
/* eslint-enable no-lone-blocks */
}
/**
@ -218,15 +245,16 @@ function randBytes (byteLength, forceLength = false) {
function randBytesSync (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf
/* eslint-disable no-lone-blocks */
{ // node
const crypto = require('crypto')
buf = Buffer.alloc(byteLength)
const buf = Buffer.alloc(byteLength)
crypto.randomFillSync(buf)
}
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 }
return buf
}
/* eslint-enable no-lone-blocks */
}
/* HELPER FUNCTIONS */
@ -576,6 +604,7 @@ function _isProbablyPrime (w, iterations = 16) {
}
let _useWorkers = true // The following is just to check whether Node.js can use workers
/* eslint-disable no-lone-blocks */
{ // Node.js
_useWorkers = (function _workers () {
try {
@ -590,6 +619,7 @@ This node version doesn't support worker_threads. You should enable them in orde
}
})()
}
/* eslint-enable no-lone-blocks */
if (_useWorkers) { // node.js with support for workers
const { parentPort, isMainThread } = require('worker_threads')
@ -671,5 +701,6 @@ exports.prime = prime
exports.primeSync = primeSync
exports.randBetween = randBetween
exports.randBits = randBits
exports.randBitsSync = randBitsSync
exports.randBytes = randBytes
exports.randBytesSync = randBytesSync

View File

@ -53,7 +53,7 @@
"ignore": [
"/test/browser/",
"/lib/index.browser.bundle.js",
"/lib/index.browser.bundle.mod.js"
"/lib/index.browser.bundle.min.mod.js"
]
},
"devDependencies": {

View File

@ -8,9 +8,9 @@ export { abs, bitLength, eGcd, gcd, lcm, max, min, modInv, modPow, toZn } from '
* @param {number | bigint} w An integer to be tested for primality
* @param {number} [iterations = 16] The number of iterations for the primality test. The value shall be consistent with Table C.1, C.2 or C.3
*
* @return {Promise<boolean>} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
* @returns {Promise<boolean>} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
*/
export async function isProbablyPrime (w, iterations = 16) {
export function isProbablyPrime (w, iterations = 16) {
if (typeof w === 'number') {
w = BigInt(w)
}
@ -98,7 +98,7 @@ export function prime (bitLength, iterations = 16) {
}
resolve(msg.value)
} else { // if a composite is found, make the worker test another random number
const buf = randBits(bitLength, true)
const buf = randBitsSync(bitLength, true)
const rnd = fromBuffer(buf)
try {
newWorker.postMessage({
@ -130,7 +130,7 @@ export function prime (bitLength, iterations = 16) {
}
/* eslint-enable no-lone-blocks */
for (let i = 0; i < workerList.length; i++) {
const buf = randBits(bitLength, true)
const buf = randBitsSync(bitLength, true)
const rnd = fromBuffer(buf)
workerList[i].postMessage({
rnd: rnd,
@ -172,12 +172,40 @@ export function randBetween (max, min = 1n) {
const bitLen = bitLength(interval)
let rnd
do {
const buf = randBits(bitLen)
const buf = randBitsSync(bitLen)
rnd = fromBuffer(buf)
} while (rnd > interval)
return rnd + min
}
/**
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
*
* @param {number} bitLength The desired number of random bits
* @param {boolean} [forceLength = false] If we want to force the output to have a specific bit length. It basically forces the msb to be 1
*
* @returns {Promise<Buffer | Uint8Array>} A Promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bits
*/
export async function randBits (bitLength, forceLength = false) {
if (bitLength < 1) {
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
}
const byteLength = Math.ceil(bitLength / 8)
const bitLengthMod8 = bitLength % 8
const rndBytes = await randBytes(byteLength, false)
if (bitLengthMod8) {
// Fill with 0's the extra bits
rndBytes[0] = rndBytes[0] & (2 ** bitLengthMod8 - 1)
}
if (forceLength) {
const mask = bitLengthMod8 ? 2 ** (bitLengthMod8 - 1) : 128
rndBytes[0] = rndBytes[0] | mask
}
return rndBytes
}
/**
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
*
@ -186,7 +214,7 @@ export function randBetween (max, min = 1n) {
*
* @returns {Buffer | Uint8Array} A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bits
*/
export function randBits (bitLength, forceLength = false) {
export function randBitsSync (bitLength, forceLength = false) {
if (bitLength < 1) {
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
}
@ -216,11 +244,10 @@ export function randBits (bitLength, forceLength = false) {
export function randBytes (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf
/* eslint-disable no-lone-blocks */
if (!process.browser) { // node
const crypto = require('crypto')
buf = Buffer.alloc(byteLength)
const buf = Buffer.alloc(byteLength)
return crypto.randomFill(buf, function (resolve) {
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 }
@ -228,14 +255,14 @@ export function randBytes (byteLength, forceLength = false) {
})
} else { // browser
return new Promise(function (resolve) {
buf = new Uint8Array(byteLength)
const buf = new Uint8Array(byteLength)
self.crypto.getRandomValues(buf)
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 }
resolve(buf)
})
}
/* eslint-disable no-lone-blocks */
/* eslint-enable no-lone-blocks */
}
/**
@ -249,18 +276,22 @@ export function randBytes (byteLength, forceLength = false) {
export function randBytesSync (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf
/* eslint-disable no-lone-blocks */
if (!process.browser) { // node
const crypto = require('crypto')
buf = Buffer.alloc(byteLength)
const buf = Buffer.alloc(byteLength)
crypto.randomFillSync(buf)
} else { // browser
buf = new Uint8Array(byteLength)
self.crypto.getRandomValues(buf)
}
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 }
return buf
} else { // browser
const buf = new Uint8Array(byteLength)
self.crypto.getRandomValues(buf)
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 }
return buf
}
/* eslint-enable no-lone-blocks */
}
/* HELPER FUNCTIONS */
@ -276,7 +307,7 @@ function fromBuffer (buf) {
function _isProbablyPrimeWorkerUrl () {
// Let's us first add all the required functions
let workerCode = `'use strict';const ${eGcd.name}=${eGcd.toString()};const ${modInv.name}=${modInv.toString()};const ${modPow.name}=${modPow.toString()};const ${toZn.name}=${toZn.toString()};const ${randBits.name}=${randBits.toString()};const ${randBytesSync.name}=${randBytesSync.toString()};const ${randBetween.name}=${randBetween.toString()};const ${isProbablyPrime.name}=${_isProbablyPrime.toString()};${bitLength.toString()}${fromBuffer.toString()}`
let workerCode = `'use strict';const ${eGcd.name}=${eGcd.toString()};const ${modInv.name}=${modInv.toString()};const ${modPow.name}=${modPow.toString()};const ${toZn.name}=${toZn.toString()};const ${randBitsSync.name}=${randBitsSync.toString()};const ${randBytesSync.name}=${randBytesSync.toString()};const ${randBetween.name}=${randBetween.toString()};const ${isProbablyPrime.name}=${_isProbablyPrime.toString()};${bitLength.toString()}${fromBuffer.toString()}`
const onmessage = async function (event) { // Let's start once we are called
// event.data = {rnd: <bigint>, iterations: <number>}
@ -635,6 +666,7 @@ function _isProbablyPrime (w, iterations = 16) {
}
let _useWorkers = true // The following is just to check whether Node.js can use workers
/* eslint-disable no-lone-blocks */
if (!process.browser) { // Node.js
_useWorkers = (function _workers () {
try {
@ -649,6 +681,7 @@ This node version doesn't support worker_threads. You should enable them in orde
}
})()
}
/* eslint-enable no-lone-blocks */
if (!process.browser && _useWorkers) { // node.js with support for workers
const { parentPort, isMainThread } = require('worker_threads')

11
types/index.d.ts vendored
View File

@ -39,6 +39,15 @@ export function primeSync(bitLength: number, iterations?: number): bigint;
* @returns {bigint} A cryptographically secure random bigint between [min,max]
*/
export function randBetween(max: bigint, min?: bigint): bigint;
/**
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
*
* @param {number} bitLength The desired number of random bits
* @param {boolean} [forceLength = false] If we want to force the output to have a specific bit length. It basically forces the msb to be 1
*
* @returns {Promise<Buffer | Uint8Array>} A Promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bits
*/
export function randBits(bitLength: number, forceLength?: boolean): Promise<Uint8Array | Buffer>;
/**
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
*
@ -47,7 +56,7 @@ export function randBetween(max: bigint, min?: bigint): bigint;
*
* @returns {Buffer | Uint8Array} A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bits
*/
export function randBits(bitLength: number, forceLength?: boolean): Uint8Array | Buffer;
export function randBitsSync(bitLength: number, forceLength?: boolean): Uint8Array | Buffer;
/**
* Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
*