From 1ffd1f949dcb74745f6882ac42ab28cefc69905f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Hern=C3=A1ndez=20Serrano?= Date: Sat, 4 May 2019 18:08:30 +0200 Subject: [PATCH] More tests. Fixed bug in modInv(a,n) when a was < 0 --- README.hbs | 2 +- README.md | 22 +- dist/bigint-crypto-utils-latest.browser.js | 32 +- .../bigint-crypto-utils-latest.browser.min.js | 2 +- .../bigint-crypto-utils-latest.browser.mod.js | 33 +- ...int-crypto-utils-latest.browser.mod.min.js | 2 +- dist/bigint-crypto-utils-latest.node.js | 33 +- src/main.js | 42 ++- test/abs.js | 37 +++ test/bitLength.js | 34 +++ test/browser/tests.js | 286 +++++++++++++++++- test/gcd.js | 46 +++ ..._PrimeValidation.js => isProbablyPrime.js} | 2 +- test/lcm.js | 46 +++ test/modInv.js | 36 +++ test/modPow.js | 45 +++ test/{02_PrimeGeneration.js => prime.js} | 11 +- test/toZn.js | 36 +++ 18 files changed, 704 insertions(+), 43 deletions(-) create mode 100644 test/abs.js create mode 100644 test/bitLength.js create mode 100644 test/gcd.js rename test/{01_PrimeValidation.js => isProbablyPrime.js} (98%) create mode 100644 test/lcm.js create mode 100644 test/modInv.js create mode 100644 test/modPow.js rename test/{02_PrimeGeneration.js => prime.js} (63%) create mode 100644 test/toZn.js diff --git a/README.hbs b/README.hbs index 8b209c2..78db684 100644 --- a/README.hbs +++ b/README.hbs @@ -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); // 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); })(); diff --git a/README.md b/README.md index 9fa5392..fd31d38 100644 --- a/README.md +++ b/README.md @@ -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); // 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); })(); @@ -123,7 +123,10 @@ and can be enabled at runtime executing node --experimental-worker with node >
randBits(bitLength, forceLength)Buffer | Uint8Array

Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()

-
randBytes(byteLength, forceLength)Buffer | Uint8Array
+
randBytes(byteLength, forceLength)Promise
+

Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()

+
+
randBytesSync(byteLength, forceLength)Buffer | Uint8Array

Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()

toZn(a, n)bigint
@@ -288,7 +291,20 @@ Secure random bits for both node and browsers. Node version uses crypto.randomFi -## randBytes(byteLength, forceLength) ⇒ Buffer \| Uint8Array +## randBytes(byteLength, forceLength) ⇒ Promise +Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues() + +**Kind**: global function +**Returns**: Promise - A promise that resolves to a Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes + +| Param | Type | Description | +| --- | --- | --- | +| byteLength | number | The desired number of random bytes | +| forceLength | boolean | If we want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1 | + + + +## randBytesSync(byteLength, forceLength) ⇒ Buffer \| Uint8Array Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues() **Kind**: global function diff --git a/dist/bigint-crypto-utils-latest.browser.js b/dist/bigint-crypto-utils-latest.browser.js index 9af7d40..30afa49 100644 --- a/dist/bigint-crypto-utils-latest.browser.js +++ b/dist/bigint-crypto-utils-latest.browser.js @@ -25,6 +25,8 @@ var bigintCryptoUtils = (function (exports) { * @returns {number} - the bit length */ function bitLength(a) { + if (a === _ONE) + return 1; let bits = 1; do { bits++; @@ -160,7 +162,7 @@ var bigintCryptoUtils = (function (exports) { * @returns {bigint} the inverse modulo n */ function modInv(a, n) { - let egcd = eGcd(a, n); + let egcd = eGcd(toZn(a,n), n); if (egcd.b !== _ONE) { return null; // modular inverse does not exist } else { @@ -287,7 +289,7 @@ var bigintCryptoUtils = (function (exports) { */ function randBits(bitLength, forceLength = false) { const byteLength = Math.ceil(bitLength / 8); - let rndBytes = randBytes(byteLength, false); + let rndBytes = randBytesSync(byteLength, false); // Fill with 0's the extra birs rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1); if (forceLength) { @@ -303,9 +305,28 @@ 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 {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) { + 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; { // browser buf = new Uint8Array(byteLength); @@ -345,7 +366,7 @@ var bigintCryptoUtils = (function (exports) { 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()}`; + 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 // event.data = {rnd: , iterations: } @@ -356,7 +377,7 @@ var bigintCryptoUtils = (function (exports) { 'id': event.data.id }); }; - + workerCode += `onmessage = ${onmessage.toString()};`; return _workerUrl(workerCode); @@ -699,6 +720,7 @@ var bigintCryptoUtils = (function (exports) { exports.randBetween = randBetween; exports.randBits = randBits; exports.randBytes = randBytes; + exports.randBytesSync = randBytesSync; exports.toZn = toZn; return exports; diff --git a/dist/bigint-crypto-utils-latest.browser.min.js b/dist/bigint-crypto-utils-latest.browser.min.js index ab98f8d..931b432 100644 --- a/dist/bigint-crypto-utils-latest.browser.min.js +++ b/dist/bigint-crypto-utils-latest.browser.min.js @@ -1 +1 @@ -var bigintCryptoUtils=function(a){'use strict';function c(b){return b=BigInt(b),b>=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<{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 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< {${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{let d=[];const e=(e,f)=>{if(e.isPrime){for(let a=0;ae(a.data,b),d.push(b)}for(let e=0;e=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<{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 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< {${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{let d=[];const e=(e,f)=>{if(e.isPrime){for(let a=0;ae(a.data,b),d.push(b)}for(let e=0;e, iterations: } @@ -353,7 +374,7 @@ function _isProbablyPrimeWorkerUrl() { 'id': event.data.id }); }; - + workerCode += `onmessage = ${onmessage.toString()};`; return _workerUrl(workerCode); @@ -684,4 +705,4 @@ function _isProbablyPrime(w, iterations = 16) { 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 }; diff --git a/dist/bigint-crypto-utils-latest.browser.mod.min.js b/dist/bigint-crypto-utils-latest.browser.mod.min.js index 921b928..55312e0 100644 --- a/dist/bigint-crypto-utils-latest.browser.mod.min.js +++ b/dist/bigint-crypto-utils-latest.browser.mod.min.js @@ -1 +1 @@ -const _ZERO=BigInt(0),_ONE=BigInt(1),_TWO=BigInt(2);function abs(b){return b=BigInt(b),b>=_ZERO?b:-b}function bitLength(b){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<{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{let d=[];const e=(e,f)=>{if(e.isPrime){for(let a=0;ae(a.data,b),d.push(b)}for(let e=0;e min");const c=a-b;let d,e=bitLength(c);do{let a=randBits(e);d=fromBuffer(a)}while(d>c);return d+b}function randBits(a,b=!1){var c=Math.ceil;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< {${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=_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<{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{let d=[];const e=(e,f)=>{if(e.isPrime){for(let a=0;ae(a.data,b),d.push(b)}for(let e=0;e min");const c=a-b;let d,e=bitLength(c);do{let a=randBits(e);d=fromBuffer(a)}while(d>c);return d+b}function randBits(a,b=!1){var c=Math.ceil;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< {${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 { resolve(rnd); }); } @@ -302,7 +304,7 @@ function randBetween(max, min = _ONE) { */ function randBits(bitLength, forceLength = false) { const byteLength = Math.ceil(bitLength / 8); - let rndBytes = randBytes(byteLength, false); + let rndBytes = randBytesSync(byteLength, false); // Fill with 0's the extra birs rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1); if (forceLength) { @@ -318,9 +320,31 @@ 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 {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) { + 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; { // node const crypto = require('crypto'); @@ -724,4 +748,5 @@ exports.prime = prime; exports.randBetween = randBetween; exports.randBits = randBits; exports.randBytes = randBytes; +exports.randBytesSync = randBytesSync; exports.toZn = toZn; diff --git a/src/main.js b/src/main.js index f448e00..df13dc5 100644 --- a/src/main.js +++ b/src/main.js @@ -24,6 +24,8 @@ export function abs(a) { * @returns {number} - the bit length */ export function bitLength(a) { + if (a === _ONE) + return 1; let bits = 1; do { bits++; @@ -184,7 +186,7 @@ export function lcm(a, b) { * @returns {bigint} the inverse modulo n */ export function modInv(a, n) { - let egcd = eGcd(a, n); + let egcd = eGcd(toZn(a,n), n); if (egcd.b !== _ONE) { return null; // modular inverse does not exist } else { @@ -239,7 +241,7 @@ export function prime(bitLength, iterations = 16) { if (!process.browser && !_useWorkers) { let rnd = _ZERO; do { - rnd = fromBuffer(randBytes(bitLength / 8, true)); + rnd = fromBuffer(randBytesSync(bitLength / 8, true)); } while (!_isProbablyPrime(rnd, iterations)); return new Promise((resolve) => { resolve(rnd); }); } @@ -326,7 +328,7 @@ export function randBetween(max, min = _ONE) { */ export function randBits(bitLength, forceLength = false) { const byteLength = Math.ceil(bitLength / 8); - let rndBytes = randBytes(byteLength, false); + let rndBytes = randBytesSync(byteLength, false); // Fill with 0's the extra birs rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1); if (forceLength) { @@ -342,9 +344,37 @@ export 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 {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) { + 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; if (!process.browser) { // node const crypto = require('crypto'); @@ -388,7 +418,7 @@ function fromBuffer(buf) { 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()}`; + 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 // event.data = {rnd: , iterations: } @@ -399,7 +429,7 @@ function _isProbablyPrimeWorkerUrl() { 'id': event.data.id }); }; - + workerCode += `onmessage = ${onmessage.toString()};`; return _workerUrl(workerCode); diff --git a/test/abs.js b/test/abs.js new file mode 100644 index 0000000..eec1ad3 --- /dev/null +++ b/test/abs.js @@ -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); + }); + }); + } +}); \ No newline at end of file diff --git a/test/bitLength.js b/test/bitLength.js new file mode 100644 index 0000000..4edde04 --- /dev/null +++ b/test/bitLength.js @@ -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); + }); + }); + } +}); \ No newline at end of file diff --git a/test/browser/tests.js b/test/browser/tests.js index 9851ee2..4963374 100644 --- a/test/browser/tests.js +++ b/test/browser/tests.js @@ -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 = [ { value: BigInt(1), @@ -54,7 +168,7 @@ const numbers = [ } ]; -describe('Testing validation of prime numbers', function () { +describe('isProbablyPrime', function () { for (const num of numbers) { describe(`isProbablyPrime(${num.value})`, 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 = [ 1024, 2048, @@ -77,16 +315,48 @@ const bitLengths = [ 4096 ]; -describe('Testing generation of prime numbers', function () { +describe('prime', function () { 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 () { let prime = await bigintCryptoUtils.prime(bitLength); - let bits = 1; - do { - bits++; - } while ((prime >>= BigInt(1)) > BigInt(1)); - chai.expect(bits).to.equal(bitLength); + let primeBitLength = bigintCryptoUtils.bitLength(prime); + chai.expect(primeBitLength).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); }); }); } diff --git a/test/gcd.js b/test/gcd.js new file mode 100644 index 0000000..7657e2c --- /dev/null +++ b/test/gcd.js @@ -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); + }); + }); + } +}); \ No newline at end of file diff --git a/test/01_PrimeValidation.js b/test/isProbablyPrime.js similarity index 98% rename from test/01_PrimeValidation.js rename to test/isProbablyPrime.js index 08cb852..a64eaae 100644 --- a/test/01_PrimeValidation.js +++ b/test/isProbablyPrime.js @@ -56,7 +56,7 @@ const numbers = [ } ]; -describe('Testing validation of prime numbers', function () { +describe('isProbablyPrime', function () { for (const num of numbers) { describe(`isProbablyPrime(${num.value})`, function () { it(`should return ${num.prime}`, async function () { diff --git a/test/lcm.js b/test/lcm.js new file mode 100644 index 0000000..84f15d9 --- /dev/null +++ b/test/lcm.js @@ -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); + }); + }); + } +}); \ No newline at end of file diff --git a/test/modInv.js b/test/modInv.js new file mode 100644 index 0000000..6437170 --- /dev/null +++ b/test/modInv.js @@ -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); + }); + }); + } +}); \ No newline at end of file diff --git a/test/modPow.js b/test/modPow.js new file mode 100644 index 0000000..8b5d92f --- /dev/null +++ b/test/modPow.js @@ -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); + }); + }); + } +}); \ No newline at end of file diff --git a/test/02_PrimeGeneration.js b/test/prime.js similarity index 63% rename from test/02_PrimeGeneration.js rename to test/prime.js index be8f07a..58c58b4 100644 --- a/test/02_PrimeGeneration.js +++ b/test/prime.js @@ -12,16 +12,13 @@ const bitLengths = [ 4096 ]; -describe('Testing generation of prime numbers', function () { +describe('prime', function () { 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 () { let prime = await bigintCryptoUtils.prime(bitLength); - let bits = 1; - do { - bits++; - } while ((prime >>= BigInt(1)) > BigInt(1)); - chai.expect(bits).to.equal(bitLength); + let primeBitLength = bigintCryptoUtils.bitLength(prime); + chai.expect(primeBitLength).to.equal(bitLength); }); }); } diff --git a/test/toZn.js b/test/toZn.js new file mode 100644 index 0000000..cf5234c --- /dev/null +++ b/test/toZn.js @@ -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); + }); + }); + } +}); \ No newline at end of file