Import noble-hashes, noble-curves and BN.js only on demand

This primarily affects the lightweight build, which will not include these
(fairly large) libs in the main bundle file. This allows fetching their code only if required:
- Noble-curves is only needed for curves other than curve25519.
- Noble-hashes is needed for streamed hashing and e.g. SHA3 on web.
- BN.js is used by the above libs, and it's also separately needed for platforms
without native BigInt support.
This commit is contained in:
larabr 2023-10-10 11:23:03 +02:00
parent 5456211266
commit 9e1962f006
15 changed files with 206 additions and 80 deletions

39
src/biginteger.js Normal file
View File

@ -0,0 +1,39 @@
/**
* This is a vanilla JS copy of @openpgp/noble-hashes/esm/biginteger/interface.ts .
* We need to duplicate the file, instead of importing it, since in that case the BigIntegerInterface instance
* would be shared with noble-hashes, which separately calls `setImplementation()` on load, causing it to throw due to
* duplicate initialization.
*/
class BigInteger {
static setImplementation(Implementation, replace = false) {
if (BigInteger.Implementation && !replace) {
throw new Error('Implementation already set');
}
BigInteger.Implementation = Implementation;
}
static new(n) {
return new BigInteger.Implementation(n);
}
}
const detectBigInt = () => typeof BigInt !== 'undefined';
export async function getBigInteger() {
if (BigInteger.Implementation) {
return BigInteger;
}
// TODOOOOO replace = true needed in case of concurrent class loading, how to fix without removing wrapper class?
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');
BigInteger.setImplementation(NativeBigInteger, true);
} 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');
BigInteger.setImplementation(FallbackBigInteger, true);
}
return BigInteger;
}

View File

@ -5,11 +5,6 @@
* @module crypto/hash
*/
import { sha1 } from '@openpgp/noble-hashes/sha1';
import { sha224, sha256 } from '@openpgp/noble-hashes/sha256';
import { sha384, sha512 } from '@openpgp/noble-hashes/sha512';
import { sha3_256, sha3_512 } from '@openpgp/noble-hashes/sha3';
import { ripemd160 } from '@openpgp/noble-hashes/ripemd160';
import * as stream from '@openpgp/web-stream-tools';
import md5 from './md5';
import util from '../../util';
@ -31,48 +26,47 @@ function nodeHash(type) {
};
}
function nobleHash(hash, webCryptoHash) {
function nobleHash(nobleHashName, webCryptoHashName) {
const getNobleHash = async () => {
const { nobleHashes } = await import('./noble_hashes');
const hash = nobleHashes.get(nobleHashName);
if (!hash) throw new Error('Unsupported hash');
return hash;
};
return async function(data) {
if (stream.isArrayStream(data)) {
data = await stream.readToEnd(data);
}
if (util.isStream(data)) {
const hash = await getNobleHash();
const hashInstance = hash.create();
return stream.transform(data, value => {
hashInstance.update(value);
}, () => hashInstance.digest());
} else if (webCrypto && webCryptoHash) {
return new Uint8Array(await webCrypto.digest(webCryptoHash, data));
} else if (webCrypto && webCryptoHashName) {
return new Uint8Array(await webCrypto.digest(webCryptoHashName, data));
} else {
const hash = await getNobleHash();
return hash(data);
}
};
}
const hashFunctions = {
md5: nodeHash('md5') || md5,
sha1: nodeHash('sha1') || nobleHash(sha1, 'SHA-1'),
sha224: nodeHash('sha224') || nobleHash(sha224),
sha256: nodeHash('sha256') || nobleHash(sha256, 'SHA-256'),
sha384: nodeHash('sha384') || nobleHash(sha384, 'SHA-384'),
sha512: nodeHash('sha512') || nobleHash(sha512, 'SHA-512'),
ripemd: nodeHash('ripemd160') || nobleHash(ripemd160),
sha3_256: nodeHash('sha3-256') || nobleHash(sha3_256),
sha3_512: nodeHash('sha3-512') || nobleHash(sha3_512)
};
export default {
/** @see module:md5 */
md5: hashFunctions.md5,
sha1: hashFunctions.sha1,
sha224: hashFunctions.sha224,
sha256: hashFunctions.sha256,
sha384: hashFunctions.sha384,
sha512: hashFunctions.sha512,
ripemd: hashFunctions.ripemd,
sha3_256: hashFunctions.sha3_256,
sha3_512: hashFunctions.sha3_512,
md5: nodeHash('md5') || md5,
sha1: nodeHash('sha1') || nobleHash('sha1', 'SHA-1'),
sha224: nodeHash('sha224') || nobleHash('sha224'),
sha256: nodeHash('sha256') || nobleHash('sha256', 'SHA-256'),
sha384: nodeHash('sha384') || nobleHash('sha384', 'SHA-384'),
sha512: nodeHash('sha512') || nobleHash('sha512', 'SHA-512'),
ripemd: nodeHash('ripemd160') || nobleHash('ripemd160'),
sha3_256: nodeHash('sha3-256') || nobleHash('sha3_256'),
sha3_512: nodeHash('sha3-512') || nobleHash('sha3_512'),
/**
* Create a hash on the specified data using the specified algorithm

View File

@ -0,0 +1,22 @@
/**
* This file is needed to dynamic import the noble-hashes.
* Separate dynamic imports are not convenient as they result in too many chunks,
* which share a lot of code anyway.
*/
import { sha1 } from '@openpgp/noble-hashes/sha1';
import { sha224, sha256 } from '@openpgp/noble-hashes/sha256';
import { sha384, sha512 } from '@openpgp/noble-hashes/sha512';
import { sha3_256, sha3_512 } from '@openpgp/noble-hashes/sha3';
import { ripemd160 } from '@openpgp/noble-hashes/ripemd160';
export const nobleHashes = new Map(Object.entries({
sha1,
sha224,
sha256,
sha384,
sha512,
sha3_256,
sha3_512,
ripemd160
}));

View File

@ -19,7 +19,6 @@
* @fileoverview A Digital signature algorithm implementation
* @module crypto/public_key/dsa
*/
import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import { getRandomBigInteger } from '../random';
import util from '../../util';
import { isProbablePrime } from './prime';
@ -42,6 +41,8 @@ import { isProbablePrime } from './prime';
* @async
*/
export async function sign(hashAlgo, hashed, g, p, q, x) {
const BigInteger = await util.getBigInteger();
const one = BigInteger.new(1);
p = BigInteger.new(p);
q = BigInteger.new(q);
@ -100,6 +101,8 @@ 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 = BigInteger.new(0);
r = BigInteger.new(r);
s = BigInteger.new(s);
@ -142,6 +145,8 @@ 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 = BigInteger.new(p);
q = BigInteger.new(q);
g = BigInteger.new(g);

View File

@ -19,9 +19,9 @@
* @fileoverview ElGamal implementation
* @module crypto/public_key/elgamal
*/
import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import { getRandomBigInteger } from '../random';
import { emeEncode, emeDecode } from '../pkcs1';
import util from '../../util';
/**
* ElGamal Encryption function
@ -34,6 +34,8 @@ import { emeEncode, emeDecode } from '../pkcs1';
* @async
*/
export async function encrypt(data, p, g, y) {
const BigInteger = await util.getBigInteger();
p = BigInteger.new(p);
g = BigInteger.new(g);
y = BigInteger.new(y);
@ -63,6 +65,8 @@ export async function encrypt(data, p, g, y) {
* @async
*/
export async function decrypt(c1, c2, p, x, randomPayload) {
const BigInteger = await util.getBigInteger();
c1 = BigInteger.new(c1);
c2 = BigInteger.new(c2);
p = BigInteger.new(p);
@ -82,6 +86,8 @@ export async function decrypt(c1, c2, p, x, randomPayload) {
* @async
*/
export async function validateParams(p, g, y, x) {
const BigInteger = await util.getBigInteger();
p = BigInteger.new(p);
g = BigInteger.new(g);
y = BigInteger.new(y);

View File

@ -21,7 +21,7 @@
*/
import nacl from '@openpgp/tweetnacl';
import { CurveWithOID, jwkToRawPublic, rawPublicToJWK, privateToJWK, validateStandardParams, getNobleCurve } from './oid_curves';
import { CurveWithOID, jwkToRawPublic, rawPublicToJWK, privateToJWK, validateStandardParams } from './oid_curves';
import * as aesKW from '../../aes_kw';
import { getRandomBytes } from '../../random';
import hash from '../../hash';
@ -210,8 +210,8 @@ export async function decrypt(oid, kdfParams, V, C, Q, d, fingerprint) {
throw err;
}
function jsPrivateEphemeralKey(curve, V, d) {
const nobleCurve = getNobleCurve(curve.name);
async function jsPrivateEphemeralKey(curve, V, d) {
const nobleCurve = await util.getNobleCurve(enums.publicKey.ecdh, curve.name);
// The output includes parity byte
const sharedSecretWithParity = nobleCurve.getSharedSecret(d, V);
const sharedKey = sharedSecretWithParity.subarray(1);
@ -219,7 +219,7 @@ function jsPrivateEphemeralKey(curve, V, d) {
}
async function jsPublicEphemeralKey(curve, Q) {
const nobleCurve = getNobleCurve(curve.name);
const nobleCurve = await util.getNobleCurve(enums.publicKey.ecdh, curve.name);
const { publicKey: V, privateKey: v } = await curve.genKeyPair();
// The output includes parity byte

View File

@ -4,7 +4,6 @@
*/
import x25519 from '@openpgp/tweetnacl';
import { x448 } from '@openpgp/noble-curves/ed448';
import * as aesKW from '../../aes_kw';
import { getRandomBytes } from '../../random';
@ -32,6 +31,7 @@ export async function generate(algo) {
return { A, k };
}
case enums.publicKey.x448: {
const x448 = await util.getNobleCurve(enums.publicKey.x448);
const k = x448.utils.randomPrivateKey();
const A = x448.getPublicKey(k);
return { A, k };
@ -60,6 +60,7 @@ export async function validateParams(algo, A, k) {
return util.equalsUint8Array(A, publicKey);
}
case enums.publicKey.x448: {
const x448 = await util.getNobleCurve(enums.publicKey.x448);
/**
* Derive public point A' from private key
* and expect A == A'
@ -102,6 +103,7 @@ export async function encrypt(algo, data, recipientA) {
return { ephemeralPublicKey, wrappedKey };
}
case enums.publicKey.x448: {
const x448 = await util.getNobleCurve(enums.publicKey.x448);
const ephemeralSecretKey = x448.utils.randomPrivateKey();
const sharedSecret = x448.getSharedSecret(ephemeralSecretKey, recipientA);
const ephemeralPublicKey = x448.getPublicKey(ephemeralSecretKey);
@ -146,6 +148,7 @@ export async function decrypt(algo, ephemeralPublicKey, wrappedKey, A, k) {
return aesKW.unwrap(encryptionKey, wrappedKey);
}
case enums.publicKey.x448: {
const x448 = await util.getNobleCurve(enums.publicKey.x448);
const sharedSecret = x448.getSharedSecret(k, ephemeralPublicKey);
const hkdfInput = util.concatUint8Array([
ephemeralPublicKey,

View File

@ -24,7 +24,7 @@ import enums from '../../../enums';
import util from '../../../util';
import { getRandomBytes } from '../../random';
import hash from '../../hash';
import { CurveWithOID, webCurves, privateToJWK, rawPublicToJWK, validateStandardParams, getNobleCurve } from './oid_curves';
import { CurveWithOID, webCurves, privateToJWK, rawPublicToJWK, validateStandardParams } from './oid_curves';
const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto();
@ -74,7 +74,7 @@ export async function sign(oid, hashAlgo, message, publicKey, privateKey, hashed
}
}
const nobleCurve = getNobleCurve(curve.name);
const nobleCurve = await util.getNobleCurve(enums.publicKey.ecdsa, curve.name);
// lowS: non-canonical sig: https://stackoverflow.com/questions/74338846/ecdsa-signature-verification-mismatch
const signature = nobleCurve.sign(hashed, privateKey, { lowS: false });
return {
@ -103,7 +103,7 @@ export async function verify(oid, hashAlgo, signature, message, publicKey, hashe
// Similarly, secp256k1 should have been used rarely enough.
// However, we implement the fix for all curves, since it's only needed in case of
// verification failure, which is unexpected, hence a minor slowdown is acceptable.
const tryFallbackVerificationForOldBug = () => (
const tryFallbackVerificationForOldBug = async () => (
hashed[0] === 0 ?
jsVerify(curve, signature, hashed.subarray(1), publicKey) :
false
@ -133,7 +133,7 @@ export async function verify(oid, hashAlgo, signature, message, publicKey, hashe
}
}
const verified = jsVerify(curve, signature, hashed, publicKey);
const verified = await jsVerify(curve, signature, hashed, publicKey);
return verified || tryFallbackVerificationForOldBug();
}
@ -183,8 +183,8 @@ export async function validateParams(oid, Q, d) {
* Fallback javascript implementation of ECDSA verification.
* To be used if no native implementation is available for the given curve/operation.
*/
function jsVerify(curve, signature, hashed, publicKey) {
const nobleCurve = getNobleCurve(curve.name);
async function jsVerify(curve, signature, hashed, publicKey) {
const nobleCurve = await util.getNobleCurve(enums.publicKey.ecdsa, curve.name);
// lowS: non-canonical sig: https://stackoverflow.com/questions/74338846/ecdsa-signature-verification-mismatch
return nobleCurve.verify(util.concatUint8Array([signature.r, signature.s]), hashed, publicKey, { lowS: false });
}

View File

@ -20,15 +20,12 @@
* @module crypto/public_key/elliptic/eddsa
*/
import { sha512 } from '@openpgp/noble-hashes/sha512';
import ed25519 from '@openpgp/tweetnacl';
import { ed448 } from '@openpgp/noble-curves/ed448';
import util from '../../../util';
import enums from '../../../enums';
import hash from '../../hash';
import { getRandomBytes } from '../../random';
ed25519.hash = bytes => sha512(bytes);
/**
* Generate (non-legacy) EdDSA key
@ -43,6 +40,7 @@ export async function generate(algo) {
return { A, seed };
}
case enums.publicKey.ed448: {
const ed448 = await util.getNobleCurve(enums.publicKey.ed448);
const seed = ed448.utils.randomPrivateKey();
const A = ed448.getPublicKey(seed);
return { A, seed };
@ -76,6 +74,7 @@ export async function sign(algo, hashAlgo, message, publicKey, privateKey, hashe
return { RS: signature };
}
case enums.publicKey.ed448: {
const ed448 = await util.getNobleCurve(enums.publicKey.ed448);
const signature = ed448.sign(hashed, privateKey);
return { RS: signature };
}
@ -104,8 +103,10 @@ export async function verify(algo, hashAlgo, { RS }, m, publicKey, hashed) {
case enums.publicKey.ed25519: {
return ed25519.sign.detached.verify(hashed, RS, publicKey);
}
case enums.publicKey.ed448:
case enums.publicKey.ed448: {
const ed448 = await util.getNobleCurve(enums.publicKey.ed448);
return ed448.verify(RS, hashed, publicKey);
}
default:
throw new Error('Unsupported EdDSA algorithm');
}
@ -131,6 +132,8 @@ export async function validateParams(algo, A, seed) {
}
case enums.publicKey.ed448: {
const ed448 = await util.getNobleCurve(enums.publicKey.ed448);
const publicKey = ed448.getPublicKey(seed);
return util.equalsUint8Array(A, publicKey);
}

View File

@ -0,0 +1,27 @@
/**
* This file is needed to dynamic import the noble-curves.
* Separate dynamic imports are not convenient as they result in too many chunks,
* which share a lot of code anyway.
*/
import { p256 } from '@openpgp/noble-curves/p256';
import { p384 } from '@openpgp/noble-curves/p384';
import { p521 } from '@openpgp/noble-curves/p521';
import { brainpoolP256r1 } from '@openpgp/noble-curves/brainpoolP256r1';
import { brainpoolP384r1 } from '@openpgp/noble-curves/brainpoolP384r1';
import { brainpoolP512r1 } from '@openpgp/noble-curves/brainpoolP512r1';
import { x448, ed448 } from '@openpgp/noble-curves/ed448';
import { secp256k1 } from '@openpgp/noble-curves/secp256k1';
export const nobleCurves = new Map(Object.entries({
p256,
p384,
p521,
brainpoolP256r1,
brainpoolP384r1,
brainpoolP512r1,
secp256k1,
x448,
ed448
}));

View File

@ -20,20 +20,12 @@
* @module crypto/public_key/elliptic/curve
*/
import nacl from '@openpgp/tweetnacl';
import { p256 } from '@openpgp/noble-curves/p256';
import { p384 } from '@openpgp/noble-curves/p384';
import { p521 } from '@openpgp/noble-curves/p521';
import { brainpoolP256r1 } from '@openpgp/noble-curves/brainpoolP256r1';
import { brainpoolP384r1 } from '@openpgp/noble-curves/brainpoolP384r1';
import { brainpoolP512r1 } from '@openpgp/noble-curves/brainpoolP512r1';
import { secp256k1 } from '@openpgp/noble-curves/secp256k1';
import { getRandomBytes } from '../../random';
import enums from '../../../enums';
import util from '../../../util';
import { uint8ArrayToB64, b64ToUint8Array } from '../../../encoding/base64';
import OID from '../../../type/oid';
import { UnsupportedError } from '../../../packet/packet';
import defaultConfig from '../../../config';
const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto();
@ -56,26 +48,6 @@ const nodeCurves = nodeCrypto ? {
[enums.curve.brainpoolP512r1]: knownCurves.includes('brainpoolP512r1') ? 'brainpoolP512r1' : undefined
} : {};
const nobleCurvess = {
[enums.curve.p256]: p256,
[enums.curve.p384]: p384,
[enums.curve.p521]: p521,
[enums.curve.secp256k1]: secp256k1,
[enums.curve.brainpoolP256r1]: brainpoolP256r1,
[enums.curve.brainpoolP384r1]: brainpoolP384r1,
[enums.curve.brainpoolP512r1]: brainpoolP512r1
};
export const getNobleCurve = curveName => {
if (!defaultConfig.useEllipticFallback) {
// TODO make import dynamic
throw new Error('This curve is only supported in the full build of OpenPGP.js');
}
const curve = nobleCurvess[curveName];
if (!curve) throw new Error('Unsupported curve');
return curve;
};
const curves = {
p256: {
oid: [0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07],
@ -291,7 +263,7 @@ async function validateStandardParams(algo, oid, Q, d) {
return true;
}
const nobleCurve = getNobleCurve(enums.write(enums.curve, oid.toHex()));
const nobleCurve = await util.getNobleCurve(enums.publicKey.ecdsa, enums.write(enums.curve, oid.toHex())); // excluding curve25519Legacy, ecdh and ecdsa use the same curves
/*
* Re-derive public point Q' = dG from private key
* Expect Q == Q'
@ -313,8 +285,8 @@ export {
// Helper functions //
// //
//////////////////////////
function jsGenKeyPair(name) {
const nobleCurve = getNobleCurve(name);
async function jsGenKeyPair(name) {
const nobleCurve = await util.getNobleCurve(enums.publicKey.ecdsa, name); // excluding curve25519Legacy, ecdh and ecdsa use the same curves
const privateKey = nobleCurve.utils.randomPrivateKey();
const publicKey = nobleCurve.getPublicKey(privateKey, false);
return { publicKey, privateKey };

View File

@ -19,7 +19,7 @@
* @fileoverview Algorithms for probabilistic random prime generation
* @module crypto/public_key/prime
*/
import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import util from '../../util';
import { getRandomBigInteger } from '../random';
/**
@ -31,6 +31,8 @@ import { getRandomBigInteger } from '../random';
* @async
*/
export async function randomProbablePrime(bits, e, k) {
const BigInteger = await util.getBigInteger();
const one = BigInteger.new(1);
const min = one.leftShift(BigInteger.new(bits - 1));
const thirty = BigInteger.new(30);
@ -91,11 +93,15 @@ export async function isProbablePrime(n, e, k) {
* @returns {boolean}
*/
export async function fermat(n, b) {
const BigInteger = await util.getBigInteger();
b = b || BigInteger.new(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(BigInteger.new(m)) !== 0;
});
@ -224,6 +230,8 @@ const smallPrimes = [
* @async
*/
export async function millerRabin(n, k, rand) {
const BigInteger = await util.getBigInteger();
const len = n.bitLength();
if (!k) {

View File

@ -19,7 +19,6 @@
* @fileoverview RSA implementation
* @module crypto/public_key/rsa
*/
import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import { randomProbablePrime } from './prime';
import { getRandomBigInteger } from '../random';
import util from '../../util';
@ -159,6 +158,8 @@ 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 = BigInteger.new(e);
// Native RSA keygen using Web Crypto
@ -262,6 +263,8 @@ export async function generate(bits, e) {
* @async
*/
export async function validateParams(n, e, d, p, q, u) {
const BigInteger = await util.getBigInteger();
n = BigInteger.new(n);
p = BigInteger.new(p);
q = BigInteger.new(q);
@ -300,6 +303,8 @@ export async function validateParams(n, e, d, p, q, u) {
}
async function bnSign(hashAlgo, n, d, hashed) {
const BigInteger = await util.getBigInteger();
n = BigInteger.new(n);
const m = BigInteger.new(await emsaEncode(hashAlgo, hashed, n.byteLength()));
d = BigInteger.new(d);
@ -360,6 +365,8 @@ 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 = BigInteger.new(n);
s = BigInteger.new(s);
e = BigInteger.new(e);
@ -427,6 +434,8 @@ async function nodeEncrypt(data, n, e) {
}
async function bnEncrypt(data, n, e) {
const BigInteger = await util.getBigInteger();
n = BigInteger.new(n);
data = BigInteger.new(emeEncode(data, n.byteLength()));
e = BigInteger.new(e);
@ -478,6 +487,8 @@ async function nodeDecrypt(data, n, e, d, p, q, u, randomPayload) {
}
async function bnDecrypt(data, n, e, d, p, q, u, randomPayload) {
const BigInteger = await util.getBigInteger();
data = BigInteger.new(data);
n = BigInteger.new(n);
e = BigInteger.new(e);
@ -519,6 +530,8 @@ 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 = BigInteger.new(p);
const qNum = BigInteger.new(q);
const dNum = BigInteger.new(d);

View File

@ -21,7 +21,6 @@
* @fileoverview Provides tools for retrieving secure randomness from browsers or Node.js
* @module crypto/random
*/
import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import util from '../util';
const nodeCrypto = util.getNodeCrypto();
@ -52,6 +51,8 @@ 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');
}

View File

@ -25,6 +25,8 @@
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 {
@ -48,6 +50,37 @@ const util = {
isStream: stream.isStream,
getBigInteger,
/**
* Load noble-curves lib on demand and return the requested curve function
* @param {enums.publicKey} publicKeyAlgo
* @param {enums.curve} [curveName] - for algos supporting different curves (e.g. ECDSA)
* @returns curve implementation
* @throws on unrecognized curve, or curve not implemented by noble-curve
*/
getNobleCurve: async (publicKeyAlgo, curveName) => {
if (!defaultConfig.useEllipticFallback) {
throw new Error('This curve is only supported in the full build of OpenPGP.js');
}
const { nobleCurves } = await import('./crypto/public_key/elliptic/noble_curves');
switch (publicKeyAlgo) {
case enums.publicKey.ecdh:
case enums.publicKey.ecdsa: {
const curve = nobleCurves.get(curveName);
if (!curve) throw new Error('Unsupported curve');
return curve;
}
case enums.publicKey.x448:
return nobleCurves.get('x448');
case enums.publicKey.ed448:
return nobleCurves.get('ed448');
default:
throw new Error('Unsupported curve');
}
},
readNumber: function (bytes) {
let n = 0;
for (let i = 0; i < bytes.length; i++) {