之前学习了私钥、公钥、签名、验证等相关知识,一个有意思的地方是,公钥是可以从签名当中恢复的,是不是很神奇?今天我们就来看一下如何从签名当中恢复公钥。
(图源 :pixabay)
理论 & 算法
从签名恢复出公钥的说明&算法可以参考《SEC 1: Elliptic Curve Cryptography》一文中的4.1.6 Public Key Recovery Operation小节:
Given an ECDSA signature (r, s) and EC domain parameters, it is generally possible to determine the public key Q, at least to within a small number of choices.
大意就是给签名和EC域参数,通常可以确定出公钥,至少在少数几个选择之内。
算法如下:
是不是很复杂?我觉得也是。
代码实现 (steem-python)
好在steem-python中帮我们实现了一段代码,我们就不必自己去写了。
代码测试 (steem-python)
用上述代码,对之前我们签名中的公钥进行恢复,测试代码如下:
1 | for i in range(0, 4): |
我们会发现,当i=2
时(第三次)程序异常退出,发现i=0
时发现的公钥是我们使用的公钥:
不知道是不是每次都是只有两个解?
至于第几个解才是我们想要的公钥,steem-python中采取的是比较方法,把正确的公钥索引写进签名的参数中(recoverPubkeyParameter
),这样我们就可以知道解出来的一系列(可能是2个)公钥中,哪个是我们签名时锁使用的了。
代码实现 ecdsa
从签名中恢复公钥,新版的ecdsa中直接就有对应函数:
反正都是读不懂,不过最后只是把R中的y换成了-y,只得出两个点Q(两组公钥),测试代码如下:
1 | Sig = ecdsa.ecdsa.Signature(r, s) |
这里得到的两个公钥其实是椭圆曲线上的两个点,转换成可阅读的公钥形式可以参考我以前的公钥生成代码(ecdsa.util.number_to_string
),或者直接调用ecdsa的ecdsa.VerifyingKey.from_public_point
即可,这里就不再赘述了。
用上述函数得出的两组公钥和用steem-python部分代码得出的两组公钥是完全相同的,所以再次得出疑问,是不是从签名中只能算出两组公钥?
哎,椭圆曲线就在眼前,想搞明白怎么回事太难了:
不过搞不懂原理就不搞了,知道咋用就好了。
相关链接
- SEC 1: Elliptic Curve Cryptography
- https://github.com/warner/python-ecdsa
- https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#der-encoding
- 每天进步一点点:学习用公钥验证
- 每天进步一点点:学习用私钥签名
- 每天进步一点点:STEEM/HIVE私钥/公钥的还原
- 每天进步一点点:STEEM/HIVE公钥(Public Key)生成探索
- 每天进步一点点:STEEM/HIVE私钥(Private Key)生成探索
This page is synchronized from the post: ‘每天进步一点点:从签名恢复公钥’