-
Notifications
You must be signed in to change notification settings - Fork 61
Output bip39 mnemonic suitable for import into HD wallets. #22
base: master
Are you sure you want to change the base?
Conversation
In addition to creating a bitcoin address, also generate a mnemonic key suitable for importing into common HD wallet software. This is an advanced function, and not suitable for most users, but may be useful to power users.
|
FYI Electrum doesn't use BIP39. Only the word list. |
|
It has a toggle for BIP39 hidden in the advanced settings. The eventual goal is to output BIP44 keys, but I haven't figured out how to do that yet. Outputting the seed is the super important part that can then be munged externally to make a useful address. |
generate 128 bits of randomness from /u/random The BIP39 clearly states that a minimum of 128 bits of entropy is to be used, but with the current way warp wallet is set up there is no way to guarantee the user's passphrase is 128 bits strong. So while these phrases might be able to import into BIP39 wallets fine, they are not BIP39 compliant, which defeats the whole purpose of BIPs. Don't call it BIP39 or advertise it as compatible with BIP39 wallets if you're going to keep it as is. Possible fix: |
|
This is a great idea. Generating BIP39 mnemonic codes is one of the things that would make Warpwallet a lot more useful. The flip side is that we still need to maintain backwards compatibility with old Warpwallet versions so that future users don't lose access to their funds. Supporting the generation of both a single keypair and the seed for an HD wallet would increase tool complexity a bit. While Electrum doesn't support BIP39 directly, another way to import into Electrum would be to convert the BIP39 into BIP32 using Ian Coleman's tool, with or without an additional passphrase: Adding HD wallet support would also help mitigate privacy issues with address re-use, that are currently encouraged with Brainwallet. |
|
|
||
| out = generate seed_final | ||
| out.seeds = seeds | ||
| out.mnemonic = mnemonic.fromSeed(seed_final.slice(0,16), mnemonic.Words.ENGLISH).toString() |
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.
Any particular reason to only use 16 elements from the seed? I believe that mnemonic.fromSeed does not require any particular number of items, so we might as well use the whole seed.
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.
16 bytes of entropy will generate a 12 word phrase (this is the most common used phrase size) 32 bytes would generate a 24 word phrase, and so on. Every 4 bytes adds 3 words.
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.
Ahh, gotcha.
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.
In that case I think the mnemonic length should be a user defined parameter. And perhaps it should default to 24. Since it doesn't need to be remembered or stored, it might as well be more secure.
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.
maximum security of ECDSA is n/2 of key size.
256 bit keys of bitcoin are only 128 bits strong, which is why 12 words is considered default on most wallets. 24 words exists if you need more words for some sort of special security measure.
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.
First of all, obfuscating this person's name does nobody any favors. Second of all, you show in your chat that you walk in to the conversation with a preconceived notion that I am wrong, and merely went to find someone you thought has clout (by looking at a wallet that uses default 24 words and poking around until someone vindicated your position) and strangely, obfuscate the name.
Also, I never said "a 24 word mnemonic doesn't provide additional security." like you did. I recognize that in special circumstances, having a 24 word or 300 word phrase could be useful, but as with the 300 word phrase example it is easy to understand that phrase lengths increasing starts to add detriments to the user experience.
To cover the points given though:
- Symmetric encryption is not relevant here, a brute force against 2^128 phrases and 2^256 phrases would find bitcoins at random OR targeted specifically at the same probability due to the pigeon hole principle.
- This is the only valid concern, but for instance, Trezor manages this vector by having the Trezor randomly display "type the word 'baseball'" etc. during recovery process in order to throw off key loggers, and inserting random fake words into the out of order recovery process. tl;dr these concerns are easily dealt with.
- Worrying about the chaincode is a moot point, if there was any known weakness in SHA2 (512 bit is also SHA2) that would show that knowing the later 32 bytes along with having a smaller possibility set would make the leftmost 32 bytes brute forceable in less than 2^256 or the original source of entropy (2^128 in our case) then that would be a very very bad weakness, and someone being able to brute force your phrase a tiny bit faster would be the least of your worries. (it could mean the beginning of a large avalanche of weaknesses found in SHA2 and bitcoin is going to be in for a wild ride)
- The Quantum computer comment at the end was also completely wrong, as the 128 bit seed is not directly used for calculating the public key... it is encoded into a phrase which requires a hash for the checksum as well as an iterative hash over the phrase to create a 64 byte hash which then is run through an HMAC which creates the private key and chain code which is then hashed again a few more times to derive the different paths to get to the actual key with a balance, which is THEN run through ECDSA multiplication... grover's algorithm must have gotten very versatile to do all of that. /s
And to top it all off:
99% of warp wallets don't have 128 bits of entropy to begin with (as the whole selling point is "ooooh look how long it takes, you can have a simple one word password with your email address and we'll magically turn that into 5 million bits of entropy using iterative hashing") so arguing over 12 or 24 words is security theatre to be honest.
The likelihood that a user is using their dogs name with their publicly known email as their warp wallet is far more likely than someone snagging their phone and running a forensic analysis on their finger prints in order to lift 12 words but they just so happen to not be able to do it for 24 words.
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.
Sorry, I didn't mean to come off wrong. Please assume good intent. All I care about is that warpwallet be as secure as possible.
I asked in a public channel and this was the first answer I got. I asked the question in the way I did because I know that ledger uses 24 word mnemonics, and so I was concerned that this PR only uses 12.
I obfuscated the name simply because I didn't ask this person's permission to quote them, and figured that it would be polite not to use their name.
I'm not sure if the last point is correct. WarpWallets don't have 128 bits of entropy, however, that is before key stretching. Since key stretching provides additional security, it seems like we should treat entropy before key stretching and after key stretching as separate.
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.
Also:
-
In that case, wouldn't it be better to force an attacker to brute force attack 2^256 phrases?
-
Grover's algorithm can be used to find inputs to a black box function using O(sqrt(N)) evaluations of the function, where N is the size of the function's domain. (Copied from wikipedia.) In this case, the black box function would be that whose input is the 128 bit seed and whose output is a public key. I could be wrong, but I don't believe it matters what the function is.
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.
The added extra entropy by the stretching is insignificant.
Thinking in bits is hard, but to make things simple to understand, let's imagine the user had a super strong password. 80 bits (which would be a 25 character password completely random from a 70 character set)
In order for key stretching to provide equivalent 48 bits of the remaining neede effective entropy, it would need to make the calculations be 2.81 x 10^14 times more expensive in calculation time.
If the original calculation took one microsecond, your stretching would need to take 8 years to make 48 bits of effective entropy.
tl;dr Key stretching is NOT meant to replace entropy. And entropy is a LOT harder to gather than people think.
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.
This is a persuasive argument. Let me see if I can follow it:
If a password is 80 random bits, then in the worst case it will take 2^80 guesses to guess it. If each guess takes a microsecond, then that's 3.8e10 years.
If a password is 128 random bits, then in the worst case it will take 2^128 guesses to guess it. At one microsecond a guess, that's 1.1e25 years.
So, in order for key stretching to make guessing our 80 bit password take as long as our 128 bit password, we need to make the 2^80 guesses take as long as the 2^128 guesses.
Through the magic of exponentiation, 1.1e25 years - 3.8e10 years ~= 1.1e25 years, so we need to make 2^80 * key-stretching function evaluation time = 1.1e25 years.
This means that each evaluation needs to take 9 years. (I rounded liberally, and 9 === 8 for the purposes of this discussion.)
So you're definitely right, key stretching cannot make up for entropy.
|
I checked a mnemonic generated by this PR against the online mnemonic tool here: https://iancoleman.github.io/bip39/ The BIP 39 seed was: And the mnemonic was: However, when entering the mnemonic, the seed from the tool didn't match that from the PR. Now, I'm not sure if the tool I used is correct, but the discrepancy should be accounted for. Also, this PR should come with an update to the test vectors to include both the mnemonic and BIP 39 seed, to make sure that the derivations are correct and don't change. |
|
@casey it's a difference in naming. the tool you linked is using "BIP39 seed" to refer to the 64 byte hash of the phrase. This PR is using the term to refer to the raw data that is to be encoded into the phrase. |
|
I did this exact thing two years ago, take a look: I also allowed the QR for import of the seed, as some wallets (like Jaxx) support this. |
|
@Logicwax Your implementation was the inspiration for my code. Unfortunately, because your variant compressed and rewrote a lot of the original warpwallet code, I was unable to update it with the new features and bugfixes included in the parent warpwallet. As a result, I adapted the idea directly into a PR against warpwallet. |
|
Came here to suggest this. I wanted to create a shared wallet where one of the signers would be a warp generated private key, but Copay only accepts bip39 mnemonics to join shared wallets (or just create normal wallets). Please do it :) |
I find a need to generate a high quality HD wallet key for Electrum. The key stretching in warpwallet is perfect for this, but it doesn't output a seed suitable for importing into Electrum.
This fix should a suitable first measure in solving #13. Admittedly, using a mnemonic as the intermediate mechanism isn't great, but it is pretty portable. Most systems that accept bip32 and bip44 will accept bip39 as an input method. Additionally, tools like [https://iancoleman.github.io/bip39/ (https://iancoleman.github.io/bip39/) make interoperability between various systems easy.