揭秘新型零知識證明漏洞:算術運算後缺乏多項式標準化

2024年2月6日 20点热度 0人点赞

Salus 向 0xPARC 的 zk-bug-tracker 庫添加了一種新型的 ZK 漏洞,算術運算後缺乏多項式標準化, 該漏洞由以太坊基金會 PSE 安全團隊負責人 Kyle Charbonnet 審核。該漏洞會破壞假設並導致錯誤的計算,或者導致通過 rust panic 進行的拒絕服務攻擊。為了更好地理解這個漏洞,我們將以 Zendoo 庫中的一個具體實例進行說明。請大傢對此類漏洞保持警惕。

1. 背景

在代碼中,多項式被表示為向量的形式。即,多項式 a0 a1x ... an-1xn-1 an*xn 被表示為[a0,a1,...,an-1,an]。在 ZK 證明系統中,需要對多項式進行標準化操作,即將多項式的最高次項的系數調整為非零。比如,將[1,2,0]調整為[1,2]才是標準化的多項式表示。

對多項式進行標準化操作是必要的。如果不進行標準化,系統會錯誤地存儲多項式的最高次數,即它會大於其實際的最高次數。比如,對於[1,2,0],如果不進行標準化操作,它的最高次數會被錯誤地存儲為 2,而實際是 1。基於非標準化的多項式生成證明時,錯誤的多項式實現將會使得 ZK 證明系統 panic,導致無法生成證明。

2. 案例分析

算術運算後缺乏多項式標準化,該漏洞屬於 ZK 證明系統實現上的通用性漏洞。以下,我們以 Zendoo 庫中用於快速傅裡葉變換(FFT)的密集多項式(dense polynomials)實現的代碼為例,說明其中存在的算術運算後缺乏多項式標準化的漏洞。

add() 函數是用來對兩個密集多項式(self 和 other)進行加法運算的,加法運算的結果(result)也是一個密集多項式,這需要進行標準化。然而,該函數僅在最後一個分支處對 result 進行了標準化操作(19-21 行)。該函數默認在前三個分支出計算得到的 result 就是標準化的,但這是不合理的。比如,當 self 是[1,2,3],other 是[1,2,-3],此時滿足第三個分支(7-12 行),即 self 和 other 這兩個多項式最高次數相等,都是 2。而在第三個分支處計算後的 result 是[2,4,0],並未對其進行標準化操作。

非標準化的多項式在之後的計算過程中會產生錯誤。具體的實現代碼如下:

而且,在這段代碼中,不隻是在加法算法後缺乏多項式標準化。在加法運算前,self 和 other 作為 add() 函數的入參,也並沒有檢查他們是否是標準化的多項式表示。或者說,構造 self 和 other 的函數是否是按照標準化的方法進行構建的,也未可知。degree() 函數用來返回多項式的最高次項的指數。在 add() 函數中,非標準化的 self 和 other 在調用 degree() 函數時會引起 rust panic。

舉個例子,self 是非標準化的多項式 1 2x 0x2,即向量[1,2,0],其最高次項的系數為 0。當 other 也不是零多項式時,滿足 add() 函數的第三個分支,以 self 來調用 degree() 函數。在 degree() 函數中進入 else 分支。在 else 分支中有一個 assert! 宏,用來確保多項式的最高次數的系數不為 0。如果為 0,self.coeffs.last().map_or(false, |coeff| !coeff.is_zero()) 表達式結果為 false。即 self 向量的最後一個元素,即多項式的最高次項的系數為 0,返回 false。此時,assert! 宏會 panic。

Rust panic 會導致 ZK 證明系統遭受 DOS 攻擊。攻擊者可以通過構造大量的非標準化多項式,並且不斷調用 add() 函數。由於這些輸入會導致程序 panic,所以程序會不斷地停止並重啟。這將占用大量的計算和網絡資源,從而影響到其他正常用戶的使用,這就構成了一種 DOS 攻擊。

更多資訊,點擊資訊活動 - 航天雲網,國傢工業互聯網平臺