自学内容网 自学内容网

密码学 | 多重签名:基于 Schnorr 的 MuSig 方案

⚠️原文:Schnorr Applications: MuSig

⚠️写在前面:本文属搬运博客,自己留存学习。



1 什么是多签名?

多签名 是指:一组签名密钥 ( X 1 , X 2 , . . . , X n ) (X_1, X_2, ..., X_n) (X1,X2,...,Xn) 共同生成一条消息的签名。

任何正常签名方案 —— 如 Schnorr 或 ECDSA —— 的多签名方案,最简单的方法是将每个签名者对给定消息的单个签名连接起来: s = ( s 1 , s 2 , . . . , s n ) s=(s_1, s_2, ..., s_n) s=(s1,s2,...,sn)

个人理解:默认的 Schnorr 或 ECDSA 是单签名方案,但它们也可以有多签名版本。最简单的方式,就是将各个单签名连接起来,构成一个多签名。

这个方案已在比特币中通过操作 OP_CHECKMULTISIG —— 简称 OP_CMS —— 得到支持。实际上,OP_CMS 支持更多的操作,你可以创建一个由 m-of-n 参与者控制的地址,其中 m ≤ n,但我们今天只考虑 n-of-n 的情况。

什么是 m-of-n 参与者?答:意思是,至少需要 n 个参与者中的 m 个人同意,才能生成一个有效的签名。当 m=1 时,它等同于传统的单签名方案,即只需要一个人同意即可生成签名。

虽然 OP_CMS 是一个正确的多签名方案,但它有一些严重的缺点。在这种方案中,n-of-n 多签名将是常规签名的 n 倍 大小,因为它需要在链上放置 n 个签名和公钥对。同样,这比验证单个签名需要更长的时间。最后,它没有隐私功能,因为所有参与者都是公开的,即所有 n 个密钥都必须用于验证。

为什么需要在链上放置 n 个签名和公钥对?答:因为在验证签名的时候,我们需要使用相应的签名和公钥。由于在 OP_CMS 方案中,一个多签名是由 n 个签名拼接来的,因此我们在验证时需要这 n 个签名和它们各自对应的公钥。

MuSig 旨在解决这些问题,它是一个 Schnorr 多签名方案。无论签字方的数量多少,它都能产生一个与普通 Schnorr 签名无法区分的签名。因此,MuSig 签名的验证与普通 Schnorr 签名完全相同。此外,它支持 密钥聚合,因此单个签名密钥可以保持私密。

与 OP_CMS 相比,MuSig 降低了存储负担、减少了验证时间、保护了密钥隐私😇

具体来说,假设有 n 个签名者 X 1 , X 2 , . . . , X n X_1, X_2, ..., X_n X1,X2,...,Xn 和一条消息 m m m,他们希望共同签署这条消息。通过使用 MuSig,他们可以生成一个单一的 Schnorr 签名 ( R , s ) (R, s) (R,s)

这将使用 聚合密钥 X = a g g ( X 1 , X 2 , . . . , X n ) X = agg(X_1, X_2, ..., X_n) X=agg(X1,X2,...,Xn) m m m 进行有效签名,这样在任何公共空间 —— 如区块链 —— 中,这 n 个签名者们可以假装自己只是一位拥有密钥 X X X 的签名者。简而言之,我们可以使得多签名输出和标准输出没有区别。



2 朴素 Schnorr 多签名

针对签名者 i i i,我们对其所使用的变量进行说明:

  • 私钥: x i x_i xi
  • 公钥: X i = x i ∗ G X_i=x_i*G Xi=xiG
  • 一次性私钥: k i k_i ki
  • 部分签名: R i = k i ∗ G R_i=k_i*G Ri=kiG
  • 部分签名: s i = k i + H ( X , R , m ) ∗ x i s_i=k_i+H(X, R, m)*x_i si=ki+H(X,R,m)xi

为什么叫作一次性私钥?答:签名者 i i i 每次签名都会重新生成一个随机值 k i k_i ki,对 k i k_i ki 是用完即弃,与 x i x_i xi 这种长期性私钥应该区分开来。

假设有 n n n 个签名者。

朴素 Schnorr 多签名让每个签名者分享自己的公钥 X i X_i Xi,计算并定义聚合密钥为:

X = X 1 + X 2 + . . . + X n X = X_1 + X_2 + ... + X_n X=X1+X2+...+Xn

让每个签名者生成并分享自己的部分签名 R i R_i Ri,计算并定义部分聚合签名为:

R = R 1 + R 2 + . . . + R n R = R_1 + R_2 + ... + R_n R=R1+R2+...+Rn

为什么 R i R_i Ri 被称为 部分签名 R R R 被称为 部分聚合签名?答:因为一个完整的签名是 ( R , s ) (R, s) (R,s),所以单独的 R R R s s s 只能算作部分签名或者部分聚合签名。

获得部分聚合签名 R R R 后,每个签名者可以自行计算他们的部分签名 s i s_i si

s i = k i + H ( X , R , m ) ∗ x i s_i = k_i + H(X, R, m)*x_i si=ki+H(X,R,m)xi

为了让 s i s_i si 们可以相加,朴素 Schnorr 多签名Schnorr 签名 中的 H ( X , R i , m ) H(X, R_i, m) H(X,Ri,m) 改为了 H ( X , R , m ) H(X, R, m) H(X,R,m)

然后再分享自己的部分签名 s i s_i si,计算并定义部分聚合签名为:

s = s 1 + s 2 + . . . + s n = ( k 1 + . . . + k n ) + H ( X , R , m ) ∗ ( x 1 + . . . + x n ) = k + H ( X , R , m ) ∗ x \begin{alignat}{2} s &= s_1 + s_2 + ... + s_n \\ &= (k_1 + ... + k_n) + H(X, R, m)*(x_1 + ... + x_n) \\ &= k + H(X, R, m)*x \end{alignat} s=s1+s2+...+sn=(k1+...+kn)+H(X,R,m)(x1+...+xn)=k+H(X,R,m)x

最终的朴素 Schnorr 多签名为 ( R , s ) (R,s) (R,s),涉及以下变量:

  • 聚合私钥: x x x
  • 聚合公钥: X X X
  • 聚合一次性私钥: k k k
  • 聚合部分签名: R R R
  • 聚合部分签名: s s s

验证者的验证等式为:

s ∗ G = ? R + H ( R , M ) ∗ X s*G\overset{?}{=} R+H(R,M)*X sG=?R+H(R,M)X

可以看出,上述方案不仅是一个 多签名方案,还是一个 聚合签名方案,因为它允许将多个签名合并为一个签名,隐藏掉了原始的单个签名的信息。遗憾的是,该方案容易受到所谓的 恶意密钥攻击 或称 流氓密钥攻击

英文是 Rogue Key Attack



3 恶意密钥攻击

假设我的公钥是 X 1 X_1 X1

我可以撒谎,将一个 X 1 ′ = X 1 − X 2 − . . . − X n X_1'=X_1 - X_2 - ... - X_n X1=X1X2...Xn 值传给其他签名者,并声称这就是我的公钥。这将导致聚合公钥 X X X 变为 X = X 1 ′ + X 2 + . . . + X n = X 1 X = X_1' + X_2 + ... + X_n = X_1 X=X1+X2+...+Xn=X1。又因为我是公钥 X 1 X_1 X1 的所有者,所以我知道 X 1 X_1 X1 对应的私钥。由此一来,我可以单方面将资金发送到任何我想要的地方,而无需任何合作。

首先,因为公钥都是公开的,所以我可以获取到所有其他签名者的公钥。接着,我令虚假公钥的值为 X 1 − X 2 − . . . − X n X_1 - X_2 - ... - X_n X1X2...Xn,以此使聚合公钥 X X X 退化为我的公钥 X 1 X_1 X1 。最后,我便可以为所欲为😈

如果你要求我证明:我对声称属于我的公钥拥有私钥,这将阻止我的恶意密钥攻击,但我还可以对随机数值 R i R_i Ri 执行相同的攻击,以控制聚合一次性私钥 k k k

原文中的 nonce 值是什么意思?答:nonce 是 number once 的缩写,在密码学中 nonce 是一个只被使用一次的任意或非重复的随机数值。

然后,我会在接收完所有其他签名者的部分签名 s i s_i si 之后,计算出聚合签名 s = k + H ( X , R , m ) ∗ x s = k + H(X, R, m)*x s=k+H(X,R,m)x,这将允许我计算出 x x x,再次让我能够不合作地将所有资金发送到任何地方。

刚才已经获取到了 k k k 值, s s s H ( X , R , m ) H(X, R, m) H(X,R,m) 又是已知的,因此可以倒推出 x x x 的值。



4 改进方案

为了修复上述方案,我们需要确保聚合随机数值 R R R 和聚合公钥 X X X 能够抵御恶意密钥攻击。

具体来说,我们要求每个签名者广播自己的随机数 R i R_i Ri 的哈希值 t i = H ( R i ) t_i = H(R_i) ti=H(Ri) —— 而非 R i R_i Ri 本身 —— 并且只有在看到所有其他签名者的 t i t_i ti 之后才揭示自己的随机数 R i R_i Ri

这里说的其实就是一个哈希承诺的过程,请自行补课密码学承诺😇

这种方案能够缓解对随机数 R i R_i Ri 的攻击,但对聚合签名公钥 X X X 来说却不切实际。因为公钥通常是公开的并且可以被重复使用。

上述方案相当于是把 R i R_i Ri 藏起来,但 X i X_i Xi 作为公钥是需要被公开的,因此不切实际。

因此,我们可以尝试改变我们的聚合公钥 X X X,使其通过所有签名公钥 X i X_i Xi 的哈希值来计算。

具体来说,令 L L L 为所有公钥的集合 ( X 1 , X 2 , . . . , X n ) (X_1, X_2, ..., X_n) (X1,X2,...,Xn) 的某种编码,然后让:

a i = H ( L ∣ ∣ X i ) a_i = H(L||X_i) ai=H(L∣∣Xi) X = a 1 ∗ X 1 + a 2 ∗ X 2 + . . . + a n ∗ X n X = a_1*X_1 + a_2*X_2 + ... + a_n*X_n X=a1X1+a2X2+...+anXn

其中 H H H 表示哈希函数。

终于看到论文中使用的方法了,喜极而泣😈

这样就很难从 ( X 1 , X 2 , . . . , X n ) (X_1, X_2, ..., X_n) (X1,X2,...,Xn) 中计算出一个 X 1 ′ X_1' X1 使得 X = X 1 X = X_1 X=X1 了。

然而,这样的修改会使聚合私钥 x = x 1 + . . . + x n x=x_1 + ... + x_n x=x1+...+xn 的值不再是聚合公钥 X X X 对应的私钥的值。幸运的是,有一个简单的调整可以修复这个问题:

s i = k i + H ( X , R , m ) ∗ a i ∗ x i s_i = k_i + H(X, R, m)*a_i*x_i si=ki+H(X,R,m)aixi

个人理解:聚合私钥 x x x 本质上就是聚合公钥 X X X 的私钥,需要满足 x ∗ G = X x*G=X xG=X 这一关系。这里 X i X_i Xi 乘以 a i a_i ai 这一权重后导致 X X X 发生了改变,那么 x i x_i xi 也需要乘以相应的权重,以保证 x x x 仍然是 X X X 的私钥。

这样我们就恢复了我们的聚合签名:

s = s 1 + s 2 + . . . + s n = ( k 1 + . . . + k n ) + H ( X , R , m ) ∗ ( a 1 ∗ x 1 + . . . + a n ∗ x n ) = k + H ( X , R , m ) ∗ x \begin{alignat}{2} s &= s_1 + s_2 + ... + s_n \\ &= (k_1 + ... + k_n) + H(X, R, m)*(a_1*x_1 + ... + a_n*x_n) \\ &= k + H(X, R, m)*x \end{alignat} s=s1+s2+...+sn=(k1+...+kn)+H(X,R,m)(a1x1+...+anxn)=k+H(X,R,m)x

回顾一下,MuSig 签名过程包括三个阶段:

  1. 所有签名者发送承诺 t i t_i ti
  2. 所有签名者揭示随机数 R i R_i Ri,并且所有签名者验证 t i = H ( R i ) t_i = H(R_i) ti=H(Ri)
  3. 所有签名者计算并发送他们的部分签名 s i s_i si

最后,任何所有签名者都可以计算并使用普通 Schnorr 签名 ( R , s ) (R, s) (R,s)

什么是承诺?答:承诺全称密码学承诺,是一个密码学概念,主要用于防止发送者撒谎。



5 未来展望

这是本文中证明安全的 MuSig 提案,但许多人对需要 3 个往返通信的要求不满意,并且已经有很多工作致力于消除一个交互性的回合,以制作一个只有 2 个回合的 MuSig 版本。参见 Jonas Nick 的这篇博客文章,了解为什么将 3 个回合协议缩短为 2 个回合协议的各种捷径是不安全的。




原文地址:https://blog.csdn.net/m0_64140451/article/details/137817516

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!