bitcoin:压缩公钥与未压缩公钥

栏目: IT技术 · 发布时间: 3年前

内容简介:欢迎大家关注Rebase公众号本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

欢迎大家关注Rebase公众号

bitcoin:压缩公钥与未压缩公钥

前文介绍

生成bitcoin地址 文章中得到了公钥 04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d公钥其实是secp256k1椭圆曲线的一个坐标点 ,即(x,y)形式,用16进制表示是 (0xd061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f69, 0x1757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d)

而且(x,y) 必然符合:

# 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)

为啥符合呢

比特币secp256k1椭圆曲线公式是 $y^2=x^3+7$ 椭圆曲线加密算法 定义在有限域 $\mathbb{F} p$上 假设 $y^2=x^3+7$ 在 $\mathbb{F} {23}$,

$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是个质数。

未压缩公钥

前缀04+x坐标+y坐标 04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d

压缩公钥

前缀03+x(如果y是奇数),前缀02+x(如果y是偶数)

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

现在一般都使用压缩公钥, 压缩/未压缩公钥生成的地址确实会不一样, 未压缩公钥早已成了非主流。

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

python code

没想到求个未压缩,常规方法不可行,计算量太大了,需要用到 二次剩余定理 ,二次剩余在 密码学以及大数分解中都很有用,还有个很出名的 Cipolla算法

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未压缩公钥

这是 secp256r1 ,是 prime256v1 ,是 NIST256p ,是 ecdsa-sha2-nistp256 ,也是 P256 椭圆曲线的计算代码, 不是btc用的secp256k1曲线

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)

比特币地址

以下是同一个私钥,不同类型的公钥生成的不同地址。 代码见 gen_addr

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

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

参考:

https://github.com/iancoleman/keycompression https://www.mina.moe/archives/11441 https://blog.mythsman.com/post/5d2c986667f841464434a58e/ https://bitcointalk.org/index.php?topic=644919 https://git.coolaj86.com/coolaj86/eckles.js https://crypto.stackexchange.com/a/42906

bitcoin:压缩公钥与未压缩公钥

前文介绍

生成bitcoin地址 文章中得到了公钥 04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d公钥其实是secp256k1椭圆曲线的一个坐标点 ,即(x,y)形式,用16进制表示是 (0xd061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f69, 0x1757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d)

而且(x,y) 必然符合:

# 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)

为啥符合呢

比特币secp256k1椭圆曲线公式是 $y^2=x^3+7$ 椭圆曲线加密算法 定义在有限域 $\mathbb{F} p$上 假设 $y^2=x^3+7$ 在 $\mathbb{F} {23}$,

$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是个质数。

未压缩公钥

前缀04+x坐标+y坐标 04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d

压缩公钥

前缀03+x(如果y是奇数),前缀02+x(如果y是偶数)

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

现在一般都使用压缩公钥, 压缩/未压缩公钥生成的地址确实会不一样, 未压缩公钥早已成了非主流。

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

python code

没想到求个未压缩,常规方法不可行,计算量太大了,需要用到 二次剩余定理 ,二次剩余在 密码学以及大数分解中都很有用,还有个很出名的 Cipolla算法

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未压缩公钥

这是 secp256r1 ,是 prime256v1 ,是 NIST256p ,是 ecdsa-sha2-nistp256 ,也是 P256 椭圆曲线的计算代码, 不是btc用的secp256k1曲线

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)

比特币地址

以下是同一个私钥,不同类型的公钥生成的不同地址。 代码见 gen_addr

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

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

参考:

https://github.com/iancoleman/keycompression https://www.mina.moe/archives/11441 https://blog.mythsman.com/post/5d2c986667f841464434a58e/ https://bitcointalk.org/index.php?topic=644919 https://git.coolaj86.com/coolaj86/eckles.js https://crypto.stackexchange.com/a/42906

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 13分钟前
  • 阅读 ( 9 )
  • 学分 ( 0 )
  • 分类:比特币

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

颠覆者:周鸿祎自传

颠覆者:周鸿祎自传

周鸿祎、范海涛 / 北京联合出版公司 / 2017-11 / 49.80元

周鸿祎,一个在中国互联网历史上举足轻重的名字。他被认为是奠定当今中国互联网格局的人之一。 作为第一代互联网人,中国互联网行业最好的产品经理、创业者,他每时每刻都以自己的实践,为互联网的发展贡献自己的力量。 在很长一段时间内,他没有在公共场合发声,甚至有粉丝对当前死水一潭的互联网现状不满意,发出了“人民想念周鸿祎”的呼声。 但周鸿祎在小时候,却是一个踢天弄井,动不动就大闹天宫的超级......一起来看看 《颠覆者:周鸿祎自传》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换