[v6] Replace elliptic.js with noble-curves, and load noble-hashes dynamically#1694
[v6] Replace elliptic.js with noble-curves, and load noble-hashes dynamically#1694larabr merged 9 commits intoopenpgpjs:v6from
Conversation
87050b3 to
111bf3d
Compare
| const { publicKey: V, privateKey: v } = await curve.genKeyPair(); | ||
|
|
||
| // The output includes parity byte | ||
| const rawSharedSecret = nobleCurve.getSharedSecret(v, Q); | ||
| return { publicKey: V, sharedKey: rawSharedSecret.subarray(1) }; |
There was a problem hiding this comment.
This is very nitpicky but it would be clearer as:
| const { publicKey: V, privateKey: v } = await curve.genKeyPair(); | |
| // The output includes parity byte | |
| const rawSharedSecret = nobleCurve.getSharedSecret(v, Q); | |
| return { publicKey: V, sharedKey: rawSharedSecret.subarray(1) }; | |
| const { publicKey, privateKey } = await curve.genKeyPair(); | |
| const rawSharedSecret = nobleCurve.getSharedSecret(privateKey, Q); | |
| const sharedKey = rawSharedSecret.subarray(1); // Remove parity byte | |
| return { publicKey, sharedKey }; |
(we might also want to rename Q, but doesn't need to be done here).
There was a problem hiding this comment.
I'd avoid "privateKey" and "publicKey" because they are confusing in a context where we also have long-term private and public keys (e.g. Q).
The letters are convenient to follow what's going on, e.g. vQ === vdG === dvG === dV, and they are commonly used (e.g. see X25519 RFC).
Since we already have params named d and Q, I think switching to different names here is confusing, as the function is not generic.
If we really want to rename, I'd go with longTermKeyPair vs ephemeralKeyPair. But in a separate commit, so that it's clearer how the values map to the old ones with the lib switch.
There was a problem hiding this comment.
OK, fair enough. Yeah, I'd prefer to have more descriptive names but indeed we can do it separately 👍
Unlike elliptic, noble-curves targets algorithmic constant time, and it relies on the native BigInts when available, resulting in a smaller bundle and improved performance. Also, expand testing of fallback elliptic implementation.
… by old lib bug At some point we used to generate invalid ECDSA sigs with the js (non-native) elliptic lib, if the signature digest had leading zeros: openpgpjs#948 . Brainpool curves are the most likely to have been affected by the bug, since they do not have WebCrypto support (unlike NIST curves). This commit reintroduces support on web to verify such invalid signatures (support for this was previously built-in in the indutny-elliptic library). It also expands the fix to work in Node.
To reflect change of underlying library
Instead of relying on externally provided one (no async loading supported)
111bf3d to
23f3908
Compare
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.
Using a wrapper requires adding some handling code to fix race conditions, but it does not provide advantages until we switch to TS.
23f3908 to
fdcb199
Compare
…htweight build This is the default setting and it ensures that the main chunk does not include additional exports, which is is important when importing the module as `import *` as shown in the readme. In practice, this change does not affect the chunking with the current code.
fdcb199 to
ac7d2ca
Compare
Unlike elliptic.js, noble-curves targets algorithmic constant-timeness (close #720).
With these changes, both noble-curves and noble-hashes are loaded dynamically, meaning they are not included in the main bundle of the lightweight build.
This results in considerable bundle size optimizations, since these libs rely on the large BN.js lib when native BigInts are not available.
TODO: