速览比特币中的Schnorr签名

Schnorr签名是比特币Taproot软分叉的一部分,Alice和Bob使用公钥抵消攻击,Alice和Bob各自选择一个大私有随机数,并生成挑战标量,最终生成一个聚合公钥和签名。Shamir秘密共享方案可以防止参与者了解有关秘密的任何信息,无脚本式门限签名方案可以让Alice、Bob和Carol每个人都收到可由任意两个人花费的资金。Bob告知Alice Carol无法联系,可以解决此攻击。

摘要由 Mars AI 生成

本摘要由 Mars AI 模型生成,其生成内容的准确性、完整性还处于迭代更新阶段。

1989 年,Claus Schnorr 发表了一篇描述后来以他命名的签名算法的论文。该算法并不为比特币和许多其他应用所使用的椭圆曲线密码学(ECC) 所特有,尽管可能与椭圆曲线密码学关系是最密切的。 Schnorr 签名有许多良好的性质:

  • 可证明安全。Schnorr 签名安全性的数学证明仅依赖于解决离散对数问题 (DLP) 的难度,尤其是对比特币所用椭圆曲线 (EC)上的离散对数问题;以及使用哈希函数(如比特币中使用的 SHA256 函数)的能力以产生不可预测的值,称为随机预言模型(ROM)。其他签名算法要么具有额外的依赖,要么需要更大的公钥或签名才能实现与 ECC-Schnorr 同等的安全性(仅当威胁被定义为经典计算机时;其他算法可能会针对量子计算机提供更有效的安全性)。
  • 线性性。Schnorr 签名具有数学家称为线性的性质,适用于具有两个特定性质的函数。第一个性质是将两个或多个变量相加,对该加总运行函数将产生与独立对每个变量运行函数然后将结果相加相同的值,如;这种性质称为加性。第二个性质是,将变量乘以一个量然后在该乘积上运行函数,将产生与在变量上运行函数然后乘以同一个量相同的值,如;该性质称为一次齐次性。
  • 在密码学操作中,某些函数可能是私有的(例如涉及私钥或秘密随机数的函数),因此无论在函数内部还是外部执行操作都能够得到相同结果的性质,使得多方可以在无需分享他们的秘密的同时轻松地协调合作。我们将在“基于 Schnorr 的无脚本式多签名”和“基于 Schnorr 的无脚本式门限签名”中看到 Schnorr 签名中线性性的一些具体好处。
  • 批量验证。当以某种方式(比如比特币中的方式)使用时,Schnorr 线性的一个结果是,相对容易做到同时验证多个 Schnorr 签名,且所需时间比独立验证每个签名所需的时间要短。批量验证的签名越多,速度提升就越大。对于一个区块中的典型签名数量,批量验证它们的时间大约是独立验证每个签名所需时间的一半。

在本章后面,我们将完全按照比特币中使用的方式描述 Schnorr 签名算法,但我们将从它的简化版本开始,分阶段逐步实现实际协议。

Schnorr 签名

Alice 首先选择一个大的随机数 (), 称为她的私钥。她还知道比特币椭圆曲线上的一个公共点, 称为生成元 () 。Alice 使用椭圆曲线乘法将  乘以她的私钥 , 这时  被称为标量, 因为它按比例缩放了  。得到的结果 , 称之为 Alice 的公钥。Alice将她的公钥发给Bob。尽管 Bob 也知道 , 但离散对数问题阻止了 Bob 把  除以  以导出 Alice 的私钥。

之后的某个时刻,Bob 希望 Alice 通过证明她知道 Bob 之前收到的公钥 () 对应的标量  来证明自己的身份。 Alice 不能直接给 Bob ,因为这会让Bob可以向其他人证明他是Alice,所以Alice需要在不向 Bob 透露  的情况下证明她知道 ,这称为零知识证明。下面我们开始介绍 Schnorr 身份识别过程:

  1. Alice 选择另一个大随机数 (), 我们称之为私有随机数。她再次将其作为标量使用,将其乘以  得到 , 称之为公共随机数。向Bob发送公共随机数。
  2. Bob 选择他自己的一个大随机数 , 称之为挑战标量。叫 “挑战” 是因为它用于挑战 Alice 来证明她知道她之前给 Bob 的公钥  的私钥 ; 叫“标量”是因为它稍后将用于乘以一个椭圆曲线点。
  3. Alice 现在有了一些数(标量) 、 和  。她使用公式  将它们组合在一起生成最终标量  。把  发给Bob。
  4. Bob 现在知道标量  和 , 但不知道  或  。然而, Bob 确实知道  和 , 并且他可以自己计算  和 。这意味着他可以去检查 Alice 执行操作的一个缩放后版本的相等性:  。如果相等, 那么Bob就可以确信Alice在生成  时知道  。

一个使用整数而不是椭圆曲线点的 Schnorr 身份识别协议:

通过使用简单整数而不是椭圆曲线上的点来替换前面提到的每个值(包括 )来构造一个不安全的过度简化版本,可能会更容易去理解交互式 Schnorr 身份识别协议。例如,我们将使用3 作为一开始的素数:

设置: Alice 选择  作为她的私钥。她将其乘以生成元 , 得到她的公钥 。她给Bob 发送 15 。

  1. Alice 选择私有随机数  并生成公共随机数  。她给 Bob发送 35。
  2. Bob 选择  并将其发给 Alice。
  3. Alice 生成  。她给 Bob 发送40 。
  4. Bob 导出  和  。然后他验证  。注意, 这里与 Alice 执行的操作相同, 但所有值都已按比例放大了5倍(的值)。

当然,这是一个过于简化的例子。当处理简单整数时,我们可以将乘积除以生成元  从而得到底层的标量,这是不安全的。这就是为什么比特币中使用的椭圆曲线密码学的一个关键性质就是做乘法很容易,但除以曲线上的点实际上是不可能的。此外,对于这么小的数字,通过穷举找到底层的值(或其他有效值)会很容易;比特币中使用的数要大得多。

讨论一下交互式 Schnorr 身份识别协议的一些使其安全的性质:

  • 随机数 ()。在步骤 1 中, Alice 选择一个 Bob 不知道也无法猜测的数字, 并给了他该数字的缩放形式  。此时, Bob 也已经拥有了她的公钥 ( , 这是她私钥  的缩放形式。这意味着当 Bob 计算最终方程  时, Bob 不知道两个独立的变量  和  。可以使用简单代数来求解包含一个未知变量的方程,但不能求解包含两个独立未知变量的方程, 因此 Alice 的随机数的存在可以阻止 Bob 导出她的私钥。值得注意的是, 这种保护依赖于随机数以任何方式都不可猜测。如果Alice的随机数有任何可预测的地方, Bob就可能利用它来计算出Alice的私钥。
  • 挑战标量()。Bob等待接收Alice的公共随机数, 然后继续执行步骤 2 , 给Alice一个她之前不知道且无法猜到的数 (挑战标量) 。非常关键的是, Bob要仅在Alice承诺公开随机数后才给她挑战标量。想象一下一个不知道  的人想冒充 Alice, 而 Bob 在收到承诺公共随机数  之前就不小心给了这个人挑战标量 , 会发生什么。冒充者就可以更改 Bob 将用于验证的等式  两边的参数; 具体来说, 可以改变  和  。考虑该表达式的简化形式:  。如果你可以同时更改  和 , 那你就可以用  消掉  (Kurt Pan注:y=x-a)。你为  选择的任何值现在都将满足方程。对于实际的方程, 冒充者只需选择一个随机数为  , 生成 , 然后使用椭圆曲线减法来选择等于  的  。把计算出的 给Bob, 随后给Bob随机的 , Bob会认为这是有效的, 因为  。这解释了为什么协议中的操作顺序至关重要: Bob 必须只在 Alice 承诺了她的公共随机数之后再向 Alice 提供挑战标量。

这里描述的交互式身份识别协议与 Claus Schnorr 的部分原始描述相匹配,但缺少去中心化比特币网络所需的两个必要性质。第一,依赖于Bob等待Alice承诺她的公共随机数,之后Bob再给她一个随机挑战标量。在比特币中,每笔交易的花费者都需要经过数千个比特币全节点的认证,包括尚未启动但其运行者有一天想要确保他们收到的比特币确实来自每个交易都有效的转账链的未来节点。今天或将来任何无法与 Alice 通信的比特币节点都将无法认证她的交易,且将与认证该交易的所有其他节点产生分歧。对于像比特币这样的共识系统来说,这是不可接受的。为了让比特币正常运作,我们需要一个不需要 Alice 和每个想要认证她身份的节点之间进行交互的协议。

一种简单的技术(以其发现者命名的 Fiat-Shamir 转换)可以将 Schnorr 交互式身份识别协议转变为非交互式数字签名方案。回想一下步骤 1 和 2 的重要性——包括按顺序执行它们的重要性。 Alice 必须承诺一个不可预测的随机数;Bob必须在收到Alice的承诺后才给她一个不可预测的挑战标量。再回想一下安全密码学哈希函数的性质:当给定相同的输入时,它将始终产生相同的输出,但当给定不同的输入时,它将产生与随机数据无法区分的值。

这就使得 Alice 可以选择她的私有随机数, 导出她的公共随机数, 然后对公共随机数进行哈希以获得挑战标量。因为 Alice 无法预测哈希函数的输出(挑战), 并且对于相同的输入 (随机数) 输出总是相同的, 所以这确保了Alice获得了一个随机挑战, 即使是她自己选择随机数并对其进行哈希运算的。我们不再需要来自Bob的交互。Alice只需发布她的公共随机数  和标量 , 数千个全节点(过去和未来的)中的每一个都可以对  进行哈希运算以生成 , 从而生成 , 然后验证  。明确写出来的话, 验证方程变为了  。

我们还需要一件事来完成将交互式 Schnorr 身份识别协议转换为对比特币有用的数字签名协议。我们不仅希望 Alice 证明她知道她的私钥;还想让她有能力对一个消息进行承诺。具体来说,我们希望她承诺与她想要发送的比特币交易相关的数据。有Fiat-Shamir 转换在这里,我们已经有了一个承诺,因此可以简单地让它额外去承诺消息。我们现在使用  也承诺消息 ,而不是 ,其中 ||代表串联。

我们现在已经定义出了 Schnorr 签名协议的一个版本,但我们还需要做一件事来解决一个比特币特定的问题。在 BIP32 密钥派生中,未强化派生的算法给定公钥并向其添加一个非秘密值以生成派生公钥。这意味着还可以将该非秘密值添加到用一个密钥的有效签名中,以生成用相关密钥的签名。该相关签名是有效的,但未经拥有私钥的人授权,这是一个重大的安全故障。为保护 BIP32 未强化的派生并支持人们想要在 Schnorr 签名之上构建的多种协议,比特币版本的 Schnorr 签名(称为 secp256k1上的BIP340 Schnorr 签名)除了对公共随机数和消息承诺之外还承诺所使用的公钥。这使得完整的承诺为。

现在我们已经描述了 BIP340 Schnorr 签名算法的每个部分并解释了它们的作用,我们可以定义协议了。整数相乘以模  进行,表示运算结果需要除以数字 (定义在secp256k1 标准中)并使用余数。数字  非常大,但如果它是 3 且运算结果是 5的话,那么我们实际使用的数字是 2(即 5 除以 3 余数为 2)。

设置: Alice 选择一个大随机数 () 作为她的私钥(直接选择或使用 BIP32 等协议从大的随机种子值确定性地生成私钥)。她使用 secp256k1 中定义的参数将生成元  乘以她的标量 , 生成  (她的公钥)。她将她的公钥提供给随后会认证她的比特币交易的每个人(例如, 通过将  包含在交易输出中)。当她准备好支出时, 她就开始生成她的签名:

  1. Alice 选择一个大的私有随机数  并导出公共随机数  。
  2. Alice选择她的消息  (例如,交易数据)并生成挑战标量  。
  3. Alice 生成标量  。  和  这两个值是她的签名。她将此签名提供给每个想要验证该签名的人; 她还需要确保每个人都能收到她的消息。在比特币中, 这是通过将她的签名包含在她的支出交易的见证结构中, 然后将该交易转发到全节点来完成的。
  4. 验证者(例如全节点)使用  导出 , 然后验证   。如果等式有效, 则 Alice 证明了她知道自己的私钥  (无需泄露之) 且承诺了消息 (包含交易数据)。

Schnorr 签名的序列化

一个Schnorr 签名由两个值组成: 和 。  值是比特币的椭圆曲线(称为 secp256k1)上的一个点,通常由两个 32 字节的坐标表示,(x, y)。但因为只需要 x 坐标即可,因此仅包含该值。当你在比特币的 Schnorr 签名中看到  时请注意,它只是该点的 x 坐标。

值  是一个标量(用于与其他数字相乘的数)。对于比特币的 secp256k1 曲线,其长度永远不会超过 32 字节。

虽然  和  有时可以是用少于 32 字节表示的值,但不太可能会比 32 字节小太多,因此它们会被序列化为两个 32 字节的值(小于 32 字节的值会有前导零)。按照先  然后  的顺序序列化,正好产生 64 个字节。

Taproot软分叉(也称为 v1 segwit)将 Schnorr 签名引入了比特币,并且是截至撰写本文时在比特币中使用它们的唯一方式。当与 taproot 密钥路径或脚本路径支出一起使用时,64 字节 Schnorr 签名被视为使用默认签名哈希 (sighash),即 SIGHASH_ALL 。如果使用替代的签名哈希,或者支出者想要浪费空间以显式指定 SIGHASH_ALL ,则会将一个指定签名哈希的附加字节附加到签名上,使签名为 65 字节。

正如我们将看到的,64 或 65 字节都比“ECDSA 签名序列化 (DER)”中会描述的用于 ECDSA 签名的序列化要高效得多。

基于 Schnorr 的无脚本式多签名

在上述单签名 Schnorr 协议中,Alice 使用签名 来公开证明她知道她的私钥,本例中称为 。想象如果 Bob 也有一个私钥 (),他想与 Alice 一起证明他们知道 ,且无需向对方或其他任何人透露他们的私钥。我们再来过一遍 BIP340 Schnorr 签名协议。

警告:我们将要描述的简化协议并不安全,原因将很快解释。在描述被认为是安全的相关协议之前,我们仅使用它来展示 Schnorr 多签名的机制。

Alice 和 Bob 需要导出  的公钥, 即  。由于可以使用椭圆曲线运算将两个椭圆曲线点相加, 因此首先 Alice 导出 , Bob导出  。然后他们将其加在一起以创建  。点  就是他们的聚合公钥。为了创建签名, 他们开始运行简单的多签名协议如下:

  1. 他们各自选择一个大私有随机数,Alice 选择, Bob 选择。他们还各自导出相应的公共随机数  和 。 共同生成一个聚合公共随机数 。
  2. 他们就要签名的消息  (比如一个交易) 达成一致, 各自生成挑战标量的副本:  。
  3. Alice 生成标量  。 Bob 生成标量  。他们将标量相加得到   。签名是两个值  和  。
  4. 验证者使用常规的方程检查他们的公钥和签名:  。

Alice和Bob已经证明了他们知道自己的私钥的和,且没有任何一个人将自己的私钥透露给对方或其他任何人。该协议可以扩展到任意数量的参与者(例如,一百万个人可以证明他们知道他们的一百万个不同密钥的和)。

上述协议存在多个安全问题。最值得注意的是,一方在确定自己的公钥之前可能会了解其他方的公钥。例如, Alice 诚实地生成她的公钥  并与 Bob 共享。Bob 使用 生成他的公钥。当它们的两个密钥组合在一起时  ,正负  项相互抵消, 因此公钥仅代表  的私钥(即 Bob 的私钥)。现在, Bob可以产生有效的签名, 而无需Alice的任何帮助。这称为密钥抵消攻击。

有多种方法可以解决密钥取消攻击。最简单的方案是要求每个参与者在与所有其他参与者共享有关该密钥的任何内容之前先承诺自己的公钥部分。例如,Alice和Bob各自哈希他们的公钥并彼此共享他们的摘要。当他们都拥有对方的摘要时,他们可以共享密钥。他们分别检查对方的密钥哈希值是否符合先前提供的摘要,然后再正常继续执行协议。这可以防止其中任何一个参与者选择一个公钥来抵消其他参与者的密钥。然而,这种方案很容易无法正确实现,例如通过未强化的 BIP32 公钥派生来简单地使用它。此外,它还为参与者之间的通信增加了一个额外的步骤,这在许多情况下可能是不可接受的。已经提出了更复杂的方案来解决这些缺点。

除了密钥抵消攻击之外,还有许多针对随机数的攻击。回想一下,随机数的目的是防止任何人能够利用他们对签名验证方程中其他值的了解来求解确定你的私钥的值。为了有效地实现这一点,你必须在每次签署不同的消息时使用不同的随机数或更改其他签名参数。不同的随机数不得以任何方式相关。对于多签名,每个参与者都必须遵守这些规则,否则可能会危及其他参与者的安全。此外,还需要防止抵消和其他攻击。实现这些目标的不同协议会做出不同的权衡,因此没有一个多签名协议可以在所有情况下推荐。相反,我们给出 MuSig 协议系列中的三个:

  • MuSig:该协议也称为 MuSig1,在签名过程中需要三轮通信,与我们刚才描述的过程类似。 MuSig1 的最大优点是它的简单性。
  • MuSig2:仅需要两轮通信,有时可以允许其中一轮与密钥交换相结合。这可以显著加快某些协议的签名速度,例如计划在闪电网络中使用的无脚本式多签名。 MuSig2 在 BIP327(截至撰写本文时唯一具有 BIP 的无脚本式多签名协议)中指定。
  • MuSig-DN: DN 代表确定性随机数,它消除了称为重复会话攻击的问题。它不能与密钥交换结合使用,并且实现起来比 MuSig 或 MuSig2 复杂得多。

对于大多数应用来说,MuSig2 是撰写本文时可用的最佳多签名协议。

基于 Schnorr 的无脚本式门限签名

无脚本式多签名协议仅适用于 -of- 签名。拥有作为聚合公钥一部分的部分公钥的每一个人,都必须为最终签名提供部分签名和部分随机数。但有时,参与者希望可以只让其中的一部分进行签名,例如 -of-,即门限 () 个的参与者可以用由  个参与者构造的密钥进行签名。这种类型的签名称为门限签名。

我们在“脚本式多签名”一节中也看到了脚本式门限签名。但正如无脚本式多签名与脚本式多签名相比可以节省空间并提高隐私性一样,无脚本式门限签名与脚本式门限签名相比也可以节省空间并提高隐私性。对于没有参与签名过程的任何人来说,一个无脚本式门限签名看起来就像由单签名用户或通过无脚本式多签名协议创建的任何其他签名一样。

已知有多种用于生成无脚本式门限签名的方法,最简单的一种就是对我们之前看到的创建无脚本式多签名的方法进行轻微修改。该协议还依赖于可验证秘密共享(其本身依赖于安全的秘密共享)。

基本的秘密共享可以通过简单的分割来实现。 Alice 有一个秘密的数,她将其分成三个等长的部分并与 Bob、Carol 和 Dan 共享。这三个人可以按照正确的顺序组合他们收到的部分数(称为份额)来重构出Alice的秘密数。一个更复杂的方案需要Alice向每个份额添加一些附加信息,称为校正码,可以让三人中的任意两人恢复该数字。该方案并不安全,因为每个份额都会让其持有者了解Alice的秘密的部分知识,使得参与者会比没有份额的非参与者更容易猜测Alice的秘密。

安全的秘密共享方案可以防止参与者了解有关秘密的任何信息,除非他们组合了达到最小门限数量的共享。例如,如果 Alice 希望 Bob、Carol 和 Dan 中的任意两人能够重构她的秘密,则她可以设置门限为 2。最著名的安全的秘密共享算法是 Shamir 秘密共享方案,通常缩写为 SSSS。这是以其发现者命名,Shamir也是我们在“Schnorr 签名”中看到的 Fiat-Shamir 转换的发现者之一。

在一些密码学协议中,例如我们正在研究的无脚本式门限签名方案,Bob、Carol 和 Dan 知道 Alice 正确遵循了她这边的协议是至关重要的。他们需要知道她创建的份额都来自同一个秘密,需要知道她确实使用了她声称的门限,并且需要知道她给每个人的份额是不同的。能够完成所有这些要求且仍然是一个安全的秘密共享方案的协议就是一个可验证秘密共享方案。

要了解多签名和可验证秘密共享是如何工作的,想象Alice、Bob 和 Carol 每个人都希望收到可由他们中的任意两个人花费的资金。他们按照“基于 Schnorr 的无脚本式多签名”中的描述进行协作,生成一个常规的多签名公钥来接受资金 (-of-)。接着,每个参与者从他们的私钥中导出两个秘密份额——给其他两个参与者各一个。这些份额可以让其中的任何两人重构出多签名的原始部分私钥。每个参与者将其秘密份额之一分发给其他两个参与者,从而每个参与者存储自己的部分私钥以及每个其他参与者的一份份额。随后,每个参与者都会验证他们收到的份额(和给其他参与者的份额比)的真实性和唯一性。

之后,当(比如)Alice和Bob想要在没有Carol参与的情况下生成无脚本式门限签名时,他们将自己拥有的两份份额交换给Carol。这使他们能够重构Carol的部分私钥。 Alice 和 Bob 也有自己的私钥,于是他们可以使用所有三个必要的密钥来创建无脚本多签名。

换句话说,刚刚描述的无脚本式门限签名方案与无脚本式多签名方案相同,只是门限值数量的参与者有能力重构出不能或不愿签名的任何其他参与者的部分私钥。

这确实指出了在考虑无脚本式门限签名协议时需要注意的一些事项:

  • 无可问责性。由于Alice和Bob重构了Carol的部分私钥,因此由包括Carol的过程产生的无脚本式多签名与不包括Carol的过程产生的无脚本式多签名之间不会有根本区别。即使Alice、Bob或Carol声称他们没有签名,也没有可证明的方法可以证明他们没有帮助生成签名。如果了解群组中的哪些成员进行了签名是很重要的,你将需要使用脚本。
  • 操纵攻击。想象一下Bob告诉Alice说Carol联系不上了,他们共同重构出Carol的部分私钥。然后Bob告诉Carol说Alice联系不上了,他们一起重构出Alice的部分私钥。这时Bob就拥有了自己的部分私钥以及Alice和Carol的部分私钥,他自己就可以花费资金了而无需其他人的参与。如果所有参与者都同意仅使用一种参与者能看到其他所有消息的方案来进行通信(例如,如果 Bob 告诉 Alice说Carol联系不上了 ,Carol 就能够在Alice和Bob开始协作之前看到该消息),则可以解决此攻击。在撰写本文时,其他的解决方案,可能更有鲁棒性的解决方案,正在研究之中。

尽管多个比特币贡献者已经对该主题进行了大量研究,但尚未有无脚本式门限签名协议作为 BIP提出,我们期望在本书出版后会出现经过同行评议的解决方案。

转载声明:本文 由CoinON抓取收录,观点仅代表作者本人,不代表CoinON资讯立场,CoinON不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。若以此作为投资依据,请自行承担全部责任。

声明:图文来源于网络,如有侵权请联系删除

风险提示:投资有风险,入市需谨慎。本资讯不作为投资理财建议。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 2023年12月12日 上午12:45
下一篇 2023年12月12日 下午12:44

相关推荐

速览比特币中的Schnorr签名

星期二 2023-12-12 0:45:12

1989 年,Claus Schnorr 发表了一篇描述后来以他命名的签名算法的论文。该算法并不为比特币和许多其他应用所使用的椭圆曲线密码学(ECC) 所特有,尽管可能与椭圆曲线密码学关系是最密切的。 Schnorr 签名有许多良好的性质:

  • 可证明安全。Schnorr 签名安全性的数学证明仅依赖于解决离散对数问题 (DLP) 的难度,尤其是对比特币所用椭圆曲线 (EC)上的离散对数问题;以及使用哈希函数(如比特币中使用的 SHA256 函数)的能力以产生不可预测的值,称为随机预言模型(ROM)。其他签名算法要么具有额外的依赖,要么需要更大的公钥或签名才能实现与 ECC-Schnorr 同等的安全性(仅当威胁被定义为经典计算机时;其他算法可能会针对量子计算机提供更有效的安全性)。
  • 线性性。Schnorr 签名具有数学家称为线性的性质,适用于具有两个特定性质的函数。第一个性质是将两个或多个变量相加,对该加总运行函数将产生与独立对每个变量运行函数然后将结果相加相同的值,如;这种性质称为加性。第二个性质是,将变量乘以一个量然后在该乘积上运行函数,将产生与在变量上运行函数然后乘以同一个量相同的值,如;该性质称为一次齐次性。
  • 在密码学操作中,某些函数可能是私有的(例如涉及私钥或秘密随机数的函数),因此无论在函数内部还是外部执行操作都能够得到相同结果的性质,使得多方可以在无需分享他们的秘密的同时轻松地协调合作。我们将在“基于 Schnorr 的无脚本式多签名”和“基于 Schnorr 的无脚本式门限签名”中看到 Schnorr 签名中线性性的一些具体好处。
  • 批量验证。当以某种方式(比如比特币中的方式)使用时,Schnorr 线性的一个结果是,相对容易做到同时验证多个 Schnorr 签名,且所需时间比独立验证每个签名所需的时间要短。批量验证的签名越多,速度提升就越大。对于一个区块中的典型签名数量,批量验证它们的时间大约是独立验证每个签名所需时间的一半。

在本章后面,我们将完全按照比特币中使用的方式描述 Schnorr 签名算法,但我们将从它的简化版本开始,分阶段逐步实现实际协议。

Schnorr 签名

Alice 首先选择一个大的随机数 (), 称为她的私钥。她还知道比特币椭圆曲线上的一个公共点, 称为生成元 () 。Alice 使用椭圆曲线乘法将  乘以她的私钥 , 这时  被称为标量, 因为它按比例缩放了  。得到的结果 , 称之为 Alice 的公钥。Alice将她的公钥发给Bob。尽管 Bob 也知道 , 但离散对数问题阻止了 Bob 把  除以  以导出 Alice 的私钥。

之后的某个时刻,Bob 希望 Alice 通过证明她知道 Bob 之前收到的公钥 () 对应的标量  来证明自己的身份。 Alice 不能直接给 Bob ,因为这会让Bob可以向其他人证明他是Alice,所以Alice需要在不向 Bob 透露  的情况下证明她知道 ,这称为零知识证明。下面我们开始介绍 Schnorr 身份识别过程:

  1. Alice 选择另一个大随机数 (), 我们称之为私有随机数。她再次将其作为标量使用,将其乘以  得到 , 称之为公共随机数。向Bob发送公共随机数。
  2. Bob 选择他自己的一个大随机数 , 称之为挑战标量。叫 “挑战” 是因为它用于挑战 Alice 来证明她知道她之前给 Bob 的公钥  的私钥 ; 叫“标量”是因为它稍后将用于乘以一个椭圆曲线点。
  3. Alice 现在有了一些数(标量) 、 和  。她使用公式  将它们组合在一起生成最终标量  。把  发给Bob。
  4. Bob 现在知道标量  和 , 但不知道  或  。然而, Bob 确实知道  和 , 并且他可以自己计算  和 。这意味着他可以去检查 Alice 执行操作的一个缩放后版本的相等性:  。如果相等, 那么Bob就可以确信Alice在生成  时知道  。

一个使用整数而不是椭圆曲线点的 Schnorr 身份识别协议:

通过使用简单整数而不是椭圆曲线上的点来替换前面提到的每个值(包括 )来构造一个不安全的过度简化版本,可能会更容易去理解交互式 Schnorr 身份识别协议。例如,我们将使用3 作为一开始的素数:

设置: Alice 选择  作为她的私钥。她将其乘以生成元 , 得到她的公钥 。她给Bob 发送 15 。

  1. Alice 选择私有随机数  并生成公共随机数  。她给 Bob发送 35。
  2. Bob 选择  并将其发给 Alice。
  3. Alice 生成  。她给 Bob 发送40 。
  4. Bob 导出  和  。然后他验证  。注意, 这里与 Alice 执行的操作相同, 但所有值都已按比例放大了5倍(的值)。

当然,这是一个过于简化的例子。当处理简单整数时,我们可以将乘积除以生成元  从而得到底层的标量,这是不安全的。这就是为什么比特币中使用的椭圆曲线密码学的一个关键性质就是做乘法很容易,但除以曲线上的点实际上是不可能的。此外,对于这么小的数字,通过穷举找到底层的值(或其他有效值)会很容易;比特币中使用的数要大得多。

讨论一下交互式 Schnorr 身份识别协议的一些使其安全的性质:

  • 随机数 ()。在步骤 1 中, Alice 选择一个 Bob 不知道也无法猜测的数字, 并给了他该数字的缩放形式  。此时, Bob 也已经拥有了她的公钥 ( , 这是她私钥  的缩放形式。这意味着当 Bob 计算最终方程  时, Bob 不知道两个独立的变量  和  。可以使用简单代数来求解包含一个未知变量的方程,但不能求解包含两个独立未知变量的方程, 因此 Alice 的随机数的存在可以阻止 Bob 导出她的私钥。值得注意的是, 这种保护依赖于随机数以任何方式都不可猜测。如果Alice的随机数有任何可预测的地方, Bob就可能利用它来计算出Alice的私钥。
  • 挑战标量()。Bob等待接收Alice的公共随机数, 然后继续执行步骤 2 , 给Alice一个她之前不知道且无法猜到的数 (挑战标量) 。非常关键的是, Bob要仅在Alice承诺公开随机数后才给她挑战标量。想象一下一个不知道  的人想冒充 Alice, 而 Bob 在收到承诺公共随机数  之前就不小心给了这个人挑战标量 , 会发生什么。冒充者就可以更改 Bob 将用于验证的等式  两边的参数; 具体来说, 可以改变  和  。考虑该表达式的简化形式:  。如果你可以同时更改  和 , 那你就可以用  消掉  (Kurt Pan注:y=x-a)。你为  选择的任何值现在都将满足方程。对于实际的方程, 冒充者只需选择一个随机数为  , 生成 , 然后使用椭圆曲线减法来选择等于  的  。把计算出的 给Bob, 随后给Bob随机的 , Bob会认为这是有效的, 因为  。这解释了为什么协议中的操作顺序至关重要: Bob 必须只在 Alice 承诺了她的公共随机数之后再向 Alice 提供挑战标量。

这里描述的交互式身份识别协议与 Claus Schnorr 的部分原始描述相匹配,但缺少去中心化比特币网络所需的两个必要性质。第一,依赖于Bob等待Alice承诺她的公共随机数,之后Bob再给她一个随机挑战标量。在比特币中,每笔交易的花费者都需要经过数千个比特币全节点的认证,包括尚未启动但其运行者有一天想要确保他们收到的比特币确实来自每个交易都有效的转账链的未来节点。今天或将来任何无法与 Alice 通信的比特币节点都将无法认证她的交易,且将与认证该交易的所有其他节点产生分歧。对于像比特币这样的共识系统来说,这是不可接受的。为了让比特币正常运作,我们需要一个不需要 Alice 和每个想要认证她身份的节点之间进行交互的协议。

一种简单的技术(以其发现者命名的 Fiat-Shamir 转换)可以将 Schnorr 交互式身份识别协议转变为非交互式数字签名方案。回想一下步骤 1 和 2 的重要性——包括按顺序执行它们的重要性。 Alice 必须承诺一个不可预测的随机数;Bob必须在收到Alice的承诺后才给她一个不可预测的挑战标量。再回想一下安全密码学哈希函数的性质:当给定相同的输入时,它将始终产生相同的输出,但当给定不同的输入时,它将产生与随机数据无法区分的值。

这就使得 Alice 可以选择她的私有随机数, 导出她的公共随机数, 然后对公共随机数进行哈希以获得挑战标量。因为 Alice 无法预测哈希函数的输出(挑战), 并且对于相同的输入 (随机数) 输出总是相同的, 所以这确保了Alice获得了一个随机挑战, 即使是她自己选择随机数并对其进行哈希运算的。我们不再需要来自Bob的交互。Alice只需发布她的公共随机数  和标量 , 数千个全节点(过去和未来的)中的每一个都可以对  进行哈希运算以生成 , 从而生成 , 然后验证  。明确写出来的话, 验证方程变为了  。

我们还需要一件事来完成将交互式 Schnorr 身份识别协议转换为对比特币有用的数字签名协议。我们不仅希望 Alice 证明她知道她的私钥;还想让她有能力对一个消息进行承诺。具体来说,我们希望她承诺与她想要发送的比特币交易相关的数据。有Fiat-Shamir 转换在这里,我们已经有了一个承诺,因此可以简单地让它额外去承诺消息。我们现在使用  也承诺消息 ,而不是 ,其中 ||代表串联。

我们现在已经定义出了 Schnorr 签名协议的一个版本,但我们还需要做一件事来解决一个比特币特定的问题。在 BIP32 密钥派生中,未强化派生的算法给定公钥并向其添加一个非秘密值以生成派生公钥。这意味着还可以将该非秘密值添加到用一个密钥的有效签名中,以生成用相关密钥的签名。该相关签名是有效的,但未经拥有私钥的人授权,这是一个重大的安全故障。为保护 BIP32 未强化的派生并支持人们想要在 Schnorr 签名之上构建的多种协议,比特币版本的 Schnorr 签名(称为 secp256k1上的BIP340 Schnorr 签名)除了对公共随机数和消息承诺之外还承诺所使用的公钥。这使得完整的承诺为。

现在我们已经描述了 BIP340 Schnorr 签名算法的每个部分并解释了它们的作用,我们可以定义协议了。整数相乘以模  进行,表示运算结果需要除以数字 (定义在secp256k1 标准中)并使用余数。数字  非常大,但如果它是 3 且运算结果是 5的话,那么我们实际使用的数字是 2(即 5 除以 3 余数为 2)。

设置: Alice 选择一个大随机数 () 作为她的私钥(直接选择或使用 BIP32 等协议从大的随机种子值确定性地生成私钥)。她使用 secp256k1 中定义的参数将生成元  乘以她的标量 , 生成  (她的公钥)。她将她的公钥提供给随后会认证她的比特币交易的每个人(例如, 通过将  包含在交易输出中)。当她准备好支出时, 她就开始生成她的签名:

  1. Alice 选择一个大的私有随机数  并导出公共随机数  。
  2. Alice选择她的消息  (例如,交易数据)并生成挑战标量  。
  3. Alice 生成标量  。  和  这两个值是她的签名。她将此签名提供给每个想要验证该签名的人; 她还需要确保每个人都能收到她的消息。在比特币中, 这是通过将她的签名包含在她的支出交易的见证结构中, 然后将该交易转发到全节点来完成的。
  4. 验证者(例如全节点)使用  导出 , 然后验证   。如果等式有效, 则 Alice 证明了她知道自己的私钥  (无需泄露之) 且承诺了消息 (包含交易数据)。

Schnorr 签名的序列化

一个Schnorr 签名由两个值组成: 和 。  值是比特币的椭圆曲线(称为 secp256k1)上的一个点,通常由两个 32 字节的坐标表示,(x, y)。但因为只需要 x 坐标即可,因此仅包含该值。当你在比特币的 Schnorr 签名中看到  时请注意,它只是该点的 x 坐标。

值  是一个标量(用于与其他数字相乘的数)。对于比特币的 secp256k1 曲线,其长度永远不会超过 32 字节。

虽然  和  有时可以是用少于 32 字节表示的值,但不太可能会比 32 字节小太多,因此它们会被序列化为两个 32 字节的值(小于 32 字节的值会有前导零)。按照先  然后  的顺序序列化,正好产生 64 个字节。

Taproot软分叉(也称为 v1 segwit)将 Schnorr 签名引入了比特币,并且是截至撰写本文时在比特币中使用它们的唯一方式。当与 taproot 密钥路径或脚本路径支出一起使用时,64 字节 Schnorr 签名被视为使用默认签名哈希 (sighash),即 SIGHASH_ALL 。如果使用替代的签名哈希,或者支出者想要浪费空间以显式指定 SIGHASH_ALL ,则会将一个指定签名哈希的附加字节附加到签名上,使签名为 65 字节。

正如我们将看到的,64 或 65 字节都比“ECDSA 签名序列化 (DER)”中会描述的用于 ECDSA 签名的序列化要高效得多。

基于 Schnorr 的无脚本式多签名

在上述单签名 Schnorr 协议中,Alice 使用签名 来公开证明她知道她的私钥,本例中称为 。想象如果 Bob 也有一个私钥 (),他想与 Alice 一起证明他们知道 ,且无需向对方或其他任何人透露他们的私钥。我们再来过一遍 BIP340 Schnorr 签名协议。

警告:我们将要描述的简化协议并不安全,原因将很快解释。在描述被认为是安全的相关协议之前,我们仅使用它来展示 Schnorr 多签名的机制。

Alice 和 Bob 需要导出  的公钥, 即  。由于可以使用椭圆曲线运算将两个椭圆曲线点相加, 因此首先 Alice 导出 , Bob导出  。然后他们将其加在一起以创建  。点  就是他们的聚合公钥。为了创建签名, 他们开始运行简单的多签名协议如下:

  1. 他们各自选择一个大私有随机数,Alice 选择, Bob 选择。他们还各自导出相应的公共随机数  和 。 共同生成一个聚合公共随机数 。
  2. 他们就要签名的消息  (比如一个交易) 达成一致, 各自生成挑战标量的副本:  。
  3. Alice 生成标量  。 Bob 生成标量  。他们将标量相加得到   。签名是两个值  和  。
  4. 验证者使用常规的方程检查他们的公钥和签名:  。

Alice和Bob已经证明了他们知道自己的私钥的和,且没有任何一个人将自己的私钥透露给对方或其他任何人。该协议可以扩展到任意数量的参与者(例如,一百万个人可以证明他们知道他们的一百万个不同密钥的和)。

上述协议存在多个安全问题。最值得注意的是,一方在确定自己的公钥之前可能会了解其他方的公钥。例如, Alice 诚实地生成她的公钥  并与 Bob 共享。Bob 使用 生成他的公钥。当它们的两个密钥组合在一起时  ,正负  项相互抵消, 因此公钥仅代表  的私钥(即 Bob 的私钥)。现在, Bob可以产生有效的签名, 而无需Alice的任何帮助。这称为密钥抵消攻击。

有多种方法可以解决密钥取消攻击。最简单的方案是要求每个参与者在与所有其他参与者共享有关该密钥的任何内容之前先承诺自己的公钥部分。例如,Alice和Bob各自哈希他们的公钥并彼此共享他们的摘要。当他们都拥有对方的摘要时,他们可以共享密钥。他们分别检查对方的密钥哈希值是否符合先前提供的摘要,然后再正常继续执行协议。这可以防止其中任何一个参与者选择一个公钥来抵消其他参与者的密钥。然而,这种方案很容易无法正确实现,例如通过未强化的 BIP32 公钥派生来简单地使用它。此外,它还为参与者之间的通信增加了一个额外的步骤,这在许多情况下可能是不可接受的。已经提出了更复杂的方案来解决这些缺点。

除了密钥抵消攻击之外,还有许多针对随机数的攻击。回想一下,随机数的目的是防止任何人能够利用他们对签名验证方程中其他值的了解来求解确定你的私钥的值。为了有效地实现这一点,你必须在每次签署不同的消息时使用不同的随机数或更改其他签名参数。不同的随机数不得以任何方式相关。对于多签名,每个参与者都必须遵守这些规则,否则可能会危及其他参与者的安全。此外,还需要防止抵消和其他攻击。实现这些目标的不同协议会做出不同的权衡,因此没有一个多签名协议可以在所有情况下推荐。相反,我们给出 MuSig 协议系列中的三个:

  • MuSig:该协议也称为 MuSig1,在签名过程中需要三轮通信,与我们刚才描述的过程类似。 MuSig1 的最大优点是它的简单性。
  • MuSig2:仅需要两轮通信,有时可以允许其中一轮与密钥交换相结合。这可以显著加快某些协议的签名速度,例如计划在闪电网络中使用的无脚本式多签名。 MuSig2 在 BIP327(截至撰写本文时唯一具有 BIP 的无脚本式多签名协议)中指定。
  • MuSig-DN: DN 代表确定性随机数,它消除了称为重复会话攻击的问题。它不能与密钥交换结合使用,并且实现起来比 MuSig 或 MuSig2 复杂得多。

对于大多数应用来说,MuSig2 是撰写本文时可用的最佳多签名协议。

基于 Schnorr 的无脚本式门限签名

无脚本式多签名协议仅适用于 -of- 签名。拥有作为聚合公钥一部分的部分公钥的每一个人,都必须为最终签名提供部分签名和部分随机数。但有时,参与者希望可以只让其中的一部分进行签名,例如 -of-,即门限 () 个的参与者可以用由  个参与者构造的密钥进行签名。这种类型的签名称为门限签名。

我们在“脚本式多签名”一节中也看到了脚本式门限签名。但正如无脚本式多签名与脚本式多签名相比可以节省空间并提高隐私性一样,无脚本式门限签名与脚本式门限签名相比也可以节省空间并提高隐私性。对于没有参与签名过程的任何人来说,一个无脚本式门限签名看起来就像由单签名用户或通过无脚本式多签名协议创建的任何其他签名一样。

已知有多种用于生成无脚本式门限签名的方法,最简单的一种就是对我们之前看到的创建无脚本式多签名的方法进行轻微修改。该协议还依赖于可验证秘密共享(其本身依赖于安全的秘密共享)。

基本的秘密共享可以通过简单的分割来实现。 Alice 有一个秘密的数,她将其分成三个等长的部分并与 Bob、Carol 和 Dan 共享。这三个人可以按照正确的顺序组合他们收到的部分数(称为份额)来重构出Alice的秘密数。一个更复杂的方案需要Alice向每个份额添加一些附加信息,称为校正码,可以让三人中的任意两人恢复该数字。该方案并不安全,因为每个份额都会让其持有者了解Alice的秘密的部分知识,使得参与者会比没有份额的非参与者更容易猜测Alice的秘密。

安全的秘密共享方案可以防止参与者了解有关秘密的任何信息,除非他们组合了达到最小门限数量的共享。例如,如果 Alice 希望 Bob、Carol 和 Dan 中的任意两人能够重构她的秘密,则她可以设置门限为 2。最著名的安全的秘密共享算法是 Shamir 秘密共享方案,通常缩写为 SSSS。这是以其发现者命名,Shamir也是我们在“Schnorr 签名”中看到的 Fiat-Shamir 转换的发现者之一。

在一些密码学协议中,例如我们正在研究的无脚本式门限签名方案,Bob、Carol 和 Dan 知道 Alice 正确遵循了她这边的协议是至关重要的。他们需要知道她创建的份额都来自同一个秘密,需要知道她确实使用了她声称的门限,并且需要知道她给每个人的份额是不同的。能够完成所有这些要求且仍然是一个安全的秘密共享方案的协议就是一个可验证秘密共享方案。

要了解多签名和可验证秘密共享是如何工作的,想象Alice、Bob 和 Carol 每个人都希望收到可由他们中的任意两个人花费的资金。他们按照“基于 Schnorr 的无脚本式多签名”中的描述进行协作,生成一个常规的多签名公钥来接受资金 (-of-)。接着,每个参与者从他们的私钥中导出两个秘密份额——给其他两个参与者各一个。这些份额可以让其中的任何两人重构出多签名的原始部分私钥。每个参与者将其秘密份额之一分发给其他两个参与者,从而每个参与者存储自己的部分私钥以及每个其他参与者的一份份额。随后,每个参与者都会验证他们收到的份额(和给其他参与者的份额比)的真实性和唯一性。

之后,当(比如)Alice和Bob想要在没有Carol参与的情况下生成无脚本式门限签名时,他们将自己拥有的两份份额交换给Carol。这使他们能够重构Carol的部分私钥。 Alice 和 Bob 也有自己的私钥,于是他们可以使用所有三个必要的密钥来创建无脚本多签名。

换句话说,刚刚描述的无脚本式门限签名方案与无脚本式多签名方案相同,只是门限值数量的参与者有能力重构出不能或不愿签名的任何其他参与者的部分私钥。

这确实指出了在考虑无脚本式门限签名协议时需要注意的一些事项:

  • 无可问责性。由于Alice和Bob重构了Carol的部分私钥,因此由包括Carol的过程产生的无脚本式多签名与不包括Carol的过程产生的无脚本式多签名之间不会有根本区别。即使Alice、Bob或Carol声称他们没有签名,也没有可证明的方法可以证明他们没有帮助生成签名。如果了解群组中的哪些成员进行了签名是很重要的,你将需要使用脚本。
  • 操纵攻击。想象一下Bob告诉Alice说Carol联系不上了,他们共同重构出Carol的部分私钥。然后Bob告诉Carol说Alice联系不上了,他们一起重构出Alice的部分私钥。这时Bob就拥有了自己的部分私钥以及Alice和Carol的部分私钥,他自己就可以花费资金了而无需其他人的参与。如果所有参与者都同意仅使用一种参与者能看到其他所有消息的方案来进行通信(例如,如果 Bob 告诉 Alice说Carol联系不上了 ,Carol 就能够在Alice和Bob开始协作之前看到该消息),则可以解决此攻击。在撰写本文时,其他的解决方案,可能更有鲁棒性的解决方案,正在研究之中。

尽管多个比特币贡献者已经对该主题进行了大量研究,但尚未有无脚本式门限签名协议作为 BIP提出,我们期望在本书出版后会出现经过同行评议的解决方案。