幾個星期前摹闽,我看了看Filecoin的代碼宏邮,整理了Filecoin的一些概念颜曾,架構以及協(xié)議 -Filecoin邏輯梳理及源代碼導讀纠拔。
PoRep以及PoSt的數(shù)據(jù)存儲證明是通過FPS模塊實現(xiàn)。整個FPS模塊是通過Rust語言實現(xiàn)泛豪。技術人總是想打破沙鍋問到底稠诲,究竟PoRep/PoSt的證明過程如何?我就從源代碼的角度诡曙,講述一遍數(shù)據(jù)證明的邏輯調(diào)用部分臀叙。方便其他小伙伴理解或者優(yōu)化相關的邏輯。有關零知識證明的推導代碼岗仑,后續(xù)文章詳細介紹匹耕。
01 Filecoin代碼模塊依賴關系
從PoRep以及PoSt存儲證明的角度來看,F(xiàn)ilecoin代碼模塊由如下三層組成:
rust-fil-proofs是存儲證明的具體實現(xiàn)荠雕,通過Rust語言實現(xiàn)稳其。rust-fil-proofs模塊依賴bellman項目(零知識證明)。bellman項目是ZCash項目使用的零知識證明模塊炸卑。bellman項目也是用Rust語言實現(xiàn)既鞠。在go-filecoin的rustverifier.go文件實現(xiàn)go到rust語言的調(diào)用。
在該導讀中盖文,go-filecoin代碼的最后一個commit信息如下:
commit b716be02c0e15436141a5c20274a38aec749490e (HEAD -> master, tag: nightly-13394-b716be, origin/master, origin/HEAD)
Author: Sidney Keese sidke.z@gmail.com
Date: ? Wed Mar 27 14:06:13 2019 -0700
? use precompiled bls-signatures library (#2368)
rust-fil-proofs代碼的最后一個commit信息如下:
commit 808dc884642acbf7b78b282eb7d933c7cc2cc3a7 (HEAD -> master, origin/master, origin/HEAD)
Author: wayne yang wayne.w.yang@foxmail.com
Date: ? Mon Mar 25 21:12:40 2019 +0800
? ?docs: delete the outdated link
02 rust-fil-proofs的框架
rust-fil-proofs功能主要由四個子模塊組成:
filecoin-proofs實現(xiàn)了filecoin存儲證明的接口嘱蛋,依賴其他兩個模塊:storage-proofs(存儲證明的邏輯)和 sector-base (數(shù)據(jù)存儲的接口)。這兩個模塊又依賴于storage-backend模塊實現(xiàn)數(shù)據(jù)的存儲五续。
相關代碼就在這四個目錄中:
03 PoRep的生成和驗證邏輯
PoRep就是Proof of Replicate洒敏,數(shù)據(jù)存儲證明。模塊之間的調(diào)用關系如下:
node.go代碼在啟動挖礦時疙驾,每120個區(qū)塊調(diào)用一次SealAllStagedSectors函數(shù)(將所有的Staged的Sector數(shù)據(jù)進行Seal)凶伙。順便說一句,用戶的數(shù)據(jù)存儲時分成一個個的Sector(目前設置為256M)它碎。Sector有三個狀態(tài):Staging(數(shù)據(jù)還未寫滿函荣,并且未超時),Staged(數(shù)據(jù)已經(jīng)寫滿或者超時)扳肛,Sealed(數(shù)據(jù)已經(jīng)Seal并存儲)傻挂。
在filecoin-proof模塊接收到請求后,確認目前所有的Staged的Sector挖息,并對每個Sector進行Seal金拒。
核心邏輯在rust-fil-proofs/filecoin-proofs/src/api/internal.rs代碼的seal函數(shù)。seal函數(shù)原型如下:
seal函數(shù)對in_path的原始數(shù)據(jù)套腹,進行復制并存儲到out_path殖蚕。在seal的過程中轿衔,提供Sector的屬性沉迹,證明人的id以及Sector的id睦疫。
3.1?Replica ID
對每一個Seal過的Sector,設置一個Replica ID鞭呕。Replica ID是一個Hash值蛤育,計算過程如下:
相應實現(xiàn)是rust-fil-proofs/storage-proofs/src/porep.rs的replica_id函數(shù)。
3.2?整體邏輯
PoRep的生成邏輯包括兩部分:1/數(shù)據(jù)的復制(replicate)2/數(shù)據(jù)的復制證明葫松。Step1/Step3實現(xiàn)復制的證明瓦糕,Step2實現(xiàn)數(shù)據(jù)的復制。
貼一段代碼腋么,方便小伙伴比對和理解:
3.3?數(shù)據(jù)復制邏輯
PoRep算法的全稱是ZigZag-DRG-PoRep咕娄。整體流程示意如下:
Sector中未Seal的原始數(shù)據(jù)首先依次分成一個個小數(shù)據(jù),每個小數(shù)據(jù)32個字節(jié)珊擂。這些小數(shù)據(jù)之間按照DRG(Depth Robust Graph)建立連接關系圣勒。按照每個小數(shù)據(jù)的依賴關系,通過VDE(Verifiable Delay Encode)函數(shù)摧扇,計算出下一層的所有小數(shù)據(jù)圣贸。整個PoRep的計算過程分為若干層(目前代碼設置為4層),仔細觀察每一層的DRG關系的箭頭方向扛稽,上一層向右吁峻,下一層就向左,因此得名ZigZag(Z字型)在张。
VDE以及ZigZag設置的參數(shù)查看rust-fil-proofs/filecoin-proofs/src/api/internal.rs:
每一層的計算邏輯示意如下:
每一層的輸入稱為d(data)用含,每一層的VDE的結果稱為r(replica)。對每一層的輸入帮匾,建構默克爾樹啄骇,樹根為comm_d, 整個樹的數(shù)據(jù)結構稱為tree_d。對每一層的輸出辟狈,建構默克爾樹肠缔,樹根為comm_r,整個樹的數(shù)據(jù)結構稱為tree_d哼转。
再介紹兩個術語:TAU明未,AUX。
TAU: 希臘字母壹蔓,一棵或者多棵Merkle樹的樹根都稱為TAU趟妥。
AUX: Auxiliary的簡稱,一棵或者多棵Merkle樹的結構稱為AUX佣蓉。
對于一層replica來說披摄,TAU包括comm_d和comm_r亲雪,AUX包括tree_d和tree_r。
對于整個PoRep來說疚膊,也就是多層replica來說义辕,TAU以及AUX示意如下:
其中的comm_r_star是每層comm_r的數(shù)據(jù)和replica id數(shù)據(jù)Hash的結果。
具體實現(xiàn)的源代碼請看兩個函數(shù):
rust-fil-proofs/storage-proofs/src/layered_drgporep.rs中的Layers的replicate函數(shù)
rust-fil-proofs/storage-proofs/src/drgporep.rs中的PoRep的replicate函數(shù)
3.4?復制證明邏輯
復制數(shù)據(jù)完成后寓盗,需要提供零知識的證明灌砖。該證明邏輯需要花很多篇幅仔細介紹,涉及到QAP傀蚌,KCA基显,Groth16,同態(tài)隱藏善炫,雙線性映射撩幽。后續(xù)的文章會詳細講解相關邏輯。本文先有些概念:需要生成證明(Proof)需要有兩步:setup以及prove箩艺。
setup:設置證明的參數(shù)
prove:提供需要證明的內(nèi)容窜醉,包括公共數(shù)據(jù)(public inputs),私有數(shù)據(jù)(private inputs)以及Groth的參數(shù)舅桩。在2.b中的代碼中可以看出酱虎,
PoRep證明的公共數(shù)據(jù)包括原始數(shù)據(jù)的comm_d,最后一層的comm_r和comm_r_star擂涛。
PoRep證明的私有數(shù)據(jù)包括所有層的comm_r/comm_d和每一層的tree_r/tree_d读串。
值得特別提出的是,PoRep提交到Filecoin區(qū)塊鏈上的數(shù)據(jù)是:PoRep的公共數(shù)據(jù)和復制證明數(shù)據(jù)撒妈。
整個數(shù)據(jù)復制的過程時間比較長恢暖,目前1G的數(shù)據(jù)需要消耗40~50分鐘。
3.5?復制驗證邏輯
在某個存儲礦工生成PoRep后狰右,通過CommitSector接口向區(qū)塊鏈提交證明信息杰捂。在Filecoin區(qū)塊鏈的所有礦工接收到CommitSector的Message交易時,調(diào)用VerifySeal進行復制驗證棋蚌,大體流程如下:
具體實現(xiàn)的源代碼請查看rust-fil-proofs/storage-proofs/src/api/internal.rs的verify_seal函數(shù)嫁佳。
04 PoSt的生成和驗證邏輯
在一個存儲礦工存儲(Seal)用戶數(shù)據(jù)后,每隔20000個區(qū)塊谷暮,必須提供一次PoSt(Proof of Space Time)的證明蒿往,也就是說,某個存儲礦工還存有用戶數(shù)據(jù)的證明湿弦。20000個區(qū)塊瓤漏,一個區(qū)塊30秒,也就說每6天提交一次證明。
4.1?PoSt生成邏輯
PoSt的生成是基于最近的存儲狀態(tài)蔬充,所以提交PoSt的證明最好能在一個區(qū)塊之內(nèi)(30秒)完成蝶俱。PoSt生成邏輯的調(diào)用關系如下:
在新的區(qū)塊生成時(OnNewHeaviestTipSet函數(shù)),每個提供存儲的礦工會檢查是否需要提供PoSt的證明饥漫。如果需要榨呆,則調(diào)用generatePoSt函數(shù)生成證明。
generatePoSt函數(shù)提供兩個參數(shù):所有提交到區(qū)塊鏈上的comm_r信息以及隨機挑戰(zhàn)信息 (ChallengeSeed)趾浅。所有提交到區(qū)塊鏈上的comm_r信息通過區(qū)塊鏈查詢可以獲取愕提。ChallengeSeed通過currentProvingPeriodPoStChallengeSeed函數(shù)生成,生成邏輯如下:
簡單的說皿哨,就是從當前區(qū)塊高度往前看幾個TipSet,找出某一個TipSet中眾多區(qū)塊中的最小Ticket纽谒。該Ticket就是ChallengeSeed证膨。
在最新的代碼邏輯中,PoSt每兩個Sector會生成一個Proof鼓黔,也就是post_adapter實現(xiàn)的邏輯央勒。提交到區(qū)塊鏈上的是眾多Proof的列表。
VDFPostCompound::setup函數(shù)設置驗證相關參數(shù)澳化。VDFPostCompound::prove函數(shù)需要四個參數(shù):
a. setup函數(shù)設置的參數(shù)
b. Public數(shù)據(jù)(comm_r的數(shù)據(jù)列表崔步,隨機挑戰(zhàn)信息)
c. 私有數(shù)據(jù)(Seal數(shù)據(jù)構成的Merkle樹的結構信息)
d. Groth相關的參數(shù)信息
具體實現(xiàn)的源代碼請查看rust-fil-proofs/storage-proofs/src/api/internal.rs的generate_post_fixed_sectors_count函數(shù)。
prove函數(shù)實現(xiàn)的邏輯就是白皮書中的PoSt的框架圖:
4.2?PoSt驗證邏輯
在某個存儲礦工生成PoSt證明后缎谷,通過SubmitPoSt接口向區(qū)塊鏈提交證明信息井濒。在Filecoin區(qū)塊鏈的所有礦工接收到SubmitPoSt的Message交易時,調(diào)用VerifyPoST進行復制驗證列林,大體流程如下:
具體實現(xiàn)的源代碼請查看rust-fil-proofs/storage-proofs/src/api/internal.rs的verify_post_fixed_sectors_count函數(shù)瑞你。
總結:PoRep是對某個Sector數(shù)據(jù)存儲的證明,每個Sector一次希痴。PoSt是一系列已經(jīng)Seal過的Sector的存儲證明者甲,每隔一段時間一次。兩個證明的核心是Groth16零知識驗證算法砌创,基于Bellman項目虏缸。