Closed bibibong closed 2 years ago
We only ever need to pad the private key bytes when further deriving a child extended key. This is already taken care of here: https://github.com/btcsuite/btcutil/blob/4649e4b73b34090724fff8a302751260c20551fd/hdkeychain/extendedkey.go#L250-L258
The other thing we care about is whether the integer corresponding to the private child key bytes is valid for the secp256k1 elliptic curve. Here it doesn't matter if the serialization was done in 32 bytes or less, as long as the underlying crypto library can convert it to a big.Int
number.
Note that the hdkeychain
package is tested against the official BIP-0032 test vectors, so I would be very surprised if there is a bug of the nature you describe.
Let me know if this answers your question. Otherwise, if you can provide a failing test case, I'll gladly take a look.
From my point of view, this implementatin might get a wrong result in some case. As the BIP32 said, in the case of computing a child extended hardened private key from the parent private key, I = HMAC-SHA512(Key = cpar, Data = 0x00 || ser256(kpar) || ser32(i)). As for implementation, see extendedkey.go. https://github.com/btcsuite/btcutil/blob/4649e4b73b34090724fff8a302751260c20551fd/hdkeychain/extendedkey.go#L250-L272 If the length of k.key is less than 32, for example 31, then the Data = 0x00 || 31 bytes || 0x00 || ser32(i). ser256(kpar) just performs like another key leading with this 31 bytes and followed one 0x00. This is not consistent with the regulations of BIP32.
Here is a test vector.
Seed(Hex): 1cae71ac5ed584ff88a078a119512d12bb61e5398521785e123b6d08809d44b2
In Chain m/44'/0', this implementaion gets a wrong result. This is because the length of the serialization of its parant private key is 31 and we are deriving a hardened child private key. I tried to fix this bug with leading 0x00 and got another result.
Seed(Hex): 1cae71ac5ed584ff88a078a119512d12bb61e5398521785e123b6d08809d44b2
I got the same result on bip32.org.
As the result shows, this implementation might calculate a child key different from the one specified in BIP32 in some scenarios. As for the official BIP-0032 test vectors, the length of the serialization of their private key are all 32.
@silencer-Tsai good case👍
@ksedgwic just ran into this issue, and I noticed that there is this already open issue. I submitted a PR just now, linked above.
@ksedgwic just ran into this issue, and I noticed that there is this already open issue. I submitted a PR just now, linked above.
I try to replace the original code with the following code. Hope to help. https://github.com/btcsuite/btcutil/blob/4649e4b73b34090724fff8a302751260c20551fd/hdkeychain/extendedkey.go#L257
copy(data[keyLen-len(k.key):], k.key)
@silencer-Tsai if you haven't already, please submit it to BIP32 with the correct result? People randomly implementing and copy/pasting fixtures might run into it then. Plus a note to explain what to look for if it fails? :)
Always thought it'd be cool to write a standard testing interface for bitcoin libraries, implement the interface for each lib, then test against vectors in the suite. This kind of bug (non-portable results due to implementation quirks) sucks and can be hard to detect for a long time if you always use the same software.. I can imagine a lot of stress trying to find out why electrum shows an empty balance but the servers say otherwise!
Is this issue resolved?
Is this issue resolved?
@benma Yes. See https://github.com/btcsuite/btcutil/pull/182
This has been resolved.
See extendedkey.go:297 The bytes length may be smaller than 32. Is there any bug when deriving hardened private key? The derived key with padding differs.