1. Lotus整體模組
簡單的說,Lotus/Filecoin專案由三部分組成:
1/ Lotus Blockchain部分 - 實現區塊鏈相關邏輯(共識演算法,P2P,區塊管理,虛擬機器等等)。注意的是,Lotus的區塊鏈相關的資料儲存在IPFS之上。go語言實現。
2/ RUST-FIL-PROOF部分 - 實現Sector的儲存以及證明電路。也就是FPS(Filecoin Proving Subsystem)。Rust語言實現。
3/ Bellman部分 - 零知識證明(zk-SNARK)的證明系統,主要是基於BLS12_381橢圓曲線上,實現了Groth26的零知識證明系統。Lotus官方推薦採用Nvidia的2080ti顯示卡,也主要做這部分的效能加速。Rust語言實現。
這篇文章,主要介紹第二部分(也就是Sector的儲存以及證明)的核心邏輯。
2. Stacked DRG
解釋具體的邏輯之前,介紹一下兩個基本術語:一個是Stacked DRG,一個是Sector。Sector相對比較簡單,就是一次資料處理的單位。知道硬碟結構的小夥伴都知道,硬碟的最小的儲存單元就叫“Sector”。Lotus採用的Sector的比較大,目前測試網路採用的是32G。
Stacked DRG是Sector資料處理的演算法。對儲存資料進一定的處理,並進行相應的證明是為了說明儲存服務方,確實如實地儲存了一些資料,而不是造假(攻擊)。Filecoin很早之前採用的是“Zig Zag DRG”演算法。可能因為太複雜(太慢),Lotus採用的是“簡化”的Stacked DRG演算法。兩種演算法的區別示意如下:
有兩點需要說明:
1/ Stacked DRG的每個節點以及每層之間不採用Zig Zag的依賴關係。也就是說,每個節點和其他節點的依賴關係是固定的。
2/ 在每層(Layer)之間增加節點的依賴關係。
3. Sector處理(Precommit)過程
Sector處理,也就是傳說中的precommit階段,主要由如下的資料處理組成:
a. 針對原始資料構造默克爾樹tree_d(sha256),樹根為comm_d。
b. Label & Encode計算:
原始資料,每32個位元組,稱為一個Node。每128M分為一個Window。32G的Sector有256個Window。每個Window,按照Stacked DRG演算法,生成4個layer的資料。從上一個Layer,透過Encode計算生成下一個Layer的資料。Encode計算,目前就是模加操作。將Window的編號和Stacked DRG的節點關係透過sha256演算法,生成“key”。將Key和原始資料進行模加生成Encode計算的結果。
c. Layer4的生成資料,構造默克爾樹tree_q(pedersen),樹根為comm_q。Layer4的生成資料,再經過一層exp的依賴關係,構造默克爾樹tree_r_last(pedersen),樹根為comm_r_last。
d. Column Hash計算
Layer4的256個Window的資料中,同一位置上的Node,拼接在一起,hash後生成Column Hash的結果。注意,Column Hash的計算結果只有一個Window大小。針對Column Hash的計算結果,構造默克爾樹tree_c,樹根為comm_c。
需要上鍊的資料是以上所有的默克爾樹的樹根:comm_d以及comm_r。其中comm_r是(comm_c|comm_q|comm_r_last)的pedersen hash的結果 。
核心程式碼在rust-fil-proofs/storage-proofs/src/stacked/proof.rs的transform_and_replicate_layers函式中。感興趣的小夥伴,可以根據下面的呼叫關係檢視具體的程式碼。
4. Sector證明(Commit)過程
在Sector處理後,需要對處理後的資料進行“證明”,畢竟不能把所有處理後的資料全部提交到區塊鏈上。Lotus使用Bellman的零知識證明庫,採用Groth26演算法進行資料處理的證明。
RUST-FIL-PROOF(FPS)實現了StackedCompound,專門用來實現Stacked DRG的資料處理證明。StackedCompound,將兩部分整合在一起,一部分是電路(Stacked Circuit),另一部分是Stacked Drg,實現電路資料的準備。這些部分又分成一個個的子功能(Window,Wrapper,ReplicaColumn等等)。在呼叫Bellman生成證明時,相應電路的synthesize介面就會被呼叫,從而完成整個電路生成R1CS的過程。
話說,Lotus的Sector的資料證明證明了什麼呢?Lotus的資料證明了如下的事實:
1/ 結合鏈上生成的隨機數,隨機挑選50個處理後資料Node,也就是在replica(複製資料)中,隨機挑選50個Node資料。
2/ 證明這些資料是從原始資料一步步處理生成的。而且,能構造出之前處理過程中生成的4個默克爾樹的樹根。
3/ 重複步驟1和2,10次。
步驟1/2的證明,如下圖所示:
簡單的說,從鏈上獲取了隨機資訊後(和區塊高度有關),隨機選擇了500個處理後的Node資料,並證明這些資料是透過Stacked DRG演算法從原始資料計算而來。並且,這些資料能構成之前遞交到鏈上的四個默克爾樹的樹根。
Lotus的電路邏輯比較複雜,電路規模達到了1億。證明生成的時間也非常長。
5. Sector證明鏈上驗證
提交到鏈上的資料包括:comm_d,comm_r以及proof證明資料。鏈上的miner智慧合約會驗證提交的證明是否正確:
func ValidatePoRep(ctx context.Context, maddr address.Address, ssize uint64, commD, commR, ticket, proof, seed []byte, sectorID uint64) (bool, ActorError)
具體的程式碼在lotus/chain/actors/actor_miner.go檔案。其中ticket和seed就是鏈上提供的隨機資訊。驗證過程就是RUST-FIL-PROOF模組呼叫Bellman驗證零知識證明是否正確。驗證過程比較快,毫秒級的計算。相對來說,儲存證明的生成過程時間比較長,有比較大的提升空間。
總結:
Lotus(蓮花),採用Stacked DRG演算法對儲存的資料進行處理,並採用Groth26零知識證明演算法對資料處理過程進行證明。Lotus的零知識證明,證明了隨機抽選的500個節點資料是正確地透過Stacked DRG演算法生成,並能生成指定的默克爾樹的樹根。Lotus的電路邏輯比較複雜,電路規模達到了1億,證明生成時間比較長。整個計算效能有很大的提升空間。