该文档提出了一个基于椭圆曲线 secp256k1 的 64 字节 Schnorr 签名标准,详细阐述了 Schnorr 签名的设计、规范、公钥生成、签名、验证以及批量验证过程,并探讨了其在多重签名、适配器签名和盲签名等方面的应用,旨在替代比特币当前使用的 ECDSA 签名方案,提升安全性和效率, 并且提供了测试向量和参考代码。
forked from bitcoin/bips
bip-anyprevout
搜索此仓库
/
复制路径
Blame更多文件操作
Blame更多文件操作
打开提交详情
2021年5月17日
255b5b6 · 2021年5月17日
打开提交详情
251 行 (180 loc) · 34.5 KB
/
顶部
预览
代码
Blame
251 行 (180 loc) · 34.5 KB
复制原始文件
下载原始文件
目录
编辑和原始操作
BIP: 340
Title: secp256k1 的 Schnorr 签名
Author: Pieter Wuille <pieter.wuille@gmail.com>
Jonas Nick <jonasd.nick@gmail.com>
Tim Ruffing <crypto@timruffing.de>
Comments-Summary: 暂无评论。
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0340
Status: 草案
Type: 标准跟踪
License: BSD-2-Clause
Created: 2020-01-19
Post-History: 2018-07-06: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-July/016203.html [bitcoin-dev] Schnorr signatures BIP
## 目录<br>固定链接:目录<br>- 简介 <br> - 摘要<br> - 版权<br> - 动机<br>- 描述 <br> - 设计<br> - 规范 <br> - 公钥生成<br> - 公钥转换<br> - 默认签名<br> - 备选签名<br> - 验证<br> - 批量验证<br>- 应用 <br> - 多重签名和阈值签名<br> - 适配器签名<br> - 盲签名<br>- 测试向量和参考代码<br>- 脚注<br>- 致谢 |
本文档提出了一个标准,用于在椭圆曲线 secp256k1 上的 64 字节 Schnorr 签名。
本文档基于 2-clause BSD 许可。
传统上,比特币使用 ECDSA 签名,基于 secp256k1 曲线 并使用 SHA256 哈希来验证交易。这些是 标准化的,但与在同一曲线上使用 Schnorr 签名 相比,存在许多缺点:
对于所有这些优点,实际上没有任何缺点,除了未标准化。本文档旨在改变这一点。当我们提出新的标准时,可以进行许多不特定于 Schnorr 签名的改进:
通过重用比特币用于 ECDSA 的相同曲线和哈希函数,我们能够保留用于选择密钥和公钥的现有机制,并且避免引入关于椭圆曲线和哈希函数安全性的新假设。
我们首先通过研究设计选择来构建签名方案的代数公式。之后,我们指定确切的编码和操作。
Schnorr 签名变体 消息 m 和公钥 P 的椭圆曲线 Schnorr 签名通常涉及点 R、由签名者选择的整数 e 和 s,以及满足 e = hash(R || m) 和 s⋅G = R + e⋅P 的基点 G。存在两种公式,具体取决于签名者是显示 e 还是 R:
由于我们希望避免短哈希带来的脆弱性,因此 e 变体不提供明显的优势。我们选择支持批量验证的 R 选项。
密钥前缀 直接使用上面的验证规则会使 Schnorr 签名容易受到“相关密钥攻击”,在这种攻击中,第三方可以将公钥 P 的签名 (R, s) 转换为公钥 P + a⋅G 的签名 (R, s + a⋅hash(R || m)) 和相同的消息 m,对于签名密钥的任何给定加法调整 a。当使用 BIP32 的未硬化派生 和其他依赖于对现有密钥进行加法调整的方法(例如 Taproot)生成密钥时,这将使签名不安全。
为了防止这些攻击,我们选择密钥前缀[ 5] Schnorr 签名,这意味着公钥在前缀哈希输入中的消息。这将等式更改为 s⋅G = R + hash(R || P || m)⋅P。 可以证明 密钥前缀可以防止使用加法调整的相关密钥攻击。通常,密钥前缀增加了多用户设置的健壮性,例如,它似乎是证明 MuSig 多重签名方案安全的要求(请参阅下面的“应用”)。
我们注意到,密钥前缀对于目前在比特币中使用的交易签名并非绝对必要,因为已签名交易间接提交给公钥,即 m 包含对 pk 的承诺。但是,不应依赖此间接承诺,因为它可能会因 SIGHASH_NOINPUT 等提案而发生变化(BIP118),并且会使签名方案不适用于签名交易以外的目的,例如 签名普通消息。
编码 R 和公钥点 P 存在几种编码椭圆曲线点的可能性:
对于验证来说,使用第一个选项效率会稍高一些(大约 10%),但我们优先考虑紧凑性,因此选择选项 3。
隐式 Y 坐标 为了支持有效的验证和批量验证,P 和 R 的 Y 坐标不能是模棱两可的(每个有效的 X 坐标都有两个可能的 Y 坐标)。我们可以选择几种对称性破坏的选项:
第二个选项与现有的密钥生成系统具有最大的兼容性,在现有密钥生成系统中,标准的 33 字节压缩公钥格式由指示 Y 坐标奇偶性的字节加上完整的 X 坐标组成。为了避免不必要的不兼容,我们为 P 选择该选项,因此我们的仅 X 公钥等效于以字节 0x02 为前缀的仅 X 密钥的压缩公钥。为了保持一致性,对 R 也这样做[ 7]。
尽管将有效公钥集的大小减半,但隐式 Y 坐标并不会降低安全性。非正式地,如果存在一种快速算法来计算机仅 X 公钥的离散对数,则它也可以用于计算完整公钥的离散对数:将其应用于 X 坐标,然后有选择地对结果取反。这表明,破解仅 X 公钥最多比破解完整公钥快一个小常数项。[ 8]。
标记哈希 密码哈希函数通常用于以下规范和比特币中用于多种目的。为了确保在一个上下文中使用的哈希不能在另一个上下文中被重新解释,可以使用依赖于上下文的标记名称来调整哈希函数,从而可以假设跨上下文的冲突是不可行的。显然,不能完全排除此类冲突,而只能排除使用带有唯一名称的标记的方案。至于其他方案,使用标记的冲突至少不如没有标记的冲突的可能性小。
例如,如果没有标记的哈希,BIP340 签名对于签名方案也可能有效,其中唯一的区别是哈希函数的参数被重新排序。更糟糕的是,如果 BIP340 随机数派生函数被复制或独立创建,则随机数可能会在另一个方案中被意外重用,从而泄露密钥。
该提案建议通过将哈希数据加前缀 SHA256(tag) || SHA256(tag) 来包含标签。因为这是一个 64 字节长的特定于上下文的常量,并且 SHA256 块大小也是 64 字节,所以可以进行优化实现(与 SHA256 本身相同,但初始状态已修改)。对于不选择使用优化的实现,使用标记名称本身的 SHA256 是相当简单和高效的。
最终方案 因此,我们的最终方案最终使用公钥 pk,它是曲线上一个点 P 的 X 坐标,该曲线的 Y 坐标是偶数,签名是 (r,s),其中 r 是一个点 R 的 X 坐标,该点的 Y 坐标是偶数。签名满足 s⋅G = R + tagged_hash(r || pk || m)⋅P。
使用以下约定,常量定义为 secp256k1。我们注意到,将此规范调整为其他椭圆曲线并非易事,并且可能导致不安全的方案[ 9]。
输入:
算法 PubKey(sk) 定义为:
请注意,我们使用的公钥格式(32 字节)与现有系统使用的格式(通常使用椭圆曲线点作为公钥,或它们的 33 字节或 65 字节编码)非常不同。副作用是 PubKey(sk) = PubKey(bytes(n - int(sk)),因此每个公钥都有两个对应的密钥。
作为随机生成密钥的替代方法,以兼容的方式重新利用现有的 ECDSA 密钥生成算法也是可能的并且安全的。由此类算法构建的密钥可以直接用作 sk。由此类算法构建的公钥(假设它们使用 33 字节的压缩编码)需要通过删除第一个字节来转换。具体而言,BIP32 和构建在其上的方案仍然可用。
输入:
算法 Sign(sk, m) 定义为:
辅助随机数据应设置为在签名时生成的新鲜随机性,从而产生所谓的合成随机数。使用 32 字节的随机性是最佳的。如果获取随机性的成本很高,则可以用 16 个空字节填充 16 个随机字节以获得 32 字节的数组。如果在签名时根本没有随机性,则可以使用一个简单的计数器,该计数器足够宽,在实践中不会重复(例如,64 位或更宽),并用空字节填充到 32 字节的数组,或者甚至可以使用带有 32 个空字节的常量数组。使用任何非重复值都会增加对 故障注入攻击 的防护。使用不可预测的随机性还会增加对其他侧信道攻击的防护,并且建议在可用时使用。请注意,虽然这意味着生成的随机数不是确定性的,但随机性仅是对安全性的补充。正常的安全属性(不包括侧信道攻击)不依赖于签名时 RNG 的质量。
应该注意的是,各种备选签名算法可用于生成同样有效的签名。可以以其他方式生成 32 字节的 rand 值,从而产生不同的但仍然有效的签名(换句话说,这不是_唯一的_签名方案)。无论使用哪种方法生成 rand 值,该值都必须是一个新鲜的均匀随机的 32 字节字符串,即使对于攻击者而言,它也不是部分可预测的。 对于没有随机性的随机数,这意味着不得在另一个上下文中显示相同的输入。这可以通过不在不同的签名方案中重用相同的密钥来最可靠地完成。例如,如果 rand 值是按照 RFC6979 计算的,并且相同的密钥在确定性 ECDSA 中与 RFC6979 一起使用,则签名可能会通过随机数重用来泄露密钥。
随机数泄露防护 可以使用第二个设备来加强随机数生成算法。在这种情况下,第二个设备会贡献随机性,实际签名者可以证明该随机性已融入到其随机数中。这可以防止某些攻击,在这种攻击中,签名者设备受到入侵并故意尝试通过其随机数选择来泄露密钥。
多重签名 此签名方案与各种类型的多重签名和阈值方案兼容,例如 MuSig,其中单个公钥需要多个密钥的持有者参与签名(请参阅下面的“应用”)。\ 重要的是要注意,一般来说,多重签名方案对于上述默认签名算法的 rand 生成(或任何其他确定性方法)是不安全的。
预计算的公钥数据 对于许多用途,可能已经知道与密钥对应的公钥的压缩 33 字节编码,从而可以轻松地评估 has_even_y(P) 和 bytes(P)。因此,让签名者直接提供这些数据可能比从密钥重新计算- 公钥 pk: 一个 32 字节的数组
算法 Verify(pk, m, sig) 定义如下:
对于每个有效的私钥 sk 和消息 m,Verify(PubKey(sk),m,Sign(sk,m)) 将会成功。
请注意,验证的正确性依赖于 lift_x 总是返回一个具有偶数 Y 坐标的点的这个事实。一个假想的验证算法将点作为公钥对待,并直接将点 P 作为输入,那么在使用具有奇数 Y 的点时将会失败。虽然可以通过在进一步处理之前对具有奇数 Y 坐标的点进行取反来纠正此问题,但这将导致每个 (消息,签名) 对对于两个公钥都有效 (一种也存在于 ECDSA 中的可延展性,但我们不希望保留)。我们通过仅将 X 坐标作为公钥来避免这些问题。
输入:
算法 BatchVerify(pk1..u, m1..u, sig1..u) 定义如下:
如果所有单个签名都有效 (即,对于它们,Verify 将返回成功),则 BatchVerify 将始终返回成功。如果至少一个签名无效,则 BatchVerify 将以至多可忽略的概率返回成功。
除了简单的签名之外,还有几个有趣的应用。 虽然最近的学术论文声称它们也可以通过 ECDSA 实现,但对 Schnorr 签名验证的共识支持将大大简化构建。
通过诸如 MuSig 之类的交互式方案,参与者可以将其公钥聚合为单个公钥,他们可以共同签名。这允许 n-of-n 多重签名,从验证者的角度来看,这与普通签名没有什么不同,与 CHECKMULTISIG 或其他方式相比,提高了隐私和效率。
此外,Schnorr 签名与 分布式密钥生成 兼容,这使得交互式阈值签名方案成为可能,例如,Stinson 和 Strobl (2001) 或 Gennaro, Jarecki 和 Krawczyk (2003) 描述的方案。这些协议可以实现 k-of-n 阈值签名,从而确保 n 个签名者的集合中的任何大小为 k 的子集都可以签名,但小于 k 的子集无法生成有效的 Schnorr 签名。但是,现有方案的实用性受到限制:文献中的大多数方案仅在 k-1 < n/2 的情况下才被证明是安全的,在多个会话中同时使用时不安全,或者需要可靠的广播机制才能安全。需要进一步的研究来改善这种情况。
适配器签名 可以由签名者通过用一个已知的点 T = t⋅G 偏移他的公钥nonce R 来生成,但不偏移签名的 s 值。 具有相同 nonce 的相同消息上的正确签名 (或部分签名,因为多重签名中的单个签名者的贡献被称为部分签名) 然后将等于由 t 偏移的适配器签名,这意味着学习 t 等同于学习正确的签名。 这可以用于启用原子交换,甚至 通用支付通道,其中不相交交易的原子性通过签名本身而不是比特币脚本支持来保证。 所得交易对于验证者而言与普通的单签名者交易没有什么不同,除了可能包含锁定时间退款逻辑。
适配器签名,除了将脚本语义编码为恒定大小的签名所带来的效率和隐私优势外,还比传统的基于哈希的支付渠道具有其他优势。 具体来说,秘密值 t 可以在 hops 之间重新盲化,从而允许构建很长的原子交易链,即使参与者也无法识别哪些交易是链的一部分。 此外,由于秘密值是在签名时而不是在密钥生成时选择的,因此现有输出可以重新用于不同的应用程序,而无需诉诸区块链,甚至可以多次使用。
盲签名协议是一种交互式协议,使签名者能够在不了解有关签名消息或签名的任何信息的情况下,应另一方的要求对消息进行签名。 Schnorr 签名允许一个非常 简单的盲签名方案,但是该方案是不安全的,因为它容易受到 Wagner's attack 的攻击。 一種已知的緩解措施是让签名者以一定的概率中止签名会话,并且可以在 非标准密码学假设下证明所得到的方案是安全的。
盲 Schnorr 签名例如可以用于 部分盲原子交换,这是一种在不受信任的托管代理的调解下实现转移 coins 的结构,而无需在公共区块链交易图中连接交易者。
为了开发和测试的目的,我们提供了一个 CSV 格式的测试向量集合 以及一个幼稚的、效率极低的、非恒定时间的 签名和验证算法的纯 Python 3.7 参考实现。 该參考实现仅用于演示目的,不能在生产环境中使用。
本文档是多年来围绕基于 Schnorr 的签名进行的许多讨论的结果,并获得了 Johnson Lau、Greg Maxwell、Andrew Poelstra、Rusty Russell 和 Anthony Towns 的投入。 作者还要感谢所有提供宝贵反馈和评论的人,包括 结构化评论 的参与者。
- 原文链接: github.com/ajtowns/bips/...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!