mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-03-30 15:08:32 +00:00
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.
This commit is contained in:
parent
7e2ea3f871
commit
d1a24d1758
50
package-lock.json
generated
50
package-lock.json
generated
@ -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",
|
||||
|
@ -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"
|
||||
|
@ -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'
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
498
src/biginteger.ts
Normal file
498
src/biginteger.ts
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
"strict": true,
|
||||
"target": "es2021",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "Bundler",
|
||||
"allowJs": true,
|
||||
"paths": {
|
||||
"openpgp": [ "." ]
|
||||
|
Loading…
x
Reference in New Issue
Block a user