From ccc777b20c2d06a813eb1934cd6f174880f10190 Mon Sep 17 00:00:00 2001 From: larabr <7375870+larabr@users.noreply.github.com> Date: Thu, 2 May 2024 19:09:23 +0200 Subject: [PATCH] Drop support for platforms without native BigInt (e.g. Safari <14) Remove BN.js fallback, and only keep native BigInteger interface (for algorithmic constant-time functions). Also, add support for TS modules, to move some over from the forked noble repos. --- package-lock.json | 50 +++ package.json | 2 + rollup.config.js | 5 + src/biginteger.js | 20 - src/biginteger.ts | 498 ++++++++++++++++++++++++ src/crypto/public_key/dsa.js | 7 +- src/crypto/public_key/elgamal.js | 8 +- src/crypto/public_key/elliptic/ecdsa.js | 5 +- src/crypto/public_key/prime.js | 9 +- src/crypto/public_key/rsa.js | 15 +- src/crypto/random.js | 3 +- src/util.js | 3 - test/crypto/validate.js | 4 +- tsconfig.json | 2 +- 14 files changed, 565 insertions(+), 66 deletions(-) delete mode 100644 src/biginteger.js create mode 100644 src/biginteger.ts diff --git a/package-lock.json b/package-lock.json index af51d0d7..e9b5d90d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.1.6", "@rollup/plugin-wasm": "^6.2.2", "@types/chai": "^4.3.14", "argon2id": "^1.0.1", @@ -49,6 +50,7 @@ "rollup": "^4.14.1", "sinon": "^17.0.1", "ts-node": "^10.9.2", + "tslib": "^2.6.2", "tsx": "^4.7.2", "typescript": "^5.4.4", "web-streams-polyfill": "^3.3.3" @@ -1007,6 +1009,32 @@ } } }, + "node_modules/@rollup/plugin-typescript": { + "version": "11.1.6", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.6.tgz", + "integrity": "sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0||^3.0.0||^4.0.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + }, + "tslib": { + "optional": true + } + } + }, "node_modules/@rollup/plugin-wasm": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/@rollup/plugin-wasm/-/plugin-wasm-6.2.2.tgz", @@ -7402,6 +7430,12 @@ "strip-bom": "^3.0.0" } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/tsx": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.2.tgz", @@ -8561,6 +8595,16 @@ "terser": "^5.17.4" } }, + "@rollup/plugin-typescript": { + "version": "11.1.6", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.6.tgz", + "integrity": "sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.1.0", + "resolve": "^1.22.1" + } + }, "@rollup/plugin-wasm": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/@rollup/plugin-wasm/-/plugin-wasm-6.2.2.tgz", @@ -13397,6 +13441,12 @@ "strip-bom": "^3.0.0" } }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "tsx": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.2.tgz", diff --git a/package.json b/package.json index a84c243b..5ecc8bd0 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.1.6", "@rollup/plugin-wasm": "^6.2.2", "@types/chai": "^4.3.14", "argon2id": "^1.0.1", @@ -102,6 +103,7 @@ "rollup": "^4.14.1", "sinon": "^17.0.1", "ts-node": "^10.9.2", + "tslib": "^2.6.2", "tsx": "^4.7.2", "typescript": "^5.4.4", "web-streams-polyfill": "^3.3.3" diff --git a/rollup.config.js b/rollup.config.js index c29e0e51..8cdc1458 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -9,6 +9,7 @@ import commonjs from '@rollup/plugin-commonjs'; import replace from '@rollup/plugin-replace'; import terser from '@rollup/plugin-terser'; import { wasm } from '@rollup/plugin-wasm'; +import typescript from '@rollup/plugin-typescript'; // ESlint does not support JSON module imports yet, see https://github.com/eslint/eslint/discussions/15305 // import pkg from './package.json' assert { type: 'json' }; @@ -63,6 +64,7 @@ export default Object.assign([ resolve({ browser: true }), + typescript(), commonjs({ ignore: nodeBuiltinModules.concat(nodeDependencies) }), @@ -85,6 +87,7 @@ export default Object.assign([ ].map(options => ({ ...options, inlineDynamicImports: true })), plugins: [ resolve(), + typescript(), commonjs(), replace({ 'OpenPGP.js VERSION': `OpenPGP.js ${pkg.version}` @@ -104,6 +107,7 @@ export default Object.assign([ resolve({ browser: true }), + typescript(), commonjs({ ignore: nodeBuiltinModules.concat(nodeDependencies) }), @@ -130,6 +134,7 @@ export default Object.assign([ resolve({ browser: true }), + typescript(), commonjs({ ignore: nodeBuiltinModules.concat(nodeDependencies), requireReturnsDefault: 'preferred' diff --git a/src/biginteger.js b/src/biginteger.js deleted file mode 100644 index bd114984..00000000 --- a/src/biginteger.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * We don't use the BigIntegerInterface wrapper from noble-hashes because: - * - importing the instance results in it being shared with noble-hashes, which separately calls `setImplementation()` - * on load, causing it to throw due to duplicate initialization. - * - even duplicating the interface code here to keep a separate instance requires handing a race-conditions the first time - * `getBigInteger` is called, when the code needs to check if the implementation is set, and initialize it if not. - * Ultimately, the interface provides no advantages and it's only needed because of TS. - */ -const detectBigInt = () => typeof BigInt !== 'undefined'; -export async function getBigInteger() { - if (detectBigInt()) { - // NativeBigInteger is small, so it's imported in isolation (it could also be imported at the top level) - const { default: NativeBigInteger } = await import('@openpgp/noble-hashes/esm/biginteger/native.interface'); - return NativeBigInteger; - } else { - // FallbackBigInteger relies on large BN.js lib, which is also used by noble-hashes and noble-curves - const { default: FallbackBigInteger } = await import('@openpgp/noble-hashes/esm/biginteger/bn.interface'); - return FallbackBigInteger; - } -} diff --git a/src/biginteger.ts b/src/biginteger.ts new file mode 100644 index 00000000..c99e5fcd --- /dev/null +++ b/src/biginteger.ts @@ -0,0 +1,498 @@ +/** + * @fileoverview + * BigInteger implementation of basic operations + * that wraps the native BigInt library. + * Operations are not constant time, + * but we try and limit timing leakage where we can + */ +export default class BigInteger { + private value: bigint; + /** + * Get a BigInteger (input must be big endian for strings and arrays) + * @param {Number|String|Uint8Array} n - Value to convert + * @throws {Error} on null or undefined input + */ + constructor(n: Uint8Array | string | number | bigint) { + if (n === undefined) { + throw new Error('Invalid BigInteger input'); + } + + if (n instanceof Uint8Array) { + const bytes = n; + const hexAlphabet = '0123456789ABCDEF'; + let s = ''; + bytes.forEach((v) => { + s += hexAlphabet[v >> 4] + hexAlphabet[v & 15]; + }); + this.value = BigInt('0x0' + s); + } else { + this.value = BigInt(n); + } + } + + clone() { + return new BigInteger(this.value); + } + + /** + * BigInteger increment in place + */ + iinc() { + this.value++; + return this; + } + + /** + * BigInteger increment + * @returns {BigInteger} this + 1. + */ + inc() { + return this.clone().iinc(); + } + + /** + * BigInteger decrement in place + */ + idec() { + this.value--; + return this; + } + + /** + * BigInteger decrement + * @returns {BigInteger} this - 1. + */ + dec() { + return this.clone().idec(); + } + + /** + * BigInteger addition in place + * @param {BigInteger} x - Value to add + */ + iadd(x: BigInteger) { + this.value += x.value; + return this; + } + + /** + * BigInteger addition + * @param {BigInteger} x - Value to add + * @returns {BigInteger} this + x. + */ + add(x: BigInteger) { + return this.clone().iadd(x); + } + + /** + * BigInteger subtraction in place + * @param {BigInteger} x - Value to subtract + */ + isub(x: BigInteger) { + this.value -= x.value; + return this; + } + + /** + * BigInteger subtraction + * @param {BigInteger} x - Value to subtract + * @returns {BigInteger} this - x. + */ + sub(x: BigInteger) { + return this.clone().isub(x); + } + + /** + * BigInteger multiplication in place + * @param {BigInteger} x - Value to multiply + */ + imul(x: BigInteger) { + this.value *= x.value; + return this; + } + + /** + * BigInteger multiplication + * @param {BigInteger} x - Value to multiply + * @returns {BigInteger} this * x. + */ + mul(x: BigInteger) { + return this.clone().imul(x); + } + + /** + * Compute value modulo m, in place + * @param {BigInteger} m - Modulo + */ + imod(m: BigInteger) { + this.value %= m.value; + if (this.isNegative()) { + this.iadd(m); + } + return this; + } + + /** + * Compute value modulo m + * @param {BigInteger} m - Modulo + * @returns {BigInteger} this mod m. + */ + mod(m: BigInteger) { + return this.clone().imod(m); + } + + /** + * Compute modular exponentiation using square and multiply + * @param {BigInteger} e - Exponent + * @param {BigInteger} n - Modulo + * @returns {BigInteger} this ** e mod n. + */ + modExp(e: BigInteger, n: BigInteger) { + if (n.isZero()) throw Error('Modulo cannot be zero'); + if (n.isOne()) return new BigInteger(0); + if (e.isNegative()) throw Error('Unsopported negative exponent'); + + let exp = e.value; + let x = this.value; + + x %= n.value; + let r = BigInt(1); + while (exp > BigInt(0)) { + const lsb = exp & BigInt(1); + exp >>= BigInt(1); // e / 2 + // Always compute multiplication step, to reduce timing leakage + const rx = (r * x) % n.value; + // Update r only if lsb is 1 (odd exponent) + r = lsb ? rx : r; + x = (x * x) % n.value; // Square + } + return new BigInteger(r); + } + + /** + * Compute the inverse of this value modulo n + * Note: this and and n must be relatively prime + * @param {BigInteger} n - Modulo + * @returns {BigInteger} x such that this*x = 1 mod n + * @throws {Error} if the inverse does not exist + */ + modInv(n: BigInteger) { + const { gcd, x } = this._egcd(n); + if (!gcd.isOne()) { + throw new Error('Inverse does not exist'); + } + return x.add(n).mod(n); + } + + /** + * BigInteger division, in place + * @param {BigInteger} n - Value to divide + */ + idiv(n: BigInteger) { + this.value /= n.value; + return this; + } + + /** + * BigInteger division + * @param {BigInteger} n - Value to divide + * @returns {BigInteger} this divded by n. + */ + div(n: BigInteger) { + return this.clone().idiv(n); + } + + /** + * Extended Eucleadian algorithm (http://anh.cs.luc.edu/331/notes/xgcd.pdf) + * Given a = this and b, compute (x, y) such that ax + by = gdc(a, b). + * Negative numbers are also supported. + * @param {BigInteger} b - Second operand + * @returns {{ gcd, x, y: BigInteger }} + */ + private _egcd(bInput: BigInteger) { + let x = BigInt(0); + let y = BigInt(1); + let xPrev = BigInt(1); + let yPrev = BigInt(0); + + // Deal with negative numbers: run algo over absolute values, + // and "move" the sign to the returned x and/or y. + // See https://math.stackexchange.com/questions/37806/extended-euclidean-algorithm-with-negative-numbers + let a = this.abs().value; + let b = bInput.abs().value; + const aNegated = this.isNegative(); + const bNegated = bInput.isNegative(); + + while (b !== BigInt(0)) { + const q = a / b; + let tmp = x; + x = xPrev - q * x; + xPrev = tmp; + + tmp = y; + y = yPrev - q * y; + yPrev = tmp; + + tmp = b; + b = a % b; + a = tmp; + } + + return { + x: new BigInteger(aNegated? -xPrev : xPrev), + y: new BigInteger(bNegated ? -yPrev : yPrev), + gcd: new BigInteger(a), + }; + } + + /** + * Compute greatest common divisor between this and n + * @param {BigInteger} b - Operand + * @returns {BigInteger} gcd + */ + gcd(bInput: BigInteger) { + let a = this.value; + let b = bInput.value; + while (b !== BigInt(0)) { + const tmp = b; + b = a % b; + a = tmp; + } + return new BigInteger(a); + } + + /** + * Shift this to the left by x, in place + * @param {BigInteger} x - Shift value + */ + ileftShift(x: BigInteger) { + this.value <<= x.value; + return this; + } + + /** + * Shift this to the left by x + * @param {BigInteger} x - Shift value + * @returns {BigInteger} this << x. + */ + leftShift(x: BigInteger) { + return this.clone().ileftShift(x); + } + + /** + * Shift this to the right by x, in place + * @param {BigInteger} x - Shift value + */ + irightShift(x: BigInteger) { + this.value >>= x.value; + return this; + } + + /** + * Shift this to the right by x + * @param {BigInteger} x - Shift value + * @returns {BigInteger} this >> x. + */ + rightShift(x: BigInteger) { + return this.clone().irightShift(x); + } + + ixor(x: BigInteger) { + this.value ^= x.value; + return this; + } + + xor(x: BigInteger) { + return this.clone().ixor(x); + } + + ibitwiseAnd(x: BigInteger) { + this.value &= x.value; + return this; + } + + bitwiseAnd(x: BigInteger) { + return this.clone().ibitwiseAnd(x); + } + + ibitwiseOr(x: BigInteger) { + this.value |= x.value; + return this; + } + + /** + * Whether this value is equal to x + * @param {BigInteger} x + * @returns {Boolean} + */ + equal(x: BigInteger) { + return this.value === x.value; + } + + /** + * Whether this value is less than x + * @param {BigInteger} x + * @returns {Boolean} + */ + lt(x: BigInteger) { + return this.value < x.value; + } + + /** + * Whether this value is less than or equal to x + * @param {BigInteger} x + * @returns {Boolean} + */ + lte(x: BigInteger) { + return this.value <= x.value; + } + + /** + * Whether this value is greater than x + * @param {BigInteger} x + * @returns {Boolean} + */ + gt(x: BigInteger) { + return this.value > x.value; + } + + /** + * Whether this value is greater than or equal to x + * @param {BigInteger} x + * @returns {Boolean} + */ + gte(x: BigInteger) { + return this.value >= x.value; + } + + isZero() { + return this.value === BigInt(0); + } + + isOne() { + return this.value === BigInt(1); + } + + isNegative() { + return this.value < BigInt(0); + } + + isEven() { + return !(this.value & BigInt(1)); + } + + abs() { + const res = this.clone(); + if (this.isNegative()) { + res.value = -res.value; + } + return res; + } + + negate() { + const res = this.clone(); + res.value = -res.value; + return res; + } + + /** + * Get this value as a string + * @returns {String} this value. + */ + toString() { + return this.value.toString(); + } + + /** + * Get this value as an exact Number (max 53 bits) + * Fails if this value is too large + * @returns {Number} + */ + toNumber() { + const number = Number(this.value); + if (number > Number.MAX_SAFE_INTEGER) { + // We throw and error to conform with the bn.js implementation + throw new Error('Number can only safely store up to 53 bits'); + } + return number; + } + + /** + * Get value of i-th bit + * @param {Number} i - Bit index + * @returns {Number} Bit value. + */ + getBit(i: number) { + const bit = (this.value >> BigInt(i)) & BigInt(1); + return bit === BigInt(0) ? 0 : 1; + } + + /** + * Compute bit length + * @returns {Number} Bit length. + */ + bitLength() { + const zero = new BigInteger(0); + const one = new BigInteger(1); + const negOne = new BigInteger(-1); + + // -1n >> -1n is -1n + // 1n >> 1n is 0n + const target = this.isNegative() ? negOne : zero; + let bitlen = 1; + const tmp = this.clone(); + while (!tmp.irightShift(one).equal(target)) { + bitlen++; + } + return bitlen; + } + + /** + * Compute byte length + * @returns {Number} Byte length. + */ + byteLength() { + const zero = new BigInteger(0); + const negOne = new BigInteger(-1); + + const target = this.isNegative() ? negOne : zero; + const eight = new BigInteger(8); + let len = 1; + const tmp = this.clone(); + while (!tmp.irightShift(eight).equal(target)) { + len++; + } + return len; + } + + /** + * Get Uint8Array representation of this number + * @param {String} endian - Endianess of output array (defaults to 'be') + * @param {Number} length - Of output array + * @returns {Uint8Array} + */ + toUint8Array(endian = 'be', length: number) { + // we get and parse the hex string (https://coolaj86.com/articles/convert-js-bigints-to-typedarrays/) + // this is faster than shift+mod iterations + let hex = this.value.toString(16); + if (hex.length % 2 === 1) { + hex = '0' + hex; + } + + const rawLength = hex.length / 2; + const bytes = new Uint8Array(length || rawLength); + // parse hex + const offset = length ? length - rawLength : 0; + let i = 0; + while (i < rawLength) { + bytes[i + offset] = parseInt(hex.slice(2 * i, 2 * i + 2), 16); + i++; + } + + if (endian !== 'be') { + bytes.reverse(); + } + + return bytes; + } +} diff --git a/src/crypto/public_key/dsa.js b/src/crypto/public_key/dsa.js index d3fb6e8c..80da4328 100644 --- a/src/crypto/public_key/dsa.js +++ b/src/crypto/public_key/dsa.js @@ -22,6 +22,7 @@ import { getRandomBigInteger } from '../random'; import util from '../../util'; import { isProbablePrime } from './prime'; +import BigInteger from '../../biginteger'; /* TODO regarding the hash function, read: @@ -41,8 +42,6 @@ import { isProbablePrime } from './prime'; * @async */ export async function sign(hashAlgo, hashed, g, p, q, x) { - const BigInteger = await util.getBigInteger(); - const one = new BigInteger(1); p = new BigInteger(p); q = new BigInteger(q); @@ -101,8 +100,6 @@ export async function sign(hashAlgo, hashed, g, p, q, x) { * @async */ export async function verify(hashAlgo, r, s, hashed, g, p, q, y) { - const BigInteger = await util.getBigInteger(); - const zero = new BigInteger(0); r = new BigInteger(r); s = new BigInteger(s); @@ -145,8 +142,6 @@ export async function verify(hashAlgo, r, s, hashed, g, p, q, y) { * @async */ export async function validateParams(p, q, g, y, x) { - const BigInteger = await util.getBigInteger(); - p = new BigInteger(p); q = new BigInteger(q); g = new BigInteger(g); diff --git a/src/crypto/public_key/elgamal.js b/src/crypto/public_key/elgamal.js index 2dc2c2fd..a64b9681 100644 --- a/src/crypto/public_key/elgamal.js +++ b/src/crypto/public_key/elgamal.js @@ -21,7 +21,7 @@ */ import { getRandomBigInteger } from '../random'; import { emeEncode, emeDecode } from '../pkcs1'; -import util from '../../util'; +import BigInteger from '../../biginteger'; /** * ElGamal Encryption function @@ -34,8 +34,6 @@ import util from '../../util'; * @async */ export async function encrypt(data, p, g, y) { - const BigInteger = await util.getBigInteger(); - p = new BigInteger(p); g = new BigInteger(g); y = new BigInteger(y); @@ -65,8 +63,6 @@ export async function encrypt(data, p, g, y) { * @async */ export async function decrypt(c1, c2, p, x, randomPayload) { - const BigInteger = await util.getBigInteger(); - c1 = new BigInteger(c1); c2 = new BigInteger(c2); p = new BigInteger(p); @@ -86,8 +82,6 @@ export async function decrypt(c1, c2, p, x, randomPayload) { * @async */ export async function validateParams(p, g, y, x) { - const BigInteger = await util.getBigInteger(); - p = new BigInteger(p); g = new BigInteger(g); y = new BigInteger(y); diff --git a/src/crypto/public_key/elliptic/ecdsa.js b/src/crypto/public_key/elliptic/ecdsa.js index 35d3c080..9f6f6446 100644 --- a/src/crypto/public_key/elliptic/ecdsa.js +++ b/src/crypto/public_key/elliptic/ecdsa.js @@ -25,6 +25,7 @@ import util from '../../../util'; import { getRandomBytes } from '../../random'; import hash from '../../hash'; import { CurveWithOID, webCurves, privateToJWK, rawPublicToJWK, validateStandardParams, nodeCurves } from './oid_curves'; +import BigInteger from '../../../biginteger'; const webCrypto = util.getWebCrypto(); const nodeCrypto = util.getNodeCrypto(); @@ -72,8 +73,8 @@ export async function sign(oid, hashAlgo, message, publicKey, privateKey, hashed // lowS: non-canonical sig: https://stackoverflow.com/questions/74338846/ecdsa-signature-verification-mismatch const signature = nobleCurve.sign(hashed, privateKey, { lowS: false }); return { - r: signature.r.toUint8Array('be', curve.payloadSize), - s: signature.s.toUint8Array('be', curve.payloadSize) + r: new BigInteger(signature.r).toUint8Array('be', curve.payloadSize), + s: new BigInteger(signature.s).toUint8Array('be', curve.payloadSize) }; } diff --git a/src/crypto/public_key/prime.js b/src/crypto/public_key/prime.js index 8045f638..7664a42c 100644 --- a/src/crypto/public_key/prime.js +++ b/src/crypto/public_key/prime.js @@ -19,6 +19,7 @@ * @fileoverview Algorithms for probabilistic random prime generation * @module crypto/public_key/prime */ +import BigInteger from '../../biginteger'; import util from '../../util'; import { getRandomBigInteger } from '../random'; @@ -31,8 +32,6 @@ import { getRandomBigInteger } from '../random'; * @async */ export async function randomProbablePrime(bits, e, k) { - const BigInteger = await util.getBigInteger(); - const one = new BigInteger(1); const min = one.leftShift(new BigInteger(bits - 1)); const thirty = new BigInteger(30); @@ -93,15 +92,11 @@ export async function isProbablePrime(n, e, k) { * @returns {boolean} */ export async function fermat(n, b) { - const BigInteger = await util.getBigInteger(); - b = b || new BigInteger(2); return b.modExp(n.dec(), n).isOne(); } export async function divisionTest(n) { - const BigInteger = await util.getBigInteger(); - return smallPrimes.every(m => { return n.mod(new BigInteger(m)) !== 0; }); @@ -230,8 +225,6 @@ const smallPrimes = [ * @async */ export async function millerRabin(n, k, rand) { - const BigInteger = await util.getBigInteger(); - const len = n.bitLength(); if (!k) { diff --git a/src/crypto/public_key/rsa.js b/src/crypto/public_key/rsa.js index 3b6b6ccb..862d34b5 100644 --- a/src/crypto/public_key/rsa.js +++ b/src/crypto/public_key/rsa.js @@ -25,6 +25,7 @@ import util from '../../util'; import { uint8ArrayToB64, b64ToUint8Array } from '../../encoding/base64'; import { emsaEncode, emeEncode, emeDecode } from '../pkcs1'; import enums from '../../enums'; +import BigInteger from '../../biginteger'; const webCrypto = util.getWebCrypto(); const nodeCrypto = util.getNodeCrypto(); @@ -141,8 +142,6 @@ export async function decrypt(data, n, e, d, p, q, u, randomPayload) { * @async */ export async function generate(bits, e) { - const BigInteger = await util.getBigInteger(); - e = new BigInteger(e); // Native RSA keygen using Web Crypto @@ -223,8 +222,6 @@ export async function generate(bits, e) { * @async */ export async function validateParams(n, e, d, p, q, u) { - const BigInteger = await util.getBigInteger(); - n = new BigInteger(n); p = new BigInteger(p); q = new BigInteger(q); @@ -263,8 +260,6 @@ export async function validateParams(n, e, d, p, q, u) { } async function bnSign(hashAlgo, n, d, hashed) { - const BigInteger = await util.getBigInteger(); - n = new BigInteger(n); const m = new BigInteger(await emsaEncode(hashAlgo, hashed, n.byteLength())); d = new BigInteger(d); @@ -301,8 +296,6 @@ async function nodeSign(hashAlgo, data, n, e, d, p, q, u) { } async function bnVerify(hashAlgo, s, n, e, hashed) { - const BigInteger = await util.getBigInteger(); - n = new BigInteger(n); s = new BigInteger(s); e = new BigInteger(e); @@ -346,8 +339,6 @@ async function nodeEncrypt(data, n, e) { } async function bnEncrypt(data, n, e) { - const BigInteger = await util.getBigInteger(); - n = new BigInteger(n); data = new BigInteger(emeEncode(data, n.byteLength())); e = new BigInteger(e); @@ -369,8 +360,6 @@ async function nodeDecrypt(data, n, e, d, p, q, u) { } async function bnDecrypt(data, n, e, d, p, q, u, randomPayload) { - const BigInteger = await util.getBigInteger(); - data = new BigInteger(data); n = new BigInteger(n); e = new BigInteger(e); @@ -412,8 +401,6 @@ async function bnDecrypt(data, n, e, d, p, q, u, randomPayload) { * @param {Uint8Array} u */ async function privateToJWK(n, e, d, p, q, u) { - const BigInteger = await util.getBigInteger(); - const pNum = new BigInteger(p); const qNum = new BigInteger(q); const dNum = new BigInteger(d); diff --git a/src/crypto/random.js b/src/crypto/random.js index 4936c97e..4b038587 100644 --- a/src/crypto/random.js +++ b/src/crypto/random.js @@ -21,6 +21,7 @@ * @fileoverview Provides tools for retrieving secure randomness from browsers or Node.js * @module crypto/random */ +import BigInteger from '../biginteger'; import util from '../util'; const nodeCrypto = util.getNodeCrypto(); @@ -51,8 +52,6 @@ export function getRandomBytes(length) { * @async */ export async function getRandomBigInteger(min, max) { - const BigInteger = await util.getBigInteger(); - if (max.lt(min)) { throw new Error('Illegal parameter value: max <= min'); } diff --git a/src/util.js b/src/util.js index 45db97e8..d4635cad 100644 --- a/src/util.js +++ b/src/util.js @@ -26,7 +26,6 @@ import * as stream from '@openpgp/web-stream-tools'; import { createRequire } from 'module'; // Must be stripped in browser built import enums from './enums'; import defaultConfig from './config'; -import { getBigInteger } from './biginteger'; const debugMode = (() => { try { @@ -50,8 +49,6 @@ const util = { isStream: stream.isStream, - getBigInteger, - /** * Load noble-curves lib on demand and return the requested curve function * @param {enums.publicKey} publicKeyAlgo diff --git a/test/crypto/validate.js b/test/crypto/validate.js index e76e4947..7f5e32bf 100644 --- a/test/crypto/validate.js +++ b/test/crypto/validate.js @@ -3,7 +3,7 @@ import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/new chaiUse(chaiAsPromised); import openpgp from '../initOpenpgp.js'; -import util from '../../src/util.js'; +import BigInteger from '../../src/biginteger.js'; const armoredDSAKey = `-----BEGIN PGP PRIVATE KEY BLOCK----- @@ -387,8 +387,6 @@ export default () => { }); it('detect g with small order', async function() { - const BigInteger = await util.getBigInteger(); - const keyPacket = await cloneKeyPacket(egKey); const { p, g } = keyPacket.publicParams; diff --git a/tsconfig.json b/tsconfig.json index a41b561b..6471d348 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "strict": true, "target": "es2021", "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "Bundler", "allowJs": true, "paths": { "openpgp": [ "." ]