14 - Extended Key Derivation using 256-bit Unsigned Integers#
DIP: 0014 Title: Extended Key Derivation using 256-bit Unsigned Integers Author(s): Samuel Westrich Special-Thanks: Dashameter, Eric Britten, Thephez Comments-Summary: No comments yet. Status: Proposed Type: Informational Created: 2020-11-25 License: MIT License
Table of Contents#
Abstract#
This Document expands the derivation ability set by BIP32 to allow for derivation on paths using 256-bit unsigned integers.
Motivation#
Derivation paths defined in BIP32 are limited to 31-bit children. The original reasoning seems to be mostly from the use case of BIP32. It seems unattainable to use more than 231 (Over 2 billion) addresses in a wallet. However if we need a unique child in a derivation path, this cannot be achieved with 31-bit children. We need unique children in DashPay derivation paths. Unique children can be defined as 2 random indexes that have less than 2128 chance of being the same. As 256-bit derivation paths might be useful for other applications, we believe the solution presented within merits its own document.
Prior work#
Compatibility#
One fundamental aspect of this document is backwards compatibility with BIP32 derivation. If a child key’s index is less than 232-1 then the resultant child key created by the derivation outlined in this document will match the derivation outlined in BIP32.
The Dashpay Example#
Derivation in BIP32 is limited to 31 bits (the 32nd bit is used to mark hardening). If we limited ourselves to 31-bit derivations we would be faced with the following problem: we need the derivation path between user A and user B to be unique and be made in such a way that a user C could never create an attack to have the same address space as given to B from A.
To illustrate the attack let’s assume we used only 31-bit derivation. Since user A and user B’s unique id is public, any form that reduces the entropy of this relationship to 31 bits per child would be attackable. For example, if we used the last 31 bits of the unique id for each user to make the tail of the derivation path then user C could cycle through ~231 Blockchain Identities and eventually find one that would match. This would easily be achievable with an ASIC miner. User C would then receive the same extended public key as user B and therefore be able to know when payments were made from User B to user A. More complicated schemes also suffer the same problem as User C could replicate any known function to create the same 31 bits.
To solve this we allow derivation of paths on 256-bit unsigned integers matching the Identity’s registration hash.
The derivation path for Dashpay relationships is discussed more in depth in the DashPay Implementation Proposal. Here we will focus on the last two 256-bit derivations. The derivation path will look like:
m(userA)/9’/5’/15’/0’/(userA’s unique id)/(userB’s unique id)
Deconstructed that is :
9 hardened / See DIP9
5 hardened / Coin type
15 hardened / Feature
0 hardened / Account
userA’s unique id (not hardened)
userB’s unique id (not hardened)
Making the last two fields non-hardened allows for an extended public key that covers all address spaces of all our contacts for all our blockchain identities. This can be used for accounting and also to create the friend requests without having to use a private key.
Specification: Key derivation#
We will modify the following to the original specification as described in BIP32.
Conventions#
As standard conversion functions, we assume:
ser256(i): serialize a 256-bit unsigned integer
i
as a 32-byte sequence, most significant byte first.
Extended Keys#
In the original BIP32 specification, each extended key had 231 normal child keys and
231 hardened child keys. We extend that specification to now allow 2256 normal
child keys and 2256 hardened child keys. Each of these child keys has an index. In the
original specification, a key was hardened if the most significant bit of the index was set. Instead
we now use a Boolean h
to represent if a child key is hardened. Hence now both normal child keys
and hardened keys will use indices 0 through 2256-1.
Child Key Derivation (CKD) Functions#
Given a parent extended key and an index i
, it is possible to compute the corresponding child
extended key. The algorithm to do so depends on whether the child is a hardened key or not, if the
index is less or more than 231, and whether we’re talking about private or public keys.
Private parent key → private child key#
The function CKDpriv256((kpar, cpar), i, h) → (ki, ci) computes a child extended private key from the parent extended private key:
Check whether i < 232 (whether we should use compatibility mode) and check if
h
is true (whether the child is a hardened key).If (i< 232) :
If hardened child (h==true): let I = HMAC-SHA512(Key = cpar, Data = 0x00 || ser256(kpar) || ser32(i)). (Note: The 0x00 pads the private key to make it 33 bytes long.)
If normal child: let I = HMAC-SHA512(Key = cpar, Data = serP(point(kpar)) || ser32(i)).
If (i>=232) :
If hardened child (h==true): let I = HMAC-SHA512(Key = cpar, Data = 0x00 || ser256(kpar) || ser256(i)). (Note: The 0x00 pads the private key to make it 33 bytes long.)
If normal child: let I = HMAC-SHA512(Key = cpar, Data = serP(point(kpar)) || ser256(i)).
Split I into two 32-byte sequences, IL and IR.
The returned child key ki is parse256(IL) + kpar (mod n).
The returned chain code ci is IR.
In case parse256(IL) ≥ n or ki = 0, the resulting key is invalid, and one should proceed with the next value for
i
. (Note: this has a probability lower than 1 in 2127.)
The HMAC-SHA512 function is specified in RFC 4231.
Public parent key → public child key#
The function CKDpub256((Kpar, cpar), i, h) → (Ki, ci) computes a child extended public key from the parent extended public key. It is only defined for non-hardened child keys.
Check if
h
is true, if it is then return failure.Check whether i < 232 (whether we should use compatibility mode).
If it is (compatibility mode): let I = HMAC-SHA512(Key = cpar, Data = serP(Kpar) || ser32(i)).
If not (UInt256 mode): let I = HMAC-SHA512(Key = cpar, Data = serp(Kpar) || ser256(i)).
Split I into two 32-byte sequences, IL and IR.
The returned child key Ki is point(parse256(IL)) + Kpar.
The returned chain code ci is IR.
In case parse256(IL) ≥ n or Ki is the point at infinity, the resulting key is invalid, and one should proceed with the next value for
i
.
Serialization Format#
Extended public and private keys are serialized as follows:
If (child number < 232) follow serialization format as described in BIP32 :
4 byte: version bytes (mainnet:
0x0488B21E
public,0x0488ADE4
private; testnet:0x043587CF
public,0x04358394
private)1 byte: depth: 0x00 for master nodes, 0x01 for level-1 derived keys, ….
4 bytes: the fingerprint of the parent’s key (0x00000000 if master key)
4 bytes: child number. This is ser32(i) for i in xi = xpar/i, with xi the key being serialized. (0x00000000 if master key)
32 bytes: the chain code
33 bytes: the public key or private key data (serP(K) for public keys, 0x00 || ser256(k) for private keys)
Because of the choice of the version bytes, the Base58 representation will start with xprv
or
xpub
on mainnet, tprv
or tpub
on testnet.
If (child number >= 232) then serialize the following way :
4 byte: version bytes (mainnet:
0X0EECEFC5
public,0x0EECF02E
private; testnet:0x0EED270B
public,0x0EED2774
private)1 byte: depth: 0x00 for master nodes, 0x01 for level-1 derived keys, ….
4 bytes: the fingerprint of the parent’s key (0x00000000 if master key)
1 byte: hardening: 0x00 if not hardened, 0x01 if hardened
32 bytes: child number. This is ser256(i) for i in xi = xpar/i, with xi the key being serialized. (Only zeros if master key)
32 bytes: the chain code
33 bytes: the public key or private key data (serP(K) for public keys, 0x00 || ser256(k) for private keys)
Because of the choice of the version bytes, the Base58 representation will start with dpms
(dashpay mainnet secret) or dpmp
(dashpay mainnet public) on mainnet, dpts
(dashpay testnet
secret) or dptp
(dashpay testnet public) on testnet or devnets.
Test Vectors#
Test Vector 1#
Mnemonic : birth kingdom trash renew flavor utility donkey gasp regular alert pave layer
Seed Data : b16d3782e714da7c55a397d5f19104cfed7ffa8036ac514509bbb50807f8ac598eeb26f0797bd8cc221a6cbff2168d90a5e9ee025a5bd977977b9eccd97894bb
Key Type : Secp256k1
Derivation (Note : The second derivation is hardened) :
m/
0x775d3854c910b7dee436869c4724bed2fe0784e198b8a39f02bbb49d8ebcfc3b/
0xf537439f36d04a15474ff7423e4b904a14373fafb37a41db74c84f1dbb5c89a6'/
0x4c4592ca670c983fc43397dfd21a6f427fac9b4ac53cb4dcdc6522ec51e81e79/
0
Key : 0xe8781fdef72862968cd9a4d2df34edaf9dcc5b17629ec505f0d2d1a8ed6f9f09
Ext Pub : tpubDF4tEyAdpXySRui9CvGRTSQU4BgLwGxuLPKEb9WqEE93raF2ffU1PRQ6oJHCgZ7dArzcMj9iKG8s8EFA1DdwgzWAXs61uFuRE1bQi8kAmLy
Ext Priv : tprv8iNr6Z8PgAHmYSgMKGbq42kMVAAQmwmzm5iTJdUXoxLf25zG3GeRCvnEdC6HKTHkU59nZkfjvcGk9VW2YHsFQMwsZrQLyNrGx9c37kgb368
Test Vector 2#
Mnemonic : birth kingdom trash renew flavor utility donkey gasp regular alert pave layer
Seed Data : b16d3782e714da7c55a397d5f19104cfed7ffa8036ac514509bbb50807f8ac598eeb26f0797bd8cc221a6cbff2168d90a5e9ee025a5bd977977b9eccd97894bb
Key Type : Secp256k1
Derivation (Note : All derivations except the last are hardened) :
m/9'/5'/15'/0'/
0x555d3854c910b7dee436869c4724bed2fe0784e198b8a39f02bbb49d8ebcfc3a'/
0xa137439f36d04a15474ff7423e4b904a14373fafb37a41db74c84f1dbb5c89b5'/
0
Key : 0xfac40790776d171ee1db90899b5eb2df2f7d2aaf35ad56f07ffb8ed2c57f8e60
Ext Pub : tpubDLqNye58JQGox9dqWN5xZUgC5XGC6KwWmTSX6qGugrGEa5QffDm3iDfsVtX7qyXuWoQsXA6YCSuckKshyjnwiGGoYWHonAv2X98HTU613UH
Ext Priv : tprv8p9LqE2tA2b94gc3ciRNA525WVkFvzkcC9qjpKEcGaTqjb9u2pwTXj41KkZTj3c1a6fJUpyXRfcB4dimsYsLMjQjsTJwi5Ukx6tJ5BpmYpx
Test Vector 3#
Mnemonic : birth kingdom trash renew flavor utility donkey gasp regular alert pave layer
Seed Data : b16d3782e714da7c55a397d5f19104cfed7ffa8036ac514509bbb50807f8ac598eeb26f0797bd8cc221a6cbff2168d90a5e9ee025a5bd977977b9eccd97894bb
Key Type : Secp256k1
Derivation (Note : The derivation is NOT hardened) :
m/
0x775d3854c910b7dee436869c4724bed2fe0784e198b8a39f02bbb49d8ebcfc3b
Key : 0xf6a95ae75ea8362d9478932f71b262b3d981918fe030316686a475dea4889938
Ext Pub : dptp1C5gGd8NzvAke5WNKyRfpDRyvV2UZ3jjrZVZU77qk9yZemMGSdZpkWp7y6wt3FzvFxAHSW8VMCaC1p6Ny5EqWuRm2sjvZLUUFMMwXhmW6eS69qjX958RYBH5R8bUCGZkCfUyQ8UVWcx9katkrRr
Ext Priv : dpts1vgMVEs9mmv1YLwURCeoTn9CFMZ8JMVhyZuxQSKttNSETR3zydMFHMKTTNDQPf6nnupCCtcNnSu3nKZXAJhaguyoJWD4Ju5PE6PSkBqAKWci7HLz37qmFmZZU6GMkLvNLtST2iV8NmqqbX37c45
Test Vector 4#
Mnemonic : birth kingdom trash renew flavor utility donkey gasp regular alert pave layer
Seed Data : b16d3782e714da7c55a397d5f19104cfed7ffa8036ac514509bbb50807f8ac598eeb26f0797bd8cc221a6cbff2168d90a5e9ee025a5bd977977b9eccd97894bb
Key Type : Secp256k1
Derivation (Note : The second derivation is hardened) :
m/
0x775d3854c910b7dee436869c4724bed2fe0784e198b8a39f02bbb49d8ebcfc3b/
0xf537439f36d04a15474ff7423e4b904a14373fafb37a41db74c84f1dbb5c89a6'
Key : b898ad92d3a0698bc3117d3777d82676673816ce52f4fc2f1263a2f676825f90
Ext Pub : dptp1CLkexeadp6guoi8Fbiwq6CLZm3hT1DJLwHsxWvwYSeAhjenFhcQ9HumZSftfZEr4dyQjFD7gkM5bSn6Aj7F1Jve8KTn4JsMEaj9dFyJkYs4Ga5HSUqeajxGVmzaY1pEioDmvUtZL3J1NCDCmzQ
Ext Priv : dpts1vwRsaPMQfqwp59ELpx5UeuYtdaMCJyGTwiGtr8zgf6qWPMWnhPpg8R73hwR1xLibbdKVdh17zfwMxFEMxZzBKUgPwvuosUGDKW4ayZjs3AQB9EGRcVpDoFT8V6nkcc6KzksmZxvmDcd3MqiPEu
Copyright#
Copyright (c) 2020 Dash Core Group, Inc. Licensed under the MIT License