国产麻豆精品福利在线观看,亚洲人亚洲精品成人网站,亚洲熟妇无码AV另类VR影视,欧美A级毛欧美1级A大片免费播放

您的位置:首頁 > 區(qū)塊鏈 >

zkSNARKs可能有雙花漏洞 可修改證明繞過防雙花檢

2019-07-30 11:46:38 來源: 巴比特

大量零知識證明項目由于錯誤地使用了某個 zkSNARKs 合約庫,引入「輸入假名 (Input Aliasing) 」漏洞,可導(dǎo)致偽造證明、雙花、重放等攻擊行為

大量零知識證明項目由于錯誤地使用了某個 zkSNARKs 合約庫,引入「輸入假名 (Input Aliasing) 」漏洞,可導(dǎo)致偽造證明、雙花、重放等攻擊行為發(fā)生,且攻擊成本極低。眾多以太坊社區(qū)開源項目受影響,其中包括三大最常用的 zkSNARKs 零知開發(fā)庫 snarkjs、ethsnarks、ZoKrates,以及近期大熱的三個混幣(匿名轉(zhuǎn)賬)應(yīng)用 hopper、Heiswap、Miximus。這是一場由 Solidity 語言之父 Chris 兩年前隨手貼的一段代碼而引發(fā)的血案。

雙花漏洞:最初暴露的問題

semaphore 是一個使用零知識證明技術(shù)的匿名信號系統(tǒng),該項目由著名開發(fā)者 barryWhiteHat 此前的混幣項目演化而來。

俄羅斯開發(fā)者 poma 最先指出該項目可能存在雙花漏洞[1]。

問題出在第 83 行代碼[2],請仔細(xì)看。

該函數(shù)需要調(diào)用者構(gòu)造一個零知識證明,證明自己可從合約中提走錢。為了防止「雙花」發(fā)生,該函數(shù)還讀取「廢棄列表」,檢查該證明的一個指定元素是否被標(biāo)記過。如果該證明在廢棄列表中,則合約判定校驗不通過,調(diào)用者無法提走錢。開發(fā)者認(rèn)為,這樣一來相同的證明就無法被重復(fù)提交獲利,認(rèn)為此舉可以有效防范雙花或重放攻擊。

然而事與愿違,這里忽視了一個致命問題。攻擊者可根據(jù)已成功提交的證明,利用「輸入假名」漏洞,對原輸入稍加修改便能迅速「偽造證明」,順利通過合約第 82 行的零知識證明校驗,并繞過第 83 行的防雙花檢查。

該問題最早可追溯到 2017 年,由 Christian Reitwiessner 大神,也就是 Solidity 語言的發(fā)明者,提供的 zkSNARKs 合約密碼學(xué)實現(xiàn)示例[3]。其后,幾乎以太坊上所有使用 zkSNARKs 技術(shù)的合約,都照用了該實現(xiàn)。因此都可能遭受以下流程的攻擊。

混幣應(yīng)用:該安全問題的重災(zāi)區(qū)

零知識證明技術(shù)在以太坊上最早和最廣泛的應(yīng)用場景是混幣合約,或匿名轉(zhuǎn)賬、隱私交易。由于以太坊本身不支持匿名交易,而社區(qū)對于隱私保護(hù)的呼聲越來越強烈,因此涌現(xiàn)出不少熱門項目。這里以混幣合約的應(yīng)用場景為例,介紹「輸入假名」漏洞對零知項目的安全威脅。

混幣合約或匿名轉(zhuǎn)賬涉及兩個要點:

證明自己有一筆錢

證明這筆錢沒有花過

為了方便理解,這里簡單描述一下流程:

A 要花一筆錢。

A 要證明自己擁有這筆錢。A 出示一個 zkproof,證明自己知道一個 hash (HashA) 的 preimage,且這個 hash 在以 root 為標(biāo)志的 tree 的葉子上,且證明這個 preimage 的另一種 hash 是 HashB。其中 HashA 是 witness,HashB 是 public statement。由于 A 無需暴露 HashA,所以是匿名的。

合約校驗 zkproof,并檢查 HashB 是否在廢棄列表中。若不在,則意味著這筆錢未花過,可以花(允許 A 的此次調(diào)用)。

如果可以花,合約需要把 HashB 放入廢棄列表中,標(biāo)明以 HashB 為代表的錢已經(jīng)被花過,不能再次花了。

上面代碼中的第 82 行 verifyProof(a, b, c, input) 用來證明這筆錢的合法性,input[] 是 public statement,即公共參數(shù)。第 83 行通過 require(nullifiers_set[input[1]] == false) 校驗這筆錢是否被花過。

很多 zkSNARKs 合約尤其是混幣合約,核心邏輯都與第 82 行和 83 行類似,因此都存在同樣的安全問題,可利用「輸入假名」漏洞進(jìn)行攻擊。

漏洞解析:一筆錢如何匿名地重復(fù)花 5 次?

上面 verifyProof(a, b, c, input) 函數(shù)的作用是根據(jù)傳入的數(shù)值在橢圓曲線上進(jìn)行計算校驗,核心用到了名為 scalar_mul() 的函數(shù),實現(xiàn)了橢圓曲線上的標(biāo)量乘法[4]。

/// @return the product of a point on G1 and a scalar, i.e.

/// p == p.scalar_mul(1) and p.add(p) == p.scalar_mul(2) for all points p.

function scalar_mul(G1Point point, uint s) internal returns (G1Point r) {

uint[3] memory input;

input[0] = p.X;

input[1] = p.Y;

input[2] = s;

bool success;

assembly {

success := call(sub(gas, 2000), 7, 0, input, 0x80, r, 0x60)

// Use "invalid" to make gas estimation work

switch success case 0 { invalid() }

}

require (success);

}

我們知道以太坊內(nèi)置了多個預(yù)編譯合約,進(jìn)行橢圓曲線上的密碼學(xué)運算,降低 zkSNARKs 驗證在鏈上的 Gas 消耗。函數(shù) scalar_mul() 的實現(xiàn)則調(diào)用了以太坊預(yù)編譯 7 號合約,根據(jù)EIP 196實現(xiàn)了橢圓曲線 alt_bn128 上的標(biāo)量乘法[5]。下圖為黃皮書中對該操作的定義,我們常稱之為 ECMUL 或 ecc_mul。

密碼學(xué)中,橢圓曲線的 {x,y} 的值域是一個基于 mod p 的有限域,這個有限域稱之為 Zp 或 Fp。也就是說,一個橢圓曲線上的一個點 {x,y} 中的 x,y 是 Fp 中的值。一條橢圓曲線上的某些點構(gòu)成一個較大的循環(huán)群,這些點的個數(shù)稱之為群的階,記為q?;跈E圓曲線的加密就在這個循環(huán)群中進(jìn)行。如果這個循環(huán)群的階數(shù)(q)為質(zhì)數(shù),那么加密就可以在 mod q 的有限域中進(jìn)行,該有限域記作 Fq。

一般選取較大的循環(huán)群作為加密計算的基礎(chǔ)。在循環(huán)群中,任意選定一個非無窮遠(yuǎn)點作為生成元 G(通常這個群的階q是個大質(zhì)數(shù),那么任選一個非零點都是等價的),其他所有的點都可以通過 G+G+.... 產(chǎn)生出來。這個群里的元素個數(shù)為 q,也即一共有 q 個點,那么我們可以用 0,1,2,3,....q-1 來編號每一個點。在這里第 0 個點是無窮遠(yuǎn)點,點1 就是剛才提到的那個 G,也叫做基點。點2 就是 G+G,點3 就是 G+G+G。

于是當(dāng)要表示一個點的時候,我們有兩種方式。第一種是給出這個點的坐標(biāo) {x,y},這里 x,y 屬于Fp。第二種方式是用 n*G 的方式給出,由于 G 是公開的,于是只要給出 n 就行了。n 屬于 Fq。

看一下 scalar_mul(G1Point point, uint s) 函數(shù)簽名,以 point 為生成元,計算 point+point+.....+point,一共 n 個 point 相加。這屬于使用上面第二種方法表示循環(huán)群中的一個點。

在 Solidity 智能合約實現(xiàn)中需要使用 uint256 類型來編碼 Fq,但 uint256 類型的最大值是大于q 值,那么 會出現(xiàn)這樣一種情況:在 uint256 中有多個數(shù) 經(jīng)過 mod 運算之后都會對應(yīng)到同一個 Fq中的值。比如 s 和 s + q 表示的其實是同一個點,即第s個點。這是因為在循環(huán)群中點q 其實等價于 點0(每個點分別對應(yīng) 0,1,2,3,....q-1)。同理,s + 2q 等均對應(yīng)到點s 。我們把可以輸入多個大整數(shù)會對應(yīng)到同一個 Fq中的值 這一現(xiàn)象稱作「輸入假名」,即這些數(shù)互為假名。

以太坊 7 號合約實現(xiàn)的橢圓曲線是 y^2 = ax^3+bx+c。p 和 q 分別如下。

這里的 q 值即上文中提到的群的階數(shù)。那么在 uint256 類型范圍內(nèi),共有 uint256_max / q 個,算下來也就是最多會有 5 個整數(shù)代表同一個點( 5 個「輸入假名」)。

這意味著什么呢?讓我們回顧上面調(diào)用 scalar_mul(G1Point point, uint s) 的 verifyProof(a, b, c, input) 函數(shù),input[] 數(shù)組里的每個元素實際就是 s。對于每個 s,在 uint256 數(shù)據(jù)類型范圍內(nèi),會最多存在其他 4 個值,傳入后計算結(jié)果與原值一致。

因此,當(dāng)用戶向合約出示零知識證明進(jìn)行提現(xiàn)后,合約會把 input[1] (也就是某個 s)放入作廢列表。用戶(或其他攻擊者)還可以使用另外 4 個值再次進(jìn)行證明提交。而這 4 個值之前并沒有被列入「廢棄列表」,因此“偽造”的證明可以順利通過校驗,利用 5 個「輸入假名」一筆錢可以被重復(fù)花 5 次,而且攻擊成本非常低!

還有更多受影響的項目

存在問題的遠(yuǎn)遠(yuǎn)不止 semaphore 一個。其他很多以太坊混幣項目以及 zkSNARKs 項目都存在同樣的允許「輸入假名」的問題。

這些項目在社區(qū)熱度都十分高,其中 Heiswap 更是被人們稱為 「Vitalik 最喜愛的項目」。

這當(dāng)中,影響最大的要數(shù)幾個大名鼎鼎的 zkSNARKs 庫或框架項目,包括 snarkjs、ethsnarks、ZoKrates 等。許多應(yīng)用項目會直接引用或參考他們的代碼進(jìn)行開發(fā),從而埋下安全隱患。因此,上述三個項目迅速進(jìn)行了安全修復(fù)更新。另外,多個利用了 zkSNARKs 技術(shù)的知名混幣項目,如 hopper、Heiswap、Miximus 也立刻進(jìn)行了同步修復(fù)。

「輸入假名」漏洞的解決方案

事實上,所有使用了該 zkSNARKs 密碼學(xué)合約庫的項目都應(yīng)該立即開展自查,評估是否受影響。那么應(yīng)該如何修復(fù)這個問題?

所幸的是,修復(fù)很簡單。僅需在驗證函數(shù)中添加對輸入?yún)?shù)大小的校驗,強制要求 input 值小于上面提到的 q 值。即嚴(yán)禁「輸入假名」,杜絕使用多個數(shù)表示同一個點。

暴露的深層問題值得反思

該「輸入假名」導(dǎo)致的安全漏洞值得社區(qū)認(rèn)真反思。我們再回顧一下整個故事。2017 年 Christian 在 Gist 網(wǎng)站貼出了自己的 zkSNARKs 合約計算實現(xiàn)。作為計算庫,我們可以認(rèn)為他的實現(xiàn)并沒有安全問題,沒有違反任何密碼學(xué)常識,完美地完成了在合約中進(jìn)行證明驗證的工作。

事實上,作為 Solidity 語言的發(fā)明者,Christian 在這里當(dāng)然不會犯任何低級錯誤。而兩年后的今天,這段代碼卻引發(fā)了如此的安全風(fēng)波。兩年多的時間內(nèi),可能有無數(shù)同行和專家看過或使用過這段只有兩百多行的代碼,卻沒有發(fā)現(xiàn)任何問題。

核心問題出在哪里?可能出在底層庫的實現(xiàn)者和庫的使用者雙方間對于程序接口的理解出現(xiàn)了偏差。換句話說:底層庫的實現(xiàn)者對于應(yīng)用開發(fā)者的不當(dāng)使用方式欠缺考慮;而上層應(yīng)用開發(fā)者沒有在使用中沒有深入理解底層實現(xiàn)原理和注意事項,進(jìn)行了錯誤的安全假設(shè)。

所幸的是,目前常見的 zkSNARKs 合約庫都火速進(jìn)行了更新,從底層庫層面杜絕「輸入假名」。安比(SECBIT)實驗室認(rèn)為,底層庫的更新誠然能夠很大程度上消除掉后續(xù)使用者的安全隱患,但若該問題的嚴(yán)重性沒有得到廣泛地宣傳和傳播,依舊會有開發(fā)者不幸使用到錯誤版本的代碼,或者是根據(jù)錯誤的教程進(jìn)行開發(fā)(就像因為整數(shù)溢出而歸零的那些 Token 一樣),從而埋下安全隱患。

「輸入假名」漏洞不禁讓我們回想起此前頻繁曝出的「整數(shù)溢出」漏洞。二者相似之處頗多:都是源于大量開發(fā)者的錯誤假設(shè);都與 Solidity 里的 uint256 類型有關(guān);波及面都十分廣;網(wǎng)絡(luò)上也都流傳著很多存在隱患的教程代碼或者庫合約。

但顯然「輸入假名」漏洞顯然更難檢測,潛伏時間更長,需要的背景知識更多(涉及到復(fù)雜的橢圓曲線和密碼學(xué)理論)。安比(SECBIT)實驗室認(rèn)為,隨著 zkSNARKs、零知識證明應(yīng)用、隱私技術(shù)的興起,社區(qū)會涌現(xiàn)出更多的新應(yīng)用,而背后暗藏的更多安全威脅可能會進(jìn)一步暴露出來。希望這波新技術(shù)浪潮中,社區(qū)能充分吸收以往的慘痛教訓(xùn),重視安全問題。(作者:p0n1)

關(guān)鍵詞: zkSNARKs 雙花漏洞 證明

精選 導(dǎo)讀

募資55億港元萬物云啟動招股 預(yù)計9月29日登陸港交所主板

萬科9月19日早間公告,萬物云當(dāng)日啟動招股,預(yù)計發(fā)行價介乎每股47 1港元至52 7港元,預(yù)計9月29日登陸港交所主板。按發(fā)行1 167億股計算,萬

發(fā)布時間: 2022-09-20 10:39
管理   2022-09-20

公募基金二季度持股情況曝光 隱形重倉股多為高端制造業(yè)

隨著半年報披露收官,公募基金二季度持股情況曝光。截至今年二季度末,公募基金全市場基金總數(shù)為9794只,資產(chǎn)凈值為269454 75億元,同比上

發(fā)布時間: 2022-09-02 10:45
資訊   2022-09-02

又有上市公司宣布變賣房產(chǎn) 上市公司粉飾財報動作不斷

再有上市公司宣布變賣房產(chǎn)。四川長虹25日稱,擬以1 66億元的轉(zhuǎn)讓底價掛牌出售31套房產(chǎn)。今年以來,A股公司出售房產(chǎn)不斷。根據(jù)記者不完全統(tǒng)

發(fā)布時間: 2022-08-26 09:44
資訊   2022-08-26

16天12連板大港股份回復(fù)深交所關(guān)注函 股份繼續(xù)沖高

回復(fù)交易所關(guān)注函后,大港股份繼續(xù)沖高。8月11日大港股份高開,隨后震蕩走高,接近收盤時觸及漲停,報20 2元 股。值得一提的是,在7月21日

發(fā)布時間: 2022-08-12 09:56
資訊   2022-08-12

萬家基金再添第二大股東 中泰證券擬受讓11%基金股權(quán)

7月13日,中泰證券發(fā)布公告,擬受讓齊河眾鑫投資有限公司(以下簡稱齊河眾鑫)所持有的萬家基金11%的股權(quán),交易雙方共同確定本次交易的標(biāo)的資

發(fā)布時間: 2022-07-14 09:39
管理   2022-07-14

央行連續(xù)7日每天30億元逆回購 對債市影響如何?

央行12日再次開展了30億元逆回購操作,中標(biāo)利率2 10%。這已是央行連續(xù)7日每天僅進(jìn)行30億元的逆回購縮量投放,創(chuàng)下去年1月以來的最低操作規(guī)

發(fā)布時間: 2022-07-13 09:38
資訊   2022-07-13

美元指數(shù)創(chuàng)近20年新高 黃金期貨創(chuàng)出逾9個月新低

由于對美聯(lián)儲激進(jìn)加息的擔(dān)憂,美元指數(shù)11日大漲近1%創(chuàng)出近20年新高。受此影響,歐美股市、大宗商品均走弱,而黃金期貨創(chuàng)出逾9個月新低。美

發(fā)布時間: 2022-07-13 09:36
資訊   2022-07-13

美股三大股指全線下跌 納斯達(dá)克跌幅創(chuàng)下記錄以來最大跌幅

今年上半年,美股持續(xù)回落。數(shù)據(jù)顯示,道瓊斯指數(shù)上半年下跌15 3%,納斯達(dá)克綜合指數(shù)下跌29 5%,標(biāo)普500指數(shù)下跌20 6%。其中,納斯達(dá)克連續(xù)

發(fā)布時間: 2022-07-04 09:51
推薦   2022-07-04

融資客熱情回升 兩市融資余額月內(nèi)增加超344億元

近期A股走強,滬指6月以來上漲4%,融資客熱情明顯回升。數(shù)據(jù)顯示,截至6月16日,兩市融資余額1 479萬億元,月內(nèi)增加344 67億元,最近一個半

發(fā)布時間: 2022-06-20 09:41
資訊   2022-06-20

4個交易日凈買入超百億元 北向資金持續(xù)流入A股市場

北向資金凈流入態(tài)勢延續(xù)。繼6月15日凈買入133 59億元后,北向資金6月16日凈買入44 52億元。自5月27日至今,除6月13日以外,北向資金累計凈

發(fā)布時間: 2022-06-17 09:37
推薦   2022-06-17