ethereum / EIPs

The Ethereum Improvement Proposal repository
https://eips.ethereum.org/
Creative Commons Zero v1.0 Universal
12.93k stars 5.3k forks source link

Standardizing of HD wallet derivation paths (BIP32, BIP39, BIP44) #84

Closed coder5876 closed 2 years ago

coder5876 commented 8 years ago

References:

BIP32 BIP39 BIP44

We are now seeing a few different Ethereum HD wallet implementations with different HD derivation paths.

When we wrote Lightwallet I considered using the BIP44 specification defined by

m / purpose' / coin_type' / account' / change / address_index 

which gives a default path of m/44'/60'/0'/0 for Ethereum. I felt at the time that this was very UTXO-coin specific and didn't make that much sense for Ethereum, so I had a scheme that was based on having different paths for different keys (like signing keys, encryption keys etc) and different identities, and the focus was not on sending/receiving Ether. The default path became m/0'/0'/0' (Purpose/ID index/key_type), but we included the ability to specify a path of your choice.

The Jaxx wallet used lightwallet (at first) under the hood and chose an HD path of m/44'/60/0' which is almost BIP44, except the change path is not used.

There is this BIP44 HD wallet

https://github.com/trapp/ethereum-bip44

by @trapp which uses the full BIP44 path m/44'/60'/0'/0.

@axic created an HD wallet library which is used in ethereumjs/testrpc here:

https://github.com/ethereumjs/testrpc/pull/44/files#diff-f3d2a8282458e5cf231eee263cd57075R32

This also uses the full BIP44 path m/44'/60'/0'/0.

UPDATE: Clarification: The ethereumjs-wallet library from @axic does not impose any path, rather that when integrated in ethereumjs/testrpc the path used is the standard BIP44 one.

So in the spirit of trying to have some interoperability between HD wallets I would ask for some input:

Arachnid commented 7 years ago

I've engaged with the BIP process to figure out how we can get a 'purpose' ID allocated for Ethereum. I've also written up https://github.com/ethereum/EIPs/pull/600 on the use of such an ID, and https://github.com/ethereum/EIPs/pull/601 on a standard 'wallet' derivation path for use in Ethereum.

psionic81 commented 7 years ago

The only input I have is that while I was the lead developer for Jaxx, I ran into an issue with testnet always being 1. I'd suggest a base code (60 for ethereum) plus a (very large) additive component (+10000) for testnet.

The problem occurred when trying to generalize, and offer wallets for testnet tokens that conformed to some type of standard that also would be not using the exact same path for ethereum testnet, btc testnet, and so on. Who needs to use this in production, I'm not sure, but it definitely caused a conflict in what the spec was supposed to represent and what ended up happening.

tldr; for the next purpose, try to keep HD testnet paths distinct per coin type.

Arachnid commented 7 years ago

@psionic81 Can you elaborate on the reason for this? With replay protection now in place, is there any reason to derive different keys for different networks, or different tokens?

psionic81 commented 7 years ago

the first component is the standard.. this is supposed to represent a one to one relationship (or so it appears) with a coin. so testnet anything is a different coin type. similarly, all testnet coin types are different coin types. so they should not be defaulting to bitcoin's testnet.

the second had to do with the segregation of tasks and database management. leaking a private key of a child node (of a neutered node) enables the entire hierarchy from the neutered node to be deterministically generated.

any of the other arguments on why this is necessary are highly debatable, as all make assumptions of what testnet tokens have been used for so far, not what the networks will use them for in the future.

In short, I'd like the standard to be internally consistent. It will be better for the developer and user community looking forwards.

On Fri, Apr 14, 2017 at 8:05 AM, Nick Johnson notifications@github.com wrote:

@psionic81 https://github.com/psionic81 Can you elaborate on the reason for this? With replay protection now in place, is there any reason to derive different keys for different networks, or different tokens?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ethereum/EIPs/issues/84#issuecomment-294143095, or mute the thread https://github.com/notifications/unsubscribe-auth/AAOi-A6tNUcNRVq5ImmoTN9P_kNJg9Qqks5rv2ElgaJpZM4H5Izp .

Arachnid commented 7 years ago

Okay; I thought you were talking about my submission #600 / #601. I'm not sure where Bitcoin's testnet comes into it?

It's certainly not practical to store every ERC20 token in a separate wallet, because tokens need gas in order to be transferred, and the ether for that gas has to come from somewhere.

tab00 commented 6 years ago

Have the majority agreed with https://github.com/ethereum/EIPs/issues/84#issuecomment-292402851 by @MicahZoltu ?

I've found that some wallet apps have stubbornly stuck with their non-standard implementations. @erasmospunk, please make Coinomi be BIP44 standard-compliant. I like Coinomi but cannot use it if its developers refuse to comply with standards.

erasmospunk commented 6 years ago

@tab00 BIP32's receive/change addresses structure does not map to Ethereum. The first lightweight wallet to use BIP44 with Ethereum tried to emulate Bitcoin (was creating new addresses after one was used). Unfortunately this approach was broken, thus the alternative path was created to avoid the situation where restoring from seed would show an incomplete balance and transaction history.

MicahZoltu commented 6 years ago

@erasmospunk While following BIP44 may not make sense for Ethereum, we SHOULD follow BIP43 which states that if you start with m/44' then the rest of the path MUST be BIP44. If you feel like BIP44 doesn't make sense or is broken for Ethereum, that is fine, just use a prefix other than m/44'.

erasmospunk commented 6 years ago

@MicahZoltu extended BIP44 defines only coin type indexes, not how each coin uses the account private key.

If you take Monero as an example, it is by definition incompatible with the proposed standard of BIP32 (different curve, the priv/pub is created with the transaction data, has spend & view private keys).

In case of Ethereum, many users are using the alternative paths and will be confused when missing their addresses.

MicahZoltu commented 6 years ago

BIP32 doesn't define any consistent path. BIP43 asserts that the first segment of the path is a purpose, which defines what the remaining segments are. m / purpose' BIP44 defines purpose 44 and sets the remaining fields to m / 44' / coin_type' / account' / change / address_index SLIP44 further defines coin_type 60' to be Ethereum and 61' to be Ethereum Classic. m / 44' / 60' / account' / change / address_index

This leaves the last 3 fields as mildly ambiguous in Ethereum since Ethereum doesn't have a concept of a change address. If your first segment is 44' and you are writing an Ethereum wallet then the second segment MUST be 60'. From there you MUST have 3 more segments. If you do this, then at least you are conforming somewhat reasonably to BIP43, BIP44 and SLIP44 and I wouldn't fault you for choosing whether account' or address_index is what gets incremented, though it does feel like the only reasonable option for change is 0 (willing to hear debate on this last point if someone feels differently).

The problem I have with several of the implementations out there such as the ones used in (Coinomi, Electrum, MyEtherWallet (ledger), Ledger Chrome App, imToken) is that they use 44' as the purpose but then they proceed to not follow it with even the correct number of following segments as defined in BIP44. By using 44' as the first segment in the path you are asserting to readers that "this is a BIP44 path". By then not even having the right number of segments you are violating that assertion directly.

The other two implementations (m/44'/60'/0'/0/x m/44'/60'/x'/0/0), still differ, which is unfortunate, but they at least adhere as closely as possible to BIP44 when asserting the purpose of 44'. In both, it is just a matter of whether or not the indexing field is hardened or not, so both are legitimate uses of BIP44 paths and provide different security benefits.

Once again, my vote personally is that we come up with an Ethereum specific path (some have already been proposed) and we stop trying to follow BIP44. It is unclear to me why people thought it was a good idea to use BIP44 paths for Ethereum in the first place.

erasmospunk commented 6 years ago

(You didn't @ mentioned me and I missed your comment)

@MicahZoltu BIP44 is for Bitcoin, you cannot apply it to Ethereum.

You didn't answer how you would handle Monero in the BIP44 context. If a coin has an EC curve different from secp256k1, you wouldn't do BIP32 public derivation unless you really wanted to lose money.

The change / address_index is bad for Ethereum for several reasons:

You are asking for an "Ethereum specific path" but the m/44'/60'/account'/0 -> account address was just that, a customised path for Ethereum.

MicahZoltu commented 6 years ago

BIP32, BIP43 and BIP44 are all designed to work with any coin, not just Bitcoin. Having Ethereum specs that needlessly collide with Bitcoin specs when the Bitcoin specs were designed with altcoins in mind just causes confusion and bugs (we already have problems with this collision in Ethereum as seen by the fractured tooling referenced in this EIP).

I'm all for a custom Ethereum path that doesn't use change field, and several have been proposed in other EIPs. I only argue that it shouldn't start it with m/44' because that is already well defined in BIP44 and there is no reason for us (Ethereum community) to intentionally be incompatible when the BIP authors took altcoins into account during their design process.

All of the confusion I have seen from users comes from the inconsistencies across tools. Most of the confusion I have seen from developers comes from them looking up the HD path specs online (which leads them to BIP32, BIP43 and BIP44) and not understanding why the accounts they are creating don't match what other tools create, followed by confusion why their paths match some tools.

I'm not sure why you are asking about Monero here, I'm not a Monero developer and know almost nothing about them (technically), so I cannot answer your questions about how it works.

When I say "Ethereum specific path" I mean something that doesn't collide with the currently well defined and specified BIP44. We have an effectively infinite space to work with, there is no reason to confuse people by colliding with BIP44.

erasmospunk commented 6 years ago

@MicahZoltu the m/44'/60'/account'/0 path was created specifically to address the one address per account nature of Ethereum, while leaving space for extensions with m/44'/60'/account'/x for x > 0.

I argue that the m / 44' / 60' / account' / change / address_index is broken and semantically unfit for Ethereum.

In Monero you have a "spend" and a "view" keys that are needed to create an address and this doesn't map to the Bitcoin model as well. This doesn't mean that it cannot use the BIP44 while defining it's own standard if needed.

What will a new path solve?

It is better to accept the de facto alternative paths and recommend new implementations supporting the sane m/44'/60'/account'/0 path that was created specifically for Ethereum.

MicahZoltu commented 6 years ago

One could easily use the XKCD comic to argue that what I'm suggesting is to not create a new standard. :grin: There already exists a perfectly fine standard BIP32 and BIP43. We should follow them, and BIP43 has a definition on how to extend it to new systems (like Ethereum).

It is better to accept the de facto alternative paths

This is what I have a problem with. As shown in https://github.com/ethereum/EIPs/issues/84#issuecomment-292324521, there is not a defacto standard on which to rally. There are 4 separate mechanisms used by a variety of different tools. Since there isn't consensus, we should standardize on something that doesn't directly collide with BIP43 and BIP44 rather than picking one of the 4 existing options that does collide.

If we want to go with one of the defacto standards rather than coming up with a new Ethereum specific BIP43 extension then we should pick a non-colliding one. If we want to come up with a new Ethereum specific BIP43 extension then it means we don't follow any of the current implementations.

erasmospunk commented 6 years ago

@MicahZoltu when a user creates an account with a specific path it cannot change and using a new path means that they have to move their coins. There are millions of people using different paths, hence the "de facto standards".

jamespic commented 6 years ago

@MicahZoltu Something to add to your "single point of truth" comment is that Ledger are switching to m/44'/60'/x'/0/0 in their new desktop app, Ledger Live.

MicahZoltu commented 6 years ago

Updated the comment, thanks @jamespic! Also great to hear that ledger is moving to a BIP44 compliant path. 😁 Really wish we could get #600, #601, #602 finalized before that happens though. 😢 cc @Arachnid

xardass commented 5 years ago

I'll update this as people respond to this thread so there is hopefully a source of truth for future readers. I think it is important that we all come to consensus on this as users with hardware wallets (e.g., Ledger/TREZOR) moving between products will expect those different products to all show them the same thing. At the moment, if I want my dApp to be able to use a hardware wallet managed primarily by Jaxx for one user and Electrum for another user I'll have to ask the user what "style" of wallet are they using (Jaxx vs Electrum) which results in a pretty poor UX.

Live Implementations: m/44'/60'/0'/0/x: BIP44, MetaMask, Jaxx, MyEtherWallet (default), TREZOR App, Exodus m/44'/60'/x'/0/0: BIP44, KeepKey, MetaMask (custom), Ledger Live m/44'/60'/0'/x: Electrum, MyEtherWallet (ledger), Ledger Chrome App, imToken m/44'/coin_type'/account'/0: Coinomi

Correct me if wrong, but at least Ledger Live and Metamask have derivation paths m/44'/60'/x'/0 for their first address

MicahZoltu commented 5 years ago

@xardass Ledger Live is m/44'/60'/x'/0/0. MEW, unless it has changed, is m/44'/60'/0'/0/x.

Something to keep in mind is that some tools append the last segment from the index of a list of addresses, and then say that the derivation path is everything but the last segment. This is incredibly confusing for users because when you ask them, "what derivation path did you use" they tell you what the UI shows which is not correct.

hatgit commented 5 years ago

Could one interim fix be for the wallet software to continuing trying other paths (in the background), and only if no balance is found on the first path, and then if no balance is found on any of the other paths it would automatically revert back to the first path (as the user may be initializing a brand new unused address) Would such a workaround be feasible?

MicahZoltu commented 5 years ago

Yeah, and I believe some wallets do this. It is not a great user experience overall but it is better than the user not being able to find their money!

3sGgpQ8H commented 5 years ago

Correct me if wrong, but at least Ledger Live and Metamask have derivation paths m/44'/60'/x'/0 for their first address

For the first address x=0, so both, Ledger and Metamask will use m/44'/60'/0'/0/0. But the following addresses will differ. For example, the second address for Ledger will be derived from m/44'/60'/1'/0/0 while the second address for Metamask will use m/44'/60'/0'/0/1.

Gennttii commented 4 years ago

How to send from multiple addresses to one. So not 1 to 1 BUT multi to 1 ?!

github-actions[bot] commented 2 years ago

There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.

github-actions[bot] commented 2 years ago

This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment.