You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The CPU/Memory cost parameter N ("costParameter") must be larger than 1, a power of 2, and less than 2^(128 * r / 8). The parallelization parameter p ("parallelizationParameter") is a positive integer less than or equal to ((2^32-1) * 32) / (128 * r).
That is, it doesn't enforce N < 2^(128 * r / 8) as far as I can tell (I'm not fluent in Go). In the Go playground I find that N's upper limit when r is 1 is 16777215 such that {N: 262144, r: 1, p: 8} won't cause scrypt to choke.
I suspect the answer to my question ("Can someone shed light...?") boils down to: "geth's test data reflects what Go's scrypt allows for."
On the other hand, the Rust implementation of scrypt used by parity does seem to restrict N according to the RFC:
I don't know Rust, so I can't speak to whether those lines are an exact match for N < 2^(128 * r / 8) but I will try geth's test data with parity and see what happens.
But it does not work when web3.js is connected to a parity client that has loaded the same wallet. When using --logging=debug with parity client, I see this in the output when attempting to unlock:
2019-08-18 10:48:24 jsonrpc-eventloop-0 DEBUG rpc Response: {"jsonrpc":"2.0","error":{"code":-32023,"message":"Unable to unlock the account.","data":"EthCrypto(Scrypt(InvalidN))"},"id":42}.
I think the right thing would be for geth to start checking the kdf params for correctness re: the scrypt RFC before calling golang's scrypt implementation; and that geth's test wallets should be refactored so that they're all valid with respect to the RFC.
I think the right thing would be for geth to start checking the kdf params for correctness re: the scrypt RFC before calling golang's scrypt implementation; and that geth's test wallets should be refactored so that they're all valid with respect to the RFC.
Geth uses {N=262144, R=8, P=1} for wallets, optionally supporting {N=4096, R=8, P=6} for low powered devices if explicitly requested. Geth will never generate a wallet other than these two, so I don't think it's too big of an issue that we can handle more keys than the IETF standard specs, as long as they are cryptographically correct.
As for invalidating the tests, we don't plan on overriding Go's crypto constraints. I'm not saying that those should not be updated, but please open an issue against upstream Go. That is the place to fix standardization issues, not downstream packages. If they accept the proposal, we'll gladly pull in the changes.
I opened an issue upstream a few minutes after I opened this one. See #33703.
I also opened an upstream issue, of sorts, with ethereum/wiki, see #674.
As I mentioned in the latter issue, portability seems to be a concern. A wallet with {N=262144, R=1, P=8} as found in geth's tests won't work with parity nor with wallet implementations in JavaScript that rely on Node's built-in scrypt, i.e. without a clumsy fallback to an scrypt implementation that's non-compliant in the same way as Go's.
As you note, in practice, because geth only generates wallets with valid params it's probably not a huge issue for geth users. I also understand your decision to wait on an upstream change. But this was a rather confusing puzzle to piece together, and it already has implications for JS libs such as web3.js and ethereumjs-wallet.
The RFC's author says that's an error in the spec golang/go#33703 (comment) and the code is actually correct. They'll probably fix up the spec whenever.
Activity
michaelsbradleyjr commentedon Aug 18, 2019
It seems that Go's implementation of scrypt, used by geth, doesn't adhere to the RFC:
https://github.com/golang/crypto/blob/master/scrypt/scrypt.go#L200
That is, it doesn't enforce
N < 2^(128 * r / 8)as far as I can tell (I'm not fluent in Go). In the Go playground I find thatN's upper limit whenris1is16777215such that{N: 262144, r: 1, p: 8}won't cause scrypt to choke.I suspect the answer to my question ("Can someone shed light...?") boils down to: "geth's test data reflects what Go's scrypt allows for."
On the other hand, the Rust implementation of scrypt used by parity does seem to restrict
Naccording to the RFC:https://docs.rs/rust-crypto/0.2.36/src/crypto/scrypt.rs.html#193-196
I don't know Rust, so I can't speak to whether those lines are an exact match for
N < 2^(128 * r / 8)but I will try geth's test data with parity and see what happens.[-]Compliance with RFC 7914?[/-][+]scrypt usage not compliant with RFC 7914?[/+]michaelsbradleyjr commentedon Aug 18, 2019
I conducted the experiment with parity vs. geth:
With a wallet based on geth's test data, but regen'd so as to include the address (otherwise an exact match):
With that wallet in the keystore and web3.js connected to geth, this works in a Node.js REPL:
But it does not work when web3.js is connected to a parity client that has loaded the same wallet. When using
--logging=debugwith parity client, I see this in the output when attempting to unlock:I think the right thing would be for geth to start checking the kdf params for correctness re: the scrypt RFC before calling golang's scrypt implementation; and that geth's test wallets should be refactored so that they're all valid with respect to the RFC.
karalabe commentedon Aug 19, 2019
Geth uses
{N=262144, R=8, P=1}for wallets, optionally supporting{N=4096, R=8, P=6}for low powered devices if explicitly requested. Geth will never generate a wallet other than these two, so I don't think it's too big of an issue that we can handle more keys than the IETF standard specs, as long as they are cryptographically correct.As for invalidating the tests, we don't plan on overriding Go's crypto constraints. I'm not saying that those should not be updated, but please open an issue against upstream Go. That is the place to fix standardization issues, not downstream packages. If they accept the proposal, we'll gladly pull in the changes.
michaelsbradleyjr commentedon Aug 19, 2019
I opened an issue upstream a few minutes after I opened this one. See #33703.
I also opened an upstream issue, of sorts, with ethereum/wiki, see #674.
As I mentioned in the latter issue, portability seems to be a concern. A wallet with
{N=262144, R=1, P=8}as found in geth's tests won't work with parity nor with wallet implementations in JavaScript that rely on Node's built-in scrypt, i.e. without a clumsy fallback to an scrypt implementation that's non-compliant in the same way as Go's.As you note, in practice, because geth only generates wallets with valid params it's probably not a huge issue for geth users. I also understand your decision to wait on an upstream change. But this was a rather confusing puzzle to piece together, and it already has implications for JS libs such as web3.js and ethereumjs-wallet.
karalabe commentedon Apr 23, 2020
The RFC's author says that's an error in the spec golang/go#33703 (comment) and the code is actually correct. They'll probably fix up the spec whenever.
tniessen commentedon Apr 27, 2020
I found the mistake in the RFC and filed errata a few months ago. See 5971, 5972, and 5973.
karalabe commentedon Apr 27, 2020
@tniessen Thank you for the corrections and the confirmation!