Electrum 2 validation: how is the HMAC always 01...?

2

1

Electrum version 2 creates a seed from a random number which is then encoded as a mnemonic. The seed is validated by checking that the hmac begins with the bytes 01 or 101 for standard and 2fa types, respectively.

I have looked at the python code on github and indeed it does return the 01 byte but I am still confused as to how one can ensure a hash is going to start with a predicted value (01\101).

How can this be so? Is it that I'm missing the nuance of what the code does or the concept of how hmac works

Wizard Of Ozzie

Posted 2015-05-22T03:15:38.313

Reputation: 4 535

Answers

3

When creating a new seed, Electrum 2.x does pretty much the same thing as vanity address generators, or for that matter Bitcoin miners... it "grinds".

It generates a seed based on some entropy and a nonce, and checks if the seed's HMAC starts with the required byte sequence (the "checksum"). If it doesn't, it increments the nonce and checks its HMAC again.

If you're interested, the code which does this is here on GitHub.

It should be noted that Electrum seeds have (by default) 128 bits of entropy. As a result of this grinding, Electrum discards (for standard wallets with a checksum of 0x01) 255 out of every 256 potential seeds. This effectively decreases the entropy in a seed by 8 bits (the length of the checksum). In order to compensate for this, Electrum 2.x adds an additional 8 bits to the total seed length, which brings the seed length to 136 bits and the entropy back up to 128 bits.

Christopher Gurnee

Posted 2015-05-22T03:15:38.313

Reputation: 2 263

Note that it's considerable faster than most vanity generators, since it only needs to do ~128 HMAC-SHA2 operations, which is really fast.Nick ODell 2015-05-22T04:47:17.110

Ah ha so that's why the True loop is used. I thought it was being used just once as while old_seed seems more intuitive to me. I can see the rationale now, especially after running successfully finding numerous cases of Electrum 1 seeds which returned a 01 hmac. I'm curious... is it possible to implement a better system whereby an old seed can never be interpreted as a new seed or is this just the most appropriate given it's a hash based seed?Wizard Of Ozzie 2015-05-22T06:09:09.453

1

@WizardOfOzzie One idea that comes to mind which Electrum could implement (but hasn't yet) is to throw out the standard BIP-39 wordlist, and use a custom one which shares no common words with the Electrum 1.x list. Electrum already eschews BIP-39, so there's no reason to keep the same wordlist. The BIP-39 wordlists aren't even all that good—they violate BIP-39's own recommendation of no similar words (auction/action, motion/emotion, garage/garbage, etc...).

Christopher Gurnee 2015-05-22T12:25:21.253

@ChristopherGurnee I was just about to raise the same solution after pondering it all day. It is a much better delineation both programmatically and intuitively IMOWizard Of Ozzie 2015-05-22T13:15:17.490

@nickodell you're right. I ran it to be sure :) While we're on the topic, what is the point of running the ecdsa.utils.randrange and incrementing the nonce when it's just as likely running the loop for a random number will return a valid seed?Wizard Of Ozzie 2015-05-23T02:21:12.440

@WizardOfOzzie No clue on that one. The same thought struck me.Nick ODell 2015-05-23T02:22:28.067

@nickodell Sha512 hmac btw. Interestingly, and this is news to me, python hashlib has a pbkdf2_hmac function which is a hell of a lot faster than my optimised pbkdf2 functionWizard Of Ozzie 2015-05-23T02:23:57.343