ZK 密碼學的數學推導互動指南:從零知識證明到底層電路設計

本文以互動式學習方式解析零知識證明的數學原理,跳過抽象的符號推導,用大量具體數字例子展示 zk-SNARKs 和 zk-STARKs 的運作原理。我們從 Schnorr 識別協議開始,逐步過渡到 R1CS 約束系統、多項式承諾、同態加密等核心概念,最後分析為什麼這些技術對 Layer 2 的發展至關重要。適合想要建立 ZK 密碼學直覺但被複雜數學符號阻擋的讀者。

ZK 密碼學的數學推導互動指南:從零知識證明到底層電路設計

老實說,當我第一次試圖理解零知識證明(Zero-Knowledge Proof)的時候,我完全被那些奇怪的希臘字母和代數符號給嚇退了。論文里到處都是「存在一個多項式時間的驗證者」和「滿足 soundness」之類的表述,搞得我頭昏腦脹。後來我決定換一種學習方式——不是從定義出發,而是從實際例子開始,慢慢往理論靠攏。

這篇文章就是我用這種方法整理出來的學習筆記。我會用大量具體的數字例子來展示零知識證明的運作原理,跳過大多數教程裡那些讓人望而卻步的符號推導。但別誤會,我並不是說理論不重要——恰恰相反,正是那些看似複雜的理論保證了 ZK 系統的安全性。我只是覺得先建立直覺再補理論,會讓整個過程輕鬆很多。

從「我是盲人,但我能區分硬幣」說起

讓我從一個流傳很廣的比喻開始。假設有一個盲人和兩枚硬幣,其中一枚是正面、另一枚是反面。盲人想知道這兩枚硬幣是否不同。你怎麼讓盲人相信它們確實不同,但又不需要讓他「看見」?

一個方法如下:你把兩枚硬幣放在桌上,讓盲人摸一下確認它們在桌上。然後你背過身去,隨機選擇翻轉其中一枚硬幣或不翻轉。接著盲人把兩枚硬幣放到你背後,讓你重複這個操作。

如果你每次都能正確說出自己翻了哪一枚(或者說了「我沒翻」),而盲人每次都能驗證你的回答是正確的,那麼經過足夠多次的測試之後,盲人就能非常有信心地相信這兩枚硬幣確實是不同的。因為如果你是在撒謊(硬幣其實是相同的),那麼有 50% 的機率你的回答會跟事實不符。經過 20 次測試之後,虛假聲明的機率就降低到了大約百萬分之一。

這個比喻完美地展示了零知識證明的三個核心特性:完整性(Completeness,真實證明者能說服驗證者)、可靠性(Soundness,撒謊者被發現的機率很高)、以及零知識性(Zero-Knowledge,驗證者除了「論述為真」之外什麼都不知道)。

橢圓曲線上的離散步驟

現在讓我把這個比喻翻譯成密碼學的語言。在以太坊使用的橢圓曲線密碼學(ECDSA)里,「硬幣是否相同」的問題被轉化成了「某個點是否在曲線上」的問題。具體來說,我們要證明的是:我知道某個秘密值 x,使得公鑰 P = x * G,其中 G 是曲線的生成點。

這裡的「翻轉硬幣」被替換成了「隨機選擇 r 並計算 R = r * G」。而「回答是否翻轉」被替換成了「計算挑戰值 e = hash(R, P, statement)」。整個互動過程可以濃縮成以下幾個步驟:

第一步:證明者隨機選擇一個值 v,計算 V = v * G,然後把 V 發送給驗證者。這類似於把硬幣放在桌上。

第二步:驗證者拋硬幣產生一個挑戰值 e(0 或 1)。這就是「翻轉或不翻轉硬幣」的動作。

第三步:證明者根據挑戰值計算回應。如果 e = 0,回應是 r = v;如果 e = 1,回應是 r = v + x。

第四步:驗證者檢查 r * G 是否等於 V(如果 e = 0)或 V + P(如果 e = 1)。這個檢查永遠為真,因為:

如果證明者不知道 x,他只能正確回應一種挑戰(e = 0 或 e = 1),但無法同時正確回應兩種。經過 n 輪互動之後,不知道 x 的機率降低到了 1/2^n。

Schnorr 識別協議:簡化版的非互動式證明

上面的三步驟互動式協議有一個問題:需要來回通信。在區塊鏈的應用場景裡,我們希望證明者能夠生成一個「一次性」的證明,不需要驗證者持續地在線互動。

Schnorr 協議解決了這個問題。它的核心思想是利用隨機種子(叫做「Common Reference String」或 CRS)把互動式協議轉化成非互動式的形式。

具體的做法是:

  1. 選擇一個哈希函數 H,其輸出作為隨機種子
  2. 把挑戰值從「驗證者拋硬幣」改為「e = H(P, V)」
  3. 證明者自己計算挑戰值,然後生成回應 r = v + e * x
  4. 驗證者檢查 r G = V + e P

這個轉換的巧妙之處在於:哈希函數的輸出在計算上可以認為是「隨機」的,即使它實際上是一個確定性函數的結果。只要哈希函數是抗碰撞的,攻擊者就無法事先預測 e 並構造假的 V 和 r。

從識別到論述:zk-SNARKs 的核心思想

Schnorr 協議只能證明「我知道某個秘密」,但我們真正想要的是證明「某個複雜的計算陳述是正確的」。這就需要把計算問題轉換成代數問題。

這個轉換的第一步是把計算過程用代數電路(Algebraic Circuit)表示。假設我們想要證明我們知道兩個數 a 和 b 使得 (a + b) * (a - b) = 143。我們可以把這個計算拆解成以下步驟:

在 R1CS(Rank-1 Constraint System)的框架里,每個乘法閘都產生一個約束。對於第三個閘來說,約束是 z = x * y。如果我們把所有的中間變數和輸出都寫成一個向量,然後定義這些向量之間的線性關係,我們就得到了一個可以提交給驗證者的「見證」(Witness)。

zk-SNARKs 的魔法在於它能把這麼一大堆約束打包成一個極小的證明。大小通常只有幾百個位元組,驗證時間也是常數級別,與原始計算的複雜度無關。這是怎麼做到的?答案涉及到多項式承諾(Polynomial Commitment)和同態加密(Homomorphic Encryption)的組合。

多項式承諾:把約束轉換成點值

想像你有兩個多項式 P(x) 和 Q(x),它們在除以某個多項式 T(x) 之後的餘項是相同的。如果我們能證明 P(x) 和 Q(x) 在一個隨機點 r 上的取值相同(P(r) = Q(r)),那麼在計算上可以相信這兩個多項式在整個域上大多是相等的。

這就是多項式承諾的基本思想。我們不直接驗證整個多項式相等與否,而是:

  1. 選擇一個隨機點 r
  2. 分別計算 P(r) 和 Q(r)
  3. 用密碼學承諾確保我們不能事後修改 P(r) 和 Q(r) 的值

在 Groth16 這個常見的 zk-SNARK 構造里,「承諾」是透過配對函數(Pairing)實現的。具體來說,如果我們有一個群 G1 和一個群 G2,以及一個配對 e: G1 × G2 → GT,那麼我們可以構造以下承諾形式:

C = g1^P(r) 其中 g1 是 G1 的生成元

驗證者檢查的是配對等式:

e(C, g2) = e(g1^Q(r), g2)

根據配對函數的性質,這個等式成立的條件是 P(r) = Q(r)。

實際數字的小型例子

讓我舉一個具體的數值例子來幫你理解這個過程。我們在很小的有限域上工作,選擇一個質數 p = 97(實際系統使用非常大的質數)。

假設我們想要證明我們知道一個值 x 使得 x^2 = 49。這是一個簡單的二次約束問題。

電路表示

設定階段(由可信第三方完成):

證明階段(由證明者完成):

驗證階段(由驗證者完成):

在實際系統中,這個過程被高度優化,以至於驗證一個涉及數百萬個約束的計算只需要幾百毫秒。

為什麼這對區塊鏈很重要

理解 ZK 密碼學的原理對評估 Layer 2 方案非常重要。不同的 ZK Rollup 項目選擇了不同的 zk-SNARK 構造,這些選擇直接影響了:

證明生成時間:Groth16 的證明生成很快,但需要可信設定且電路是電路特定的。PLONK 和它的衍生者(如 UltraPLONK)使用了通用設定,犧牲了一點效率但增加了靈活性。STARK 不需要任何設定,但證明大小通常更大。

驗證成本:在以太坊上,驗證一個 zk-SNARK 證明的 Gas 成本取決於配對操作的數量。優化這個成本是很多研究團隊的工作重點。

信任假設:有些系統(如 Groth16)需要一個「有毒廢料」(Toxic Waste)的信任假設——如果設定階段的隨機種子被洩露,攻擊者可以偽造任意證明。其他系統(如 STARK)只依賴於哈希函數的安全性。

結語:直覺先於形式化

寫這篇文章的時候,我一直在問自己一個問題:讀完這篇文章之後,你真的能夠設計一個 zk-SNARK 系統嗎?答案是當然不能——那需要好幾年的研究生訓練和大量的實踐經驗。

但我希望這篇文章能幫你建立一些有用的直覺:零知識證明不是魔法,它只是一種巧妙的密碼學技術組合;它讓「證明我知道某個秘密」這件事變得可驗證、但不可竊取;而這個特性打開了一個全新的應用空間,從 Rollup 到隱私保護再到可驗證計算。

如果你對這個領域感興趣,我建議你找一個實際的項目跟著教程做一遍。密碼學是一門需要動手的學問,光看書和論文是不夠的。


相關文章


參考資料

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。

目前尚無評論,成為第一個發表評論的人吧!