快捷搜索:

Schnorr 签名怎么样提高BTC

签名

第二个问题是已知的 Rogue 密钥攻击。这篇论文解说得很好,所以我就不赘述了。大概意思是假如你的其中一个设施被黑(譬如你的热钱包被劫持),并假装我们的公钥是(P1 - P2),那就可以仅凭私钥 pk1 便控制两个私钥共享的资金。一个容易的解决方法是,在设置设施时,需要用私钥对相应的公钥签名。

还有第三个重大问题。你没法用确定性的 k 来签名。假如你用了确定性的 k,则仅需一种容易的攻击,黑客即可获得你的私钥。攻击如下:某个黑客黑入你的手提电脑,完全控制了其中一把私钥(譬如 pk1)。大家感觉资金仍是安全的,由于用大家的BTC需要 pk1 和 pk2 的聚合签名。所以大家像平常一样发起买卖,筹备好一笔待签名的买卖和 R1,发送给大家的硬件钱包,硬件钱包签名后将 (R2, s2)发回给热钱包 …… 然后,热钱包出错了,没法完成签名和广播。于是大家再试一次,但这一次被黑的电脑用了另一个随机数 —— R1' 。大家在硬件钱包里签名了同一笔买卖,又将 (R2, s2')发回给了被黑的电脑。这一次,没下文了 —— 大家所有些BTC都不翼而飞了。

在这次攻击中,黑客获得了同一笔买卖的两个有效的签名:(R1, s1, R2, s2) 和 (R1', s1',R2,s2')。这个 R2 是一样的,但R = R1 + R2和R' = R1' + R2是不一样的。这就意味着黑客可以计算出大家的第二个私钥:s2-s2'=-hash)⋅pk2或者说pk2=/-hash)。我发现这就是密钥聚合最不便捷的地方 —— 大家每次都要用一个好的随机数生成器,如此才能安全地聚合。

MuSig解决了其中一个问题 —— rogue key 攻击将不可以再奏效。这里的目的是把 多方/多个设置的签名和公钥聚合在一块,但又不需要你证明自己具备与这部分公钥相对应的私钥。

聚合签名对应着聚合公钥。但在 MuSig 中,大家不是把所有联合签名者的公钥直接相加,而是都乘以一些参数,使得聚合公钥P = hash×P1 + … + hash×Pn。在这里,L = hash—— 这个公共数基于所有些公钥。L 的非线性特质阻止了攻击者架构特殊的公钥来发动攻击。即便攻击者知晓他的hash×Patk应该是什么,他也没办法从中推导出 Patk 来 —— 这就跟你想从公钥中推导出私钥是一样的。

签名架构的其它过程跟上面介绍的非常像。在生成签名时,每一个联合签名者都选择一个随机数 ki 并与他人推荐Ri = ki * G。然后他们把所有些随机点加起来获得R=R1+…+Rn,然后生成签名si = ki + hash ⋅ hash ⋅ pki。因此,聚合签名是=,而验证签名的办法与以前一样:s×G = R + hash×P。

你可能也注意到了,MuSig 和密钥聚合需要 *所有签名者签名一个买卖*。但假如你想做的是 2-3 的多签名脚本呢?这个时候大家可以用签名聚合吗,还是不能不用一般的 OP_CHECKMULTISIG 和分别签名?(译者注:OP_CHECKMULTISIG 是BTC验证椭圆曲线多签名脚本的操作码)

先说答案,是可以的,但协议上或有些许的不同。大家可以开发一个像 OP_CHECKMULTISIG 的操作码,只是检查聚合签名是不是对应于公钥默克尔树上的一个元素。

举例,假如大家想用公钥 P1、P2 和 P3 组成一个 2-3 的多签名脚本,大家需要用这几把公钥的所有两两组合 (P1, P2)、(P2, P3)、(P1, P3) 来构建一棵默克尔树,并把默克尔树根公布在锁定脚本中。

在花费BTC时,大家需要提交一个签名和一个证据,证明这个签名所对应的公钥坐落于由这个树根标记的默克尔树上。对于 2-3 多签名合约来讲,树上只有 3 个元素,证据仅需 2 条哈希值 —— 那个大家想用的公钥组合的哈希值,还有一个邻居的。对于 7-11 多签名脚本来讲,公钥组合有 11!/7!/4!=330 种,证据需要 8 条哈希值。一般来讲,证据所包含的元素数目与多签名的密钥数目大体成正比 ,为log2)。

但有了默克尔公钥树,大家就不必局限于 m-n 多签名脚本了。大家可以做一棵用任意公钥组合的树。举例,假如大家有一个手提电脑,一个手机,一个硬件钱包和一个助记词,大家可以构建一棵默克尔树,允许大家用 手提电脑 + 硬件钱包、手机 + 硬件钱包 或者单独的助记词来用BTC。这是目前的 OP_CHECKMULTISIG 做不到的 —— 除非你用 “IF - Else” 式的步骤控制来架构更复杂的脚本。

- 聚合公钥的默克尔树。不止是多签名 -

Schnorr 签名非常棒,它解决了区块验证中的一些计算开销问题,也给了大家密钥聚合的能力。后者在用时有的不便利,但大家不是在强迫大伙用它 —— 无论怎么样,大家都可以仍旧用一般的多签名策略,用单独的、不聚合的签名。

我迫不及待想用 Schnorr 签名,期望BTC协议能尽快纳入这种签名策略。

另外,我也真心喜欢MuSig,它是个高雅的策略,论文也浅显易懂。

- 图形解析 Schnorr 签名和验证 -

这个等式是线性的,所以多个等式可以相加相减而等号仍然成立。这给大家带来了 Schnorr 签名的多种好特质。

在验证区块链上的一个区块时,大家需要验证区块中所有买卖的签名都是有效的。假如其中一个是无效的,无论是哪一个 —— 大家都需要拒绝掉整个区块。

ECDSA 的每个签名都需要专门验证,意味着假如一个区块中包含 1000 条签名,那大家就需要计算 1000 次除法和 2000 次点乘法,总计约 3000 次繁重的运算。

但有了 Schnorr 签名,大家可以把所有些签名验证等式加起来并节省一些计算量。在一个包含 1000 笔买卖的区块中,大家可以验证:

在阅读 Blockstream 写作的MuSig论文时,我一直在想象,这对于我一个BTC用户来讲,到底意味着什么。我发现 Schnorr 签名的一些特质实在是很棒而且便利,但某一些特质则很烦人。在这篇文章里,我期望能跟各位推荐我的想法。不过,大家先迅速回顾一下。

目前BTC的所有权体系用的是ECDSA(椭圆曲线签名算法)。在签名一条消息m时,大家先哈希这条消息,得出一个哈希值,即z = hash。大家也需要一个随机数(或者至少看上去随机的数)k。在这里,大家不期望信赖随机数生成器(有太多的错误和漏洞都与不合格的随机数生成器有关),所以大家一般用RFC6979,基于大家所知的一个秘密值和大家要签名的消息,计算出一个确定性的 k。

用私钥pk,大家可以为消息m生成一个签名,签名由两个数组成:r(随机点R = k * G的 x 坐标)和s = /k。

然后,用大家的公钥P = pk * G,其他人都可以验证大家的签名,也就是检查×G+×P的 x 坐标确为r。

- ECDSA 算法图形解析。为便于说明,椭圆曲线作在实数域上 -

这种算法是非常容易见到的,也很好使。但还有提高空间。第一,签名的验证包含除法(1/s)和两次点乘法,而这部分操作的计算量都很大。在BTC互联网中,每一个节点都要验证每一笔买卖,所以当你在互联网中发出一笔买卖时,全网几千个节点都要验证你的签名。因此,即便签名的过程开销变得更大,让验证签名变得更容易也还是很有好处的。

第二,节点在验证签名时,每一个签名都要单独验证。在一个 m-n 的多签买卖中,节点需要多次验证同一个签名。譬如一笔 7-11 的多签名买卖,里面包含了 7 个签名,互联网中的每一个节点都要分别验证 7 个签名。另外,这种买卖的体积也很大,用户需要为此付出多得多的手续费。

Schnorr 签名的生成方法有的许不同。它不是两个标量,而是一个点R和一个标量s。像 ECDSA 签名,R 是一个椭圆曲线上的随机点R = k * G。而签名的第二部分 s 的计算过程也有一些不同:s = k + hash ⋅ pk。这里 pk 就是你的私钥,而P = pk * G是你的公钥,m 就是那条消息。验证过程是检查s * G = R + hash * P。

× G=+×P1+ hash×P2+…+hash×P1000)

这里就是一连串的点加法(从计算机运算的角度看,真的是不收费的)和 1001 次点乘法。已经是几乎 3 倍的性能提高了 —— 验证时仅需为每一个签名付出一次重运算。

- 两个签名的批量验证。由于验证等式是线性可加的,所以只须所有些签名都是有效的,这几个等式的和等式也必成立。大家节省了一些运算量,由于标量和点加法比点乘法容易计算得多。-

大家想要安全地保管我们的BTC,所以大家可能会期望用至少两把不一样的私钥来控制BTC。一个在手提电脑或者手机(在线钱包,热钱包)上用,而另一个放在 硬件钱包/冷钱包 里面。即便其中一个泄露了,大家还是掌控着我们的BTC。

目前,达成这种钱包的做法是通过 2-2 的多签名脚本。也就是一笔买卖需要包含两个独立的签名。

有了 Schnorr 签名,大家可以用一对密钥 ,并用一个共享公钥P = P1 + P2 = pk1 * G + pk2 * G生成一个一同签名。在生成签名时,大家需要在两个设施上分别生成一个随机数 (k1, k2),并以此生成两个随机点Ri = ki * G,再分别加上hash,就可以获得 s1 和 s2 了(由于si = ki + hash* pki)。最后,把它们都加起来即可获得签名 = ,这就是大家的共享签名,可用共享公钥来验证。别的人根本没办法看出这是否一个聚合签名,它跟一个一般的 Schnorr 签名看着没两样。

不过,这种做法有三个问题。

第一个问题是 UI 上的。要发起一笔买卖,大家需要在两个设施上发起多轮交互 —— 为了计算一同的 R,为了签名。在两把私钥的状况下,仅需访问一次冷钱包:大家可以在热钱包里筹备好待签名的买卖,选好 k1 并生成R1 = k1 * G,然后把待签名的买卖和这部分数据一同传入冷钱包并签名。由于已经有了 R1,签名买卖在冷钱包中仅需一轮就可以完成。从冷钱包中大家得到 R2 和 s2,传回给热钱包。热钱包用前述的 (k1,R1) 签名买卖,把两个签名加总起来即可向外广播买卖了。

这在体验上跟大家目前能做到的没什么不同,而且每当你加多一把私钥,问题就会变得愈加复杂。假设你有一笔财富是用 10 把私钥一同控制的,而 10 把私钥分别存放在世界各地,这个时候你要发送买卖,该有多麻烦!在目前的 ECDSA 算法中,每一个设施你都仅需访问一次,但假如你用上 Schnorr 的密钥聚合,则需要两次,以获得所有些 Ri 并签名。在这样的情况下,可能不用聚合,而用各私钥单独签名的方法会好一些 —— 如此就仅需一轮交互。

文章完成后,我得到了 Manu Drijvers 的反馈:在一个可证明安全性的多签名策略中,你需要 3 轮交互:

选择一个随机数 ki 与相应的随机点 Ri = ki \G,然后告诉每个设施 Ri 的哈希值 ti=hash,然后每一个设施都能确保你没在知晓别的人的随机数之后改变主意*

采集所有些数字 Ri 并计算公共的 R

您可能还会对下面的文章感兴趣: