https://popeller.io/schnorr-basics
如果你在思考 Schnorr 签名时遇到困难,那么你并不孤单。在这篇文章中,我尝试在我自己能理解的水平上解释 Schnorr 签名,希望你也会发现它的价值。
Schnorr 是比特币中的一种新签名方案,它在Taproot升级中被激活。BIP340 中列出了Schnorr 一些不错的性质 ,我不在这里赘述。
https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki#motivation
签名方案由两个操作组成,签名和验证,如下图所示:

签名者拥有私钥和要签名的消息(例如,比特币交易或猫图),并生成签名。验证者拥有与签名者使用的私钥相对应的公钥、消息和签名。验证过程在不知道私钥的情况下确保签名是使用正确的私钥创建的。
如果你想要更深入的解释,请访问Grokking Bitcoin 第 2 章的后半部分
https://rosenbaum.se/book/grokking-bitcoin-2.html#_digital_signatures
我们现在来看 Schnorr 签名是如何创建的,即上图的左侧。我假设你熟悉如何使用随机数生成器和椭圆曲线创建密钥对。如果没有,我建议你阅读 Grokking Bitcoin 的第 4.8 节。
https://rosenbaum.se/book/grokking-bitcoin-4.html#public-key-math
假设你要给一张猫图签名,猫图就是要签名的消息,你的属于你的公钥的私钥是。
你要做的第一件事是抽取一个随机数,我们将称之为nonce(“只用一次的数字”的意思)。接着你就把当作是一个私钥,这意味着你可以通过乘以来生成相应的公钥(是生成元点)。在此阶段,你有的东西如下:
是nonce的承诺,它将成为最终签名的第一部分。则必须保密并且永远不会被重复使用。你已准备好签名所需的一切。签名将分两步完成。第一步是计算一个所谓的挑战哈希:
挑战哈希是对挑战进行哈希,其中挑战是的串联。这几个部分都将供验证者使用。使用挑战哈希,你现在可以进行第 2 步:计算挑战应答,这是签名的第二部分:
最终你生成的签名是:
你把猫图,还有你的签名 一起发给你的朋友Fred。
Fred 想确保猫图片在传输过程中没有受到损坏,以及确保它确实是来自与你,即唯一可以访问你的私钥的人。他可以访问,当然也可以访问这个广为人知的常数。根据这些信息可以计算挑战哈希并验证验证方程是否成立:
如果这个等式成立,Fred 可以确定签名是用生成的. 可以看到如果给上述应答方程两边同乘以,我们就可以得到验证方程:
如你所见:如果应答方程成立,则验证方程成立。同样,如果验证方程成立,则响应方程也成立。因此,当 Fred 基于椭圆曲线上的点验证验证方程成立时,他也隐含地验证了基于标量的应答方程成立。
当 Fred 验证了签名后,他就可以欣赏这张猫的照片了,并完全相信这张图实际上与你发送给他的照片是相同的。
你可能想知道为什么 nonce 必须保密。你甚至可能想知道为什么会需要这个 ?我们从后者开始,如果从签名过程中删除,看看会发生什么。
你将按如下方式创建签名:
签名将只包括 . Fred 将验证你的签名通过验证如下等式成立:
这个等式是成立的。但是,因为Fred知道和,他可以通过应答方程提取出私钥:
好吧,我们确实需要 nonce 来防止 Fred 得到你的私钥。但是为什么我们必须对 nonce 保密呢?为什么要很麻烦地去使用 nonce 承诺而不是 nonce 本身呢?
这是出于同样的原因。假设Fred得到了nonce ,那么他可以弄通过如下方式得到:
所以Fred可以通过从里减掉再除以的方式来计算出。
通过只给Fred展现 nonce 承诺,我们确保 Fred 无法计算出 , 同时允许他验证确实被用于签名的生成。
即使对 nonce 保密,如果你对同一个私钥使用两次 nonce,仍然可能会泄露你的私钥。假设你使用相同的nonce和私钥进行两个签名,如下所示:
你把签名 和 给验证者。验证者就可以使用简单算术来计算出你的私钥了!他可以建立一个有两个方程和两个未知数的方程组如下:
两个方程相减是可以得到的:
如你所见,验证者将能够提取私钥。学到的经验教训:不要重复使用nonce!
如果 nonce 被重用,但是对于不同的私钥和的,上述的方程组将不可解,因为你有三个未知数,, 和 ,但只有两个方程。
挑战哈希 是挑战的哈希. 为什么要使用这个特殊的挑战呢?我们分别看一下这三个部分。
要签名的消息是 ,所以以某种方式由签名得到承诺当然是重要的。如果从挑战中去掉,“签名”将对任何消息都有效。
为了确保除了私钥的所有者之外没有人可以创建签名,挑战必须包含 nonce 承诺 。假设挑战不包括 nonce 承诺,那么任何有权访问公钥的人都可以轻松伪造签名。他们可以使用任意的并做如下操作:
最后一个方程是为了解的所谓“验证方程”。注意到方程右侧只包含已知量和 ,因此签名是有效的。
如果把包含在挑战中,使得 是挑战的一部分,就不可能解关于的验证方程了,因为很难找到一个 使得 。
我们最后来看看在挑战中做些什么。假设在挑战中没有,,是对公钥和消息的有效签名。那么对于任意数,签名将是对于公钥和消息的有效签名。我们看看为什么:
这称为相关密钥攻击。如果你熟悉BIP32 中的扩展公钥派生的工作原理,你可能会看到潜在的危险。这里是一般的想法:

这意味着,如果攻击者知道父扩展公钥 (xpub) 和子密钥的有效签名,则攻击者可以使用此技巧来为父 xpub 以及可以派生的任何子xpub 伪造签名。这不仅仅是 BIP32 的问题,也是许多以某种方式使用公钥添加的方案的问题,例如 Taproot(BIP341)。更多详细信息请查看 BIP340 的设计部分。
https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki#Design
在下一篇文章中,我将展示如何在多重签名场景中使用 Schnorr 签名来生成看起来像普通单个签名的签名。这在比特币中非常实用,因为它减少了验证区块链的资源需求。
最后加一个Google翻译的梗来作为这篇关于签名文章的meta-签名:
电子 = H(电阻|磷|米) ;秒 = 电阻 + 电子磷