每天进步一点点:从签名恢复公钥

每天进步一点点:从签名恢复公钥

之前学习了私钥、公钥、签名、验证等相关知识,一个有意思的地方是,公钥是可以从签名当中恢复的,是不是很神奇?今天我们就来看一下如何从签名当中恢复公钥。


(图源 :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域参数,通常可以确定出公钥,至少在少数几个选择之内。

算法如下:

image.png

是不是很复杂?我觉得也是。

代码实现 (steem-python)

好在steem-python中帮我们实现了一段代码,我们就不必自己去写了。

image.png

代码测试 (steem-python)

用上述代码,对之前我们签名中的公钥进行恢复,测试代码如下:

1
2
3
4
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时发现的公钥是我们使用的公钥:

image.png

不知道是不是每次都是只有两个解

至于第几个解才是我们想要的公钥,steem-python中采取的是比较方法,把正确的公钥索引写进签名的参数中(recoverPubkeyParameter),这样我们就可以知道解出来的一系列(可能是2个)公钥中,哪个是我们签名时锁使用的了。

代码实现 ecdsa

从签名中恢复公钥,新版的ecdsa中直接就有对应函数:

image.png

反正都是读不懂,不过最后只是把R中的y换成了-y,只得出两个点Q(两组公钥),测试代码如下:

1
2
3
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部分代码得出的两组公钥是完全相同的,所以再次得出疑问,是不是从签名中只能算出两组公钥?

哎,椭圆曲线就在眼前,想搞明白怎么回事太难了:

image.png

不过搞不懂原理就不搞了,知道咋用就好了。

相关链接


This page is synchronized from the post: ‘每天进步一点点:从签名恢复公钥’

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×