randBitsSync
This commit is contained in:
parent
66b4d7fad1
commit
c52d54f66b
110
README.md
110
README.md
|
@ -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.<boolean></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.<boolean></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.<bigint></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.<bigint></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.<(Buffer\|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>Promise.<(Buffer\|Uint8Array)></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.<(Buffer\|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>Promise.<(Buffer\|Uint8Array)></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>
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
||||
jsdoc2md.clear().then(() => {
|
||||
const readmeContents = jsdoc2md.renderSync(options)
|
||||
|
||||
const readmeFile = path.join(rootDir, 'README.md')
|
||||
|
||||
fs.writeFileSync(readmeFile, readmeContents)
|
||||
})
|
||||
|
|
|
@ -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
|
@ -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,15 +227,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 */
|
||||
{ // 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 }
|
||||
|
|
|
@ -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,16 +245,17 @@ 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
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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()
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue