揭秘新型零知識(shí)證明漏洞:算術(shù)運(yùn)算后缺乏多項(xiàng)式標(biāo)準(zhǔn)化
Salus 向 0xPARC 的 zk-bug-tracker 庫添加了一種新型的 ZK 漏洞,算術(shù)運(yùn)算后缺乏多項(xiàng)式標(biāo)準(zhǔn)化, 該漏洞由以太坊基金會(huì) PSE 安全團(tuán)隊(duì)負(fù)責(zé)人 Kyle Charbonnet 審核。該漏洞會(huì)破壞假設(shè)并導(dǎo)致錯(cuò)誤的計(jì)算,或者導(dǎo)致通過 rust panic 進(jìn)行的拒絕服務(wù)攻擊。為了更好地理解這個(gè)漏洞,我們將以 Zendoo 庫中的一個(gè)具體實(shí)例進(jìn)行說明。請(qǐng)大家對(duì)此類漏洞保持警惕。
1. 背景
在代碼中,多項(xiàng)式被表示為向量的形式。即,多項(xiàng)式 a0+a1x+...+an-1xn-1+an*xn 被表示為[a0,a1,...,an-1,an]。在 ZK 證明系統(tǒng)中,需要對(duì)多項(xiàng)式進(jìn)行標(biāo)準(zhǔn)化操作,即將多項(xiàng)式的最高次項(xiàng)的系數(shù)調(diào)整為非零。比如,將[1,2,0]調(diào)整為[1,2]才是標(biāo)準(zhǔn)化的多項(xiàng)式表示。
對(duì)多項(xiàng)式進(jìn)行標(biāo)準(zhǔn)化操作是必要的。如果不進(jìn)行標(biāo)準(zhǔn)化,系統(tǒng)會(huì)錯(cuò)誤地存儲(chǔ)多項(xiàng)式的最高次數(shù),即它會(huì)大于其實(shí)際的最高次數(shù)。比如,對(duì)于[1,2,0],如果不進(jìn)行標(biāo)準(zhǔn)化操作,它的最高次數(shù)會(huì)被錯(cuò)誤地存儲(chǔ)為 2,而實(shí)際是 1。基于非標(biāo)準(zhǔn)化的多項(xiàng)式生成證明時(shí),錯(cuò)誤的多項(xiàng)式實(shí)現(xiàn)將會(huì)使得 ZK 證明系統(tǒng) panic,導(dǎo)致無法生成證明。
2. 案例分析
算術(shù)運(yùn)算后缺乏多項(xiàng)式標(biāo)準(zhǔn)化,該漏洞屬于 ZK 證明系統(tǒng)實(shí)現(xiàn)上的通用性漏洞。以下,我們以 Zendoo 庫中用于快速傅里葉變換(FFT)的密集多項(xiàng)式(dense polynomials)實(shí)現(xiàn)的代碼為例,說明其中存在的算術(shù)運(yùn)算后缺乏多項(xiàng)式標(biāo)準(zhǔn)化的漏洞。
add() 函數(shù)是用來對(duì)兩個(gè)密集多項(xiàng)式(self 和 other)進(jìn)行加法運(yùn)算的,加法運(yùn)算的結(jié)果(result)也是一個(gè)密集多項(xiàng)式,這需要進(jìn)行標(biāo)準(zhǔn)化。然而,該函數(shù)僅在最后一個(gè)分支處對(duì) result 進(jìn)行了標(biāo)準(zhǔn)化操作(19-21 行)。該函數(shù)默認(rèn)在前三個(gè)分支出計(jì)算得到的 result 就是標(biāo)準(zhǔn)化的,但這是不合理的。比如,當(dāng) self 是[1,2,3],other 是[1,2,-3],此時(shí)滿足第三個(gè)分支(7-12 行),即 self 和 other 這兩個(gè)多項(xiàng)式最高次數(shù)相等,都是 2。而在第三個(gè)分支處計(jì)算后的 result 是[2,4,0],并未對(duì)其進(jìn)行標(biāo)準(zhǔn)化操作。
非標(biāo)準(zhǔn)化的多項(xiàng)式在之后的計(jì)算過程中會(huì)產(chǎn)生錯(cuò)誤。具體的實(shí)現(xiàn)代碼如下:
而且,在這段代碼中,不只是在加法算法后缺乏多項(xiàng)式標(biāo)準(zhǔn)化。在加法運(yùn)算前,self 和 other 作為 add() 函數(shù)的入?yún)?,也并沒有檢查他們是否是標(biāo)準(zhǔn)化的多項(xiàng)式表示?;蛘哒f,構(gòu)造 self 和 other 的函數(shù)是否是按照標(biāo)準(zhǔn)化的方法進(jìn)行構(gòu)建的,也未可知。degree() 函數(shù)用來返回多項(xiàng)式的最高次項(xiàng)的指數(shù)。在 add() 函數(shù)中,非標(biāo)準(zhǔn)化的 self 和 other 在調(diào)用 degree() 函數(shù)時(shí)會(huì)引起 rust panic。
舉個(gè)例子,self 是非標(biāo)準(zhǔn)化的多項(xiàng)式 1+2x+0x2,即向量[1,2,0],其最高次項(xiàng)的系數(shù)為 0。當(dāng) other 也不是零多項(xiàng)式時(shí),滿足 add() 函數(shù)的第三個(gè)分支,以 self 來調(diào)用 degree() 函數(shù)。在 degree() 函數(shù)中進(jìn)入 else 分支。在 else 分支中有一個(gè) assert! 宏,用來確保多項(xiàng)式的最高次數(shù)的系數(shù)不為 0。如果為 0,self.coeffs.last().map_or(false, |coeff| !coeff.is_zero()) 表達(dá)式結(jié)果為 false。即 self 向量的最后一個(gè)元素,即多項(xiàng)式的最高次項(xiàng)的系數(shù)為 0,返回 false。此時(shí),assert! 宏會(huì) panic。
Rust panic 會(huì)導(dǎo)致 ZK 證明系統(tǒng)遭受 DOS 攻擊。攻擊者可以通過構(gòu)造大量的非標(biāo)準(zhǔn)化多項(xiàng)式,并且不斷調(diào)用 add() 函數(shù)。由于這些輸入會(huì)導(dǎo)致程序 panic,所以程序會(huì)不斷地停止并重啟。這將占用大量的計(jì)算和網(wǎng)絡(luò)資源,從而影響到其他正常用戶的使用,這就構(gòu)成了一種 DOS 攻擊。
3. 總結(jié)
Salus 在 0xPARC 的 zk-bug-tracker 庫中添加的新型 ZK 漏洞,即算術(shù)運(yùn)算后缺乏多項(xiàng)式標(biāo)準(zhǔn)化,是具有通用性的。在 ZK 證明系統(tǒng)中,我們需要特別注意避免該漏洞。該漏洞會(huì)造成 ZK 證明系統(tǒng)的計(jì)算錯(cuò)誤,或使系統(tǒng)遭受 DOS 攻擊??梢栽诜祷厮阈g(shù)運(yùn)算結(jié)果之前調(diào)用truncate_leading_zeros()函數(shù)進(jìn)行標(biāo)準(zhǔn)化操作,同時(shí),基于from_coefficients_vec()函數(shù)來構(gòu)造標(biāo)準(zhǔn)化的多項(xiàng)式也是必要的。
針對(duì)此漏洞,Salus 團(tuán)隊(duì)提醒 ZK 項(xiàng)目方,在構(gòu)建多項(xiàng)式時(shí)和執(zhí)行多項(xiàng)式操作之后對(duì)其進(jìn)行標(biāo)準(zhǔn)化,以免破壞 ZK 證明系統(tǒng)的完整性。同時(shí),強(qiáng)烈建議項(xiàng)目方在項(xiàng)目上線之前,尋求專業(yè)的安全審計(jì)公司進(jìn)行充分的安全審計(jì),確保項(xiàng)目安全。