riplin



Offline



Activity: 116

Merit: 10







MemberActivity: 116Merit: 10 Proposal: Base58 encoded HD Wallet root key with optional encryption July 18, 2013, 07:03:17 PM

Last edit: April 24, 2014, 06:18:32 PM by riplin #1 Recent changes:



24-04-2014 - Changed the preH and PostH calculation. Again.

21-04-2014 - Changed the preH and postH calculation.

15-02-2014 - Updated wording of various parts.

06-02-2014 - Added Will Yager's implementation as reference.

05-02-2014 - Changed prefix to 2 bytes, 'RK' and 'rk' for clear version and encrypted version respectively.

05-02-2014 - Added entropy field to encrypted version, moved KDF field from prefix into entropy field.

05-02-2014 - Changed computation of H to use PBKDF2-HMAC-SHA512 instead of Scrypt.

05-02-2014 - Changed checksum field to bloom field in encrypted version. Now supports 2 passwords.

27-12-2013 - Added some clarifications such as password character set (UTF-8) and endianness of fields.

26-12-2013 - Changed checksum to double SHA256 of private key, added 3rd party KDF support.

01-10-2013 - Expanded the salt to be prefix + date + checksum and renamed 'master seed' to 'root key'.

24-07-2013 - Added user selectable KDF + parameters, encoded in the prefix.

22-07-2013 - Added 2 byte creation date field, as a result, the prefix is expanded to 3 bytes.





BIP:

Title: Base58 encoded HD Wallet root key with optional encryption

Authors: Jean-Paul Kogelman, William Yager

Status: Draft

Type: Informational

Created: 18-07-2013



Abstract



This proposal describes a method for encoding and optionally encrypting a Bitcoin Hierarchical Deterministic (HD) Wallet root key. Encoded root keys are intended for use on paper wallets. Each string contains all the information needed to verify and reconstitute an HD wallet except for the optional passphrases. The encrypted version uses salting and a user selectable key derivation function (KDF) + parameters to resist brute-force attacks at varying degrees and optionally a second password for plausible deniability.



The method provides two encoding methodologies in 3 lengths each (16, 32 and 64 byte root keys). One is a clear version of the root key with verification information for integrity checking and the other is an encrypted representation.



Additionally a 2 byte compressed date field is present to limit the block chain rescan on wallet import.





Motivation



The extended private keys proposed in BIP 0032 are long, fixed length records and don't offer any form of security. The root key used to generate the HD wallet is typically shorter than the extended master private key that results from it.



A compact representation of the root key is easier to handle and a 2-factor version of the root key record allows for safe storage and the creation of paper wallets by 3rd parties. The KDF and its parameters are user selectable, allowing for a varying level of resistance against brute force attacks. This proposal currently defines 5 sets of parameters with room for 27 more that can be defined at a later date. Implementors are advised to contact the author with new KDF proposals.



Copyright



This proposal is hereby placed in the public domain.



Rationale



User story: As a Bitcoin user who uses HD wallets, I would like the ability to store my wallet root key in a compact form as a paper wallet.



User story: As a Bitcoin user who uses HD wallets, I would like the ability to have a 3rd party create a paper wallet with my root key in it, without having access to the funds stored in the wallet.



User story: As a Bitcoin user who uses HD wallets, I would like the ability to choose the strength of the root key depending on my security requirements and how I wish to store it.



User story: As a Bitcoin user who uses HD wallets, I would like the ability to import a root key into a simplified payment verification (SPV) client without having to redownload the entire block chain, but rater a limited range, to find associated transactions.



User story: As a Bitcoin user who uses HD wallets, I would like to choose the KDF and its parameters that is used to hash the passphrase that protects my root key to fit my security needs and available processing power.



User story: As a Bitcoin user who uses HD wallets, I would like to outsource the KDF computation to a 3rd party with more processing power.



User story: As a Bitcoin user who uses HD wallets, I would like to have a second password that can decrypt a second root key.



Specification



This proposal makes use of the following functions and definitions:



All input/output text is to be UTF-8 encoded



AES256Encrypt, AES256Decrypt: The AES block cipher, applied in ECB mode.



SHA256, SHA512: The hash algorithms of the same name.



HMAC-SHA512: The HMAC message authentication code algorithm, using SHA512 as the hash function



PBKDF2-HMAC-SHA512: The PBKDF2 key derivation algorithm, described in PKCS #5 v2.0 and RFC 2898, using HMAC-SHA512 as the pseudorandom function



Scrypt: The key stretching algorithm of the same name



Base58Check: The textual data encoding frequently used by various Bitcoin-related systems



"Root Key": The 16/32/64 byte value encoded in the wallet. This value is used to derive the private keys for addresses in the Bitcoin Wallet



"Master Key": The primary Bitcoin private key, which is derived from the Root Key



"||" refers to concatenation, not the logical OR operation



"G", "N": Constants defined as part of the secp256k1 elliptic curve. G is an elliptic curve point, and N is a large positive integer.



Prefix



The Base58Check representation of the wallet will start with "RK" (Root Key) if the wallet is unencrypted, and will start with "rk" if the wallet is encrypted.



Proposed specification



Unencrypted wallet:



Prefixes:

0x28C1: 16 byte root key, no encryption. 24 byte total length

0x4AC5: 32 byte root key, no encryption. 40 byte total length

0xFBB3: 64 byte root key, no encryption. 72 byte total length



These are constant bytes that appear at the beginning of the Base58Check-encoded record, and their presence causes the resulting string to have a predictable prefix.



"date" is a 2-byte, little endian field containing the number of weeks since jan 1st 2013. It is used to optimize blockchain scan upon wallet import.



"checksum" is the first 4 bytes of SHA256(SHA256(master_secret)), where master_secret is the "Master Secret Key (I L )" from the BIP32 specification. In other words, "checksum"=SHA256(SHA256(HMAC-SHA512("Bitcoin seed", root_key)[0:32]))[0:4].



"root_key" is the 16/32/64 byte root key used for the HD wallet



In summary, the clear wallet looks like this:

[prefix, 2 bytes][date, 2 bytes][checksum, 4 bytes][root_key, 16/32/64 bytes]



Range in Base58Check encoding for clear 16 byte root key (prefix RK):

Minimum value: RK52zvuD3xRhwto8JDTonxhru6awsFfNqKCTmT (based on 0x28 0xC1 plus twenty-two 0x00's)

Maximum value: RKCsfF9RpLnrxo1kp2o7mfWYeAV1NNYxWSMRym (based on 0x28 0xC1 plus twenty-two 0xFF's)



Range in Base58Check encoding for clear 32 byte root key (prefix RK):

Minimum value: RK15fXAj9BEMooghtx2gY5YrSh23LYKS8mZnaz8oYf1EDnqAwtAADGMVUDHG (based on 0x4A 0xC5 plus thirty-eight 0x00's)

Maximum value: RK5MUEoFU24QARcsX5HR2ieCjem468hDeQm4J2aH5zsCVJXUCGn6nsVQEFhN (based on 0x4A 0xC5 plus thirty-eight 0xFF's)



Range in Base58Check encoding for clear 64 byte root key (prefix RK):

Minimum value: RK1uXsCQAKqaa2s7YBDeaLS2KTqZcNjjQSgdSfDv4fqGkTw8KBfZ2ND4Cp7vHdzhjJ2C2Jtf4CwgScR nXvpzuQT2W4Vj2SgCyfBgpTzF (based on 0xFB 0xB3 plus seventy 0x00's)

Maximum value: RK3B9TMn55dey3an1oHpwB81FPZboakivYtqFvCaeknPzPK4iTvoFKzxVWKcD9YfJwjkyS36bqnSqji bUurcQ7J2EsQww5zPpJNzqjkw (based on 0xFB 0xB3 plus seventy 0xFF's)





Encrypted wallet:



Prefixes:



0xF83F: 16 byte root key, encrypted. 26 byte total length

0x6731: 32 byte root key, encrypted. 43 byte total length

0x4EB4: 64 byte root key, encrypted. 76 byte total length



These are constant bytes that appear at the beginning of the Base58Check-encoded record, and their presence causes the resulting string to have a predictable prefix.



"date" is a 2-byte, little endian field containing the number of weeks since jan 1st 2013. It is used to optimize blockchain scan upon wallet import. The maximum value of 0xFFFF results in: jan 1st 3269



"entropy" is a 2/3/4 byte (corresponding to whether the key is 16/32/64 bytes) field. The first five bits contain the KDF type, and all other bits contain random data. This is used as a salt to make cracking the wallet password harder.



"bloom_filter" is a 4 byte little-endian field containing a bloom filter to check that the user entered their password correctly.



"encrypted_root_key" is the 16/32/64 byte encrypted root key used for the HD wallet



In summary, the encrypted wallet looks like this:

[prefix, 2 bytes][date, 2 bytes][entropy, 2/3/4 bytes][bloom_filter, 4 bytes][encrypted_root_key, 16/32/64 bytes]





Range in Base58Check encoding for encrypted 16 byte root key (prefix rk):

Minimum value: rk2V4R2ys91WigNPL5nots6a97rfMnwTkPAb2XgNo (based on 0xF8 0x3F plus twenty-four 0x00's)

Maximum value: rk57mv9oertBLsHfncAvqnbetCBdNS1gFHQaFsD3p (based on 0xF8 0x3F plus twenty-four 0xFF's)



Range in Base58Check encoding for encrypted 32 byte root key (prefix rk):

Minimum value: rk1CYsqKjsbXa7uvncEaW4XSeVzcpq1U9yDMxd2cWwfkGf1FMjENaVThYpLRNwqo (based on 0x67 0x31 plus fourty-one 0x00's)

Maximum value: rk7Xw5b6fidaCk489LhaiMqHkZo7RYGTmzvJY9A5joxe8KXAn8BC66cmQPYYYvy8 (based on 0x67 0x31 plus fourty-one 0xFF's)



Range in Base58Check encoding for encrypted 64 byte root key (prefix rk):

Minimum value: rk48BmQWeQbATSXbP5U6XVsXRJTs4Ea1TVZBbHLPPsboCFyxDj2Jaz2JAJno97hq6dq2bANLuWydY8Q SZgKVGhPRZazXt1swPXwzVLw1QnVAz (based on 0x4E 0xB4 plus seventy-four 0x00's)

Maximum value: rkCRtT9R9kuAapCaLQFif5uo8gUrjgKsvYmGGTpX2ZTjTfwe9M7A6KezTh7f4FDxfZFVbHypodMNnNd mWYb8mzTokHXVR1u7KicrLLFFu7GJW (based on 0x4E 0xB4 plus seventy-four 0xFF's)





Encoding of KDF + parameters:



A number of KDF functions are available, to accommodate a wide range of possible use cases. The KDFs are defined as follows:



ID KDF Parameters 0x00 scrypt n = 214, r = 8, p = 8 0x01 scrypt n = 216, r = 16, p = 16 0x02 scrypt n = 218, r = 16, p = 16 0x08 PBKDF2-HMAC-SHA512 iterations = 216 0x09 PBKDF2-HMAC-SHA512 iterations = 221

All other possible values (3-7 and 10-31) are reserved.



Please note that KDFs 1 and 2 will probably not run on mobile devices. KDFs 8 and 9 are very memory efficient.



Generation of date:



The purpose of the date field is to make scanning the blockchain for transactions to/from this wallet faster. The date *must* be on or before the date of the first transaction to/from the wallet. If the date is unknown (e.g. on an embedded device) or the user does not wish to reveal the wallet creation date, this field can be set to zero (which may incur a performance penalty for the wallet software). When importing, it is advised to start scanning from a few days before the encoded date. The date field is a little-endian integer containing the number of weeks, rounded down, since Jan 1st 2013.



Examples:



sep 18th 2013 - jan 1st 2013 = 260 days = 37 weeks 1 day = rounded down becomes 0x0025

mar 3rd 2027 - jan 1st 2013 = 5174 days = 739 weeks 1 day = rounded down becomes 0x02E3



Derivation of Master Key from Root Key (please see



1. Take 16/32/64 byte Root Key. Call it S

2. Calculate I = HMAC-SHA512(key = "Bitcoin seed", msg = S)

3. Let I L = I[0:32]. I L is the Master Key

4. If I L is 0 or I L >= N, where N is the curve order of Secp256k1 (the elliptic curve used by Bitcoin), the Root Key is invalid and a new one should be chosen.



Encryption:



Let "passphrase" be the user's chosen passphrase

Let "fake_passphrase" be the user's chosen second passphrase, or a randomly generated string if the user chose not to use a second passphrase

Let "KDF" be the chosen key derivation function

Let "root_key" be the 16/32/64 byte Root Key



1. Create the correct "Prefix" and "Date" field

2. Create the random "Entropy" field and encode the KDF number in the top 5 bits

3. Let "salt" = Prefix || Date || Entropy

4. Calculate "preH" = PBKDF2-HMAC-SHA512(key = salt, msg = passphrase, iterations = 10000, output_len = 64)

5. Calculate "strongH" = KDF(msg = preH[0:32], salt = preH[0:32], output_len = 64) This step can be outsourced to a 3rd party, if desired.

6. Calculate "H" = PBKDF2-HMAC-SHA512(msg = preH, salt = strongH, iterations = 1, output_len = len(root_key) + 32)

7. Calculate "whitened_key" = root_key XOR H[0:len(root_key)]

8. Calculate "encrypted_key" = AES256Encrypt(message = whitened_key, key = HR), where HR is the last 32 bytes of H

9. Calculate "fake_key" by decrypting encrypted_key with fake_passphrase

10. Calculate "bloom_filter", containing root_key and fake_key. See the "Bloom Filter" section for more info.



encrypted_wallet = Prefix || Date || Entropy || bloom_filter || encrypted_key



Decryption of Root Key:



Let "passphrase" be the passphrase provided by the user



1. Extract "Prefix", "Date", "Entropy", "bloom_filter", and "encrypted_key" from the encrypted wallet

2. Determine the correct KDF from the top 5 bits of Entropy.

3. Let "salt" = Prefix || Date || Entropy

4. Perform steps 4 through 6 of Encryption to derive "H"

5. Calculate "whitened_key" = AES256Decrypt(message = encrypted_key, key = HR), where HR is the last 32 bytes of H

6. Calculate "root_key" = whitened_key XOR H[0:len(whitened_key)]

7. Verify that root_key is a member of bloom_filter



Bloom Filter:



The Bloom Filter is a data structure that allows us to check, within a range of probability, whether or not some piece of data has been added to it. In this case, we want to make sure that the user entered their password correctly, so we're checking that the decrypted root_key corresponds to the one that was added to the bloom filter when the wallet was created.



Bloom Filter Creation:



1. Let "bloom_filter" be an empty (set to all zeros) 32-bit, little-endian integer

2. To add an element "X" to bloom_filter,

3. Calculate "E" = SHA256(SHA256(HMAC-SHA512("Bitcoin seed", X)[0:32]))[0:11]. Note, this corresponds to the same algorithm used as a checksum for un-encrypted wallets. It also corresponds to the double-SHA of the Master Key.

4. For each of the 11 bytes in E (call each byte "B"):

4a. calculate "N" = B & 0x1F. N will range from 0 to 31. Set the Nth bit in bloom_filter to 1



You can add more items to the bloom filter, if desired. However, the filter parameters are optimized for 2 items (one "real" password/wallet, and one "fake" password/wallet). Please note that adding more items will drastically increase the chance of a false positive when entering a password. The chance of a password similar to a correct password passing the filter becomes more likely. This will generate a different Root Key and not the original one the user intended to decrypt.



Bloom Filter Verification:



Let "X" be some item

Let "bloom_filter" be the Bloom Filter you want to check if X belongs to



1. Calculate "x_only_filter", which is a Bloom Filter with X added to it

2. Ensure that any bit that is set in x_only_filter is also set in bloom_filter (i.e. x_only_filter & bloom_filter == x_only_filter)

3. If all bits set in x_only_filter are also set in bloom_filter, you know X is probably a member of bloom_filter. If not, X is definitely *not* a member of bloom_filter.



Suggestions for implementers of proposal with alt-chains



This proposal is network and coin agnostic (so long as the coin in question uses SECP256K1 ECC).



Reference implementation



Python reference implementation:



Acknowledgements



Mike Caldwell for BIP 0038, which this proposal borrows heavily from.



See Also



BIP 0032 Hierarchical Deterministic Wallets:

BIP 0038 Passphrase-protected private key:



Test vectors



The primary password will always decrypt the same root key, regardless of KDF selection, however, the secondary password will generate a different root key for every KDF.



Clarification:

Root Key: The BIP32 root key.

Private Key: IL in BIP32 parlance.

Salt Entropy: The random data used to generate the salt. With this, wallet generation can be tested deterministically. If you use this salt data, your encrypted wallets should *exactly* match the encrypted wallets listed here.



Test 1:



Root Key 000102030405060708090a0b0c0d0e0f Private Key e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35 Creation Date 04-02-2014 Cleartext Wallet RK6nEaou4eFQC4SfrHtdh9jpnEme4K9dt2jBmG Password Satoshi Second Password Alpaca Salt Entropy abcd Encrypted with KDF 0 rk354bQrbuzi9tVCt48rv9CCrc1Mi7sk9m3Yykpt3 Second Private Key 0 cf345038e7b0068d50e796756a3df60314f6edb7bc47c9ee7b4d73678668cdcb Encrypted with KDF 1 rk354bf4mvtwNXcLdcfppZECW4AoUBvTB8S23agNs Second Private Key 1 632c122124ba9905be5e02078d36ba63b7588edd2c68f1b385b9d6c2ca3e0817 Encrypted with KDF 8 rk354dNXRL2jSEL5Neh6ndDsxNgvRoP3Tt4oMqLTV Second Private Key 8 a44ca5f6b4f38385e4a5cc751ace5d2117e3305aee52827286cbc981f00e80da Encrypted with KDF 9 rk354dcjNKEyDFwVgYrdCQnkZYpUWzhyjMY16enLT Second Private Key 9 29e35fd44226c74117022b7e3079687bc2fa6391998753bc978509a8d9c5c323

Test 2:



Root Key 7f0ad7d595be13e6fe4cf1fa0fbb6ae9c26c5d9b09920709414982b6363d5844 Private Key 08965cb883e1c8783d72b65a0b7104d64baa9412eb655a6f05c5aaa6103781be Creation Date 04-02-2014 Cleartext Wallet RK22qqMb3CozsQfTTbSVsLEgXcjekut99SuSHn6urU4vWxjiQneHWVYabWgv Password Nakamoto Second Password hunter2 Salt Entropy defg Encrypted with KDF 0 rk2cMHcqyHdHNudopX8ZXwbrXgXK182FXpQJgiNdJbDGZXUpdWjfayTqi9tryTbS Second Private Key 0 7645740391ba1c5ef56286a1f43e8f95ac0b66de3bffb5ad3922ec140b7ad28f Encrypted with KDF 1 rk2cMJD2R82kefxdoLEmXM3B8ox336pr2mbUNasLvEGKpZHzUMToWQyWmn6Y7szk Second Private Key 1 ffd47e0d8fa64a9a696b4c3b7128fe416f1363aee1ddf6acfd2dd433c2e6bee6 Encrypted with KDF 8 rk2cMNLHXGrjxDyBtQvM1Ef5AxiGgtHympDceeMoCqj9mhqteoeFtPRpc1PXXMfd Second Private Key 8 96b831152e40d5461470729b88429c340de9c117c0d2af7564f91eb7e5f18443 Encrypted with KDF 9 rk2cMNvTy3VED3dCysRmZ6JswXAN2eYtA5oWegufDYNr7YQx2QHLbp3iie49u9Wf Second Private Key 9 391edef21757317e5bf1df133c0000ae86f982ad3b340ab5876a33fb057930a8

Test 3:



Root Key fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8 a8784817e7b7875726f6c696663605d5a5754514e4b484542 Private Key 4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e Creation Date 04-02-2014 Cleartext Wallet RK2BvY13FUD6bX25tA7XDyfAn7zbXSL8pR6TRE3EHZZ8qBm9qEyZRih8x1XhhcZwjcTfpe1Qjydn4KU dia8Wf1NshUusP1D38i88MLU9 Password Vires In Numeris Second Password Quis Custodiet Ipsos Custodes? Salt Entropy hijk Encrypted with KDF 0 rk5ySVNYwdRMDLnyxs1pXCdN3wrcBdPziWUudFidmwSfcJaZKPH8U24WSegPhidQiD7tXejMNQfxrAR h9JG8jLFtMY39fo9unpB4PsPSKymqy Second Private Key 0 0625f1c1e50cb7c3f302ff37d5eaa0fe20f45b10eb13634f4403b71dd3e49526 Encrypted with KDF 1 rk5ySW9NGHgAxs48UvF5oWvb6PHsZte43p1vjKmYuybLyGNrSMVHAkypTfb9qLFNTFixfCrxqnT3a8V c5UoTcBzRxjLQAwYMoB7YcmzCWdVtD Second Private Key 1 4a525d10640a9ccd26bbcc1af8a4803803e97628b7e7b6f0db5376c94021c83b Encrypted with KDF 8 rk5ySbZ5WuX3ba2Pudt1HE6iDQf7cSMg4zTsWbMKdFhucAwJEjNwH48oqCC52mbh3jxTQEGXN294Azx YsDbJowkiHSocGqWh7SFy24sE9KHGn Second Private Key 8 83d025017755701dbfcf5b50d07a95a99d517c15f40f0bec5529ae1cc3e39ba0 Encrypted with KDF 9 rk5yScKtqZmWe5FAB54x7WvvuxDSnNg81J3CADPdh4GJ4t2QaHckv8iuWF2spbC6uDC7DSM3GkYSQvN tz88su2h89vj9yUpmECmeELH2TkzM5 Second Private Key 9 c16e82babbf14512c9acde344a817693d2f401d2c73c7aeacdd21c455a9d5dd8

Test 4:



Root Key 6ca4a27ac660c683340f59353b1375a9 Private Key f544dd076ffe8fb68aa81ca9a33059946e9a91f8d95258ae1b7a1db6215ce51a Creation Date 04-02-2014 Cleartext Wallet RK6nEmXZj2nqgtCVWk3s7Suvz2XtWrdhDPpJqS Password 聡中本 Second Password Bitcoin Salt Entropy lmno Encrypted with KDF 0 rk354bWG9c8dupPhhYsKgFEcZ8uqxV7JKbvbsmnzh Second Private Key 0 b5af32696fe4bd75015d55f52a5bec16af4de74c256458ba8fdba7702509b7ca Encrypted with KDF 1 rk354bkUKo7gu3vhdadunrCUSSjJuQrQwyRXoydTE Second Private Key 1 de80aba55dee465b979a71a90d43c9a1f594eaaa30086944b8280603783ff4b8 Encrypted with KDF 8 rk354dTvdLGCSSPHP8tjFeLXMhwybvE47szr2jUPH Second Private Key 8 54b9fbe968a76327b452d0f7af1c74dfff34cddc4884ec6c65d1d1f66b3df79d Encrypted with KDF 9 rk354di8idN7qLmnbYSsFgjPbeHQ4b9CxSSviqXiH Second Private Key 9 247f6877db617c7a28a45c44a97041d055f0c664f109e2b6c1f3d9702dcaaeaa 24-04-2014 - Changed the preH and PostH calculation. Again.21-04-2014 - Changed the preH and postH calculation.15-02-2014 - Updated wording of various parts.06-02-2014 - Added Will Yager's implementation as reference.05-02-2014 - Changed prefix to 2 bytes, 'RK' and 'rk' for clear version and encrypted version respectively.05-02-2014 - Added entropy field to encrypted version, moved KDF field from prefix into entropy field.05-02-2014 - Changed computation of H to use PBKDF2-HMAC-SHA512 instead of Scrypt.05-02-2014 - Changed checksum field to bloom field in encrypted version. Now supports 2 passwords.27-12-2013 - Added some clarifications such as password character set (UTF-8) and endianness of fields.26-12-2013 - Changed checksum to double SHA256 of private key, added 3party KDF support.01-10-2013 - Expanded the salt to be prefix + date + checksum and renamed 'master seed' to 'root key'.24-07-2013 - Added user selectable KDF + parameters, encoded in the prefix.22-07-2013 - Added 2 byte creation date field, as a result, the prefix is expanded to 3 bytes.BIP:Title: Base58 encoded HD Wallet root key with optional encryptionAuthors: Jean-Paul Kogelman, William YagerStatus: DraftType: InformationalCreated: 18-07-2013This proposal describes a method for encoding and optionally encrypting a Bitcoin Hierarchical Deterministic (HD) Wallet root key. Encoded root keys are intended for use on paper wallets. Each string contains all the information needed to verify and reconstitute an HD wallet except for the optional passphrases. The encrypted version uses salting and a user selectable key derivation function (KDF) + parameters to resist brute-force attacks at varying degrees and optionally a second password for plausible deniability.The method provides two encoding methodologies in 3 lengths each (16, 32 and 64 byte root keys). One is a clear version of the root key with verification information for integrity checking and the other is an encrypted representation.Additionally a 2 byte compressed date field is present to limit the block chain rescan on wallet import.The extended private keys proposed in BIP 0032 are long, fixed length records and don't offer any form of security. The root key used to generate the HD wallet is typically shorter than the extended master private key that results from it.A compact representation of the root key is easier to handle and a 2-factor version of the root key record allows for safe storage and the creation of paper wallets by 3parties. The KDF and its parameters are user selectable, allowing for a varying level of resistance against brute force attacks. This proposal currently defines 5 sets of parameters with room for 27 more that can be defined at a later date. Implementors are advised to contact the author with new KDF proposals.This proposal is hereby placed in the public domain.User story: As a Bitcoin user who uses HD wallets, I would like the ability to store my wallet root key in a compact form as a paper wallet.User story: As a Bitcoin user who uses HD wallets, I would like the ability to have a 3rd party create a paper wallet with my root key in it, without having access to the funds stored in the wallet.User story: As a Bitcoin user who uses HD wallets, I would like the ability to choose the strength of the root key depending on my security requirements and how I wish to store it.User story: As a Bitcoin user who uses HD wallets, I would like the ability to import a root key into a simplified payment verification (SPV) client without having to redownload the entire block chain, but rater a limited range, to find associated transactions.User story: As a Bitcoin user who uses HD wallets, I would like to choose the KDF and its parameters that is used to hash the passphrase that protects my root key to fit my security needs and available processing power.User story: As a Bitcoin user who uses HD wallets, I would like to outsource the KDF computation to a 3party with more processing power.User story: As a Bitcoin user who uses HD wallets, I would like to have a second password that can decrypt a second root key.This proposal makes use of the following functions and definitions:All input/output text is to be UTF-8 encodedAES256Encrypt, AES256Decrypt: The AES block cipher, applied in ECB mode.SHA256, SHA512: The hash algorithms of the same name.HMAC-SHA512: The HMAC message authentication code algorithm, using SHA512 as the hash functionPBKDF2-HMAC-SHA512: The PBKDF2 key derivation algorithm, described in PKCS #5 v2.0 and RFC 2898, using HMAC-SHA512 as the pseudorandom functionScrypt: The key stretching algorithm of the same nameBase58Check: The textual data encoding frequently used by various Bitcoin-related systems"Root Key": The 16/32/64 byte value encoded in the wallet. This value is used to derive the private keys for addresses in the Bitcoin Wallet"Master Key": The primary Bitcoin private key, which is derived from the Root Key"||" refers to concatenation, not the logical OR operation"G", "N": Constants defined as part of the secp256k1 elliptic curve. G is an elliptic curve point, and N is a large positive integer.The Base58Check representation of the wallet will start with "RK" (Root Key) if the wallet is unencrypted, and will start with "rk" if the wallet is encrypted.Unencrypted wallet:Prefixes:0x28C1: 16 byte root key, no encryption. 24 byte total length0x4AC5: 32 byte root key, no encryption. 40 byte total length0xFBB3: 64 byte root key, no encryption. 72 byte total lengthThese are constant bytes that appear at the beginning of the Base58Check-encoded record, and their presence causes the resulting string to have a predictable prefix."date" is a 2-byte, little endian field containing the number of weeks since jan 1st 2013. It is used to optimize blockchain scan upon wallet import."checksum" is the first 4 bytes of SHA256(SHA256(master_secret)), where master_secret is the "Master Secret Key (I)" from the BIP32 specification. In other words, "checksum"=SHA256(SHA256(HMAC-SHA512("Bitcoin seed", root_key)[0:32]))[0:4]."root_key" is the 16/32/64 byte root key used for the HD walletIn summary, the clear wallet looks like this:[prefix, 2 bytes][date, 2 bytes][checksum, 4 bytes][root_key, 16/32/64 bytes]Range in Base58Check encoding for clear 16 byte root key (prefix RK):Minimum value: RK52zvuD3xRhwto8JDTonxhru6awsFfNqKCTmT (based on 0x28 0xC1 plus twenty-two 0x00's)Maximum value: RKCsfF9RpLnrxo1kp2o7mfWYeAV1NNYxWSMRym (based on 0x28 0xC1 plus twenty-two 0xFF's)Range in Base58Check encoding for clear 32 byte root key (prefix RK):Minimum value: RK15fXAj9BEMooghtx2gY5YrSh23LYKS8mZnaz8oYf1EDnqAwtAADGMVUDHG (based on 0x4A 0xC5 plus thirty-eight 0x00's)Maximum value: RK5MUEoFU24QARcsX5HR2ieCjem468hDeQm4J2aH5zsCVJXUCGn6nsVQEFhN (based on 0x4A 0xC5 plus thirty-eight 0xFF's)Range in Base58Check encoding for clear 64 byte root key (prefix RK):Minimum value: RK1uXsCQAKqaa2s7YBDeaLS2KTqZcNjjQSgdSfDv4fqGkTw8KBfZ2ND4Cp7vHdzhjJ2C2Jtf4CwgScRnXvpzuQT2W4Vj2SgCyfBgpTzF (based on 0xFB 0xB3 plus seventy 0x00's)Maximum value: RK3B9TMn55dey3an1oHpwB81FPZboakivYtqFvCaeknPzPK4iTvoFKzxVWKcD9YfJwjkyS36bqnSqjibUurcQ7J2EsQww5zPpJNzqjkw (based on 0xFB 0xB3 plus seventy 0xFF's)Encrypted wallet:Prefixes:0xF83F: 16 byte root key, encrypted. 26 byte total length0x6731: 32 byte root key, encrypted. 43 byte total length0x4EB4: 64 byte root key, encrypted. 76 byte total lengthThese are constant bytes that appear at the beginning of the Base58Check-encoded record, and their presence causes the resulting string to have a predictable prefix."date" is a 2-byte, little endian field containing the number of weeks since jan 1st 2013. It is used to optimize blockchain scan upon wallet import. The maximum value of 0xFFFF results in: jan 1st 3269"entropy" is a 2/3/4 byte (corresponding to whether the key is 16/32/64 bytes) field. The first five bits contain the KDF type, and all other bits contain random data. This is used as a salt to make cracking the wallet password harder."bloom_filter" is a 4 byte little-endian field containing a bloom filter to check that the user entered their password correctly."encrypted_root_key" is the 16/32/64 byte encrypted root key used for the HD walletIn summary, the encrypted wallet looks like this:[prefix, 2 bytes][date, 2 bytes][entropy, 2/3/4 bytes][bloom_filter, 4 bytes][encrypted_root_key, 16/32/64 bytes]Range in Base58Check encoding for encrypted 16 byte root key (prefix rk):Minimum value: rk2V4R2ys91WigNPL5nots6a97rfMnwTkPAb2XgNo (based on 0xF8 0x3F plus twenty-four 0x00's)Maximum value: rk57mv9oertBLsHfncAvqnbetCBdNS1gFHQaFsD3p (based on 0xF8 0x3F plus twenty-four 0xFF's)Range in Base58Check encoding for encrypted 32 byte root key (prefix rk):Minimum value: rk1CYsqKjsbXa7uvncEaW4XSeVzcpq1U9yDMxd2cWwfkGf1FMjENaVThYpLRNwqo (based on 0x67 0x31 plus fourty-one 0x00's)Maximum value: rk7Xw5b6fidaCk489LhaiMqHkZo7RYGTmzvJY9A5joxe8KXAn8BC66cmQPYYYvy8 (based on 0x67 0x31 plus fourty-one 0xFF's)Range in Base58Check encoding for encrypted 64 byte root key (prefix rk):Minimum value: rk48BmQWeQbATSXbP5U6XVsXRJTs4Ea1TVZBbHLPPsboCFyxDj2Jaz2JAJno97hq6dq2bANLuWydY8QSZgKVGhPRZazXt1swPXwzVLw1QnVAz (based on 0x4E 0xB4 plus seventy-four 0x00's)Maximum value: rkCRtT9R9kuAapCaLQFif5uo8gUrjgKsvYmGGTpX2ZTjTfwe9M7A6KezTh7f4FDxfZFVbHypodMNnNdmWYb8mzTokHXVR1u7KicrLLFFu7GJW (based on 0x4E 0xB4 plus seventy-four 0xFF's)Encoding of KDF + parameters:A number of KDF functions are available, to accommodate a wide range of possible use cases. The KDFs are defined as follows:All other possible values (3-7 and 10-31) are reserved.Please note that KDFs 1 and 2 will probably not run on mobile devices. KDFs 8 and 9 are very memory efficient.Generation of date:The purpose of the date field is to make scanning the blockchain for transactions to/from this wallet faster. The date *must* be on or before the date of the first transaction to/from the wallet. If the date is unknown (e.g. on an embedded device) or the user does not wish to reveal the wallet creation date, this field can be set to zero (which may incur a performance penalty for the wallet software). When importing, it is advised to start scanning from a few days before the encoded date. The date field is a little-endian integer containing the number of weeks, rounded down, since Jan 1st 2013.Examples:sep 18th 2013 - jan 1st 2013 = 260 days = 37 weeks 1 day = rounded down becomes 0x0025mar 3rd 2027 - jan 1st 2013 = 5174 days = 739 weeks 1 day = rounded down becomes 0x02E3Derivation of Master Key from Root Key (please see BIP 0032 for a full description of HD wallets):1. Take 16/32/64 byte Root Key. Call it S2. Calculate I = HMAC-SHA512(key = "Bitcoin seed", msg = S)3. Let I= I[0:32]. Iis the Master Key4. If Iis 0 or I>= N, where N is the curve order of Secp256k1 (the elliptic curve used by Bitcoin), the Root Key is invalid and a new one should be chosen.Encryption:Let "passphrase" be the user's chosen passphraseLet "fake_passphrase" be the user's chosen second passphrase, or a randomly generated string if the user chose not to use a second passphraseLet "KDF" be the chosen key derivation functionLet "root_key" be the 16/32/64 byte Root Key1. Create the correct "Prefix" and "Date" field2. Create the random "Entropy" field and encode the KDF number in the top 5 bits3. Let "salt" = Prefix || Date || Entropy4. Calculate "preH" = PBKDF2-HMAC-SHA512(key = salt, msg = passphrase, iterations = 10000, output_len = 64)5. Calculate "strongH" = KDF(msg = preH[0:32], salt = preH[0:32], output_len = 64) This step can be outsourced to a 3rd party, if desired.6. Calculate "H" = PBKDF2-HMAC-SHA512(msg = preH, salt = strongH, iterations = 1, output_len = len(root_key) + 32)7. Calculate "whitened_key" = root_key XOR H[0:len(root_key)]8. Calculate "encrypted_key" = AES256Encrypt(message = whitened_key, key = HR), where HR is the last 32 bytes of H9. Calculate "fake_key" by decrypting encrypted_key with fake_passphrase10. Calculate "bloom_filter", containing root_key and fake_key. See the "Bloom Filter" section for more info.encrypted_wallet = Prefix || Date || Entropy || bloom_filter || encrypted_keyDecryption of Root Key:Let "passphrase" be the passphrase provided by the user1. Extract "Prefix", "Date", "Entropy", "bloom_filter", and "encrypted_key" from the encrypted wallet2. Determine the correct KDF from the top 5 bits of Entropy.3. Let "salt" = Prefix || Date || Entropy4. Perform steps 4 through 6 of Encryption to derive "H"5. Calculate "whitened_key" = AES256Decrypt(message = encrypted_key, key = HR), where HR is the last 32 bytes of H6. Calculate "root_key" = whitened_key XOR H[0:len(whitened_key)]7. Verify that root_key is a member of bloom_filterBloom Filter:The Bloom Filter is a data structure that allows us to check, within a range of probability, whether or not some piece of data has been added to it. In this case, we want to make sure that the user entered their password correctly, so we're checking that the decrypted root_key corresponds to the one that was added to the bloom filter when the wallet was created.Bloom Filter Creation:1. Let "bloom_filter" be an empty (set to all zeros) 32-bit, little-endian integer2. To add an element "X" to bloom_filter,3. Calculate "E" = SHA256(SHA256(HMAC-SHA512("Bitcoin seed", X)[0:32]))[0:11]. Note, this corresponds to the same algorithm used as a checksum for un-encrypted wallets. It also corresponds to the double-SHA of the Master Key.4. For each of the 11 bytes in E (call each byte "B"):4a. calculate "N" = B & 0x1F. N will range from 0 to 31. Set the Nth bit in bloom_filter to 1You can add more items to the bloom filter, if desired. However, the filter parameters are optimized for 2 items (one "real" password/wallet, and one "fake" password/wallet). Please note that adding more items will drastically increase the chance of a false positive when entering a password. The chance of a password similar to a correct password passing the filter becomes more likely. This will generate a different Root Key and not the original one the user intended to decrypt.Bloom Filter Verification:Let "X" be some itemLet "bloom_filter" be the Bloom Filter you want to check if X belongs to1. Calculate "x_only_filter", which is a Bloom Filter with X added to it2. Ensure that any bit that is set in x_only_filter is also set in bloom_filter (i.e. x_only_filter & bloom_filter == x_only_filter)3. If all bits set in x_only_filter are also set in bloom_filter, you know X is probably a member of bloom_filter. If not, X is definitely *not* a member of bloom_filter.This proposal is network and coin agnostic (so long as the coin in question uses SECP256K1 ECC).Python reference implementation: https://github.com/wyager/Encrypted-HD-wallet Mike Caldwell for BIP 0038, which this proposal borrows heavily from.BIP 0032 Hierarchical Deterministic Wallets: https://en.bitcoin.it/wiki/BIP_0032 BIP 0038 Passphrase-protected private key: https://en.bitcoin.it/wiki/BIP_0038 Clarification:Root Key: The BIP32 root key.Private Key: IL in BIP32 parlance.Salt Entropy: The random data used to generate the salt. With this, wallet generation can be tested deterministically. If you use this salt data, your encrypted wallets should *exactly* match the encrypted wallets listed here.Test 1:Test 2:Test 3:Test 4: