1. 程式人生 > >STARKs, Part I: 多項式證明

STARKs, Part I: 多項式證明

相信很多人都聽過ZK-SNARKS,一個通用而簡潔的零知識證明技術,從可驗證計算到需要隱私保護的加密貨幣,它可以被應用於各類場景。不過,可能你還不知道現在 ZK-SNARKs 有了一個新兄弟:ZK-STARKs. 這裡的 T 表示 “transparent”,“透明的”,ZK-STARKs 解決了 ZK-SNARKs 的一個主要的缺點,即 ZK-SNARKs 依賴於“可信啟動(trusted setup)”。ZK-STARKs 也帶來了更加簡單的密碼學假設,避免了使用橢圓曲線,配對和指數知識的假設(the knowledge-of-exponent assumption),並且完全地基於雜湊和資訊理論。這也意味著,即使是面對使用量子計算機的攻擊者,它仍然是安全的。

當然,這也是有代價的:一個證明的大小將從 288 位元組(b)上升到幾百 千位元組(kb)。儘管在某些情況下,這些代價可能並不十分划得來,不過在另一些場景下,尤其對於需要高度的信任最小化的區塊鏈應用,它可能是物有所值。而一旦橢圓曲線被破解,或者量子計算機真的到來的話,那麼它必然是非常值得的。

那麼,這種新的零知識證明到底是如何工作的呢?在這之前,先讓我們來回顧一下,簡潔通用的零知識證明做的是什麼事情。假設你現在有一個(公開,public)函式f,一個(私有,private)輸入x,和一個(公開,public)輸入y。在不透露 x 是什麼的情況下,你想要證明你知道有一個 x能夠使得f(x) = y(譯者注:比如有一個保險箱,你要在不透漏密碼具體是什麼的情況下,證明你確實知道這個保險箱的密碼)。此外,為了這個證明具有一定的簡潔性,相比於通過計算f 本身,你希望它能夠通過一種更快的方式進行驗證。

在這裡插入圖片描述

讓我們來討論幾個案例:

f是一個計算,它需要在一臺普通計算機上執行兩週,但是一個數據中心只需要兩小時即可完成。你可以把計算任務(也就是執行f的程式碼)傳送給資料中心,資料中心執行計算,然後返回答案,也就是y 證明。在幾毫秒之內你就可以完成驗證,並且可以確信y就是真實的答案。
你有一筆經過加密的交易,形式為 “X1 是我舊的餘額。X2 是你舊的餘額。X3 是我新的餘額。X4 是你新的餘額”。你想要構建一個證明,證明這筆交易是有效的(具體來說,證明舊的和新的餘額都是非負的,並且我的餘額減少量剛好是你的餘額增加量)。x 可能是一對加密金鑰,f可能是一個函式,這個函式包含了一個內建公開輸入的交易,輸入金鑰,解密交易,執行檢查,如果通過的話返回 1,否則返回 0。y 必然是 1 了。
你有一個像以太坊一樣的區塊鏈,並下載了最新的塊。你想要構造一個證明,證明這個塊是有效的,並且它是鏈上最新的塊,同時這個鏈裡面的每個塊都是有效的。你向一個已知的全節點詢問來提供這樣一個證明。x 是整個(全部?或者是部分)的區塊鏈,f 是一個按塊處理它的函式,驗證有效性並輸出上一個塊的雜湊,而 y就是你剛剛下載的塊雜湊。

在這裡插入圖片描述

那麼,對於所有這些案例,其困難之處在哪兒呢?事實證明,零知識(也就是隱私)保證是(相對!)容易提供的。有多種方式可以將任何計算轉換成一個類似三色圖問題的一種,圖的三著色與原始問題的解決方案有關,然後在不透露具體方案的情況下,使用一個傳統的零知識證明協議,來證明你有一個有效的圖色方案。這篇來自 Matthew Green 2014 年很棒的文章對其中細節做了闡釋。

更加困難的一件事情是簡潔性。直觀來講,簡潔地證明計算相關的事情十分困難,因為計算 極其脆弱。如果你有一個很長很複雜的計算,並且假設你有一種能夠在計算中間將任何一位(bit)從 0 變為 1 的能力,那麼在很多情況下,即使是僅僅改變其中某一位,也足夠使得計算產生一個完全不同的結果。因此,很難看出如何才能通過一些手段判定其正確性,比如隨機取樣一個計算軌跡,因為非常容易就會錯過那“邪惡的一位(one evil bit)”。不過,通過一些花哨的數學方法,可以證明其實你是可以做到的。

一般高層次的直覺是協議可以實現這一點,類似 擦除編碼 中使用的數學,它經常被用於使得資料具有容錯性。如果你有一些資料,並且將這些資料編碼為一條線,然後你可以從這條線上選出四個點。這四個點中的任意兩個都可以重建這條線,因此也會給你另外兩個點。進一步地,即使你對這些資料做出極微小的改變,然後保證這四個點的至少三個。你可以將這些資料編碼為一個 1,000,000 次多項式,然後在這個多項式上選出 2,000,000 個點,任意一個 1,000,001 個點都會恢復原始資料,繼而恢復其他點,原始資料的任何一點偏離都會改變至少 1,000,000 個點。這裡展示的演算法,大量通過這個途徑利用了多項式來進行錯誤放大。

一個簡單的例子

假設,你想要證明你有一個多項式 P,對於從 1 到 1 百萬之間的所有x,P(x) 是一個整數且0 <= P(x) <= 9。這是十分常見的 “範圍檢查” 的一個簡單示例。你可以把這種檢查想象成某種驗證,比如,在執行一些交易以後,一些賬戶餘額仍然是正數。如果 1 <= P(x) <= 9,這就可能是檢測一個正確的數獨解的一部分。

證明這個問題的“傳統” 方法是,遍歷所有的 1,000,000 點,逐個對值進行校驗來進行驗證。但是,我們想要知道是否我們能夠構造一個證明,它可以在小於 1,000,000 步的情況下得到驗證。簡單地隨機對 P 進行求值校驗無法做到這一點;總是有可能出現一個惡意證明者,他會想出一個 P,這個 P 滿足在 999,999 位置內的限制,但是不滿足最後一個,那麼隨機取樣僅有的幾個值,將會總是錯過那個正確的值。那麼,我們可以做什麼呢?

-多項式-

讓我們從數學上對這個問題進行一下轉化。讓 C(x) 為一個約束檢查多項式(constraint checking polynomial),如果0 <= x <= 9,C(x) = 0否則為非 0。構造C(x)有一個簡單的方式: x * (x-1) * (x-2) * … * (x-9)。

-C(x)-

現在,問題變成了:證明你知道 P,對於從 1 到 1,000,000 的所有 x,都有 C(P(x)) = 0。讓 Z(x) = (x-1) * (x-2) * … (x-1000000)。這是一個已知的數學事實,對於從 1 到 1,000,000 的所有 x,任何等於零的多項式都是 Z(x)的一個乘積。因而,問題可以被再次轉化:對於所有的 x ,證明你知道 P 和 D, 滿足 C(P(x)) = Z(x) * D(x) (注意,如果你知道一個合適的 C(P(x))),然後除以 Z(x) 來計算 D(x) 並不太難;你使用 多項式長除法 ,或基於 快速傅立葉變換 更具有實際意義更快的演算法)。現在,我們已經將原始命題轉化為一個看起來數學上更清晰,也更可證的一個問題。

那麼,要如何證明呢?我們可以把證明過程想象成證明者和驗證者之間一個三步的交流過程:

證明者傳送一些資訊
然後驗證者傳送一些請求
然後證明者再發送一些資訊
首先,證明者提交(也就是,生成一個 Merkle 樹並且將根雜湊傳送給驗證者)對於從 1 到 10 億(是的,10 億)之間的所有 x, P(x) 和 D(x) 的值. 這包含了 1 百萬個點,(滿足) 0 <= P(x) <= 9 而 9.99 億個(可能)是狀況外的點。

我們假設驗證者已經知道了 Z(x) 在所有這些點上的值;在這個方案中,Z(x) 就像是一個 公開驗證金鑰,每個人都必須提前知道(客戶端沒有儲存 Z(x) 的空間,因為它整個可能只是簡單地儲存了 Z(x) 的 Merkle 根,並需要證明者同時提供驗證者需要查詢的每個 Z(x) 值的分支;又或者,對於某個 x ,有一些在 Z(x) 之上非常容易計算的數字)。在獲得提交(也就是 Merkle 根)後,驗證者在 1 和 10 億之間隨機選擇 16 個 x 的值,並要求證明者提供這些值上 P(x) 和 D(x) 的 Merkle 分支。證明者提供這些值,驗證者檢查:

分支與之前提供的 Merkle 根相匹配
C(P(x)) 在所有 16 種情況下都等於 Z(x) * D(x)

-想象中的情形-

我們知道這個證明改善了完備性 — 如果你真的知道一個合適的 P(x),然後如果你計算 D(x)並且正確地構造出證明,那麼這 16 個檢查都將順利通過。但是 可靠性 怎麼樣呢? — 也就是,如果一個惡意證明者提供了一個壞的 P(x),他們被發現的最小概率是多少?我們可以進行如下分析:因為 C(P(x)) 是一個 1,000,000 次多項式,它的次數至多是 10,000,000。通常來說,我們知道兩個不同的 N 次多項式至多相交 N 個點。因此,對於某個 x,一個 1,000,000 次多項式,一個總是等於 Z(x) * D(x) 的任意多項式,這兩個多項式若不同,那麼將會必然在至少 990,000,000 個點上都不同。故而,即使是隻檢查一次,一個壞的 p(x) 被發現的概率已經是 99%,再加上有 16 次檢查,被發現的概率會上升到 1- 10 ^ -32。也就是說,該方案與計算雜湊衝突一樣難以欺騙。

所以,我們剛剛到底分析了些什麼?我們使用多項式“增強”了在任何不好的解決方案中的錯誤,也就是將原始問題糟糕的解決方案,即需要直接執行一百萬次檢查,變成了一個驗證協議的方案,該方案即使進行一次檢查,就能夠 99% 地標識出錯誤。

我們可以將這個三步的機制轉化為一個非互動式證明,也就是在利用 Fiat Shamir heuristic 的基礎上,一個證明者可以將它進行廣播,然後被所有人進行驗證。證明者首先構建一棵 P(x) 和 D(x) 值的 Merkle 樹,然後計算樹的根雜湊。根自身隨後被用作是熵的來源,熵決定了證明者需要提供樹的哪個分支。證明者然後一起廣播 Merkle 樹根和分支作為證明。計算全部在證明者一端完成。從資料中計算 Merkle 樹根,然後用它來挑選要審計的分支,高效地取代了一個互動式驗證者的需要。

對於一個沒有有效 P(x) 的惡意證明者,他能做的唯一事情是進入盡力不斷地構造一個有效證明,直到他們最終足夠幸運的話,找到了他們選擇計算的 Merkle 樹根分支。不過鑑於可靠性是 1 – 10 ^ -32(也就是,對於一個給定的假證明,至少有 1-10^-32 的概率無法通過檢查),這可能會耗費惡意證明者數十億年的時間來找到一個可通過檢查的證明。

進一步探究

為了闡釋這個技術的強大之處,讓我們來用它做一點不尋常的事情:證明你知道第一百萬個斐波那契數。為此,我們會證明你知道一個表示一個計算帶的多項式,而 P(x) 表示第 x個斐波那契數。約束檢驗多項式現在會跨越 3 個 x 座標:C(x1, x2, x3) = x3 - x2 - x1(注意,對於所有的 x, P(x) 表示一個斐波那契額序列,如果 C(P(x), P(x+1), P(x+2)) = 0 會怎樣)。

在這裡插入圖片描述

-斐波那契-

轉換後的問題變成了:驗證你知道 P 和 D 使得 C(P(x), P(x+1), P(x+2)) = Z(x) * D(x)。對於證明審計的 16 中情況中的每一個,證明者需要提供用於 P(x),P(x+1),P(x+2) 和 D(x) 的 Merkle 分支。證明者額外還需要提供 Merkle 分支來表明 P(0) = P(1) = 1。否則,整個過程都是一樣的。

現在,要想在現實中實現它,還需要解決兩個問題。第一個問題是,如果想要實際應用於普通數字,這個方案不夠高效,因為數字本身非常容易變的極大。比如,第一百萬個斐波那契數有 208988 位。如果我們真的想要在實踐中達到簡潔的要求,不是在普通數字上計算多項式,而是需要使用有限域(finite field) — 即仍然遵循同樣數學規則的數字系統,比如 a * (b+c) = (ab) + (ac) 和 (a^2 - b^2) = (a-b) * (a+b),但是這個數字系統中的每一個數字都保證只佔據常量空間。證明第一百萬個斐波那契數將會需要一個更加複雜的設計,這個設計在這個有限域數學之上實現大數算術。

最簡單最可能的有限域是模組化數學。也就是,對於某個質數 N,使用 a + b mod N 替換每一個 a + b 。將同時的操作應用與減法和乘法,對於除法,使用 modular inverses(比如,如果 n = 7,那麼 3 + 4 = 0,2 + 6 = 1,3 * 4 = 5,4 / 2 = 2 ,5 / 2 = 6)。你可以在 這裡 (在頁面上搜索 “prime field”)瞭解更多關於這類數字系統,在裡面我對質數域做了一些介紹。或者從有關模組化數學的 維基百科(在文章內直接搜尋 “finite fields” 和 “prime fields”,可能看起來非常複雜,與抽象代數直接相關,但是不要在意這些)瞭解更多。

第二,你可能已經注意到,在我上面的可靠性證明梗概中,我忽略了一種攻擊:不用似然的 1,000,000 次 P(x) 和 9,000,000 次 D(x),攻擊者提交另一些值,這些值不來源與任何相對低次的多項式?然後,一個無效 C(P(x)) 的引數,必須在至少 990 百萬不適用的點上不同於任何有效 C(P(x)),所以也就可能出現更多的這種有效攻擊。比如,一個攻擊者可以為每一個 x 生成一個隨機值 p,然後計算 d = C§ / Z(x) ,然後提交這些值替換 P(x) 和 D(x)。這些值不會是基於任何一種低次多項式,但是它們會通過測試。

事實證明,儘管用到的工具可能相當複雜,但上面這種可能性仍然可以進行有效地防範,現在你可以非常負責任地說,它們確實填補了 STARKs 中數學創新的空缺。不過,這個解決方法也有一個限制:雖然你可能會剔除與 1,000,000 次多項式相差甚遠(比如,你會需要改變所有值的 20% ,使它成為一個 1,000,000 次多項式)的一些資料保證(commiment to data),但是你無法排除僅在於只有一兩個座標不同的多項式資料。因此,這些工具將提供臨近證明(proof of proximity) — 證明 P 和 D 上的大多數點都與那類多項式相關。

因此,儘管有兩個“意外情況(catches)”,但是構建一個證明仍然是足夠的。首先,驗證者需要再多檢查一些情況,為其侷限性所引入的錯誤留一些餘地。第二,如果我們正在做“邊界約束檢查(boundary constraint checking)”(比如,證明上面斐波那契案例中的 P(0) = P(1) = 1),然後,我們需要擴充套件臨近證明,不僅證明大多數點都在同一個多項式上,而且證明這兩個(或你想要檢查的任何點數)特定點都在這個多項式上。

在這個系列的下一部分,我會繼續解讀臨近檢查問題的解決方案。

原文連結: http://vitalik.ca/general/2017/11/09/starks_part_1.html
作者: Vitalik Buterin
翻譯: liuchengxu
本文轉載自liuchengxu的簡書: http://www.jianshu.com/p/ffb6b475312a