Skip to content

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

Closed

Description

@coder5876

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:

  • Should we just settle on the full BIP44 path m/44'/60'/0'/0 (which seems to be the most popular based on my unscientific sample)?
  • Does it matter that change doesn't make much sense for an account-based architecture like Ethereum?

Activity

  1. jprichardson commented on Mar 26, 2016

    @jprichardson

    For Exodus, we use m/44'/60'/0'/0/0, we'll probably just stick with this since it's a solved problem. Please let me know if I'm missing anything.

  2. coder5876 commented on Mar 26, 2016

    @coder5876
    Author

    @jprichardson Your path refers to the first address created, right? So in general m/44'/60'/0'/0/n for the nth wallet created. So your project is another data point favoring the standard BIP44 path.

  3. coder5876 commented on Mar 26, 2016

    @coder5876
    Author

    From testing the Jaxx Chrome plugin I can verify that Jaxx uses the HD root m/44'/60'/0' which makes the single derived Ether address m/44'/60'/0'/0. So this is not really compliant with BIP44. Would be nice to have Jaxx on board with the standard since it's a high-profile wallet.

    I believe @chrisforrester is currently working on full HD-support for Ether, will you be using the full HD path when this is released?

  4. axic commented on Mar 26, 2016

    @axic
    Member

    For the record, my library is at https://github.com/axic/ethereumjs-wallet and it is used in a few places, not only testrpc, however it doesn't impose any path restrictions, in fact it doesn't have any path in the source code as it is only a toolkit to build wallets.

    I have used the BIP44 path on Quorum just for the reasoning that should work well with current Bitcoin wallets. It turned out Trezor itself doesn't have any restrictions either. No idea about the others.

    @christianlundkvist I understand your point and I think I'm in favour of that reasoning, with the exception of different number for purpose. I simply don't think 0' is a good one. Maybe it would be useful fleshing out a few use cases and how those fit into your scheme.

  5. coder5876 commented on Mar 26, 2016

    @coder5876
    Author

    @axic Yes, I should have been more clear that your library is completely agnostic, I updated the original post with this.

    Personally I think I was overthinking things a bit in my HD path reasoning and that it's too soon to start looking for some optimal HD scheme that will cover all cases. Sticking with BIP44 makes sense at this early stage I think since most use cases at this point are about sending/receiving Ether.

  6. axic commented on Mar 26, 2016

    @axic
    Member

    It might be early to make a decision, nevertheless can you describe your scheme in depth? It can be a good starting point.

  7. coder5876 commented on Mar 26, 2016

    @coder5876
    Author

    @axic Sure, it was not really that advanced: The main idea is that you can have one seed for different identities or Personas. For persona nr n (at the path n') you have one branch for Ethereum signing keys m/0'/n'/0', one branch for keys to be used for asymmetric encryption m/0'/n'/1', one branch to be used for symmetric encryption m/0'/n'/2'. That's about as far as I got 😄

    I was also thinking about separating signing keys used to mainly hold Ether with keys mainly used to interact with smart contracts, so in this case I would probably use something like BIP44 for holding and transacting Ether and the above paths for interacting with contracts.

  8. chrisforrester commented on Mar 26, 2016

    @chrisforrester

    @christianlundkvist Hi everyone :) Chris here.

    I'm deep into the ethereum HD side of things. As Christian mentioned, our existing Jaxx project only uses the root conventional "account" node, which is obviously "wrong", however given the nature of the contract ecosystem, I don't think the bitcoin send + change really applies.

    A lot of this is user expectation handling. Obviously privacy for conventional transfers of ether around the network are a good use-case, and for this I'm using the following standard:

    m/44'/60'/0' is the "account" node.
    m/44'/60'/0'/0/x is the "receive" node.
    m/44'/60'/0'/1/y is the "change" node.

    If the user receives ether into the current public receive node index, the x index will increase.

    Sending ether from the wallet, I'm sorting through all the receive nodes, seeing if any specific node has the balance to cover the transaction, and sending directly as a single TX from that node. any change, gas price differences etc, will be returned to this address.

    In the event that this highest-balance node cannot cover the send request cost, I'm appending tx together into a batch. Obviously the tx cost increases simply from the extra gas cost required. If requested, I'm going to build some sort of smarty-pants optimizer to give people some options with this (tx completion time to cost and so on)

    To give users their total "spendable" balance, I take a look at the address they're trying to send to, calculate the total gas cost per tx, and subtract those from the user's "spendable" amount.

    Any nodes that don't have the ability to send 1 + 21000x50Gwei are below the finite dust limit, and so aren't taken into account. They still have minor utility however as they can be swept completely if they had another deposit into that specific node.

    The other option I considered was the complete reverse, always packaging the smallest amount account into an internal "change" node and sending from there. benefits to the user would be that anyone seeing a tx from them would always have a single tx on their list from the "change" node address.

    However, this will cost gas to do, and has a delay in the case where a user receives a few tx at nearly the same block, and wants to send out immediately.

    So I'm not doing this "proactive" packaging, instead I'm doing a "lazy" methodology. It should work fairly well.

    As I need to support previous users, I'm going to apply that original node balance (yes I should have done a bit more thought about that earlier on :D) optionally to the first "receive" node index. Otherwise it'll be kept as a virtual node and used in that "lazy" passthrough system. Our existing pipeline includes transferring funds from an ethereum paper wallet, and this should be a rational analog to that system.

    My thoughts on where to go from here re: contract watch addresses, contract ownership accounts, are that people are also going to want token support, so the UI is really the big undetermined factor right now. Since Mist has a basic support for this there's no huge rush, and since this process will form the expectation of how users go about accessing their accounts it's best to do this correctly instead of hacking something together that will have major ramifications in the next year as onboarding continues.

  9. coder5876 commented on Mar 26, 2016

    @coder5876
    Author

    @chrisforrester Thanks for the detailed run-through! So it seems most HD wallets are now using the full BIP44 path. Support for tokens are a good question, I have some thoughts about which paths to use for that, but that's for another EIP. 😃

  10. chrisforrester commented on Mar 26, 2016

    @chrisforrester

    I was thinking that we could extend the metaphor logically.. we could use
    m'/60000'->70000' or the like.

    On Sat, Mar 26, 2016 at 2:12 PM, Christian Lundkvist <
    notifications@github.com> wrote:

    @chrisforrester https://github.com/chrisforrester Thanks for the
    detailed run-through! So it seems most HD wallets are now using the full
    BIP44 path. Support for tokens are a good question, I have some thoughts
    about which paths to use for that, but that's for another EIP. [image:
    😃]

    —
    You are receiving this because you were mentioned.
    Reply to this email directly or view it on GitHub
    #84 (comment)

  11. kumavis commented on Mar 28, 2016

    @kumavis
    Member

    linking SLIP44 (used by jaxx) which proposes constants for different coins.

    That said, is there a requirement for the branches to be numbers? seems like using a name would work just as well: "ethereum" or "eth"

  12. axic commented on Mar 28, 2016

    @axic
    Member

    BIP32 is the one defining the derivation:

    ser32(i): serialize a 32-bit unsigned integer i as a 4-byte sequence, most significant byte first.

    and see the usage for ser32.

    Additionally the private-to-private derivation (hardened key) has a condition to only accept i ≥ 2^31. If you would use your text encoded as hex, that would always be a hardened derivation.

  13. subtly commented on Mar 28, 2016

    @subtly
    Member

    Ethereum doesn't have change addresses and, realistically, BIP32 is far from ideal for Ethereum. That said, its not a bad bridge until Serenity.

    I would like to +1 the idea of only using hardened addresses. This facilitates privacy by default and requires that a developer or user manually do something in order to disable privacy. Moreover, the linkable nature of non-hardened addresses is out-of-scope for ethereum – with bitcoin it makes sense because there are change addresses. With ethereum, and especially with smart contracts, the feature is moot.

  14. chrisforrester commented on Mar 28, 2016

    @chrisforrester

    I'd like to bring up an interesting use-case.

    (caution, my absorption of this is still quite new, someone please correct me if I'm wrong :D )
    If I use non-hardened addresses, I can derive all of the public keys from the receive node's extended path.
    (caution ended, the stuff below is legit)
    Using this, as I sometimes have to batch transactions together, I can create a method of determining if, from any given one address, another address is associated with that batch, as long as they came from the same HD wallet.

    In the case where this is desired, a user can send an "audit requestable" hd batch that have some data in them relating to a common nature(# of transactions in a batch, extended public key, username), that will make it really easy for the receiver to be able to hook into our one-name integration and say "yep all these transactions came from dudewiththehatnonotthatdudetheotherdude" and even then, be able to in the UI batch these as a single item.

    and even better, if I hook this into the ethereum contract mechanism, I can have a way of batching transactions together to be "counted" as coming from a single source by contracts, and also allow, optionally, easy auditing of bank activity.

  15. frozeman commented on Mar 29, 2016

    @frozeman
    Contributor

    Whats then the advantage of using HD wallet here at all? Why then not reusing addresses?

    This sending multiple tx from many accounts with dust, doesn't seem smart of efficient to me.

    [offtopic]
    btw does jaxx now finally provide enough gas? we had a lot of users who can't send from jaxx to kryptokit to a wallet contract..
    [/offtopic]

  16. 51 remaining items

  17. erasmospunk commented on Jun 16, 2018

    @erasmospunk

    @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.

  18. MicahZoltu commented on Jun 17, 2018

    @MicahZoltu

    One could easily use the XKCD comic to argue that what I'm suggesting is to not create a new standard. 😁 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 #84 (comment), 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.

  19. erasmospunk commented on Jun 26, 2018

    @erasmospunk

    @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".

  20. jamespic commented on Jul 19, 2018

    @jamespic

    @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.

  21. MicahZoltu commented on Jul 19, 2018

    @MicahZoltu

    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

  22. xardass commented on Aug 2, 2019

    @xardass

    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

  23. MicahZoltu commented on Aug 2, 2019

    @MicahZoltu

    @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.

  24. hatgit commented on Aug 22, 2019

    @hatgit

    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?

  25. MicahZoltu commented on Aug 22, 2019

    @MicahZoltu

    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!

  26. 3sGgpQ8H commented on Sep 5, 2019

    @3sGgpQ8H

    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.

  27. Gennttii commented on Jan 25, 2020

    @Gennttii

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

  28. github-actions commented on Jan 16, 2022

    @github-actions

    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.

  29. github-actions commented on Jan 30, 2022

    @github-actions

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions