内容简介:欢迎大家关注Rebase公众号本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
欢迎大家关注Rebase公众号
前文介绍
生成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地址 文章中得到了公钥 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 )
- 分类:比特币
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- [学习笔记] “付款到公钥” 和 “付款到公钥哈希”
- Golang代码搜集-基于RSA的公钥加密私钥解密-私钥签名公钥验证
- 随处可见的公钥证书
- 工业网络安全趋势:公钥加密
- Crypto-RSA-公钥攻击小结
- 如何为区块链生成公钥和私钥
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
UNIX编程艺术
[美] Eric S. Raymond / 姜宏、何源、蔡晓骏 / 电子工业出版社 / 2012-8 / 99.00元
《UNIX编程艺术》主要介绍了Unix系统领域中的设计和开发哲学、思想文化体系、原则与经验,由公认的Unix编程大师、开源运动领袖人物之一Eric S.Raymond倾力多年写作而成。包括Unix设计者在内的多位领域专家也为《UNIX编程艺术》贡献了宝贵的内容。《UNIX编程艺术》内容涉及社群文化、软件开发设计与实现,覆盖面广、内容深邃,完全展现了作者极其深厚的经验积累和领域智慧。一起来看看 《UNIX编程艺术》 这本书的介绍吧!