EIP-2539 深度解读:在以太坊 EVM 中以预编译合约实现 BLS12-377 曲线运算
【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs
导读
本文围绕本仓库中的 EIPS/eip-2539.md 展开,完整解读一份面向以太坊核心协议的提案:通过引入9 个新的预编译合约(precompile),让 EVM 可以高效执行 BLS12-377 配对友好曲线上的点加、点乘、多标量乘、配对与域映射操作,从而支撑 BLS 签名验证与 zkSNARK 证明验证等密码学场景。读完本文,你将掌握这 9 个预编译的地址分配、曲线参数、字段元素编码规范、逐操作 ABI 约定、错误处理与完整 Gas 定价模型,并能基于本仓库中 EIP-1962、EIP-2537、EIP-3026 等关联提案理解其在以太坊密码学预编译演进中的位置。
状态说明:本 EIP 当前在仓库中的
status为Stagnant(停滞),type为 Standards Track,category为 Core,创建于 2020-02-26,作者为 Alex Vlasov(@shamatar)与 hujw77(@hujw77),并requiresEIP-1109(PRECOMPILEDCALL 操作码)与 EIP-2046(降低预编译 STATICCALL 成本)。
一、背景与动机:为什么需要 BLS12-377 预编译
1.1 从安全强度说起
以太坊早期引入的 BN254 配对预编译只能提供约80 bit 的安全强度。而 BLS12-377(来自 Zexe 论文)作为配对友好曲线,可以支撑120+ bit 的安全强度,同时其独特性质还允许高效的一次性递归证明聚合——例如"关于存在某个 BLS12-377 签名"的证明。这正是本 EIP 的动机所在:
- 支撑 BLS 签名验证:包括公钥聚合与多签名者的签名聚合;
- 支撑 SNARK 验证:提供必要的曲线运算原语,且 BLS12-377 的特性允许在后续 SNARK 中高效地"验证 BLS12-377 配对",进而实现常数大小的 BLS 签名聚合。
1.2 九个预编译与地址分配
如果block.number >= X(激活区块号由部署决定),本 EIP 将引入 9 个独立预编译,地址从0x15到0x1d:
| Precompile | 地址 | 功能 |
|---|---|---|
| BLS12_377_G1ADD | 0x15 | 素域曲线上点的加法 |
| BLS12_377_G1MUL | 0x16 | 素域曲线上点的标量乘法 |
| BLS12_377_G1MULTIEXP | 0x17 | 素域曲线上的多标量乘(multiexponentiation) |
| BLS12_377_G2ADD | 0x18 | 基域二次扩域上 twist 曲线的点加法 |
| BLS12_377_G2MUL | 0x19 | 基域二次扩域上 twist 曲线的点乘法 |
| BLS12_377_G2MULTIEXP | 0x1a | 基域二次扩域上的多标量乘 |
| BLS12_377_PAIRING | 0x1b | 一组 (G1, G2) 点对的配对运算 |
| BLS12_377_MAP_FP_TO_G1 | 0x1c | 将基域元素映射为 G1 点 |
| BLS12_377_MAP_FP2_TO_G2 | 0x1d | 将扩域元素映射为 G2 点 |
其中G1MULTIEXP / G2MULTIEXP的存在尤为关键:BLS 签名验证需要把多个公钥或多个签名者的签名聚合起来,单独的多标量乘预编译可以一次性完成,避免反复调用乘法预编译叠加 CALL 开销。
1.3 在仓库提案谱系中的位置
BLS12-377 预编译并非孤立提案,在本仓库中可以找到完整的关联脉络:
- EIPS/eip-2537.md:BLS12-381 曲线预编译提案(状态为Final),地址
0x0b~0x11,只含 7 个预编译,与本 EIP 构成"BLS12 家族"的两条技术路线; - EIPS/eip-1962.md:matter-labs 提出的通用椭圆曲线运算预编译,其中明确写到"BLS12 家族已完成并测试了 BLS12-381 与 BLS12-377 曲线",并在基准测试中给出 BLS12-381 配对约
2,348,317 ns/iter、CP6 曲线(嵌入 BLS12-377 的 Cocks-Pinch 曲线)配对约86,328,825 ns/iter的数据(见 EIPS/eip-1962.md 的 Preliminary benchmarks 一节); - EIPS/eip-3026.md:BW6-761 曲线预编译,
requires: 2539,文中明确说明"在大多数应用中 BW6-761 被用作 BLS12-377 的外层曲线",二者配合可实现单层 SNARK 证明组合(proof composition)。
这组提案共同描绘了以太坊配对密码学预编译的演进路径:从 80 bit 的 BN254 走向 120+ bit 的 BLS 家族,再到支撑递归证明组合的 BLS12-377 + BW6-761 双层曲线结构。
二、曲线参数规格
BLS12-377 曲线由以下参数集合完整定义(所有 BLS12 曲线系数A = 0,即曲线方程为y² = x³ + B):
Base field modulus = 0x01ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001 B coefficient = 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 Main subgroup order = 0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001 Extension tower: Fp2 construction: Fp quadratic non-residue = 0x01ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508bffffffffffc Fp6/Fp12 construction: Fp2 cubic non-residue c0 = 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 Fp2 cubic non-residue c1 = 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 Twist parameters: Twist type: D B coefficient for twist c0 = 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 B coefficient for twist c1 = 0x010222f6db0fd6f343bd03737460c589dc7b4f91cd5fd889129207b63c6bf8000dd39e5c1ccccccd1c9ed9999999999a Generators: G1: X = 0x008848defe740a67c8fc6225bf87ff5485951e2caa9d41bb188282c8bd37cb5cd5481512ffcd394eeab9b16eb21be9ef Y = 0x01914a69c5102eff1f674f5d30afeec4bd7fb348ca3e52d96d182ad44fb82305c2fe3d3634a9591afd82de55559c8ea6 G2: X c0 = 0x018480be71c785fec89630a2a3841d01c565f071203e50317ea501f557db6b9b71889f52bb53540274e3e48f7c005196 X c1 = 0x00ea6040e700403170dc5a51b1b140d5532777ee6651cecbe7223ece0799c9de5cf89984bff76fe6b26bfefa6ea16afe Y c0 = 0x00690d665d446f7bd960736bcbb2efb4de03ed7274b49a58e458c282f832d204f2cf88886d8c7c2ef094094409fd4ddf Y c1 = 0x00f8169fd28355189e549da3151a70aa61ef11ac3d591bf12463b01acee304c24279b83f5e52270bd9a1cdd185eb8f93 Pairing parameters: |x| (miller loop scalar) = 0x8508c00000000001 x is negative = false几个值得注意的细节:
- Base field modulus与Main subgroup order的末尾都带有
...8508c00000000001结构,这是 BLS12 曲线族刻意设计的稀疏 Miller 循环标量,直接影响配对运算的速度; - Twist type 为 D 型 twist,其
B coefficient for twist c1带有...ccccc...这样的稀疏结构,同样是面向高效实现的参数选择; - 与 BLS12-381(twist type M,见 EIPS/eip-2537.md)不同,BLS12-377 使用 D 型 twist。
三、编码规则:字段元素与点的字节表示
3.1 基域元素 Fp 编码(64 字节)
- 对相应(无符号)整数做BigEndian 编码,总长度固定为
64字节,其中顶部16字节恒为零; - 选 64 字节是为了得到 32 字节对齐的 ABI(在 Solidity 中可表示为
bytes32[2]或uint256[2]); - 对应的整数必须小于域模数(field modulus)。
3.2 二次扩域元素 Fp2 编码(128 字节)
- Fp2 元素形如
el = c0 + c1 * v,其中v是形式化的二次非剩余(quadratic non-residue),c0、c1均为 Fp 元素; - 字节编码为
encode(c0) || encode(c1),即两个 64 字节编码的字节拼接,总计128 字节(Solidity 中对应bytes32[4]或uint256[4])。
3.3 点的编码
- G1 点(基域上)与 G2 点(扩域上)均为两个仿射坐标
x、y各自编码后的字节拼接; - G1 点总长 128 字节(2 × 64),G2 点总长 256 字节(2 × 128)。
3.4 无穷远点(零点)编码
- 对 BLS12 曲线而言,坐标为
(0, 0)的点不在曲线上(y² = x³ + B在x=0, y=0时不成立,因为B ≠ 0); - 因此规范约定:使用
(0, 0)(Fp 或 Fp2 中的形式零)的编码作为无穷远点的约定编码。
3.5 乘法标量编码(32 字节)
- 对标量做 BigEndian 编码,固定32 字节;
- 与域元素不同,标量整数不要求小于或等于主子群阶(main subgroup size)——实现需要正确处理"未归一化标量",这一点在后面的测试属性中也会体现。
硬性要求:解析过程中只要出现任何不符合上述规范的编码,预编译必须返回错误(error)。
四、九个操作的 ABI 规格
4.1 G1 加法(0x15)
- 输入:
256字节,为两个 G1 点编码(各128字节)的字节拼接; - 输出:单个 G1 点编码(
128字节); - 错误情形:任一点不在曲线上;域元素编码违反规则;输入长度非法。
4.2 G1 乘法(0x16)
- 输入:
160字节 = G1 点(128字节)|| 标量(32字节); - 输出:
128字节 G1 点; - 错误情形:点不在曲线上;域元素编码非法;输入长度非法。
4.3 G1 多标量乘(0x17)
- 输入:
160*k字节,为k个切片(每个切片 = G1 点128字节 || 标量32字节)的拼接; - 输出:
128字节 G1 点; - 错误情形:任一 G1 点不在曲线上;域元素编码非法;输入长度非法。
4.4 G2 加法(0x18)
- 输入:
512字节 = 两个 G2 点(各256字节); - 输出:
256字节 G2 点; - 错误情形:任一点不在曲线上;域元素编码非法;输入长度非法。
4.5 G2 乘法(0x19)
- 输入:
288字节 = G2 点(256字节)|| 标量(32字节); - 输出:
256字节 G2 点; - 错误情形:点不在曲线上;域元素编码非法;输入长度非法。
4.6 G2 多标量乘(0x1a)
- 输入:
288*k字节,为k个切片(每个切片 = G2 点256字节 || 标量32字节)的拼接; - 输出:
256字节 G2 点; - 错误情形:任一 G2 点不在曲线上;域元素编码非法;输入长度非法。
4.7 配对运算(0x1b)
- 输入:
384*k字节,为k个切片的拼接,每个切片结构为:128字节 G1 点编码;256字节 G2 点编码;
- 输出:
32字节。若配对结果等于配对目标域中的乘法单位元(即配对成功),则前31字节为0x00、末字节为0x01;否则末字节为0x00; - 错误情形:布尔变量编码非法(对应上述 32 字节输出的编码校验);任一 G1/G2 点不在曲线上;任一 G1/G2 点不在正确子群中;域元素编码非法;输入长度非法。
注意:配对运算是唯一强制要求**子群检查(subgroup check)**的操作。
4.8 Fp → G1 映射(0x1c)
- 输入:
64字节,解释为基域元素; - 输出:
128字节 G1 点; - 错误情形:输入长度非法;输入不是合法域元素。
4.9 Fp2 → G2 映射(0x1d)
- 输入:
128字节,解释为二次扩域元素; - 输出:
256字节 G2 点; - 错误情形:输入长度非法;输入不是合法域元素。
这些映射操作不负责"字节串 → 域元素"的转换(该步骤可在 EVM 中高效实现且做法多样),只负责域元素 → 曲线点的域算术,是签名方案(如 BLS 签名)所需的哈希到曲线(hash-to-curve)基础设施(这一设计思路与 EIPS/eip-2537.md 中独立的 field_to_curve 映射文档 一致)。
五、错误处理与 DDoS 防护
预编译涉及大量计算,因此任何错误路径都必须消费完对应操作 Gas 表中的全部 Gas("错误处理期间的 DDoS 防护")。这是以太坊预编译的标准防御手段:防止攻击者用极低的 Gas 代价触发昂贵的失败计算路径,从而免费消耗节点的 CPU 资源。
具体到各操作的错误情形(不在曲线、编码非法、长度非法、子群非法等),见上一节逐操作列表。
六、Gas 定价模型
假设常量为30 MGas/秒,提案给出如下定价:
| 操作 | Gas 成本 |
|---|---|
| G1 加法 | 600 |
| G1 乘法 | 12000 |
| G2 加法 | 4500 |
| G2 乘法 | 55000 |
| Fp → G1 映射 | 5500 |
| Fp2 → G2 映射 | 75000 |
6.1 多标量乘(G1/G2)的折扣定价
多标量乘必须采用 Peppinger 算法执行,才能获得相对"逐对相乘再相加"朴素实现的加速(从而体现折扣)。为避免非整数运算,调用成本按如下公式计算:
cost = k * multiplication_cost * discount / multiplier其中multiplier = 1000,k为 (标量, 点) 对的数目,multiplication_cost为对应曲线(G1/G2)单次乘法成本。
折扣表为[k, discount]向量对(仅覆盖k <= 128,超过部分使用上限max_discount):
[[1, 1200], [2, 888], [3, 764], [4, 641], [5, 594], [6, 547], [7, 500], [8, 453], [9, 438], [10, 423], [11, 408], [12, 394], [13, 379], [14, 364], [15, 349], [16, 334], [17, 330], [18, 326], [19, 322], [20, 318], [21, 314], [22, 310], [23, 306], [24, 302], [25, 298], [26, 294], [27, 289], [28, 285], [29, 281], [30, 277], [31, 273], [32, 269], [33, 268], [34, 266], [35, 265], [36, 263], [37, 262], [38, 260], [39, 259], [40, 257], [41, 256], [42, 254], [43, 253], [44, 251], [45, 250], [46, 248], [47, 247], [48, 245], [49, 244], [50, 242], [51, 241], [52, 239], [53, 238], [54, 236], [55, 235], [56, 233], [57, 232], [58, 231], [59, 229], [60, 228], [61, 226], [62, 225], [63, 223], [64, 222], [65, 221], [66, 220], [67, 219], [68, 219], [69, 218], [70, 217], [71, 216], [72, 216], [73, 215], [74, 214], [75, 213], [76, 213], [77, 212], [78, 211], [79, 211], [80, 210], [81, 209], [82, 208], [83, 208], [84, 207], [85, 206], [86, 205], [87, 205], [88, 204], [89, 203], [90, 202], [91, 202], [92, 201], [93, 200], [94, 199], [95, 199], [96, 198], [97, 197], [98, 196], [99, 196], [100, 195], [101, 194], [102, 193], [103, 193], [104, 192], [105, 191], [106, 191], [107, 190], [108, 189], [109, 188], [110, 188], [111, 187], [112, 186], [113, 185], [114, 185], [115, 184], [116, 183], [117, 182], [118, 182], [119, 181], [120, 180], [121, 179], [122, 179], [123, 178], [124, 177], [125, 176], [126, 176], [127, 175], [128, 174]]max_discount = 174(即k > 128时折扣固定在 174)。
解读:折扣值随k增大而递减(1200 → 174),表示规模越大单位点成本越低。注意k=1时 discount 为1200,乘以乘法成本再除以 1000 后恰好约等于一次 G1/G2 乘法成本,与"单点多标量乘退化为普通乘法"的直觉一致。之所以把k=1的折扣设为1200而非1000,从折扣表结构看是为了保证公式在k=1时成本不低于单次乘法(12000 × 1200 / 1000 = 14400,略高于 12000,避免用 MULTIEXP 绕过 MUL 定价),可结合该公式自行推导验证。
6.2 配对运算
pairing_cost = 55000 * k + 65000其中k为配对点对的数量:每增加一对 G1/G2 点对,成本线性增加55000,另有固定开销65000。
6.3 多标量乘为何值得单独设计
Rationale 一节给出了量化理由:CALL操作本身在以太坊中(写作时)相当昂贵。若对 100 个点做多标量乘而不得不调用 100 次乘法预编译 + 99 次加法预编译,将产生不可忽视的 CALL 开销;而独立的 MULTIEXP 预编译可节省约138600Gas(即省去 199 次 CALL 的开销)。这解释了为什么提案坚持将多标量乘作为独立操作而非让用户在链上自行组合。
七、向后兼容与实现要点
7.1 向后兼容
提案声明"不存在向后兼容性问题"——9 个预编译全部使用新地址(0x15~0x1d),不改变任何既有预编译或操作码语义。这与 EIP-1962(其声明"可能作为现有ECADD、ECMUL、配对检查预编译0x06/0x07/0x08的完整替代")形成对比:本 EIP 采取纯新增、零冲突的策略。
7.2 重要实现注意点:子群检查
- 配对调用中子群检查是强制的;
- 实现应该使用快速子群检查:提案写作时,乘法 Gas 成本基于
double-and-add乘法方法(其"最坏情况"是标量所有比特均为 1)。对配对操作,预期实现采用更快的子群检查,例如椭圆曲线wNAF 乘法方法——窗口大小为 4 时大约便宜40%(经经验测试;节省源于群阶更低的汉明重量以及 wNAF 更低的汉明重量); - 具体而言,一对 (G1, G2) 点的子群检查合计约
35000Gas。
7.3 参考实现
提案列出了可直接参考的既有曲线运算实现(可能需额外工作以适配本 ABI):
- 固定参数代码库:matter-labs 的 Rust 与 C++ 实现;
- Zexe 论文原始实现:Rust,github.com/scipr-lab/zexe;
- 独立 Go 实现:github.com/kilic/bls12-377。
作为对照,仓库内 EIPS/eip-1962.md 的基准数据显示:matter-labs 使用 Peppinger 算法实现的 BN254 多标量乘(bench_peppinger_bn254)约为2,678,743 ns/iter,明显优于朴素多标量乘(bench_naive_multiexp_bn254约10,659,911 ns/iter),从侧面印证了本 EIP 选择 Peppinger 算法的性能合理性。
八、测试属性(Test Cases)
由于测试参数空间巨大,提案不提供穷举测试向量,而是规定各操作必须满足的数学性质。记号约定:大写字母P、Q表示点,小写字母a、b表示标量;G1 生成元记为G,G2 生成元记为H;0表示零标量或无穷远点,1表示单位标量或乘法单位元;group_order为主子群阶;e(P, Q)表示配对。
基础操作(加法/乘法)必满足的性质:
- 交换律:
P + Q = Q + P - 加法逆元:
P + (-P) = 0 - 倍点:
P + P = 2*P - 子群检查:
group_order * P = 0 - 平凡乘法:
1 * P = P - 零乘:
0 * P = 0 - 未归一化标量乘法:
(scalar + group_order) * P = scalar * P
最后一条性质与编码规则中"标量不要求 ≤ 主子群阶"的设计相呼应,验证实现必须正确处理标量模group_order归约。
配对操作必满足的性质:
- 退化性(Degeneracy):
e(P, 0*Q) = e(0*P, Q) = 1 - 双线性(Bilinearity):
e(a*P, b*Q) = e(a*b*P, Q) = e(P, a*b*Q)(内部测试,不通过 ABI 暴露)
提案注明:所有操作的测试向量在 matter-labs 的 1962 提案所附 CSV 文件中展开,即与本仓库 EIPS/eip-1962.md 的测试体系同源。
九、安全考量
- 严格遵循本规范即可消除安全与共识层面的隐患(相对此前的 BN254 预编译而言),因为编码、子群检查、错误处理都有明确且统一的强制约定;
- 关于"常数时间(constant time)"属性,提案明确声明本预编译不要求所有操作都使用常数时间算法实现——这与签名场景中密钥隔离(side-channel)需求由上层方案自行权衡的设计取向一致。
十、总结与延伸阅读
EIP-2539 是一份规格完整的 Core 类预编译提案:它以 9 个新地址(0x15~0x1d)提供 BLS12-377 曲线的全套运算,用严格的字节编码规范、逐操作 ABI、Peppinger 多标量乘折扣表与 DDoS 防护式错误处理,为 120+ bit 安全强度的 BLS 签名验证与 SNARK 验证提供了 EVM 内的高效原语。它也是后续 EIP-3026(BW6-761 外层曲线,requires: 2539)实现单层 SNARK 证明组合的底层支撑。
若想深入理解本主题在仓库中的全貌,建议继续阅读:
- EIPS/eip-2537.md:已 Final 的 BLS12-381 预编译(同族曲线的另一路线与地址分配);
- EIPS/eip-1962.md:matter-labs 的通用曲线预编译提案(含 BLS12-377 支持与配对基准数据);
- EIPS/eip-3026.md:依赖本 EIP 的 BW6-761 预编译(证明组合场景);
- EIPS/eip-1109.md 与 EIPS/eip-2046.md:本 EIP
requires的两个提案,分别针对预编译 CALL 成本与 STATICCALL 成本优化,是理解预编译生态经济模型的关键背景。
本文所有技术事实均来自 EIPS/eip-2539.md 原文及其在本仓库中的关联提案;该 EIP 状态为 Stagnant,尚未在任何以太坊主网激活,文中 Gas 价格与地址分配均为提案设计值,实际部署以最终激活版本为准。
【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考