more tests. Fixed some bugs. Added github actions
This commit is contained in:
parent
f4430c5f08
commit
b3a90aa6bc
|
@ -0,0 +1,81 @@
|
|||
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
||||
|
||||
name: Node CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: build, test, check coverage
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [11, 12, 13]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: install
|
||||
run: npm ci
|
||||
|
||||
- name: build
|
||||
run: npm run build
|
||||
|
||||
- name: test
|
||||
run: npm test
|
||||
|
||||
publication:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: EndBug/version-check@v1
|
||||
id: check
|
||||
|
||||
- name: check version changes
|
||||
if: steps.check.outputs.changed == 'true'
|
||||
run: 'echo "Version change found! New version: ${{ steps.check.outputs.version }} (${{ steps.check.outputs.type }})"'
|
||||
|
||||
- uses: actions/setup-node@v1
|
||||
if: steps.check.outputs.changed == 'true'
|
||||
with:
|
||||
node-version: 12
|
||||
registry-url: https://registry.npmjs.org/
|
||||
|
||||
- name: install
|
||||
if: steps.check.outputs.changed == 'true'
|
||||
run: npm ci
|
||||
|
||||
- name: build
|
||||
if: steps.check.outputs.changed == 'true'
|
||||
run: npm run build
|
||||
|
||||
- name: test
|
||||
if: steps.check.outputs.changed == 'true'
|
||||
run: npm test
|
||||
|
||||
- name: create code coverage report
|
||||
if: steps.check.outputs.changed == 'true'
|
||||
run: npm run coverage
|
||||
|
||||
- name: send report to coveralls.io
|
||||
if: steps.check.outputs.changed == 'true'
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: publish to NPM
|
||||
if: steps.check.outputs.changed == 'true'
|
||||
run: npm publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@ -13,4 +13,8 @@ node_modules/
|
|||
.vscode
|
||||
|
||||
# IntelliJ
|
||||
.idea/
|
||||
.idea
|
||||
|
||||
# MYC output
|
||||
.nyc_output
|
||||
coverage/*
|
||||
|
|
13
.npmignore
13
.npmignore
|
@ -20,3 +20,16 @@ npm-debug.log*
|
|||
|
||||
# Visual Studio Code
|
||||
.vscode
|
||||
|
||||
# IntelliJ
|
||||
.idea
|
||||
|
||||
# MYC output
|
||||
.nyc_output
|
||||
coverage/*
|
||||
|
||||
# Travis
|
||||
.travis.yml
|
||||
|
||||
# GitHub
|
||||
.github
|
266
README.md
266
README.md
|
@ -1,8 +1,15 @@
|
|||
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
|
||||
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
|
||||
![Node CI](https://github.com/juanelas/bigint-crypto-utils/workflows/Node%20CI/badge.svg)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/juanelas/bigint-crypto-utils/badge.svg?branch=master)](https://coveralls.io/github/juanelas/bigint-crypto-utils?branch=master)
|
||||
|
||||
# bigint-crypto-utils
|
||||
|
||||
Utils for working with cryptography using native JS ([ES-2020](https://tc39.es/ecma262/#sec-bigint-objects)) implementation of BigInt. It includes some extra functions to work with modular arithmetic along with secure random numbers and a fast strong probable prime generator/tester (parallelized multi-threaded Miller-Rabin primality tests if workers are supported). It can be used by any [Web Browser or webview supporting BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) and with Node.js (>=10.4.0).
|
||||
Arbitrary precision modular arithmetic, cryptographically secure random numbers and strong probable prime generation/testing.
|
||||
|
||||
It relies on the native JS implementation of ([BigInt](https://tc39.es/ecma262/#sec-bigint-objects)). It can be used by any [Web Browser or webview supporting BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) and with Node.js (>=10.4.0). The bundles can be imported directly by the browser or in Angular projects, React apps, Node.js, etc.
|
||||
|
||||
Secure random numbers are generated using the native crypto implementation of the browsers ([Web Cryptography API](https://w3c.github.io/webcrypto/)) or [Node.js Crypto](https://nodejs.org/dist/latest/docs/api/crypto.html)). Strong probable prime generation and testing use Miller-Rabin primality tests and are automatically sped up using parallel workers both in browsers and Node.js.
|
||||
|
||||
> The operations supported on BigInts are not constant time. BigInt can be therefore **[unsuitable for use in cryptography](https://www.chosenplaintext.ca/articles/beginners-guide-constant-time-cryptography.html).** Many platforms provide native support for cryptography, such as [Web Cryptography API](https://w3c.github.io/webcrypto/) or [Node.js Crypto](https://nodejs.org/dist/latest/docs/api/crypto.html).
|
||||
|
||||
|
@ -16,9 +23,7 @@ bigint-crypto-utils can be imported to your project with `npm`:
|
|||
npm install bigint-crypto-utils
|
||||
```
|
||||
|
||||
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 bundle](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.iife.js) or the [ES6 bundle module](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.mod.js) from GitHub.
|
||||
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 bundle](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.iife.js) or the [ESM bundle](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.mod.js) from the repository.
|
||||
|
||||
## Usage examples
|
||||
|
||||
|
@ -29,13 +34,30 @@ Import your module as :
|
|||
const bigintCryptoUtils = require('bigint-crypto-utils')
|
||||
... // your code here
|
||||
```
|
||||
- JavaScript native or TypeScript project
|
||||
- JavaScript native or TypeScript project (including React and Angular JS)
|
||||
```javascript
|
||||
import * as bigintCryptoUtils from 'bigint-crypto-utils'
|
||||
... // your code here
|
||||
```
|
||||
> 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`.
|
||||
- JavaScript native browser ES6 mod
|
||||
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`.
|
||||
`bigint-crypto-utils` **CANNOT BE POLYFILLED** to suport older browsers. If you are using webpack/babel to create your production bundles, you should target only the most modern browsers. For instance, for **React** apps created with [`create-react-app`](https://create-react-app.dev/), you should edit your `package.json` and modify the `browserList` so that it only targets the latest browsers (supporting the latest features):
|
||||
```json
|
||||
"browserslist": {
|
||||
"production": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
```
|
||||
Also, notice that 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`.
|
||||
|
||||
- JavaScript native browser ES module
|
||||
```html
|
||||
<script type="module">
|
||||
import * as bigintCryptoUtils from 'lib/index.browser.bundle.mod.js' // Use you actual path to the broser mod bundle
|
||||
|
@ -100,214 +122,9 @@ You can find examples in the [examples folder of the repository](https://github.
|
|||
|
||||
## API reference documentation
|
||||
|
||||
### 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="#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="#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>
|
||||
<dt><a href="#isProbablyPrime">isProbablyPrime(w, [iterations])</a> ⇒ <code>Promise.<boolean></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="#prime">prime(bitLength, [iterations])</a> ⇒ <code>Promise.<bigint></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>Promise.<(Buffer|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>
|
||||
<p>Since version 3.0.0 this is an async function and a new randBitsSync function has been added. If you are migrating from version 2 call randBitsSync instead.</p>
|
||||
</dd>
|
||||
<dt><a href="#randBitsSync">randBitsSync(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.<(Buffer|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="#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>
|
||||
</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>
|
||||
|
||||
<a name="abs"></a>
|
||||
|
||||
### abs(a) ⇒ <code>bigint</code>
|
||||
Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>bigint</code> - the absolute value of a
|
||||
|
||||
| Param | Type |
|
||||
| --- | --- |
|
||||
| a | <code>number</code> \| <code>bigint</code> |
|
||||
|
||||
<a name="bitLength"></a>
|
||||
|
||||
### bitLength(a) ⇒ <code>number</code>
|
||||
Returns the bitlength of a number
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>number</code> - - the bit length
|
||||
|
||||
| Param | Type |
|
||||
| --- | --- |
|
||||
| a | <code>number</code> \| <code>bigint</code> |
|
||||
|
||||
<a name="eGcd"></a>
|
||||
|
||||
### eGcd(a, b) ⇒ [<code>egcdReturn</code>](#egcdReturn)
|
||||
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).
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: [<code>egcdReturn</code>](#egcdReturn) - A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
|
||||
| Param | Type |
|
||||
| --- | --- |
|
||||
| a | <code>number</code> \| <code>bigint</code> |
|
||||
| b | <code>number</code> \| <code>bigint</code> |
|
||||
|
||||
<a name="gcd"></a>
|
||||
|
||||
### gcd(a, b) ⇒ <code>bigint</code>
|
||||
Greatest-common divisor of two integers based on the iterative binary algorithm.
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>bigint</code> - The greatest common divisor of a and b
|
||||
|
||||
| Param | Type |
|
||||
| --- | --- |
|
||||
| a | <code>number</code> \| <code>bigint</code> |
|
||||
| b | <code>number</code> \| <code>bigint</code> |
|
||||
|
||||
<a name="lcm"></a>
|
||||
|
||||
### lcm(a, b) ⇒ <code>bigint</code>
|
||||
The least common multiple computed as abs(a*b)/gcd(a,b)
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>bigint</code> - The least common multiple of a and b
|
||||
|
||||
| Param | Type |
|
||||
| --- | --- |
|
||||
| a | <code>number</code> \| <code>bigint</code> |
|
||||
| b | <code>number</code> \| <code>bigint</code> |
|
||||
|
||||
<a name="max"></a>
|
||||
|
||||
### max(a, b) ⇒ <code>bigint</code>
|
||||
Maximum. max(a,b)==a if a>=b. max(a,b)==b if a<=b
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>bigint</code> - maximum of numbers a and b
|
||||
|
||||
| Param | Type |
|
||||
| --- | --- |
|
||||
| a | <code>number</code> \| <code>bigint</code> |
|
||||
| b | <code>number</code> \| <code>bigint</code> |
|
||||
|
||||
<a name="min"></a>
|
||||
|
||||
### min(a, b) ⇒ <code>bigint</code>
|
||||
Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<=b
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>bigint</code> - minimum of numbers a and b
|
||||
|
||||
| Param | Type |
|
||||
| --- | --- |
|
||||
| a | <code>number</code> \| <code>bigint</code> |
|
||||
| b | <code>number</code> \| <code>bigint</code> |
|
||||
|
||||
<a name="modInv"></a>
|
||||
|
||||
### modInv(a, n) ⇒ <code>bigint</code>
|
||||
Modular inverse.
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>bigint</code> - the inverse modulo n or NaN if it does not exist
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| a | <code>number</code> \| <code>bigint</code> | The number to find an inverse for |
|
||||
| n | <code>number</code> \| <code>bigint</code> | The modulo |
|
||||
|
||||
<a name="modPow"></a>
|
||||
|
||||
### modPow(b, e, n) ⇒ <code>bigint</code>
|
||||
Modular exponentiation b**e mod n. Currently using the right-to-left binary method
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>bigint</code> - b**e mod n
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| b | <code>number</code> \| <code>bigint</code> | base |
|
||||
| e | <code>number</code> \| <code>bigint</code> | exponent |
|
||||
| n | <code>number</code> \| <code>bigint</code> | modulo |
|
||||
|
||||
<a name="toZn"></a>
|
||||
|
||||
### toZn(a, n) ⇒ <code>bigint</code>
|
||||
Finds the smallest positive element that is congruent to a in modulo n
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>bigint</code> - The smallest positive representation of a in modulo n
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| a | <code>number</code> \| <code>bigint</code> | An integer |
|
||||
| n | <code>number</code> \| <code>bigint</code> | The modulo |
|
||||
|
||||
<a name="isProbablyPrime"></a>
|
||||
|
||||
### isProbablyPrime(w, [iterations]) ⇒ <code>Promise.<boolean></code>
|
||||
### isProbablyPrime(w, [iterations], [disableWorkers]) ⇒ <code>Promise.<boolean></code>
|
||||
The test first tries if any of the first 250 small primes are a factor of the input number and then passes several
|
||||
iterations of Miller-Rabin Probabilistic Primality Test (FIPS 186-4 C.3.1)
|
||||
|
||||
|
@ -318,6 +135,7 @@ iterations of Miller-Rabin Probabilistic Primality Test (FIPS 186-4 C.3.1)
|
|||
| --- | --- | --- | --- |
|
||||
| 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 |
|
||||
| [disableWorkers] | <code>boolean</code> | <code>false</code> | Disable the use of workers for the primality test |
|
||||
|
||||
<a name="prime"></a>
|
||||
|
||||
|
@ -353,7 +171,7 @@ The sync version is NOT RECOMMENDED since it won't use workers and thus it'll be
|
|||
<a name="randBetween"></a>
|
||||
|
||||
### randBetween(max, [min]) ⇒ <code>bigint</code>
|
||||
Returns a cryptographically secure random integer between [min,max]
|
||||
Returns a cryptographically secure random integer between [min,max]. Both numbers must be >=0
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>bigint</code> - A cryptographically secure random bigint between [min,max]
|
||||
|
@ -368,11 +186,8 @@ Returns a cryptographically secure random integer between [min,max]
|
|||
### randBits(bitLength, [forceLength]) ⇒ <code>Promise.<(Buffer\|Uint8Array)></code>
|
||||
Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
|
||||
Since version 3.0.0 this is an async function and a new randBitsSync function has been added. If you are migrating from version 2 call randBitsSync instead.
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>Promise.<(Buffer\|Uint8Array)></code> - A Promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bits
|
||||
**Since**: 3.0.0
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
|
@ -386,7 +201,6 @@ Secure random bits for both node and browsers. Node version uses crypto.randomFi
|
|||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>Buffer</code> \| <code>Uint8Array</code> - A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bits
|
||||
**Since**: 3.0.0
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
|
@ -396,7 +210,7 @@ Secure random bits for both node and browsers. Node version uses crypto.randomFi
|
|||
<a name="randBytes"></a>
|
||||
|
||||
### randBytes(byteLength, [forceLength]) ⇒ <code>Promise.<(Buffer\|Uint8Array)></code>
|
||||
Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
Secure random bytes for both node and browsers. Node version uses crypto.randomBytes() and browser one self.crypto.getRandomValues()
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>Promise.<(Buffer\|Uint8Array)></code> - A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
||||
|
@ -419,17 +233,3 @@ Secure random bytes for both node and browsers. Node version uses crypto.randomF
|
|||
| byteLength | <code>number</code> | | The desired number of random bytes |
|
||||
| [forceLength] | <code>boolean</code> | <code>false</code> | If we want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1 |
|
||||
|
||||
<a name="egcdReturn"></a>
|
||||
|
||||
### egcdReturn : <code>Object</code>
|
||||
A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
|
||||
**Kind**: global typedef
|
||||
**Properties**
|
||||
|
||||
| Name | Type |
|
||||
| --- | --- |
|
||||
| g | <code>bigint</code> |
|
||||
| x | <code>bigint</code> |
|
||||
| y | <code>bigint</code> |
|
||||
|
||||
|
|
|
@ -7,15 +7,57 @@ const pkgJson = require('../package.json')
|
|||
|
||||
const rootDir = path.join(__dirname, '..')
|
||||
|
||||
const template = path.join(rootDir, pkgJson.directories.src, 'doc', 'readme-template.md')
|
||||
function camelise (str) {
|
||||
return str.replace(/-([a-z])/g,
|
||||
function (m, w) {
|
||||
return w.toUpperCase()
|
||||
})
|
||||
}
|
||||
|
||||
function getRepositoryData () {
|
||||
if (typeof pkgJson.repository === 'string') {
|
||||
const repodata = pkgJson.repository.split(/[:/]/)
|
||||
const repoProvider = repodata[0]
|
||||
if (repoProvider === 'github' || repoProvider === 'gitlab' || repoProvider === 'bitbucket') {
|
||||
return {
|
||||
repoProvider,
|
||||
repoUsername: repodata[1],
|
||||
repoName: repodata[2]
|
||||
}
|
||||
} else return null
|
||||
}
|
||||
}
|
||||
|
||||
const { repoProvider, repoUsername, repoName } = getRepositoryData() || { repoProvider: null, repoUsername: null, repoName: null }
|
||||
|
||||
let iifeBundle, esmBundle, workflowBadget, coverallsBadge
|
||||
if (repoProvider && repoProvider === 'github') {
|
||||
iifeBundle = `[IIFE bundle](https://raw.githubusercontent.com/${repoUsername}/${repoName}/master/lib/index.browser.bundle.iife.js)`
|
||||
esmBundle = `[ESM bundle](https://raw.githubusercontent.com/${repoUsername}/${repoName}/master/lib/index.browser.bundle.mod.js)`
|
||||
workflowBadget = `![Node CI](https://github.com/${repoUsername}/${repoName}/workflows/Node%20CI/badge.svg)`
|
||||
coverallsBadge = `[![Coverage Status](https://coveralls.io/repos/github/${repoUsername}/${repoName}/badge.svg?branch=master)](https://coveralls.io/github/${repoUsername}/${repoName}?branch=master)`
|
||||
}
|
||||
|
||||
const templateFile = path.join(rootDir, pkgJson.directories.src, 'doc', 'readme-template.md')
|
||||
let template = fs.readFileSync(templateFile, { encoding: 'UTF-8' })
|
||||
.replace(/\{\{PKG_NAME\}\}/g, pkgJson.name)
|
||||
.replace(/\{\{PKG_CAMELCASE\}\}/g, camelise(pkgJson.name))
|
||||
.replace(/\{\{IIFE_BUNDLE\}\}/g, iifeBundle || 'IIFE bundle')
|
||||
.replace(/\{\{ESM_BUNDLE\}\}/g, esmBundle || 'ESM bundle')
|
||||
|
||||
if (repoProvider && repoProvider === 'github') {
|
||||
template = template.replace(/\{\{GITHUB_ACTIONS_BADGES\}\}/g, workflowBadget + '\n' + coverallsBadge)
|
||||
}
|
||||
|
||||
const input = path.join(rootDir, pkgJson.browser)
|
||||
// Let us replace bigint literals by standard numbers to avoid issues with bigint
|
||||
const source = fs.readFileSync(input, { encoding: 'UTF-8' }).replace(/([0-9]+)n([,\s\n)])/g, '$1$2')
|
||||
|
||||
const options = {
|
||||
source, // we need to use this instead of files in order to avoid issues with esnext features
|
||||
template: fs.readFileSync(template, { encoding: 'UTF-8' }),
|
||||
'heading-depth': 3 // The initial heading depth. For example, with a value of 2 the top-level markdown headings look like "## The heading"
|
||||
// 'global-index-format': 'none' // none, grouped, table, dl.
|
||||
source,
|
||||
template,
|
||||
'heading-depth': 3, // The initial heading depth. For example, with a value of 2 the top-level markdown headings look like "## The heading"
|
||||
'global-index-format': 'none' // none, grouped, table, dl.
|
||||
}
|
||||
|
||||
jsdoc2md.clear().then(() => {
|
||||
|
|
|
@ -24,13 +24,24 @@ const pkgCamelisedName = camelise(pkgName)
|
|||
const input = path.join(srcDir, 'js', 'index.js')
|
||||
|
||||
module.exports = [
|
||||
{ // Browser
|
||||
{ // Native JS
|
||||
input: input,
|
||||
output: [
|
||||
{
|
||||
file: path.join(rootDir, pkgJson.browser),
|
||||
format: 'es'
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
replace({
|
||||
'process.browser': true
|
||||
})
|
||||
],
|
||||
external: ['bigint-mod-arith']
|
||||
},
|
||||
{ // Browser bundles
|
||||
input: input,
|
||||
output: [
|
||||
{
|
||||
file: path.join(dstDir, 'index.browser.bundle.iife.js'),
|
||||
format: 'iife',
|
||||
|
@ -48,24 +59,22 @@ module.exports = [
|
|||
resolve({
|
||||
browser: true
|
||||
}),
|
||||
terser({
|
||||
exclude: [path.basename(pkgJson.browser)]
|
||||
})
|
||||
terser()
|
||||
]
|
||||
},
|
||||
{ // Node
|
||||
input: input,
|
||||
output: {
|
||||
file: path.join(rootDir, pkgJson.main),
|
||||
format: 'cjs'
|
||||
format: 'cjs',
|
||||
esModule: false,
|
||||
externalLiveBindings: false
|
||||
},
|
||||
plugins: [
|
||||
replace({
|
||||
'process.browser': false
|
||||
}),
|
||||
resolve({
|
||||
browser: true
|
||||
})
|
||||
]
|
||||
],
|
||||
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,213 +1,5 @@
|
|||
/**
|
||||
* 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 >= 0n) ? 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 === 1n) { return 1 }
|
||||
let bits = 1
|
||||
do {
|
||||
bits++
|
||||
} while ((a >>= 1n) > 1n)
|
||||
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 <= 0n | b <= 0n) { return NaN } // a and b MUST be positive
|
||||
|
||||
let x = 0n
|
||||
let y = 1n
|
||||
let u = 1n
|
||||
let v = 0n
|
||||
|
||||
while (a !== 0n) {
|
||||
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 === 0n) { return b } else if (b === 0n) { return a }
|
||||
|
||||
let shift = 0n
|
||||
while (!((a | b) & 1n)) {
|
||||
a >>= 1n
|
||||
b >>= 1n
|
||||
shift++
|
||||
}
|
||||
while (!(a & 1n)) a >>= 1n
|
||||
do {
|
||||
while (!(b & 1n)) b >>= 1n
|
||||
if (a > b) {
|
||||
const x = a
|
||||
a = b
|
||||
b = x
|
||||
}
|
||||
b -= a
|
||||
} while (b)
|
||||
|
||||
// rescale
|
||||
return a << shift
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 === 0n && b === 0n) { return 0n }
|
||||
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 !== 1n) {
|
||||
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 === 0n) { return NaN } else if (n === 1n) { return 0n }
|
||||
|
||||
b = toZn(b, n)
|
||||
|
||||
e = BigInt(e)
|
||||
if (e < 0n) {
|
||||
return modInv(modPow(b, abs(e), n), n)
|
||||
}
|
||||
|
||||
let r = 1n
|
||||
while (e > 0) {
|
||||
if ((e % 2n) === 1n) {
|
||||
r = (r * b) % n
|
||||
}
|
||||
e = e / 2n
|
||||
b = b ** 2n % n
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
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
|
||||
|
@ -215,10 +7,11 @@ function toZn (a, n) {
|
|||
*
|
||||
* @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
|
||||
* @param {boolean} [disableWorkers = false] Disable the use of workers for the primality test
|
||||
*
|
||||
* @returns {Promise<boolean>} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
|
||||
*/
|
||||
function isProbablyPrime (w, iterations = 16) {
|
||||
function isProbablyPrime (w, iterations = 16, disableWorkers = false) {
|
||||
if (typeof w === 'number') {
|
||||
w = BigInt(w)
|
||||
}
|
||||
|
@ -259,8 +52,9 @@ function isProbablyPrime (w, iterations = 16) {
|
|||
* @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 (bitLength < 1) throw new RangeError('bitLength MUST be > 0')
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (!_useWorkers) { // If there is no support for workers
|
||||
let rnd = 0n
|
||||
do {
|
||||
|
@ -305,13 +99,14 @@ function prime (bitLength, iterations = 16) {
|
|||
}
|
||||
/* eslint-enable no-lone-blocks */
|
||||
for (let i = 0; i < workerList.length; i++) {
|
||||
const buf = randBitsSync(bitLength, true)
|
||||
randBits(bitLength, true).then(function (buf) {
|
||||
const rnd = fromBuffer(buf)
|
||||
workerList[i].postMessage({
|
||||
rnd: rnd,
|
||||
iterations: iterations,
|
||||
id: i
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -326,7 +121,7 @@ function prime (bitLength, iterations = 16) {
|
|||
* @returns {bigint} A bigint probable prime of bitLength bits.
|
||||
*/
|
||||
function primeSync (bitLength, iterations = 16) {
|
||||
if (bitLength < 1) throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
|
||||
if (bitLength < 1) throw new RangeError('bitLength MUST be > 0')
|
||||
let rnd = 0n
|
||||
do {
|
||||
rnd = fromBuffer(randBitsSync(bitLength, true))
|
||||
|
@ -335,14 +130,14 @@ function primeSync (bitLength, iterations = 16) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a cryptographically secure random integer between [min,max]
|
||||
* Returns a cryptographically secure random integer between [min,max]. Both numbers must be >=0
|
||||
* @param {bigint} max Returned value will be <= max
|
||||
* @param {bigint} [min = BigInt(1)] Returned value will be >= min
|
||||
*
|
||||
* @returns {bigint} A cryptographically secure random bigint between [min,max]
|
||||
*/
|
||||
function randBetween (max, min = 1n) {
|
||||
if (max <= min) throw new Error('max must be > min')
|
||||
if (max <= 0n || min < 0n || max <= min) throw new Error('inputs should be max > 0, min >= 0; max > min')
|
||||
const interval = max - min
|
||||
const bitLen = bitLength(interval)
|
||||
let rnd
|
||||
|
@ -356,8 +151,6 @@ function randBetween (max, min = 1n) {
|
|||
/**
|
||||
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
*
|
||||
* Since version 3.0.0 this is an async function and a new randBitsSync function has been added. If you are migrating from version 2 call randBitsSync instead.
|
||||
* @since 3.0.0
|
||||
* @param {number} bitLength The desired number of random bits
|
||||
* @param {boolean} [forceLength = false] If we want to force the output to have a specific bit length. It basically forces the msb to be 1
|
||||
*
|
||||
|
@ -365,7 +158,7 @@ function randBetween (max, min = 1n) {
|
|||
*/
|
||||
async function randBits (bitLength, forceLength = false) {
|
||||
if (bitLength < 1) {
|
||||
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
|
||||
throw new RangeError('bitLength MUST be > 0')
|
||||
}
|
||||
|
||||
const byteLength = Math.ceil(bitLength / 8)
|
||||
|
@ -385,7 +178,6 @@ async function randBits (bitLength, forceLength = false) {
|
|||
|
||||
/**
|
||||
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
* @since 3.0.0
|
||||
* @param {number} bitLength The desired number of random bits
|
||||
* @param {boolean} [forceLength = false] If we want to force the output to have a specific bit length. It basically forces the msb to be 1
|
||||
*
|
||||
|
@ -393,7 +185,7 @@ async function randBits (bitLength, forceLength = false) {
|
|||
*/
|
||||
function randBitsSync (bitLength, forceLength = false) {
|
||||
if (bitLength < 1) {
|
||||
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
|
||||
throw new RangeError('bitLength MUST be > 0')
|
||||
}
|
||||
|
||||
const byteLength = Math.ceil(bitLength / 8)
|
||||
|
@ -411,7 +203,7 @@ function randBitsSync (bitLength, forceLength = false) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
* Secure random bytes for both node and browsers. Node version uses crypto.randomBytes() and browser one self.crypto.getRandomValues()
|
||||
*
|
||||
* @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
|
||||
|
@ -419,19 +211,19 @@ function randBitsSync (bitLength, forceLength = false) {
|
|||
* @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}`) }
|
||||
if (byteLength < 1) throw new RangeError('byteLength MUST be > 0')
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
/* eslint-disable no-lone-blocks */
|
||||
{ // browser
|
||||
return new Promise(function (resolve) {
|
||||
const buf = new Uint8Array(byteLength)
|
||||
self.crypto.getRandomValues(buf)
|
||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
||||
if (forceLength) buf[0] = buf[0] | 128
|
||||
resolve(buf)
|
||||
})
|
||||
}
|
||||
/* eslint-enable no-lone-blocks */
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -443,14 +235,14 @@ function randBytes (byteLength, forceLength = false) {
|
|||
* @returns {Buffer | Uint8Array} A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
||||
*/
|
||||
function randBytesSync (byteLength, forceLength = false) {
|
||||
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
|
||||
if (byteLength < 1) throw new RangeError('byteLength MUST be > 0')
|
||||
|
||||
/* eslint-disable no-lone-blocks */
|
||||
{ // browser
|
||||
const buf = new Uint8Array(byteLength)
|
||||
self.crypto.getRandomValues(buf)
|
||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
||||
if (forceLength) { buf[0] = buf[0] | 128 }
|
||||
if (forceLength) buf[0] = buf[0] | 128
|
||||
return buf
|
||||
}
|
||||
/* eslint-enable no-lone-blocks */
|
||||
|
@ -814,4 +606,4 @@ let _useWorkers = false // The following is just to check whether we can use wor
|
|||
if (self.Worker) _useWorkers = true
|
||||
}
|
||||
|
||||
export { abs, bitLength, eGcd, gcd, isProbablyPrime, lcm, max, min, modInv, modPow, prime, primeSync, randBetween, randBits, randBitsSync, randBytes, randBytesSync, toZn }
|
||||
export { isProbablyPrime, prime, primeSync, randBetween, randBits, randBitsSync, randBytes, randBytesSync }
|
||||
|
|
|
@ -1,217 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true })
|
||||
|
||||
/**
|
||||
* 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 >= 0n) ? 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 === 1n) { return 1 }
|
||||
let bits = 1
|
||||
do {
|
||||
bits++
|
||||
} while ((a >>= 1n) > 1n)
|
||||
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 <= 0n | b <= 0n) { return NaN } // a and b MUST be positive
|
||||
|
||||
let x = 0n
|
||||
let y = 1n
|
||||
let u = 1n
|
||||
let v = 0n
|
||||
|
||||
while (a !== 0n) {
|
||||
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 === 0n) { return b } else if (b === 0n) { return a }
|
||||
|
||||
let shift = 0n
|
||||
while (!((a | b) & 1n)) {
|
||||
a >>= 1n
|
||||
b >>= 1n
|
||||
shift++
|
||||
}
|
||||
while (!(a & 1n)) a >>= 1n
|
||||
do {
|
||||
while (!(b & 1n)) b >>= 1n
|
||||
if (a > b) {
|
||||
const x = a
|
||||
a = b
|
||||
b = x
|
||||
}
|
||||
b -= a
|
||||
} while (b)
|
||||
|
||||
// rescale
|
||||
return a << shift
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 === 0n && b === 0n) { return 0n }
|
||||
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 !== 1n) {
|
||||
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 === 0n) { return NaN } else if (n === 1n) { return 0n }
|
||||
|
||||
b = toZn(b, n)
|
||||
|
||||
e = BigInt(e)
|
||||
if (e < 0n) {
|
||||
return modInv(modPow(b, abs(e), n), n)
|
||||
}
|
||||
|
||||
let r = 1n
|
||||
while (e > 0) {
|
||||
if ((e % 2n) === 1n) {
|
||||
r = (r * b) % n
|
||||
}
|
||||
e = e / 2n
|
||||
b = b ** 2n % n
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
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
|
||||
|
@ -219,16 +8,18 @@ function toZn (a, n) {
|
|||
*
|
||||
* @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
|
||||
* @param {boolean} [disableWorkers = false] Disable the use of workers for the primality test
|
||||
*
|
||||
* @returns {Promise<boolean>} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
|
||||
*/
|
||||
function isProbablyPrime (w, iterations = 16) {
|
||||
function isProbablyPrime (w, iterations = 16, disableWorkers = false) {
|
||||
if (typeof w === 'number') {
|
||||
w = BigInt(w)
|
||||
}
|
||||
/* eslint-disable no-lone-blocks */
|
||||
{ // Node.js
|
||||
if (_useWorkers) {
|
||||
/* istanbul ignore else */
|
||||
if (!disableWorkers && _useWorkers) {
|
||||
const { Worker } = require('worker_threads')
|
||||
return new Promise((resolve, reject) => {
|
||||
const worker = new Worker(__filename)
|
||||
|
@ -244,7 +35,6 @@ function isProbablyPrime (w, iterations = 16) {
|
|||
rnd: w,
|
||||
iterations: iterations,
|
||||
id: 0
|
||||
|
||||
})
|
||||
})
|
||||
} else {
|
||||
|
@ -269,8 +59,9 @@ function isProbablyPrime (w, iterations = 16) {
|
|||
* @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 (bitLength < 1) throw new RangeError('bitLength MUST be > 0')
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (!_useWorkers) { // If there is no support for workers
|
||||
let rnd = 0n
|
||||
do {
|
||||
|
@ -316,13 +107,14 @@ function prime (bitLength, iterations = 16) {
|
|||
}
|
||||
/* eslint-enable no-lone-blocks */
|
||||
for (let i = 0; i < workerList.length; i++) {
|
||||
const buf = randBitsSync(bitLength, true)
|
||||
randBits(bitLength, true).then(function (buf) {
|
||||
const rnd = fromBuffer(buf)
|
||||
workerList[i].postMessage({
|
||||
rnd: rnd,
|
||||
iterations: iterations,
|
||||
id: i
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -337,7 +129,7 @@ function prime (bitLength, iterations = 16) {
|
|||
* @returns {bigint} A bigint probable prime of bitLength bits.
|
||||
*/
|
||||
function primeSync (bitLength, iterations = 16) {
|
||||
if (bitLength < 1) throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
|
||||
if (bitLength < 1) throw new RangeError('bitLength MUST be > 0')
|
||||
let rnd = 0n
|
||||
do {
|
||||
rnd = fromBuffer(randBitsSync(bitLength, true))
|
||||
|
@ -346,16 +138,16 @@ function primeSync (bitLength, iterations = 16) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a cryptographically secure random integer between [min,max]
|
||||
* Returns a cryptographically secure random integer between [min,max]. Both numbers must be >=0
|
||||
* @param {bigint} max Returned value will be <= max
|
||||
* @param {bigint} [min = BigInt(1)] Returned value will be >= min
|
||||
*
|
||||
* @returns {bigint} A cryptographically secure random bigint between [min,max]
|
||||
*/
|
||||
function randBetween (max, min = 1n) {
|
||||
if (max <= min) throw new Error('max must be > min')
|
||||
if (max <= 0n || min < 0n || max <= min) throw new Error('inputs should be max > 0, min >= 0; max > min')
|
||||
const interval = max - min
|
||||
const bitLen = bitLength(interval)
|
||||
const bitLen = bigintModArith.bitLength(interval)
|
||||
let rnd
|
||||
do {
|
||||
const buf = randBitsSync(bitLen)
|
||||
|
@ -367,8 +159,6 @@ function randBetween (max, min = 1n) {
|
|||
/**
|
||||
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
*
|
||||
* Since version 3.0.0 this is an async function and a new randBitsSync function has been added. If you are migrating from version 2 call randBitsSync instead.
|
||||
* @since 3.0.0
|
||||
* @param {number} bitLength The desired number of random bits
|
||||
* @param {boolean} [forceLength = false] If we want to force the output to have a specific bit length. It basically forces the msb to be 1
|
||||
*
|
||||
|
@ -376,7 +166,7 @@ function randBetween (max, min = 1n) {
|
|||
*/
|
||||
async function randBits (bitLength, forceLength = false) {
|
||||
if (bitLength < 1) {
|
||||
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
|
||||
throw new RangeError('bitLength MUST be > 0')
|
||||
}
|
||||
|
||||
const byteLength = Math.ceil(bitLength / 8)
|
||||
|
@ -396,7 +186,6 @@ async function randBits (bitLength, forceLength = false) {
|
|||
|
||||
/**
|
||||
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
* @since 3.0.0
|
||||
* @param {number} bitLength The desired number of random bits
|
||||
* @param {boolean} [forceLength = false] If we want to force the output to have a specific bit length. It basically forces the msb to be 1
|
||||
*
|
||||
|
@ -404,7 +193,7 @@ async function randBits (bitLength, forceLength = false) {
|
|||
*/
|
||||
function randBitsSync (bitLength, forceLength = false) {
|
||||
if (bitLength < 1) {
|
||||
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
|
||||
throw new RangeError('bitLength MUST be > 0')
|
||||
}
|
||||
|
||||
const byteLength = Math.ceil(bitLength / 8)
|
||||
|
@ -422,7 +211,7 @@ function randBitsSync (bitLength, forceLength = false) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
* Secure random bytes for both node and browsers. Node version uses crypto.randomBytes() and browser one self.crypto.getRandomValues()
|
||||
*
|
||||
* @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
|
||||
|
@ -430,19 +219,22 @@ function randBitsSync (bitLength, forceLength = false) {
|
|||
* @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}`) }
|
||||
if (byteLength < 1) throw new RangeError('byteLength MUST be > 0')
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
/* eslint-disable no-lone-blocks */
|
||||
{ // node
|
||||
{
|
||||
const crypto = require('crypto')
|
||||
const buf = Buffer.alloc(byteLength)
|
||||
return crypto.randomFill(buf, function (resolve) {
|
||||
crypto.randomBytes(byteLength, function (err, buf) {
|
||||
/* istanbul ignore if */
|
||||
if (err) reject(err)
|
||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
||||
if (forceLength) buf[0] = buf[0] | 128
|
||||
resolve(buf)
|
||||
})
|
||||
}
|
||||
/* eslint-enable no-lone-blocks */
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -454,15 +246,14 @@ function randBytes (byteLength, forceLength = false) {
|
|||
* @returns {Buffer | Uint8Array} A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
||||
*/
|
||||
function randBytesSync (byteLength, forceLength = false) {
|
||||
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
|
||||
if (byteLength < 1) throw new RangeError('byteLength MUST be > 0')
|
||||
|
||||
/* eslint-disable no-lone-blocks */
|
||||
{ // node
|
||||
const crypto = require('crypto')
|
||||
const buf = Buffer.alloc(byteLength)
|
||||
crypto.randomFillSync(buf)
|
||||
const buf = crypto.randomBytes(byteLength)
|
||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
||||
if (forceLength) { buf[0] = buf[0] | 128 }
|
||||
if (forceLength) buf[0] = buf[0] | 128
|
||||
return buf
|
||||
}
|
||||
/* eslint-enable no-lone-blocks */
|
||||
|
@ -780,11 +571,11 @@ function _isProbablyPrime (w, iterations = 16) {
|
|||
|
||||
do {
|
||||
const b = randBetween(d, 2n)
|
||||
let z = modPow(b, m, w)
|
||||
let z = bigintModArith.modPow(b, m, w)
|
||||
if (z === 1n || z === d) continue
|
||||
let j = 1
|
||||
while (j < a) {
|
||||
z = modPow(z, 2n, w)
|
||||
z = bigintModArith.modPow(z, 2n, w)
|
||||
if (z === d) break
|
||||
if (z === 1n) return false
|
||||
j++
|
||||
|
@ -802,10 +593,12 @@ let _useWorkers = false // The following is just to check whether we can use wor
|
|||
require.resolve('worker_threads')
|
||||
_useWorkers = true
|
||||
} catch (e) {
|
||||
/* istanbul ignore next */
|
||||
console.log(`[bigint-crypto-utils] WARNING:
|
||||
This node version doesn't support worker_threads. You should enable them in order to greatly speedup the generation of big prime numbers.
|
||||
· With Node >=11 it is enabled by default (consider upgrading).
|
||||
· With Node 10, starting with 10.5.0, you can enable worker_threads at runtime executing node --experimental-worker `)
|
||||
/* istanbul ignore next */
|
||||
_useWorkers = true
|
||||
}
|
||||
}
|
||||
|
@ -813,6 +606,7 @@ This node version doesn't support worker_threads. You should enable them in orde
|
|||
|
||||
if (_useWorkers) { // node.js with support for workers
|
||||
const { parentPort, isMainThread } = require('worker_threads')
|
||||
/* istanbul ignore if */
|
||||
if (!isMainThread) { // worker
|
||||
parentPort.on('message', function (data) { // Let's start once we are called
|
||||
// data = {rnd: <bigint>, iterations: <number>}
|
||||
|
@ -826,16 +620,17 @@ if (_useWorkers) { // node.js with support for workers
|
|||
}
|
||||
}
|
||||
|
||||
exports.abs = abs
|
||||
exports.bitLength = bitLength
|
||||
exports.eGcd = eGcd
|
||||
exports.gcd = gcd
|
||||
exports.abs = bigintModArith.abs
|
||||
exports.bitLength = bigintModArith.bitLength
|
||||
exports.eGcd = bigintModArith.eGcd
|
||||
exports.gcd = bigintModArith.gcd
|
||||
exports.lcm = bigintModArith.lcm
|
||||
exports.max = bigintModArith.max
|
||||
exports.min = bigintModArith.min
|
||||
exports.modInv = bigintModArith.modInv
|
||||
exports.modPow = bigintModArith.modPow
|
||||
exports.toZn = 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
|
||||
|
@ -843,4 +638,3 @@ exports.randBits = randBits
|
|||
exports.randBitsSync = randBitsSync
|
||||
exports.randBytes = randBytes
|
||||
exports.randBytesSync = randBytesSync
|
||||
exports.toZn = toZn
|
||||
|
|
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "bigint-crypto-utils",
|
||||
"version": "3.0.1",
|
||||
"description": "Utils for working with cryptography using native JS implementation of BigInt. It includes arbitrary precision modular arithmetic, cryptographically secure random numbers and strong probable prime generation/testing.",
|
||||
"description": "Arbitrary precision modular arithmetic, cryptographically secure random numbers and strong probable prime generation/testing. It relies on the native JS implementation of BigInt and therefore it works in modern browsers, Angular, React, Node.js, etc.",
|
||||
"keywords": [
|
||||
"modular arithmetics",
|
||||
"crypto",
|
||||
|
@ -10,7 +10,9 @@
|
|||
"rng",
|
||||
"prng",
|
||||
"primality test",
|
||||
"BigInt"
|
||||
"BigInt",
|
||||
"angular",
|
||||
"react"
|
||||
],
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
|
@ -29,15 +31,20 @@
|
|||
"test": "./test",
|
||||
"types": "./types"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.4.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha",
|
||||
"test": "nyc --check-coverage mocha",
|
||||
"coverage": "nyc report --reporter=lcov",
|
||||
"build:js": "rollup -c build/rollup.config.js",
|
||||
"build:standard": "standard --fix",
|
||||
"build:browserTests": "rollup -c build/rollup.tests.config.js",
|
||||
"build:docs": "node build/build.docs.js",
|
||||
"build:dts": "node build/build.dts.js",
|
||||
"build": "run-s build:**",
|
||||
"prepublishOnly": "npm run build"
|
||||
"preversion": "npm run build && npm run test",
|
||||
"postversion": "git push"
|
||||
},
|
||||
"standard": {
|
||||
"env": [
|
||||
|
@ -57,21 +64,22 @@
|
|||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^11.0.2",
|
||||
"@rollup/plugin-commonjs": "^11.1.0",
|
||||
"@rollup/plugin-multi-entry": "^3.0.0",
|
||||
"@rollup/plugin-node-resolve": "^7.1.1",
|
||||
"@rollup/plugin-replace": "^2.3.1",
|
||||
"bigint-mod-arith": "^2.0.4",
|
||||
"@rollup/plugin-node-resolve": "^7.1.3",
|
||||
"@rollup/plugin-replace": "^2.3.2",
|
||||
"chai": "^4.2.0",
|
||||
"jsdoc-to-markdown": "^5.0.3",
|
||||
"mocha": "^7.1.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"rollup": "^2.3.4",
|
||||
"nyc": "^15.0.1",
|
||||
"rollup": "^2.6.1",
|
||||
"rollup-plugin-terser": "^5.3.0",
|
||||
"standard": "^14.3.3",
|
||||
"typescript": "^3.8.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": ">=10"
|
||||
"@types/node": ">=10.4.0",
|
||||
"bigint-mod-arith": "^2.0.7"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,28 @@
|
|||
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
|
||||
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
|
||||
{{GITHUB_ACTIONS_BADGES}}
|
||||
|
||||
# bigint-crypto-utils
|
||||
# {{PKG_NAME}}
|
||||
|
||||
Utils for working with cryptography using native JS ([ES-2020](https://tc39.es/ecma262/#sec-bigint-objects)) implementation of BigInt. It includes some extra functions to work with modular arithmetic along with secure random numbers and a fast strong probable prime generator/tester (parallelized multi-threaded Miller-Rabin primality tests if workers are supported). It can be used by any [Web Browser or webview supporting BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) and with Node.js (>=10.4.0).
|
||||
Arbitrary precision modular arithmetic, cryptographically secure random numbers and strong probable prime generation/testing.
|
||||
|
||||
It relies on the native JS implementation of ([BigInt](https://tc39.es/ecma262/#sec-bigint-objects)). It can be used by any [Web Browser or webview supporting BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) and with Node.js (>=10.4.0). The bundles can be imported directly by the browser or in Angular projects, React apps, Node.js, etc.
|
||||
|
||||
Secure random numbers are generated using the native crypto implementation of the browsers ([Web Cryptography API](https://w3c.github.io/webcrypto/)) or [Node.js Crypto](https://nodejs.org/dist/latest/docs/api/crypto.html)). Strong probable prime generation and testing use Miller-Rabin primality tests and are automatically sped up using parallel workers both in browsers and Node.js.
|
||||
|
||||
> The operations supported on BigInts are not constant time. BigInt can be therefore **[unsuitable for use in cryptography](https://www.chosenplaintext.ca/articles/beginners-guide-constant-time-cryptography.html).** Many platforms provide native support for cryptography, such as [Web Cryptography API](https://w3c.github.io/webcrypto/) or [Node.js Crypto](https://nodejs.org/dist/latest/docs/api/crypto.html).
|
||||
|
||||
## Installation
|
||||
|
||||
bigint-crypto-utils is distributed for [web browsers and/or webviews supporting BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) as an ES6 module or an IIFE file; and for Node.js (>=10.4.0), as a CJS module.
|
||||
{{PKG_NAME}} is distributed for [web browsers and/or webviews supporting BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) as an ES6 module or an IIFE file; and for Node.js (>=10.4.0), as a CJS module.
|
||||
|
||||
bigint-crypto-utils can be imported to your project with `npm`:
|
||||
{{PKG_NAME}} can be imported to your project with `npm`:
|
||||
|
||||
```bash
|
||||
npm install bigint-crypto-utils
|
||||
npm install {{PKG_NAME}}
|
||||
```
|
||||
|
||||
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 bundle](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.iife.js) or the [ES6 bundle module](https://raw.githubusercontent.com/juanelas/bigint-crypto-utils/master/lib/index.browser.bundle.mod.js) from GitHub.
|
||||
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_BUNDLE}} or the {{ESM_BUNDLE}} from the repository.
|
||||
|
||||
## Usage examples
|
||||
|
||||
|
@ -29,13 +33,30 @@ Import your module as :
|
|||
const bigintCryptoUtils = require('bigint-crypto-utils')
|
||||
... // your code here
|
||||
```
|
||||
- JavaScript native or TypeScript project
|
||||
- JavaScript native or TypeScript project (including React and Angular JS)
|
||||
```javascript
|
||||
import * as bigintCryptoUtils from 'bigint-crypto-utils'
|
||||
... // your code here
|
||||
```
|
||||
> 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`.
|
||||
- JavaScript native browser ES6 mod
|
||||
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`.
|
||||
`{{PKG_NAME}}` **CANNOT BE POLYFILLED** to suport older browsers. If you are using webpack/babel to create your production bundles, you should target only the most modern browsers. For instance, for **React** apps created with [`create-react-app`](https://create-react-app.dev/), you should edit your `package.json` and modify the `browserList` so that it only targets the latest browsers (supporting the latest features):
|
||||
```json
|
||||
"browserslist": {
|
||||
"production": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
```
|
||||
Also, notice that 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`.
|
||||
|
||||
- JavaScript native browser ES module
|
||||
```html
|
||||
<script type="module">
|
||||
import * as bigintCryptoUtils from 'lib/index.browser.bundle.mod.js' // Use you actual path to the broser mod bundle
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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'
|
||||
/* istanbul ignore next */
|
||||
export { abs, bitLength, eGcd, gcd, lcm, max, min, modInv, modPow, toZn } from 'bigint-mod-arith' // already tested for coverage
|
||||
|
||||
/**
|
||||
* The test first tries if any of the first 250 small primes are a factor of the input number and then passes several
|
||||
|
@ -7,16 +8,18 @@ export { abs, bitLength, eGcd, gcd, lcm, max, min, modInv, modPow, toZn } from '
|
|||
*
|
||||
* @param {number | bigint} w An integer to be tested for primality
|
||||
* @param {number} [iterations = 16] The number of iterations for the primality test. The value shall be consistent with Table C.1, C.2 or C.3
|
||||
* @param {boolean} [disableWorkers = false] Disable the use of workers for the primality test
|
||||
*
|
||||
* @returns {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, iterations = 16) {
|
||||
export function isProbablyPrime (w, iterations = 16, disableWorkers = false) {
|
||||
if (typeof w === 'number') {
|
||||
w = BigInt(w)
|
||||
}
|
||||
/* eslint-disable no-lone-blocks */
|
||||
if (!process.browser) { // Node.js
|
||||
if (_useWorkers) {
|
||||
/* istanbul ignore else */
|
||||
if (!disableWorkers && _useWorkers) {
|
||||
const { Worker } = require('worker_threads')
|
||||
return new Promise((resolve, reject) => {
|
||||
const worker = new Worker(__filename)
|
||||
|
@ -32,7 +35,6 @@ export function isProbablyPrime (w, iterations = 16) {
|
|||
rnd: w,
|
||||
iterations: iterations,
|
||||
id: 0
|
||||
|
||||
})
|
||||
})
|
||||
} else {
|
||||
|
@ -76,8 +78,9 @@ export function isProbablyPrime (w, iterations = 16) {
|
|||
* @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 (bitLength < 1) throw new RangeError('bitLength MUST be > 0')
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (!_useWorkers) { // If there is no support for workers
|
||||
let rnd = 0n
|
||||
do {
|
||||
|
@ -130,13 +133,14 @@ export function prime (bitLength, iterations = 16) {
|
|||
}
|
||||
/* eslint-enable no-lone-blocks */
|
||||
for (let i = 0; i < workerList.length; i++) {
|
||||
const buf = randBitsSync(bitLength, true)
|
||||
randBits(bitLength, true).then(function (buf) {
|
||||
const rnd = fromBuffer(buf)
|
||||
workerList[i].postMessage({
|
||||
rnd: rnd,
|
||||
iterations: iterations,
|
||||
id: i
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -151,7 +155,7 @@ export function prime (bitLength, iterations = 16) {
|
|||
* @returns {bigint} A bigint probable prime of bitLength bits.
|
||||
*/
|
||||
export function primeSync (bitLength, iterations = 16) {
|
||||
if (bitLength < 1) throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
|
||||
if (bitLength < 1) throw new RangeError('bitLength MUST be > 0')
|
||||
let rnd = 0n
|
||||
do {
|
||||
rnd = fromBuffer(randBitsSync(bitLength, true))
|
||||
|
@ -160,14 +164,14 @@ export function primeSync (bitLength, iterations = 16) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a cryptographically secure random integer between [min,max]
|
||||
* Returns a cryptographically secure random integer between [min,max]. Both numbers must be >=0
|
||||
* @param {bigint} max Returned value will be <= max
|
||||
* @param {bigint} [min = BigInt(1)] Returned value will be >= min
|
||||
*
|
||||
* @returns {bigint} A cryptographically secure random bigint between [min,max]
|
||||
*/
|
||||
export function randBetween (max, min = 1n) {
|
||||
if (max <= min) throw new Error('max must be > min')
|
||||
if (max <= 0n || min < 0n || max <= min) throw new Error('inputs should be max > 0, min >= 0; max > min')
|
||||
const interval = max - min
|
||||
const bitLen = bitLength(interval)
|
||||
let rnd
|
||||
|
@ -181,8 +185,6 @@ export function randBetween (max, min = 1n) {
|
|||
/**
|
||||
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
*
|
||||
* Since version 3.0.0 this is an async function and a new randBitsSync function has been added. If you are migrating from version 2 call randBitsSync instead.
|
||||
* @since 3.0.0
|
||||
* @param {number} bitLength The desired number of random bits
|
||||
* @param {boolean} [forceLength = false] If we want to force the output to have a specific bit length. It basically forces the msb to be 1
|
||||
*
|
||||
|
@ -190,7 +192,7 @@ export function randBetween (max, min = 1n) {
|
|||
*/
|
||||
export async function randBits (bitLength, forceLength = false) {
|
||||
if (bitLength < 1) {
|
||||
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
|
||||
throw new RangeError('bitLength MUST be > 0')
|
||||
}
|
||||
|
||||
const byteLength = Math.ceil(bitLength / 8)
|
||||
|
@ -210,7 +212,6 @@ export async function randBits (bitLength, forceLength = false) {
|
|||
|
||||
/**
|
||||
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
* @since 3.0.0
|
||||
* @param {number} bitLength The desired number of random bits
|
||||
* @param {boolean} [forceLength = false] If we want to force the output to have a specific bit length. It basically forces the msb to be 1
|
||||
*
|
||||
|
@ -218,7 +219,7 @@ export async function randBits (bitLength, forceLength = false) {
|
|||
*/
|
||||
export function randBitsSync (bitLength, forceLength = false) {
|
||||
if (bitLength < 1) {
|
||||
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`)
|
||||
throw new RangeError('bitLength MUST be > 0')
|
||||
}
|
||||
|
||||
const byteLength = Math.ceil(bitLength / 8)
|
||||
|
@ -236,7 +237,7 @@ export function randBitsSync (bitLength, forceLength = false) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
* Secure random bytes for both node and browsers. Node version uses crypto.randomBytes() and browser one self.crypto.getRandomValues()
|
||||
*
|
||||
* @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
|
||||
|
@ -244,27 +245,28 @@ export function randBitsSync (bitLength, forceLength = false) {
|
|||
* @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}`) }
|
||||
if (byteLength < 1) throw new RangeError('byteLength MUST be > 0')
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
/* eslint-disable no-lone-blocks */
|
||||
if (!process.browser) { // node
|
||||
if (!process.browser) {
|
||||
const crypto = require('crypto')
|
||||
const buf = Buffer.alloc(byteLength)
|
||||
return crypto.randomFill(buf, function (resolve) {
|
||||
crypto.randomBytes(byteLength, function (err, buf) {
|
||||
/* istanbul ignore if */
|
||||
if (err) reject(err)
|
||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
||||
if (forceLength) buf[0] = buf[0] | 128
|
||||
resolve(buf)
|
||||
})
|
||||
} else { // browser
|
||||
return new Promise(function (resolve) {
|
||||
const buf = new Uint8Array(byteLength)
|
||||
self.crypto.getRandomValues(buf)
|
||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
||||
if (forceLength) buf[0] = buf[0] | 128
|
||||
resolve(buf)
|
||||
})
|
||||
}
|
||||
/* eslint-enable no-lone-blocks */
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -276,21 +278,20 @@ export function randBytes (byteLength, forceLength = false) {
|
|||
* @returns {Buffer | Uint8Array} A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
||||
*/
|
||||
export function randBytesSync (byteLength, forceLength = false) {
|
||||
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
|
||||
if (byteLength < 1) throw new RangeError('byteLength MUST be > 0')
|
||||
|
||||
/* eslint-disable no-lone-blocks */
|
||||
if (!process.browser) { // node
|
||||
const crypto = require('crypto')
|
||||
const buf = Buffer.alloc(byteLength)
|
||||
crypto.randomFillSync(buf)
|
||||
const buf = crypto.randomBytes(byteLength)
|
||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
||||
if (forceLength) { buf[0] = buf[0] | 128 }
|
||||
if (forceLength) buf[0] = buf[0] | 128
|
||||
return buf
|
||||
} else { // browser
|
||||
const buf = new Uint8Array(byteLength)
|
||||
self.crypto.getRandomValues(buf)
|
||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
||||
if (forceLength) { buf[0] = buf[0] | 128 }
|
||||
if (forceLength) buf[0] = buf[0] | 128
|
||||
return buf
|
||||
}
|
||||
/* eslint-enable no-lone-blocks */
|
||||
|
@ -655,10 +656,12 @@ if (!process.browser) { // Node.js
|
|||
require.resolve('worker_threads')
|
||||
_useWorkers = true
|
||||
} catch (e) {
|
||||
/* istanbul ignore next */
|
||||
console.log(`[bigint-crypto-utils] WARNING:
|
||||
This node version doesn't support worker_threads. You should enable them in order to greatly speedup the generation of big prime numbers.
|
||||
· With Node >=11 it is enabled by default (consider upgrading).
|
||||
· With Node 10, starting with 10.5.0, you can enable worker_threads at runtime executing node --experimental-worker `)
|
||||
/* istanbul ignore next */
|
||||
_useWorkers = true
|
||||
}
|
||||
} else { // Native JS
|
||||
|
@ -668,6 +671,7 @@ This node version doesn't support worker_threads. You should enable them in orde
|
|||
|
||||
if (!process.browser && _useWorkers) { // node.js with support for workers
|
||||
const { parentPort, isMainThread } = require('worker_threads')
|
||||
/* istanbul ignore if */
|
||||
if (!isMainThread) { // worker
|
||||
parentPort.on('message', function (data) { // Let's start once we are called
|
||||
// data = {rnd: <bigint>, iterations: <number>}
|
||||
|
|
|
@ -7,60 +7,86 @@
|
|||
const numbers = [
|
||||
{
|
||||
value: BigInt(1),
|
||||
prime: false
|
||||
prime: false,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt(2),
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt(15),
|
||||
prime: false
|
||||
prime: false,
|
||||
iterations: 32,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: 29,
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt('669483106578092405936560831017556154622901950048903016651289'),
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 24,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt('2074722246773485207821695222107608587480996474721117292752992589912196684750549658310084416732550077'),
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt('2074722246773485207821695222107608587480996474721117292752992589912196684750549658310084416732550079'),
|
||||
prime: false
|
||||
prime: false,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt('115922179551495973383410176342643722334557255682879605864838806293659619625004303206250384392546855063844106965156287951749387634112551089284595541103692716528774876311641700929986988023197242224581099872580798960693521778607396791006450968430359009613295725905514216842343121690916290236558767890728449777'),
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 24,
|
||||
workers: true
|
||||
},
|
||||
{
|
||||
value: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109') * BigInt('144678545212641449725111562354371812236197961234111744040227045242578772124779004756249085154188369039159690638725821245974978963371615699005072473649705367893567309027634121825164880046600125480885803891136149601797439273507802533807541605261215613891134865916295914192271736572001975016089773532547481638243'),
|
||||
prime: false
|
||||
prime: false,
|
||||
iterations: 16,
|
||||
workers: true
|
||||
},
|
||||
{
|
||||
value: BigInt('918145944120889203205646923554374144932845997937845799234617798611046542304088105084854788397071323714642587188481158334265864050544813693415594035822877094557870151480865568334936301231664228940480803192289508235412296324312748621874408067955753620604885023289655277704554716080844406284392300643321715285709865081125252390440327650852470312931679380011885102491340191287595160450544053114365852338670819405357496612993587404998677760882578064637552397840566752638770525765833183986360029736508910848408875329873614164495552615086579144675027852136994842529623698055210822311666048300438808691619782893307972452223713060928388502843564836966586109748062827799521852219158489504529458627699284110902303538160168376473182639384638674469114371472053977558648090155686345760457454061117853710619580819749222459422610617170567016772342291486643520567969321969827786373531753524990712622940069883277763528926899970596407140603912036918433859986491820017690762751824769335720368488097262208835708414085501930989486498185503469986946236128468697606998536541209764920494156326791142098506801288127033229779646920082892258428128572765585196779698362187479280520327053508580551167899837393726371144977951402741307021389967382422805567365901203'),
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: true
|
||||
},
|
||||
{
|
||||
value: BigInt('940719693126280825126763871881743336375040232953039527942717290104060740215493004508206768342926022549956464101136893240409560470269654765366248516968645294076406953865805712688760371102637642013723011744011617678651884521901163090779813242269935310225049805992299292275574585773507915278612311449919050091057023179541184986547995894821648553256021675133997240195429424258757033557367142630663053464438840832073753440939208165158795269598771598124509831433327480118038278887538430675994497384283550890544882369140852048496460551123626856255619494025370171790720106325655890348475483349150258338517508459674722099347335608814922179633411167540545786247819334838979610017735984374883325689517847175539632896026875016305529321705457954181425405794479825617747354596485074451489940385640535898876551301296003465792117006135339109817937663957519031436646579178503423889430062127572272773511424424297800355292430651838502733756881154935252456036638082486459287411002911323257940893413982671660332662880068976408321968046549017547143836993553556640198884769590214676797037397502067035957959952990027503148987727895561468097917730167320715053689862847457761993196945361244822787209076446259359976421264285658106819879849052247546957718175231'),
|
||||
prime: false
|
||||
prime: false,
|
||||
iterations: 16,
|
||||
workers: true
|
||||
}
|
||||
];
|
||||
|
||||
describe('isProbablyPrime', function () {
|
||||
this.timeout(90000);
|
||||
for (const num of numbers) {
|
||||
describe(`isProbablyPrime(${num.value})`, function () {
|
||||
describe(`isProbablyPrime(${num.value}, ${num.iterations}, ${!num.workers})`, function () {
|
||||
it(`should return ${num.prime}`, async function () {
|
||||
const ret = await _pkg.isProbablyPrime(num.value);
|
||||
let ret;
|
||||
if (num.iterations === 16 && num.workers) ret = await _pkg.isProbablyPrime(num.value);
|
||||
else ret = await _pkg.isProbablyPrime(num.value, num.iterations, !num.workers);
|
||||
chai.expect(ret).to.equal(num.prime);
|
||||
});
|
||||
});
|
||||
|
@ -74,6 +100,7 @@ describe('isProbablyPrime', function () {
|
|||
// <--
|
||||
|
||||
const bitLengths = [
|
||||
0,
|
||||
8,
|
||||
255,
|
||||
256,
|
||||
|
@ -81,8 +108,7 @@ const bitLengths = [
|
|||
512,
|
||||
1024,
|
||||
2048,
|
||||
3072,
|
||||
4096
|
||||
3072
|
||||
];
|
||||
|
||||
describe('prime', function () {
|
||||
|
@ -90,8 +116,11 @@ describe('prime', function () {
|
|||
for (const bitLength of bitLengths) {
|
||||
describe(`prime(${bitLength})`, function () {
|
||||
it(`should return a random ${bitLength}-bits probable prime`, async function () {
|
||||
let primeBitLength = bitLength;
|
||||
try {
|
||||
const prime = await _pkg.prime(bitLength);
|
||||
const primeBitLength = _pkg.bitLength(prime);
|
||||
primeBitLength = _pkg.bitLength(prime);
|
||||
} catch {}
|
||||
chai.expect(primeBitLength).to.equal(bitLength);
|
||||
});
|
||||
});
|
||||
|
@ -101,6 +130,202 @@ describe('prime', function () {
|
|||
const prime = _pkg.primeSync(1024, 16);
|
||||
const primeBitLength = _pkg.bitLength(prime);
|
||||
chai.expect(primeBitLength).to.equal(1024);
|
||||
try {
|
||||
_pkg.primeSync(0);
|
||||
} catch (error) {
|
||||
chai.expect(true).to.equal(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Every test file (you can create as many as you want) should start like this
|
||||
// Please, do NOT touch. They will be automatically removed for browser tests -->
|
||||
|
||||
|
||||
// <--
|
||||
|
||||
const numbers$1 = [
|
||||
{
|
||||
min: BigInt(1),
|
||||
max: BigInt(2) ** BigInt(234),
|
||||
iterations: 100,
|
||||
error: false,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt('122461641436345153'),
|
||||
max: BigInt(2) ** BigInt(234),
|
||||
iterations: 100,
|
||||
error: false,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt(146347),
|
||||
max: BigInt(2),
|
||||
iterations: 1,
|
||||
error: true,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt(2),
|
||||
max: BigInt(2),
|
||||
iterations: 1,
|
||||
error: true,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt(-4),
|
||||
max: BigInt(2),
|
||||
iterations: 1,
|
||||
error: true,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt(1),
|
||||
max: BigInt(-1),
|
||||
iterations: 1,
|
||||
error: true,
|
||||
errorMax: true
|
||||
}
|
||||
];
|
||||
|
||||
describe('randBetween', function () {
|
||||
this.timeout(90000);
|
||||
for (const num of numbers$1) {
|
||||
describe(`randBetween(${num.max}, ${num.min})`, function () {
|
||||
if (!num.error) {
|
||||
it(`[${num.iterations} iterations] should return x such that min < x < max`, function () {
|
||||
let ret = true;
|
||||
for (let i = 0; i < num.iterations; i++) {
|
||||
const x = _pkg.randBetween(num.max, num.min);
|
||||
ret = ret && x > num.min && x < num.max;
|
||||
}
|
||||
chai.expect(ret).to.equal(true);
|
||||
});
|
||||
} else {
|
||||
it('should return error (max <=0 || min <0 || min>=max)', function () {
|
||||
try {
|
||||
_pkg.randBetween(num.max, num.min);
|
||||
chai.expect(num.error).to.equal(false);
|
||||
} catch (error) {
|
||||
chai.expect(num.error).to.equal(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
describe(`randBetween(${num.max})`, function () {
|
||||
if (!num.errorMax) {
|
||||
it(`[${num.iterations} iterations] should return x such that 1 <= x <= max`, function () {
|
||||
let ret = true;
|
||||
for (let i = 0; i < num.iterations; i++) {
|
||||
const x = _pkg.randBetween(num.max);
|
||||
ret = ret && x >= BigInt(1) && x <= num.max;
|
||||
}
|
||||
chai.expect(ret).to.equal(true);
|
||||
});
|
||||
} else {
|
||||
it('should return error (max <=0)', function () {
|
||||
try {
|
||||
_pkg.randBetween(num.max);
|
||||
chai.expect(num.errorMax).to.equal(false);
|
||||
} catch (error) {
|
||||
chai.expect(num.errorMax).to.equal(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Every test file (you can create as many as you want) should start like this
|
||||
// Please, do NOT touch. They will be automatically removed for browser tests -->
|
||||
|
||||
|
||||
// <--
|
||||
|
||||
const iterations = 10;
|
||||
const bitLengths$1 = [0, 3, 8, 16, 511, 2048];
|
||||
const byteLengths = [0, 1, 8, 33, 40];
|
||||
|
||||
describe('testing randBits', async function () {
|
||||
for (const bitLength of bitLengths$1) {
|
||||
describe(`${iterations} of randBitsSync(${bitLength})`, function () {
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
it('should return a buffer', function () {
|
||||
try {
|
||||
const randbits = _pkg.randBitsSync(bitLength);
|
||||
// console.log(JSON.stringify(randbits))
|
||||
if (randbits instanceof Uint8Array) chai.expect(randbits).to.be.an.instanceOf(Uint8Array);
|
||||
else chai.expect(randbits).to.be.an.instanceOf(Buffer);
|
||||
const randbits2 = _pkg.randBitsSync(bitLength, true);
|
||||
// console.log(JSON.stringify(randbits2))
|
||||
if (randbits2 instanceof Uint8Array) chai.expect(randbits2).to.be.an.instanceOf(Uint8Array);
|
||||
else chai.expect(randbits2).to.be.an.instanceOf(Buffer);
|
||||
} catch (error) {
|
||||
chai.expect(bitLength).to.be.lte(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
describe(`${iterations} of randBits(${bitLength})`, async function () {
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
it('should return a buffer', async function () {
|
||||
try {
|
||||
const randbits = await _pkg.randBits(bitLength);
|
||||
// console.log(JSON.stringify(randbits))
|
||||
if (randbits instanceof Uint8Array) chai.expect(randbits).to.be.an.instanceOf(Uint8Array);
|
||||
else chai.expect(randbits).to.be.an.instanceOf(Buffer);
|
||||
const randbits2 = await _pkg.randBits(bitLength, true);
|
||||
// console.log(JSON.stringify(randbits2))
|
||||
if (randbits2 instanceof Uint8Array) chai.expect(randbits2).to.be.an.instanceOf(Uint8Array);
|
||||
else chai.expect(randbits2).to.be.an.instanceOf(Buffer);
|
||||
} catch (error) {
|
||||
chai.expect(bitLength).to.be.lte(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('testing randBytes', async function () {
|
||||
for (const byteLength of byteLengths) {
|
||||
describe(`${iterations} of randBytesSync(${byteLength})`, function () {
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
it('should return a buffer', function () {
|
||||
try {
|
||||
const randbits = _pkg.randBytesSync(byteLength);
|
||||
console.log(JSON.stringify(randbits));
|
||||
if (randbits instanceof Uint8Array) chai.expect(randbits).to.be.an.instanceOf(Uint8Array);
|
||||
else chai.expect(randbits).to.be.an.instanceOf(Buffer);
|
||||
const randbits2 = _pkg.randBytesSync(byteLength, true);
|
||||
console.log(JSON.stringify(randbits2));
|
||||
if (randbits2 instanceof Uint8Array) chai.expect(randbits2).to.be.an.instanceOf(Uint8Array);
|
||||
else chai.expect(randbits2).to.be.an.instanceOf(Buffer);
|
||||
} catch (error) {
|
||||
chai.expect(byteLength).to.be.lte(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
describe(`${iterations} of randBytes(${byteLength})`, async function () {
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
it('should return a buffer', async function () {
|
||||
try {
|
||||
const randbits = await _pkg.randBytes(byteLength);
|
||||
console.log(JSON.stringify(randbits));
|
||||
if (randbits instanceof Uint8Array) chai.expect(randbits).to.be.an.instanceOf(Uint8Array);
|
||||
else chai.expect(randbits).to.be.an.instanceOf(Buffer);
|
||||
const randbits2 = await _pkg.randBytes(byteLength, true);
|
||||
console.log(JSON.stringify(randbits2));
|
||||
if (randbits2 instanceof Uint8Array) chai.expect(randbits2).to.be.an.instanceOf(Uint8Array);
|
||||
else chai.expect(randbits2).to.be.an.instanceOf(Buffer);
|
||||
} catch (error) {
|
||||
chai.expect(byteLength).to.be.lte(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -9,60 +9,86 @@ const chai = require('chai')
|
|||
const numbers = [
|
||||
{
|
||||
value: BigInt(1),
|
||||
prime: false
|
||||
prime: false,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt(2),
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt(15),
|
||||
prime: false
|
||||
prime: false,
|
||||
iterations: 32,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: 29,
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt('669483106578092405936560831017556154622901950048903016651289'),
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 24,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt('2074722246773485207821695222107608587480996474721117292752992589912196684750549658310084416732550077'),
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt('2074722246773485207821695222107608587480996474721117292752992589912196684750549658310084416732550079'),
|
||||
prime: false
|
||||
prime: false,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt('115922179551495973383410176342643722334557255682879605864838806293659619625004303206250384392546855063844106965156287951749387634112551089284595541103692716528774876311641700929986988023197242224581099872580798960693521778607396791006450968430359009613295725905514216842343121690916290236558767890728449777'),
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 24,
|
||||
workers: true
|
||||
},
|
||||
{
|
||||
value: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109') * BigInt('144678545212641449725111562354371812236197961234111744040227045242578772124779004756249085154188369039159690638725821245974978963371615699005072473649705367893567309027634121825164880046600125480885803891136149601797439273507802533807541605261215613891134865916295914192271736572001975016089773532547481638243'),
|
||||
prime: false
|
||||
prime: false,
|
||||
iterations: 16,
|
||||
workers: true
|
||||
},
|
||||
{
|
||||
value: BigInt('918145944120889203205646923554374144932845997937845799234617798611046542304088105084854788397071323714642587188481158334265864050544813693415594035822877094557870151480865568334936301231664228940480803192289508235412296324312748621874408067955753620604885023289655277704554716080844406284392300643321715285709865081125252390440327650852470312931679380011885102491340191287595160450544053114365852338670819405357496612993587404998677760882578064637552397840566752638770525765833183986360029736508910848408875329873614164495552615086579144675027852136994842529623698055210822311666048300438808691619782893307972452223713060928388502843564836966586109748062827799521852219158489504529458627699284110902303538160168376473182639384638674469114371472053977558648090155686345760457454061117853710619580819749222459422610617170567016772342291486643520567969321969827786373531753524990712622940069883277763528926899970596407140603912036918433859986491820017690762751824769335720368488097262208835708414085501930989486498185503469986946236128468697606998536541209764920494156326791142098506801288127033229779646920082892258428128572765585196779698362187479280520327053508580551167899837393726371144977951402741307021389967382422805567365901203'),
|
||||
prime: true
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: true
|
||||
},
|
||||
{
|
||||
value: BigInt('940719693126280825126763871881743336375040232953039527942717290104060740215493004508206768342926022549956464101136893240409560470269654765366248516968645294076406953865805712688760371102637642013723011744011617678651884521901163090779813242269935310225049805992299292275574585773507915278612311449919050091057023179541184986547995894821648553256021675133997240195429424258757033557367142630663053464438840832073753440939208165158795269598771598124509831433327480118038278887538430675994497384283550890544882369140852048496460551123626856255619494025370171790720106325655890348475483349150258338517508459674722099347335608814922179633411167540545786247819334838979610017735984374883325689517847175539632896026875016305529321705457954181425405794479825617747354596485074451489940385640535898876551301296003465792117006135339109817937663957519031436646579178503423889430062127572272773511424424297800355292430651838502733756881154935252456036638082486459287411002911323257940893413982671660332662880068976408321968046549017547143836993553556640198884769590214676797037397502067035957959952990027503148987727895561468097917730167320715053689862847457761993196945361244822787209076446259359976421264285658106819879849052247546957718175231'),
|
||||
prime: false
|
||||
prime: false,
|
||||
iterations: 16,
|
||||
workers: true
|
||||
}
|
||||
]
|
||||
|
||||
describe('isProbablyPrime', function () {
|
||||
this.timeout(90000)
|
||||
for (const num of numbers) {
|
||||
describe(`isProbablyPrime(${num.value})`, function () {
|
||||
describe(`isProbablyPrime(${num.value}, ${num.iterations}, ${!num.workers})`, function () {
|
||||
it(`should return ${num.prime}`, async function () {
|
||||
const ret = await _pkg.isProbablyPrime(num.value)
|
||||
let ret
|
||||
if (num.iterations === 16 && num.workers) ret = await _pkg.isProbablyPrime(num.value)
|
||||
else ret = await _pkg.isProbablyPrime(num.value, num.iterations, !num.workers)
|
||||
chai.expect(ret).to.equal(num.prime)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -7,6 +7,7 @@ const chai = require('chai')
|
|||
// <--
|
||||
|
||||
const bitLengths = [
|
||||
0,
|
||||
8,
|
||||
255,
|
||||
256,
|
||||
|
@ -14,8 +15,7 @@ const bitLengths = [
|
|||
512,
|
||||
1024,
|
||||
2048,
|
||||
3072,
|
||||
4096
|
||||
3072
|
||||
]
|
||||
|
||||
describe('prime', function () {
|
||||
|
@ -23,8 +23,11 @@ describe('prime', function () {
|
|||
for (const bitLength of bitLengths) {
|
||||
describe(`prime(${bitLength})`, function () {
|
||||
it(`should return a random ${bitLength}-bits probable prime`, async function () {
|
||||
let primeBitLength = bitLength
|
||||
try {
|
||||
const prime = await _pkg.prime(bitLength)
|
||||
const primeBitLength = _pkg.bitLength(prime)
|
||||
primeBitLength = _pkg.bitLength(prime)
|
||||
} catch {}
|
||||
chai.expect(primeBitLength).to.equal(bitLength)
|
||||
})
|
||||
})
|
||||
|
@ -34,6 +37,11 @@ describe('prime', function () {
|
|||
const prime = _pkg.primeSync(1024, 16)
|
||||
const primeBitLength = _pkg.bitLength(prime)
|
||||
chai.expect(primeBitLength).to.equal(1024)
|
||||
try {
|
||||
_pkg.primeSync(0)
|
||||
} catch (error) {
|
||||
chai.expect(true).to.equal(true)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
'use strict'
|
||||
|
||||
// Every test file (you can create as many as you want) should start like this
|
||||
// Please, do NOT touch. They will be automatically removed for browser tests -->
|
||||
const _pkg = require('../lib/index.node')
|
||||
const chai = require('chai')
|
||||
// <--
|
||||
|
||||
const numbers = [
|
||||
{
|
||||
min: BigInt(1),
|
||||
max: BigInt(2) ** BigInt(234),
|
||||
iterations: 100,
|
||||
error: false,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt('122461641436345153'),
|
||||
max: BigInt(2) ** BigInt(234),
|
||||
iterations: 100,
|
||||
error: false,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt(146347),
|
||||
max: BigInt(2),
|
||||
iterations: 1,
|
||||
error: true,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt(2),
|
||||
max: BigInt(2),
|
||||
iterations: 1,
|
||||
error: true,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt(-4),
|
||||
max: BigInt(2),
|
||||
iterations: 1,
|
||||
error: true,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt(1),
|
||||
max: BigInt(-1),
|
||||
iterations: 1,
|
||||
error: true,
|
||||
errorMax: true
|
||||
}
|
||||
]
|
||||
|
||||
describe('randBetween', function () {
|
||||
this.timeout(90000)
|
||||
for (const num of numbers) {
|
||||
describe(`randBetween(${num.max}, ${num.min})`, function () {
|
||||
if (!num.error) {
|
||||
it(`[${num.iterations} iterations] should return x such that min < x < max`, function () {
|
||||
let ret = true
|
||||
for (let i = 0; i < num.iterations; i++) {
|
||||
const x = _pkg.randBetween(num.max, num.min)
|
||||
ret = ret && x > num.min && x < num.max
|
||||
}
|
||||
chai.expect(ret).to.equal(true)
|
||||
})
|
||||
} else {
|
||||
it('should return error (max <=0 || min <0 || min>=max)', function () {
|
||||
try {
|
||||
_pkg.randBetween(num.max, num.min)
|
||||
chai.expect(num.error).to.equal(false)
|
||||
} catch (error) {
|
||||
chai.expect(num.error).to.equal(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
describe(`randBetween(${num.max})`, function () {
|
||||
if (!num.errorMax) {
|
||||
it(`[${num.iterations} iterations] should return x such that 1 <= x <= max`, function () {
|
||||
let ret = true
|
||||
for (let i = 0; i < num.iterations; i++) {
|
||||
const x = _pkg.randBetween(num.max)
|
||||
ret = ret && x >= BigInt(1) && x <= num.max
|
||||
}
|
||||
chai.expect(ret).to.equal(true)
|
||||
})
|
||||
} else {
|
||||
it('should return error (max <=0)', function () {
|
||||
try {
|
||||
_pkg.randBetween(num.max)
|
||||
chai.expect(num.errorMax).to.equal(false)
|
||||
} catch (error) {
|
||||
chai.expect(num.errorMax).to.equal(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
|
@ -0,0 +1,93 @@
|
|||
'use strict'
|
||||
|
||||
// Every test file (you can create as many as you want) should start like this
|
||||
// Please, do NOT touch. They will be automatically removed for browser tests -->
|
||||
const _pkg = require('../lib/index.node')
|
||||
const chai = require('chai')
|
||||
// <--
|
||||
|
||||
const iterations = 10
|
||||
const bitLengths = [0, 3, 8, 16, 511, 2048]
|
||||
const byteLengths = [0, 1, 8, 33, 40]
|
||||
|
||||
describe('testing randBits', async function () {
|
||||
for (const bitLength of bitLengths) {
|
||||
describe(`${iterations} of randBitsSync(${bitLength})`, function () {
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
it('should return a buffer', function () {
|
||||
try {
|
||||
const randbits = _pkg.randBitsSync(bitLength)
|
||||
// console.log(JSON.stringify(randbits))
|
||||
if (randbits instanceof Uint8Array) chai.expect(randbits).to.be.an.instanceOf(Uint8Array)
|
||||
else chai.expect(randbits).to.be.an.instanceOf(Buffer)
|
||||
const randbits2 = _pkg.randBitsSync(bitLength, true)
|
||||
// console.log(JSON.stringify(randbits2))
|
||||
if (randbits2 instanceof Uint8Array) chai.expect(randbits2).to.be.an.instanceOf(Uint8Array)
|
||||
else chai.expect(randbits2).to.be.an.instanceOf(Buffer)
|
||||
} catch (error) {
|
||||
chai.expect(bitLength).to.be.lte(0)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
describe(`${iterations} of randBits(${bitLength})`, async function () {
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
it('should return a buffer', async function () {
|
||||
try {
|
||||
const randbits = await _pkg.randBits(bitLength)
|
||||
// console.log(JSON.stringify(randbits))
|
||||
if (randbits instanceof Uint8Array) chai.expect(randbits).to.be.an.instanceOf(Uint8Array)
|
||||
else chai.expect(randbits).to.be.an.instanceOf(Buffer)
|
||||
const randbits2 = await _pkg.randBits(bitLength, true)
|
||||
// console.log(JSON.stringify(randbits2))
|
||||
if (randbits2 instanceof Uint8Array) chai.expect(randbits2).to.be.an.instanceOf(Uint8Array)
|
||||
else chai.expect(randbits2).to.be.an.instanceOf(Buffer)
|
||||
} catch (error) {
|
||||
chai.expect(bitLength).to.be.lte(0)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
describe('testing randBytes', async function () {
|
||||
for (const byteLength of byteLengths) {
|
||||
describe(`${iterations} of randBytesSync(${byteLength})`, function () {
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
it('should return a buffer', function () {
|
||||
try {
|
||||
const randbits = _pkg.randBytesSync(byteLength)
|
||||
console.log(JSON.stringify(randbits))
|
||||
if (randbits instanceof Uint8Array) chai.expect(randbits).to.be.an.instanceOf(Uint8Array)
|
||||
else chai.expect(randbits).to.be.an.instanceOf(Buffer)
|
||||
const randbits2 = _pkg.randBytesSync(byteLength, true)
|
||||
console.log(JSON.stringify(randbits2))
|
||||
if (randbits2 instanceof Uint8Array) chai.expect(randbits2).to.be.an.instanceOf(Uint8Array)
|
||||
else chai.expect(randbits2).to.be.an.instanceOf(Buffer)
|
||||
} catch (error) {
|
||||
chai.expect(byteLength).to.be.lte(0)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
describe(`${iterations} of randBytes(${byteLength})`, async function () {
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
it('should return a buffer', async function () {
|
||||
try {
|
||||
const randbits = await _pkg.randBytes(byteLength)
|
||||
console.log(JSON.stringify(randbits))
|
||||
if (randbits instanceof Uint8Array) chai.expect(randbits).to.be.an.instanceOf(Uint8Array)
|
||||
else chai.expect(randbits).to.be.an.instanceOf(Buffer)
|
||||
const randbits2 = await _pkg.randBytes(byteLength, true)
|
||||
console.log(JSON.stringify(randbits2))
|
||||
if (randbits2 instanceof Uint8Array) chai.expect(randbits2).to.be.an.instanceOf(Uint8Array)
|
||||
else chai.expect(randbits2).to.be.an.instanceOf(Buffer)
|
||||
} catch (error) {
|
||||
chai.expect(byteLength).to.be.lte(0)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
|
@ -1,106 +1,14 @@
|
|||
/**
|
||||
* 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)
|
||||
*
|
||||
* @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
|
||||
* @param {boolean} [disableWorkers = false] Disable the use of workers for the primality test
|
||||
*
|
||||
* @returns {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<boolean>;
|
||||
/**
|
||||
* 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, disableWorkers?: boolean): 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
|
||||
|
@ -125,7 +33,7 @@ export function prime(bitLength: number, iterations?: number): Promise<bigint>;
|
|||
*/
|
||||
export function primeSync(bitLength: number, iterations?: number): bigint;
|
||||
/**
|
||||
* Returns a cryptographically secure random integer between [min,max]
|
||||
* Returns a cryptographically secure random integer between [min,max]. Both numbers must be >=0
|
||||
* @param {bigint} max Returned value will be <= max
|
||||
* @param {bigint} [min = BigInt(1)] Returned value will be >= min
|
||||
*
|
||||
|
@ -135,8 +43,6 @@ export function randBetween(max: bigint, min?: bigint): bigint;
|
|||
/**
|
||||
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
*
|
||||
* Since version 3.0.0 this is an async function and a new randBitsSync function has been added. If you are migrating from version 2 call randBitsSync instead.
|
||||
* @since 3.0.0
|
||||
* @param {number} bitLength The desired number of random bits
|
||||
* @param {boolean} [forceLength = false] If we want to force the output to have a specific bit length. It basically forces the msb to be 1
|
||||
*
|
||||
|
@ -145,7 +51,6 @@ export function randBetween(max: bigint, min?: bigint): bigint;
|
|||
export function randBits(bitLength: number, forceLength?: boolean): Promise<Uint8Array | Buffer>;
|
||||
/**
|
||||
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
* @since 3.0.0
|
||||
* @param {number} bitLength The desired number of random bits
|
||||
* @param {boolean} [forceLength = false] If we want to force the output to have a specific bit length. It basically forces the msb to be 1
|
||||
*
|
||||
|
@ -153,7 +58,7 @@ export function randBits(bitLength: number, forceLength?: boolean): Promise<Uint
|
|||
*/
|
||||
export function randBitsSync(bitLength: number, forceLength?: boolean): Uint8Array | Buffer;
|
||||
/**
|
||||
* Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
* Secure random bytes for both node and browsers. Node version uses crypto.randomBytes() and browser one self.crypto.getRandomValues()
|
||||
*
|
||||
* @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
|
||||
|
@ -170,11 +75,4 @@ export function randBytes(byteLength: number, forceLength?: boolean): Promise<Ui
|
|||
* @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