-
Notifications
You must be signed in to change notification settings - Fork 274
Update secp2561 ECDSA dependency to v4.0.0 #228
Conversation
Have also submitted an issue #229 to split the test cases into separate files, this would actually ease the work here. |
3684eba
to
d8434f8
Compare
Rebased this on top of #231 |
package.json
Outdated
@@ -92,7 +92,7 @@ | |||
"ethjs-util": "0.1.6", | |||
"keccak": "^3.0.0", | |||
"rlp": "^2.2.3", | |||
"secp256k1": "^3.0.1" | |||
"secp256k1": "^4.0.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this bump and keccak having been bumped to ^3.0.0
should an "engines"
field be added to package.json?
"engines": { "node": ">=10.0.0" }
Likewise, should Node 8.x be dropped from the testing matrix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no experience with the engines
field but I would assume it would make sense to use this throughout the EthereumJS libraries in general. Does this prevent an installation from happening when defined too strict?
Yes, Node 8 should then also be dropped from the test matrix. We nevertheless need to get these basic decisions outlined above done first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"engines"
behavior varies depending on whether npm
is used or yarn
is used.
In the case of npm
, the restriction is only enforced with respect to your project's package.json
. That is, if dev/Deps listed in your project's package.json
have an "engines"
setting that isn't satisfied, it doesn't matter, they'll get installed anyway. But if your project's package.json
has an "engines"
setting that isn't satisfied, then running npm install
in your project will fail.
In the case of yarn
both your project's and its dependencies' "engines"
settings are checked and yarn install
will fail if there is any mismatch.
Either way, the "engines"
setting is helpful metadata for humans, signaling a package manager's intention to support some Node versions and not others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, thanks, but then I would assume at least to define a max version is somewhat dangerous and should eventually be skipped.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typically you only want a max version if you know that, for some reason, your package isn't compatible with a newer version of node.
For awhile the embark
package had:
"engines": { "node": ">=10.17.0 <12.0.0" }
10.17.0 was the first Node version that had a change to Node's built-in scrypt that we wanted to be sure was in-place in a user's setup; at the same time, we had some transitive dependencies that weren't yet compatible with Node >=12.0.0
. We eventually resolved the latter and now we have:
"engines": { "node": ">=10.17.0" }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, right, likely a case-by-case decision. If there is a dependency clearly not compatible on the upper bound it makes sense to narrow. If one is is potentially - and unnecessarily - preventing users to upgrade to a future Node version, this should be left open.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cgewecke ah, and can you also add an engines
field with "engines": { "node": ">=10.0.0" }
as suggested in the first comment here?
Update: had another short look, actually it's not the success cases which fail (e.g. These now throw with the new library (behavior before: evaluate to PATH/ethereumjs-util/node_modules/secp256k1/lib/index.js:18
if (!cond) throw new Error(msg)
^
Error: Expected private key to be an Uint8Array with length 32 So seems we have to decide here if we want to adopt here along the new API behavior (throw as well) or wrap this up in a Likely also a cc for @alcuadrado 😄 Maybe a two-step approach makes sense: on the first round wrap this up to be able to do a minor release here but keep this in mind to change the behavior on the next major release? |
Ok, I have now added an exemplary backwards-compatible fix for the If no objection I would continue to do fixes like this towards a backwards-compatible release with an updated |
I think there are no performance implications, Regarding compatibility,
I agree. I'd do this to get a minor release out. I'd also do things like the What worries me about this change, is that this library re-exports |
Thanks a lot for catching this, wouldn't have thought about this along the way! Thought about this a bit longer: I think we then just can't do the release in the intended way - so as a minor release - no way to get around that here without risking to break stuff for people. Since we had this
@alcuadrado Does this make sense? I know people are eager to get this released but I think this would be very much worth it the short additional waiting period. Will also include @s1na here to take notice (and eventually also leave a comment or suggestion). |
Makes sense @holgerd77. I think I'd also remove the re-export of TBH, I'm not sure what's the advantage of that export anyway. |
4d40475
to
65a459d
Compare
There's more to do here...just leaving a couple intermediate notes so things don't get forgotten.
It looks like invalid SEC1 keys will validate in the browser if sanitization is turned on. There
@holger What is the consensus about this? The secp256k1 package allows Buffer inputs and the changes in this PR just make sure Buffer comes out as well. Should the API reflect the new interface more closely? Cross links
|
RE: Invalid SEC1 tests. Secpk256k1's tests for publicKeyVerify are here and look like this: t.test('validate invalid public keys', (t) => {
const privateKey = util.getPrivateKey()
const publicKey = util.getPublicKey(privateKey)
const invalidVersion = Buffer.from(publicKey.compressed)
invalidVersion[0] = 0x00
t.false(secp256k1.publicKeyVerify(invalidVersion), 'invalid version byte')
const invalidY = Buffer.from(publicKey.uncompressed)
invalidY[64] ^= 0x01
t.false(secp256k1.publicKeyVerify(invalidY), 'invalid Y')
t.end()
}) They prefix the array with ethereumjs-util/test/account.spec.ts Line 148 in 3bbc948
Changing our test case to so that it resembles secp256k1's causes the tests to pass as expected (e.g without making the options change). But this doesn't explain why the result for the existing case is different in the browser vs. node...think we may need to open an issue asking for advice at secp256k1 unless someone already knows what's going on here. |
@cgewecke Can you do a branch update here? |
…secp256k1 v4.0.0 API
10e2607
to
98bf0dc
Compare
Yeah, Node 8 can be dropped from the test matrix
Yes, might be really worth to open an issue over there, can you do that? Maybe we are lucky and get a short-term answer/investigation. |
Yes I will make a minimal reproduction case for that today and report at secp256k1. Have looked through the issues at elliptic as well and haven't seen anything that looks exactly like this problem... |
Just reread some issues and stumbled over the "WASM modules for Crypto" issue https://github.com/ethereumjs/ethereumjs-util/issues/198 opened by @s1na. If this here causes some problems I wonder if it might be more promising (and - apart from that - generally more future-proof eventually) to play around with https://github.com/bitauth/bitcoin-ts mentioned in the thread. @cgewecke what do you think? |
@holgerd77 One thing about New things in this PR since last look...
|
Thanks for opening the issue over on the Have removed the Node 8 tests from the checks being required, so this is now passing CI. Let me know once this is ready for review. |
@holgerd77 040cb54 updates to 4.0.1 and reverts the SEC1 test case changes. Looks like everything's working ok now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, will approve/merge by admin merge since this is technically not my PR and therefore uncritical.
@@ -182,7 +183,7 @@ export const privateToPublic = function(privateKey: Buffer): Buffer { | |||
export const importPublic = function(publicKey: Buffer): Buffer { | |||
assertIsBuffer(publicKey) | |||
if (publicKey.length !== 64) { | |||
publicKey = secp256k1.publicKeyConvert(publicKey, false).slice(1) | |||
publicKey = toBuffer(secp256k1.publicKeyConvert(publicKey, false).slice(1)) | |||
} | |||
return publicKey | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, have checked for all return
value conversions, looks complete.
/** | ||
* [`secp256k1`](https://github.com/cryptocoinjs/secp256k1-node/) | ||
*/ | ||
export { secp256k1 } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For reference: removal of the secp2561
re-export
const senderPubKey = secp256k1.recover(msgHash, signature, recovery) | ||
return secp256k1.publicKeyConvert(senderPubKey, false).slice(1) | ||
const senderPubKey = secp256k1.ecdsaRecover(signature, recovery, msgHash) | ||
return toBuffer(secp256k1.publicKeyConvert(senderPubKey, false).slice(1)) | ||
} | ||
|
||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, also checked for completeness here.
This has now been published in the v7.0.0 release on npm. |
Did some first tests here, as @alcuadrado stated the API changed significantly and there are currently 11 tests failing for functionality in
account.ts
andsignature.ts
.Main thing here is that the API changed from using
Buffer
values toUint8Array
values, see v4 API docs and v3 API docs for comparison.Two things to address here:
1. Analyze API Change Implications
My knowledge of the implications of this switch is actually limited. I would need some additional voices here from people knowing better what this comes along with on the performance and compatibility side.
2. Library Fixes
I would assume that (at least on a first round) it would make most sense to wrap the
Uint8Array
usage and hide this from users of this library, since the whole EthereumJS ecosystem is based onBuffer
usage anyhow?Did a first test wrapping the
isValidPrivate
function, this didn't improve the test success numbers, not sure why, this would need some further analysis.Generally there would minimally be the need to get all test passing again.
// @michaelsbradleyjr @alcuadrado @iurimatias @evertonfraga @ryanio
Follow-up on #225