3

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

2
  • 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. Commented 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.
    – cdecker
    Commented May 29, 2013 at 14:50

2 Answers 2

3

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.

  1. 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.
  2. Derive from yP a single bit ȳP as follows (this allows the y-coordinate to be represented compactly using a single bit):
  3. If q = p is an odd prime, set ȳP = yP mod 2.
  4. 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.
  5. Assign the value 0216 to the single octet Y if ȳP = 0, or the value 0316 if ȳP = 1.
  6. 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.

0

Parity determines if its 0x02 or 0x03

Node.JS:

if (y.isEven()) {
    publicKeyBytesCompressed.unshift(0x02)
} else {
    publicKeyBytesCompressed.unshift(0x03)
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.