2019-04-19 10:05:37 +00:00
|
|
|
|
var bigintCryptoUtils = (function (exports) {
|
2019-04-19 07:42:28 +00:00
|
|
|
|
'use strict';
|
|
|
|
|
|
2019-04-29 11:23:15 +00:00
|
|
|
|
const _ZERO = BigInt(0);
|
|
|
|
|
const _ONE = BigInt(1);
|
|
|
|
|
const _TWO = BigInt(2);
|
|
|
|
|
|
|
|
|
|
|
2019-04-19 07:42:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
2019-04-19 14:40:11 +00:00
|
|
|
|
function abs(a) {
|
2019-04-19 07:42:28 +00:00
|
|
|
|
a = BigInt(a);
|
2019-04-23 14:57:06 +00:00
|
|
|
|
return (a >= _ZERO) ? a : -a;
|
2019-04-19 14:40:11 +00:00
|
|
|
|
}
|
2019-04-19 07:42:28 +00:00
|
|
|
|
|
2019-04-29 10:34:20 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the bitlength of a number
|
|
|
|
|
*
|
2019-05-04 16:29:09 +00:00
|
|
|
|
* @param {number|bigint} a
|
2019-04-29 10:34:20 +00:00
|
|
|
|
* @returns {number} - the bit length
|
|
|
|
|
*/
|
|
|
|
|
function bitLength(a) {
|
2019-05-04 16:29:09 +00:00
|
|
|
|
a = BigInt(a);
|
2019-05-09 07:39:12 +00:00
|
|
|
|
if (a === _ONE)
|
2019-05-04 16:08:30 +00:00
|
|
|
|
return 1;
|
2019-04-29 10:34:20 +00:00
|
|
|
|
let bits = 1;
|
|
|
|
|
do {
|
|
|
|
|
bits++;
|
|
|
|
|
} while ((a >>= _ONE) > _ONE);
|
|
|
|
|
return bits;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-19 10:05:37 +00:00
|
|
|
|
/**
|
|
|
|
|
* @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
|
|
|
|
|
*
|
2019-05-09 07:39:12 +00:00
|
|
|
|
* @returns {egcdReturn} A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
2019-04-19 10:05:37 +00:00
|
|
|
|
*/
|
2019-04-19 14:40:11 +00:00
|
|
|
|
function eGcd(a, b) {
|
2019-04-19 10:05:37 +00:00
|
|
|
|
a = BigInt(a);
|
|
|
|
|
b = BigInt(b);
|
2019-05-09 07:39:12 +00:00
|
|
|
|
if (a <= _ZERO | b <= _ZERO)
|
|
|
|
|
return NaN; // a and b MUST be positive
|
|
|
|
|
|
2019-04-23 14:57:06 +00:00
|
|
|
|
let x = _ZERO;
|
|
|
|
|
let y = _ONE;
|
|
|
|
|
let u = _ONE;
|
|
|
|
|
let v = _ZERO;
|
2019-04-19 10:05:37 +00:00
|
|
|
|
|
2019-04-23 14:57:06 +00:00
|
|
|
|
while (a !== _ZERO) {
|
2019-04-19 10:05:37 +00:00
|
|
|
|
let q = b / a;
|
|
|
|
|
let r = b % a;
|
|
|
|
|
let m = x - (u * q);
|
|
|
|
|
let n = y - (v * q);
|
|
|
|
|
b = a;
|
|
|
|
|
a = r;
|
|
|
|
|
x = u;
|
|
|
|
|
y = v;
|
|
|
|
|
u = m;
|
|
|
|
|
v = n;
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
b: b,
|
|
|
|
|
x: x,
|
|
|
|
|
y: y
|
|
|
|
|
};
|
2019-04-19 14:40:11 +00:00
|
|
|
|
}
|
2019-04-19 10:05:37 +00:00
|
|
|
|
|
2019-04-19 07:42:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
2019-04-19 14:40:11 +00:00
|
|
|
|
function gcd(a, b) {
|
2019-04-19 07:42:28 +00:00
|
|
|
|
a = abs(a);
|
|
|
|
|
b = abs(b);
|
2019-05-09 07:39:12 +00:00
|
|
|
|
if (a === _ZERO)
|
|
|
|
|
return b;
|
|
|
|
|
else if (b === _ZERO)
|
|
|
|
|
return a;
|
|
|
|
|
|
2019-04-23 14:57:06 +00:00
|
|
|
|
let shift = _ZERO;
|
|
|
|
|
while (!((a | b) & _ONE)) {
|
|
|
|
|
a >>= _ONE;
|
|
|
|
|
b >>= _ONE;
|
2019-04-19 07:42:28 +00:00
|
|
|
|
shift++;
|
|
|
|
|
}
|
2019-04-23 14:57:06 +00:00
|
|
|
|
while (!(a & _ONE)) a >>= _ONE;
|
2019-04-19 07:42:28 +00:00
|
|
|
|
do {
|
2019-04-23 14:57:06 +00:00
|
|
|
|
while (!(b & _ONE)) b >>= _ONE;
|
2019-04-19 07:42:28 +00:00
|
|
|
|
if (a > b) {
|
|
|
|
|
let x = a;
|
|
|
|
|
a = b;
|
|
|
|
|
b = x;
|
|
|
|
|
}
|
|
|
|
|
b -= a;
|
|
|
|
|
} while (b);
|
|
|
|
|
|
|
|
|
|
// rescale
|
|
|
|
|
return a << shift;
|
2019-04-19 14:40:11 +00:00
|
|
|
|
}
|
2019-04-19 07:42:28 +00:00
|
|
|
|
|
|
|
|
|
/**
|
2019-04-20 20:11:44 +00:00
|
|
|
|
* 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)
|
2019-04-19 07:42:28 +00:00
|
|
|
|
*
|
2019-05-04 16:29:09 +00:00
|
|
|
|
* @param {number|bigint} w An integer to be tested for primality
|
2019-04-19 10:05:37 +00:00
|
|
|
|
* @param {number} iterations The number of iterations for the primality test. The value shall be consistent with Table C.1, C.2 or C.3
|
2019-04-19 07:42:28 +00:00
|
|
|
|
*
|
2019-04-23 13:22:48 +00:00
|
|
|
|
* @return {Promise} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
|
2019-04-19 07:42:28 +00:00
|
|
|
|
*/
|
2019-04-19 14:40:11 +00:00
|
|
|
|
async function isProbablyPrime(w, iterations = 16) {
|
2019-05-04 16:29:09 +00:00
|
|
|
|
if (typeof w === 'number') {
|
|
|
|
|
w = BigInt(w);
|
|
|
|
|
}
|
2019-04-20 20:11:44 +00:00
|
|
|
|
{ // browser
|
|
|
|
|
return new Promise((resolve, reject) => {
|
2019-04-26 13:03:53 +00:00
|
|
|
|
let worker = new Worker(_isProbablyPrimeWorkerUrl());
|
2019-04-19 10:05:37 +00:00
|
|
|
|
|
|
|
|
|
worker.onmessage = (event) => {
|
|
|
|
|
worker.terminate();
|
|
|
|
|
resolve(event.data.isPrime);
|
|
|
|
|
};
|
|
|
|
|
|
2019-04-20 20:11:44 +00:00
|
|
|
|
worker.onmessageerror = (event) => {
|
|
|
|
|
reject(event);
|
|
|
|
|
};
|
|
|
|
|
|
2019-04-19 10:05:37 +00:00
|
|
|
|
worker.postMessage({
|
|
|
|
|
'rnd': w,
|
2019-04-20 20:11:44 +00:00
|
|
|
|
'iterations': iterations,
|
|
|
|
|
'id': 0
|
2019-04-19 10:05:37 +00:00
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
2019-04-19 14:40:11 +00:00
|
|
|
|
}
|
2019-04-19 07:42:28 +00:00
|
|
|
|
|
|
|
|
|
/**
|
2019-04-19 10:05:37 +00:00
|
|
|
|
* The least common multiple computed as abs(a*b)/gcd(a,b)
|
2019-04-19 07:42:28 +00:00
|
|
|
|
* @param {number|bigint} a
|
|
|
|
|
* @param {number|bigint} b
|
|
|
|
|
*
|
2019-04-19 10:05:37 +00:00
|
|
|
|
* @returns {bigint} The least common multiple of a and b
|
2019-04-19 07:42:28 +00:00
|
|
|
|
*/
|
2019-04-19 14:40:11 +00:00
|
|
|
|
function lcm(a, b) {
|
2019-04-19 07:42:28 +00:00
|
|
|
|
a = BigInt(a);
|
|
|
|
|
b = BigInt(b);
|
2019-05-09 07:39:12 +00:00
|
|
|
|
if (a === _ZERO && b === _ZERO)
|
|
|
|
|
return _ZERO;
|
2019-04-19 10:05:37 +00:00
|
|
|
|
return abs(a * b) / gcd(a, b);
|
2019-04-19 14:40:11 +00:00
|
|
|
|
}
|
2019-04-19 07:42:28 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Modular inverse.
|
|
|
|
|
*
|
|
|
|
|
* @param {number|bigint} a The number to find an inverse for
|
|
|
|
|
* @param {number|bigint} n The modulo
|
|
|
|
|
*
|
2019-05-09 07:39:12 +00:00
|
|
|
|
* @returns {bigint} the inverse modulo n or NaN if it does not exist
|
2019-04-19 07:42:28 +00:00
|
|
|
|
*/
|
2019-04-19 14:40:11 +00:00
|
|
|
|
function modInv(a, n) {
|
2019-05-09 07:39:12 +00:00
|
|
|
|
if (a == _ZERO | n <= _ZERO)
|
|
|
|
|
return NaN;
|
|
|
|
|
|
|
|
|
|
let egcd = eGcd(toZn(a, n), n);
|
2019-04-23 14:57:06 +00:00
|
|
|
|
if (egcd.b !== _ONE) {
|
2019-05-09 07:39:12 +00:00
|
|
|
|
return NaN; // modular inverse does not exist
|
2019-04-19 07:42:28 +00:00
|
|
|
|
} else {
|
|
|
|
|
return toZn(egcd.x, n);
|
|
|
|
|
}
|
2019-04-19 14:40:11 +00:00
|
|
|
|
}
|
2019-04-19 07:42:28 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Modular exponentiation a**b mod n
|
|
|
|
|
* @param {number|bigint} a base
|
|
|
|
|
* @param {number|bigint} b exponent
|
|
|
|
|
* @param {number|bigint} n modulo
|
|
|
|
|
*
|
|
|
|
|
* @returns {bigint} a**b mod n
|
|
|
|
|
*/
|
2019-04-19 14:40:11 +00:00
|
|
|
|
function modPow(a, b, n) {
|
2019-04-19 07:42:28 +00:00
|
|
|
|
// See Knuth, volume 2, section 4.6.3.
|
|
|
|
|
n = BigInt(n);
|
2019-05-09 07:39:12 +00:00
|
|
|
|
if (n === _ZERO)
|
|
|
|
|
return NaN;
|
|
|
|
|
|
2019-04-19 07:42:28 +00:00
|
|
|
|
a = toZn(a, n);
|
|
|
|
|
b = BigInt(b);
|
2019-04-23 14:57:06 +00:00
|
|
|
|
if (b < _ZERO) {
|
2019-04-19 07:42:28 +00:00
|
|
|
|
return modInv(modPow(a, abs(b), n), n);
|
|
|
|
|
}
|
2019-04-23 14:57:06 +00:00
|
|
|
|
let result = _ONE;
|
2019-04-19 07:42:28 +00:00
|
|
|
|
let x = a;
|
|
|
|
|
while (b > 0) {
|
2019-04-23 14:57:06 +00:00
|
|
|
|
var leastSignificantBit = b % _TWO;
|
|
|
|
|
b = b / _TWO;
|
|
|
|
|
if (leastSignificantBit == _ONE) {
|
2019-04-19 07:42:28 +00:00
|
|
|
|
result = result * x;
|
|
|
|
|
result = result % n;
|
|
|
|
|
}
|
|
|
|
|
x = x * x;
|
|
|
|
|
x = x % n;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
2019-04-19 14:40:11 +00:00
|
|
|
|
}
|
2019-04-19 07:42:28 +00:00
|
|
|
|
|
|
|
|
|
/**
|
2019-04-19 10:05:37 +00:00
|
|
|
|
* 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).
|
2019-04-20 20:21:41 +00:00
|
|
|
|
* The node version can also use worker_threads if they are available (enabled by default with Node 11 and
|
2019-04-21 07:39:28 +00:00
|
|
|
|
* and can be enabled at runtime executing node --experimental-worker with node >=10.5.0).
|
2019-04-19 07:42:28 +00:00
|
|
|
|
*
|
2019-04-19 10:05:37 +00:00
|
|
|
|
* @param {number} bitLength The required bit length for the generated prime
|
|
|
|
|
* @param {number} iterations The number of iterations for the Miller-Rabin Probabilistic Primality Test
|
2019-04-19 07:42:28 +00:00
|
|
|
|
*
|
2019-04-19 10:05:37 +00:00
|
|
|
|
* @returns {Promise} A promise that resolves to a bigint probable prime of bitLength bits
|
2019-04-19 07:42:28 +00:00
|
|
|
|
*/
|
2019-04-26 13:03:53 +00:00
|
|
|
|
function prime(bitLength, iterations = 16) {
|
2019-05-09 07:39:12 +00:00
|
|
|
|
if (bitLength < 1)
|
|
|
|
|
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`);
|
2019-04-20 20:11:44 +00:00
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
let workerList = [];
|
|
|
|
|
const _onmessage = (msg, newWorker) => {
|
|
|
|
|
if (msg.isPrime) {
|
|
|
|
|
// if a prime number has been found, stop all the workers, and return it
|
|
|
|
|
for (let j = 0; j < workerList.length; j++) {
|
|
|
|
|
workerList[j].terminate();
|
|
|
|
|
}
|
|
|
|
|
while (workerList.length) {
|
|
|
|
|
workerList.pop();
|
|
|
|
|
}
|
|
|
|
|
resolve(msg.value);
|
|
|
|
|
} else { // if a composite is found, make the worker test another random number
|
2019-04-26 13:03:53 +00:00
|
|
|
|
let buf = randBits(bitLength, true);
|
|
|
|
|
let rnd = fromBuffer(buf);
|
|
|
|
|
try {
|
|
|
|
|
newWorker.postMessage({
|
|
|
|
|
'rnd': rnd,
|
|
|
|
|
'iterations': iterations,
|
|
|
|
|
'id': msg.id
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
// The worker has already terminated. There is nothing to handle here
|
|
|
|
|
}
|
2019-04-20 20:11:44 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
{ //browser
|
2019-04-26 13:03:53 +00:00
|
|
|
|
let workerURL = _isProbablyPrimeWorkerUrl();
|
2019-04-20 20:11:44 +00:00
|
|
|
|
for (let i = 0; i < self.navigator.hardwareConcurrency; i++) {
|
|
|
|
|
let newWorker = new Worker(workerURL);
|
|
|
|
|
newWorker.onmessage = (event) => _onmessage(event.data, newWorker);
|
2019-04-19 10:05:37 +00:00
|
|
|
|
workerList.push(newWorker);
|
|
|
|
|
}
|
2019-04-20 20:11:44 +00:00
|
|
|
|
}
|
|
|
|
|
for (let i = 0; i < workerList.length; i++) {
|
2019-04-26 13:03:53 +00:00
|
|
|
|
let buf = randBits(bitLength, true);
|
|
|
|
|
let rnd = fromBuffer(buf);
|
|
|
|
|
workerList[i].postMessage({
|
|
|
|
|
'rnd': rnd,
|
|
|
|
|
'iterations': iterations,
|
|
|
|
|
'id': i
|
2019-04-20 20:11:44 +00:00
|
|
|
|
});
|
2019-04-19 07:42:28 +00:00
|
|
|
|
}
|
|
|
|
|
});
|
2019-04-19 14:40:11 +00:00
|
|
|
|
}
|
2019-04-19 07:42:28 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns a cryptographically secure random integer between [min,max]
|
|
|
|
|
* @param {bigint} max Returned value will be <= max
|
|
|
|
|
* @param {bigint} min Returned value will be >= min
|
|
|
|
|
*
|
2019-04-26 13:03:53 +00:00
|
|
|
|
* @returns {bigint} A cryptographically secure random bigint between [min,max]
|
2019-04-19 07:42:28 +00:00
|
|
|
|
*/
|
2019-04-26 13:03:53 +00:00
|
|
|
|
function randBetween(max, min = _ONE) {
|
2019-04-20 20:11:44 +00:00
|
|
|
|
if (max <= min) throw new Error('max must be > min');
|
|
|
|
|
const interval = max - min;
|
|
|
|
|
let bitLen = bitLength(interval);
|
2019-04-19 07:42:28 +00:00
|
|
|
|
let rnd;
|
|
|
|
|
do {
|
2019-04-26 13:03:53 +00:00
|
|
|
|
let buf = randBits(bitLen);
|
2019-04-19 07:42:28 +00:00
|
|
|
|
rnd = fromBuffer(buf);
|
2019-04-20 20:11:44 +00:00
|
|
|
|
} while (rnd > interval);
|
|
|
|
|
return rnd + min;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
|
|
|
|
*
|
|
|
|
|
* @param {number} bitLength The desired number of random bits
|
|
|
|
|
* @param {boolean} forceLength If we want to force the output to have a specific bit length. It basically forces the msb to be 1
|
|
|
|
|
*
|
2019-04-29 10:29:23 +00:00
|
|
|
|
* @returns {Buffer|Uint8Array} A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bits
|
2019-04-20 20:11:44 +00:00
|
|
|
|
*/
|
2019-04-26 13:03:53 +00:00
|
|
|
|
function randBits(bitLength, forceLength = false) {
|
2019-05-09 07:39:12 +00:00
|
|
|
|
if (bitLength < 1)
|
|
|
|
|
throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`);
|
|
|
|
|
|
2019-04-20 20:11:44 +00:00
|
|
|
|
const byteLength = Math.ceil(bitLength / 8);
|
2019-05-04 16:08:30 +00:00
|
|
|
|
let rndBytes = randBytesSync(byteLength, false);
|
2019-05-09 07:39:12 +00:00
|
|
|
|
// Fill with 0's the extra bits
|
2019-04-20 20:11:44 +00:00
|
|
|
|
rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1);
|
|
|
|
|
if (forceLength) {
|
|
|
|
|
let mask = (bitLength % 8) ? 2 ** ((bitLength % 8) - 1) : 128;
|
|
|
|
|
rndBytes[0] = rndBytes[0] | mask;
|
|
|
|
|
}
|
|
|
|
|
return rndBytes;
|
2019-04-19 14:40:11 +00:00
|
|
|
|
}
|
2019-04-19 07:42:28 +00:00
|
|
|
|
|
|
|
|
|
/**
|
2019-04-19 10:05:37 +00:00
|
|
|
|
* Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
2019-04-19 07:42:28 +00:00
|
|
|
|
*
|
2019-04-19 10:05:37 +00:00
|
|
|
|
* @param {number} byteLength The desired number of random bytes
|
|
|
|
|
* @param {boolean} forceLength If we want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1
|
2019-04-19 07:42:28 +00:00
|
|
|
|
*
|
2019-05-04 16:08:30 +00:00
|
|
|
|
* @returns {Promise} A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
2019-04-19 07:42:28 +00:00
|
|
|
|
*/
|
2019-04-26 13:03:53 +00:00
|
|
|
|
function randBytes(byteLength, forceLength = false) {
|
2019-05-09 07:39:12 +00:00
|
|
|
|
if (byteLength < 1)
|
|
|
|
|
throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`);
|
|
|
|
|
|
2019-05-04 16:08:30 +00:00
|
|
|
|
let buf;
|
|
|
|
|
{ // browser
|
|
|
|
|
return new Promise(function (resolve) {
|
|
|
|
|
buf = new Uint8Array(byteLength);
|
|
|
|
|
self.crypto.getRandomValues(buf);
|
|
|
|
|
resolve(buf);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
|
|
|
|
*
|
|
|
|
|
* @param {number} byteLength The desired number of random bytes
|
|
|
|
|
* @param {boolean} forceLength If we want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1
|
|
|
|
|
*
|
|
|
|
|
* @returns {Buffer|Uint8Array} A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
|
|
|
|
|
*/
|
|
|
|
|
function randBytesSync(byteLength, forceLength = false) {
|
2019-05-09 07:39:12 +00:00
|
|
|
|
if (byteLength < 1)
|
|
|
|
|
throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`);
|
|
|
|
|
|
2019-04-26 13:03:53 +00:00
|
|
|
|
let buf;
|
|
|
|
|
{ // browser
|
|
|
|
|
buf = new Uint8Array(byteLength);
|
|
|
|
|
self.crypto.getRandomValues(buf);
|
|
|
|
|
}
|
|
|
|
|
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
|
|
|
|
if (forceLength)
|
|
|
|
|
buf[0] = buf[0] | 128;
|
|
|
|
|
return buf;
|
2019-04-19 14:40:11 +00:00
|
|
|
|
}
|
2019-04-19 10:05:37 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
2019-04-19 14:40:11 +00:00
|
|
|
|
function toZn(a, n) {
|
2019-04-19 10:05:37 +00:00
|
|
|
|
n = BigInt(n);
|
2019-05-09 07:39:12 +00:00
|
|
|
|
if (n <= 0)
|
|
|
|
|
return NaN;
|
|
|
|
|
|
2019-04-19 10:05:37 +00:00
|
|
|
|
a = BigInt(a) % n;
|
|
|
|
|
return (a < 0) ? a + n : a;
|
2019-04-19 14:40:11 +00:00
|
|
|
|
}
|
2019-04-19 10:05:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* HELPER FUNCTIONS */
|
|
|
|
|
|
|
|
|
|
function fromBuffer(buf) {
|
2019-04-23 14:57:06 +00:00
|
|
|
|
let ret = _ZERO;
|
2019-04-19 10:05:37 +00:00
|
|
|
|
for (let i of buf.values()) {
|
|
|
|
|
let bi = BigInt(i);
|
|
|
|
|
ret = (ret << BigInt(8)) + bi;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-26 13:03:53 +00:00
|
|
|
|
function _isProbablyPrimeWorkerUrl() {
|
2019-04-20 20:11:44 +00:00
|
|
|
|
// Let's us first add all the required functions
|
2019-05-04 16:08:30 +00:00
|
|
|
|
let workerCode = `'use strict';const _ZERO = BigInt(0);const _ONE = BigInt(1);const _TWO = BigInt(2);const eGcd = ${eGcd.toString()};const modInv = ${modInv.toString()};const modPow = ${modPow.toString()};const toZn = ${toZn.toString()};const randBits = ${randBits.toString()};const randBytesSync = ${randBytesSync.toString()};const randBetween = ${randBetween.toString()};const isProbablyPrime = ${_isProbablyPrime.toString()};${bitLength.toString()}${fromBuffer.toString()}`;
|
2019-04-20 20:11:44 +00:00
|
|
|
|
|
2019-04-26 13:03:53 +00:00
|
|
|
|
const onmessage = async function (event) { // Let's start once we are called
|
2019-04-19 10:04:06 +00:00
|
|
|
|
// event.data = {rnd: <bigint>, iterations: <number>}
|
2019-04-19 10:05:37 +00:00
|
|
|
|
const isPrime = await isProbablyPrime(event.data.rnd, event.data.iterations);
|
2019-04-19 10:04:06 +00:00
|
|
|
|
postMessage({
|
|
|
|
|
'isPrime': isPrime,
|
2019-04-20 20:11:44 +00:00
|
|
|
|
'value': event.data.rnd,
|
|
|
|
|
'id': event.data.id
|
2019-04-19 10:04:06 +00:00
|
|
|
|
});
|
2019-04-20 20:11:44 +00:00
|
|
|
|
};
|
2019-05-04 16:08:30 +00:00
|
|
|
|
|
2019-04-26 13:03:53 +00:00
|
|
|
|
workerCode += `onmessage = ${onmessage.toString()};`;
|
2019-04-19 10:04:06 +00:00
|
|
|
|
|
2019-04-26 13:03:53 +00:00
|
|
|
|
return _workerUrl(workerCode);
|
|
|
|
|
}
|
2019-04-19 10:05:37 +00:00
|
|
|
|
|
2019-04-26 13:03:53 +00:00
|
|
|
|
function _workerUrl(workerCode) {
|
|
|
|
|
workerCode = `(() => {${workerCode}})()`; // encapsulate IIFE
|
2019-04-19 10:04:06 +00:00
|
|
|
|
var _blob = new Blob([workerCode], { type: 'text/javascript' });
|
2019-04-19 14:17:09 +00:00
|
|
|
|
return window.URL.createObjectURL(_blob);
|
2019-04-19 10:04:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-26 13:03:53 +00:00
|
|
|
|
function _isProbablyPrime(w, iterations = 16) {
|
2019-04-19 07:42:28 +00:00
|
|
|
|
/*
|
|
|
|
|
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.
|
|
|
|
|
*/
|
2019-04-23 14:57:06 +00:00
|
|
|
|
if (w === _TWO)
|
2019-04-19 07:42:28 +00:00
|
|
|
|
return true;
|
2019-04-23 14:57:06 +00:00
|
|
|
|
else if ((w & _ONE) === _ZERO || w === _ONE)
|
2019-04-19 07:42:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Test if any of the first 250 small primes are a factor of w. 2 is not tested because it was already tested above.
|
|
|
|
|
*/
|
|
|
|
|
const firstPrimes = [
|
|
|
|
|
3,
|
|
|
|
|
5,
|
|
|
|
|
7,
|
|
|
|
|
11,
|
|
|
|
|
13,
|
|
|
|
|
17,
|
|
|
|
|
19,
|
|
|
|
|
23,
|
|
|
|
|
29,
|
|
|
|
|
31,
|
|
|
|
|
37,
|
|
|
|
|
41,
|
|
|
|
|
43,
|
|
|
|
|
47,
|
|
|
|
|
53,
|
|
|
|
|
59,
|
|
|
|
|
61,
|
|
|
|
|
67,
|
|
|
|
|
71,
|
|
|
|
|
73,
|
|
|
|
|
79,
|
|
|
|
|
83,
|
|
|
|
|
89,
|
|
|
|
|
97,
|
|
|
|
|
101,
|
|
|
|
|
103,
|
|
|
|
|
107,
|
|
|
|
|
109,
|
|
|
|
|
113,
|
|
|
|
|
127,
|
|
|
|
|
131,
|
|
|
|
|
137,
|
|
|
|
|
139,
|
|
|
|
|
149,
|
|
|
|
|
151,
|
|
|
|
|
157,
|
|
|
|
|
163,
|
|
|
|
|
167,
|
|
|
|
|
173,
|
|
|
|
|
179,
|
|
|
|
|
181,
|
|
|
|
|
191,
|
|
|
|
|
193,
|
|
|
|
|
197,
|
|
|
|
|
199,
|
|
|
|
|
211,
|
|
|
|
|
223,
|
|
|
|
|
227,
|
|
|
|
|
229,
|
|
|
|
|
233,
|
|
|
|
|
239,
|
|
|
|
|
241,
|
|
|
|
|
251,
|
|
|
|
|
257,
|
|
|
|
|
263,
|
|
|
|
|
269,
|
|
|
|
|
271,
|
|
|
|
|
277,
|
|
|
|
|
281,
|
|
|
|
|
283,
|
|
|
|
|
293,
|
|
|
|
|
307,
|
|
|
|
|
311,
|
|
|
|
|
313,
|
|
|
|
|
317,
|
|
|
|
|
331,
|
|
|
|
|
337,
|
|
|
|
|
347,
|
|
|
|
|
349,
|
|
|
|
|
353,
|
|
|
|
|
359,
|
|
|
|
|
367,
|
|
|
|
|
373,
|
|
|
|
|
379,
|
|
|
|
|
383,
|
|
|
|
|
389,
|
|
|
|
|
397,
|
|
|
|
|
401,
|
|
|
|
|
409,
|
|
|
|
|
419,
|
|
|
|
|
421,
|
|
|
|
|
431,
|
|
|
|
|
433,
|
|
|
|
|
439,
|
|
|
|
|
443,
|
|
|
|
|
449,
|
|
|
|
|
457,
|
|
|
|
|
461,
|
|
|
|
|
463,
|
|
|
|
|
467,
|
|
|
|
|
479,
|
|
|
|
|
487,
|
|
|
|
|
491,
|
|
|
|
|
499,
|
|
|
|
|
503,
|
|
|
|
|
509,
|
|
|
|
|
521,
|
|
|
|
|
523,
|
|
|
|
|
541,
|
|
|
|
|
547,
|
|
|
|
|
557,
|
|
|
|
|
563,
|
|
|
|
|
569,
|
|
|
|
|
571,
|
|
|
|
|
577,
|
|
|
|
|
587,
|
|
|
|
|
593,
|
|
|
|
|
599,
|
|
|
|
|
601,
|
|
|
|
|
607,
|
|
|
|
|
613,
|
|
|
|
|
617,
|
|
|
|
|
619,
|
|
|
|
|
631,
|
|
|
|
|
641,
|
|
|
|
|
643,
|
|
|
|
|
647,
|
|
|
|
|
653,
|
|
|
|
|
659,
|
|
|
|
|
661,
|
|
|
|
|
673,
|
|
|
|
|
677,
|
|
|
|
|
683,
|
|
|
|
|
691,
|
|
|
|
|
701,
|
|
|
|
|
709,
|
|
|
|
|
719,
|
|
|
|
|
727,
|
|
|
|
|
733,
|
|
|
|
|
739,
|
|
|
|
|
743,
|
|
|
|
|
751,
|
|
|
|
|
757,
|
|
|
|
|
761,
|
|
|
|
|
769,
|
|
|
|
|
773,
|
|
|
|
|
787,
|
|
|
|
|
797,
|
|
|
|
|
809,
|
|
|
|
|
811,
|
|
|
|
|
821,
|
|
|
|
|
823,
|
|
|
|
|
827,
|
|
|
|
|
829,
|
|
|
|
|
839,
|
|
|
|
|
853,
|
|
|
|
|
857,
|
|
|
|
|
859,
|
|
|
|
|
863,
|
|
|
|
|
877,
|
|
|
|
|
881,
|
|
|
|
|
883,
|
|
|
|
|
887,
|
|
|
|
|
907,
|
|
|
|
|
911,
|
|
|
|
|
919,
|
|
|
|
|
929,
|
|
|
|
|
937,
|
|
|
|
|
941,
|
|
|
|
|
947,
|
|
|
|
|
953,
|
|
|
|
|
967,
|
|
|
|
|
971,
|
|
|
|
|
977,
|
|
|
|
|
983,
|
|
|
|
|
991,
|
|
|
|
|
997,
|
|
|
|
|
1009,
|
|
|
|
|
1013,
|
|
|
|
|
1019,
|
|
|
|
|
1021,
|
|
|
|
|
1031,
|
|
|
|
|
1033,
|
|
|
|
|
1039,
|
|
|
|
|
1049,
|
|
|
|
|
1051,
|
|
|
|
|
1061,
|
|
|
|
|
1063,
|
|
|
|
|
1069,
|
|
|
|
|
1087,
|
|
|
|
|
1091,
|
|
|
|
|
1093,
|
|
|
|
|
1097,
|
|
|
|
|
1103,
|
|
|
|
|
1109,
|
|
|
|
|
1117,
|
|
|
|
|
1123,
|
|
|
|
|
1129,
|
|
|
|
|
1151,
|
|
|
|
|
1153,
|
|
|
|
|
1163,
|
|
|
|
|
1171,
|
|
|
|
|
1181,
|
|
|
|
|
1187,
|
|
|
|
|
1193,
|
|
|
|
|
1201,
|
|
|
|
|
1213,
|
|
|
|
|
1217,
|
|
|
|
|
1223,
|
|
|
|
|
1229,
|
|
|
|
|
1231,
|
|
|
|
|
1237,
|
|
|
|
|
1249,
|
|
|
|
|
1259,
|
|
|
|
|
1277,
|
|
|
|
|
1279,
|
|
|
|
|
1283,
|
|
|
|
|
1289,
|
|
|
|
|
1291,
|
|
|
|
|
1297,
|
|
|
|
|
1301,
|
|
|
|
|
1303,
|
|
|
|
|
1307,
|
|
|
|
|
1319,
|
|
|
|
|
1321,
|
|
|
|
|
1327,
|
|
|
|
|
1361,
|
|
|
|
|
1367,
|
|
|
|
|
1373,
|
|
|
|
|
1381,
|
|
|
|
|
1399,
|
|
|
|
|
1409,
|
|
|
|
|
1423,
|
|
|
|
|
1427,
|
|
|
|
|
1429,
|
|
|
|
|
1433,
|
|
|
|
|
1439,
|
|
|
|
|
1447,
|
|
|
|
|
1451,
|
|
|
|
|
1453,
|
|
|
|
|
1459,
|
|
|
|
|
1471,
|
|
|
|
|
1481,
|
|
|
|
|
1483,
|
|
|
|
|
1487,
|
|
|
|
|
1489,
|
|
|
|
|
1493,
|
|
|
|
|
1499,
|
|
|
|
|
1511,
|
|
|
|
|
1523,
|
|
|
|
|
1531,
|
|
|
|
|
1543,
|
|
|
|
|
1549,
|
|
|
|
|
1553,
|
|
|
|
|
1559,
|
|
|
|
|
1567,
|
|
|
|
|
1571,
|
|
|
|
|
1579,
|
|
|
|
|
1583,
|
|
|
|
|
1597,
|
|
|
|
|
];
|
|
|
|
|
for (let i = 0; i < firstPrimes.length && (BigInt(firstPrimes[i]) <= w); i++) {
|
|
|
|
|
const p = BigInt(firstPrimes[i]);
|
|
|
|
|
if (w === p)
|
|
|
|
|
return true;
|
2019-04-23 14:57:06 +00:00
|
|
|
|
else if (w % p === _ZERO)
|
2019-04-19 07:42:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
1. Let a be the largest integer such that 2**a divides w−1.
|
|
|
|
|
2. m = (w−1) / 2**a.
|
|
|
|
|
3. wlen = len (w).
|
|
|
|
|
4. For i = 1 to iterations do
|
|
|
|
|
4.1 Obtain a string b of wlen bits from an RBG.
|
|
|
|
|
Comment: Ensure that 1 < b < w−1.
|
|
|
|
|
4.2 If ((b ≤ 1) or (b ≥ w−1)), then go to step 4.1.
|
|
|
|
|
4.3 z = b**m mod w.
|
|
|
|
|
4.4 If ((z = 1) or (z = w − 1)), then go to step 4.7.
|
|
|
|
|
4.5 For j = 1 to a − 1 do.
|
|
|
|
|
4.5.1 z = z**2 mod w.
|
|
|
|
|
4.5.2 If (z = w−1), then go to step 4.7.
|
|
|
|
|
4.5.3 If (z = 1), then go to step 4.6.
|
|
|
|
|
4.6 Return COMPOSITE.
|
|
|
|
|
4.7 Continue.
|
|
|
|
|
Comment: Increment i for the do-loop in step 4.
|
|
|
|
|
5. Return PROBABLY PRIME.
|
|
|
|
|
*/
|
2019-04-23 14:57:06 +00:00
|
|
|
|
let a = _ZERO, d = w - _ONE;
|
|
|
|
|
while (d % _TWO === _ZERO) {
|
|
|
|
|
d /= _TWO;
|
2019-04-19 07:42:28 +00:00
|
|
|
|
++a;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-23 14:57:06 +00:00
|
|
|
|
let m = (w - _ONE) / (_TWO ** a);
|
2019-04-19 07:42:28 +00:00
|
|
|
|
|
|
|
|
|
loop: do {
|
2019-04-26 13:03:53 +00:00
|
|
|
|
let b = randBetween(w - _ONE, _TWO);
|
2019-04-19 07:42:28 +00:00
|
|
|
|
let z = modPow(b, m, w);
|
2019-04-23 14:57:06 +00:00
|
|
|
|
if (z === _ONE || z === w - _ONE)
|
2019-04-19 07:42:28 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
for (let j = 1; j < a; j++) {
|
2019-04-23 14:57:06 +00:00
|
|
|
|
z = modPow(z, _TWO, w);
|
|
|
|
|
if (z === w - _ONE)
|
2019-04-19 07:42:28 +00:00
|
|
|
|
continue loop;
|
2019-04-23 14:57:06 +00:00
|
|
|
|
if (z === _ONE)
|
2019-04-19 07:42:28 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
} while (--iterations);
|
|
|
|
|
|
|
|
|
|
return true;
|
2019-04-19 10:04:06 +00:00
|
|
|
|
}
|
2019-04-19 07:42:28 +00:00
|
|
|
|
|
|
|
|
|
exports.abs = abs;
|
2019-04-29 10:34:20 +00:00
|
|
|
|
exports.bitLength = bitLength;
|
2019-04-19 07:42:28 +00:00
|
|
|
|
exports.eGcd = eGcd;
|
|
|
|
|
exports.gcd = gcd;
|
|
|
|
|
exports.isProbablyPrime = isProbablyPrime;
|
|
|
|
|
exports.lcm = lcm;
|
|
|
|
|
exports.modInv = modInv;
|
|
|
|
|
exports.modPow = modPow;
|
|
|
|
|
exports.prime = prime;
|
|
|
|
|
exports.randBetween = randBetween;
|
2019-04-20 20:11:44 +00:00
|
|
|
|
exports.randBits = randBits;
|
2019-04-19 07:42:28 +00:00
|
|
|
|
exports.randBytes = randBytes;
|
2019-05-04 16:08:30 +00:00
|
|
|
|
exports.randBytesSync = randBytesSync;
|
2019-04-19 07:42:28 +00:00
|
|
|
|
exports.toZn = toZn;
|
|
|
|
|
|
|
|
|
|
return exports;
|
|
|
|
|
|
|
|
|
|
}({}));
|