If it is not truly async then is sync

This commit is contained in:
juanelas 2019-04-26 15:03:53 +02:00
parent 292c78dc5a
commit 3f571c9dd6
7 changed files with 210 additions and 225 deletions

View File

@ -114,13 +114,13 @@ 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 &gt;=10.5.0).</p>
</dd>
<dt><a href="#randBetween">randBetween(max, min)</a><code>Promise</code></dt>
<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</code></dt>
<dt><a href="#randBits">randBits(bitLength, forceLength)</a><code>Buffer</code> | <code>Uint8Array</code></dt>
<dd><p>Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()</p>
</dd>
<dt><a href="#randBytes">randBytes(byteLength, forceLength)</a><code>Promise</code></dt>
<dt><a href="#randBytes">randBytes(byteLength, forceLength)</a><code>Buffer</code> | <code>Uint8Array</code></dt>
<dd><p>Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()</p>
</dd>
<dt><a href="#toZn">toZn(a, n)</a><code>bigint</code></dt>
@ -247,11 +247,11 @@ and can be enabled at runtime executing node --experimental-worker with node >=1
<a name="randBetween"></a>
## randBetween(max, min) ⇒ <code>Promise</code>
## randBetween(max, min) ⇒ <code>bigint</code>
Returns a cryptographically secure random integer between [min,max]
**Kind**: global function
**Returns**: <code>Promise</code> - A promise that resolves to a cryptographically secure random bigint between [min,max]
**Returns**: <code>bigint</code> - A cryptographically secure random bigint between [min,max]
| Param | Type | Description |
| --- | --- | --- |
@ -260,11 +260,11 @@ Returns a cryptographically secure random integer between [min,max]
<a name="randBits"></a>
## randBits(bitLength, forceLength) ⇒ <code>Promise</code>
## randBits(bitLength, forceLength) ⇒ <code>Buffer</code> \| <code>Uint8Array</code>
Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
**Kind**: global function
**Returns**: <code>Promise</code> - A promise that resolves to a Buffer/UInt8Array filled with cryptographically secure random bits
**Returns**: <code>Buffer</code> \| <code>Uint8Array</code> - A Buffer/UInt8Array filled with cryptographically secure random bits
| Param | Type | Description |
| --- | --- | --- |
@ -273,11 +273,11 @@ Secure random bits for both node and browsers. Node version uses crypto.randomFi
<a name="randBytes"></a>
## randBytes(byteLength, forceLength) ⇒ <code>Promise</code>
## randBytes(byteLength, forceLength) ⇒ <code>Buffer</code> \| <code>Uint8Array</code>
Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
**Kind**: global function
**Returns**: <code>Promise</code> - A promise that resolves to a Buffer/UInt8Array filled with cryptographically secure random bytes
**Returns**: <code>Buffer</code> \| <code>Uint8Array</code> - A Buffer/UInt8Array filled with cryptographically secure random bytes
| Param | Type | Description |
| --- | --- | --- |

View File

@ -99,7 +99,7 @@ var bigintCryptoUtils = (function (exports) {
async function isProbablyPrime(w, iterations = 16) {
{ // browser
return new Promise((resolve, reject) => {
let worker = new Worker(_isProbablyPrimeWorkerURL());
let worker = new Worker(_isProbablyPrimeWorkerUrl());
worker.onmessage = (event) => {
worker.terminate();
@ -192,7 +192,7 @@ var bigintCryptoUtils = (function (exports) {
*
* @returns {Promise} A promise that resolves to a bigint probable prime of bitLength bits
*/
async function prime(bitLength, iterations = 16) {
function prime(bitLength, iterations = 16) {
return new Promise((resolve) => {
let workerList = [];
const _onmessage = (msg, newWorker) => {
@ -206,7 +206,7 @@ var bigintCryptoUtils = (function (exports) {
}
resolve(msg.value);
} else { // if a composite is found, make the worker test another random number
randBits(bitLength, true).then((buf) => {
let buf = randBits(bitLength, true);
let rnd = fromBuffer(buf);
try {
newWorker.postMessage({
@ -217,11 +217,10 @@ var bigintCryptoUtils = (function (exports) {
} catch (error) {
// The worker has already terminated. There is nothing to handle here
}
});
}
};
{ //browser
let workerURL = _isProbablyPrimeWorkerURL();
let workerURL = _isProbablyPrimeWorkerUrl();
for (let i = 0; i < self.navigator.hardwareConcurrency; i++) {
let newWorker = new Worker(workerURL);
newWorker.onmessage = (event) => _onmessage(event.data, newWorker);
@ -229,14 +228,13 @@ var bigintCryptoUtils = (function (exports) {
}
}
for (let i = 0; i < workerList.length; i++) {
randBits(bitLength, true).then((buf) => {
let buf = randBits(bitLength, true);
let rnd = fromBuffer(buf);
workerList[i].postMessage({
'rnd': rnd,
'iterations': iterations,
'id': i
});
});
}
});
}
@ -246,15 +244,15 @@ var bigintCryptoUtils = (function (exports) {
* @param {bigint} max Returned value will be <= max
* @param {bigint} min Returned value will be >= min
*
* @returns {Promise} A promise that resolves to a cryptographically secure random bigint between [min,max]
* @returns {bigint} A cryptographically secure random bigint between [min,max]
*/
async function randBetween(max, min = _ONE) {
function randBetween(max, min = _ONE) {
if (max <= min) throw new Error('max must be > min');
const interval = max - min;
let bitLen = bitLength(interval);
let rnd;
do {
let buf = await randBits(bitLen);
let buf = randBits(bitLen);
rnd = fromBuffer(buf);
} while (rnd > interval);
return rnd + min;
@ -266,11 +264,11 @@ var bigintCryptoUtils = (function (exports) {
* @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
*
* @returns {Promise} A promise that resolves to a Buffer/UInt8Array filled with cryptographically secure random bits
* @returns {Buffer|Uint8Array} A Buffer/UInt8Array filled with cryptographically secure random bits
*/
async function randBits(bitLength, forceLength = false) {
function randBits(bitLength, forceLength = false) {
const byteLength = Math.ceil(bitLength / 8);
let rndBytes = await randBytes(byteLength, false);
let rndBytes = randBytes(byteLength, false);
// Fill with 0's the extra birs
rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1);
if (forceLength) {
@ -286,21 +284,18 @@ var bigintCryptoUtils = (function (exports) {
* @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 {Promise} A promise that resolves to a Buffer/UInt8Array filled with cryptographically secure random bytes
* @returns {Buffer|Uint8Array} A Buffer/UInt8Array filled with cryptographically secure random bytes
*/
async function randBytes(byteLength, forceLength = false) {
return new Promise((resolve) => {
function randBytes(byteLength, forceLength = false) {
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;
resolve(buf);
}
});
return buf;
}
/**
@ -337,11 +332,11 @@ var bigintCryptoUtils = (function (exports) {
return bits;
}
function _isProbablyPrimeWorkerURL() {
function _isProbablyPrimeWorkerUrl() {
// Let's us first add all the required functions
let workerCode = `'use strict';const _ZERO = BigInt(0);const _ONE = BigInt(1);const _TWO = BigInt(2);const eGcd = ${eGcd.toString()};const modInv = ${modInv.toString()};const modPow = ${modPow.toString()};const toZn = ${toZn.toString()};const randBits = ${randBits.toString()};const randBytes = ${randBytes.toString()};const randBetween = ${randBetween.toString()};const isProbablyPrime = ${_isProbablyPrime.toString()};${bitLength.toString()}${fromBuffer.toString()}`;
const _onmessage = async function (event) { // Let's start once we are called
const onmessage = async function (event) { // Let's start once we are called
// event.data = {rnd: <bigint>, iterations: <number>}
const isPrime = await isProbablyPrime(event.data.rnd, event.data.iterations);
postMessage({
@ -350,16 +345,19 @@ var bigintCryptoUtils = (function (exports) {
'id': event.data.id
});
};
workerCode += `onmessage = ${_onmessage.toString()};`;
workerCode += `onmessage = ${onmessage.toString()};`;
return _workerUrl(workerCode);
}
function _workerUrl(workerCode) {
workerCode = `(() => {${workerCode}})()`; // encapsulate IIFE
var _blob = new Blob([workerCode], { type: 'text/javascript' });
return window.URL.createObjectURL(_blob);
}
async function _isProbablyPrime(w, iterations = 16) {
function _isProbablyPrime(w, iterations = 16) {
/*
PREFILTERING. Even values but 2 are not primes, so don't test.
1 is not a prime and the M-R algorithm needs w>1.
@ -660,7 +658,7 @@ var bigintCryptoUtils = (function (exports) {
let m = (w - _ONE) / (_TWO ** a);
loop: do {
let b = await randBetween(w - _ONE, _TWO);
let b = randBetween(w - _ONE, _TWO);
let z = modPow(b, m, w);
if (z === _ONE || z === w - _ONE)
continue;

View File

@ -1 +1 @@
var bigintCryptoUtils=function(a){'use strict';function c(b){return b=BigInt(b),b>=q?b:-b}function d(c,d){c=BigInt(c),d=BigInt(d);let e=q,f=r,g=r,h=q;for(;c!==q;){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 e(d,e){d=c(d),e=c(e);let f=q;for(;!((d|e)&r);)d>>=r,e>>=r,f++;for(;!(d&r);)d>>=r;do{for(;!(e&r);)e>>=r;if(d>e){let a=d;d=e,e=a}e-=d}while(e);return d<<f}async function f(a,b=16){return new Promise((c,d)=>{let 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 g(b,a){let c=d(b,a);return c.b===r?l(c.x,a):null}function h(d,e,f){if(f=BigInt(f),d=l(d,f),e=BigInt(e),e<q)return g(h(d,c(e),f),f);let i=r,j=d;for(;0<e;){var k=e%s;e/=s,k==r&&(i*=j,i%=f),j*=j,j%=f}return i}async function i(a,b=r){if(a<=b)throw new Error("max must be > min");const c=a-b;let d,e=n(c);do{let a=await j(e);d=m(a)}while(d>c);return d+b}async function j(a,b=!1){var c=Math.ceil;const d=c(a/8);let e=await k(d,!1);if(e[0]&=2**(a%8)-1,b){let b=a%8?2**(a%8-1):128;e[0]|=b}return e}async function k(a,b=!1){return new Promise(c=>{let d;d=new Uint8Array(a),self.crypto.getRandomValues(d),b&&(d[0]|=128),c(d)})}function l(b,c){return c=BigInt(c),b=BigInt(b)%c,0>b?b+c:b}function m(a){let b=q;for(let c of a.values()){let a=BigInt(c);b=(b<<BigInt(8))+a}return b}function n(b){let c=1;do c++;while((b>>=r)>r);return c}function o(){let a=`'use strict';const _ZERO = BigInt(0);const _ONE = BigInt(1);const _TWO = BigInt(2);const eGcd = ${d.toString()};const modInv = ${g.toString()};const modPow = ${h.toString()};const toZn = ${l.toString()};const randBits = ${j.toString()};const randBytes = ${k.toString()};const randBetween = ${i.toString()};const isProbablyPrime = ${p.toString()};${n.toString()}${m.toString()}`;a+=`onmessage = ${async function(a){const b=await f(a.data.rnd,a.data.iterations);postMessage({isPrime:b,value:a.data.rnd,id:a.data.id})}.toString()};`,a=`(() => {${a}})()`;var b=new Blob([a],{type:"text/javascript"});return window.URL.createObjectURL(b)}async function p(c,b=16){if(c===s)return!0;if((c&r)===q||c===r)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<e.length&&BigInt(e[a])<=c;a++){const b=BigInt(e[a]);if(c===b)return!0;if(c%b===q)return!1}let f=q,g=c-r;for(;g%s===q;)g/=s,++f;let j=(c-r)/s**f;loop:do{let a=await i(c-r,s),b=h(a,j,c);if(b===r||b===c-r)continue;for(let a=1;a<f;a++){if(b=h(b,s,c),b===c-r)continue loop;if(b===r)break}return!1}while(--b);return!0}const q=BigInt(0),r=BigInt(1),s=BigInt(2);return a.abs=c,a.eGcd=d,a.gcd=e,a.isProbablyPrime=f,a.lcm=function(d,f){return d=BigInt(d),f=BigInt(f),c(d*f)/e(d,f)},a.modInv=g,a.modPow=h,a.prime=async function(a,b=16){return new Promise(c=>{let d=[];const e=(e,f)=>{if(e.isPrime){for(let a=0;a<d.length;a++)d[a].terminate();for(;d.length;)d.pop();c(e.value)}else j(a,!0).then(a=>{let c=m(a);try{f.postMessage({rnd:c,iterations:b,id:e.id})}catch(a){}})};{let a=o();for(let b,c=0;c<self.navigator.hardwareConcurrency;c++)b=new Worker(a),b.onmessage=a=>e(a.data,b),d.push(b)}for(let e=0;e<d.length;e++)j(a,!0).then(a=>{let c=m(a);d[e].postMessage({rnd:c,iterations:b,id:e})})})},a.randBetween=i,a.randBits=j,a.randBytes=k,a.toZn=l,a}({});
var bigintCryptoUtils=function(a){'use strict';function c(b){return b=BigInt(b),b>=r?b:-b}function d(c,d){c=BigInt(c),d=BigInt(d);let e=r,f=s,g=s,h=r;for(;c!==r;){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 e(d,e){d=c(d),e=c(e);let f=r;for(;!((d|e)&s);)d>>=s,e>>=s,f++;for(;!(d&s);)d>>=s;do{for(;!(e&s);)e>>=s;if(d>e){let a=d;d=e,e=a}e-=d}while(e);return d<<f}async function f(a,b=16){return new Promise((c,d)=>{let 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 g(b,a){let c=d(b,a);return c.b===s?l(c.x,a):null}function h(d,e,f){if(f=BigInt(f),d=l(d,f),e=BigInt(e),e<r)return g(h(d,c(e),f),f);let i=s,j=d;for(;0<e;){var k=e%t;e/=t,k==s&&(i*=j,i%=f),j*=j,j%=f}return i}function i(a,b=s){if(a<=b)throw new Error("max must be > min");const c=a-b;let d,e=n(c);do{let a=j(e);d=m(a)}while(d>c);return d+b}function j(a,b=!1){var c=Math.ceil;const d=c(a/8);let e=k(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 k(a,b=!1){let c;return c=new Uint8Array(a),self.crypto.getRandomValues(c),b&&(c[0]|=128),c}function l(b,c){return c=BigInt(c),b=BigInt(b)%c,0>b?b+c:b}function m(a){let b=r;for(let c of a.values()){let a=BigInt(c);b=(b<<BigInt(8))+a}return b}function n(b){let c=1;do c++;while((b>>=s)>s);return c}function o(){let a=`'use strict';const _ZERO = BigInt(0);const _ONE = BigInt(1);const _TWO = BigInt(2);const eGcd = ${d.toString()};const modInv = ${g.toString()};const modPow = ${h.toString()};const toZn = ${l.toString()};const randBits = ${j.toString()};const randBytes = ${k.toString()};const randBetween = ${i.toString()};const isProbablyPrime = ${q.toString()};${n.toString()}${m.toString()}`;return a+=`onmessage = ${async function(a){const b=await f(a.data.rnd,a.data.iterations);postMessage({isPrime:b,value:a.data.rnd,id:a.data.id})}.toString()};`,p(a)}function p(a){a=`(() => {${a}})()`;var b=new Blob([a],{type:"text/javascript"});return window.URL.createObjectURL(b)}function q(c,b=16){if(c===t)return!0;if((c&s)===r||c===s)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<e.length&&BigInt(e[a])<=c;a++){const b=BigInt(e[a]);if(c===b)return!0;if(c%b===r)return!1}let f=r,g=c-s;for(;g%t===r;)g/=t,++f;let j=(c-s)/t**f;loop:do{let a=i(c-s,t),b=h(a,j,c);if(b===s||b===c-s)continue;for(let a=1;a<f;a++){if(b=h(b,t,c),b===c-s)continue loop;if(b===s)break}return!1}while(--b);return!0}const r=BigInt(0),s=BigInt(1),t=BigInt(2);return a.abs=c,a.eGcd=d,a.gcd=e,a.isProbablyPrime=f,a.lcm=function(d,f){return d=BigInt(d),f=BigInt(f),c(d*f)/e(d,f)},a.modInv=g,a.modPow=h,a.prime=function(a,b=16){return new Promise(c=>{let d=[];const e=(e,f)=>{if(e.isPrime){for(let a=0;a<d.length;a++)d[a].terminate();for(;d.length;)d.pop();c(e.value)}else{let c=j(a,!0),d=m(c);try{f.postMessage({rnd:d,iterations:b,id:e.id})}catch(a){}}};{let a=o();for(let b,c=0;c<self.navigator.hardwareConcurrency;c++)b=new Worker(a),b.onmessage=a=>e(a.data,b),d.push(b)}for(let e=0;e<d.length;e++){let c=j(a,!0),f=m(c);d[e].postMessage({rnd:f,iterations:b,id:e})}})},a.randBetween=i,a.randBits=j,a.randBytes=k,a.toZn=l,a}({});

View File

@ -96,7 +96,7 @@ function gcd(a, b) {
async function isProbablyPrime(w, iterations = 16) {
{ // browser
return new Promise((resolve, reject) => {
let worker = new Worker(_isProbablyPrimeWorkerURL());
let worker = new Worker(_isProbablyPrimeWorkerUrl());
worker.onmessage = (event) => {
worker.terminate();
@ -189,7 +189,7 @@ function modPow(a, b, n) {
*
* @returns {Promise} A promise that resolves to a bigint probable prime of bitLength bits
*/
async function prime(bitLength, iterations = 16) {
function prime(bitLength, iterations = 16) {
return new Promise((resolve) => {
let workerList = [];
const _onmessage = (msg, newWorker) => {
@ -203,7 +203,7 @@ async function prime(bitLength, iterations = 16) {
}
resolve(msg.value);
} else { // if a composite is found, make the worker test another random number
randBits(bitLength, true).then((buf) => {
let buf = randBits(bitLength, true);
let rnd = fromBuffer(buf);
try {
newWorker.postMessage({
@ -214,11 +214,10 @@ async function prime(bitLength, iterations = 16) {
} catch (error) {
// The worker has already terminated. There is nothing to handle here
}
});
}
};
{ //browser
let workerURL = _isProbablyPrimeWorkerURL();
let workerURL = _isProbablyPrimeWorkerUrl();
for (let i = 0; i < self.navigator.hardwareConcurrency; i++) {
let newWorker = new Worker(workerURL);
newWorker.onmessage = (event) => _onmessage(event.data, newWorker);
@ -226,14 +225,13 @@ async function prime(bitLength, iterations = 16) {
}
}
for (let i = 0; i < workerList.length; i++) {
randBits(bitLength, true).then((buf) => {
let buf = randBits(bitLength, true);
let rnd = fromBuffer(buf);
workerList[i].postMessage({
'rnd': rnd,
'iterations': iterations,
'id': i
});
});
}
});
}
@ -243,15 +241,15 @@ async function prime(bitLength, iterations = 16) {
* @param {bigint} max Returned value will be <= max
* @param {bigint} min Returned value will be >= min
*
* @returns {Promise} A promise that resolves to a cryptographically secure random bigint between [min,max]
* @returns {bigint} A cryptographically secure random bigint between [min,max]
*/
async function randBetween(max, min = _ONE) {
function randBetween(max, min = _ONE) {
if (max <= min) throw new Error('max must be > min');
const interval = max - min;
let bitLen = bitLength(interval);
let rnd;
do {
let buf = await randBits(bitLen);
let buf = randBits(bitLen);
rnd = fromBuffer(buf);
} while (rnd > interval);
return rnd + min;
@ -263,11 +261,11 @@ async function randBetween(max, min = _ONE) {
* @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
*
* @returns {Promise} A promise that resolves to a Buffer/UInt8Array filled with cryptographically secure random bits
* @returns {Buffer|Uint8Array} A Buffer/UInt8Array filled with cryptographically secure random bits
*/
async function randBits(bitLength, forceLength = false) {
function randBits(bitLength, forceLength = false) {
const byteLength = Math.ceil(bitLength / 8);
let rndBytes = await randBytes(byteLength, false);
let rndBytes = randBytes(byteLength, false);
// Fill with 0's the extra birs
rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1);
if (forceLength) {
@ -283,21 +281,18 @@ async function randBits(bitLength, forceLength = false) {
* @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 {Promise} A promise that resolves to a Buffer/UInt8Array filled with cryptographically secure random bytes
* @returns {Buffer|Uint8Array} A Buffer/UInt8Array filled with cryptographically secure random bytes
*/
async function randBytes(byteLength, forceLength = false) {
return new Promise((resolve) => {
function randBytes(byteLength, forceLength = false) {
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;
resolve(buf);
}
});
return buf;
}
/**
@ -334,11 +329,11 @@ function bitLength(a) {
return bits;
}
function _isProbablyPrimeWorkerURL() {
function _isProbablyPrimeWorkerUrl() {
// Let's us first add all the required functions
let workerCode = `'use strict';const _ZERO = BigInt(0);const _ONE = BigInt(1);const _TWO = BigInt(2);const eGcd = ${eGcd.toString()};const modInv = ${modInv.toString()};const modPow = ${modPow.toString()};const toZn = ${toZn.toString()};const randBits = ${randBits.toString()};const randBytes = ${randBytes.toString()};const randBetween = ${randBetween.toString()};const isProbablyPrime = ${_isProbablyPrime.toString()};${bitLength.toString()}${fromBuffer.toString()}`;
const _onmessage = async function (event) { // Let's start once we are called
const onmessage = async function (event) { // Let's start once we are called
// event.data = {rnd: <bigint>, iterations: <number>}
const isPrime = await isProbablyPrime(event.data.rnd, event.data.iterations);
postMessage({
@ -347,16 +342,19 @@ function _isProbablyPrimeWorkerURL() {
'id': event.data.id
});
};
workerCode += `onmessage = ${_onmessage.toString()};`;
workerCode += `onmessage = ${onmessage.toString()};`;
return _workerUrl(workerCode);
}
function _workerUrl(workerCode) {
workerCode = `(() => {${workerCode}})()`; // encapsulate IIFE
var _blob = new Blob([workerCode], { type: 'text/javascript' });
return window.URL.createObjectURL(_blob);
}
async function _isProbablyPrime(w, iterations = 16) {
function _isProbablyPrime(w, iterations = 16) {
/*
PREFILTERING. Even values but 2 are not primes, so don't test.
1 is not a prime and the M-R algorithm needs w>1.
@ -657,7 +655,7 @@ async function _isProbablyPrime(w, iterations = 16) {
let m = (w - _ONE) / (_TWO ** a);
loop: do {
let b = await randBetween(w - _ONE, _TWO);
let b = randBetween(w - _ONE, _TWO);
let z = modPow(b, m, w);
if (z === _ONE || z === w - _ONE)
continue;

View File

@ -1 +1 @@
function abs(b){return b=BigInt(b),b>=_ZERO?b:-b}function eGcd(c,d){c=BigInt(c),d=BigInt(d);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){c=abs(c),d=abs(d);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<<e}async function isProbablyPrime(a,b=16){return new Promise((c,d)=>{let 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),abs(c*d)/gcd(c,d)}function modInv(b,a){let c=eGcd(b,a);return c.b===_ONE?toZn(c.x,a):null}function modPow(c,d,e){if(e=BigInt(e),c=toZn(c,e),d=BigInt(d),d<_ZERO)return modInv(modPow(c,abs(d),e),e);let f=_ONE,g=c;for(;0<d;){var h=d%_TWO;d/=_TWO,h==_ONE&&(f*=g,f%=e),g*=g,g%=e}return f}async function prime(a,b=16){return new Promise(c=>{let d=[];const e=(e,f)=>{if(e.isPrime){for(let a=0;a<d.length;a++)d[a].terminate();for(;d.length;)d.pop();c(e.value)}else randBits(a,!0).then(a=>{let c=fromBuffer(a);try{f.postMessage({rnd:c,iterations:b,id:e.id})}catch(a){}})};{let a=_isProbablyPrimeWorkerURL();for(let b,c=0;c<self.navigator.hardwareConcurrency;c++)b=new Worker(a),b.onmessage=a=>e(a.data,b),d.push(b)}for(let e=0;e<d.length;e++)randBits(a,!0).then(a=>{let c=fromBuffer(a);d[e].postMessage({rnd:c,iterations:b,id:e})})})}async 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=await randBits(e);d=fromBuffer(a)}while(d>c);return d+b}async function randBits(a,b=!1){var c=Math.ceil;const d=c(a/8);let e=await randBytes(d,!1);if(e[0]&=2**(a%8)-1,b){let b=a%8?2**(a%8-1):128;e[0]|=b}return e}async function randBytes(a,b=!1){return new Promise(c=>{let d;d=new Uint8Array(a),self.crypto.getRandomValues(d),b&&(d[0]|=128),c(d)})}function toZn(b,c){return c=BigInt(c),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<<BigInt(8))+a}return b}function bitLength(b){let c=1;do c++;while((b>>=_ONE)>_ONE);return c}function _isProbablyPrimeWorkerURL(){let a=`'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 randBytes = ${randBytes.toString()};const randBetween = ${randBetween.toString()};const isProbablyPrime = ${_isProbablyPrime.toString()};${bitLength.toString()}${fromBuffer.toString()}`;a+=`onmessage = ${async function(a){const b=await isProbablyPrime(a.data.rnd,a.data.iterations);postMessage({isPrime:b,value:a.data.rnd,id:a.data.id})}.toString()};`,a=`(() => {${a}})()`;var b=new Blob([a],{type:"text/javascript"});return window.URL.createObjectURL(b)}async 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<e.length&&BigInt(e[a])<=c;a++){const b=BigInt(e[a]);if(c===b)return!0;if(c%b===_ZERO)return!1}let f=_ZERO,g=c-_ONE;for(;g%_TWO===_ZERO;)g/=_TWO,++f;let h=(c-_ONE)/_TWO**f;loop:do{let a=await randBetween(c-_ONE,_TWO),b=modPow(a,h,c);if(b===_ONE||b===c-_ONE)continue;for(let a=1;a<f;a++){if(b=modPow(b,_TWO,c),b===c-_ONE)continue loop;if(b===_ONE)break}return!1}while(--b);return!0}const _ZERO=BigInt(0),_ONE=BigInt(1),_TWO=BigInt(2);export{abs,eGcd,gcd,isProbablyPrime,lcm,modInv,modPow,prime,randBetween,randBits,randBytes,toZn};
function abs(b){return b=BigInt(b),b>=_ZERO?b:-b}function eGcd(c,d){c=BigInt(c),d=BigInt(d);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){c=abs(c),d=abs(d);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<<e}async function isProbablyPrime(a,b=16){return new Promise((c,d)=>{let 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),abs(c*d)/gcd(c,d)}function modInv(b,a){let c=eGcd(b,a);return c.b===_ONE?toZn(c.x,a):null}function modPow(c,d,e){if(e=BigInt(e),c=toZn(c,e),d=BigInt(d),d<_ZERO)return modInv(modPow(c,abs(d),e),e);let f=_ONE,g=c;for(;0<d;){var h=d%_TWO;d/=_TWO,h==_ONE&&(f*=g,f%=e),g*=g,g%=e}return f}function prime(a,b=16){return new Promise(c=>{let d=[];const e=(e,f)=>{if(e.isPrime){for(let a=0;a<d.length;a++)d[a].terminate();for(;d.length;)d.pop();c(e.value)}else{let c=randBits(a,!0),d=fromBuffer(c);try{f.postMessage({rnd:d,iterations:b,id:e.id})}catch(a){}}};{let a=_isProbablyPrimeWorkerUrl();for(let b,c=0;c<self.navigator.hardwareConcurrency;c++)b=new Worker(a),b.onmessage=a=>e(a.data,b),d.push(b)}for(let e=0;e<d.length;e++){let c=randBits(a,!0),f=fromBuffer(c);d[e].postMessage({rnd:f,iterations:b,id:e})}})}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;const d=c(a/8);let e=randBytes(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){let c;return c=new Uint8Array(a),self.crypto.getRandomValues(c),b&&(c[0]|=128),c}function toZn(b,c){return c=BigInt(c),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<<BigInt(8))+a}return b}function bitLength(b){let c=1;do c++;while((b>>=_ONE)>_ONE);return c}function _isProbablyPrimeWorkerUrl(){let a=`'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 randBytes = ${randBytes.toString()};const randBetween = ${randBetween.toString()};const isProbablyPrime = ${_isProbablyPrime.toString()};${bitLength.toString()}${fromBuffer.toString()}`;return a+=`onmessage = ${async function(a){const b=await isProbablyPrime(a.data.rnd,a.data.iterations);postMessage({isPrime:b,value:a.data.rnd,id:a.data.id})}.toString()};`,_workerUrl(a)}function _workerUrl(a){a=`(() => {${a}})()`;var 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<e.length&&BigInt(e[a])<=c;a++){const b=BigInt(e[a]);if(c===b)return!0;if(c%b===_ZERO)return!1}let f=_ZERO,g=c-_ONE;for(;g%_TWO===_ZERO;)g/=_TWO,++f;let h=(c-_ONE)/_TWO**f;loop:do{let a=randBetween(c-_ONE,_TWO),b=modPow(a,h,c);if(b===_ONE||b===c-_ONE)continue;for(let a=1;a<f;a++){if(b=modPow(b,_TWO,c),b===c-_ONE)continue loop;if(b===_ONE)break}return!1}while(--b);return!0}const _ZERO=BigInt(0),_ONE=BigInt(1),_TWO=BigInt(2);export{abs,eGcd,gcd,isProbablyPrime,lcm,modInv,modPow,prime,randBetween,randBits,randBytes,toZn};

View File

@ -119,7 +119,9 @@ async function isProbablyPrime(w, iterations = 16) {
});
});
} else {
return _isProbablyPrime(w, iterations);
return new Promise((resolve) => {
resolve(_isProbablyPrime(w, iterations));
});
}
}
}
@ -197,13 +199,13 @@ function modPow(a, b, n) {
*
* @returns {Promise} A promise that resolves to a bigint probable prime of bitLength bits
*/
async function prime(bitLength, iterations = 16) {
function prime(bitLength, iterations = 16) {
if (!_useWorkers) {
let rnd = _ZERO;
do {
rnd = fromBuffer(await randBytes(bitLength / 8, true));
} while (! await _isProbablyPrime(rnd, iterations));
return rnd;
rnd = fromBuffer(randBytes(bitLength / 8, true));
} while (!_isProbablyPrime(rnd, iterations));
return new Promise((resolve) => { resolve(rnd); });
}
return new Promise((resolve) => {
let workerList = [];
@ -218,7 +220,7 @@ async function prime(bitLength, iterations = 16) {
}
resolve(msg.value);
} else { // if a composite is found, make the worker test another random number
randBits(bitLength, true).then((buf) => {
let buf = randBits(bitLength, true);
let rnd = fromBuffer(buf);
try {
newWorker.postMessage({
@ -229,7 +231,6 @@ async function prime(bitLength, iterations = 16) {
} catch (error) {
// The worker has already terminated. There is nothing to handle here
}
});
}
};
{ // Node.js
@ -242,14 +243,13 @@ async function prime(bitLength, iterations = 16) {
}
}
for (let i = 0; i < workerList.length; i++) {
randBits(bitLength, true).then((buf) => {
let buf = randBits(bitLength, true);
let rnd = fromBuffer(buf);
workerList[i].postMessage({
'rnd': rnd,
'iterations': iterations,
'id': i
});
});
}
});
}
@ -259,15 +259,15 @@ async function prime(bitLength, iterations = 16) {
* @param {bigint} max Returned value will be <= max
* @param {bigint} min Returned value will be >= min
*
* @returns {Promise} A promise that resolves to a cryptographically secure random bigint between [min,max]
* @returns {bigint} A cryptographically secure random bigint between [min,max]
*/
async function randBetween(max, min = _ONE) {
function randBetween(max, min = _ONE) {
if (max <= min) throw new Error('max must be > min');
const interval = max - min;
let bitLen = bitLength(interval);
let rnd;
do {
let buf = await randBits(bitLen);
let buf = randBits(bitLen);
rnd = fromBuffer(buf);
} while (rnd > interval);
return rnd + min;
@ -279,11 +279,11 @@ async function randBetween(max, min = _ONE) {
* @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
*
* @returns {Promise} A promise that resolves to a Buffer/UInt8Array filled with cryptographically secure random bits
* @returns {Buffer|Uint8Array} A Buffer/UInt8Array filled with cryptographically secure random bits
*/
async function randBits(bitLength, forceLength = false) {
function randBits(bitLength, forceLength = false) {
const byteLength = Math.ceil(bitLength / 8);
let rndBytes = await randBytes(byteLength, false);
let rndBytes = randBytes(byteLength, false);
// Fill with 0's the extra birs
rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1);
if (forceLength) {
@ -299,24 +299,19 @@ async function randBits(bitLength, forceLength = false) {
* @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 {Promise} A promise that resolves to a Buffer/UInt8Array filled with cryptographically secure random bytes
* @returns {Buffer|Uint8Array} A Buffer/UInt8Array filled with cryptographically secure random bytes
*/
async function randBytes(byteLength, forceLength = false) {
return new Promise((resolve) => {
function randBytes(byteLength, forceLength = false) {
let buf;
{ // node
const crypto = require('crypto');
buf = Buffer.alloc(byteLength);
crypto.randomFill(buf, (err, buf) => {
crypto.randomFillSync(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);
});
}
});
return buf;
}
/**
@ -353,7 +348,7 @@ function bitLength(a) {
return bits;
}
async function _isProbablyPrime(w, iterations = 16) {
function _isProbablyPrime(w, iterations = 16) {
/*
PREFILTERING. Even values but 2 are not primes, so don't test.
1 is not a prime and the M-R algorithm needs w>1.
@ -654,7 +649,7 @@ async function _isProbablyPrime(w, iterations = 16) {
let m = (w - _ONE) / (_TWO ** a);
loop: do {
let b = await randBetween(w - _ONE, _TWO);
let b = randBetween(w - _ONE, _TWO);
let z = modPow(b, m, w);
if (z === _ONE || z === w - _ONE)
continue;
@ -698,9 +693,9 @@ 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');
if (!isMainThread) { // worker
parentPort.on('message', async function (data) { // Let's start once we are called
parentPort.on('message', function (data) { // Let's start once we are called
// data = {rnd: <bigint>, iterations: <number>}
const isPrime = await _isProbablyPrime(data.rnd, data.iterations);
const isPrime = _isProbablyPrime(data.rnd, data.iterations);
parentPort.postMessage({
'isPrime': isPrime,
'value': data.rnd,

View File

@ -117,11 +117,13 @@ export async function isProbablyPrime(w, iterations = 16) {
});
});
} else {
return _isProbablyPrime(w, iterations);
return new Promise((resolve) => {
resolve(_isProbablyPrime(w, iterations));
});
}
} else { // browser
return new Promise((resolve, reject) => {
let worker = new Worker(_isProbablyPrimeWorkerURL());
let worker = new Worker(_isProbablyPrimeWorkerUrl());
worker.onmessage = (event) => {
worker.terminate();
@ -214,13 +216,13 @@ export function modPow(a, b, n) {
*
* @returns {Promise} A promise that resolves to a bigint probable prime of bitLength bits
*/
export async function prime(bitLength, iterations = 16) {
export function prime(bitLength, iterations = 16) {
if (!process.browser && !_useWorkers) {
let rnd = _ZERO;
do {
rnd = fromBuffer(await randBytes(bitLength / 8, true));
} while (! await _isProbablyPrime(rnd, iterations));
return rnd;
rnd = fromBuffer(randBytes(bitLength / 8, true));
} while (!_isProbablyPrime(rnd, iterations));
return new Promise((resolve) => { resolve(rnd); });
}
return new Promise((resolve) => {
let workerList = [];
@ -235,7 +237,7 @@ export async function prime(bitLength, iterations = 16) {
}
resolve(msg.value);
} else { // if a composite is found, make the worker test another random number
randBits(bitLength, true).then((buf) => {
let buf = randBits(bitLength, true);
let rnd = fromBuffer(buf);
try {
newWorker.postMessage({
@ -246,11 +248,10 @@ export async function prime(bitLength, iterations = 16) {
} catch (error) {
// The worker has already terminated. There is nothing to handle here
}
});
}
};
if (process.browser) { //browser
let workerURL = _isProbablyPrimeWorkerURL();
let workerURL = _isProbablyPrimeWorkerUrl();
for (let i = 0; i < self.navigator.hardwareConcurrency; i++) {
let newWorker = new Worker(workerURL);
newWorker.onmessage = (event) => _onmessage(event.data, newWorker);
@ -266,14 +267,13 @@ export async function prime(bitLength, iterations = 16) {
}
}
for (let i = 0; i < workerList.length; i++) {
randBits(bitLength, true).then((buf) => {
let buf = randBits(bitLength, true);
let rnd = fromBuffer(buf);
workerList[i].postMessage({
'rnd': rnd,
'iterations': iterations,
'id': i
});
});
}
});
}
@ -283,15 +283,15 @@ export async function prime(bitLength, iterations = 16) {
* @param {bigint} max Returned value will be <= max
* @param {bigint} min Returned value will be >= min
*
* @returns {Promise} A promise that resolves to a cryptographically secure random bigint between [min,max]
* @returns {bigint} A cryptographically secure random bigint between [min,max]
*/
export async function randBetween(max, min = _ONE) {
export function randBetween(max, min = _ONE) {
if (max <= min) throw new Error('max must be > min');
const interval = max - min;
let bitLen = bitLength(interval);
let rnd;
do {
let buf = await randBits(bitLen);
let buf = randBits(bitLen);
rnd = fromBuffer(buf);
} while (rnd > interval);
return rnd + min;
@ -303,11 +303,11 @@ export async function randBetween(max, min = _ONE) {
* @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
*
* @returns {Promise} A promise that resolves to a Buffer/UInt8Array filled with cryptographically secure random bits
* @returns {Buffer|Uint8Array} A Buffer/UInt8Array filled with cryptographically secure random bits
*/
export async function randBits(bitLength, forceLength = false) {
export function randBits(bitLength, forceLength = false) {
const byteLength = Math.ceil(bitLength / 8);
let rndBytes = await randBytes(byteLength, false);
let rndBytes = randBytes(byteLength, false);
// Fill with 0's the extra birs
rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1);
if (forceLength) {
@ -323,31 +323,22 @@ export async function randBits(bitLength, forceLength = false) {
* @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 {Promise} A promise that resolves to a Buffer/UInt8Array filled with cryptographically secure random bytes
* @returns {Buffer|Uint8Array} A Buffer/UInt8Array filled with cryptographically secure random bytes
*/
export async function randBytes(byteLength, forceLength = false) {
return new Promise((resolve) => {
export function randBytes(byteLength, forceLength = false) {
let buf;
if (!process.browser) { // node
const crypto = require('crypto');
buf = Buffer.alloc(byteLength);
crypto.randomFill(buf, (err, 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);
});
crypto.randomFillSync(buf);
} else { // 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;
resolve(buf);
}
});
return buf;
}
/**
@ -384,11 +375,11 @@ function bitLength(a) {
return bits;
}
function _isProbablyPrimeWorkerURL() {
function _isProbablyPrimeWorkerUrl() {
// Let's us first add all the required functions
let workerCode = `'use strict';const _ZERO = BigInt(0);const _ONE = BigInt(1);const _TWO = BigInt(2);const eGcd = ${eGcd.toString()};const modInv = ${modInv.toString()};const modPow = ${modPow.toString()};const toZn = ${toZn.toString()};const randBits = ${randBits.toString()};const randBytes = ${randBytes.toString()};const randBetween = ${randBetween.toString()};const isProbablyPrime = ${_isProbablyPrime.toString()};${bitLength.toString()}${fromBuffer.toString()}`;
const _onmessage = async function (event) { // Let's start once we are called
const onmessage = async function (event) { // Let's start once we are called
// event.data = {rnd: <bigint>, iterations: <number>}
const isPrime = await isProbablyPrime(event.data.rnd, event.data.iterations);
postMessage({
@ -397,16 +388,19 @@ function _isProbablyPrimeWorkerURL() {
'id': event.data.id
});
};
workerCode += `onmessage = ${_onmessage.toString()};`;
workerCode += `onmessage = ${onmessage.toString()};`;
return _workerUrl(workerCode);
}
function _workerUrl(workerCode) {
workerCode = `(() => {${workerCode}})()`; // encapsulate IIFE
var _blob = new Blob([workerCode], { type: 'text/javascript' });
return window.URL.createObjectURL(_blob);
}
async function _isProbablyPrime(w, iterations = 16) {
function _isProbablyPrime(w, iterations = 16) {
/*
PREFILTERING. Even values but 2 are not primes, so don't test.
1 is not a prime and the M-R algorithm needs w>1.
@ -707,7 +701,7 @@ async function _isProbablyPrime(w, iterations = 16) {
let m = (w - _ONE) / (_TWO ** a);
loop: do {
let b = await randBetween(w - _ONE, _TWO);
let b = randBetween(w - _ONE, _TWO);
let z = modPow(b, m, w);
if (z === _ONE || z === w - _ONE)
continue;
@ -751,9 +745,9 @@ 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');
if (!isMainThread) { // worker
parentPort.on('message', async function (data) { // Let's start once we are called
parentPort.on('message', function (data) { // Let's start once we are called
// data = {rnd: <bigint>, iterations: <number>}
const isPrime = await _isProbablyPrime(data.rnd, data.iterations);
const isPrime = _isProbablyPrime(data.rnd, data.iterations);
parentPort.postMessage({
'isPrime': isPrime,
'value': data.rnd,