什么是zkSNARK攻擊
早上很多朋友@我,安比實(shí)驗(yàn)室發(fā)表了一篇文章zkSNARK的“輸入假名”的攻擊。迅速看了看,很贊。這個(gè)攻擊原理其實(shí)比較簡(jiǎn)單,但是,不深入理解zkSNARK以及使用場(chǎng)景的朋友確實(shí)很難發(fā)現(xiàn)和理解。本文講講我對(duì)這個(gè)攻擊的分析和理解。
源于三天前
這種攻擊方式一直潛伏著,沒(méi)被發(fā)現(xiàn)。直到三天前:
俄羅斯開(kāi)發(fā)者poma,在項(xiàng)目semaphore提交了一個(gè)issue,公開(kāi)了這個(gè)攻擊方法。poma同時(shí)也在kovan測(cè)試網(wǎng)絡(luò)驗(yàn)證了這種攻擊方式。
先從semaphore項(xiàng)目的代碼開(kāi)始:
話(huà)說(shuō),semaphore是個(gè)很有意思的項(xiàng)目,它提供了一套方法能讓用戶(hù)不暴露自己身份的情況下廣播消息。暫不深入介紹這個(gè)項(xiàng)目的內(nèi)容,直接看函數(shù)。broadcastSignal函數(shù)提交了證明,某個(gè)用戶(hù)發(fā)送某個(gè)消息(signal)。只有具體的某個(gè)broadcaster(server)才會(huì)調(diào)用這個(gè)函數(shù)。
signal - 廣播的消息內(nèi)容
a/b/c以及input - 是zkSNARK的證明以及公開(kāi)信息(statement信息)
函數(shù)實(shí)現(xiàn)(第82行),調(diào)用verifyProof函數(shù)驗(yàn)證證明以及statement信息是否是合理的證明。第83行,查看nullifier_hash是否被用過(guò)。
什么是Nullifier?
熟悉ZCash的朋友,估計(jì)對(duì)Nullifier比較熟悉。
為了保護(hù)交易的隱私,在鏈上只存儲(chǔ)Note和Nullifier對(duì)應(yīng)的hash信息。Note代表可以花的錢(qián),Nullifier表示某筆錢(qián)已經(jīng)消費(fèi)。Note和Nullifier一一對(duì)應(yīng),一個(gè)Note只存在一個(gè)Nullifier。通過(guò)zkSNARK生成證明,證明Note和Nullifier的正確性以及存在某種聯(lián)系。在鏈上,為了防止雙花,在執(zhí)行某個(gè)交易時(shí),必須確定某個(gè)Note是否已經(jīng)消費(fèi)。確定的方法就是記錄下Nullifier對(duì)應(yīng)的hash信息。
verifyProof的計(jì)算
verifyProof的函數(shù)實(shí)現(xiàn)在snarkjs項(xiàng)目的templates/verifier_groth.sol(以Groth16為例)。verifyProof只是個(gè)簡(jiǎn)單的wrapper,具體計(jì)算的實(shí)現(xiàn)時(shí)verify函數(shù)。
verify就是驗(yàn)證Groth16的驗(yàn)證等式是否成立,再看Groth16的驗(yàn)證等式:
其中橙色部分就是input,藍(lán)色部分就是vk.IC。scalar_mul是橢圓曲線(xiàn)的“標(biāo)量乘法”計(jì)算。vk.IC是橢圓曲線(xiàn)上的一個(gè)點(diǎn)(假設(shè)為P),input是個(gè)標(biāo)量(假設(shè)x)。scalar_mul(P, x) 表示為xP。如果橢圓曲線(xiàn)的階為q的話(huà),下面的等式成立:
(x+q)P = xP + qP = xP
也就是說(shuō),x+p和x作為input的話(huà),scalar_mul的計(jì)算結(jié)果相等。也就是說(shuō),Groth16的等式依然成立。
如何攻擊?
在智能合約中,輸入input是用uint表示。以太坊上一般采用bn254的曲線(xiàn),q為:
21888242871839275222246405745257275088548364400416034343698204186575808495617。雖然這個(gè)q比較大,但是,uint的最大值還是比q大不少。
攻擊方法就形成了:
在一個(gè)用戶(hù)提交了證明以及公開(kāi)的input信息后,攻擊者修改input中的nullifier_hash即可。雖然邏輯上在花費(fèi)同一筆錢(qián),但是,智能合約卻認(rèn)為是花費(fèi)不同的費(fèi)用。智能合約認(rèn)為一個(gè)Note只能對(duì)應(yīng)一個(gè)Nullfier,事實(shí)上,在這樣的情況下,一個(gè)Note對(duì)應(yīng)了多個(gè)Nullfier。
如何修復(fù)?
修復(fù)的方式有好多種,目前最簡(jiǎn)單的修復(fù)方式是在verify函數(shù)加限制:
限制input不能超過(guò)q。
總結(jié):
三天前,俄羅斯開(kāi)發(fā)者poma公開(kāi)了zkSNARK應(yīng)用模型下的一種攻擊方式。攻擊不需要重新生成證明信息,只需要修改Statement中Nullfier對(duì)應(yīng)的hash數(shù)據(jù)。原理是,橢圓曲線(xiàn)是個(gè)循環(huán)群,scalarMul計(jì)算在輸入的標(biāo)量加上橢圓曲線(xiàn)的階的情況下,結(jié)果相等。





