More tests. Fixed bug in modInv(a,n) when a was < 0

This commit is contained in:
Juan Hernández Serrano 2019-05-04 18:08:30 +02:00
parent fb3dd95190
commit 1ffd1f949d
18 changed files with 704 additions and 43 deletions

View File

@ -73,7 +73,7 @@ From a browser, you can just load the module in a html page as:
alert(p.toString() + '\nIs prime?\n' + isPrime); alert(p.toString() + '\nIs prime?\n' + isPrime);
// Get a cryptographically secure random number between 1 and 2**256 bits. // Get a cryptographically secure random number between 1 and 2**256 bits.
const rnd = await bigintCryptoUtils.randBetween(BigInt(2) ** BigInt(256)); const rnd = bigintCryptoUtils.randBetween(BigInt(2) ** BigInt(256));
alert(rnd); alert(rnd);
})(); })();
</script> </script>

View File

@ -73,7 +73,7 @@ From a browser, you can just load the module in a html page as:
alert(p.toString() + '\nIs prime?\n' + isPrime); alert(p.toString() + '\nIs prime?\n' + isPrime);
// Get a cryptographically secure random number between 1 and 2**256 bits. // Get a cryptographically secure random number between 1 and 2**256 bits.
const rnd = await bigintCryptoUtils.randBetween(BigInt(2) ** BigInt(256)); const rnd = bigintCryptoUtils.randBetween(BigInt(2) ** BigInt(256));
alert(rnd); alert(rnd);
})(); })();
</script> </script>
@ -123,7 +123,10 @@ and can be enabled at runtime executing node --experimental-worker with node &gt
<dt><a href="#randBits">randBits(bitLength, forceLength)</a><code>Buffer</code> | <code>Uint8Array</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><p>Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()</p>
</dd> </dd>
<dt><a href="#randBytes">randBytes(byteLength, forceLength)</a><code>Buffer</code> | <code>Uint8Array</code></dt> <dt><a href="#randBytes">randBytes(byteLength, forceLength)</a><code>Promise</code></dt>
<dd><p>Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()</p>
</dd>
<dt><a href="#randBytesSync">randBytesSync(byteLength, forceLength)</a><code>Buffer</code> | <code>Uint8Array</code></dt>
<dd><p>Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()</p> <dd><p>Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()</p>
</dd> </dd>
<dt><a href="#toZn">toZn(a, n)</a><code>bigint</code></dt> <dt><a href="#toZn">toZn(a, n)</a><code>bigint</code></dt>
@ -288,7 +291,20 @@ Secure random bits for both node and browsers. Node version uses crypto.randomFi
<a name="randBytes"></a> <a name="randBytes"></a>
## randBytes(byteLength, forceLength) ⇒ <code>Buffer</code> \| <code>Uint8Array</code> ## randBytes(byteLength, forceLength) ⇒ <code>Promise</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 (Node.js/Browser) filled with cryptographically secure random bytes
| Param | Type | Description |
| --- | --- | --- |
| byteLength | <code>number</code> | The desired number of random bytes |
| forceLength | <code>boolean</code> | If we want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1 |
<a name="randBytesSync"></a>
## randBytesSync(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() Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
**Kind**: global function **Kind**: global function

View File

@ -25,6 +25,8 @@ var bigintCryptoUtils = (function (exports) {
* @returns {number} - the bit length * @returns {number} - the bit length
*/ */
function bitLength(a) { function bitLength(a) {
if (a === _ONE)
return 1;
let bits = 1; let bits = 1;
do { do {
bits++; bits++;
@ -160,7 +162,7 @@ var bigintCryptoUtils = (function (exports) {
* @returns {bigint} the inverse modulo n * @returns {bigint} the inverse modulo n
*/ */
function modInv(a, n) { function modInv(a, n) {
let egcd = eGcd(a, n); let egcd = eGcd(toZn(a,n), n);
if (egcd.b !== _ONE) { if (egcd.b !== _ONE) {
return null; // modular inverse does not exist return null; // modular inverse does not exist
} else { } else {
@ -287,7 +289,7 @@ var bigintCryptoUtils = (function (exports) {
*/ */
function randBits(bitLength, forceLength = false) { function randBits(bitLength, forceLength = false) {
const byteLength = Math.ceil(bitLength / 8); const byteLength = Math.ceil(bitLength / 8);
let rndBytes = randBytes(byteLength, false); let rndBytes = randBytesSync(byteLength, false);
// Fill with 0's the extra birs // Fill with 0's the extra birs
rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1); rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1);
if (forceLength) { if (forceLength) {
@ -303,9 +305,28 @@ var bigintCryptoUtils = (function (exports) {
* @param {number} byteLength The desired number of random bytes * @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 * @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 * @returns {Promise} A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
*/ */
function randBytes(byteLength, forceLength = false) { function randBytes(byteLength, forceLength = false) {
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) {
let buf; let buf;
{ // browser { // browser
buf = new Uint8Array(byteLength); buf = new Uint8Array(byteLength);
@ -345,7 +366,7 @@ var bigintCryptoUtils = (function (exports) {
function _isProbablyPrimeWorkerUrl() { function _isProbablyPrimeWorkerUrl() {
// Let's us first add all the required functions // 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()}`; 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()}`;
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>} // event.data = {rnd: <bigint>, iterations: <number>}
@ -699,6 +720,7 @@ var bigintCryptoUtils = (function (exports) {
exports.randBetween = randBetween; exports.randBetween = randBetween;
exports.randBits = randBits; exports.randBits = randBits;
exports.randBytes = randBytes; exports.randBytes = randBytes;
exports.randBytesSync = randBytesSync;
exports.toZn = toZn; exports.toZn = toZn;
return exports; return exports;

View File

@ -1 +1 @@
var bigintCryptoUtils=function(a){'use strict';function c(b){return b=BigInt(b),b>=r?b:-b}function d(b){let c=1;do c++;while((b>>=s)>s);return c}function e(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 f(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 g(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 h(b,a){let c=e(b,a);return c.b===s?m(c.x,a):null}function i(d,e,f){if(f=BigInt(f),d=m(d,f),e=BigInt(e),e<r)return h(i(d,c(e),f),f);let g=s,j=d;for(;0<e;){var k=e%t;e/=t,k==s&&(g*=j,g%=f),j*=j,j%=f}return g}function j(a,b=s){if(a<=b)throw new Error("max must be > 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;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){let c;return c=new Uint8Array(a),self.crypto.getRandomValues(c),b&&(c[0]|=128),c}function m(b,c){return c=BigInt(c),b=BigInt(b)%c,0>b?b+c:b}function n(a){let b=r;for(let c of a.values()){let a=BigInt(c);b=(b<<BigInt(8))+a}return b}function o(){let a=`'use strict';const _ZERO = BigInt(0);const _ONE = BigInt(1);const _TWO = BigInt(2);const eGcd = ${e.toString()};const modInv = ${h.toString()};const modPow = ${i.toString()};const toZn = ${m.toString()};const randBits = ${k.toString()};const randBytes = ${l.toString()};const randBetween = ${j.toString()};const isProbablyPrime = ${q.toString()};${d.toString()}${n.toString()}`;return a+=`onmessage = ${async function(a){const b=await g(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 h=(c-s)/t**f;loop:do{let a=j(c-s,t),b=i(a,h,c);if(b===s||b===c-s)continue;for(let a=1;a<f;a++){if(b=i(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.bitLength=d,a.eGcd=e,a.gcd=f,a.isProbablyPrime=g,a.lcm=function(d,e){return d=BigInt(d),e=BigInt(e),c(d*e)/f(d,e)},a.modInv=h,a.modPow=i,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=k(a,!0),d=n(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=k(a,!0),f=n(c);d[e].postMessage({rnd:f,iterations:b,id:e})}})},a.randBetween=j,a.randBits=k,a.randBytes=l,a.toZn=m,a}({}); var bigintCryptoUtils=function(a){'use strict';function c(b){return b=BigInt(b),b>=r?b:-b}function d(b){if(b===s)return 1;let c=1;do c++;while((b>>=s)>s);return c}function e(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 f(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 g(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 h(b,a){let c=e(m(b,a),a);return c.b===s?m(c.x,a):null}function i(d,e,f){if(f=BigInt(f),d=m(d,f),e=BigInt(e),e<r)return h(i(d,c(e),f),f);let g=s,j=d;for(;0<e;){var k=e%t;e/=t,k==s&&(g*=j,g%=f),j*=j,j%=f}return g}function j(a,b=s){if(a<=b)throw new Error("max must be > 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;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){let c;return c=new Uint8Array(a),self.crypto.getRandomValues(c),b&&(c[0]|=128),c}function m(b,c){return c=BigInt(c),b=BigInt(b)%c,0>b?b+c:b}function n(a){let b=r;for(let c of a.values()){let a=BigInt(c);b=(b<<BigInt(8))+a}return b}function o(){let a=`'use strict';const _ZERO = BigInt(0);const _ONE = BigInt(1);const _TWO = BigInt(2);const eGcd = ${e.toString()};const modInv = ${h.toString()};const modPow = ${i.toString()};const toZn = ${m.toString()};const randBits = ${k.toString()};const randBytesSync = ${l.toString()};const randBetween = ${j.toString()};const isProbablyPrime = ${q.toString()};${d.toString()}${n.toString()}`;return a+=`onmessage = ${async function(a){const b=await g(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 h=(c-s)/t**f;loop:do{let a=j(c-s,t),b=i(a,h,c);if(b===s||b===c-s)continue;for(let a=1;a<f;a++){if(b=i(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.bitLength=d,a.eGcd=e,a.gcd=f,a.isProbablyPrime=g,a.lcm=function(d,e){return d=BigInt(d),e=BigInt(e),c(d*e)/f(d,e)},a.modInv=h,a.modPow=i,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=k(a,!0),d=n(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=k(a,!0),f=n(c);d[e].postMessage({rnd:f,iterations:b,id:e})}})},a.randBetween=j,a.randBits=k,a.randBytes=function(a,b=!1){let c;return new Promise(function(b){c=new Uint8Array(a),self.crypto.getRandomValues(c),b(c)})},a.randBytesSync=l,a.toZn=m,a}({});

View File

@ -22,6 +22,8 @@ function abs(a) {
* @returns {number} - the bit length * @returns {number} - the bit length
*/ */
function bitLength(a) { function bitLength(a) {
if (a === _ONE)
return 1;
let bits = 1; let bits = 1;
do { do {
bits++; bits++;
@ -157,7 +159,7 @@ function lcm(a, b) {
* @returns {bigint} the inverse modulo n * @returns {bigint} the inverse modulo n
*/ */
function modInv(a, n) { function modInv(a, n) {
let egcd = eGcd(a, n); let egcd = eGcd(toZn(a,n), n);
if (egcd.b !== _ONE) { if (egcd.b !== _ONE) {
return null; // modular inverse does not exist return null; // modular inverse does not exist
} else { } else {
@ -284,7 +286,7 @@ function randBetween(max, min = _ONE) {
*/ */
function randBits(bitLength, forceLength = false) { function randBits(bitLength, forceLength = false) {
const byteLength = Math.ceil(bitLength / 8); const byteLength = Math.ceil(bitLength / 8);
let rndBytes = randBytes(byteLength, false); let rndBytes = randBytesSync(byteLength, false);
// Fill with 0's the extra birs // Fill with 0's the extra birs
rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1); rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1);
if (forceLength) { if (forceLength) {
@ -300,9 +302,28 @@ function randBits(bitLength, forceLength = false) {
* @param {number} byteLength The desired number of random bytes * @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 * @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 * @returns {Promise} A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
*/ */
function randBytes(byteLength, forceLength = false) { function randBytes(byteLength, forceLength = false) {
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) {
let buf; let buf;
{ // browser { // browser
buf = new Uint8Array(byteLength); buf = new Uint8Array(byteLength);
@ -342,7 +363,7 @@ function fromBuffer(buf) {
function _isProbablyPrimeWorkerUrl() { function _isProbablyPrimeWorkerUrl() {
// Let's us first add all the required functions // 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()}`; 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()}`;
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>} // event.data = {rnd: <bigint>, iterations: <number>}
@ -684,4 +705,4 @@ function _isProbablyPrime(w, iterations = 16) {
return true; return true;
} }
export { abs, bitLength, eGcd, gcd, isProbablyPrime, lcm, modInv, modPow, prime, randBetween, randBits, randBytes, toZn }; export { abs, bitLength, eGcd, gcd, isProbablyPrime, lcm, modInv, modPow, prime, randBetween, randBits, randBytes, randBytesSync, toZn };

View File

@ -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){let c=1;do c++;while((b>>=_ONE)>_ONE);return c}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 _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}export{abs,bitLength,eGcd,gcd,isProbablyPrime,lcm,modInv,modPow,prime,randBetween,randBits,randBytes,toZn}; 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===_ONE)return 1;let c=1;do c++;while((b>>=_ONE)>_ONE);return c}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(toZn(b,a),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=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){let c;return new Promise(function(b){c=new Uint8Array(a),self.crypto.getRandomValues(c),b(c)})}function randBytesSync(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 _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 randBytesSync = ${randBytesSync.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}export{abs,bitLength,eGcd,gcd,isProbablyPrime,lcm,modInv,modPow,prime,randBetween,randBits,randBytes,randBytesSync,toZn};

View File

@ -26,6 +26,8 @@ function abs(a) {
* @returns {number} - the bit length * @returns {number} - the bit length
*/ */
function bitLength(a) { function bitLength(a) {
if (a === _ONE)
return 1;
let bits = 1; let bits = 1;
do { do {
bits++; bits++;
@ -167,7 +169,7 @@ function lcm(a, b) {
* @returns {bigint} the inverse modulo n * @returns {bigint} the inverse modulo n
*/ */
function modInv(a, n) { function modInv(a, n) {
let egcd = eGcd(a, n); let egcd = eGcd(toZn(a,n), n);
if (egcd.b !== _ONE) { if (egcd.b !== _ONE) {
return null; // modular inverse does not exist return null; // modular inverse does not exist
} else { } else {
@ -222,7 +224,7 @@ function prime(bitLength, iterations = 16) {
if (!_useWorkers) { if (!_useWorkers) {
let rnd = _ZERO; let rnd = _ZERO;
do { do {
rnd = fromBuffer(randBytes(bitLength / 8, true)); rnd = fromBuffer(randBytesSync(bitLength / 8, true));
} while (!_isProbablyPrime(rnd, iterations)); } while (!_isProbablyPrime(rnd, iterations));
return new Promise((resolve) => { resolve(rnd); }); return new Promise((resolve) => { resolve(rnd); });
} }
@ -302,7 +304,7 @@ function randBetween(max, min = _ONE) {
*/ */
function randBits(bitLength, forceLength = false) { function randBits(bitLength, forceLength = false) {
const byteLength = Math.ceil(bitLength / 8); const byteLength = Math.ceil(bitLength / 8);
let rndBytes = randBytes(byteLength, false); let rndBytes = randBytesSync(byteLength, false);
// Fill with 0's the extra birs // Fill with 0's the extra birs
rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1); rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1);
if (forceLength) { if (forceLength) {
@ -318,9 +320,31 @@ function randBits(bitLength, forceLength = false) {
* @param {number} byteLength The desired number of random bytes * @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 * @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 * @returns {Promise} A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
*/ */
function randBytes(byteLength, forceLength = false) { function randBytes(byteLength, forceLength = false) {
let buf;
{ // node
const crypto = require('crypto');
buf = Buffer.alloc(byteLength);
return crypto.randomFill(buf, function (resolve) {
// 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);
});
}
}
/**
* 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) {
let buf; let buf;
{ // node { // node
const crypto = require('crypto'); const crypto = require('crypto');
@ -724,4 +748,5 @@ exports.prime = prime;
exports.randBetween = randBetween; exports.randBetween = randBetween;
exports.randBits = randBits; exports.randBits = randBits;
exports.randBytes = randBytes; exports.randBytes = randBytes;
exports.randBytesSync = randBytesSync;
exports.toZn = toZn; exports.toZn = toZn;

View File

@ -24,6 +24,8 @@ export function abs(a) {
* @returns {number} - the bit length * @returns {number} - the bit length
*/ */
export function bitLength(a) { export function bitLength(a) {
if (a === _ONE)
return 1;
let bits = 1; let bits = 1;
do { do {
bits++; bits++;
@ -184,7 +186,7 @@ export function lcm(a, b) {
* @returns {bigint} the inverse modulo n * @returns {bigint} the inverse modulo n
*/ */
export function modInv(a, n) { export function modInv(a, n) {
let egcd = eGcd(a, n); let egcd = eGcd(toZn(a,n), n);
if (egcd.b !== _ONE) { if (egcd.b !== _ONE) {
return null; // modular inverse does not exist return null; // modular inverse does not exist
} else { } else {
@ -239,7 +241,7 @@ export function prime(bitLength, iterations = 16) {
if (!process.browser && !_useWorkers) { if (!process.browser && !_useWorkers) {
let rnd = _ZERO; let rnd = _ZERO;
do { do {
rnd = fromBuffer(randBytes(bitLength / 8, true)); rnd = fromBuffer(randBytesSync(bitLength / 8, true));
} while (!_isProbablyPrime(rnd, iterations)); } while (!_isProbablyPrime(rnd, iterations));
return new Promise((resolve) => { resolve(rnd); }); return new Promise((resolve) => { resolve(rnd); });
} }
@ -326,7 +328,7 @@ export function randBetween(max, min = _ONE) {
*/ */
export function randBits(bitLength, forceLength = false) { export function randBits(bitLength, forceLength = false) {
const byteLength = Math.ceil(bitLength / 8); const byteLength = Math.ceil(bitLength / 8);
let rndBytes = randBytes(byteLength, false); let rndBytes = randBytesSync(byteLength, false);
// Fill with 0's the extra birs // Fill with 0's the extra birs
rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1); rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1);
if (forceLength) { if (forceLength) {
@ -342,9 +344,37 @@ export function randBits(bitLength, forceLength = false) {
* @param {number} byteLength The desired number of random bytes * @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 * @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 * @returns {Promise} A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
*/ */
export function randBytes(byteLength, forceLength = false) { export function randBytes(byteLength, forceLength = false) {
let buf;
if (!process.browser) { // node
const crypto = require('crypto');
buf = Buffer.alloc(byteLength);
return crypto.randomFill(buf, function (resolve) {
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength)
buf[0] = buf[0] | 128;
resolve(buf);
});
} else { // browser
return new Promise(function (resolve) {
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
*/
export function randBytesSync(byteLength, forceLength = false) {
let buf; let buf;
if (!process.browser) { // node if (!process.browser) { // node
const crypto = require('crypto'); const crypto = require('crypto');
@ -388,7 +418,7 @@ function fromBuffer(buf) {
function _isProbablyPrimeWorkerUrl() { function _isProbablyPrimeWorkerUrl() {
// Let's us first add all the required functions // 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()}`; 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()}`;
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>} // event.data = {rnd: <bigint>, iterations: <number>}

37
test/abs.js Normal file
View File

@ -0,0 +1,37 @@
'use strict';
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const bigintCryptoUtils = require('../dist/bigint-crypto-utils-latest.node');
const chai = require('chai');
const inputs = [
{
value: BigInt(1),
abs: BigInt(1)
},
{
value: BigInt(-2),
abs: BigInt(2)
},
{
value: BigInt('115922179551495973383410176342643722334557255682879605864838806293659619625004303206250384392546855063844106965156287951749387634112551089284595541103692716528774876311641700929986988023197242224581099872580798960693521778607396791006450968430359009613295725905514216842343121690916290236558767890728449777'),
abs: BigInt('115922179551495973383410176342643722334557255682879605864838806293659619625004303206250384392546855063844106965156287951749387634112551089284595541103692716528774876311641700929986988023197242224581099872580798960693521778607396791006450968430359009613295725905514216842343121690916290236558767890728449777')
},
{
value: BigInt('-918145944120889203205646923554374144932845997937845799234617798611046542304088105084854788397071323714642587188481158334265864050544813693415594035822877094557870151480865568334936301231664228940480803192289508235412296324312748621874408067955753620604885023289655277704554716080844406284392300643321715285709865081125252390440327650852470312931679380011885102491340191287595160450544053114365852338670819405357496612993587404998677760882578064637552397840566752638770525765833183986360029736508910848408875329873614164495552615086579144675027852136994842529623698055210822311666048300438808691619782893307972452223713060928388502843564836966586109748062827799521852219158489504529458627699284110902303538160168376473182639384638674469114371472053977558648090155686345760457454061117853710619580819749222459422610617170567016772342291486643520567969321969827786373531753524990712622940069883277763528926899970596407140603912036918433859986491820017690762751824769335720368488097262208835708414085501930989486498185503469986946236128468697606998536541209764920494156326791142098506801288127033229779646920082892258428128572765585196779698362187479280520327053508580551167899837393726371144977951402741307021389967382422805567365901203'),
abs: BigInt('918145944120889203205646923554374144932845997937845799234617798611046542304088105084854788397071323714642587188481158334265864050544813693415594035822877094557870151480865568334936301231664228940480803192289508235412296324312748621874408067955753620604885023289655277704554716080844406284392300643321715285709865081125252390440327650852470312931679380011885102491340191287595160450544053114365852338670819405357496612993587404998677760882578064637552397840566752638770525765833183986360029736508910848408875329873614164495552615086579144675027852136994842529623698055210822311666048300438808691619782893307972452223713060928388502843564836966586109748062827799521852219158489504529458627699284110902303538160168376473182639384638674469114371472053977558648090155686345760457454061117853710619580819749222459422610617170567016772342291486643520567969321969827786373531753524990712622940069883277763528926899970596407140603912036918433859986491820017690762751824769335720368488097262208835708414085501930989486498185503469986946236128468697606998536541209764920494156326791142098506801288127033229779646920082892258428128572765585196779698362187479280520327053508580551167899837393726371144977951402741307021389967382422805567365901203')
}
];
describe('abs', function () {
for (const input of inputs) {
let ret;
describe(`abs(${input.value})`, function () {
it(`should return ${input.abs}`, function () {
ret = bigintCryptoUtils.abs(input.value);
chai.expect(ret).to.equal(input.abs);
});
});
}
});

34
test/bitLength.js Normal file
View File

@ -0,0 +1,34 @@
'use strict';
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const bigintCryptoUtils = require('../dist/bigint-crypto-utils-latest.node');
const chai = require('chai');
const inputs = [
{
value: BigInt(1),
bitLength: 1
},
{
value: BigInt(-2),
bitLength: 2
},
{
value: BigInt(11592217955149597331),
abs: BigInt(11592217955149597331),
bitLength: 64
}
];
describe('bitLength', function () {
for (const input of inputs) {
let ret;
describe(`bitLength(${input.value})`, function () {
it(`should return ${input.bitLength}`, function () {
ret = bigintCryptoUtils.bitLength(input.value);
chai.expect(ret).to.equal(input.bitLength);
});
});
}
});

View File

@ -3,6 +3,120 @@
const inputs = [
{
value: BigInt(1),
abs: BigInt(1)
},
{
value: BigInt(-2),
abs: BigInt(2)
},
{
value: BigInt('115922179551495973383410176342643722334557255682879605864838806293659619625004303206250384392546855063844106965156287951749387634112551089284595541103692716528774876311641700929986988023197242224581099872580798960693521778607396791006450968430359009613295725905514216842343121690916290236558767890728449777'),
abs: BigInt('115922179551495973383410176342643722334557255682879605864838806293659619625004303206250384392546855063844106965156287951749387634112551089284595541103692716528774876311641700929986988023197242224581099872580798960693521778607396791006450968430359009613295725905514216842343121690916290236558767890728449777')
},
{
value: BigInt('-918145944120889203205646923554374144932845997937845799234617798611046542304088105084854788397071323714642587188481158334265864050544813693415594035822877094557870151480865568334936301231664228940480803192289508235412296324312748621874408067955753620604885023289655277704554716080844406284392300643321715285709865081125252390440327650852470312931679380011885102491340191287595160450544053114365852338670819405357496612993587404998677760882578064637552397840566752638770525765833183986360029736508910848408875329873614164495552615086579144675027852136994842529623698055210822311666048300438808691619782893307972452223713060928388502843564836966586109748062827799521852219158489504529458627699284110902303538160168376473182639384638674469114371472053977558648090155686345760457454061117853710619580819749222459422610617170567016772342291486643520567969321969827786373531753524990712622940069883277763528926899970596407140603912036918433859986491820017690762751824769335720368488097262208835708414085501930989486498185503469986946236128468697606998536541209764920494156326791142098506801288127033229779646920082892258428128572765585196779698362187479280520327053508580551167899837393726371144977951402741307021389967382422805567365901203'),
abs: BigInt('918145944120889203205646923554374144932845997937845799234617798611046542304088105084854788397071323714642587188481158334265864050544813693415594035822877094557870151480865568334936301231664228940480803192289508235412296324312748621874408067955753620604885023289655277704554716080844406284392300643321715285709865081125252390440327650852470312931679380011885102491340191287595160450544053114365852338670819405357496612993587404998677760882578064637552397840566752638770525765833183986360029736508910848408875329873614164495552615086579144675027852136994842529623698055210822311666048300438808691619782893307972452223713060928388502843564836966586109748062827799521852219158489504529458627699284110902303538160168376473182639384638674469114371472053977558648090155686345760457454061117853710619580819749222459422610617170567016772342291486643520567969321969827786373531753524990712622940069883277763528926899970596407140603912036918433859986491820017690762751824769335720368488097262208835708414085501930989486498185503469986946236128468697606998536541209764920494156326791142098506801288127033229779646920082892258428128572765585196779698362187479280520327053508580551167899837393726371144977951402741307021389967382422805567365901203')
}
];
describe('abs', function () {
for (const input of inputs) {
let ret;
describe(`abs(${input.value})`, function () {
it(`should return ${input.abs}`, function () {
ret = bigintCryptoUtils.abs(input.value);
chai.expect(ret).to.equal(input.abs);
});
});
}
});
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const inputs$1 = [
{
value: BigInt(1),
bitLength: 1
},
{
value: BigInt(-2),
bitLength: 2
},
{
value: BigInt(11592217955149597331),
abs: BigInt(11592217955149597331),
bitLength: 64
}
];
describe('bitLength', function () {
for (const input of inputs$1) {
let ret;
describe(`bitLength(${input.value})`, function () {
it(`should return ${input.bitLength}`, function () {
ret = bigintCryptoUtils.bitLength(input.value);
chai.expect(ret).to.equal(input.bitLength);
});
});
}
});
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const inputs$2 = [
{
a: BigInt(1),
b: BigInt(1),
gcd: BigInt(1)
},
{
a: BigInt(1),
b: BigInt('14546149867129487614601346814'),
gcd: BigInt(1)
},
{
a: BigInt(27),
b: BigInt(18),
gcd: BigInt(9)
},
{
a: BigInt(-27),
b: BigInt(18),
gcd: BigInt(9)
},
{
a: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109'),
b: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109') * BigInt('144678545212641449725111562354371812236197961234111744040227045242578772124779004756249085154188369039159690638725821245974978963371615699005072473649705367893567309027634121825164880046600125480885803891136149601797439273507802533807541605261215613891134865916295914192271736572001975016089773532547481638243'),
gcd: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109')
}
];
describe('gcd', function () {
for (const input of inputs$2) {
let ret;
describe(`gcd(${input.a}, ${input.b})`, function () {
it(`should return ${input.gcd}`, function () {
ret = bigintCryptoUtils.gcd(input.a, input.b);
chai.expect(ret).to.equal(input.gcd);
});
});
}
});
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const numbers = [ const numbers = [
{ {
value: BigInt(1), value: BigInt(1),
@ -54,7 +168,7 @@ const numbers = [
} }
]; ];
describe('Testing validation of prime numbers', function () { describe('isProbablyPrime', function () {
for (const num of numbers) { for (const num of numbers) {
describe(`isProbablyPrime(${num.value})`, function () { describe(`isProbablyPrime(${num.value})`, function () {
it(`should return ${num.prime}`, async function () { it(`should return ${num.prime}`, async function () {
@ -70,6 +184,130 @@ describe('Testing validation of prime numbers', function () {
const inputs$3 = [
{
a: BigInt(1),
b: BigInt(1),
lcm: BigInt(1)
},
{
a: BigInt(1),
b: BigInt('14546149867129487614601346814'),
lcm: BigInt('14546149867129487614601346814')
},
{
a: BigInt(27),
b: BigInt(18),
lcm: BigInt(27) * BigInt(2)
},
{
a: BigInt(-27),
b: BigInt(18),
lcm: BigInt(27) * BigInt(2)
},
{
a: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109'),
b: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109') * BigInt('144678545212641449725111562354371812236197961234111744040227045242578772124779004756249085154188369039159690638725821245974978963371615699005072473649705367893567309027634121825164880046600125480885803891136149601797439273507802533807541605261215613891134865916295914192271736572001975016089773532547481638243'),
lcm: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109') * BigInt('144678545212641449725111562354371812236197961234111744040227045242578772124779004756249085154188369039159690638725821245974978963371615699005072473649705367893567309027634121825164880046600125480885803891136149601797439273507802533807541605261215613891134865916295914192271736572001975016089773532547481638243'),
}
];
describe('lcm', function () {
for (const input of inputs$3) {
let ret;
describe(`lcm(${input.a}, ${input.b})`, function () {
it(`should return ${input.lcm}`, function () {
ret = bigintCryptoUtils.lcm(input.a, input.b);
chai.expect(ret).to.equal(input.lcm);
});
});
}
});
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const inputs$4 = [
{
a: BigInt(1),
n: BigInt(19),
modInv: BigInt(1)
},
{
a: BigInt(2),
n: BigInt(5),
modInv: BigInt(3)
},
{
a: BigInt(-2),
n: BigInt(5),
modInv: BigInt(2)
}
];
describe('modInv', function () {
for (const input of inputs$4) {
let ret;
describe(`modInv(${input.a}, ${input.n})`, function () {
it(`should return ${input.modInv}`, function () {
ret = bigintCryptoUtils.modInv(input.a, input.n);
chai.expect(ret).to.equal(input.modInv);
});
});
}
});
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const inputs$5 = [
{
a: BigInt(4),
b: BigInt(-1),
n: BigInt(19),
modPow: BigInt(5)
},
{
a: BigInt(-5),
b: BigInt(2),
n: BigInt(7),
modPow: BigInt(4)
},
{
a: BigInt(2),
b: BigInt(255),
n: BigInt(64),
modPow: BigInt(0)
},
{
a: BigInt(3),
b: BigInt(3),
n: BigInt(25),
modPow: BigInt(2)
}
];
describe('modPow', function () {
for (const input of inputs$5) {
let ret;
describe(`modPow(${input.a}, ${input.b}, ${input.n})`, function () {
it(`should return ${input.modPow}`, function () {
ret = bigintCryptoUtils.modPow(input.a, input.b, input.n);
chai.expect(ret).to.equal(input.modPow);
});
});
}
});
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const bitLengths = [ const bitLengths = [
1024, 1024,
2048, 2048,
@ -77,16 +315,48 @@ const bitLengths = [
4096 4096
]; ];
describe('Testing generation of prime numbers', function () { describe('prime', function () {
for (const bitLength of bitLengths) { for (const bitLength of bitLengths) {
describe(`Executing prime(${bitLength})`, function () { describe(`prime(${bitLength})`, function () {
it(`should return a random ${bitLength}-bits probable prime`, async function () { it(`should return a random ${bitLength}-bits probable prime`, async function () {
let prime = await bigintCryptoUtils.prime(bitLength); let prime = await bigintCryptoUtils.prime(bitLength);
let bits = 1; let primeBitLength = bigintCryptoUtils.bitLength(prime);
do { chai.expect(primeBitLength).to.equal(bitLength);
bits++; });
} while ((prime >>= BigInt(1)) > BigInt(1)); });
chai.expect(bits).to.equal(bitLength); }
});
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const inputs$6 = [
{
a: BigInt(1),
n: BigInt(19),
toZn: BigInt(1)
},
{
a: BigInt(-25),
n: BigInt(9),
toZn: BigInt(2)
},
{
a: BigInt('12359782465012847510249'),
n: BigInt(5),
toZn: BigInt(4)
}
];
describe('toZn', function () {
for (const input of inputs$6) {
let ret;
describe(`toZn(${input.a}, ${input.n})`, function () {
it(`should return ${input.toZn}`, function () {
ret = bigintCryptoUtils.toZn(input.a, input.n);
chai.expect(ret).to.equal(input.toZn);
}); });
}); });
} }

46
test/gcd.js Normal file
View File

@ -0,0 +1,46 @@
'use strict';
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const bigintCryptoUtils = require('../dist/bigint-crypto-utils-latest.node');
const chai = require('chai');
const inputs = [
{
a: BigInt(1),
b: BigInt(1),
gcd: BigInt(1)
},
{
a: BigInt(1),
b: BigInt('14546149867129487614601346814'),
gcd: BigInt(1)
},
{
a: BigInt(27),
b: BigInt(18),
gcd: BigInt(9)
},
{
a: BigInt(-27),
b: BigInt(18),
gcd: BigInt(9)
},
{
a: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109'),
b: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109') * BigInt('144678545212641449725111562354371812236197961234111744040227045242578772124779004756249085154188369039159690638725821245974978963371615699005072473649705367893567309027634121825164880046600125480885803891136149601797439273507802533807541605261215613891134865916295914192271736572001975016089773532547481638243'),
gcd: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109')
}
];
describe('gcd', function () {
for (const input of inputs) {
let ret;
describe(`gcd(${input.a}, ${input.b})`, function () {
it(`should return ${input.gcd}`, function () {
ret = bigintCryptoUtils.gcd(input.a, input.b);
chai.expect(ret).to.equal(input.gcd);
});
});
}
});

View File

@ -56,7 +56,7 @@ const numbers = [
} }
]; ];
describe('Testing validation of prime numbers', function () { describe('isProbablyPrime', function () {
for (const num of numbers) { for (const num of numbers) {
describe(`isProbablyPrime(${num.value})`, function () { describe(`isProbablyPrime(${num.value})`, function () {
it(`should return ${num.prime}`, async function () { it(`should return ${num.prime}`, async function () {

46
test/lcm.js Normal file
View File

@ -0,0 +1,46 @@
'use strict';
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const bigintCryptoUtils = require('../dist/bigint-crypto-utils-latest.node');
const chai = require('chai');
const inputs = [
{
a: BigInt(1),
b: BigInt(1),
lcm: BigInt(1)
},
{
a: BigInt(1),
b: BigInt('14546149867129487614601346814'),
lcm: BigInt('14546149867129487614601346814')
},
{
a: BigInt(27),
b: BigInt(18),
lcm: BigInt(27) * BigInt(2)
},
{
a: BigInt(-27),
b: BigInt(18),
lcm: BigInt(27) * BigInt(2)
},
{
a: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109'),
b: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109') * BigInt('144678545212641449725111562354371812236197961234111744040227045242578772124779004756249085154188369039159690638725821245974978963371615699005072473649705367893567309027634121825164880046600125480885803891136149601797439273507802533807541605261215613891134865916295914192271736572001975016089773532547481638243'),
lcm: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109') * BigInt('144678545212641449725111562354371812236197961234111744040227045242578772124779004756249085154188369039159690638725821245974978963371615699005072473649705367893567309027634121825164880046600125480885803891136149601797439273507802533807541605261215613891134865916295914192271736572001975016089773532547481638243'),
}
];
describe('lcm', function () {
for (const input of inputs) {
let ret;
describe(`lcm(${input.a}, ${input.b})`, function () {
it(`should return ${input.lcm}`, function () {
ret = bigintCryptoUtils.lcm(input.a, input.b);
chai.expect(ret).to.equal(input.lcm);
});
});
}
});

36
test/modInv.js Normal file
View File

@ -0,0 +1,36 @@
'use strict';
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const bigintCryptoUtils = require('../dist/bigint-crypto-utils-latest.node');
const chai = require('chai');
const inputs = [
{
a: BigInt(1),
n: BigInt(19),
modInv: BigInt(1)
},
{
a: BigInt(2),
n: BigInt(5),
modInv: BigInt(3)
},
{
a: BigInt(-2),
n: BigInt(5),
modInv: BigInt(2)
}
];
describe('modInv', function () {
for (const input of inputs) {
let ret;
describe(`modInv(${input.a}, ${input.n})`, function () {
it(`should return ${input.modInv}`, function () {
ret = bigintCryptoUtils.modInv(input.a, input.n);
chai.expect(ret).to.equal(input.modInv);
});
});
}
});

45
test/modPow.js Normal file
View File

@ -0,0 +1,45 @@
'use strict';
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const bigintCryptoUtils = require('../dist/bigint-crypto-utils-latest.node');
const chai = require('chai');
const inputs = [
{
a: BigInt(4),
b: BigInt(-1),
n: BigInt(19),
modPow: BigInt(5)
},
{
a: BigInt(-5),
b: BigInt(2),
n: BigInt(7),
modPow: BigInt(4)
},
{
a: BigInt(2),
b: BigInt(255),
n: BigInt(64),
modPow: BigInt(0)
},
{
a: BigInt(3),
b: BigInt(3),
n: BigInt(25),
modPow: BigInt(2)
}
];
describe('modPow', function () {
for (const input of inputs) {
let ret;
describe(`modPow(${input.a}, ${input.b}, ${input.n})`, function () {
it(`should return ${input.modPow}`, function () {
ret = bigintCryptoUtils.modPow(input.a, input.b, input.n);
chai.expect(ret).to.equal(input.modPow);
});
});
}
});

View File

@ -12,16 +12,13 @@ const bitLengths = [
4096 4096
]; ];
describe('Testing generation of prime numbers', function () { describe('prime', function () {
for (const bitLength of bitLengths) { for (const bitLength of bitLengths) {
describe(`Executing prime(${bitLength})`, function () { describe(`prime(${bitLength})`, function () {
it(`should return a random ${bitLength}-bits probable prime`, async function () { it(`should return a random ${bitLength}-bits probable prime`, async function () {
let prime = await bigintCryptoUtils.prime(bitLength); let prime = await bigintCryptoUtils.prime(bitLength);
let bits = 1; let primeBitLength = bigintCryptoUtils.bitLength(prime);
do { chai.expect(primeBitLength).to.equal(bitLength);
bits++;
} while ((prime >>= BigInt(1)) > BigInt(1));
chai.expect(bits).to.equal(bitLength);
}); });
}); });
} }

36
test/toZn.js Normal file
View File

@ -0,0 +1,36 @@
'use strict';
// For the browser test builder to work you MUST import them module in a variable that
// is the camelised version of the package name.
const bigintCryptoUtils = require('../dist/bigint-crypto-utils-latest.node');
const chai = require('chai');
const inputs = [
{
a: BigInt(1),
n: BigInt(19),
toZn: BigInt(1)
},
{
a: BigInt(-25),
n: BigInt(9),
toZn: BigInt(2)
},
{
a: BigInt('12359782465012847510249'),
n: BigInt(5),
toZn: BigInt(4)
}
];
describe('toZn', function () {
for (const input of inputs) {
let ret;
describe(`toZn(${input.a}, ${input.n})`, function () {
it(`should return ${input.toZn}`, function () {
ret = bigintCryptoUtils.toZn(input.a, input.n);
chai.expect(ret).to.equal(input.toZn);
});
});
}
});