mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-11-24 14:35:51 +00:00
Use noble-ed25519 over tweetnacl for signature verification (#16)
Much faster than tweetnacl, and no constant-timeness required. We are not using v2 for now, despite being smaller, because it relies on bigint literals, and it requires polyfilling the WebCrypto lib manually in Node < 19.
This commit is contained in:
parent
9fe278241a
commit
0ebf5797a5
13
package-lock.json
generated
13
package-lock.json
generated
@ -11,6 +11,7 @@
|
||||
"devDependencies": {
|
||||
"@noble/ciphers": "^1.0.0",
|
||||
"@noble/curves": "^1.6.0",
|
||||
"@noble/ed25519": "^1.7.3",
|
||||
"@noble/hashes": "^1.5.0",
|
||||
"@openpgp/jsdoc": "^3.6.11",
|
||||
"@openpgp/seek-bzip": "^1.0.5-git",
|
||||
@ -956,6 +957,18 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/ed25519": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz",
|
||||
"integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz",
|
||||
|
||||
@ -64,6 +64,7 @@
|
||||
"devDependencies": {
|
||||
"@noble/ciphers": "^1.0.0",
|
||||
"@noble/curves": "^1.6.0",
|
||||
"@noble/ed25519": "^1.7.3",
|
||||
"@noble/hashes": "^1.5.0",
|
||||
"@openpgp/jsdoc": "^3.6.11",
|
||||
"@openpgp/seek-bzip": "^1.0.5-git",
|
||||
|
||||
@ -100,6 +100,13 @@ const fullBrowserBuild = {
|
||||
commonjs({
|
||||
ignore: nodeBuiltinModules.concat(nodeDependencies)
|
||||
}),
|
||||
replace({
|
||||
include: 'node_modules/@noble/ed25519/**',
|
||||
// Rollup ignores the `browser: { crypto: false }` directive in package.json, since `exports` are present,
|
||||
// hence we need to manually drop it.
|
||||
"import * as nodeCrypto from 'crypto'": 'const nodeCrypto = null',
|
||||
delimiters: ['', '']
|
||||
}),
|
||||
replace({
|
||||
'OpenPGP.js VERSION': `OpenPGP.js ${pkg.version}`,
|
||||
"import { createRequire } from 'module';": 'const createRequire = () => () => {}',
|
||||
@ -127,6 +134,13 @@ const lightweightBrowserBuild = {
|
||||
commonjs({
|
||||
ignore: nodeBuiltinModules.concat(nodeDependencies)
|
||||
}),
|
||||
replace({
|
||||
include: 'node_modules/@noble/ed25519/**',
|
||||
// Rollup ignores the `browser: { crypto: false }` directive in package.json, since `exports` are present,
|
||||
// hence we need to manually drop it.
|
||||
"import * as nodeCrypto from 'crypto'": 'const nodeCrypto = null',
|
||||
delimiters: ['', '']
|
||||
}),
|
||||
replace({
|
||||
'OpenPGP.js VERSION': `OpenPGP.js ${pkg.version}`,
|
||||
"import { createRequire } from 'module';": 'const createRequire = () => () => {}',
|
||||
@ -158,6 +172,13 @@ const testBuild = {
|
||||
ignore: nodeBuiltinModules.concat(nodeDependencies),
|
||||
requireReturnsDefault: 'preferred'
|
||||
}),
|
||||
replace({
|
||||
include: 'node_modules/@noble/ed25519/**',
|
||||
// Rollup ignores the `browser: { crypto: false }` directive in package.json, since `exports` are present,
|
||||
// hence we need to manually drop it.
|
||||
"import * as nodeCrypto from 'crypto'": 'const nodeCrypto = null',
|
||||
delimiters: ['', '']
|
||||
}),
|
||||
replace({
|
||||
"import { createRequire } from 'module';": 'const createRequire = () => () => {}',
|
||||
delimiters: ['', '']
|
||||
|
||||
@ -20,7 +20,9 @@
|
||||
* @module crypto/public_key/elliptic/eddsa
|
||||
*/
|
||||
|
||||
import ed25519 from '@openpgp/tweetnacl';
|
||||
import naclEd25519 from '@openpgp/tweetnacl'; // better constant-timeness as it uses Uint8Arrays over BigInts
|
||||
import { verify as nobleEd25519Verify } from '@noble/ed25519';
|
||||
|
||||
import util from '../../../util';
|
||||
import enums from '../../../enums';
|
||||
import { getHashByteLength } from '../../hash';
|
||||
@ -52,7 +54,7 @@ export async function generate(algo) {
|
||||
throw err;
|
||||
}
|
||||
const seed = getRandomBytes(getPayloadSize(algo));
|
||||
const { publicKey: A } = ed25519.sign.keyPair.fromSeed(seed);
|
||||
const { publicKey: A } = naclEd25519.sign.keyPair.fromSeed(seed);
|
||||
return { A, seed };
|
||||
}
|
||||
|
||||
@ -104,7 +106,7 @@ export async function sign(algo, hashAlgo, message, publicKey, privateKey, hashe
|
||||
throw err;
|
||||
}
|
||||
const secretKey = util.concatUint8Array([privateKey, publicKey]);
|
||||
const signature = ed25519.sign.detached(hashed, secretKey);
|
||||
const signature = naclEd25519.sign.detached(hashed, secretKey);
|
||||
return { RS: signature };
|
||||
}
|
||||
|
||||
@ -149,7 +151,7 @@ export async function verify(algo, hashAlgo, { RS }, m, publicKey, hashed) {
|
||||
if (err.name !== 'NotSupportedError') {
|
||||
throw err;
|
||||
}
|
||||
return ed25519.sign.detached.verify(hashed, RS, publicKey);
|
||||
return nobleEd25519Verify(RS, hashed, publicKey);
|
||||
}
|
||||
|
||||
case enums.publicKey.ed448: {
|
||||
@ -177,7 +179,7 @@ export async function validateParams(algo, A, seed) {
|
||||
* and expect A == A'
|
||||
* TODO: move to sign-verify using WebCrypto (same as ECDSA) when curve is more widely implemented
|
||||
*/
|
||||
const { publicKey } = ed25519.sign.keyPair.fromSeed(seed);
|
||||
const { publicKey } = naclEd25519.sign.keyPair.fromSeed(seed);
|
||||
return util.equalsUint8Array(A, publicKey);
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
* @module crypto/public_key/elliptic/eddsa_legacy
|
||||
*/
|
||||
|
||||
import nacl from '@openpgp/tweetnacl';
|
||||
import naclEd25519 from '@openpgp/tweetnacl'; // better constant-timeness as it uses Uint8Arrays over BigInts
|
||||
import util from '../../../util';
|
||||
import enums from '../../../enums';
|
||||
import { getHashByteLength } from '../../hash';
|
||||
@ -101,7 +101,7 @@ export async function validateParams(oid, Q, k) {
|
||||
* Derive public point Q' = dG from private key
|
||||
* and expect Q == Q'
|
||||
*/
|
||||
const { publicKey } = nacl.sign.keyPair.fromSeed(k);
|
||||
const { publicKey } = naclEd25519.sign.keyPair.fromSeed(k);
|
||||
const dG = new Uint8Array([0x40, ...publicKey]); // Add public key prefix
|
||||
return util.equalsUint8Array(Q, dG);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user