每天进步一点点:从签名恢复公钥
之前学习了私钥、公钥、签名、验证等相关知识,一个有意思的地方是,公钥是可以从签名当中恢复的,是不是很神奇?今天我们就来看一下如何从签名当中恢复公钥。
(图源 :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)
用上述代码,对之前我们签名中的公钥进行恢复,测试代码如下:
for i in range(0, 4):
print(i)
vk=recover_public_key(digest,sigstr,i)
print(hexlify(vk.to_string()).decode())
我们会发现,当i=2时(第三次)程序异常退出,发现i=0时发现的公钥是我们使用的公钥:
不知道是不是每次都是只有两个解?
至于第几个解才是我们想要的公钥,steem-python中采取的是比较方法,把正确的公钥索引写进签名的参数中(recoverPubkeyParameter),这样我们就可以知道解出来的一系列(可能是2个)公钥中,哪个是我们签名时锁使用的了。
代码实现 ecdsa
从签名中恢复公钥,新版的ecdsa中直接就有对应函数:
反正都是读不懂,不过最后只是把R中的y换成了-y,只得出两个点Q(两组公钥),测试代码如下:
Sig = ecdsa.ecdsa.Signature(r, s)
digest_number = ecdsa.util.string_to_number(digest)
pubks = Sig.recover_public_keys(digest_number,ecdsa.SECP256k1.generator)
这里得到的两个公钥其实是椭圆曲线上的两个点,转换成可阅读的公钥形式可以参考我以前的公钥生成代码(ecdsa.util.number_to_string),或者直接调用ecdsa的ecdsa.VerifyingKey.from_public_point即可,这里就不再赘述了。
用上述函数得出的两组公钥和用steem-python部分代码得出的两组公钥是完全相同的,所以再次得出疑问,是不是从签名中只能算出两组公钥?
哎,椭圆曲线就在眼前,想搞明白怎么回事太难了:
不过搞不懂原理就不搞了,知道咋用就好了。
相关链接
Leave 每天进步一点点:从签名恢复公钥 to:
Read more #cn posts
Best Posts From oflyhigh
We have not curated any of oflyhigh's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.