Well, there is really only one public key for a given private key. The two forms are just different expressions for the same thing.
We start by picking a private key
k which is just a 256 bit integer. Then we multiply (EC multiplication, not regular) a defined base point on the curve by
k. That gives us a point on the plane, two 256 bit integers,
x and
y.
(x, y) is our public key. It turns out that if we know
x, we can almost calculate
y pretty easily. I say almost calculate, because there is a square root, so we find two possible values for
y, one positive and one negative. So, we can "compress" the public key by giving
x, and the
sign of y, 257 bits instead of 512. (In practice it is 272 vs 520, but whatever.)
It is easy to calculate the full public key using either the compressed key, or the private key. Private keys are scalars, not points, so they can't be "compressed".
To calculate the public key from the private key, it is just
G*
k.
G is the base point defined in
sec2 for secp256k1 (the curve we use).
To calculate it from the compressed key, the magnitude of
y is sqrt(
x3+7). You already have
x because it is stored normally in the compressed key, along with
z which tells you the sign of
y.
The bitcoin address is calculated by hashing the public key. I think the hash is always performed using the full point, and I know that using the full point works, because I've calculated addresses using the uncompressed key, sent coins to them, and spent them using the corresponding private key. I don't
think that starting the hash process using a compressed key will work, but it is late, and I don't feel like digging through the code to find out for sure. Hopefully someone will chime in.