`fromMnemonic` returns a private key which shouldn't be used
See original GitHub issueThis isn’t a bug, but rather a way that an SDK user can easily misuse the PrivateKey::fromMnemonic
function.
By default, calling fromMnemonic
returns the key at derivation path m/44'/3030'/0'/0'
(A
in the figure below). If a programmer isn’t familiar with derivation paths, they will probably just use the resulting private key without a further thought. This behavior seems to be enforced by the online documentation, which shows simple usage of fromMnemonic
//Use the mnemonic to recover the private key
PrivateKey privateKey = PrivateKey.fromMnemonic(mnemonic);
PublicKey publicKey = privateKey.publicKey();
//v2.0.0
However, the private key created from fromMnemonic
should not be used directly - the programmer ought to go one layer deeper in the derivation path, to m/44'/3030'/0'/0'/0'
, m/44'/3030'/0'/0'/1'
, etc… (B
in the figure below). This requirement is documented, but only briefly, in the function documentation
* @return the recovered key; use {@link #derive(int)} to get a key for an account index (0
* for default account)
My understanding is that receiving to A
is out of line with expected BIP44 behavior, and doing so might result in different wallets not finding existing funds. It seems worth it to me to make it harder for a wallet developer to mistakenly receive here.
Issue Analytics
- State:
- Created 10 months ago
- Comments:8
I guess this means that if we were to change Ed25519 derivation to not infer all indices are hardened, that would be a breaking change 🤔 So we probably should continue inferring all Ed25519 indices are hardened. But to get a hardened ECDSA child, it must be explicitly chosen
One more consideration-
since Ed25519 supports only hardened derivation, we need to decide whether
Ed25519PrivateKey::fromMnemonic(mnemonic, 0)
interprets “0” to mean the 0th hardened child index (2147483648), or whether this should throw an error due to invalid child indexI think my preference would be that
Ed25519PrivateKey::fromMnemonic(mnemonic, 0)
kicks back an error, and the user would have to do something likeEd25519PrivateKey::fromMnemonic(mnemonic, toHardened(0))
. But I can see this going either way, as long as there is consistency across SDKs