From ace7d479eef105225d9a9b54a65a53dd9e7c5325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Hern=C3=A1ndez=20Serrano?= Date: Wed, 9 Oct 2019 14:56:11 +0200 Subject: [PATCH] added sync version of prime --- README.md | 24 +++++++++++-- dist/bigint-crypto-utils-latest.browser.js | 34 +++++++++++------- .../bigint-crypto-utils-latest.browser.min.js | 2 +- .../bigint-crypto-utils-latest.browser.mod.js | 35 ++++++++++++------- ...int-crypto-utils-latest.browser.mod.min.js | 2 +- dist/bigint-crypto-utils-latest.node.js | 28 ++++++++++++--- src/main.js | 27 +++++++++++--- test/browser/tests.js | 4 +-- test/prime.js | 4 +-- 9 files changed, 116 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 0ea9d02..360c62b 100644 --- a/README.md +++ b/README.md @@ -116,13 +116,17 @@ iterations of Miller-Rabin Probabilistic Primality Test (FIPS 186-4 C.3.1)

modPow(b, e, n)bigint

Modular exponentiation b**e mod n. Currently using the right-to-left binary method

-
prime(bitLength, iterations, sync)Promise | bigint
+
prime(bitLength, iterations, sync)Promise

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).

+
primeSync(bitLength, iterations)bigint
+

A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator. +The sync version is NOT RECOMMENDED since it won't use workers and thus it'll be slower and may freeze thw window in browser's javascript. Please consider using prime() instead.

+
randBetween(max, min)bigint

Returns a cryptographically secure random integer between [min,max]

@@ -281,7 +285,7 @@ Modular exponentiation b**e mod n. Currently using the right-to-left binary meth -## prime(bitLength, iterations, sync) ⇒ Promise \| bigint +## prime(bitLength, iterations, sync) ⇒ Promise 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). @@ -289,7 +293,7 @@ The node version can also use worker_threads if they are available (enabled by d and can be enabled at runtime executing node --experimental-worker with node >=10.5.0). **Kind**: global function -**Returns**: Promise \| bigint - A promise that resolves to a bigint probable prime of bitLength bits or a bigint if called in synchronous mode. +**Returns**: Promise - A promise that resolves to a bigint probable prime of bitLength bits. | Param | Type | Description | | --- | --- | --- | @@ -297,6 +301,20 @@ and can be enabled at runtime executing node --experimental-worker with node >=1 | iterations | number | The number of iterations for the Miller-Rabin Probabilistic Primality Test | | sync | boolean | NOT RECOMMENDED. Invoke the function synchronously. It won't use workers so it'll be slower and may freeze thw window in browser's javascript. | + + +## primeSync(bitLength, iterations) ⇒ bigint +A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator. +The sync version is NOT RECOMMENDED since it won't use workers and thus it'll be slower and may freeze thw window in browser's javascript. Please consider using prime() instead. + +**Kind**: global function +**Returns**: bigint - A bigint probable prime of bitLength bits. + +| Param | Type | Description | +| --- | --- | --- | +| bitLength | number | The required bit length for the generated prime | +| iterations | number | The number of iterations for the Miller-Rabin Probabilistic Primality Test | + ## randBetween(max, min) ⇒ bigint diff --git a/dist/bigint-crypto-utils-latest.browser.js b/dist/bigint-crypto-utils-latest.browser.js index 7afc65a..fc65dad 100644 --- a/dist/bigint-crypto-utils-latest.browser.js +++ b/dist/bigint-crypto-utils-latest.browser.js @@ -259,21 +259,11 @@ var bigintCryptoUtils = (function (exports) { * @param {number} iterations The number of iterations for the Miller-Rabin Probabilistic Primality Test * @param {boolean} sync NOT RECOMMENDED. Invoke the function synchronously. It won't use workers so it'll be slower and may freeze thw window in browser's javascript. * - * @returns {Promise|bigint} A promise that resolves to a bigint probable prime of bitLength bits or a bigint if called in synchronous mode. + * @returns {Promise} A promise that resolves to a bigint probable prime of bitLength bits. */ - function prime(bitLength, iterations = 16, sync = false) { + function prime(bitLength, iterations = 16) { if (bitLength < 1) throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`); - - if ( sync) { - let rnd = _ZERO; - do { - rnd = fromBuffer(randBytesSync(bitLength / 8, true)); - } while (!_isProbablyPrime(rnd, iterations)); - if(sync) - return rnd; - return new Promise((resolve) => { resolve(rnd); }); - } return new Promise((resolve) => { let workerList = []; const _onmessage = (msg, newWorker) => { @@ -320,6 +310,25 @@ var bigintCryptoUtils = (function (exports) { }); } + /** + * 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. + * + * @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 + * + * @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}`); + let rnd = _ZERO; + do { + rnd = fromBuffer(randBytesSync(bitLength / 8, true)); + } while (!_isProbablyPrime(rnd, iterations)); + return rnd; + } + /** * Returns a cryptographically secure random integer between [min,max] * @param {bigint} max Returned value will be <= max @@ -794,6 +803,7 @@ var bigintCryptoUtils = (function (exports) { exports.modInv = modInv; exports.modPow = modPow; exports.prime = prime; + exports.primeSync = primeSync; exports.randBetween = randBetween; exports.randBits = randBits; exports.randBytes = randBytes; diff --git a/dist/bigint-crypto-utils-latest.browser.min.js b/dist/bigint-crypto-utils-latest.browser.min.js index 42d6ff2..688bfdf 100644 --- a/dist/bigint-crypto-utils-latest.browser.min.js +++ b/dist/bigint-crypto-utils-latest.browser.min.js @@ -1 +1 @@ -var bigintCryptoUtils=function(a){'use strict';function c(b){return b=BigInt(b),b>=s?b:-b}function d(b){if(b=BigInt(b),b===t)return 1;let c=1;do c++;while((b>>=t)>t);return c}function e(c,d){if(c=BigInt(c),d=BigInt(d),c<=s|d<=s)return NaN;let e=s,f=t,g=t,h=s;for(;c!==s;){let a=d/c,b=d%c,i=e-g*a,j=f-h*a;d=c,c=b,e=g,f=h,g=i,h=j}return{b:d,x:e,y:f}}function f(d,e){if(d=c(d),e=c(e),d===s)return e;if(e===s)return d;let f=s;for(;!((d|e)&t);)d>>=t,e>>=t,f++;for(;!(d&t);)d>>=t;do{for(;!(e&t);)e>>=t;if(d>e){let a=d;d=e,e=a}e-=d}while(e);return d<{const e=new Worker(o());e.onmessage=a=>{e.terminate(),c(a.data.isPrime)},e.onmessageerror=a=>{d(a)},e.postMessage({rnd:a,iterations:b,id:0})})}function h(b,a){if(b==s|a<=s)return NaN;let c=e(m(b,a),a);return c.b===t?m(c.x,a):NaN}function i(a,d,f){if(f=BigInt(f),f===s)return NaN;if(f===t)return s;if(a=m(a,f),d=BigInt(d),d min");const c=a-b;let e,f=d(c);do{let a=k(f);e=n(a)}while(e>c);return e+b}function k(a,b=!1){var c=Math.ceil;if(1>a)throw new RangeError(`bitLength MUST be > 0 and it is ${a}`);const d=c(a/8);let e=l(d,!1);if(e[0]&=2**(a%8)-1,b){let b=a%8?2**(a%8-1):128;e[0]|=b}return e}function l(a,b=!1){if(1>a)throw new RangeError(`byteLength MUST be > 0 and it is ${a}`);let c;return c=new Uint8Array(a),self.crypto.getRandomValues(c),b&&(c[0]|=128),c}function m(b,c){return(c=BigInt(c),0>=c)?NaN:(b=BigInt(b)%c,0>b?b+c:b)}function n(a){let b=s;for(let c of a.values()){let a=BigInt(c);b=(b< {${a}})()`;const b=new Blob([a],{type:"text/javascript"});return window.URL.createObjectURL(b)}function q(c,b=16){if(c===u)return!0;if((c&t)===s||c===t)return!1;const e=[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 a=0;a=d?c:d},a.min=function(c,d){return c=BigInt(c),d=BigInt(d),c>=d?d:c},a.modInv=h,a.modPow=i,a.prime=function(a,b=16,c=!1){if(1>a)throw new RangeError(`bitLength MUST be > 0 and it is ${a}`);if(c){let d=s;do d=n(l(a/8,!0));while(!q(d,b));return c?d:new Promise(a=>{a(d)})}return new Promise(c=>{let d=[];const e=(e,f)=>{if(e.isPrime){for(let a=0;ae(a.data,b),d.push(b)}for(let e=0;ea)throw new RangeError(`byteLength MUST be > 0 and it is ${a}`);let c;return new Promise(function(d){c=new Uint8Array(a),self.crypto.getRandomValues(c),b&&(c[0]|=128),d(c)})},a.randBytesSync=l,a.toZn=m,a}({}); +var bigintCryptoUtils=function(a){'use strict';function c(b){return b=BigInt(b),b>=s?b:-b}function d(b){if(b=BigInt(b),b===t)return 1;let c=1;do c++;while((b>>=t)>t);return c}function e(c,d){if(c=BigInt(c),d=BigInt(d),c<=s|d<=s)return NaN;let e=s,f=t,g=t,h=s;for(;c!==s;){let a=d/c,b=d%c,i=e-g*a,j=f-h*a;d=c,c=b,e=g,f=h,g=i,h=j}return{b:d,x:e,y:f}}function f(d,e){if(d=c(d),e=c(e),d===s)return e;if(e===s)return d;let f=s;for(;!((d|e)&t);)d>>=t,e>>=t,f++;for(;!(d&t);)d>>=t;do{for(;!(e&t);)e>>=t;if(d>e){let a=d;d=e,e=a}e-=d}while(e);return d<{const e=new Worker(o());e.onmessage=a=>{e.terminate(),c(a.data.isPrime)},e.onmessageerror=a=>{d(a)},e.postMessage({rnd:a,iterations:b,id:0})})}function h(b,a){if(b==s|a<=s)return NaN;let c=e(m(b,a),a);return c.b===t?m(c.x,a):NaN}function i(a,d,f){if(f=BigInt(f),f===s)return NaN;if(f===t)return s;if(a=m(a,f),d=BigInt(d),d min");const c=a-b;let e,f=d(c);do{let a=k(f);e=n(a)}while(e>c);return e+b}function k(a,b=!1){var c=Math.ceil;if(1>a)throw new RangeError(`bitLength MUST be > 0 and it is ${a}`);const d=c(a/8);let e=l(d,!1);if(e[0]&=2**(a%8)-1,b){let b=a%8?2**(a%8-1):128;e[0]|=b}return e}function l(a,b=!1){if(1>a)throw new RangeError(`byteLength MUST be > 0 and it is ${a}`);let c;return c=new Uint8Array(a),self.crypto.getRandomValues(c),b&&(c[0]|=128),c}function m(b,c){return(c=BigInt(c),0>=c)?NaN:(b=BigInt(b)%c,0>b?b+c:b)}function n(a){let b=s;for(let c of a.values()){let a=BigInt(c);b=(b< {${a}})()`;const b=new Blob([a],{type:"text/javascript"});return window.URL.createObjectURL(b)}function q(c,b=16){if(c===u)return!0;if((c&t)===s||c===t)return!1;const e=[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 a=0;a=d?c:d},a.min=function(c,d){return c=BigInt(c),d=BigInt(d),c>=d?d:c},a.modInv=h,a.modPow=i,a.prime=function(a,b=16){if(1>a)throw new RangeError(`bitLength MUST be > 0 and it is ${a}`);return new Promise(c=>{let d=[];const e=(e,f)=>{if(e.isPrime){for(let a=0;ae(a.data,b),d.push(b)}for(let e=0;ea)throw new RangeError(`bitLength MUST be > 0 and it is ${a}`);let c=s;do c=n(l(a/8,!0));while(!q(c,b));return c},a.randBetween=j,a.randBits=k,a.randBytes=function(a,b=!1){if(1>a)throw new RangeError(`byteLength MUST be > 0 and it is ${a}`);let c;return new Promise(function(d){c=new Uint8Array(a),self.crypto.getRandomValues(c),b&&(c[0]|=128),d(c)})},a.randBytesSync=l,a.toZn=m,a}({}); diff --git a/dist/bigint-crypto-utils-latest.browser.mod.js b/dist/bigint-crypto-utils-latest.browser.mod.js index ff5e34c..a7472bf 100644 --- a/dist/bigint-crypto-utils-latest.browser.mod.js +++ b/dist/bigint-crypto-utils-latest.browser.mod.js @@ -256,21 +256,11 @@ function modPow(b, e, n) { * @param {number} iterations The number of iterations for the Miller-Rabin Probabilistic Primality Test * @param {boolean} sync NOT RECOMMENDED. Invoke the function synchronously. It won't use workers so it'll be slower and may freeze thw window in browser's javascript. * - * @returns {Promise|bigint} A promise that resolves to a bigint probable prime of bitLength bits or a bigint if called in synchronous mode. + * @returns {Promise} A promise that resolves to a bigint probable prime of bitLength bits. */ -function prime(bitLength, iterations = 16, sync = false) { +function prime(bitLength, iterations = 16) { if (bitLength < 1) throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`); - - if ( sync) { - let rnd = _ZERO; - do { - rnd = fromBuffer(randBytesSync(bitLength / 8, true)); - } while (!_isProbablyPrime(rnd, iterations)); - if(sync) - return rnd; - return new Promise((resolve) => { resolve(rnd); }); - } return new Promise((resolve) => { let workerList = []; const _onmessage = (msg, newWorker) => { @@ -317,6 +307,25 @@ function prime(bitLength, iterations = 16, sync = false) { }); } +/** + * 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. + * + * @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 + * + * @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}`); + let rnd = _ZERO; + do { + rnd = fromBuffer(randBytesSync(bitLength / 8, true)); + } while (!_isProbablyPrime(rnd, iterations)); + return rnd; +} + /** * Returns a cryptographically secure random integer between [min,max] * @param {bigint} max Returned value will be <= max @@ -780,4 +789,4 @@ function _isProbablyPrime(w, iterations = 16) { return true; } -export { abs, bitLength, eGcd, gcd, isProbablyPrime, lcm, max, min, modInv, modPow, prime, randBetween, randBits, randBytes, randBytesSync, toZn }; +export { abs, bitLength, eGcd, gcd, isProbablyPrime, lcm, max, min, modInv, modPow, prime, primeSync, randBetween, randBits, randBytes, randBytesSync, toZn }; diff --git a/dist/bigint-crypto-utils-latest.browser.mod.min.js b/dist/bigint-crypto-utils-latest.browser.mod.min.js index 3bb4db5..2ff798a 100644 --- a/dist/bigint-crypto-utils-latest.browser.mod.min.js +++ b/dist/bigint-crypto-utils-latest.browser.mod.min.js @@ -1 +1 @@ -const _ZERO=BigInt(0),_ONE=BigInt(1),_TWO=BigInt(2);function abs(b){return b=BigInt(b),b>=_ZERO?b:-b}function bitLength(b){if(b=BigInt(b),b===_ONE)return 1;let c=1;do c++;while((b>>=_ONE)>_ONE);return c}function eGcd(c,d){if(c=BigInt(c),d=BigInt(d),c<=_ZERO|d<=_ZERO)return NaN;let e=_ZERO,f=_ONE,g=_ONE,h=_ZERO;for(;c!==_ZERO;){let a=d/c,b=d%c,i=e-g*a,j=f-h*a;d=c,c=b,e=g,f=h,g=i,h=j}return{b:d,x:e,y:f}}function gcd(c,d){if(c=abs(c),d=abs(d),c===_ZERO)return d;if(d===_ZERO)return c;let e=_ZERO;for(;!((c|d)&_ONE);)c>>=_ONE,d>>=_ONE,e++;for(;!(c&_ONE);)c>>=_ONE;do{for(;!(d&_ONE);)d>>=_ONE;if(c>d){let a=c;c=d,d=a}d-=c}while(d);return c<{const e=new Worker(_isProbablyPrimeWorkerUrl());e.onmessage=a=>{e.terminate(),c(a.data.isPrime)},e.onmessageerror=a=>{d(a)},e.postMessage({rnd:a,iterations:b,id:0})})}function lcm(c,d){return c=BigInt(c),d=BigInt(d),c===_ZERO&&d===_ZERO?_ZERO:abs(c*d)/gcd(c,d)}function max(c,d){return c=BigInt(c),d=BigInt(d),c>=d?c:d}function min(c,d){return c=BigInt(c),d=BigInt(d),c>=d?d:c}function modInv(b,a){if(b==_ZERO|a<=_ZERO)return NaN;let c=eGcd(toZn(b,a),a);return c.b===_ONE?toZn(c.x,a):NaN}function modPow(a,c,d){if(d=BigInt(d),d===_ZERO)return NaN;if(d===_ONE)return _ZERO;if(a=toZn(a,d),c=BigInt(c),c<_ZERO)return modInv(modPow(a,abs(c),d),d);let f=_ONE;for(;0a)throw new RangeError(`bitLength MUST be > 0 and it is ${a}`);if(c){let d=_ZERO;do d=fromBuffer(randBytesSync(a/8,!0));while(!_isProbablyPrime(d,b));return c?d:new Promise(a=>{a(d)})}return new Promise(c=>{let d=[];const e=(e,f)=>{if(e.isPrime){for(let a=0;ae(a.data,b),d.push(b)}for(let e=0;e min");const c=a-b;let d,e=bitLength(c);do{let a=randBits(e);d=fromBuffer(a)}while(d>c);return d+b}function randBits(a,b=!1){var c=Math.ceil;if(1>a)throw new RangeError(`bitLength MUST be > 0 and it is ${a}`);const d=c(a/8);let e=randBytesSync(d,!1);if(e[0]&=2**(a%8)-1,b){let b=a%8?2**(a%8-1):128;e[0]|=b}return e}function randBytes(a,b=!1){if(1>a)throw new RangeError(`byteLength MUST be > 0 and it is ${a}`);let c;return new Promise(function(d){c=new Uint8Array(a),self.crypto.getRandomValues(c),b&&(c[0]|=128),d(c)})}function randBytesSync(a,b=!1){if(1>a)throw new RangeError(`byteLength MUST be > 0 and it is ${a}`);let c;return c=new Uint8Array(a),self.crypto.getRandomValues(c),b&&(c[0]|=128),c}function toZn(b,c){return(c=BigInt(c),0>=c)?NaN:(b=BigInt(b)%c,0>b?b+c:b)}function fromBuffer(a){let b=_ZERO;for(let c of a.values()){let a=BigInt(c);b=(b< {${a}})()`;const b=new Blob([a],{type:"text/javascript"});return window.URL.createObjectURL(b)}function _isProbablyPrime(c,b=16){if(c===_TWO)return!0;if((c&_ONE)===_ZERO||c===_ONE)return!1;const e=[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 a=0;a=_ZERO?b:-b}function bitLength(b){if(b=BigInt(b),b===_ONE)return 1;let c=1;do c++;while((b>>=_ONE)>_ONE);return c}function eGcd(c,d){if(c=BigInt(c),d=BigInt(d),c<=_ZERO|d<=_ZERO)return NaN;let e=_ZERO,f=_ONE,g=_ONE,h=_ZERO;for(;c!==_ZERO;){let a=d/c,b=d%c,i=e-g*a,j=f-h*a;d=c,c=b,e=g,f=h,g=i,h=j}return{b:d,x:e,y:f}}function gcd(c,d){if(c=abs(c),d=abs(d),c===_ZERO)return d;if(d===_ZERO)return c;let e=_ZERO;for(;!((c|d)&_ONE);)c>>=_ONE,d>>=_ONE,e++;for(;!(c&_ONE);)c>>=_ONE;do{for(;!(d&_ONE);)d>>=_ONE;if(c>d){let a=c;c=d,d=a}d-=c}while(d);return c<{const e=new Worker(_isProbablyPrimeWorkerUrl());e.onmessage=a=>{e.terminate(),c(a.data.isPrime)},e.onmessageerror=a=>{d(a)},e.postMessage({rnd:a,iterations:b,id:0})})}function lcm(c,d){return c=BigInt(c),d=BigInt(d),c===_ZERO&&d===_ZERO?_ZERO:abs(c*d)/gcd(c,d)}function max(c,d){return c=BigInt(c),d=BigInt(d),c>=d?c:d}function min(c,d){return c=BigInt(c),d=BigInt(d),c>=d?d:c}function modInv(b,a){if(b==_ZERO|a<=_ZERO)return NaN;let c=eGcd(toZn(b,a),a);return c.b===_ONE?toZn(c.x,a):NaN}function modPow(a,c,d){if(d=BigInt(d),d===_ZERO)return NaN;if(d===_ONE)return _ZERO;if(a=toZn(a,d),c=BigInt(c),c<_ZERO)return modInv(modPow(a,abs(c),d),d);let f=_ONE;for(;0a)throw new RangeError(`bitLength MUST be > 0 and it is ${a}`);return new Promise(c=>{let d=[];const e=(e,f)=>{if(e.isPrime){for(let a=0;ae(a.data,b),d.push(b)}for(let e=0;ea)throw new RangeError(`bitLength MUST be > 0 and it is ${a}`);let c=_ZERO;do c=fromBuffer(randBytesSync(a/8,!0));while(!_isProbablyPrime(c,b));return c}function randBetween(a,b=_ONE){if(a<=b)throw new Error("max must be > min");const c=a-b;let d,e=bitLength(c);do{let a=randBits(e);d=fromBuffer(a)}while(d>c);return d+b}function randBits(a,b=!1){var c=Math.ceil;if(1>a)throw new RangeError(`bitLength MUST be > 0 and it is ${a}`);const d=c(a/8);let e=randBytesSync(d,!1);if(e[0]&=2**(a%8)-1,b){let b=a%8?2**(a%8-1):128;e[0]|=b}return e}function randBytes(a,b=!1){if(1>a)throw new RangeError(`byteLength MUST be > 0 and it is ${a}`);let c;return new Promise(function(d){c=new Uint8Array(a),self.crypto.getRandomValues(c),b&&(c[0]|=128),d(c)})}function randBytesSync(a,b=!1){if(1>a)throw new RangeError(`byteLength MUST be > 0 and it is ${a}`);let c;return c=new Uint8Array(a),self.crypto.getRandomValues(c),b&&(c[0]|=128),c}function toZn(b,c){return(c=BigInt(c),0>=c)?NaN:(b=BigInt(b)%c,0>b?b+c:b)}function fromBuffer(a){let b=_ZERO;for(let c of a.values()){let a=BigInt(c);b=(b< {${a}})()`;const b=new Blob([a],{type:"text/javascript"});return window.URL.createObjectURL(b)}function _isProbablyPrime(c,b=16){if(c===_TWO)return!0;if((c&_ONE)===_ZERO||c===_ONE)return!1;const e=[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 a=0;a 0 and it is ${bitLength}`); - if (( !_useWorkers) || sync) { + if ( !_useWorkers) { let rnd = _ZERO; do { rnd = fromBuffer(randBytesSync(bitLength / 8, true)); } while (!_isProbablyPrime(rnd, iterations)); - if(sync) - return rnd; return new Promise((resolve) => { resolve(rnd); }); } return new Promise((resolve) => { @@ -328,6 +326,25 @@ function prime(bitLength, iterations = 16, sync = false) { }); } +/** + * 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. + * + * @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 + * + * @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}`); + let rnd = _ZERO; + do { + rnd = fromBuffer(randBytesSync(bitLength / 8, true)); + } while (!_isProbablyPrime(rnd, iterations)); + return rnd; +} + /** * Returns a cryptographically secure random integer between [min,max] * @param {bigint} max Returned value will be <= max @@ -812,6 +829,7 @@ exports.min = min; exports.modInv = modInv; exports.modPow = modPow; exports.prime = prime; +exports.primeSync = primeSync; exports.randBetween = randBetween; exports.randBits = randBits; exports.randBytes = randBytes; diff --git a/src/main.js b/src/main.js index 86226c2..66cd41b 100644 --- a/src/main.js +++ b/src/main.js @@ -283,19 +283,17 @@ export function modPow(b, e, n) { * @param {number} iterations The number of iterations for the Miller-Rabin Probabilistic Primality Test * @param {boolean} sync NOT RECOMMENDED. Invoke the function synchronously. It won't use workers so it'll be slower and may freeze thw window in browser's javascript. * - * @returns {Promise|bigint} A promise that resolves to a bigint probable prime of bitLength bits or a bigint if called in synchronous mode. + * @returns {Promise} A promise that resolves to a bigint probable prime of bitLength bits. */ -export function prime(bitLength, iterations = 16, sync = false) { +export function prime(bitLength, iterations = 16) { if (bitLength < 1) throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`); - if ((!process.browser && !_useWorkers) || sync) { + if (!process.browser && !_useWorkers) { let rnd = _ZERO; do { rnd = fromBuffer(randBytesSync(bitLength / 8, true)); } while (!_isProbablyPrime(rnd, iterations)); - if(sync) - return rnd; return new Promise((resolve) => { resolve(rnd); }); } return new Promise((resolve) => { @@ -352,6 +350,25 @@ export function prime(bitLength, iterations = 16, sync = false) { }); } +/** + * 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. + * + * @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 + * + * @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}`); + let rnd = _ZERO; + do { + rnd = fromBuffer(randBytesSync(bitLength / 8, true)); + } while (!_isProbablyPrime(rnd, iterations)); + return rnd; +} + /** * Returns a cryptographically secure random integer between [min,max] * @param {bigint} max Returned value will be <= max diff --git a/test/browser/tests.js b/test/browser/tests.js index d818531..83287b2 100644 --- a/test/browser/tests.js +++ b/test/browser/tests.js @@ -537,9 +537,9 @@ describe('prime', function () { }); }); } - describe('Testing sync (NOT-RECOMMENDED) version of prime', function() { + describe('Testing sync (NOT-RECOMMENDED) version: primeSync()', function() { it('should return a random 1024-bits probable prime', function () { - const prime = bigintCryptoUtils.prime(1024, 16, true); + const prime = bigintCryptoUtils.primeSync(1024, 16); const primeBitLength = bigintCryptoUtils.bitLength(prime); chai.expect(primeBitLength).to.equal(1024); }); diff --git a/test/prime.js b/test/prime.js index a15a924..87adf61 100644 --- a/test/prime.js +++ b/test/prime.js @@ -24,9 +24,9 @@ describe('prime', function () { }); }); } - describe('Testing sync (NOT-RECOMMENDED) version of prime', function() { + describe('Testing sync (NOT-RECOMMENDED) version: primeSync()', function() { it('should return a random 1024-bits probable prime', function () { - const prime = bigintCryptoUtils.prime(1024, 16, true); + const prime = bigintCryptoUtils.primeSync(1024, 16); const primeBitLength = bigintCryptoUtils.bitLength(prime); chai.expect(primeBitLength).to.equal(1024); });