首页
/ Bitcoin Core 中的 libsecp256k1 完全指南:椭圆曲线密码库原理、模块化构建与源码验证

Bitcoin Core 中的 libsecp256k1 完全指南:椭圆曲线密码库原理、模块化构建与源码验证

2026-09-07 14:55:18作者:伍霜盼Ellen

libsecp256k1 是运行在 secp256k1 椭圆曲线上、面向数字签名与其他密码原语的高性能、高可信 C 语言库,它以子目录(subtree)的形式内嵌于本仓库 src/secp256k1,是 Bitcoin Core 所有密钥生成、ECDSA/Schnorr 签名与验证、MuSig2 聚合与 BIP-324 传输加密的底层基石。本文将以该库自带文档为主体,结合本仓库的实际集成代码与构建配置,系统讲解其设计特性、内部数学实现、与 Bitcoin Core 的对接方式、标签校验流程以及 Autotools/CMake 两种构建路径与交叉编译细节,帮助读者获得可复现、可验证的完整认识。

一、它是什么:定位与设计哲学

libsecp256k1 自述 将其定位为 "High-performance high-assurance C library for digital signatures and other cryptographic primitives on the secp256k1 elliptic curve",即针对 secp256k1 曲线的高性能、高保证(可被严格审计)密码库。

文档同时给出了一个重要边界声明:该库的主要开发目标是服务于比特币系统,凡是用法与比特币不同(非典型使用场景)的部分,可能没有经过同等程度的测试、验证,接口设计也可能考虑不周;正确使用需要使用者自行判断该库是否适合自身应用场景。这一点在将此库复用到其他区块链或通用密码系统时尤其值得注意。

围绕这一目标,README 明确了若干实现层面的硬性约束,这些约束在源码中同样可以找到佐证:

  • 零运行时堆分配:整个库不使用运行时堆内存,全部在调用方提供的上下文与栈上完成;
  • 不使用浮点类型:所有运算均为整数运算,避免浮点行为不一致带来的可移植性与时序问题;
  • C89 + uint64_t 即可移植:设计目标是可在任何支持 C89 编译器与 uint64_t 的系统上编译;
  • 最小化 API 面:只暴露高层接口,压缩攻击面,官方称之为 "Be difficult to use insecurely"(让人很难不安全地使用);
  • 结构化便于审计:源码按 field/scalar/group/ecmult 等层次组织,配合测试、穷举测试与常量时间测试基础设施。

这些约束与 CMakeLists 中 CMAKE_C_STANDARD 90(即 C89/C90) 的设置一致,也与其 README 声称的 "Intended to be portable to any system with a C89 compiler and uint64_t support" 相互印证。

二、功能特性与可选模块

README 列出的核心功能可归纳为以下三个层次。

2.1 核心密码功能

  • secp256k1 ECDSA:签名、验证与密钥生成;
  • 密钥 tweaking:支持对私钥/公钥进行加法与乘法意义上的 tweak(如 Taproot 的 tweak 操作);
  • 序列化/解析:私钥、公钥、签名的编解码;
  • 恒定时间保证:签名与公钥生成的代码路径不依赖数据值(constant time、constant memory access),防止时序侧信道;
  • 去随机化 ECDSA:支持 RFC6979 确定性随机数,也支持由调用方注入 nonce 函数。

2.2 可选功能模块

库的主体只依赖核心曲线运算,其余功能以"模块"形式按需编译,README 中共列 6 个模块,对应本仓库中的源码目录与公开头文件:

模块 说明 子目录实现 公开头文件
Public key recovery 从签名反推公钥(ecrecover src/secp256k1/src/modules/recovery secp256k1_recovery.h
ECDH 椭圆曲线 Diffie-Hellman 密钥交换 src/secp256k1/src/modules/ecdh secp256k1_ecdh.h
Schnorr 签名 依据 BIP-340 的 Schnorr 签名 src/secp256k1/src/modules/schnorrsig secp256k1_schnorrsig.h
ElligatorSwift 依据 BIP-324 的椭圆曲线密钥交换编码 src/secp256k1/src/modules/ellswift secp256k1_ellswift.h
MuSig2 依据 BIP-327 的 Schnorr 多重签名 src/secp256k1/src/modules/musig secp256k1_musig.h
Silent Payments 依据 BIP-352 的静默支付收发 src/secp256k1/src/modules/silentpayments secp256k1_silentpayments.h

从源码结构看,每个模块统一由 main_impl.h 提供实现、tests_impl.h 提供测试、可选的 tests_exhaustive_impl.h 提供对小型曲线的穷举测试,例如 extrakeys 模块 是 Schnorr 与 MuSig2 的公共依赖。MuSig2 模块进一步拆分为 keyagg_impl.h(密钥聚合)session_impl.h(多轮会话状态机),并在 musig/vectors.h 中内置了官方测试向量;Silent Payments 模块则携带 BIP-352 官方向量

2.3 Bitcoin Core 侧实际启用了哪些模块

值得强调的是,本仓库是 Bitcoin Core,其 根级 CMake 集成脚本 cmake/secp256k1.cmake 定义了"core 视角"下模块的取舍,与库自身默认值并不完全相同:

SECP256K1_ENABLE_MODULE_ECDH      OFF   # Bitcoin Core 不使用 ECDH 模块
SECP256K1_ENABLE_MODULE_RECOVERY  ON    # 需要 ecrecover(legacy 签名验证)
SECP256K1_ENABLE_MODULE_MUSIG     ON    # MuSig2 聚合(BIP-327)
SECP256K1_BUILD_BENCHMARK         OFF   # Core 构建不编译基准
SECP256K1_BUILD_TESTS             ${BUILD_TESTS}

src/CMakeLists.txt 中通过 add_secp256k1(secp256k1) 将该子树链接进 bitcoind/bitcoin-qt 等目标。对应地,核心源码在几个关键文件中直接消费这些 API:

  • src/key.cpp 同时包含 <secp256k1.h>secp256k1_ellswift.hsecp256k1_extrakeys.hsecp256k1_recovery.hsecp256k1_schnorrsig.h,并在其中实现 DER 格式私钥的宽松导入/导出(ec_seckey_import_der / ec_seckey_export_der);
  • src/pubkey.cppsecp256k1_schnorrsig_verify 完成 Taproot 公钥的 Schnorr 验证,并在 第 374 行 调用 secp256k1_ellswift_decode 把 BIP-324 的 64 字节编码还原成椭圆曲线点;
  • src/musig.cpp 是基于 MuSig2 模块的封装层,MuSig2AggregatePubkeys 调用 secp256k1_musig_pubkey_agg,签名流程调用 secp256k1_musig_nonce_gen 生成临时 nonce

由此可以直观看到:MuSig2(BIP-327)与 ElligatorSwift(BIP-324)模块正是为了 Bitcoin Core 的 Taproot 相关功能而启用

三、内部实现细节:从域运算到常量时间点乘

README 用较大篇幅披露了底层算法选型,这些描述与 src/secp256k1/src 下的实现文件一一对应,是理解其性能与安全性来源的关键。

3.1 域与标量运算

secp256k1 曲线的域大小(field size)是 2^256 - 0x1000003D1,标量阶(order)则是另一组参数。库对两者的模算术分别提供了多套 limb 表示:

  • 域运算(field arithmetic)
    • 5 个 52-bit limb 的实现,见 field_5x52_impl.h
    • 10 个 26-bit limb 的实现,见 field_10x26_impl.h,其中包含由 Wladimir J. van der Laan 编写的 32-bit ARM 手写汇编asm/field_10x26_arm.s)。README 特别注明:该 ARM 汇编属于实验性特性,尚未经过足以达到本库质量标准的大量审查,目前仅面向社区测试与评审开放——在 CMake 中需要同时开启 SECP256K1_ASM=arm32SECP256K1_EXPERIMENTAL=ON 才能使用(见 CMakeLists.txtSECP256K1_ASM 选项与 CheckArm32Assembly.cmake)。
  • 标量运算(scalar arithmetic)
    • 4 个 64-bit limb,依赖编译器 __int128 支持,见 scalar_4x64_impl.h
    • 8 个 32-bit limb,见 scalar_8x32_impl.h
    • 两者都明确做到"无数据相关分支"(without data-dependent branches)。
  • 模逆(modular inverse):域元素与标量的求逆均基于 safegcd 算法(含部分修改),另有一个可变时间(variable-time)变体,由 Peter Dettman 贡献;具体推导记录在 doc/safegcd_implementation.md,实现见 modinv64_impl.hmodinv32_impl.h

3.2 群运算与点乘

  • 群运算(group operations)
    • 点加公式针对本曲线方程 y^2 = x^3 + 7 做了专门化简;
    • 尽量在 Jacobian 与仿射(affine)坐标之间混合做加法;
    • 在必要时使用统一的加/倍公式,以避免数据相关分支;
    • 点/坐标比较不需要域求逆,直接在 Jacobian 坐标空间中完成。
  • 验证侧点乘 a*P + b*G(ecmult),核心代码见 ecmult_impl.h
    • 对点乘数使用 wNAF(窗口化非相邻形式) 记法;
    • G 的倍数使用更大的窗口与预计算倍点表;
    • Shamir's trick 同时完成"公钥点 + 生成元"的双标量乘;
    • 利用 secp256k1 可高效计算的 endomorphism,把 P 的乘数拆成两个半长的乘数,从而降低运算量。
  • 签名侧点乘(ecmult_gen),核心代码见 ecmult_gen_impl.h
    • 预计算"16 的幂 × 生成元"的倍点表,使一般乘法退化为一系列加法;
    • 目标是私钥操作在合理硬件/工具链上完全无时序侧信道:用无分支的条件移动访问查表,保证内存访问模式一致;不存在数据相关分支;
    • 提供可选的运行时盲化(blinding),用于对抗差分功耗分析(DPA);
    • 预计算表会"先加后减"一些没有任何人知道其标量(私钥)的点,即使攻击者能控制私钥,也无法影响内部使用的数据,进一步切断侧信道联系。

预计算表本身由 precompute_ecmult.cprecompute_ecmult_gen.c 生成后固化到 precomputed_ecmult.cprecomputed_ecmult_gen.c,这也是为什么 --with-ecmult-window 超过 15 时需要删除预生成文件以重建的原因。

3.3 可调的性能/内存权衡参数

实现之上还暴露了若干构建期调优参数(configure.acCMakeLists.txt 均有对应选项):

  • --with-ecmult-window=SIZE / SECP256K1_ECMULT_WINDOW_SIZE(默认 15,合法范围 2~24):验证预计算的窗口大小,越大性能越好,但预计算表以 2^(SIZE-1) × 64 字节 的速度膨胀;窗口 >15 时需删除预生成的 precomputed_ecmult.c 以便重新生成,超大窗口建议 make -j 1 以降低编译期内存;
  • --with-ecmult-gen-kb=2|22|86 / SECP256K1_ECMULT_GEN_KB(默认 86):签名预计算表大小(以 1024 字节的倍数计),值越大签名/密钥生成越快、表越大;
  • --with-asm=x86_64|arm32|no|auto / SECP256K1_ASM(默认 auto):是否使用汇编优化,arm32 为实验特性。

四、获取与校验:标签的 GPG 验证流程

README 指出,每个发布版本对应的 git 标签(例如 v0.6.0)都由一位维护者用 GPG 签名。对于追求"fully verified build"的用户,推荐的路径是:通过 git 获取仓库 → 获取签名维护者的 GPG 公钥 → 用 git 校验发布标签签名。注意在本仓库中,库本身位于 src/secp256k1 子树中;当前子树的 CMakeLists 声明的项目版本为 0.8.1,而 README 以 v0.7.1 标签作为校验示例。

推荐校验步骤如下(命令以 v0.7.1 为例):

  1. 获取 SECURITY.md 中列出的 GPG 密钥;
  2. 尽量通过其所有者控制的其他渠道(社交媒体、个人网站等)交叉核对这些 key ID,以降低"本仓库展示的是被篡改内容"这种小概率风险;
  3. 克隆仓库;
  4. 检出目标发布标签,例如 git checkout v0.7.1
  5. 用 git 校验标签 GPG 签名并过滤出 "Good signature":
git tag -v v0.7.1 | grep -C 3 'Good signature'

gpg: Signature made Mon 26 Jan 2026 07:42:46 PM UTC
gpg:                using RSA key 2840EAABF4BC9F0FFD716AFAFBAFCC46DE2D3FE2
gpg: Good signature from "Pieter Wuille <pieter@wuille.net>" [unknown]
gpg:                 aka "Pieter Wuille <pieter.wuille@gmail.com>" [full]
gpg:                 aka "[jpeg image of size 5996]" [undefined]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 133E AC17 9436 F14A 5CF1  B794 860F EB80 4E66 9320
     Subkey fingerprint: 2840 EAAB F4BC 9F0F FD71  6AFA FBAF CC46 DE2D 3FE2

其中 "WARNING: This key is not certified with a trusted signature!" 属于 GPG 对"密钥未在本地信任网中经过认证"的常规提示,并不表示签名无效——只要出现 Good signature 即说明标签内容与签名人公钥匹配。上述交叉核验步骤的目的正是弥补这条信任链的缺口。

五、构建方式:Autotools 与 CMake 双轨

5.1 通过 Autotools 构建

库自带 autogen.shconfigure.acMakefile.am 等全套 autotools 基础设施,经典流程为:

$ ./autogen.sh       # 生成 ./configure 脚本
$ ./configure        # 生成构建系统
$ make               # 实际编译
$ make check         # 运行测试套件
$ sudo make install  # 安装到系统(可选)

编译可选模块需要在 ./configure 时追加开关,例如 Schnorr 模块使用 --enable-module-schnorrsig。完整的可用开关列表通过 ./configure --help 查看。configure.ac 中声明的模块开关 及其默认值如下(均形如 --enable-module-xxx):

configure 开关 含义 默认值
--enable-module-ecdh ECDH 模块 yes
--enable-module-recovery ECDSA 公钥恢复模块 no
--enable-module-extrakeys extrakeys 模块 yes
--enable-module-schnorrsig Schnorr 签名模块 yes
--enable-module-musig MuSig2 模块 yes
--enable-module-ellswift ElligatorSwift 模块 yes
--enable-module-silentpayments Silent Payments 模块 yes

另有 --enable-benchmark(默认 yes)、--enable-tests(默认 yes)、--enable-exhaustive-tests(默认 yes)、--enable-ctime-tests(若启用 valgrind 则默认 yes)、--enable-examples(默认 no)、--enable-experimental(默认 no)与 --enable-coverage(默认 no)等开关。

5.2 通过 CMake 构建

CMake 鼓励out-of-source(源码树外)构建以保持源码目录干净。POSIX 系统上的标准流程为:

$ cmake -B build              # 在子目录 build 中生成构建系统
$ cmake --build build         # 实际编译
$ ctest --test-dir build      # 运行测试套件
$ sudo cmake --install build  # 安装到系统(可选)

对应的模块开关变为 -DSECP256K1_ENABLE_MODULE_SCHNORRSIG=ON 这种形式;查看全部可用选项执行 cmake -B build -LH(或图形化的 ccmake -B build)。库内 CMakeLists.txt 的模块选项默认值 为:ECDH=ON、RECOVERY=OFF、EXTRAKEYS=ON、SCHNORRSIG=ON、MUSIG=ON、ELLSWIFT=ON、SILENTPAYMENTS=ON;RECOVERY 默认关闭而 ECDH 默认开启,恰好与上文 Bitcoin Core 集成脚本的取舍相反,属于"发行版默认"与"宿主项目按需覆盖"的正常差异。

5.3 交叉编译

为缓解交叉编译的痛点,项目在 cmake 目录中预置了工具链文件,例如本仓库内即可看到 x86_64-w64-mingw32.toolchain.cmakearm-linux-gnueabihf.toolchain.cmake。README 给出的示例:

交叉编译到 Windows:

$ cmake -B build -DCMAKE_TOOLCHAIN_FILE=cmake/x86_64-w64-mingw32.toolchain.cmake

借助 Android NDK 交叉编译到 Android(需设置好 ANDROID_NDK_ROOT 环境变量):

$ cmake -B build -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=28

5.4 在 Windows 上原生构建

以下示例假设使用 Visual Studio 2022,并推荐 clang-cl。在 "Developer Command Prompt for VS 2022" 中:

>cmake -B build -T ClangCL
>cmake --build build --config RelWithDebInfo

(若使用其它配置名,库内 CMake 也提供了 MinSizeRel、Release、Coverage 等自定义构建类型供选用。)

六、可直接运行的示例与性能基准

6.1 官方示例程序

examples 目录 中提供了可编译运行的完整示例,README 明确要求先用 ./configure --enable-examples(CMake 侧为打开模块后设置 SECP256K1_BUILD_EXAMPLES)进行配置,并确保所需模块已开启:

这些示例通过条件编译与模块联动(examples/CMakeLists.txt 中按 SECP256K1_ENABLE_MODULE_* 逐个纳入目标),是理解库 API 正确调用顺序的最佳起点。

6.2 性能基准(benchmark)

若以 --enable-benchmark 配置(默认即开启;CMake 侧 SECP256K1_BUILD_BENCHMARK 默认 ON),构建完成后根目录下会出现一批 bench_* 基准二进制(对应源码为 bench.cbench_ecmult.c 等,各模块另有 bench_impl.h 提供对应基准)。运行方式:

$ ./bench_name

将结果转成 CSV 以便制表:

$ ./bench_name | sed '2d;s/ \{1,\}//g' > bench_name.csv

七、测试、常量时间验证与安全披露

为保证"高保证"承诺,库内测试是多层的:常规单元测试(src/tests.c)、针对小规模曲线的穷举测试src/tests_exhaustive.c)、以及在 Valgrind 下运行的常量时间测试src/ctime_tests.c),后者用于在运行时探测数据相关的内存访问/分支,是"签名路径无时序侧信道"这一承诺的直接验证手段;配合 Wycheproof 测试向量(src/wycheproof)做第三方交叉验证。构建期可通过 --with-valgrind/SECP256K1_VALGRIND(默认 auto)启用额外检查,社区 CI 配置见 ci/ci.sh

安全与贡献相关事宜分别由 SECURITY.md(漏洞上报)与 CONTRIBUTING.md(贡献指南)承载,自述文档中明确指引读者参阅这两份文件;版本演进历史则记录在 CHANGELOG.md

八、总结与使用前提

libsecp256k1 通过"受限的 C89 接口 + 精心挑选的 limb 表示与预计算策略 + 无分支常量时间代码路径 + 穷举/常量时间测试"四层手段,在比特币系统中同时达成了性能与安全的高标准。对 Bitcoin Core 而言,它在 cmake/secp256k1.cmake 中以「启用 Recovery + MuSig2、关闭 ECDH」的最小必要配置嵌入,支撑着从 legacy 公钥恢复到 Taproot Schnorr 验证、再到 BIP-327 聚合签名的整条密钥链。

最后仍需回到 README 的告诫:该库以比特币用法为第一优先,其他使用场景可能未被同等验证,接口也不一定完备;任何将其用于非比特币场景的项目,都应先评估其是否适用于自身目的,并通过第三节介绍的自述文档 + 第二节列出的源码实现 + 第七节的多层测试来独立判断其可信度。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388