# bitcoin：压缩公钥与未压缩公钥

## 前文介绍

# python code
Pcurve = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 -1 #有限域
x = 0xd061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f69
y = 0x1757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d

x_res = x**3+7
y_res = y**2

(x_res%Pcurve) == (y_res%Pcurve)

### 为啥符合呢

$x^3+7 \ mod \ 23$ 就是 ((x**3)+7) % 23

$y^2 \ mod \ 23$ 就是 (y**2)%23

((x**3)+7) % 23 == (y**2)%23 必然成立，不成立就不符合椭圆曲线加密的定义了。 secp256k1的有限域是Pcurve，Pcurve是个质数。

## 压缩公钥

0x1757......429d 从最后一位 0xd 来看，这个数是奇数，所以压缩公钥是 03d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f69

## 通过压缩公钥得到 未压缩公钥

### python code

def pow_mod(x, y, z):
"Calculate (x ** y) % z efficiently"
number = 1
while y:
if y & 1:
number = number * x % z
y >>= 1
x = x * x % z
return number

def get_uncompressed_key(compressed_key):
Pcurve = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 -1

y_parity = int(compressed_key[:2]) - 2
x = int(compressed_key[2:], 16)

a = (pow_mod(x, 3, Pcurve) + 7) % Pcurve

y = pow_mod(a, (Pcurve+1)//4, Pcurve)

if y % 2 != y_parity:
y = -y % Pcurve

uncompressed_key = '04{:x}{:x}'.format(x, y)
print(uncompressed_key)

get_uncompressed_key("03d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f69")

### js code

var compressedKey = "03d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f69";
var hex = compressedKey.replace(/^0x/, "");
var b = bitcoinjs.Buffer.Buffer.from(hex, "hex");

var keypair = bitcoinjs.bitcoin.ECPair.fromPublicKeyBuffer(b);
keypair.getPublicKeyBuffer().toString("hex");

var o = { compressed: false };
var displayKey = new bitcoinjs.bitcoin.ECPair(null, keypair.__Q, o);

console.log(displayKey.getPublicKeyBuffer().toString("hex"));

### 求secp256r1未压缩公钥

const { PublicKey } = require('bitcore-lib-p256')

const uncompress = key => {
if (!key.compressed) {
throw new Error('Publick key is not compressed.')
}

const x = key.point.getX()
const y = key.point.getY()
const xbuf = x.toBuffer({ size: 32,})

const ybuf = y.toBuffer({ size: 32,})

return Buffer.concat([Buffer.from([0x04]), xbuf, ybuf])
}

const pubKey = '023e3df0d294c19ed29a3e83a21648f7fc6ef9c1363c7dffc7b3650e1f08d98032'
const pubKeyObj = PublicKey.fromString(pubKey)
const rs = uncompress(pubKeyObj).toString('hex')
console.log('rs', rs)

## 比特币地址

#############未压缩公钥生成的地址#############
14xfJr1DArtYR156XBs28FoYk6sQqirT2s
35egEPVeimCvWAmXeHXcYtAUtdA8RtsNUY
mjUcbu6BytKoC7YiEkqPxB1sc6U7nnjFse

#############压缩公钥生成的地址#############
1ASfqPzBTfPSBA9DWdHYYNk4qM5NoGNtzL
3B8gkwUd1ZhpGKqedix8y16zysN6QWqQxS
mpxd8T5AGgpgxGcqECFvNHxPhLg5of8Sh3