diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1e2dc1b --- /dev/null +++ b/.gitignore @@ -0,0 +1,68 @@ +# Project specific files +dist/bigint-mod-arith-?.?.?.* + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# next.js build output +.next + +# Visual Studio Code +.vscode + diff --git a/README.hbs b/README.hbs index 1b0d1c8..a7c2ca1 100644 --- a/README.hbs +++ b/README.hbs @@ -1,62 +1,52 @@ # bigint-mod-arith -Some extra functions to work with modular arithmetics using native JS (stage 3) implementation of BigInt. It can be used -with Node.js (>=10.4.0) and [Web Browsers supporting -BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility). +Some extra functions to work with modular arithmetics using native JS (stage 3) implementation of BigInt. It can be used by any [Web Browser or webview supporting BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) and with Node.js (>=10.4.0). -If you are looking for a cryptographically secure random generator and for probale primes (generation and testing), you +If you are looking for a cryptographically-secure random generator and for strong probable primes (generation and testing), you may be interested in [bigint-secrets](https://github.com/juanelas/bigint-secrets) -_The operations supported on BigInts are not constant time. BigInt can be therefore **[unsuitable for use in -cryptography](https://www.chosenplaintext.ca/articles/beginners-guide-constant-time-cryptography.html)**_ - -Many platforms provide native support for cryptography, such as -[webcrypto](https://w3c.github.io/webcrypto/Overview.html) or [node -crypto](https://nodejs.org/dist/latest/docs/api/crypto.html). +_The operations supported on BigInts are not constant time. BigInt can be therefore **[unsuitable for use in cryptography](https://www.chosenplaintext.ca/articles/beginners-guide-constant-time-cryptography.html).** Many platforms provide native support for cryptography, such as [Web Cryptography API](https://w3c.github.io/webcrypto/) or [Node.js Crypto](https://nodejs.org/dist/latest/docs/api/crypto.html)._ ## Installation -bigint-mod-arith is distributed as both an ES6 and a CJS module. - -The ES6 module is built for any [web browser supporting -BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility). -The module only uses native javascript implementations and no polyfills had been applied. - -The CJS module is built as a standard node module. +bigint-mod-arith is distributed for [web browsers and/or webviews supporting +BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) +as an ES6 module or an IIFE file; and for Node.js (>=10.4.0), as a CJS module. bigint-mod-arith can be imported to your project with `npm`: ```bash npm install bigint-mod-arith ``` +NPM installation defaults to the ES6 module for browsers and the CJS one for Node.js. -For web browsers, you can also [download the bundle from -GitHub](https://raw.githubusercontent.com/juanelas/bigint-mod-arith/master/dist/bigint-mod-arith-latest.browser.mod.min.js). +For web browsers, you can also directly download the minimised version of the [IIFE file](https://raw.githubusercontent.com/juanelas/bigint-mod-arith/master/dist/bigint-mod-arith-latest.browser.min.js) or the [ES6 module](https://raw.githubusercontent.com/juanelas/bigint-mod-arith/master/dist/bigint-mod-arith-latest.browser.mod.min.js) from GitHub. -## Usage examples +## Usage example With node js: ```javascript const bigintModArith = require('bigint-mod-arith'); -// Stage 3 BigInts with value 666 can be declared as BigInt('666') -// or the shorter no-linter-friendly new syntax 666n - +/* Stage 3 BigInts with value 666 can be declared as BigInt('666') +or the shorter new no-so-linter-friendly syntax 666n. +Notice that you can also pass a number, e.g. BigInt(666), but it is not +recommended since values over 2**53 - 1 won't be safe but no warning will +be raised. +*/ let a = BigInt('5'); let b = BigInt('2'); let n = BigInt('19'); -console.log(bigintModArith.modPow(a, b, n)); // prints 6 +console.log(bigintCryptoUtils.modPow(a, b, n)); // prints 6 -console.log(bigintModArith.modInv(BigInt('2'), BigInt('5'))); // prints 3 +console.log(bigintCryptoUtils.modInv(BigInt('2'), BigInt('5'))); // prints 3 -console.log(bigintModArith.modInv(BigInt('3'), BigInt('5'))); // prints 2 +console.log(bigintCryptoUtils.modInv(BigInt('3'), BigInt('5'))); // prints 2 ``` From a browser, you can just load the module in a html page as: ```html -``` +For web browsers, you can also directly download the minimised version of the [IIFE file](https://raw.githubusercontent.com/juanelas/bigint-mod-arith/master/dist/bigint-mod-arith-latest.browser.min.js) or the [ES6 module](https://raw.githubusercontent.com/juanelas/bigint-mod-arith/master/dist/bigint-mod-arith-latest.browser.mod.min.js) from GitHub. -## Usage examples +## Usage example +With node js: ```javascript const bigintModArith = require('bigint-mod-arith'); -// Stage 3 BigInts with value 666 can be declared as BigInt('666') -// or the shorter no-linter-friendly new syntax 666n - -let a = BigInt('5'); -let b = BigInt('2'); +/* Stage 3 BigInts with value 666 can be declared as BigInt('666') +or the shorter new no-so-linter-friendly syntax 666n. +Notice that you can also pass a number, e.g. BigInt(666), but it is not +recommended since values over 2**53 - 1 won't be safe but no warning will +be raised. +*/ +let a = BigInt('5'); +let b = BigInt('2'); let n = BigInt('19'); - -console.log(bigintModArith.modPow(a, b, n)); // prints 6 - -console.log(bigintModArith.modInv(BigInt('2'), BigInt('5'))); // prints 3 - -console.log(bigintModArith.modInv(BigInt('3'), BigInt('5'))); // prints 2 + +console.log(bigintCryptoUtils.modPow(a, b, n)); // prints 6 + +console.log(bigintCryptoUtils.modInv(BigInt('2'), BigInt('5'))); // prints 3 + +console.log(bigintCryptoUtils.modInv(BigInt('3'), BigInt('5'))); // prints 2 +``` + +From a browser, you can just load the module in a html page as: +```html + ``` # bigint-mod-arith JS Doc @@ -52,25 +68,25 @@ console.log(bigintModArith.modInv(BigInt('3'), BigInt('5'))); // prints 2
bigint
Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0
egcdReturn
An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm. +Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).
+bigint
Greatest-common divisor of two integers based on the iterative binary algorithm.
bigint
The least common multiple computed as abs(a*b)/gcd(a,b)
bigint
Finds the smallest positive element that is congruent to a in modulo n
-egcdReturn
An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm. -Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).
-bigint
Modular inverse.
bigint
Modular exponentiation a**b mod n
bigint
Finds the smallest positive element that is congruent to a in modulo n
+number
\| bigint
|
+
+
+## eGcd(a, b) ⇒ [egcdReturn
](#egcdReturn)
+An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm.
+Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).
+
+**Kind**: global function
+
+| Param | Type |
+| --- | --- |
+| a | number
\| bigint
|
+| b | number
\| bigint
|
+
## gcd(a, b) ⇒ bigint
@@ -119,32 +148,6 @@ The least common multiple computed as abs(a*b)/gcd(a,b)
| a | number
\| bigint
|
| b | number
\| bigint
|
-
-
-## toZn(a, n) ⇒ bigint
-Finds the smallest positive element that is congruent to a in modulo n
-
-**Kind**: global function
-**Returns**: bigint
- The smallest positive representation of a in modulo n
-
-| Param | Type | Description |
-| --- | --- | --- |
-| a | number
\| bigint
| An integer |
-| n | number
\| bigint
| The modulo |
-
-
-
-## eGcd(a, b) ⇒ [egcdReturn
](#egcdReturn)
-An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm.
-Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).
-
-**Kind**: global function
-
-| Param | Type |
-| --- | --- |
-| a | number
\| bigint
|
-| b | number
\| bigint
|
-
## modInv(a, n) ⇒ bigint
@@ -172,6 +175,19 @@ Modular exponentiation a**b mod n
| b | number
\| bigint
| exponent |
| n | number
\| bigint
| modulo |
+
+
+## toZn(a, n) ⇒ bigint
+Finds the smallest positive element that is congruent to a in modulo n
+
+**Kind**: global function
+**Returns**: bigint
- The smallest positive representation of a in modulo n
+
+| Param | Type | Description |
+| --- | --- | --- |
+| a | number
\| bigint
| An integer |
+| n | number
\| bigint
| The modulo |
+
## egcdReturn : Object
@@ -187,4 +203,4 @@ A triple (g, x, y), such that ax + by = g = gcd(a, b).
| y | bigint
|
-* * *
+* * *
\ No newline at end of file
diff --git a/build/build.rollup.js b/build/build.rollup.js
index 9e46a21..8b7c4bc 100644
--- a/build/build.rollup.js
+++ b/build/build.rollup.js
@@ -1,48 +1,73 @@
+'use strict';
+
const rollup = require('rollup');
-const commonjs = require('rollup-plugin-commonjs');
const minify = require('rollup-plugin-babel-minify');
const fs = require('fs');
const path = require('path');
const pkgJson = require('../package.json');
+const rootDir = path.join(__dirname, '..');
+const srcDir = path.join(rootDir, 'src');
+const dstDir = path.join(rootDir, 'dist');
const buildOptions = [
{ // Browser
input: {
- input: path.join(__dirname, '..', 'src', 'main.js'),
- plugins: [
- commonjs()
- ],
+ input: path.join(srcDir, 'main.js')
},
output: {
- file: path.join(__dirname, '..', 'dist', `${pkgJson.name}-${pkgJson.version}.browser.mod.js`),
- format: 'esm'
+ file: path.join(dstDir, `${pkgJson.name}-${pkgJson.version}.browser.js`),
+ format: 'iife',
+ name: camelise(pkgJson.name)
}
},
{ // Browser minified
input: {
- input: path.join(__dirname, '..', 'src', 'main.js'),
+ input: path.join(srcDir, 'main.js'),
plugins: [
- commonjs(),
minify({
'comments': false
})
],
},
output: {
- file: path.join(__dirname, '..', 'dist', `${pkgJson.name}-${pkgJson.version}.browser.mod.min.js`),
+ file: path.join(dstDir, `${pkgJson.name}-${pkgJson.version}.browser.min.js`),
+ format: 'iife',
+ name: camelise(pkgJson.name)
+ }
+ },
+ { // Browser esm
+ input: {
+ input: path.join(srcDir, 'main.js')
+ },
+ output: {
+ file: path.join(dstDir, `${pkgJson.name}-${pkgJson.version}.browser.mod.js`),
+ format: 'esm'
+ }
+ },
+ { // Browser esm minified
+ input: {
+ input: path.join(srcDir, 'main.js'),
+ plugins: [
+ minify({
+ 'comments': false
+ })
+ ],
+ },
+ output: {
+ file: path.join(dstDir, `${pkgJson.name}-${pkgJson.version}.browser.mod.min.js`),
format: 'esm'
}
},
{ // Node
input: {
- input: path.join(__dirname, '..', 'src', 'main.js'),
+ input: path.join(srcDir, 'main.js'),
},
output: {
- file: path.join(__dirname, '..', 'dist', `${pkgJson.name}-${pkgJson.version}.node.js`),
+ file: path.join(dstDir, `${pkgJson.name}-${pkgJson.version}.node.js`),
format: 'cjs'
}
- },
+ }
];
for (const options of buildOptions) {
@@ -50,7 +75,6 @@ for (const options of buildOptions) {
}
-
/* --- HELPLER FUNCTIONS --- */
async function build(options) {
@@ -69,3 +93,10 @@ async function build(options) {
options.output.file.replace(`${pkgJson.name}-${pkgJson.version}.`, `${pkgJson.name}-latest.`)
);
}
+
+function camelise(str) {
+ return str.replace(/-([a-z])/g,
+ function (m, w) {
+ return w.toUpperCase();
+ });
+}
\ No newline at end of file
diff --git a/dist/bigint-mod-arith-latest.browser.mod.js b/dist/bigint-mod-arith-latest.browser.mod.js
index 85bb47b..bb83052 100644
--- a/dist/bigint-mod-arith-latest.browser.mod.js
+++ b/dist/bigint-mod-arith-latest.browser.mod.js
@@ -1,3 +1,7 @@
+const _ZERO = BigInt(0);
+const _ONE = BigInt(1);
+const _TWO = BigInt(2);
+
/**
* Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0
*
@@ -5,68 +9,10 @@
*
* @returns {bigint} the absolute value of a
*/
-const abs = function (a) {
+function abs(a) {
a = BigInt(a);
- return (a >= BigInt(0)) ? a : -a;
-};
-
-/**
- * Greatest-common divisor of two integers based on the iterative binary algorithm.
- *
- * @param {number|bigint} a
- * @param {number|bigint} b
- *
- * @returns {bigint} The greatest common divisor of a and b
- */
-const gcd = function (a, b) {
- a = abs(a);
- b = abs(b);
- let shift = BigInt(0);
- while (!((a | b) & BigInt(1))) {
- a >>= BigInt(1);
- b >>= BigInt(1);
- shift++;
- }
- while (!(a & BigInt(1))) a >>= BigInt(1);
- do {
- while (!(b & BigInt(1))) b >>= BigInt(1);
- if (a > b) {
- let x = a;
- a = b;
- b = x;
- }
- b -= a;
- } while (b);
-
- // rescale
- return a << shift;
-};
-
-/**
- * The least common multiple computed as abs(a*b)/gcd(a,b)
- * @param {number|bigint} a
- * @param {number|bigint} b
- *
- * @returns {bigint} The least common multiple of a and b
- */
-const lcm = function (a, b) {
- a = BigInt(a);
- b = BigInt(b);
- return abs(a * b) / gcd(a, b);
-};
-
-/**
- * Finds the smallest positive element that is congruent to a in modulo n
- * @param {number|bigint} a An integer
- * @param {number|bigint} n The modulo
- *
- * @returns {bigint} The smallest positive representation of a in modulo n
- */
-const toZn = function (a, n) {
- n = BigInt(n);
- a = BigInt(a) % n;
- return (a < 0) ? a + n : a;
-};
+ return (a >= _ZERO) ? a : -a;
+}
/**
* @typedef {Object} egcdReturn A triple (g, x, y), such that ax + by = g = gcd(a, b).
@@ -83,15 +29,15 @@ const toZn = function (a, n) {
*
* @returns {egcdReturn}
*/
-const eGcd = function (a, b) {
+function eGcd(a, b) {
a = BigInt(a);
b = BigInt(b);
- let x = BigInt(0);
- let y = BigInt(1);
- let u = BigInt(1);
- let v = BigInt(0);
+ let x = _ZERO;
+ let y = _ONE;
+ let u = _ONE;
+ let v = _ZERO;
- while (a !== BigInt(0)) {
+ while (a !== _ZERO) {
let q = b / a;
let r = b % a;
let m = x - (u * q);
@@ -108,7 +54,52 @@ const eGcd = function (a, b) {
x: x,
y: y
};
-};
+}
+
+/**
+ * Greatest-common divisor of two integers based on the iterative binary algorithm.
+ *
+ * @param {number|bigint} a
+ * @param {number|bigint} b
+ *
+ * @returns {bigint} The greatest common divisor of a and b
+ */
+function gcd(a, b) {
+ a = abs(a);
+ b = abs(b);
+ let shift = _ZERO;
+ while (!((a | b) & _ONE)) {
+ a >>= _ONE;
+ b >>= _ONE;
+ shift++;
+ }
+ while (!(a & _ONE)) a >>= _ONE;
+ do {
+ while (!(b & _ONE)) b >>= _ONE;
+ if (a > b) {
+ let x = a;
+ a = b;
+ b = x;
+ }
+ b -= a;
+ } while (b);
+
+ // rescale
+ return a << shift;
+}
+
+/**
+ * The least common multiple computed as abs(a*b)/gcd(a,b)
+ * @param {number|bigint} a
+ * @param {number|bigint} b
+ *
+ * @returns {bigint} The least common multiple of a and b
+ */
+function lcm(a, b) {
+ a = BigInt(a);
+ b = BigInt(b);
+ return abs(a * b) / gcd(a, b);
+}
/**
* Modular inverse.
@@ -118,14 +109,14 @@ const eGcd = function (a, b) {
*
* @returns {bigint} the inverse modulo n
*/
-const modInv = function (a, n) {
+function modInv(a, n) {
let egcd = eGcd(a, n);
- if (egcd.b !== BigInt(1)) {
+ if (egcd.b !== _ONE) {
return null; // modular inverse does not exist
} else {
return toZn(egcd.x, n);
}
-};
+}
/**
* Modular exponentiation a**b mod n
@@ -135,20 +126,20 @@ const modInv = function (a, n) {
*
* @returns {bigint} a**b mod n
*/
-const modPow = function (a, b, n) {
+function modPow(a, b, n) {
// See Knuth, volume 2, section 4.6.3.
n = BigInt(n);
a = toZn(a, n);
b = BigInt(b);
- if (b < BigInt(0)) {
+ if (b < _ZERO) {
return modInv(modPow(a, abs(b), n), n);
}
- let result = BigInt(1);
+ let result = _ONE;
let x = a;
while (b > 0) {
- var leastSignificantBit = b % BigInt(2);
- b = b / BigInt(2);
- if (leastSignificantBit == BigInt(1)) {
+ var leastSignificantBit = b % _TWO;
+ b = b / _TWO;
+ if (leastSignificantBit == _ONE) {
result = result * x;
result = result % n;
}
@@ -156,20 +147,19 @@ const modPow = function (a, b, n) {
x = x % n;
}
return result;
-};
+}
-var main = {
- abs: abs,
- gcd: gcd,
- lcm: lcm,
- modInv: modInv,
- modPow: modPow
-};
-var main_1 = main.abs;
-var main_2 = main.gcd;
-var main_3 = main.lcm;
-var main_4 = main.modInv;
-var main_5 = main.modPow;
+/**
+ * Finds the smallest positive element that is congruent to a in modulo n
+ * @param {number|bigint} a An integer
+ * @param {number|bigint} n The modulo
+ *
+ * @returns {bigint} The smallest positive representation of a in modulo n
+ */
+function toZn(a, n) {
+ n = BigInt(n);
+ a = BigInt(a) % n;
+ return (a < 0) ? a + n : a;
+}
-export default main;
-export { main_1 as abs, main_2 as gcd, main_3 as lcm, main_4 as modInv, main_5 as modPow };
+export { abs, eGcd, gcd, lcm, modInv, modPow, toZn };
diff --git a/dist/bigint-mod-arith-latest.browser.mod.min.js b/dist/bigint-mod-arith-latest.browser.mod.min.js
index 952f775..8bdd544 100644
--- a/dist/bigint-mod-arith-latest.browser.mod.min.js
+++ b/dist/bigint-mod-arith-latest.browser.mod.min.js
@@ -1 +1 @@
-const abs=function(b){return b=BigInt(b),b>=BigInt(0)?b:-b},gcd=function(c,d){c=abs(c),d=abs(d);let e=BigInt(0);for(;!((c|d)&BigInt(1));)c>>=BigInt(1),d>>=BigInt(1),e++;for(;!(c&BigInt(1));)c>>=BigInt(1);do{for(;!(d&BigInt(1));)d>>=BigInt(1);if(c>d){let a=c;c=d,d=a}d-=c}while(d);return c<