Now the bundle can be mangled. Multi-threaded uses all CPUs but 1. Readme improvements
This commit is contained in:
parent
e945922b8b
commit
d2a21a818f
195
README.md
195
README.md
|
@ -16,9 +16,9 @@ bigint-crypto-utils can be imported to your project with `npm`:
|
|||
npm install bigint-crypto-utils
|
||||
```
|
||||
|
||||
NPM installation defaults to the minified ES6 module for browsers and the CJS one for Node.js.
|
||||
NPM installation defaults to the ES6 module for browsers and the CJS one for Node.js.
|
||||
|
||||
For web browsers, you can also directly download the [IIFE file](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.js) or the [ES6 module](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.mod.js) from GitHub.
|
||||
For web browsers, you can also directly download the [IIFE bundle](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.js) or the [ES6 bundle module](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.mod.js) from GitHub.
|
||||
|
||||
## Usage examples
|
||||
|
||||
|
@ -29,26 +29,25 @@ Import your module as :
|
|||
const bigintCryptoUtils = require('bigint-crypto-utils')
|
||||
... // your code here
|
||||
```
|
||||
- Javascript native project
|
||||
- JavaScript native project
|
||||
```javascript
|
||||
import * as bigintCryptoUtils from 'bigint-crypto-utils'
|
||||
... // your code here
|
||||
```
|
||||
- Javascript native browser ES6 mod
|
||||
- JavaScript native browser ES6 mod
|
||||
```html
|
||||
<script type="module">
|
||||
import * as bigintCryptoUtils from 'lib/index.browser.bundle.mod.js' // Use you actual path to the broser mod bundle
|
||||
... // your code here
|
||||
</script>
|
||||
import as bcu from 'bigint-crypto-utils'
|
||||
... // your code here
|
||||
```
|
||||
- Javascript native browser IIFE
|
||||
- JavaScript native browser IIFE
|
||||
```html
|
||||
<script src="../../lib/index.browser.bundle.js"></script>
|
||||
<script src="../../lib/index.browser.bundle.js"></script> <!-- Use you actual path to the browser bundle -->
|
||||
<script>
|
||||
... // your code here
|
||||
</script>
|
||||
```
|
||||
- TypeScript
|
||||
```typescript
|
||||
import * as bigintCryptoUtils from 'bigint-crypto-utils'
|
||||
|
@ -56,6 +55,8 @@ Import your module as :
|
|||
```
|
||||
> BigInt is [ES-2020](https://tc39.es/ecma262/#sec-bigint-objects). In order to use it with TypeScript you should set `lib` (and probably also `target` and `module`) to `esnext` in `tsconfig.json`.
|
||||
|
||||
And you could use it like in the following:
|
||||
|
||||
```javascript
|
||||
/* Stage 3 BigInts with value 666 can be declared as BigInt('666')
|
||||
or the shorter new no-so-linter-friendly syntax 666n.
|
||||
|
@ -65,22 +66,22 @@ be raised.
|
|||
*/
|
||||
const a = BigInt('5')
|
||||
const b = BigInt('2')
|
||||
const n = BigInt('19')
|
||||
const n = 19n
|
||||
|
||||
console.log(bigintCryptoUtils.modPow(a, b, n)) // prints 6
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(BigInt('2'), BigInt('5'))) // prints 3
|
||||
console.log(bigintCryptoUtils.modInv(2n, 5n)) // prints 3
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(BigInt('3'), BigInt('5'))) // prints 2
|
||||
|
||||
console.log(bigintCryptoUtils.randBetween(BigInt(2) ** BigInt(256))) // Prints a cryptographically secure random number between 1 and 2**256 bits.
|
||||
console.log(bigintCryptoUtils.randBetween(2n ** 256n)) // Prints a cryptographically secure random number between 1 and 2**256 bits.
|
||||
|
||||
async function primeTesting () {
|
||||
// Output of a probable prime of 2048 bits
|
||||
console.log(await bigintCryptoUtils.prime(2048))
|
||||
|
||||
// Testing if a number is a probable prime (Miller-Rabin)
|
||||
const number = 27
|
||||
const number = 27n
|
||||
const isPrime = await bigintCryptoUtils.isProbablyPrime(number)
|
||||
if (isPrime) {
|
||||
console.log(`${number} is prime`)
|
||||
|
@ -93,78 +94,7 @@ primeTesting()
|
|||
|
||||
```
|
||||
|
||||
## bigint-crypto-utils JS Doc
|
||||
|
||||
### Functions
|
||||
|
||||
<dl>
|
||||
<dt><a href="#abs">abs(a)</a> ⇒ <code>bigint</code></dt>
|
||||
<dd><p>Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0</p>
|
||||
</dd>
|
||||
<dt><a href="#bitLength">bitLength(a)</a> ⇒ <code>number</code></dt>
|
||||
<dd><p>Returns the bitlength of a number</p>
|
||||
</dd>
|
||||
<dt><a href="#eGcd">eGcd(a, b)</a> ⇒ <code><a href="#egcdReturn">egcdReturn</a></code></dt>
|
||||
<dd><p>An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm.
|
||||
Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).</p>
|
||||
</dd>
|
||||
<dt><a href="#gcd">gcd(a, b)</a> ⇒ <code>bigint</code></dt>
|
||||
<dd><p>Greatest-common divisor of two integers based on the iterative binary algorithm.</p>
|
||||
</dd>
|
||||
<dt><a href="#isProbablyPrime">isProbablyPrime(w, [iterations])</a> ⇒ <code>Promise</code></dt>
|
||||
<dd><p>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)</p>
|
||||
</dd>
|
||||
<dt><a href="#lcm">lcm(a, b)</a> ⇒ <code>bigint</code></dt>
|
||||
<dd><p>The least common multiple computed as abs(a*b)/gcd(a,b)</p>
|
||||
</dd>
|
||||
<dt><a href="#max">max(a, b)</a> ⇒ <code>bigint</code></dt>
|
||||
<dd><p>Maximum. max(a,b)==a if a>=b. max(a,b)==b if a<=b</p>
|
||||
</dd>
|
||||
<dt><a href="#min">min(a, b)</a> ⇒ <code>bigint</code></dt>
|
||||
<dd><p>Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<=b</p>
|
||||
</dd>
|
||||
<dt><a href="#modInv">modInv(a, n)</a> ⇒ <code>bigint</code></dt>
|
||||
<dd><p>Modular inverse.</p>
|
||||
</dd>
|
||||
<dt><a href="#modPow">modPow(b, e, n)</a> ⇒ <code>bigint</code></dt>
|
||||
<dd><p>Modular exponentiation b**e mod n. Currently using the right-to-left binary method</p>
|
||||
</dd>
|
||||
<dt><a href="#prime">prime(bitLength, [iterations])</a> ⇒ <code>Promise</code></dt>
|
||||
<dd><p>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).</p>
|
||||
</dd>
|
||||
<dt><a href="#primeSync">primeSync(bitLength, [iterations])</a> ⇒ <code>bigint</code></dt>
|
||||
<dd><p>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.</p>
|
||||
</dd>
|
||||
<dt><a href="#randBetween">randBetween(max, [min])</a> ⇒ <code>bigint</code></dt>
|
||||
<dd><p>Returns a cryptographically secure random integer between [min,max]</p>
|
||||
</dd>
|
||||
<dt><a href="#randBits">randBits(bitLength, [forceLength])</a> ⇒ <code>Buffer</code> | <code>Uint8Array</code></dt>
|
||||
<dd><p>Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()</p>
|
||||
</dd>
|
||||
<dt><a href="#randBytes">randBytes(byteLength, [forceLength])</a> ⇒ <code>Promise</code></dt>
|
||||
<dd><p>Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()</p>
|
||||
</dd>
|
||||
<dt><a href="#randBytesSync">randBytesSync(byteLength, [forceLength])</a> ⇒ <code>Buffer</code> | <code>Uint8Array</code></dt>
|
||||
<dd><p>Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()</p>
|
||||
</dd>
|
||||
<dt><a href="#toZn">toZn(a, n)</a> ⇒ <code>bigint</code></dt>
|
||||
<dd><p>Finds the smallest positive element that is congruent to a in modulo n</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
### Typedefs
|
||||
|
||||
<dl>
|
||||
<dt><a href="#egcdReturn">egcdReturn</a> : <code>Object</code></dt>
|
||||
<dd><p>A triple (g, x, y), such that ax + by = g = gcd(a, b).</p>
|
||||
</dd>
|
||||
</dl>
|
||||
## API reference documentation
|
||||
|
||||
<a name="abs"></a>
|
||||
|
||||
|
@ -217,20 +147,6 @@ Greatest-common divisor of two integers based on the iterative binary algorithm.
|
|||
| a | <code>number</code> \| <code>bigint</code> |
|
||||
| b | <code>number</code> \| <code>bigint</code> |
|
||||
|
||||
<a name="isProbablyPrime"></a>
|
||||
|
||||
### isProbablyPrime(w, [iterations]) ⇒ <code>Promise</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</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="lcm"></a>
|
||||
|
||||
### lcm(a, b) ⇒ <code>bigint</code>
|
||||
|
@ -297,89 +213,6 @@ Modular exponentiation b**e mod n. Currently using the right-to-left binary meth
|
|||
| e | <code>number</code> \| <code>bigint</code> | exponent |
|
||||
| n | <code>number</code> \| <code>bigint</code> | modulo |
|
||||
|
||||
<a name="prime"></a>
|
||||
|
||||
### prime(bitLength, [iterations]) ⇒ <code>Promise</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</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>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</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</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="toZn"></a>
|
||||
|
||||
### toZn(a, n) ⇒ <code>bigint</code>
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
'use strict'
|
||||
|
||||
const fs = require('fs')
|
||||
const jsdoc2md = require('jsdoc-to-markdown')
|
||||
const path = require('path')
|
||||
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 options = {
|
||||
source: fs.readFileSync(input, { encoding: 'UTF-8' }), // 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)
|
||||
|
||||
const readmeFile = path.join(rootDir, 'README.md')
|
||||
|
||||
fs.writeFileSync(readmeFile, readmeContents)
|
|
@ -37,8 +37,8 @@ module.exports = [
|
|||
replace({
|
||||
'process.browser': true
|
||||
})
|
||||
]
|
||||
// external: ['bigint-crypto-utils']
|
||||
],
|
||||
external: ['bigint-mod-arith']
|
||||
},
|
||||
{ // Browser bundles
|
||||
input: input,
|
||||
|
@ -61,8 +61,8 @@ module.exports = [
|
|||
browser: true
|
||||
}),
|
||||
terser({
|
||||
mangle: false,
|
||||
compress: false
|
||||
// mangle: false,
|
||||
// compress: false
|
||||
})
|
||||
]
|
||||
},
|
||||
|
@ -76,7 +76,7 @@ module.exports = [
|
|||
output: {
|
||||
file: path.join(dstDir, 'index.node.js'),
|
||||
format: 'cjs'
|
||||
}
|
||||
// external: ['bigint-crypto-utils']
|
||||
},
|
||||
external: ['bigint-mod-arith']
|
||||
}
|
||||
]
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,112 +1,5 @@
|
|||
const _ZERO = BigInt(0)
|
||||
const _ONE = BigInt(1)
|
||||
const _TWO = BigInt(2)
|
||||
|
||||
/**
|
||||
* Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
*
|
||||
* @returns {bigint} the absolute value of a
|
||||
*/
|
||||
function abs (a) {
|
||||
a = BigInt(a)
|
||||
return (a >= _ZERO) ? a : -a
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bitlength of a number
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @returns {number} - the bit length
|
||||
*/
|
||||
function bitLength (a) {
|
||||
a = BigInt(a)
|
||||
if (a === _ONE) { return 1 }
|
||||
let bits = 1
|
||||
do {
|
||||
bits++
|
||||
} while ((a >>= _ONE) > _ONE)
|
||||
return bits
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} egcdReturn A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
* @property {bigint} g
|
||||
* @property {bigint} x
|
||||
* @property {bigint} y
|
||||
*/
|
||||
/**
|
||||
* An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm.
|
||||
* Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {egcdReturn} A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*/
|
||||
function eGcd (a, b) {
|
||||
a = BigInt(a)
|
||||
b = BigInt(b)
|
||||
if (a <= _ZERO | b <= _ZERO) { return NaN } // a and b MUST be positive
|
||||
|
||||
let x = _ZERO
|
||||
let y = _ONE
|
||||
let u = _ONE
|
||||
let v = _ZERO
|
||||
|
||||
while (a !== _ZERO) {
|
||||
const q = b / a
|
||||
const r = b % a
|
||||
const m = x - (u * q)
|
||||
const n = y - (v * q)
|
||||
b = a
|
||||
a = r
|
||||
x = u
|
||||
y = v
|
||||
u = m
|
||||
v = n
|
||||
}
|
||||
return {
|
||||
b: b,
|
||||
x: x,
|
||||
y: y
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Greatest-common divisor of two integers based on the iterative binary algorithm.
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} The greatest common divisor of a and b
|
||||
*/
|
||||
function gcd (a, b) {
|
||||
a = abs(a)
|
||||
b = abs(b)
|
||||
if (a === _ZERO) { return b } else if (b === _ZERO) { return a }
|
||||
|
||||
let shift = _ZERO
|
||||
while (!((a | b) & _ONE)) {
|
||||
a >>= _ONE
|
||||
b >>= _ONE
|
||||
shift++
|
||||
}
|
||||
while (!(a & _ONE)) a >>= _ONE
|
||||
do {
|
||||
while (!(b & _ONE)) b >>= _ONE
|
||||
if (a > b) {
|
||||
const x = a
|
||||
a = b
|
||||
b = x
|
||||
}
|
||||
b -= a
|
||||
} while (b)
|
||||
|
||||
// rescale
|
||||
return a << shift
|
||||
}
|
||||
import { bitLength, eGcd, modInv, modPow, toZn } from 'bigint-mod-arith'
|
||||
export { abs, bitLength, eGcd, gcd, lcm, max, min, modInv, modPow, toZn } from 'bigint-mod-arith'
|
||||
|
||||
/**
|
||||
* The test first tries if any of the first 250 small primes are a factor of the input number and then passes several
|
||||
|
@ -115,7 +8,7 @@ function gcd (a, b) {
|
|||
* @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} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
|
||||
* @return {Promise<boolean>} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
|
||||
*/
|
||||
async function isProbablyPrime (w, iterations = 16) {
|
||||
if (typeof w === 'number') {
|
||||
|
@ -145,96 +38,6 @@ async function isProbablyPrime (w, iterations = 16) {
|
|||
/* eslint-enable no-lone-blocks */
|
||||
}
|
||||
|
||||
/**
|
||||
* The least common multiple computed as abs(a*b)/gcd(a,b)
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} The least common multiple of a and b
|
||||
*/
|
||||
function lcm (a, b) {
|
||||
a = BigInt(a)
|
||||
b = BigInt(b)
|
||||
if (a === _ZERO && b === _ZERO) { return _ZERO }
|
||||
return abs(a * b) / gcd(a, b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum. max(a,b)==a if a>=b. max(a,b)==b if a<=b
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} maximum of numbers a and b
|
||||
*/
|
||||
function max (a, b) {
|
||||
a = BigInt(a)
|
||||
b = BigInt(b)
|
||||
return (a >= b) ? a : b
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<=b
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} minimum of numbers a and b
|
||||
*/
|
||||
function min (a, b) {
|
||||
a = BigInt(a)
|
||||
b = BigInt(b)
|
||||
return (a >= b) ? b : a
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular inverse.
|
||||
*
|
||||
* @param {number|bigint} a The number to find an inverse for
|
||||
* @param {number|bigint} n The modulo
|
||||
*
|
||||
* @returns {bigint} the inverse modulo n or NaN if it does not exist
|
||||
*/
|
||||
function modInv (a, n) {
|
||||
const egcd = eGcd(toZn(a, n), n)
|
||||
if (egcd.b !== _ONE) {
|
||||
return NaN // modular inverse does not exist
|
||||
} else {
|
||||
return toZn(egcd.x, n)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular exponentiation b**e mod n. Currently using the right-to-left binary method
|
||||
*
|
||||
* @param {number|bigint} b base
|
||||
* @param {number|bigint} e exponent
|
||||
* @param {number|bigint} n modulo
|
||||
*
|
||||
* @returns {bigint} b**e mod n
|
||||
*/
|
||||
function modPow (b, e, n) {
|
||||
n = BigInt(n)
|
||||
if (n === _ZERO) { return NaN } else if (n === _ONE) { return _ZERO }
|
||||
|
||||
b = toZn(b, n)
|
||||
|
||||
e = BigInt(e)
|
||||
if (e < _ZERO) {
|
||||
return modInv(modPow(b, abs(e), n), n)
|
||||
}
|
||||
|
||||
let r = _ONE
|
||||
while (e > 0) {
|
||||
if ((e % _TWO) === _ONE) {
|
||||
r = (r * b) % n
|
||||
}
|
||||
e = e / _TWO
|
||||
b = b ** _TWO % n
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -245,7 +48,7 @@ function modPow (b, e, n) {
|
|||
* @param {number} bitLength The required bit length for the generated prime
|
||||
* @param {number} [iterations = 16] The number of iterations for the Miller-Rabin Probabilistic Primality Test
|
||||
*
|
||||
* @returns {Promise} A promise that resolves to a bigint probable prime of bitLength bits.
|
||||
* @returns {Promise<bigint>} A promise that resolves to a bigint probable prime of bitLength bits.
|
||||
*/
|
||||
function prime (bitLength, iterations = 16) {
|
||||
if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) }
|
||||
|
@ -278,7 +81,7 @@ function prime (bitLength, iterations = 16) {
|
|||
/* eslint-disable no-lone-blocks */
|
||||
{ // browser
|
||||
const workerURL = _isProbablyPrimeWorkerUrl()
|
||||
for (let i = 0; i < self.navigator.hardwareConcurrency; i++) {
|
||||
for (let i = 0; i < self.navigator.hardwareConcurrency - 1; i++) {
|
||||
const newWorker = new Worker(workerURL)
|
||||
newWorker.onmessage = (event) => _onmessage(event.data, newWorker)
|
||||
workerList.push(newWorker)
|
||||
|
@ -308,7 +111,7 @@ function prime (bitLength, iterations = 16) {
|
|||
*/
|
||||
function primeSync (bitLength, iterations = 16) {
|
||||
if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) }
|
||||
let rnd = _ZERO
|
||||
let rnd = 0n
|
||||
do {
|
||||
rnd = fromBuffer(randBytesSync(bitLength / 8, true))
|
||||
} while (!_isProbablyPrime(rnd, iterations))
|
||||
|
@ -322,7 +125,7 @@ function primeSync (bitLength, iterations = 16) {
|
|||
*
|
||||
* @returns {bigint} A cryptographically secure random bigint between [min,max]
|
||||
*/
|
||||
function randBetween (max, min = _ONE) {
|
||||
function randBetween (max, min = 1n) {
|
||||
if (max <= min) throw new Error('max must be > min')
|
||||
const interval = max - min
|
||||
const bitLen = bitLength(interval)
|
||||
|
@ -367,7 +170,7 @@ function randBits (bitLength, forceLength = false) {
|
|||
* @param {number} byteLength The desired number of random bytes
|
||||
* @param {boolean} [forceLength = false] If we want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1
|
||||
*
|
||||
* @returns {Promise} A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
||||
* @returns {Promise<Buffer | Uint8Array>} A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
||||
*/
|
||||
function randBytes (byteLength, forceLength = false) {
|
||||
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
|
||||
|
@ -407,25 +210,10 @@ function randBytesSync (byteLength, forceLength = false) {
|
|||
return buf
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the smallest positive element that is congruent to a in modulo n
|
||||
* @param {number|bigint} a An integer
|
||||
* @param {number|bigint} n The modulo
|
||||
*
|
||||
* @returns {bigint} The smallest positive representation of a in modulo n
|
||||
*/
|
||||
function toZn (a, n) {
|
||||
n = BigInt(n)
|
||||
if (n <= 0) { return NaN }
|
||||
|
||||
a = BigInt(a) % n
|
||||
return (a < 0) ? a + n : a
|
||||
}
|
||||
|
||||
/* HELPER FUNCTIONS */
|
||||
|
||||
function fromBuffer (buf) {
|
||||
let ret = _ZERO
|
||||
let ret = 0n
|
||||
for (const i of buf.values()) {
|
||||
const bi = BigInt(i)
|
||||
ret = (ret << BigInt(8)) + bi
|
||||
|
@ -435,7 +223,7 @@ function fromBuffer (buf) {
|
|||
|
||||
function _isProbablyPrimeWorkerUrl () {
|
||||
// Let's us first add all the required functions
|
||||
let workerCode = `'use strict';const _ZERO = BigInt(0);const _ONE = BigInt(1);const _TWO = BigInt(2);const eGcd = ${eGcd.toString()};const modInv = ${modInv.toString()};const modPow = ${modPow.toString()};const toZn = ${toZn.toString()};const randBits = ${randBits.toString()};const randBytesSync = ${randBytesSync.toString()};const randBetween = ${randBetween.toString()};const isProbablyPrime = ${_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 ${randBits.name}=${randBits.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>}
|
||||
|
@ -463,269 +251,269 @@ function _isProbablyPrime (w, iterations = 16) {
|
|||
PREFILTERING. Even values but 2 are not primes, so don't test.
|
||||
1 is not a prime and the M-R algorithm needs w>1.
|
||||
*/
|
||||
if (w === _TWO) { return true } else if ((w & _ONE) === _ZERO || w === _ONE) { return false }
|
||||
if (w === 2n) { return true } else if ((w & 1n) === 0n || w === 1n) { return false }
|
||||
|
||||
/*
|
||||
Test if any of the first 250 small primes are a factor of w. 2 is not tested because it was already tested above.
|
||||
*/
|
||||
const firstPrimes = [
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
11,
|
||||
13,
|
||||
17,
|
||||
19,
|
||||
23,
|
||||
29,
|
||||
31,
|
||||
37,
|
||||
41,
|
||||
43,
|
||||
47,
|
||||
53,
|
||||
59,
|
||||
61,
|
||||
67,
|
||||
71,
|
||||
73,
|
||||
79,
|
||||
83,
|
||||
89,
|
||||
97,
|
||||
101,
|
||||
103,
|
||||
107,
|
||||
109,
|
||||
113,
|
||||
127,
|
||||
131,
|
||||
137,
|
||||
139,
|
||||
149,
|
||||
151,
|
||||
157,
|
||||
163,
|
||||
167,
|
||||
173,
|
||||
179,
|
||||
181,
|
||||
191,
|
||||
193,
|
||||
197,
|
||||
199,
|
||||
211,
|
||||
223,
|
||||
227,
|
||||
229,
|
||||
233,
|
||||
239,
|
||||
241,
|
||||
251,
|
||||
257,
|
||||
263,
|
||||
269,
|
||||
271,
|
||||
277,
|
||||
281,
|
||||
283,
|
||||
293,
|
||||
307,
|
||||
311,
|
||||
313,
|
||||
317,
|
||||
331,
|
||||
337,
|
||||
347,
|
||||
349,
|
||||
353,
|
||||
359,
|
||||
367,
|
||||
373,
|
||||
379,
|
||||
383,
|
||||
389,
|
||||
397,
|
||||
401,
|
||||
409,
|
||||
419,
|
||||
421,
|
||||
431,
|
||||
433,
|
||||
439,
|
||||
443,
|
||||
449,
|
||||
457,
|
||||
461,
|
||||
463,
|
||||
467,
|
||||
479,
|
||||
487,
|
||||
491,
|
||||
499,
|
||||
503,
|
||||
509,
|
||||
521,
|
||||
523,
|
||||
541,
|
||||
547,
|
||||
557,
|
||||
563,
|
||||
569,
|
||||
571,
|
||||
577,
|
||||
587,
|
||||
593,
|
||||
599,
|
||||
601,
|
||||
607,
|
||||
613,
|
||||
617,
|
||||
619,
|
||||
631,
|
||||
641,
|
||||
643,
|
||||
647,
|
||||
653,
|
||||
659,
|
||||
661,
|
||||
673,
|
||||
677,
|
||||
683,
|
||||
691,
|
||||
701,
|
||||
709,
|
||||
719,
|
||||
727,
|
||||
733,
|
||||
739,
|
||||
743,
|
||||
751,
|
||||
757,
|
||||
761,
|
||||
769,
|
||||
773,
|
||||
787,
|
||||
797,
|
||||
809,
|
||||
811,
|
||||
821,
|
||||
823,
|
||||
827,
|
||||
829,
|
||||
839,
|
||||
853,
|
||||
857,
|
||||
859,
|
||||
863,
|
||||
877,
|
||||
881,
|
||||
883,
|
||||
887,
|
||||
907,
|
||||
911,
|
||||
919,
|
||||
929,
|
||||
937,
|
||||
941,
|
||||
947,
|
||||
953,
|
||||
967,
|
||||
971,
|
||||
977,
|
||||
983,
|
||||
991,
|
||||
997,
|
||||
1009,
|
||||
1013,
|
||||
1019,
|
||||
1021,
|
||||
1031,
|
||||
1033,
|
||||
1039,
|
||||
1049,
|
||||
1051,
|
||||
1061,
|
||||
1063,
|
||||
1069,
|
||||
1087,
|
||||
1091,
|
||||
1093,
|
||||
1097,
|
||||
1103,
|
||||
1109,
|
||||
1117,
|
||||
1123,
|
||||
1129,
|
||||
1151,
|
||||
1153,
|
||||
1163,
|
||||
1171,
|
||||
1181,
|
||||
1187,
|
||||
1193,
|
||||
1201,
|
||||
1213,
|
||||
1217,
|
||||
1223,
|
||||
1229,
|
||||
1231,
|
||||
1237,
|
||||
1249,
|
||||
1259,
|
||||
1277,
|
||||
1279,
|
||||
1283,
|
||||
1289,
|
||||
1291,
|
||||
1297,
|
||||
1301,
|
||||
1303,
|
||||
1307,
|
||||
1319,
|
||||
1321,
|
||||
1327,
|
||||
1361,
|
||||
1367,
|
||||
1373,
|
||||
1381,
|
||||
1399,
|
||||
1409,
|
||||
1423,
|
||||
1427,
|
||||
1429,
|
||||
1433,
|
||||
1439,
|
||||
1447,
|
||||
1451,
|
||||
1453,
|
||||
1459,
|
||||
1471,
|
||||
1481,
|
||||
1483,
|
||||
1487,
|
||||
1489,
|
||||
1493,
|
||||
1499,
|
||||
1511,
|
||||
1523,
|
||||
1531,
|
||||
1543,
|
||||
1549,
|
||||
1553,
|
||||
1559,
|
||||
1567,
|
||||
1571,
|
||||
1579,
|
||||
1583,
|
||||
1597
|
||||
3n,
|
||||
5n,
|
||||
7n,
|
||||
11n,
|
||||
13n,
|
||||
17n,
|
||||
19n,
|
||||
23n,
|
||||
29n,
|
||||
31n,
|
||||
37n,
|
||||
41n,
|
||||
43n,
|
||||
47n,
|
||||
53n,
|
||||
59n,
|
||||
61n,
|
||||
67n,
|
||||
71n,
|
||||
73n,
|
||||
79n,
|
||||
83n,
|
||||
89n,
|
||||
97n,
|
||||
101n,
|
||||
103n,
|
||||
107n,
|
||||
109n,
|
||||
113n,
|
||||
127n,
|
||||
131n,
|
||||
137n,
|
||||
139n,
|
||||
149n,
|
||||
151n,
|
||||
157n,
|
||||
163n,
|
||||
167n,
|
||||
173n,
|
||||
179n,
|
||||
181n,
|
||||
191n,
|
||||
193n,
|
||||
197n,
|
||||
199n,
|
||||
211n,
|
||||
223n,
|
||||
227n,
|
||||
229n,
|
||||
233n,
|
||||
239n,
|
||||
241n,
|
||||
251n,
|
||||
257n,
|
||||
263n,
|
||||
269n,
|
||||
271n,
|
||||
277n,
|
||||
281n,
|
||||
283n,
|
||||
293n,
|
||||
307n,
|
||||
311n,
|
||||
313n,
|
||||
317n,
|
||||
331n,
|
||||
337n,
|
||||
347n,
|
||||
349n,
|
||||
353n,
|
||||
359n,
|
||||
367n,
|
||||
373n,
|
||||
379n,
|
||||
383n,
|
||||
389n,
|
||||
397n,
|
||||
401n,
|
||||
409n,
|
||||
419n,
|
||||
421n,
|
||||
431n,
|
||||
433n,
|
||||
439n,
|
||||
443n,
|
||||
449n,
|
||||
457n,
|
||||
461n,
|
||||
463n,
|
||||
467n,
|
||||
479n,
|
||||
487n,
|
||||
491n,
|
||||
499n,
|
||||
503n,
|
||||
509n,
|
||||
521n,
|
||||
523n,
|
||||
541n,
|
||||
547n,
|
||||
557n,
|
||||
563n,
|
||||
569n,
|
||||
571n,
|
||||
577n,
|
||||
587n,
|
||||
593n,
|
||||
599n,
|
||||
601n,
|
||||
607n,
|
||||
613n,
|
||||
617n,
|
||||
619n,
|
||||
631n,
|
||||
641n,
|
||||
643n,
|
||||
647n,
|
||||
653n,
|
||||
659n,
|
||||
661n,
|
||||
673n,
|
||||
677n,
|
||||
683n,
|
||||
691n,
|
||||
701n,
|
||||
709n,
|
||||
719n,
|
||||
727n,
|
||||
733n,
|
||||
739n,
|
||||
743n,
|
||||
751n,
|
||||
757n,
|
||||
761n,
|
||||
769n,
|
||||
773n,
|
||||
787n,
|
||||
797n,
|
||||
809n,
|
||||
811n,
|
||||
821n,
|
||||
823n,
|
||||
827n,
|
||||
829n,
|
||||
839n,
|
||||
853n,
|
||||
857n,
|
||||
859n,
|
||||
863n,
|
||||
877n,
|
||||
881n,
|
||||
883n,
|
||||
887n,
|
||||
907n,
|
||||
911n,
|
||||
919n,
|
||||
929n,
|
||||
937n,
|
||||
941n,
|
||||
947n,
|
||||
953n,
|
||||
967n,
|
||||
971n,
|
||||
977n,
|
||||
983n,
|
||||
991n,
|
||||
997n,
|
||||
1009n,
|
||||
1013n,
|
||||
1019n,
|
||||
1021n,
|
||||
1031n,
|
||||
1033n,
|
||||
1039n,
|
||||
1049n,
|
||||
1051n,
|
||||
1061n,
|
||||
1063n,
|
||||
1069n,
|
||||
1087n,
|
||||
1091n,
|
||||
1093n,
|
||||
1097n,
|
||||
1103n,
|
||||
1109n,
|
||||
1117n,
|
||||
1123n,
|
||||
1129n,
|
||||
1151n,
|
||||
1153n,
|
||||
1163n,
|
||||
1171n,
|
||||
1181n,
|
||||
1187n,
|
||||
1193n,
|
||||
1201n,
|
||||
1213n,
|
||||
1217n,
|
||||
1223n,
|
||||
1229n,
|
||||
1231n,
|
||||
1237n,
|
||||
1249n,
|
||||
1259n,
|
||||
1277n,
|
||||
1279n,
|
||||
1283n,
|
||||
1289n,
|
||||
1291n,
|
||||
1297n,
|
||||
1301n,
|
||||
1303n,
|
||||
1307n,
|
||||
1319n,
|
||||
1321n,
|
||||
1327n,
|
||||
1361n,
|
||||
1367n,
|
||||
1373n,
|
||||
1381n,
|
||||
1399n,
|
||||
1409n,
|
||||
1423n,
|
||||
1427n,
|
||||
1429n,
|
||||
1433n,
|
||||
1439n,
|
||||
1447n,
|
||||
1451n,
|
||||
1453n,
|
||||
1459n,
|
||||
1471n,
|
||||
1481n,
|
||||
1483n,
|
||||
1487n,
|
||||
1489n,
|
||||
1493n,
|
||||
1499n,
|
||||
1511n,
|
||||
1523n,
|
||||
1531n,
|
||||
1543n,
|
||||
1549n,
|
||||
1553n,
|
||||
1559n,
|
||||
1567n,
|
||||
1571n,
|
||||
1579n,
|
||||
1583n,
|
||||
1597n
|
||||
]
|
||||
let p = _ZERO
|
||||
for (let i = 0; i < firstPrimes.length && (p <= w); i++) {
|
||||
p = BigInt(firstPrimes[i])
|
||||
|
||||
for (let i = 0; i < firstPrimes.length && (firstPrimes[i] <= w); i++) {
|
||||
const p = firstPrimes[i]
|
||||
if (w === p) {
|
||||
return true
|
||||
} else if (w % p === _ZERO) {
|
||||
} else if (w % p === 0n) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -749,30 +537,48 @@ function _isProbablyPrime (w, iterations = 16) {
|
|||
Comment: Increment i for the do-loop in step 4.
|
||||
5. Return PROBABLY PRIME.
|
||||
*/
|
||||
let a = _ZERO; let d = w - _ONE
|
||||
while (d % _TWO === _ZERO) {
|
||||
d /= _TWO
|
||||
let a = 0n
|
||||
const d = w - 1n
|
||||
let aux = d
|
||||
while (aux % 2n === 0n) {
|
||||
aux /= 2n
|
||||
++a
|
||||
}
|
||||
|
||||
const m = (w - _ONE) / (_TWO ** a)
|
||||
const m = d / (2n ** a)
|
||||
|
||||
/* eslint-disable no-labels */
|
||||
loop: do {
|
||||
const b = randBetween(w - _ONE, _TWO)
|
||||
// /* eslint-disable no-labels */
|
||||
// loop: do {
|
||||
// const b = randBetween(w - 1n, 2n)
|
||||
// let z = modPow(b, m, w)
|
||||
// if (z === 1n || z === w - 1n) { continue }
|
||||
// for (let j = 1; j < a; j++) {
|
||||
// z = modPow(z, 2n, w)
|
||||
// if (z === w - 1n) { continue loop }
|
||||
// if (z === 1n) { break }
|
||||
// }
|
||||
// return false
|
||||
// } while (--iterations)
|
||||
// /* eslint-enable no-labels */
|
||||
|
||||
// return true
|
||||
|
||||
do {
|
||||
const b = randBetween(d, 2n)
|
||||
let z = modPow(b, m, w)
|
||||
if (z === _ONE || z === w - _ONE) { continue }
|
||||
|
||||
for (let j = 1; j < a; j++) {
|
||||
z = modPow(z, _TWO, w)
|
||||
if (z === w - _ONE) { continue loop }
|
||||
if (z === _ONE) { break }
|
||||
if (z === 1n || z === d) { continue }
|
||||
let j = 1
|
||||
while (j < a) {
|
||||
z = modPow(z, 2n, w)
|
||||
if (z === d) { break }
|
||||
if (z === 1n) { return false }
|
||||
j++
|
||||
}
|
||||
if (z !== d) {
|
||||
return false
|
||||
}
|
||||
} while (--iterations)
|
||||
/* eslint-enable no-labels */
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export { abs, bitLength, eGcd, gcd, isProbablyPrime, lcm, max, min, modInv, modPow, prime, primeSync, randBetween, randBits, randBytes, randBytesSync, toZn }
|
||||
export { isProbablyPrime, prime, primeSync, randBetween, randBits, randBytes, randBytesSync }
|
||||
|
|
|
@ -2,115 +2,7 @@
|
|||
|
||||
Object.defineProperty(exports, '__esModule', { value: true })
|
||||
|
||||
const _ZERO = BigInt(0)
|
||||
const _ONE = BigInt(1)
|
||||
const _TWO = BigInt(2)
|
||||
|
||||
/**
|
||||
* Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
*
|
||||
* @returns {bigint} the absolute value of a
|
||||
*/
|
||||
function abs (a) {
|
||||
a = BigInt(a)
|
||||
return (a >= _ZERO) ? a : -a
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bitlength of a number
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @returns {number} - the bit length
|
||||
*/
|
||||
function bitLength (a) {
|
||||
a = BigInt(a)
|
||||
if (a === _ONE) { return 1 }
|
||||
let bits = 1
|
||||
do {
|
||||
bits++
|
||||
} while ((a >>= _ONE) > _ONE)
|
||||
return bits
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} egcdReturn A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
* @property {bigint} g
|
||||
* @property {bigint} x
|
||||
* @property {bigint} y
|
||||
*/
|
||||
/**
|
||||
* An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm.
|
||||
* Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {egcdReturn} A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*/
|
||||
function eGcd (a, b) {
|
||||
a = BigInt(a)
|
||||
b = BigInt(b)
|
||||
if (a <= _ZERO | b <= _ZERO) { return NaN } // a and b MUST be positive
|
||||
|
||||
let x = _ZERO
|
||||
let y = _ONE
|
||||
let u = _ONE
|
||||
let v = _ZERO
|
||||
|
||||
while (a !== _ZERO) {
|
||||
const q = b / a
|
||||
const r = b % a
|
||||
const m = x - (u * q)
|
||||
const n = y - (v * q)
|
||||
b = a
|
||||
a = r
|
||||
x = u
|
||||
y = v
|
||||
u = m
|
||||
v = n
|
||||
}
|
||||
return {
|
||||
b: b,
|
||||
x: x,
|
||||
y: y
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Greatest-common divisor of two integers based on the iterative binary algorithm.
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} The greatest common divisor of a and b
|
||||
*/
|
||||
function gcd (a, b) {
|
||||
a = abs(a)
|
||||
b = abs(b)
|
||||
if (a === _ZERO) { return b } else if (b === _ZERO) { return a }
|
||||
|
||||
let shift = _ZERO
|
||||
while (!((a | b) & _ONE)) {
|
||||
a >>= _ONE
|
||||
b >>= _ONE
|
||||
shift++
|
||||
}
|
||||
while (!(a & _ONE)) a >>= _ONE
|
||||
do {
|
||||
while (!(b & _ONE)) b >>= _ONE
|
||||
if (a > b) {
|
||||
const x = a
|
||||
a = b
|
||||
b = x
|
||||
}
|
||||
b -= a
|
||||
} while (b)
|
||||
|
||||
// rescale
|
||||
return a << shift
|
||||
}
|
||||
var bigintModArith = require('bigint-mod-arith')
|
||||
|
||||
/**
|
||||
* The test first tries if any of the first 250 small primes are a factor of the input number and then passes several
|
||||
|
@ -119,7 +11,7 @@ function gcd (a, b) {
|
|||
* @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} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
|
||||
* @return {Promise<boolean>} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
|
||||
*/
|
||||
async function isProbablyPrime (w, iterations = 16) {
|
||||
if (typeof w === 'number') {
|
||||
|
@ -155,96 +47,6 @@ async function isProbablyPrime (w, iterations = 16) {
|
|||
/* eslint-enable no-lone-blocks */
|
||||
}
|
||||
|
||||
/**
|
||||
* The least common multiple computed as abs(a*b)/gcd(a,b)
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} The least common multiple of a and b
|
||||
*/
|
||||
function lcm (a, b) {
|
||||
a = BigInt(a)
|
||||
b = BigInt(b)
|
||||
if (a === _ZERO && b === _ZERO) { return _ZERO }
|
||||
return abs(a * b) / gcd(a, b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum. max(a,b)==a if a>=b. max(a,b)==b if a<=b
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} maximum of numbers a and b
|
||||
*/
|
||||
function max (a, b) {
|
||||
a = BigInt(a)
|
||||
b = BigInt(b)
|
||||
return (a >= b) ? a : b
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<=b
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} minimum of numbers a and b
|
||||
*/
|
||||
function min (a, b) {
|
||||
a = BigInt(a)
|
||||
b = BigInt(b)
|
||||
return (a >= b) ? b : a
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular inverse.
|
||||
*
|
||||
* @param {number|bigint} a The number to find an inverse for
|
||||
* @param {number|bigint} n The modulo
|
||||
*
|
||||
* @returns {bigint} the inverse modulo n or NaN if it does not exist
|
||||
*/
|
||||
function modInv (a, n) {
|
||||
const egcd = eGcd(toZn(a, n), n)
|
||||
if (egcd.b !== _ONE) {
|
||||
return NaN // modular inverse does not exist
|
||||
} else {
|
||||
return toZn(egcd.x, n)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular exponentiation b**e mod n. Currently using the right-to-left binary method
|
||||
*
|
||||
* @param {number|bigint} b base
|
||||
* @param {number|bigint} e exponent
|
||||
* @param {number|bigint} n modulo
|
||||
*
|
||||
* @returns {bigint} b**e mod n
|
||||
*/
|
||||
function modPow (b, e, n) {
|
||||
n = BigInt(n)
|
||||
if (n === _ZERO) { return NaN } else if (n === _ONE) { return _ZERO }
|
||||
|
||||
b = toZn(b, n)
|
||||
|
||||
e = BigInt(e)
|
||||
if (e < _ZERO) {
|
||||
return modInv(modPow(b, abs(e), n), n)
|
||||
}
|
||||
|
||||
let r = _ONE
|
||||
while (e > 0) {
|
||||
if ((e % _TWO) === _ONE) {
|
||||
r = (r * b) % n
|
||||
}
|
||||
e = e / _TWO
|
||||
b = b ** _TWO % n
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -255,13 +57,13 @@ function modPow (b, e, n) {
|
|||
* @param {number} bitLength The required bit length for the generated prime
|
||||
* @param {number} [iterations = 16] The number of iterations for the Miller-Rabin Probabilistic Primality Test
|
||||
*
|
||||
* @returns {Promise} A promise that resolves to a bigint probable prime of bitLength bits.
|
||||
* @returns {Promise<bigint>} A promise that resolves to a bigint probable prime of bitLength bits.
|
||||
*/
|
||||
function prime (bitLength, iterations = 16) {
|
||||
if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) }
|
||||
|
||||
if (!_useWorkers) {
|
||||
let rnd = _ZERO
|
||||
let rnd = 0n
|
||||
do {
|
||||
rnd = fromBuffer(randBytesSync(bitLength / 8, true))
|
||||
} while (!_isProbablyPrime(rnd, iterations))
|
||||
|
@ -297,7 +99,7 @@ function prime (bitLength, iterations = 16) {
|
|||
{ // Node.js
|
||||
const { cpus } = require('os')
|
||||
const { Worker } = require('worker_threads')
|
||||
for (let i = 0; i < cpus().length; i++) {
|
||||
for (let i = 0; i < cpus().length - 1; i++) {
|
||||
const newWorker = new Worker(__filename)
|
||||
newWorker.on('message', (msg) => _onmessage(msg, newWorker))
|
||||
workerList.push(newWorker)
|
||||
|
@ -327,7 +129,7 @@ function prime (bitLength, iterations = 16) {
|
|||
*/
|
||||
function primeSync (bitLength, iterations = 16) {
|
||||
if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) }
|
||||
let rnd = _ZERO
|
||||
let rnd = 0n
|
||||
do {
|
||||
rnd = fromBuffer(randBytesSync(bitLength / 8, true))
|
||||
} while (!_isProbablyPrime(rnd, iterations))
|
||||
|
@ -341,10 +143,10 @@ function primeSync (bitLength, iterations = 16) {
|
|||
*
|
||||
* @returns {bigint} A cryptographically secure random bigint between [min,max]
|
||||
*/
|
||||
function randBetween (max, min = _ONE) {
|
||||
function randBetween (max, min = 1n) {
|
||||
if (max <= min) throw new Error('max must be > min')
|
||||
const interval = max - min
|
||||
const bitLen = bitLength(interval)
|
||||
const bitLen = bigintModArith.bitLength(interval)
|
||||
let rnd
|
||||
do {
|
||||
const buf = randBits(bitLen)
|
||||
|
@ -386,7 +188,7 @@ function randBits (bitLength, forceLength = false) {
|
|||
* @param {number} byteLength The desired number of random bytes
|
||||
* @param {boolean} [forceLength = false] If we want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1
|
||||
*
|
||||
* @returns {Promise} A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
||||
* @returns {Promise<Buffer | Uint8Array>} A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
||||
*/
|
||||
function randBytes (byteLength, forceLength = false) {
|
||||
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
|
||||
|
@ -427,25 +229,10 @@ function randBytesSync (byteLength, forceLength = false) {
|
|||
return buf
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the smallest positive element that is congruent to a in modulo n
|
||||
* @param {number|bigint} a An integer
|
||||
* @param {number|bigint} n The modulo
|
||||
*
|
||||
* @returns {bigint} The smallest positive representation of a in modulo n
|
||||
*/
|
||||
function toZn (a, n) {
|
||||
n = BigInt(n)
|
||||
if (n <= 0) { return NaN }
|
||||
|
||||
a = BigInt(a) % n
|
||||
return (a < 0) ? a + n : a
|
||||
}
|
||||
|
||||
/* HELPER FUNCTIONS */
|
||||
|
||||
function fromBuffer (buf) {
|
||||
let ret = _ZERO
|
||||
let ret = 0n
|
||||
for (const i of buf.values()) {
|
||||
const bi = BigInt(i)
|
||||
ret = (ret << BigInt(8)) + bi
|
||||
|
@ -458,269 +245,269 @@ function _isProbablyPrime (w, iterations = 16) {
|
|||
PREFILTERING. Even values but 2 are not primes, so don't test.
|
||||
1 is not a prime and the M-R algorithm needs w>1.
|
||||
*/
|
||||
if (w === _TWO) { return true } else if ((w & _ONE) === _ZERO || w === _ONE) { return false }
|
||||
if (w === 2n) { return true } else if ((w & 1n) === 0n || w === 1n) { return false }
|
||||
|
||||
/*
|
||||
Test if any of the first 250 small primes are a factor of w. 2 is not tested because it was already tested above.
|
||||
*/
|
||||
const firstPrimes = [
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
11,
|
||||
13,
|
||||
17,
|
||||
19,
|
||||
23,
|
||||
29,
|
||||
31,
|
||||
37,
|
||||
41,
|
||||
43,
|
||||
47,
|
||||
53,
|
||||
59,
|
||||
61,
|
||||
67,
|
||||
71,
|
||||
73,
|
||||
79,
|
||||
83,
|
||||
89,
|
||||
97,
|
||||
101,
|
||||
103,
|
||||
107,
|
||||
109,
|
||||
113,
|
||||
127,
|
||||
131,
|
||||
137,
|
||||
139,
|
||||
149,
|
||||
151,
|
||||
157,
|
||||
163,
|
||||
167,
|
||||
173,
|
||||
179,
|
||||
181,
|
||||
191,
|
||||
193,
|
||||
197,
|
||||
199,
|
||||
211,
|
||||
223,
|
||||
227,
|
||||
229,
|
||||
233,
|
||||
239,
|
||||
241,
|
||||
251,
|
||||
257,
|
||||
263,
|
||||
269,
|
||||
271,
|
||||
277,
|
||||
281,
|
||||
283,
|
||||
293,
|
||||
307,
|
||||
311,
|
||||
313,
|
||||
317,
|
||||
331,
|
||||
337,
|
||||
347,
|
||||
349,
|
||||
353,
|
||||
359,
|
||||
367,
|
||||
373,
|
||||
379,
|
||||
383,
|
||||
389,
|
||||
397,
|
||||
401,
|
||||
409,
|
||||
419,
|
||||
421,
|
||||
431,
|
||||
433,
|
||||
439,
|
||||
443,
|
||||
449,
|
||||
457,
|
||||
461,
|
||||
463,
|
||||
467,
|
||||
479,
|
||||
487,
|
||||
491,
|
||||
499,
|
||||
503,
|
||||
509,
|
||||
521,
|
||||
523,
|
||||
541,
|
||||
547,
|
||||
557,
|
||||
563,
|
||||
569,
|
||||
571,
|
||||
577,
|
||||
587,
|
||||
593,
|
||||
599,
|
||||
601,
|
||||
607,
|
||||
613,
|
||||
617,
|
||||
619,
|
||||
631,
|
||||
641,
|
||||
643,
|
||||
647,
|
||||
653,
|
||||
659,
|
||||
661,
|
||||
673,
|
||||
677,
|
||||
683,
|
||||
691,
|
||||
701,
|
||||
709,
|
||||
719,
|
||||
727,
|
||||
733,
|
||||
739,
|
||||
743,
|
||||
751,
|
||||
757,
|
||||
761,
|
||||
769,
|
||||
773,
|
||||
787,
|
||||
797,
|
||||
809,
|
||||
811,
|
||||
821,
|
||||
823,
|
||||
827,
|
||||
829,
|
||||
839,
|
||||
853,
|
||||
857,
|
||||
859,
|
||||
863,
|
||||
877,
|
||||
881,
|
||||
883,
|
||||
887,
|
||||
907,
|
||||
911,
|
||||
919,
|
||||
929,
|
||||
937,
|
||||
941,
|
||||
947,
|
||||
953,
|
||||
967,
|
||||
971,
|
||||
977,
|
||||
983,
|
||||
991,
|
||||
997,
|
||||
1009,
|
||||
1013,
|
||||
1019,
|
||||
1021,
|
||||
1031,
|
||||
1033,
|
||||
1039,
|
||||
1049,
|
||||
1051,
|
||||
1061,
|
||||
1063,
|
||||
1069,
|
||||
1087,
|
||||
1091,
|
||||
1093,
|
||||
1097,
|
||||
1103,
|
||||
1109,
|
||||
1117,
|
||||
1123,
|
||||
1129,
|
||||
1151,
|
||||
1153,
|
||||
1163,
|
||||
1171,
|
||||
1181,
|
||||
1187,
|
||||
1193,
|
||||
1201,
|
||||
1213,
|
||||
1217,
|
||||
1223,
|
||||
1229,
|
||||
1231,
|
||||
1237,
|
||||
1249,
|
||||
1259,
|
||||
1277,
|
||||
1279,
|
||||
1283,
|
||||
1289,
|
||||
1291,
|
||||
1297,
|
||||
1301,
|
||||
1303,
|
||||
1307,
|
||||
1319,
|
||||
1321,
|
||||
1327,
|
||||
1361,
|
||||
1367,
|
||||
1373,
|
||||
1381,
|
||||
1399,
|
||||
1409,
|
||||
1423,
|
||||
1427,
|
||||
1429,
|
||||
1433,
|
||||
1439,
|
||||
1447,
|
||||
1451,
|
||||
1453,
|
||||
1459,
|
||||
1471,
|
||||
1481,
|
||||
1483,
|
||||
1487,
|
||||
1489,
|
||||
1493,
|
||||
1499,
|
||||
1511,
|
||||
1523,
|
||||
1531,
|
||||
1543,
|
||||
1549,
|
||||
1553,
|
||||
1559,
|
||||
1567,
|
||||
1571,
|
||||
1579,
|
||||
1583,
|
||||
1597
|
||||
3n,
|
||||
5n,
|
||||
7n,
|
||||
11n,
|
||||
13n,
|
||||
17n,
|
||||
19n,
|
||||
23n,
|
||||
29n,
|
||||
31n,
|
||||
37n,
|
||||
41n,
|
||||
43n,
|
||||
47n,
|
||||
53n,
|
||||
59n,
|
||||
61n,
|
||||
67n,
|
||||
71n,
|
||||
73n,
|
||||
79n,
|
||||
83n,
|
||||
89n,
|
||||
97n,
|
||||
101n,
|
||||
103n,
|
||||
107n,
|
||||
109n,
|
||||
113n,
|
||||
127n,
|
||||
131n,
|
||||
137n,
|
||||
139n,
|
||||
149n,
|
||||
151n,
|
||||
157n,
|
||||
163n,
|
||||
167n,
|
||||
173n,
|
||||
179n,
|
||||
181n,
|
||||
191n,
|
||||
193n,
|
||||
197n,
|
||||
199n,
|
||||
211n,
|
||||
223n,
|
||||
227n,
|
||||
229n,
|
||||
233n,
|
||||
239n,
|
||||
241n,
|
||||
251n,
|
||||
257n,
|
||||
263n,
|
||||
269n,
|
||||
271n,
|
||||
277n,
|
||||
281n,
|
||||
283n,
|
||||
293n,
|
||||
307n,
|
||||
311n,
|
||||
313n,
|
||||
317n,
|
||||
331n,
|
||||
337n,
|
||||
347n,
|
||||
349n,
|
||||
353n,
|
||||
359n,
|
||||
367n,
|
||||
373n,
|
||||
379n,
|
||||
383n,
|
||||
389n,
|
||||
397n,
|
||||
401n,
|
||||
409n,
|
||||
419n,
|
||||
421n,
|
||||
431n,
|
||||
433n,
|
||||
439n,
|
||||
443n,
|
||||
449n,
|
||||
457n,
|
||||
461n,
|
||||
463n,
|
||||
467n,
|
||||
479n,
|
||||
487n,
|
||||
491n,
|
||||
499n,
|
||||
503n,
|
||||
509n,
|
||||
521n,
|
||||
523n,
|
||||
541n,
|
||||
547n,
|
||||
557n,
|
||||
563n,
|
||||
569n,
|
||||
571n,
|
||||
577n,
|
||||
587n,
|
||||
593n,
|
||||
599n,
|
||||
601n,
|
||||
607n,
|
||||
613n,
|
||||
617n,
|
||||
619n,
|
||||
631n,
|
||||
641n,
|
||||
643n,
|
||||
647n,
|
||||
653n,
|
||||
659n,
|
||||
661n,
|
||||
673n,
|
||||
677n,
|
||||
683n,
|
||||
691n,
|
||||
701n,
|
||||
709n,
|
||||
719n,
|
||||
727n,
|
||||
733n,
|
||||
739n,
|
||||
743n,
|
||||
751n,
|
||||
757n,
|
||||
761n,
|
||||
769n,
|
||||
773n,
|
||||
787n,
|
||||
797n,
|
||||
809n,
|
||||
811n,
|
||||
821n,
|
||||
823n,
|
||||
827n,
|
||||
829n,
|
||||
839n,
|
||||
853n,
|
||||
857n,
|
||||
859n,
|
||||
863n,
|
||||
877n,
|
||||
881n,
|
||||
883n,
|
||||
887n,
|
||||
907n,
|
||||
911n,
|
||||
919n,
|
||||
929n,
|
||||
937n,
|
||||
941n,
|
||||
947n,
|
||||
953n,
|
||||
967n,
|
||||
971n,
|
||||
977n,
|
||||
983n,
|
||||
991n,
|
||||
997n,
|
||||
1009n,
|
||||
1013n,
|
||||
1019n,
|
||||
1021n,
|
||||
1031n,
|
||||
1033n,
|
||||
1039n,
|
||||
1049n,
|
||||
1051n,
|
||||
1061n,
|
||||
1063n,
|
||||
1069n,
|
||||
1087n,
|
||||
1091n,
|
||||
1093n,
|
||||
1097n,
|
||||
1103n,
|
||||
1109n,
|
||||
1117n,
|
||||
1123n,
|
||||
1129n,
|
||||
1151n,
|
||||
1153n,
|
||||
1163n,
|
||||
1171n,
|
||||
1181n,
|
||||
1187n,
|
||||
1193n,
|
||||
1201n,
|
||||
1213n,
|
||||
1217n,
|
||||
1223n,
|
||||
1229n,
|
||||
1231n,
|
||||
1237n,
|
||||
1249n,
|
||||
1259n,
|
||||
1277n,
|
||||
1279n,
|
||||
1283n,
|
||||
1289n,
|
||||
1291n,
|
||||
1297n,
|
||||
1301n,
|
||||
1303n,
|
||||
1307n,
|
||||
1319n,
|
||||
1321n,
|
||||
1327n,
|
||||
1361n,
|
||||
1367n,
|
||||
1373n,
|
||||
1381n,
|
||||
1399n,
|
||||
1409n,
|
||||
1423n,
|
||||
1427n,
|
||||
1429n,
|
||||
1433n,
|
||||
1439n,
|
||||
1447n,
|
||||
1451n,
|
||||
1453n,
|
||||
1459n,
|
||||
1471n,
|
||||
1481n,
|
||||
1483n,
|
||||
1487n,
|
||||
1489n,
|
||||
1493n,
|
||||
1499n,
|
||||
1511n,
|
||||
1523n,
|
||||
1531n,
|
||||
1543n,
|
||||
1549n,
|
||||
1553n,
|
||||
1559n,
|
||||
1567n,
|
||||
1571n,
|
||||
1579n,
|
||||
1583n,
|
||||
1597n
|
||||
]
|
||||
let p = _ZERO
|
||||
for (let i = 0; i < firstPrimes.length && (p <= w); i++) {
|
||||
p = BigInt(firstPrimes[i])
|
||||
|
||||
for (let i = 0; i < firstPrimes.length && (firstPrimes[i] <= w); i++) {
|
||||
const p = firstPrimes[i]
|
||||
if (w === p) {
|
||||
return true
|
||||
} else if (w % p === _ZERO) {
|
||||
} else if (w % p === 0n) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -744,29 +531,47 @@ function _isProbablyPrime (w, iterations = 16) {
|
|||
Comment: Increment i for the do-loop in step 4.
|
||||
5. Return PROBABLY PRIME.
|
||||
*/
|
||||
let a = _ZERO; let d = w - _ONE
|
||||
while (d % _TWO === _ZERO) {
|
||||
d /= _TWO
|
||||
let a = 0n
|
||||
const d = w - 1n
|
||||
let aux = d
|
||||
while (aux % 2n === 0n) {
|
||||
aux /= 2n
|
||||
++a
|
||||
}
|
||||
|
||||
const m = (w - _ONE) / (_TWO ** a)
|
||||
const m = d / (2n ** a)
|
||||
|
||||
/* eslint-disable no-labels */
|
||||
loop: do {
|
||||
const b = randBetween(w - _ONE, _TWO)
|
||||
let z = modPow(b, m, w)
|
||||
if (z === _ONE || z === w - _ONE) { continue }
|
||||
// /* eslint-disable no-labels */
|
||||
// loop: do {
|
||||
// const b = randBetween(w - 1n, 2n)
|
||||
// let z = modPow(b, m, w)
|
||||
// if (z === 1n || z === w - 1n) { continue }
|
||||
// for (let j = 1; j < a; j++) {
|
||||
// z = modPow(z, 2n, w)
|
||||
// if (z === w - 1n) { continue loop }
|
||||
// if (z === 1n) { break }
|
||||
// }
|
||||
// return false
|
||||
// } while (--iterations)
|
||||
// /* eslint-enable no-labels */
|
||||
|
||||
for (let j = 1; j < a; j++) {
|
||||
z = modPow(z, _TWO, w)
|
||||
if (z === w - _ONE) { continue loop }
|
||||
if (z === _ONE) { break }
|
||||
// return true
|
||||
|
||||
do {
|
||||
const b = randBetween(d, 2n)
|
||||
let z = bigintModArith.modPow(b, m, w)
|
||||
if (z === 1n || z === d) { continue }
|
||||
let j = 1
|
||||
while (j < a) {
|
||||
z = bigintModArith.modPow(z, 2n, w)
|
||||
if (z === d) { break }
|
||||
if (z === 1n) { return false }
|
||||
j++
|
||||
}
|
||||
if (z !== d) {
|
||||
return false
|
||||
}
|
||||
} while (--iterations)
|
||||
/* eslint-enable no-labels */
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -801,20 +606,70 @@ if (_useWorkers) { // node.js with support for workers
|
|||
}
|
||||
}
|
||||
|
||||
exports.abs = abs
|
||||
exports.bitLength = bitLength
|
||||
exports.eGcd = eGcd
|
||||
exports.gcd = gcd
|
||||
Object.defineProperty(exports, 'abs', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return bigintModArith.abs
|
||||
}
|
||||
})
|
||||
Object.defineProperty(exports, 'bitLength', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return bigintModArith.bitLength
|
||||
}
|
||||
})
|
||||
Object.defineProperty(exports, 'eGcd', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return bigintModArith.eGcd
|
||||
}
|
||||
})
|
||||
Object.defineProperty(exports, 'gcd', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return bigintModArith.gcd
|
||||
}
|
||||
})
|
||||
Object.defineProperty(exports, 'lcm', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return bigintModArith.lcm
|
||||
}
|
||||
})
|
||||
Object.defineProperty(exports, 'max', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return bigintModArith.max
|
||||
}
|
||||
})
|
||||
Object.defineProperty(exports, 'min', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return bigintModArith.min
|
||||
}
|
||||
})
|
||||
Object.defineProperty(exports, 'modInv', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return bigintModArith.modInv
|
||||
}
|
||||
})
|
||||
Object.defineProperty(exports, 'modPow', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return bigintModArith.modPow
|
||||
}
|
||||
})
|
||||
Object.defineProperty(exports, 'toZn', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return bigintModArith.toZn
|
||||
}
|
||||
})
|
||||
exports.isProbablyPrime = isProbablyPrime
|
||||
exports.lcm = lcm
|
||||
exports.max = max
|
||||
exports.min = min
|
||||
exports.modInv = modInv
|
||||
exports.modPow = modPow
|
||||
exports.prime = prime
|
||||
exports.primeSync = primeSync
|
||||
exports.randBetween = randBetween
|
||||
exports.randBits = randBits
|
||||
exports.randBytes = randBytes
|
||||
exports.randBytesSync = randBytesSync
|
||||
exports.toZn = toZn
|
||||
|
|
|
@ -105,8 +105,7 @@
|
|||
"@types/node": {
|
||||
"version": "13.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.11.0.tgz",
|
||||
"integrity": "sha512-uM4mnmsIIPK/yeO+42F2RQhGUIs39K2RFmugcJANppXe6J1nvH87PvzPZYpza7Xhhs8Yn9yIAVdLZ84z61+0xQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-uM4mnmsIIPK/yeO+42F2RQhGUIs39K2RFmugcJANppXe6J1nvH87PvzPZYpza7Xhhs8Yn9yIAVdLZ84z61+0xQ=="
|
||||
},
|
||||
"@types/resolve": {
|
||||
"version": "0.0.8",
|
||||
|
@ -262,6 +261,11 @@
|
|||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"dev": true
|
||||
},
|
||||
"bigint-mod-arith": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/bigint-mod-arith/-/bigint-mod-arith-2.0.4.tgz",
|
||||
"integrity": "sha512-sQyEj0XMU4hai3G/+uLwohrGjfUn8rGVWAYnnlFrQhw8YjilptTyJrx7NMimKwQvYr2eXGWGDlYVL3wfE4GIRg=="
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
"build:js": "rollup -c build/rollup.config.js",
|
||||
"build:standard": "standard --fix",
|
||||
"build:browserTests": "rollup -c build/rollup.tests.config.js",
|
||||
"build:docs": "jsdoc2md --template=./src/doc/readme-template.md --files ./lib/index.browser.mod.js -d 3 > README.md",
|
||||
"build:docs": "node build/build.docs.js",
|
||||
"build:dts": "node build/build.dts.js",
|
||||
"build": "run-s build:**",
|
||||
"prepublishOnly": "npm run build"
|
||||
|
@ -69,5 +69,9 @@
|
|||
"rollup-plugin-terser": "^5.3.0",
|
||||
"standard": "^14.3.3",
|
||||
"typescript": "^3.8.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "^13.11.0",
|
||||
"bigint-mod-arith": "^2.0.4"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@ bigint-crypto-utils can be imported to your project with `npm`:
|
|||
npm install bigint-crypto-utils
|
||||
```
|
||||
|
||||
NPM installation defaults to the minified ES6 module for browsers and the CJS one for Node.js.
|
||||
NPM installation defaults to the ES6 module for browsers and the CJS one for Node.js.
|
||||
|
||||
For web browsers, you can also directly download the [IIFE file](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.js) or the [ES6 module](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.mod.js) from GitHub.
|
||||
For web browsers, you can also directly download the [IIFE bundle](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.js) or the [ES6 bundle module](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.mod.js) from GitHub.
|
||||
|
||||
## Usage examples
|
||||
|
||||
|
@ -29,26 +29,25 @@ Import your module as :
|
|||
const bigintCryptoUtils = require('bigint-crypto-utils')
|
||||
... // your code here
|
||||
```
|
||||
- Javascript native project
|
||||
- JavaScript native project
|
||||
```javascript
|
||||
import * as bigintCryptoUtils from 'bigint-crypto-utils'
|
||||
... // your code here
|
||||
```
|
||||
- Javascript native browser ES6 mod
|
||||
- JavaScript native browser ES6 mod
|
||||
```html
|
||||
<script type="module">
|
||||
import * as bigintCryptoUtils from 'lib/index.browser.bundle.mod.js' // Use you actual path to the broser mod bundle
|
||||
... // your code here
|
||||
</script>
|
||||
import as bcu from 'bigint-crypto-utils'
|
||||
... // your code here
|
||||
```
|
||||
- Javascript native browser IIFE
|
||||
- JavaScript native browser IIFE
|
||||
```html
|
||||
<script src="../../lib/index.browser.bundle.js"></script>
|
||||
<script src="../../lib/index.browser.bundle.js"></script> <!-- Use you actual path to the browser bundle -->
|
||||
<script>
|
||||
... // your code here
|
||||
</script>
|
||||
```
|
||||
- TypeScript
|
||||
```typescript
|
||||
import * as bigintCryptoUtils from 'bigint-crypto-utils'
|
||||
|
@ -56,6 +55,8 @@ Import your module as :
|
|||
```
|
||||
> BigInt is [ES-2020](https://tc39.es/ecma262/#sec-bigint-objects). In order to use it with TypeScript you should set `lib` (and probably also `target` and `module`) to `esnext` in `tsconfig.json`.
|
||||
|
||||
And you could use it like in the following:
|
||||
|
||||
```javascript
|
||||
/* Stage 3 BigInts with value 666 can be declared as BigInt('666')
|
||||
or the shorter new no-so-linter-friendly syntax 666n.
|
||||
|
@ -65,22 +66,22 @@ be raised.
|
|||
*/
|
||||
const a = BigInt('5')
|
||||
const b = BigInt('2')
|
||||
const n = BigInt('19')
|
||||
const n = 19n
|
||||
|
||||
console.log(bigintCryptoUtils.modPow(a, b, n)) // prints 6
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(BigInt('2'), BigInt('5'))) // prints 3
|
||||
console.log(bigintCryptoUtils.modInv(2n, 5n)) // prints 3
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(BigInt('3'), BigInt('5'))) // prints 2
|
||||
|
||||
console.log(bigintCryptoUtils.randBetween(BigInt(2) ** BigInt(256))) // Prints a cryptographically secure random number between 1 and 2**256 bits.
|
||||
console.log(bigintCryptoUtils.randBetween(2n ** 256n)) // Prints a cryptographically secure random number between 1 and 2**256 bits.
|
||||
|
||||
async function primeTesting () {
|
||||
// Output of a probable prime of 2048 bits
|
||||
console.log(await bigintCryptoUtils.prime(2048))
|
||||
|
||||
// Testing if a number is a probable prime (Miller-Rabin)
|
||||
const number = 27
|
||||
const number = 27n
|
||||
const isPrime = await bigintCryptoUtils.isProbablyPrime(number)
|
||||
if (isPrime) {
|
||||
console.log(`${number} is prime`)
|
||||
|
@ -93,6 +94,6 @@ primeTesting()
|
|||
|
||||
```
|
||||
|
||||
## bigint-crypto-utils JS Doc
|
||||
## API reference documentation
|
||||
|
||||
{{>main}}
|
||||
|
|
794
src/js/index.js
794
src/js/index.js
|
@ -1,112 +1,5 @@
|
|||
const _ZERO = BigInt(0)
|
||||
const _ONE = BigInt(1)
|
||||
const _TWO = BigInt(2)
|
||||
|
||||
/**
|
||||
* Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
*
|
||||
* @returns {bigint} the absolute value of a
|
||||
*/
|
||||
export function abs (a) {
|
||||
a = BigInt(a)
|
||||
return (a >= _ZERO) ? a : -a
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bitlength of a number
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @returns {number} - the bit length
|
||||
*/
|
||||
export function bitLength (a) {
|
||||
a = BigInt(a)
|
||||
if (a === _ONE) { return 1 }
|
||||
let bits = 1
|
||||
do {
|
||||
bits++
|
||||
} while ((a >>= _ONE) > _ONE)
|
||||
return bits
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} egcdReturn A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
* @property {bigint} g
|
||||
* @property {bigint} x
|
||||
* @property {bigint} y
|
||||
*/
|
||||
/**
|
||||
* An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm.
|
||||
* Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {egcdReturn} A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*/
|
||||
export function eGcd (a, b) {
|
||||
a = BigInt(a)
|
||||
b = BigInt(b)
|
||||
if (a <= _ZERO | b <= _ZERO) { return NaN } // a and b MUST be positive
|
||||
|
||||
let x = _ZERO
|
||||
let y = _ONE
|
||||
let u = _ONE
|
||||
let v = _ZERO
|
||||
|
||||
while (a !== _ZERO) {
|
||||
const q = b / a
|
||||
const r = b % a
|
||||
const m = x - (u * q)
|
||||
const n = y - (v * q)
|
||||
b = a
|
||||
a = r
|
||||
x = u
|
||||
y = v
|
||||
u = m
|
||||
v = n
|
||||
}
|
||||
return {
|
||||
b: b,
|
||||
x: x,
|
||||
y: y
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Greatest-common divisor of two integers based on the iterative binary algorithm.
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} The greatest common divisor of a and b
|
||||
*/
|
||||
export function gcd (a, b) {
|
||||
a = abs(a)
|
||||
b = abs(b)
|
||||
if (a === _ZERO) { return b } else if (b === _ZERO) { return a }
|
||||
|
||||
let shift = _ZERO
|
||||
while (!((a | b) & _ONE)) {
|
||||
a >>= _ONE
|
||||
b >>= _ONE
|
||||
shift++
|
||||
}
|
||||
while (!(a & _ONE)) a >>= _ONE
|
||||
do {
|
||||
while (!(b & _ONE)) b >>= _ONE
|
||||
if (a > b) {
|
||||
const x = a
|
||||
a = b
|
||||
b = x
|
||||
}
|
||||
b -= a
|
||||
} while (b)
|
||||
|
||||
// rescale
|
||||
return a << shift
|
||||
}
|
||||
import { bitLength, eGcd, modInv, modPow, toZn } from 'bigint-mod-arith'
|
||||
export { abs, bitLength, eGcd, gcd, lcm, max, min, modInv, modPow, toZn } from 'bigint-mod-arith'
|
||||
|
||||
/**
|
||||
* The test first tries if any of the first 250 small primes are a factor of the input number and then passes several
|
||||
|
@ -115,7 +8,7 @@ export function gcd (a, b) {
|
|||
* @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} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
|
||||
* @return {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) {
|
||||
if (typeof w === 'number') {
|
||||
|
@ -170,96 +63,6 @@ export async function isProbablyPrime (w, iterations = 16) {
|
|||
/* eslint-enable no-lone-blocks */
|
||||
}
|
||||
|
||||
/**
|
||||
* The least common multiple computed as abs(a*b)/gcd(a,b)
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} The least common multiple of a and b
|
||||
*/
|
||||
export function lcm (a, b) {
|
||||
a = BigInt(a)
|
||||
b = BigInt(b)
|
||||
if (a === _ZERO && b === _ZERO) { return _ZERO }
|
||||
return abs(a * b) / gcd(a, b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum. max(a,b)==a if a>=b. max(a,b)==b if a<=b
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} maximum of numbers a and b
|
||||
*/
|
||||
export function max (a, b) {
|
||||
a = BigInt(a)
|
||||
b = BigInt(b)
|
||||
return (a >= b) ? a : b
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<=b
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} minimum of numbers a and b
|
||||
*/
|
||||
export function min (a, b) {
|
||||
a = BigInt(a)
|
||||
b = BigInt(b)
|
||||
return (a >= b) ? b : a
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular inverse.
|
||||
*
|
||||
* @param {number|bigint} a The number to find an inverse for
|
||||
* @param {number|bigint} n The modulo
|
||||
*
|
||||
* @returns {bigint} the inverse modulo n or NaN if it does not exist
|
||||
*/
|
||||
export function modInv (a, n) {
|
||||
const egcd = eGcd(toZn(a, n), n)
|
||||
if (egcd.b !== _ONE) {
|
||||
return NaN // modular inverse does not exist
|
||||
} else {
|
||||
return toZn(egcd.x, n)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular exponentiation b**e mod n. Currently using the right-to-left binary method
|
||||
*
|
||||
* @param {number|bigint} b base
|
||||
* @param {number|bigint} e exponent
|
||||
* @param {number|bigint} n modulo
|
||||
*
|
||||
* @returns {bigint} b**e mod n
|
||||
*/
|
||||
export function modPow (b, e, n) {
|
||||
n = BigInt(n)
|
||||
if (n === _ZERO) { return NaN } else if (n === _ONE) { return _ZERO }
|
||||
|
||||
b = toZn(b, n)
|
||||
|
||||
e = BigInt(e)
|
||||
if (e < _ZERO) {
|
||||
return modInv(modPow(b, abs(e), n), n)
|
||||
}
|
||||
|
||||
let r = _ONE
|
||||
while (e > 0) {
|
||||
if ((e % _TWO) === _ONE) {
|
||||
r = (r * b) % n
|
||||
}
|
||||
e = e / _TWO
|
||||
b = b ** _TWO % n
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -270,13 +73,13 @@ export function modPow (b, e, n) {
|
|||
* @param {number} bitLength The required bit length for the generated prime
|
||||
* @param {number} [iterations = 16] The number of iterations for the Miller-Rabin Probabilistic Primality Test
|
||||
*
|
||||
* @returns {Promise} A promise that resolves to a bigint probable prime of bitLength bits.
|
||||
* @returns {Promise<bigint>} A promise that resolves to a bigint probable prime of bitLength bits.
|
||||
*/
|
||||
export function prime (bitLength, iterations = 16) {
|
||||
if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) }
|
||||
|
||||
if (!process.browser && !_useWorkers) {
|
||||
let rnd = _ZERO
|
||||
let rnd = 0n
|
||||
do {
|
||||
rnd = fromBuffer(randBytesSync(bitLength / 8, true))
|
||||
} while (!_isProbablyPrime(rnd, iterations))
|
||||
|
@ -311,7 +114,7 @@ export function prime (bitLength, iterations = 16) {
|
|||
/* eslint-disable no-lone-blocks */
|
||||
if (process.browser) { // browser
|
||||
const workerURL = _isProbablyPrimeWorkerUrl()
|
||||
for (let i = 0; i < self.navigator.hardwareConcurrency; i++) {
|
||||
for (let i = 0; i < self.navigator.hardwareConcurrency - 1; i++) {
|
||||
const newWorker = new Worker(workerURL)
|
||||
newWorker.onmessage = (event) => _onmessage(event.data, newWorker)
|
||||
workerList.push(newWorker)
|
||||
|
@ -319,7 +122,7 @@ export function prime (bitLength, iterations = 16) {
|
|||
} else { // Node.js
|
||||
const { cpus } = require('os')
|
||||
const { Worker } = require('worker_threads')
|
||||
for (let i = 0; i < cpus().length; i++) {
|
||||
for (let i = 0; i < cpus().length - 1; i++) {
|
||||
const newWorker = new Worker(__filename)
|
||||
newWorker.on('message', (msg) => _onmessage(msg, newWorker))
|
||||
workerList.push(newWorker)
|
||||
|
@ -349,7 +152,7 @@ export function prime (bitLength, iterations = 16) {
|
|||
*/
|
||||
export function primeSync (bitLength, iterations = 16) {
|
||||
if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) }
|
||||
let rnd = _ZERO
|
||||
let rnd = 0n
|
||||
do {
|
||||
rnd = fromBuffer(randBytesSync(bitLength / 8, true))
|
||||
} while (!_isProbablyPrime(rnd, iterations))
|
||||
|
@ -363,7 +166,7 @@ export function primeSync (bitLength, iterations = 16) {
|
|||
*
|
||||
* @returns {bigint} A cryptographically secure random bigint between [min,max]
|
||||
*/
|
||||
export function randBetween (max, min = _ONE) {
|
||||
export function randBetween (max, min = 1n) {
|
||||
if (max <= min) throw new Error('max must be > min')
|
||||
const interval = max - min
|
||||
const bitLen = bitLength(interval)
|
||||
|
@ -408,7 +211,7 @@ export function randBits (bitLength, forceLength = false) {
|
|||
* @param {number} byteLength The desired number of random bytes
|
||||
* @param {boolean} [forceLength = false] If we want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1
|
||||
*
|
||||
* @returns {Promise} A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
||||
* @returns {Promise<Buffer | Uint8Array>} A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
||||
*/
|
||||
export function randBytes (byteLength, forceLength = false) {
|
||||
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
|
||||
|
@ -460,25 +263,10 @@ export function randBytesSync (byteLength, forceLength = false) {
|
|||
return buf
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the smallest positive element that is congruent to a in modulo n
|
||||
* @param {number|bigint} a An integer
|
||||
* @param {number|bigint} n The modulo
|
||||
*
|
||||
* @returns {bigint} The smallest positive representation of a in modulo n
|
||||
*/
|
||||
export function toZn (a, n) {
|
||||
n = BigInt(n)
|
||||
if (n <= 0) { return NaN }
|
||||
|
||||
a = BigInt(a) % n
|
||||
return (a < 0) ? a + n : a
|
||||
}
|
||||
|
||||
/* HELPER FUNCTIONS */
|
||||
|
||||
function fromBuffer (buf) {
|
||||
let ret = _ZERO
|
||||
let ret = 0n
|
||||
for (const i of buf.values()) {
|
||||
const bi = BigInt(i)
|
||||
ret = (ret << BigInt(8)) + bi
|
||||
|
@ -488,7 +276,7 @@ function fromBuffer (buf) {
|
|||
|
||||
function _isProbablyPrimeWorkerUrl () {
|
||||
// Let's us first add all the required functions
|
||||
let workerCode = `'use strict';const _ZERO = BigInt(0);const _ONE = BigInt(1);const _TWO = BigInt(2);const eGcd = ${eGcd.toString()};const modInv = ${modInv.toString()};const modPow = ${modPow.toString()};const toZn = ${toZn.toString()};const randBits = ${randBits.toString()};const randBytesSync = ${randBytesSync.toString()};const randBetween = ${randBetween.toString()};const isProbablyPrime = ${_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 ${randBits.name}=${randBits.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>}
|
||||
|
@ -516,269 +304,269 @@ function _isProbablyPrime (w, iterations = 16) {
|
|||
PREFILTERING. Even values but 2 are not primes, so don't test.
|
||||
1 is not a prime and the M-R algorithm needs w>1.
|
||||
*/
|
||||
if (w === _TWO) { return true } else if ((w & _ONE) === _ZERO || w === _ONE) { return false }
|
||||
if (w === 2n) { return true } else if ((w & 1n) === 0n || w === 1n) { return false }
|
||||
|
||||
/*
|
||||
Test if any of the first 250 small primes are a factor of w. 2 is not tested because it was already tested above.
|
||||
*/
|
||||
const firstPrimes = [
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
11,
|
||||
13,
|
||||
17,
|
||||
19,
|
||||
23,
|
||||
29,
|
||||
31,
|
||||
37,
|
||||
41,
|
||||
43,
|
||||
47,
|
||||
53,
|
||||
59,
|
||||
61,
|
||||
67,
|
||||
71,
|
||||
73,
|
||||
79,
|
||||
83,
|
||||
89,
|
||||
97,
|
||||
101,
|
||||
103,
|
||||
107,
|
||||
109,
|
||||
113,
|
||||
127,
|
||||
131,
|
||||
137,
|
||||
139,
|
||||
149,
|
||||
151,
|
||||
157,
|
||||
163,
|
||||
167,
|
||||
173,
|
||||
179,
|
||||
181,
|
||||
191,
|
||||
193,
|
||||
197,
|
||||
199,
|
||||
211,
|
||||
223,
|
||||
227,
|
||||
229,
|
||||
233,
|
||||
239,
|
||||
241,
|
||||
251,
|
||||
257,
|
||||
263,
|
||||
269,
|
||||
271,
|
||||
277,
|
||||
281,
|
||||
283,
|
||||
293,
|
||||
307,
|
||||
311,
|
||||
313,
|
||||
317,
|
||||
331,
|
||||
337,
|
||||
347,
|
||||
349,
|
||||
353,
|
||||
359,
|
||||
367,
|
||||
373,
|
||||
379,
|
||||
383,
|
||||
389,
|
||||
397,
|
||||
401,
|
||||
409,
|
||||
419,
|
||||
421,
|
||||
431,
|
||||
433,
|
||||
439,
|
||||
443,
|
||||
449,
|
||||
457,
|
||||
461,
|
||||
463,
|
||||
467,
|
||||
479,
|
||||
487,
|
||||
491,
|
||||
499,
|
||||
503,
|
||||
509,
|
||||
521,
|
||||
523,
|
||||
541,
|
||||
547,
|
||||
557,
|
||||
563,
|
||||
569,
|
||||
571,
|
||||
577,
|
||||
587,
|
||||
593,
|
||||
599,
|
||||
601,
|
||||
607,
|
||||
613,
|
||||
617,
|
||||
619,
|
||||
631,
|
||||
641,
|
||||
643,
|
||||
647,
|
||||
653,
|
||||
659,
|
||||
661,
|
||||
673,
|
||||
677,
|
||||
683,
|
||||
691,
|
||||
701,
|
||||
709,
|
||||
719,
|
||||
727,
|
||||
733,
|
||||
739,
|
||||
743,
|
||||
751,
|
||||
757,
|
||||
761,
|
||||
769,
|
||||
773,
|
||||
787,
|
||||
797,
|
||||
809,
|
||||
811,
|
||||
821,
|
||||
823,
|
||||
827,
|
||||
829,
|
||||
839,
|
||||
853,
|
||||
857,
|
||||
859,
|
||||
863,
|
||||
877,
|
||||
881,
|
||||
883,
|
||||
887,
|
||||
907,
|
||||
911,
|
||||
919,
|
||||
929,
|
||||
937,
|
||||
941,
|
||||
947,
|
||||
953,
|
||||
967,
|
||||
971,
|
||||
977,
|
||||
983,
|
||||
991,
|
||||
997,
|
||||
1009,
|
||||
1013,
|
||||
1019,
|
||||
1021,
|
||||
1031,
|
||||
1033,
|
||||
1039,
|
||||
1049,
|
||||
1051,
|
||||
1061,
|
||||
1063,
|
||||
1069,
|
||||
1087,
|
||||
1091,
|
||||
1093,
|
||||
1097,
|
||||
1103,
|
||||
1109,
|
||||
1117,
|
||||
1123,
|
||||
1129,
|
||||
1151,
|
||||
1153,
|
||||
1163,
|
||||
1171,
|
||||
1181,
|
||||
1187,
|
||||
1193,
|
||||
1201,
|
||||
1213,
|
||||
1217,
|
||||
1223,
|
||||
1229,
|
||||
1231,
|
||||
1237,
|
||||
1249,
|
||||
1259,
|
||||
1277,
|
||||
1279,
|
||||
1283,
|
||||
1289,
|
||||
1291,
|
||||
1297,
|
||||
1301,
|
||||
1303,
|
||||
1307,
|
||||
1319,
|
||||
1321,
|
||||
1327,
|
||||
1361,
|
||||
1367,
|
||||
1373,
|
||||
1381,
|
||||
1399,
|
||||
1409,
|
||||
1423,
|
||||
1427,
|
||||
1429,
|
||||
1433,
|
||||
1439,
|
||||
1447,
|
||||
1451,
|
||||
1453,
|
||||
1459,
|
||||
1471,
|
||||
1481,
|
||||
1483,
|
||||
1487,
|
||||
1489,
|
||||
1493,
|
||||
1499,
|
||||
1511,
|
||||
1523,
|
||||
1531,
|
||||
1543,
|
||||
1549,
|
||||
1553,
|
||||
1559,
|
||||
1567,
|
||||
1571,
|
||||
1579,
|
||||
1583,
|
||||
1597
|
||||
3n,
|
||||
5n,
|
||||
7n,
|
||||
11n,
|
||||
13n,
|
||||
17n,
|
||||
19n,
|
||||
23n,
|
||||
29n,
|
||||
31n,
|
||||
37n,
|
||||
41n,
|
||||
43n,
|
||||
47n,
|
||||
53n,
|
||||
59n,
|
||||
61n,
|
||||
67n,
|
||||
71n,
|
||||
73n,
|
||||
79n,
|
||||
83n,
|
||||
89n,
|
||||
97n,
|
||||
101n,
|
||||
103n,
|
||||
107n,
|
||||
109n,
|
||||
113n,
|
||||
127n,
|
||||
131n,
|
||||
137n,
|
||||
139n,
|
||||
149n,
|
||||
151n,
|
||||
157n,
|
||||
163n,
|
||||
167n,
|
||||
173n,
|
||||
179n,
|
||||
181n,
|
||||
191n,
|
||||
193n,
|
||||
197n,
|
||||
199n,
|
||||
211n,
|
||||
223n,
|
||||
227n,
|
||||
229n,
|
||||
233n,
|
||||
239n,
|
||||
241n,
|
||||
251n,
|
||||
257n,
|
||||
263n,
|
||||
269n,
|
||||
271n,
|
||||
277n,
|
||||
281n,
|
||||
283n,
|
||||
293n,
|
||||
307n,
|
||||
311n,
|
||||
313n,
|
||||
317n,
|
||||
331n,
|
||||
337n,
|
||||
347n,
|
||||
349n,
|
||||
353n,
|
||||
359n,
|
||||
367n,
|
||||
373n,
|
||||
379n,
|
||||
383n,
|
||||
389n,
|
||||
397n,
|
||||
401n,
|
||||
409n,
|
||||
419n,
|
||||
421n,
|
||||
431n,
|
||||
433n,
|
||||
439n,
|
||||
443n,
|
||||
449n,
|
||||
457n,
|
||||
461n,
|
||||
463n,
|
||||
467n,
|
||||
479n,
|
||||
487n,
|
||||
491n,
|
||||
499n,
|
||||
503n,
|
||||
509n,
|
||||
521n,
|
||||
523n,
|
||||
541n,
|
||||
547n,
|
||||
557n,
|
||||
563n,
|
||||
569n,
|
||||
571n,
|
||||
577n,
|
||||
587n,
|
||||
593n,
|
||||
599n,
|
||||
601n,
|
||||
607n,
|
||||
613n,
|
||||
617n,
|
||||
619n,
|
||||
631n,
|
||||
641n,
|
||||
643n,
|
||||
647n,
|
||||
653n,
|
||||
659n,
|
||||
661n,
|
||||
673n,
|
||||
677n,
|
||||
683n,
|
||||
691n,
|
||||
701n,
|
||||
709n,
|
||||
719n,
|
||||
727n,
|
||||
733n,
|
||||
739n,
|
||||
743n,
|
||||
751n,
|
||||
757n,
|
||||
761n,
|
||||
769n,
|
||||
773n,
|
||||
787n,
|
||||
797n,
|
||||
809n,
|
||||
811n,
|
||||
821n,
|
||||
823n,
|
||||
827n,
|
||||
829n,
|
||||
839n,
|
||||
853n,
|
||||
857n,
|
||||
859n,
|
||||
863n,
|
||||
877n,
|
||||
881n,
|
||||
883n,
|
||||
887n,
|
||||
907n,
|
||||
911n,
|
||||
919n,
|
||||
929n,
|
||||
937n,
|
||||
941n,
|
||||
947n,
|
||||
953n,
|
||||
967n,
|
||||
971n,
|
||||
977n,
|
||||
983n,
|
||||
991n,
|
||||
997n,
|
||||
1009n,
|
||||
1013n,
|
||||
1019n,
|
||||
1021n,
|
||||
1031n,
|
||||
1033n,
|
||||
1039n,
|
||||
1049n,
|
||||
1051n,
|
||||
1061n,
|
||||
1063n,
|
||||
1069n,
|
||||
1087n,
|
||||
1091n,
|
||||
1093n,
|
||||
1097n,
|
||||
1103n,
|
||||
1109n,
|
||||
1117n,
|
||||
1123n,
|
||||
1129n,
|
||||
1151n,
|
||||
1153n,
|
||||
1163n,
|
||||
1171n,
|
||||
1181n,
|
||||
1187n,
|
||||
1193n,
|
||||
1201n,
|
||||
1213n,
|
||||
1217n,
|
||||
1223n,
|
||||
1229n,
|
||||
1231n,
|
||||
1237n,
|
||||
1249n,
|
||||
1259n,
|
||||
1277n,
|
||||
1279n,
|
||||
1283n,
|
||||
1289n,
|
||||
1291n,
|
||||
1297n,
|
||||
1301n,
|
||||
1303n,
|
||||
1307n,
|
||||
1319n,
|
||||
1321n,
|
||||
1327n,
|
||||
1361n,
|
||||
1367n,
|
||||
1373n,
|
||||
1381n,
|
||||
1399n,
|
||||
1409n,
|
||||
1423n,
|
||||
1427n,
|
||||
1429n,
|
||||
1433n,
|
||||
1439n,
|
||||
1447n,
|
||||
1451n,
|
||||
1453n,
|
||||
1459n,
|
||||
1471n,
|
||||
1481n,
|
||||
1483n,
|
||||
1487n,
|
||||
1489n,
|
||||
1493n,
|
||||
1499n,
|
||||
1511n,
|
||||
1523n,
|
||||
1531n,
|
||||
1543n,
|
||||
1549n,
|
||||
1553n,
|
||||
1559n,
|
||||
1567n,
|
||||
1571n,
|
||||
1579n,
|
||||
1583n,
|
||||
1597n
|
||||
]
|
||||
let p = _ZERO
|
||||
for (let i = 0; i < firstPrimes.length && (p <= w); i++) {
|
||||
p = BigInt(firstPrimes[i])
|
||||
|
||||
for (let i = 0; i < firstPrimes.length && (firstPrimes[i] <= w); i++) {
|
||||
const p = firstPrimes[i]
|
||||
if (w === p) {
|
||||
return true
|
||||
} else if (w % p === _ZERO) {
|
||||
} else if (w % p === 0n) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -802,29 +590,47 @@ function _isProbablyPrime (w, iterations = 16) {
|
|||
Comment: Increment i for the do-loop in step 4.
|
||||
5. Return PROBABLY PRIME.
|
||||
*/
|
||||
let a = _ZERO; let d = w - _ONE
|
||||
while (d % _TWO === _ZERO) {
|
||||
d /= _TWO
|
||||
let a = 0n
|
||||
const d = w - 1n
|
||||
let aux = d
|
||||
while (aux % 2n === 0n) {
|
||||
aux /= 2n
|
||||
++a
|
||||
}
|
||||
|
||||
const m = (w - _ONE) / (_TWO ** a)
|
||||
const m = d / (2n ** a)
|
||||
|
||||
/* eslint-disable no-labels */
|
||||
loop: do {
|
||||
const b = randBetween(w - _ONE, _TWO)
|
||||
// /* eslint-disable no-labels */
|
||||
// loop: do {
|
||||
// const b = randBetween(w - 1n, 2n)
|
||||
// let z = modPow(b, m, w)
|
||||
// if (z === 1n || z === w - 1n) { continue }
|
||||
// for (let j = 1; j < a; j++) {
|
||||
// z = modPow(z, 2n, w)
|
||||
// if (z === w - 1n) { continue loop }
|
||||
// if (z === 1n) { break }
|
||||
// }
|
||||
// return false
|
||||
// } while (--iterations)
|
||||
// /* eslint-enable no-labels */
|
||||
|
||||
// return true
|
||||
|
||||
do {
|
||||
const b = randBetween(d, 2n)
|
||||
let z = modPow(b, m, w)
|
||||
if (z === _ONE || z === w - _ONE) { continue }
|
||||
|
||||
for (let j = 1; j < a; j++) {
|
||||
z = modPow(z, _TWO, w)
|
||||
if (z === w - _ONE) { continue loop }
|
||||
if (z === _ONE) { break }
|
||||
if (z === 1n || z === d) { continue }
|
||||
let j = 1
|
||||
while (j < a) {
|
||||
z = modPow(z, 2n, w)
|
||||
if (z === d) { break }
|
||||
if (z === 1n) { return false }
|
||||
j++
|
||||
}
|
||||
if (z !== d) {
|
||||
return false
|
||||
}
|
||||
} while (--iterations)
|
||||
/* eslint-enable no-labels */
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -1,51 +1,3 @@
|
|||
/**
|
||||
* A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*/
|
||||
export type egcdReturn = {
|
||||
g: bigint;
|
||||
x: bigint;
|
||||
y: bigint;
|
||||
};
|
||||
/**
|
||||
* Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
*
|
||||
* @returns {bigint} the absolute value of a
|
||||
*/
|
||||
export function abs(a: number | bigint): bigint;
|
||||
/**
|
||||
* Returns the bitlength of a number
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @returns {number} - the bit length
|
||||
*/
|
||||
export function bitLength(a: number | bigint): number;
|
||||
/**
|
||||
* @typedef {Object} egcdReturn A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
* @property {bigint} g
|
||||
* @property {bigint} x
|
||||
* @property {bigint} y
|
||||
*/
|
||||
/**
|
||||
* An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm.
|
||||
* Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {egcdReturn} A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*/
|
||||
export function eGcd(a: number | bigint, b: number | bigint): egcdReturn;
|
||||
/**
|
||||
* Greatest-common divisor of two integers based on the iterative binary algorithm.
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} The greatest common divisor of a and b
|
||||
*/
|
||||
export function gcd(a: number | bigint, b: number | bigint): bigint;
|
||||
/**
|
||||
* 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)
|
||||
|
@ -53,54 +5,9 @@ export function gcd(a: number | bigint, b: number | bigint): bigint;
|
|||
* @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} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
|
||||
* @return {Promise<boolean>} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
|
||||
*/
|
||||
export function isProbablyPrime(w: number | bigint, iterations?: number): Promise<any>;
|
||||
/**
|
||||
* The least common multiple computed as abs(a*b)/gcd(a,b)
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} The least common multiple of a and b
|
||||
*/
|
||||
export function lcm(a: number | bigint, b: number | bigint): bigint;
|
||||
/**
|
||||
* Maximum. max(a,b)==a if a>=b. max(a,b)==b if a<=b
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} maximum of numbers a and b
|
||||
*/
|
||||
export function max(a: number | bigint, b: number | bigint): bigint;
|
||||
/**
|
||||
* Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<=b
|
||||
*
|
||||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @returns {bigint} minimum of numbers a and b
|
||||
*/
|
||||
export function min(a: number | bigint, b: number | bigint): bigint;
|
||||
/**
|
||||
* Modular inverse.
|
||||
*
|
||||
* @param {number|bigint} a The number to find an inverse for
|
||||
* @param {number|bigint} n The modulo
|
||||
*
|
||||
* @returns {bigint} the inverse modulo n or NaN if it does not exist
|
||||
*/
|
||||
export function modInv(a: number | bigint, n: number | bigint): bigint;
|
||||
/**
|
||||
* Modular exponentiation b**e mod n. Currently using the right-to-left binary method
|
||||
*
|
||||
* @param {number|bigint} b base
|
||||
* @param {number|bigint} e exponent
|
||||
* @param {number|bigint} n modulo
|
||||
*
|
||||
* @returns {bigint} b**e mod n
|
||||
*/
|
||||
export function modPow(b: number | bigint, e: number | bigint, n: number | bigint): bigint;
|
||||
export function isProbablyPrime(w: number | bigint, iterations?: number): Promise<boolean>;
|
||||
/**
|
||||
* 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
|
||||
|
@ -111,9 +18,9 @@ export function modPow(b: number | bigint, e: number | bigint, n: number | bigin
|
|||
* @param {number} bitLength The required bit length for the generated prime
|
||||
* @param {number} [iterations = 16] The number of iterations for the Miller-Rabin Probabilistic Primality Test
|
||||
*
|
||||
* @returns {Promise} A promise that resolves to a bigint probable prime of bitLength bits.
|
||||
* @returns {Promise<bigint>} A promise that resolves to a bigint probable prime of bitLength bits.
|
||||
*/
|
||||
export function prime(bitLength: number, iterations?: number): Promise<any>;
|
||||
export function prime(bitLength: number, iterations?: number): Promise<bigint>;
|
||||
/**
|
||||
* 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.
|
||||
|
@ -147,9 +54,9 @@ export function randBits(bitLength: number, forceLength?: boolean): Uint8Array |
|
|||
* @param {number} byteLength The desired number of random bytes
|
||||
* @param {boolean} [forceLength = false] If we want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1
|
||||
*
|
||||
* @returns {Promise} A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
||||
* @returns {Promise<Buffer | Uint8Array>} A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
||||
*/
|
||||
export function randBytes(byteLength: number, forceLength?: boolean): Promise<any>;
|
||||
export function randBytes(byteLength: number, forceLength?: boolean): Promise<Uint8Array | Buffer>;
|
||||
/**
|
||||
* Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
*
|
||||
|
@ -159,11 +66,4 @@ export function randBytes(byteLength: number, forceLength?: boolean): Promise<an
|
|||
* @returns {Buffer | Uint8Array} A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
||||
*/
|
||||
export function randBytesSync(byteLength: number, forceLength?: boolean): Uint8Array | Buffer;
|
||||
/**
|
||||
* Finds the smallest positive element that is congruent to a in modulo n
|
||||
* @param {number|bigint} a An integer
|
||||
* @param {number|bigint} n The modulo
|
||||
*
|
||||
* @returns {bigint} The smallest positive representation of a in modulo n
|
||||
*/
|
||||
export function toZn(a: number | bigint, n: number | bigint): bigint;
|
||||
export { abs, bitLength, eGcd, gcd, lcm, max, min, modInv, modPow, toZn } from "bigint-mod-arith";
|
||||
|
|
Loading…
Reference in New Issue