I've noticed that compressed public keys are always either 0x02 or 0x03, but what exactly determines whether it's 0x02 or 0x03? I can go look at the OpenSSL code to answer this, but I'm hoping someone already knows the answer and can tell me :P
-
Nevermind, I figured it out myself looking at the source. For those that want to know, the first byte of an OpenSSL EC public key has three bitflags. They have these semantics: bit0 - tells you which y coordinate to use, bit1 - compressed, bit2 - uncompressed So compressed public keys will always be 2 or 3 in the first byte, depending on which y coord is being used.– user2387532Commented May 28, 2013 at 21:50
-
Could you elaborate and post it as a response, then accept it? That way we the question gets marked as complete.– cdeckerCommented May 29, 2013 at 14:50
Add a comment
|
2 Answers
The public key format that OpenSSL and Bitcoin use is described in SEP 1, published by the Standards for Efficent Cryptography Group on page 10.
- Convert the field element xP to an octet string X of length ceil([log2 q]/8) octets using the conversion routine specified in Section 2.3.5.
- Derive from yP a single bit ȳP as follows (this allows the y-coordinate to be represented compactly using a single bit):
- If q = p is an odd prime, set ȳP = yP mod 2.
- If q = 2m, set ȳP = 0 if xP = 0, otherwise compute z = zm-1xm-1 + · · · + z1x + z0 such that z = yPxP and set ȳP = z0.
- Assign the value 0216 to the single octet Y if ȳP = 0, or the value 0316 if ȳP = 1.
- Output M = Y || X.
... and page 53 ...
- If C is an octet string and the leftmost octet of C is 0216 or 0316, parse the leftmost ceil([log2 q]/8)+1 octets of C as an octet string R, the rightmost maclen octets of C as an octet string D, and the remaining octets of C as an octet string EM.
- If the leftmost octet of C is 0416, parse the leftmost 2 * ceil([log2 q]/8) + 1 octets of C as an octet string R, the rightmost maclen octets of C as an octet string D, and the remaining octets of C as an octet string EM.
- If the leftmost octet of C is not 0216, 0316, or 0416, output “invalid” and stop.
So, in plain English:
- It can be 0x04 too. That's is the 'uncompressed' key. If you generate a key today, it won't create one of these. However, if you have an old wallet, you might have some. They are equivalent in security to compressed keys.
- Whether it's 0x02 or 0x03 depends on on the value of ȳP. We can generate ȳP instead of including the full y coordinate, which saves us a nice bit of space. That's what compressed keys are.
I'm not sure what q is in this context, if somebody wants to tell me in comments, it'd be appreciated.
Parity determines if its 0x02 or 0x03
Node.JS:
if (y.isEven()) {
publicKeyBytesCompressed.unshift(0x02)
} else {
publicKeyBytesCompressed.unshift(0x03)
}