Jochen Hoenicke [ARCHIVE] on Nostr: 📅 Original date posted:2016-04-20 📝 Original message:Hello Bitcoin Developers, ...
📅 Original date posted:2016-04-20
📝 Original message:Hello Bitcoin Developers,
I would like to make a proposal to update BIP-32 in a small way.
TL;DR: BIP-32 is hard to use right (due to its requirement to skip
addresses). This proposal suggests a modification such that the
difficulty can be encapsulated in the library.
#MOTIVATION:
The current BIP-32 specifies that if for some node in the hierarchy
the computed hash I_L is larger or equal to the prime or 0, then the
node is invalid and should be skipped in the BIP-32 tree. This has
several unfortunate consequences:
- All callers of CKDpriv or CKDpub have to check for errors and handle
them appropriately. This shifts the burden to the application
developer instead of being able to handle it in the BIP-32 library.
- It is not clear what to do if an intermediate node is
missing. E.g. for the default wallet layout, if m/i_H/0 is missing
should m/i_H/1 be used for external chain and m/i_H/2 for internal
chain? This would make the wallet handling much more difficult.
- It gets even worse with standards like BIP-44. If m/44' is missing
should we use m/45' instead? If m/44'/0' is missing should we use
m/44'/1' instead, using the same addresses as for testnet?
One could also restart with a different seed in this case, but this
wouldn't work if one later wants to support another BIP-43 proposal
and still keep the same wallet.
I think the first point alone is reason enough to change this. I am
not aware of a BIP-32 application that handles errors like this
correctly in all cases. It is also very hard to test, since it is
infeasible to brute-force a BIP-32 key and a path where the node does
not exists.
This problem can be avoided by repeating the hashing with slightly
different input data until a valid private key is found. This would
be in the same spirit as RFC-6979. This way, the library will always
return a valid node for all paths. Of course, in the case where the
node is valid according to the current standard the behavior should be
unchanged.
I think the backward compatibility issues are minimal. The chance
that this affects anyone is less than 10^-30. Even if it happens, it
would only create some additional addresses (that are not seen if the
user downgrades). The main reason for suggesting a change is that we
want a similar method for different curves where a collision is much
more likely.
#QUESTIONS:
What is the procedure to update the BIP? Is it still possible to
change the existing BIP-32 even though it is marked as final? Or
should I make a new BIP for this that obsoletes BIP-32?
What algorithm is preferred? (bike-shedding) My suggestion:
---
Change the last step of the private -> private derivation functions to:
. In case parse(I_L) >= n or k_i = 0, the procedure is repeated
at step 2 with
I = HMAC-SHA512(Key = c_par, Data = 0x01 || I_R || ser32(i))
---
I think this suggestion is simple to implement (a bit harder to unit
test) and the string to hash with HMAC-SHA512 always has the same
length. I use I_R, since I_L is obviously not very random if I_L >= n.
There is a minimal chance that it will lead to an infinite loop if I_R
is the same in two consecutive iterations, but that has only a chance
of 1 in 2^512 (if the algorithm is used for different curves that make
I_L >= n more likely, the chance is still less than 1 in 2^256). In
theory, this loop can be avoided by incrementing i in every iteration,
but this would make an implementation error in the "hard to test" path
of the program more likely.
The other derivation functions should be updated in a similar matter.
Also the derivation of the root node from the seed should be updated
in a similar matter to avoid invalid seeds.
If you followed until here, thanks for reading this long posting.
Jochen
Published at
2023-06-07 17:50:09Event JSON
{
"id": "d2ceb940d8e685faff395dd75041e7b793c42297d92e1b25d748eaac636cf617",
"pubkey": "5f325e2a1875039f7993aa44faeaa213e27f236f1388a14ae04289d0c742bc95",
"created_at": 1686160209,
"kind": 1,
"tags": [
[
"e",
"7a09f5b1650d8bf91dee85a09eb46eb6358130e456757f2a5ef707d77b99ebe5",
"",
"reply"
],
[
"p",
"a23dbf6c6cc83e14cc3df4e56cc71845f611908084cfe620e83e40c06ccdd3d0"
]
],
"content": "📅 Original date posted:2016-04-20\n📝 Original message:Hello Bitcoin Developers,\n\nI would like to make a proposal to update BIP-32 in a small way.\n\nTL;DR: BIP-32 is hard to use right (due to its requirement to skip\naddresses). This proposal suggests a modification such that the\ndifficulty can be encapsulated in the library.\n\n#MOTIVATION:\n\nThe current BIP-32 specifies that if for some node in the hierarchy\nthe computed hash I_L is larger or equal to the prime or 0, then the\nnode is invalid and should be skipped in the BIP-32 tree. This has\nseveral unfortunate consequences:\n\n- All callers of CKDpriv or CKDpub have to check for errors and handle\n them appropriately. This shifts the burden to the application\n developer instead of being able to handle it in the BIP-32 library.\n\n- It is not clear what to do if an intermediate node is\n missing. E.g. for the default wallet layout, if m/i_H/0 is missing\n should m/i_H/1 be used for external chain and m/i_H/2 for internal\n chain? This would make the wallet handling much more difficult.\n\n- It gets even worse with standards like BIP-44. If m/44' is missing\n should we use m/45' instead? If m/44'/0' is missing should we use\n m/44'/1' instead, using the same addresses as for testnet?\n One could also restart with a different seed in this case, but this\n wouldn't work if one later wants to support another BIP-43 proposal\n and still keep the same wallet.\n\nI think the first point alone is reason enough to change this. I am\nnot aware of a BIP-32 application that handles errors like this\ncorrectly in all cases. It is also very hard to test, since it is\ninfeasible to brute-force a BIP-32 key and a path where the node does\nnot exists.\n\nThis problem can be avoided by repeating the hashing with slightly\ndifferent input data until a valid private key is found. This would\nbe in the same spirit as RFC-6979. This way, the library will always\nreturn a valid node for all paths. Of course, in the case where the\nnode is valid according to the current standard the behavior should be\nunchanged.\n\nI think the backward compatibility issues are minimal. The chance\nthat this affects anyone is less than 10^-30. Even if it happens, it\nwould only create some additional addresses (that are not seen if the\nuser downgrades). The main reason for suggesting a change is that we\nwant a similar method for different curves where a collision is much\nmore likely.\n\n#QUESTIONS:\n\nWhat is the procedure to update the BIP? Is it still possible to\nchange the existing BIP-32 even though it is marked as final? Or\nshould I make a new BIP for this that obsoletes BIP-32?\n\nWhat algorithm is preferred? (bike-shedding) My suggestion:\n\n---\n\nChange the last step of the private -\u003e private derivation functions to:\n\n . In case parse(I_L) \u003e= n or k_i = 0, the procedure is repeated\n at step 2 with\n I = HMAC-SHA512(Key = c_par, Data = 0x01 || I_R || ser32(i))\n\n---\n\nI think this suggestion is simple to implement (a bit harder to unit\ntest) and the string to hash with HMAC-SHA512 always has the same\nlength. I use I_R, since I_L is obviously not very random if I_L \u003e= n.\nThere is a minimal chance that it will lead to an infinite loop if I_R\nis the same in two consecutive iterations, but that has only a chance\nof 1 in 2^512 (if the algorithm is used for different curves that make\nI_L \u003e= n more likely, the chance is still less than 1 in 2^256). In\ntheory, this loop can be avoided by incrementing i in every iteration,\nbut this would make an implementation error in the \"hard to test\" path\nof the program more likely.\n\nThe other derivation functions should be updated in a similar matter.\nAlso the derivation of the root node from the seed should be updated\nin a similar matter to avoid invalid seeds.\n\nIf you followed until here, thanks for reading this long posting.\n\n Jochen",
"sig": "80edb424964178bafe08e1d80e54bbd20e35aec46ac1c2d9878dcd49b0ada7524383b41b9b4b7ac9f2fe142ff0bd8f96ee3074564b6e587b4d559b45bc166874"
}