基於零知識證明的PoR原理與實現
- 資產審計
電路(circuit)定義及說明
BatchCreateUser電路是用於操作帳戶樹和對每個賬戶的數據進行集合,電路的定義如下:
1.輸入:
(1).公共輸入:
group_commitment:總承諾哈希值。
(2)秘密輸入:
preSmt_root:當前這個批次的默克樹的樹根值。
nextSmt_root:將當前這個批次的用戶進行操作之後的默克樹的樹根值。
pre_cex_commitment:當前這個批次的使用者,交易所的所有資產的承諾值(哈希)。
next_cex_commitment:在當前這個批次的用戶進行操作之後,交易所的所有資產的承諾值(哈希)。
Pre_cex_asset:當前這個批次的使用者,交易所的所有的幣種資產清單。
totalCex_Asset:所有幣種折u相加得到的總的交易所資產。
Uesr_Instructions:一組用戶的資訊表。
△asset:單個用戶的資產清單
△totalEquity:使用者的折U凈資產
△totalDebt:使用者的折U總負債
△account_index:使用者的索引
△account_idhash:用戶的葉子結點的哈希值
△account_proof:用戶葉子結點的證明路徑
2.約束
(1) group_commitment與preSmt_root,nextSmt_root,pre_cex_commitment,next_cex_commitment計算出的哈希相等。
(2)通過Pre_cex_asset來計算出pre_cex_commitment,兩個哈希值相等。
(3)preSmt_root等於Uesr_Instructions中第一個元素的preSmt_root的值。
(4)nextSmt_root等於Uesr_Instructions中最後一個元素的nextSmt_root值。
(5)通過totalCex_Asset計算出totalCexEquity和totalCexDebt,範圍屬於「0,2^64」,且equit大於Debt。
(6)通過after_asset_list算出next_cex_commitment,這兩個next_cex_commitment相等。
(7)每個使用者的資產大於其負債,保證每個使用者的凈資產折U大於0。
(8)使用者葉子結點哈希結合默克爾路徑計算出的根哈希和nextSmt_root相等
(9)nextSmt_root等於下一組使用者的preSmt_root。
當所有的使用者都被操作完成後,我們將得到一系列的證明:[proof_0, proof_1, ..., proof_n],同樣也有一組承諾:[group_commitment_0, group_ commitment_1, ..., group_commitment_n]和[cex_commitment_0, cex_commitment_1, ..., cex_commitment_n],同時還有一組根哈希值:[SMT_root_0, SMT_root_1, ..., SMT_ root_n]。 所以這些資訊都會發佈出來,任何使用者都可以進行下載,並進行驗證。
如何計算witness
Witness 服務用於為 Prover 服務產生生成 witness,作為 Prover 生成證明的輸入,最終生成的 witness 輸入數據保存在 mysql 中。 在生成 witness 時,考慮到龐大用戶數和資產數量,我們對用戶數據進行了分批計算,對單個使用者的資產數據以稀疏向量的形式進行存儲以節省存儲空間,在從 mysql 表中讀取當前批次的 witness 數據時再進行向量稠密化處理,對齊數據維度,以便於進行後續計算。
用於計算 witness 的數據舉例如下所示(該數據為每月定期某時刻取出的用戶資產快照數據):
Index |
UID |
Btc_balance |
Eth_balance |
... |
Total_Equity |
Total_Debt |
0 |
Id1 |
0.00000032 |
0 |
|
0.008672 |
0 |
1 |
Id2 |
0.00000031 |
0 |
|
0.009716 |
0 |
2 |
Id3 |
0 |
0 |
|
0.00108 |
0 |
其中使用者的所有資產的 balance 列表示使用者對應幣種的凈資產數量,total_equity 表示使用者所有幣種資產的折U總價格,total_debt 表示使用者所有幣種債務的折U總價格。 在計算時,交易所單個幣種的總資產數量由用戶對應幣種資產數量累加得到,在後續設計證明電路時通過相應的約束保證這一計算過程的正確性來防止作弊。 由於儲備金證明採用的零知識證明演算法只能在有限域上進行計算,對於浮點數的處理我們統一採用了乘法因數來進行擴大並對餘下精度予以截斷處理來進行數據的規範化。
在管理所有使用者賬戶數據時,採用了稀疏默克爾樹的樹形數據結構來對帳戶數據進行管理(如上圖所示)。 稀疏默克爾樹和標準默克爾樹的區別是其中的數據是有序的(對應於前表中的Index),比如Index為0,3的使用者A、D一定在上圖中最下方對應的第0個(最左)和第3個葉子節點(最右),如果Index為1、2的使用者B、C在交易所中沒有資產數據(僅註冊帳戶沒有資產),其在稀疏默克爾樹中的位置依舊是固定的。 這樣的設計便於快速校驗某個使用者是否存在或不存在於證明過程中,使得證明方案更為嚴謹。
在 witness 數據的計算中需要頻繁進行hash運算而hash演算法的複雜性會在零知識證明的電路中引入大量約束。 為了在保證安全的前提下加速證明計算過程,我們在數字承諾的計算中採取了零知識證明友好的hash函poseidon hash 來用於hash計算,其結構如下圖所示。 通過hash函數的優化可以在保證證明安全的前提下將計算複雜度減少到原來的1/8。
如何進行Prover 及verifier
HTXHTX通過使用keygen程式生成的r1cs電路以及pk,vk檔,生成所需要的proof檔並將其保存在資料庫中,讓用戶能夠下載並進行verify。
運行方式:保證當前工作目錄在zkmerkleverify下面,也就是src的上層目錄下面。
(1)當只使用一台主機開啟prover服務的時候,使用如下指令來使用prover服務:
當prover 正常運行后,最後輸出顯示:
(2)當使用多台主機開啟prover服務的時候,所有主機都保證在上面所說的工作目錄下,然後使用同樣的指令:
當所有主機的這個指令結束之後,都會有下面的輸出:
使用如下命令:
來檢測是否還有沒有運行完的prover程式,如果有就將其運行完成,當該程式正常運行后,最後輸出顯示:
Verifier工具使用說明
HTXHTX使用提供verifier服務為使用者提供自行驗證PoR驗證服務以及userproof驗證服務。 客戶使用prover服務生成的proof表格以及vk進行PoR驗證和userproof驗證。 其中,PoR驗證是我們的零知識資產證明驗證,userproof是我們的零知識默克爾樹驗證,用戶可以通過如下位置進行下載:
使用方式:
要進行用戶驗證,只需下載審計資料 (公開),並將下載的 public-data.zip 檔案解壓縮為一個資料夾,裡面包含三個檔案:config.json、proof0.csv、zkpor500.vk.save,並將此資料夾保存在一個目錄中。接著前往 https://github.com/huobiapi/Tool-Go-MerkleVerify/releases/tag/2.0.0,按照您使用的作業系統下載相應的執行程式 (這裡以 macOS 為例)。將下載的 zkverifier-macos-x64.zip 解壓縮並儲存至前述步驟的同個目錄中,結構如下圖所示:
在「終端機」中使用如下的指令來進行 POR 驗證:
當 macOS 第一次執行該指令時,可能會出現如下所示的錯誤訊息:
只需前往「系統設定 > 隱私權與安全性 > 安全性」,並按一下「App Store 和已識別的開發者」即可。
或是打開「終端機」輸入如下指令:
sudo spctl --master-disable
執行時,驗證程式會檢查目前目錄下是否含有名為 public-data 的目錄,並選擇其中一個目錄進行讀取。針對選取的目錄,驗證程式會如下所示顯示其路徑: (如果無法讀取到最新下載的目錄,請刪除先前下載的目錄)
若驗證成功,會顯示:
在使用默克爾驗證前,用戶需先點按如下圖所示的按鈕,下載審計資料 (私人):user_config.json:
下載後,將審計資料 (私人) 放入 POR 驗證目錄,目錄結構如下所示:
在「終端機」中使用如下的指令來進行默克爾驗證:
若驗證成功,會顯示:
若用戶想要從頭開始執行完整流程,可以按照 README 中的步驟使用 GitHub 上的程式進行作業。
具體的數學原理可以參考《為什麼要使用零知識證明來做儲備金證明?》。