Examples of code. If a webview doesn't support Web Workers, they are not used
This commit is contained in:
parent
49bd34b7e9
commit
0524f41a3f
17
README.md
17
README.md
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# bigint-crypto-utils
|
# 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 test). 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). In the latter case, for multi-threaded primality tests, you should use Node.js v11 or newer or enable at runtime with `node --experimental-worker` with Node.js version >= 10.5.0 and < 11.
|
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).
|
||||||
|
|
||||||
> 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).
|
> 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).
|
||||||
|
|
||||||
|
@ -56,14 +56,14 @@ Import your module as :
|
||||||
</body>
|
</body>
|
||||||
```
|
```
|
||||||
|
|
||||||
And you could use it like in the following:
|
An example of usage could be:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
/* Stage 3 BigInts with value 666 can be declared as BigInt('666')
|
/* A BigInt with value 666 can be declared calling the bigint constructor as
|
||||||
or the shorter new no-so-linter-friendly syntax 666n.
|
BigInt('666') or with the shorter 666n.
|
||||||
Notice that you can also pass a number, e.g. BigInt(666), but it is not
|
Notice that you can also pass a number to the constructor, e.g. BigInt(666).
|
||||||
recommended since values over 2**53 - 1 won't be safe but no warning will
|
However, it is not recommended since values over 2**53 - 1 won't be safe but
|
||||||
be raised.
|
no warning will be raised.
|
||||||
*/
|
*/
|
||||||
const a = BigInt('5')
|
const a = BigInt('5')
|
||||||
const b = BigInt('2')
|
const b = BigInt('2')
|
||||||
|
@ -95,6 +95,9 @@ primeTesting()
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can find examples in the [examples folder of the repository](https://github.com/juanelas/bigint-crypto-utils/tree/master/examples).
|
||||||
|
|
||||||
|
|
||||||
## API reference documentation
|
## API reference documentation
|
||||||
|
|
||||||
### Functions
|
### Functions
|
||||||
|
|
|
@ -23,12 +23,12 @@ const dstFileName = path.join(dstDir, 'index.html')
|
||||||
const template = fs.readFileSync(templatePath, 'utf-8')
|
const template = fs.readFileSync(templatePath, 'utf-8')
|
||||||
const bundleFile = path.join(rootDir, pkgJson.directories.lib, 'index.browser.bundle.mod.js')
|
const bundleFile = path.join(rootDir, pkgJson.directories.lib, 'index.browser.bundle.mod.js')
|
||||||
const testsJs = `
|
const testsJs = `
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import * as _pkg from '${path.relative(templatePath, bundleFile)}'
|
import * as _pkg from '${path.relative(templatePath, bundleFile)}'
|
||||||
window._pkg = _pkg;
|
window._pkg = _pkg
|
||||||
import './tests.js';
|
import './tests.js'
|
||||||
mocha.run();
|
mocha.run()
|
||||||
</script>`
|
</script>`
|
||||||
|
|
||||||
fs.writeFileSync(dstFileName,
|
fs.writeFileSync(dstFileName,
|
||||||
template.replace(/{{TESTS}}/g, testsJs).replace(/{{PKG_NAME}}/g, pkgName).replace(/{{MOCHA_VERSION}}/g, mochaVersion).replace(/{{CHAI_VERSION}}/g, chaiVersion)
|
template.replace(/{{TESTS}}/g, testsJs).replace(/{{PKG_NAME}}/g, pkgName).replace(/{{MOCHA_VERSION}}/g, mochaVersion).replace(/{{CHAI_VERSION}}/g, chaiVersion)
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -260,6 +260,14 @@ function isProbablyPrime (w, iterations = 16) {
|
||||||
*/
|
*/
|
||||||
function prime (bitLength, iterations = 16) {
|
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 and it is ${bitLength}`) }
|
||||||
|
|
||||||
|
if (!_useWorkers) { // If there is no support for workers
|
||||||
|
let rnd = 0n
|
||||||
|
do {
|
||||||
|
rnd = fromBuffer(randBitsSync(bitLength, true))
|
||||||
|
} while (!_isProbablyPrime(rnd, iterations))
|
||||||
|
return new Promise((resolve) => { resolve(rnd) })
|
||||||
|
}
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const workerList = []
|
const workerList = []
|
||||||
const _onmessage = (msg, newWorker) => {
|
const _onmessage = (msg, newWorker) => {
|
||||||
|
@ -318,7 +326,7 @@ function prime (bitLength, iterations = 16) {
|
||||||
* @returns {bigint} A bigint probable prime of bitLength bits.
|
* @returns {bigint} A bigint probable prime of bitLength bits.
|
||||||
*/
|
*/
|
||||||
function primeSync (bitLength, iterations = 16) {
|
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 and it is ${bitLength}`)
|
||||||
let rnd = 0n
|
let rnd = 0n
|
||||||
do {
|
do {
|
||||||
rnd = fromBuffer(randBitsSync(bitLength, true))
|
rnd = fromBuffer(randBitsSync(bitLength, true))
|
||||||
|
@ -417,9 +425,9 @@ function randBytes (byteLength, forceLength = false) {
|
||||||
{ // browser
|
{ // browser
|
||||||
return new Promise(function (resolve) {
|
return new Promise(function (resolve) {
|
||||||
const buf = new Uint8Array(byteLength)
|
const buf = new Uint8Array(byteLength)
|
||||||
self.crypto.getRandomValues(buf)
|
crypto.getRandomValues(buf)
|
||||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
// 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
|
||||||
resolve(buf)
|
resolve(buf)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -440,7 +448,7 @@ function randBytesSync (byteLength, forceLength = false) {
|
||||||
/* eslint-disable no-lone-blocks */
|
/* eslint-disable no-lone-blocks */
|
||||||
{ // browser
|
{ // browser
|
||||||
const buf = new Uint8Array(byteLength)
|
const buf = new Uint8Array(byteLength)
|
||||||
self.crypto.getRandomValues(buf)
|
crypto.getRandomValues(buf)
|
||||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
// 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
|
return buf
|
||||||
|
@ -489,7 +497,8 @@ function _isProbablyPrime (w, iterations = 16) {
|
||||||
PREFILTERING. Even values but 2 are not primes, so don't test.
|
PREFILTERING. Even values but 2 are not primes, so don't test.
|
||||||
1 is not a prime and the M-R algorithm needs w>1.
|
1 is not a prime and the M-R algorithm needs w>1.
|
||||||
*/
|
*/
|
||||||
if (w === 2n) { return true } else if ((w & 1n) === 0n || w === 1n) { return false }
|
if (w === 2n) return true
|
||||||
|
else if ((w & 1n) === 0n || w === 1n) return false
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Test if any of the first 250 small primes are a factor of w. 2 is not tested because it was already tested above.
|
Test if any of the first 250 small primes are a factor of w. 2 is not tested because it was already tested above.
|
||||||
|
@ -749,11 +758,8 @@ function _isProbablyPrime (w, iterations = 16) {
|
||||||
|
|
||||||
for (let i = 0; i < firstPrimes.length && (firstPrimes[i] <= w); i++) {
|
for (let i = 0; i < firstPrimes.length && (firstPrimes[i] <= w); i++) {
|
||||||
const p = firstPrimes[i]
|
const p = firstPrimes[i]
|
||||||
if (w === p) {
|
if (w === p) return true
|
||||||
return true
|
else if (w % p === 0n) return false
|
||||||
} else if (w % p === 0n) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -785,38 +791,27 @@ function _isProbablyPrime (w, iterations = 16) {
|
||||||
|
|
||||||
const m = d / (2n ** a)
|
const m = d / (2n ** a)
|
||||||
|
|
||||||
// /* eslint-disable no-labels */
|
|
||||||
// loop: do {
|
|
||||||
// const b = randBetween(w - 1n, 2n)
|
|
||||||
// let z = modPow(b, m, w)
|
|
||||||
// if (z === 1n || z === w - 1n) { continue }
|
|
||||||
// for (let j = 1; j < a; j++) {
|
|
||||||
// z = modPow(z, 2n, w)
|
|
||||||
// if (z === w - 1n) { continue loop }
|
|
||||||
// if (z === 1n) { break }
|
|
||||||
// }
|
|
||||||
// return false
|
|
||||||
// } while (--iterations)
|
|
||||||
// /* eslint-enable no-labels */
|
|
||||||
|
|
||||||
// return true
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
const b = randBetween(d, 2n)
|
const b = randBetween(d, 2n)
|
||||||
let z = modPow(b, m, w)
|
let z = modPow(b, m, w)
|
||||||
if (z === 1n || z === d) { continue }
|
if (z === 1n || z === d) continue
|
||||||
let j = 1
|
let j = 1
|
||||||
while (j < a) {
|
while (j < a) {
|
||||||
z = modPow(z, 2n, w)
|
z = modPow(z, 2n, w)
|
||||||
if (z === d) { break }
|
if (z === d) break
|
||||||
if (z === 1n) { return false }
|
if (z === 1n) return false
|
||||||
j++
|
j++
|
||||||
}
|
}
|
||||||
if (z !== d) {
|
if (z !== d) return false
|
||||||
return false
|
|
||||||
}
|
|
||||||
} while (--iterations)
|
} while (--iterations)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _useWorkers = false // The following is just to check whether we can use workers
|
||||||
|
/* eslint-disable no-lone-blocks */
|
||||||
|
{ // Native JS
|
||||||
|
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 { abs, bitLength, eGcd, gcd, isProbablyPrime, lcm, max, min, modInv, modPow, prime, primeSync, randBetween, randBits, randBitsSync, randBytes, randBytesSync, toZn }
|
||||||
|
|
|
@ -271,7 +271,7 @@ function isProbablyPrime (w, iterations = 16) {
|
||||||
function prime (bitLength, iterations = 16) {
|
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 and it is ${bitLength}`) }
|
||||||
|
|
||||||
if (!_useWorkers) {
|
if (!_useWorkers) { // If there is no support for workers
|
||||||
let rnd = 0n
|
let rnd = 0n
|
||||||
do {
|
do {
|
||||||
rnd = fromBuffer(randBitsSync(bitLength, true))
|
rnd = fromBuffer(randBitsSync(bitLength, true))
|
||||||
|
@ -337,7 +337,7 @@ function prime (bitLength, iterations = 16) {
|
||||||
* @returns {bigint} A bigint probable prime of bitLength bits.
|
* @returns {bigint} A bigint probable prime of bitLength bits.
|
||||||
*/
|
*/
|
||||||
function primeSync (bitLength, iterations = 16) {
|
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 and it is ${bitLength}`)
|
||||||
let rnd = 0n
|
let rnd = 0n
|
||||||
do {
|
do {
|
||||||
rnd = fromBuffer(randBitsSync(bitLength, true))
|
rnd = fromBuffer(randBitsSync(bitLength, true))
|
||||||
|
@ -438,7 +438,7 @@ function randBytes (byteLength, forceLength = false) {
|
||||||
const buf = Buffer.alloc(byteLength)
|
const buf = Buffer.alloc(byteLength)
|
||||||
return crypto.randomFill(buf, function (resolve) {
|
return crypto.randomFill(buf, function (resolve) {
|
||||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
// 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
|
||||||
resolve(buf)
|
resolve(buf)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -484,7 +484,8 @@ function _isProbablyPrime (w, iterations = 16) {
|
||||||
PREFILTERING. Even values but 2 are not primes, so don't test.
|
PREFILTERING. Even values but 2 are not primes, so don't test.
|
||||||
1 is not a prime and the M-R algorithm needs w>1.
|
1 is not a prime and the M-R algorithm needs w>1.
|
||||||
*/
|
*/
|
||||||
if (w === 2n) { return true } else if ((w & 1n) === 0n || w === 1n) { return false }
|
if (w === 2n) return true
|
||||||
|
else if ((w & 1n) === 0n || w === 1n) return false
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Test if any of the first 250 small primes are a factor of w. 2 is not tested because it was already tested above.
|
Test if any of the first 250 small primes are a factor of w. 2 is not tested because it was already tested above.
|
||||||
|
@ -744,11 +745,8 @@ function _isProbablyPrime (w, iterations = 16) {
|
||||||
|
|
||||||
for (let i = 0; i < firstPrimes.length && (firstPrimes[i] <= w); i++) {
|
for (let i = 0; i < firstPrimes.length && (firstPrimes[i] <= w); i++) {
|
||||||
const p = firstPrimes[i]
|
const p = firstPrimes[i]
|
||||||
if (w === p) {
|
if (w === p) return true
|
||||||
return true
|
else if (w % p === 0n) return false
|
||||||
} else if (w % p === 0n) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -780,55 +778,36 @@ function _isProbablyPrime (w, iterations = 16) {
|
||||||
|
|
||||||
const m = d / (2n ** a)
|
const m = d / (2n ** a)
|
||||||
|
|
||||||
// /* eslint-disable no-labels */
|
|
||||||
// loop: do {
|
|
||||||
// const b = randBetween(w - 1n, 2n)
|
|
||||||
// let z = modPow(b, m, w)
|
|
||||||
// if (z === 1n || z === w - 1n) { continue }
|
|
||||||
// for (let j = 1; j < a; j++) {
|
|
||||||
// z = modPow(z, 2n, w)
|
|
||||||
// if (z === w - 1n) { continue loop }
|
|
||||||
// if (z === 1n) { break }
|
|
||||||
// }
|
|
||||||
// return false
|
|
||||||
// } while (--iterations)
|
|
||||||
// /* eslint-enable no-labels */
|
|
||||||
|
|
||||||
// return true
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
const b = randBetween(d, 2n)
|
const b = randBetween(d, 2n)
|
||||||
let z = modPow(b, m, w)
|
let z = modPow(b, m, w)
|
||||||
if (z === 1n || z === d) { continue }
|
if (z === 1n || z === d) continue
|
||||||
let j = 1
|
let j = 1
|
||||||
while (j < a) {
|
while (j < a) {
|
||||||
z = modPow(z, 2n, w)
|
z = modPow(z, 2n, w)
|
||||||
if (z === d) { break }
|
if (z === d) break
|
||||||
if (z === 1n) { return false }
|
if (z === 1n) return false
|
||||||
j++
|
j++
|
||||||
}
|
}
|
||||||
if (z !== d) {
|
if (z !== d) return false
|
||||||
return false
|
|
||||||
}
|
|
||||||
} while (--iterations)
|
} while (--iterations)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
let _useWorkers = true // The following is just to check whether Node.js can use workers
|
let _useWorkers = false // The following is just to check whether we can use workers
|
||||||
/* eslint-disable no-lone-blocks */
|
/* eslint-disable no-lone-blocks */
|
||||||
{ // Node.js
|
{ // Node.js
|
||||||
_useWorkers = (function _workers () {
|
try {
|
||||||
try {
|
require.resolve('worker_threads')
|
||||||
require.resolve('worker_threads')
|
_useWorkers = true
|
||||||
return true
|
} catch (e) {
|
||||||
} catch (e) {
|
console.log(`[bigint-crypto-utils] WARNING:
|
||||||
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.
|
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 >=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 `)
|
· With Node 10, starting with 10.5.0, you can enable worker_threads at runtime executing node --experimental-worker `)
|
||||||
return false
|
_useWorkers = true
|
||||||
}
|
}
|
||||||
})()
|
|
||||||
}
|
}
|
||||||
/* eslint-enable no-lone-blocks */
|
/* eslint-enable no-lone-blocks */
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
"BigInt",
|
"BigInt",
|
||||||
"Blob",
|
"Blob",
|
||||||
"postMessage",
|
"postMessage",
|
||||||
|
"crypto",
|
||||||
"self",
|
"self",
|
||||||
"Worker"
|
"Worker"
|
||||||
],
|
],
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# bigint-crypto-utils
|
# 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 test). 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). In the latter case, for multi-threaded primality tests, you should use Node.js v11 or newer or enable at runtime with `node --experimental-worker` with Node.js version >= 10.5.0 and < 11.
|
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).
|
||||||
|
|
||||||
> 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).
|
> 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).
|
||||||
|
|
||||||
|
@ -56,14 +56,14 @@ Import your module as :
|
||||||
</body>
|
</body>
|
||||||
```
|
```
|
||||||
|
|
||||||
And you could use it like in the following:
|
An example of usage could be:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
/* Stage 3 BigInts with value 666 can be declared as BigInt('666')
|
/* A BigInt with value 666 can be declared calling the bigint constructor as
|
||||||
or the shorter new no-so-linter-friendly syntax 666n.
|
BigInt('666') or with the shorter 666n.
|
||||||
Notice that you can also pass a number, e.g. BigInt(666), but it is not
|
Notice that you can also pass a number to the constructor, e.g. BigInt(666).
|
||||||
recommended since values over 2**53 - 1 won't be safe but no warning will
|
However, it is not recommended since values over 2**53 - 1 won't be safe but
|
||||||
be raised.
|
no warning will be raised.
|
||||||
*/
|
*/
|
||||||
const a = BigInt('5')
|
const a = BigInt('5')
|
||||||
const b = BigInt('2')
|
const b = BigInt('2')
|
||||||
|
@ -95,6 +95,9 @@ primeTesting()
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can find examples in the [examples folder of the repository](https://github.com/juanelas/bigint-crypto-utils/tree/master/examples).
|
||||||
|
|
||||||
|
|
||||||
## API reference documentation
|
## API reference documentation
|
||||||
|
|
||||||
{{>main}}
|
{{>main}}
|
||||||
|
|
|
@ -78,7 +78,7 @@ export function isProbablyPrime (w, iterations = 16) {
|
||||||
export function prime (bitLength, iterations = 16) {
|
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 and it is ${bitLength}`) }
|
||||||
|
|
||||||
if (!process.browser && !_useWorkers) {
|
if (!_useWorkers) { // If there is no support for workers
|
||||||
let rnd = 0n
|
let rnd = 0n
|
||||||
do {
|
do {
|
||||||
rnd = fromBuffer(randBitsSync(bitLength, true))
|
rnd = fromBuffer(randBitsSync(bitLength, true))
|
||||||
|
@ -151,7 +151,7 @@ export function prime (bitLength, iterations = 16) {
|
||||||
* @returns {bigint} A bigint probable prime of bitLength bits.
|
* @returns {bigint} A bigint probable prime of bitLength bits.
|
||||||
*/
|
*/
|
||||||
export function primeSync (bitLength, iterations = 16) {
|
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 and it is ${bitLength}`)
|
||||||
let rnd = 0n
|
let rnd = 0n
|
||||||
do {
|
do {
|
||||||
rnd = fromBuffer(randBitsSync(bitLength, true))
|
rnd = fromBuffer(randBitsSync(bitLength, true))
|
||||||
|
@ -252,15 +252,15 @@ export function randBytes (byteLength, forceLength = false) {
|
||||||
const buf = Buffer.alloc(byteLength)
|
const buf = Buffer.alloc(byteLength)
|
||||||
return crypto.randomFill(buf, function (resolve) {
|
return crypto.randomFill(buf, function (resolve) {
|
||||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
// 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
|
||||||
resolve(buf)
|
resolve(buf)
|
||||||
})
|
})
|
||||||
} else { // browser
|
} else { // browser
|
||||||
return new Promise(function (resolve) {
|
return new Promise(function (resolve) {
|
||||||
const buf = new Uint8Array(byteLength)
|
const buf = new Uint8Array(byteLength)
|
||||||
self.crypto.getRandomValues(buf)
|
crypto.getRandomValues(buf)
|
||||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
// 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
|
||||||
resolve(buf)
|
resolve(buf)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -288,7 +288,7 @@ export function randBytesSync (byteLength, forceLength = false) {
|
||||||
return buf
|
return buf
|
||||||
} else { // browser
|
} else { // browser
|
||||||
const buf = new Uint8Array(byteLength)
|
const buf = new Uint8Array(byteLength)
|
||||||
self.crypto.getRandomValues(buf)
|
crypto.getRandomValues(buf)
|
||||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
// 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
|
return buf
|
||||||
|
@ -337,7 +337,8 @@ function _isProbablyPrime (w, iterations = 16) {
|
||||||
PREFILTERING. Even values but 2 are not primes, so don't test.
|
PREFILTERING. Even values but 2 are not primes, so don't test.
|
||||||
1 is not a prime and the M-R algorithm needs w>1.
|
1 is not a prime and the M-R algorithm needs w>1.
|
||||||
*/
|
*/
|
||||||
if (w === 2n) { return true } else if ((w & 1n) === 0n || w === 1n) { return false }
|
if (w === 2n) return true
|
||||||
|
else if ((w & 1n) === 0n || w === 1n) return false
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Test if any of the first 250 small primes are a factor of w. 2 is not tested because it was already tested above.
|
Test if any of the first 250 small primes are a factor of w. 2 is not tested because it was already tested above.
|
||||||
|
@ -597,11 +598,8 @@ function _isProbablyPrime (w, iterations = 16) {
|
||||||
|
|
||||||
for (let i = 0; i < firstPrimes.length && (firstPrimes[i] <= w); i++) {
|
for (let i = 0; i < firstPrimes.length && (firstPrimes[i] <= w); i++) {
|
||||||
const p = firstPrimes[i]
|
const p = firstPrimes[i]
|
||||||
if (w === p) {
|
if (w === p) return true
|
||||||
return true
|
else if (w % p === 0n) return false
|
||||||
} else if (w % p === 0n) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -633,55 +631,38 @@ function _isProbablyPrime (w, iterations = 16) {
|
||||||
|
|
||||||
const m = d / (2n ** a)
|
const m = d / (2n ** a)
|
||||||
|
|
||||||
// /* eslint-disable no-labels */
|
|
||||||
// loop: do {
|
|
||||||
// const b = randBetween(w - 1n, 2n)
|
|
||||||
// let z = modPow(b, m, w)
|
|
||||||
// if (z === 1n || z === w - 1n) { continue }
|
|
||||||
// for (let j = 1; j < a; j++) {
|
|
||||||
// z = modPow(z, 2n, w)
|
|
||||||
// if (z === w - 1n) { continue loop }
|
|
||||||
// if (z === 1n) { break }
|
|
||||||
// }
|
|
||||||
// return false
|
|
||||||
// } while (--iterations)
|
|
||||||
// /* eslint-enable no-labels */
|
|
||||||
|
|
||||||
// return true
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
const b = randBetween(d, 2n)
|
const b = randBetween(d, 2n)
|
||||||
let z = modPow(b, m, w)
|
let z = modPow(b, m, w)
|
||||||
if (z === 1n || z === d) { continue }
|
if (z === 1n || z === d) continue
|
||||||
let j = 1
|
let j = 1
|
||||||
while (j < a) {
|
while (j < a) {
|
||||||
z = modPow(z, 2n, w)
|
z = modPow(z, 2n, w)
|
||||||
if (z === d) { break }
|
if (z === d) break
|
||||||
if (z === 1n) { return false }
|
if (z === 1n) return false
|
||||||
j++
|
j++
|
||||||
}
|
}
|
||||||
if (z !== d) {
|
if (z !== d) return false
|
||||||
return false
|
|
||||||
}
|
|
||||||
} while (--iterations)
|
} while (--iterations)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
let _useWorkers = true // The following is just to check whether Node.js can use workers
|
let _useWorkers = false // The following is just to check whether we can use workers
|
||||||
/* eslint-disable no-lone-blocks */
|
/* eslint-disable no-lone-blocks */
|
||||||
if (!process.browser) { // Node.js
|
if (!process.browser) { // Node.js
|
||||||
_useWorkers = (function _workers () {
|
try {
|
||||||
try {
|
require.resolve('worker_threads')
|
||||||
require.resolve('worker_threads')
|
_useWorkers = true
|
||||||
return true
|
} catch (e) {
|
||||||
} catch (e) {
|
console.log(`[bigint-crypto-utils] WARNING:
|
||||||
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.
|
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 >=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 `)
|
· With Node 10, starting with 10.5.0, you can enable worker_threads at runtime executing node --experimental-worker `)
|
||||||
return false
|
_useWorkers = true
|
||||||
}
|
}
|
||||||
})()
|
} else { // Native JS
|
||||||
|
if (self.Worker) _useWorkers = true
|
||||||
}
|
}
|
||||||
/* eslint-enable no-lone-blocks */
|
/* eslint-enable no-lone-blocks */
|
||||||
|
|
||||||
|
|
|
@ -12,12 +12,12 @@
|
||||||
<div id="mocha"></div>
|
<div id="mocha"></div>
|
||||||
<script>mocha.setup('bdd'); mocha.setup({ timeout: 90000 });</script>
|
<script>mocha.setup('bdd'); mocha.setup({ timeout: 90000 });</script>
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import * as _pkg from '../../../lib/index.browser.bundle.mod.js'
|
import * as _pkg from '../../../lib/index.browser.bundle.mod.js'
|
||||||
window._pkg = _pkg;
|
window._pkg = _pkg
|
||||||
import './tests.js';
|
import './tests.js'
|
||||||
mocha.run();
|
mocha.run()
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -1,26 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title>Primes</title>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="syncPrime">result of primeSync() will show up here</div>
|
|
||||||
<div id="asyncPrime">result of prime() will show up here</div>
|
|
||||||
|
|
||||||
<script src="../../lib/index.browser.bundle.iife.js"></script>
|
|
||||||
<script>
|
|
||||||
(async () => {
|
|
||||||
document.getElementById(
|
|
||||||
"syncPrime"
|
|
||||||
).innerHTML = bigintCryptoUtils.primeSync(123);
|
|
||||||
document.getElementById(
|
|
||||||
"asyncPrime"
|
|
||||||
).innerHTML = await bigintCryptoUtils.prime(123);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
Loading…
Reference in New Issue