本文详细介绍了 libsecp256k1 库的历史、演变及其在比特币生态系统中的关键作用。它阐述了该库如何从一个小型项目成长为比特币核心的关键加密组件,以及它在性能优化、安全性保障(如抵御侧信道攻击)和引入新功能(如 Schnorr 签名和 Taproot)方面所做的努力。
来自《核心问题》:一个最初只是“小型业余项目”的库,如何演变为保护万亿美元资产的最安全关键代码路径之一的故事。
比特币爱好者常说“不信任,去验证”或“不是你的密钥,就不是你的币”,有时甚至声称它“由数学支撑”。但这些谚语最终归结为何,以及这些相关的数学究竟是如何付诸实践的?大多数读者肯定都知道,比特币设计中的一个基本要素是公钥密码学,更具体地说是数字签名,这对于在不需要中心实体的情况下证明所有权至关重要。可能鲜为人知的是,幕后是哪一段软件使得椭圆曲线数学得以运行,以及需要付出怎样的努力才能确保以最安全和最高效的方式实现这一点,并持续改进。让我们深入探讨“libsecp256k1”激动人心的历史和演变,这个库最初只是一个小型业余项目,多年来已发展成为保护万亿美元资产的共识规则中不可或缺的一部分。
由于我们无法确定的原因,中本聪选择了名为“secp256k1”的椭圆曲线来在比特币中创建和验证数字签名。比特币客户端的初始版本使用广泛的OpenSSL库来签名和验证交易。从软件工程的角度来看,依赖第三方库似乎是一种合理的方法(如果它是一个像椭圆曲线密码学这样领域特定且复杂的东西,则更是如此),但这种选择后来由于签名解析代码中的不一致而变得有问题。在最坏的情况下,这甚至可能导致意想不到的链分裂。那段时间的一个教训是,OpenSSL对于像比特币这样的共识关键系统来说不是一个合适的库。这个问题后来通过BIP66修复,该BIP确保了ECDSA签名的严格编码。此后,OpenSSL的依赖在2016年初发布的Bitcoin Core v0.12中被libsecp256k1取代。1
但退一步讲,启动libsecp256k1项目的最初动机主要是出于对潜在加速的好奇。2012年某个时候,Bitcoin Core开发者Pieter Wuille,又名“sipa”,偶然发现Hal Finney(因在2009年收到中本聪的第一笔比特币交易而闻名)在bitcointalk上的一个帖子。
在“加速签名验证”的主题下,该帖子讨论了一种优化,即利用所谓的“endomorphism”(更具体地说,是使用所谓的GLV-method,Gallant-Lambert-Vanstone),这是只有某些椭圆曲线才允许的,secp256k1恰好是其中之一。Hal Finney本人使用OpenSSL原语实现了它,后来甚至作为PR提交给Bitcoin Core。2 尽管它显示出显著的
约20%的速度提升,但最终并未合并,因为人们担心代码复杂性增加以及缺乏对所涉及密码学健全性的保证。
Pieter Wuille着手决定从头开始创建一个新库,其中“secp256k1”仓库的首次提交日期是2013年3月5日。仅仅一周后,该库就能够验证整个区块链(当时区块高度约为225000),再过一周,签名功能也已实现。又经过一段时间的开发和测试,该库才准备好在Bitcoin Core中替代OpenSSL使用,首先用于钱包中的签名(v0.10版本,2015年),最后用于共识中的ECDSA签名验证(v0.12版本,2016年)。这些努力绝对是值得的:根据Core中的PR描述,使用libsecp256k1进行签名验证“速度快了2.5到5.5倍”。讽刺的是,这当时还不包括前面提到的endomorphism优化,因为它默认没有开启,原因是担心专利侵权。直到2020年专利过期后才被激活(在v0.20版本中启用),带来了大约16%的又一次显著加速。
随着时间的推移,该项目吸引了其他几位贡献者。这自然包括与Pieter从一开始就在Blockstream密切合作的人,即当时的首席技术官Gregory Maxwell和研究员Andrew Poelstra。2015年,Jonas Nick加入,几年后Tim Ruffing也加入,他们都被Blockstream聘为研究员,并且现在都担任libsecp256k1的维护者多年。由于他们负责指定新的密码协议(包括详细的安全证明)并将其付诸实践,通过实现和审查它们,因此称他们为“全栈密码学家”非常恰当,正如Tim Ruffing喜欢描述自己的那样。
偶尔甚至有来自比特币领域之外的密码学家也为libsecp256k1做出了贡献。一个值得注意的例子是Peter Dettman,他以作为C#/Java密码学库BouncyCastle的维护者之一而闻名,他至今仍不时提出各种性能改进建议。他的一项主要贡献是在2021年使用“safegcd”算法实现模逆,以安全地改进,遵循Daniel J. Bernstein和Bo-Yin Yang的一篇论文。
libsecp256k1的目标是为secp256k1曲线上的密码操作提供最高质量的库,其主要目的是在更广泛的比特币生态系统中有用——Bitcoin Core只是使用它的主要客户端。libsecp256k1的API设计得稳健且难以误用,以防止用户执行不安全的操作(例如,通过自行设计密码方案),这在最坏情况下可能导致资金损失。通过只专注于一条椭圆曲线,并将其功能限制在与比特币相关的操作(即,主要是签名和验证交易),代码可以更快,更易于审查,从而降低维护负担,并与其它实现相比,提高整体质量。libsecp256k1是用C语言编写的,不依赖于其他库,因此它只使用专门为该项目编写的内部代码。因此,它也被设计为在微控制器等受限设备上运行,这些设备通常用于硬件钱包。
从很早开始,libsecp256k1就非常注重质量保证,并在多年来不断改进和完善。现在它的测试代码覆盖率接近100%,新模块只有在满足这一标准的情况下才有机会被合并。除此之外,还有一种特殊的保证形式称为“穷举测试”。基本思想是针对曲线上所有可能的取值范围来执行库的功能。由于这在实际的secp256k1曲线上(由约2^256个点组成)是不可行的,因此使用了一个特殊且小得多但非常相似的曲线,其阶数仅为两位或三位数,因此可以在合理的时间内轻松执行。测试的另一个重要部分是保证常量时间行为,这对于签名尤其重要,我们将在下面看到。
将我们的焦点从QA转向新功能,过去十年中libsecp256k1和整个比特币协议的一个主要里程碑是引入了Schnorr签名。作为2021年末激活的Schnorr/Taproot软分叉的重要组成部分,它们比ECDSA签名具有许多优势,包括在标准假设下可证明安全,更紧凑,并能在其之上实现许多其他构造,例如用于更高效多重签名方案的密钥和签名聚合。BIP340中的规范和实现均由libsecp256k1的现有三位维护者Pieter Wuille、Jonas Nick和Tim Ruffing创建。
不言而喻,验证数字签名是比特币共识引擎中最重要的(如果不是最重要的)安全关键代码路径之一。无论锁定脚本中可能包含多么复杂的脚本路径和额外的花费条件,最终交易中很可能至少涉及一个签名检查,以确保它确实由被花费的币的所有者创建。对于这样一个基本操作,我们希望代码尽可能地健壮、经过良好测试和高性能。快速签名验证对于快速交易和区块传播也至关重要,并且还能加速网络新参与者的初始区块下载(IBD)。我们之前已经提到,大约十年前libsecp256k1首次取代OpenSSL时带来了约5倍的速度提升。随着时间的推移,进一步的性能改进得以实施,最近的一项调查显示,libsecp256k1现在对于ECDSA签名验证的速度比OpenSSL快约8倍,使用的是各自的最新版本。3
到目前为止,我们一直专注于libsecp256k1的验证功能,这对节点运行者和矿工的性能至关重要。Coin的另一面(无双关语!)是签名,即为了花费资金而为交易创建数字签名的过程。使这个过程变得微妙的事实是,它涉及秘密密钥材料。如果这些材料以任何方式泄露,在最坏的情况下可能导致灾难性的资金损失,因此在实现层面必须特别小心。libsecp256k1试图通过避免数据相关的分支来对抗所谓的“侧信道攻击”,即根据输入数据的不同执行不同代码片段的情况。这是一项不简单的任务,并且对于现代编译器来说需要额外的努力,因为它们有时“太聪明”,在编译代码时会尝试优化代码,生成我们明确不希望出现资源节约分支的软件。这不仅仅是一个理论问题,而是已经发生过不止一次,需要发布补丁(例如0.3.1和0.3.2版本)。重要的常量时间属性也使用一个名为“valgrind”的工具进行测试,该工具最初是为调试内存问题而构建的。通过使用它来查找操作秘密数据的代码中的任何分支,我们可以检测是否存在潜在的侧信道风险。
秘密材料可能被泄露的另一种方式是无意中将其留在内存中。覆盖内存区域以确保其被擦除听起来很简单,但这必须以一种方式完成,以防止编译器在编译期间由于代码优化而阻碍我们。我们非常小心地确保这种情况不会发生。
在库的开发过程中,不止一次地出现了一些有趣的意外。2014年,Pieter Wuille和Gregory Maxwell已经在为该库开发一个广泛的测试套件。提高保证程度的策略之一是使用特殊的随机输入,对照其他实现来验证库内部函数的行为。这揭示了一个OpenSSL在平方一个数字时给出错误结果的案例,这是一个严重的安全相关错误,被列为CVE-2014-3570(“大数平方可能产生不正确的结果。”)。
几年后,在另一个案例中,Pieter Wuille提出了一种新方法,用于计算前述用于计算模逆的“safegcd”算法所需的迭代次数的界限(或限制)。这使得该界限得以缩小,从而实现了更快的计算。但这并没有止步。Gregory Maxwell在很大程度上是偶然发现了Bernstein和Yang算法的一个不同变体,其界限更低,从而在签名和验证方面又带来了显著的加速。
值得一提的是,“safegcd”实现的正确性(即安全性)已使用一种名为“Rocq”(前身为“Coq”)的特殊定理证明软件和“Verifiable C”程序逻辑进行了形式化验证。4 这项令人印象深刻的工作由Russell O’Connor和Andrew Poelstra完成,他们表示libsecp256k1的整体也可以通过相同的方式进行验证。
我们已经展示了libsecp256k1主要用于在比特币交易中创建和验证数字签名,并非常谨慎地以最安全和最有效的方式进行,但这并非终点。每当提出涉及secp256k1曲线上的密码操作(最好以BIP形式正式化)且被认为对比特币生态系统总体有利的其他提案时,所需的代码很有可能被纳入该库的范围。在这种情况下,只要有足够的开发者时间进行实现和审查,它就有很大的机会在libsecp256k1的某个版本中发布。这之前已经发生过,例如ElligatorSwift模块,它对于启用节点P2P通信的加密至关重要[参见BIP324;在此处深入讨论],以及最近的MuSig2,一个基于Schnorr签名的密钥聚合方案,允许以空间高效和隐私保护的方式创建n对n多重签名。目前还有一个正在进行的努力,旨在为Silent Payments添加一个新模块,这是一个用于隐私保护的静态可重用地址的提案,它在支付前不需要发送方和接收方之间的交互。未来还有更多内容:Schnorr签名的批量验证、DLEQ证明、FROST等。让我们拭目以待libsecp256k1在未来10年将带来什么!
对libsecp256k1感兴趣的读者可以查看并试用secp256k1lab,这是一个secp256k1曲线的Python实现,旨在用于原型设计和实验。5
[1] https://gnusha.org/pi/bitcoindev/55B79146.70309@gmail.com/
[2] (#2061, https://github.com/bitcoin/bitcoin/pull/2061)
[4] [ https://www.arxiv.org/abs/2507.17956]
[5] https://github.com/secp256k1lab/secp256k1lab/
- 原文链接: bitcoinmagazine.com/prin...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!