中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

circom/snarkjs實戰zk rollup的示例分析

發布時間:2021-12-13 21:26:30 來源:億速云 閱讀:233 作者:柒染 欄目:互聯網科技

今天就跟大家聊聊有關circom/snarkjs實戰zk rollup的示例分析,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

過去的一年出現了很多零知識證明應用,在這個教程中,我們將首先學習零知識證明的基本概念、使用circom搭建算術電路、使用snarkjs實現零知識證明的全過程,并利用這些知識實現二層擴容方案zk rollup。

零知識程序和其他程序的實現不太一樣。首先,你要解決的問題需要先轉化成多項式,再進一步轉化成電路。例如,多項式x3 + x +5 可以表示成如下的電路:

sym_1 = x * x // sym_1 = x2 
sym_2 = sym_1 * x // sym_2 = x3 
y = sym_2 + x // y = x3 + x 
~out = y + 5

Circom編譯器將邏輯轉換為電路。通常我們不需要自己設計基礎電路。如果你需要一個哈希函數或簽名函數,可以在circomlib 找到。

2、證據的生成與驗證:零知識證明的流程

在運行零知識證明程序之前,我們需要創建一個可信的設置,這需要 一個電路以及一些隨機數。一旦設置完成就會生成一個證明密鑰和一個驗證密鑰,分別用于生成證據和執行驗證。

circom/snarkjs實戰zk rollup的示例分析

一旦創建了證明/驗證密鑰對,就可以生成證據了。

有兩種類型的輸入:公開輸入和私有輸入。例如,A向B轉賬但是不希望公開賬戶余額,那么A的賬戶余額就是私有輸入,也被稱為見證(Witness)。公開輸入可以是A和B的地址或者轉賬金額,這完全取決于你的具體設計。

接下來證明人就可以利用證明密鑰、公開輸入和見證來生成證據:

circom/snarkjs實戰zk rollup的示例分析

最后一步是驗證。驗證方使用公開輸入、證據和驗證密鑰來驗證證據。

circom/snarkjs實戰zk rollup的示例分析 公開輸入、見證(私有輸入)、證明密鑰、驗證密鑰、電路、證據這些基本概念以及相互之間的關系,就是我們繼續下面的教程之前需要理解的零知識證明的基本概念。

3、Circom基本概念:算術電路語言

首先我們先了解下Circom的語法。Circom的語法類似javascript和C,提供一些基本的數據類型和操作,例如for、while、>>、array等。

讓我們看一個具體的實例。

假設x、y是保密的(即witness),我們不想暴露x和y的具體值,但是希望證明 (x * y) + z == out,其中z,out是公開輸入。我們假設out = 30, z = 10, 那么顯然 (x*y) = 20,但是這不會暴露x和y的具體值。

circom提供了如下這些關鍵字用于描述算術電路:

  • signal:信號變量,要轉換為電路的變量,可以是private或public

  • template:模板,用于函數定義,就像Solidity中的function或golang中的func

  • component:組件變量,可以把組件變量想象成對象,而信號變量是對象的公共成員

Circom也提供了一些操作符用于操作信號變量:

  • <==, ==>:這兩個操作符用于連接信號變量,同時定義約束

  • ←, →:這些操作符為信號變量賦值,但不會生成約束條件

  • ===:這個操作符用來定義約束

好了,這些就是我們繼續零知識證明實踐需要了解的circom關鍵字。

4、用circom和snarkjs實現零知識證明應用的全流程

STEP 1:編譯電路文件,生成circuit.json:

circom sample1.circom

STEP 2:創建可信設置,使用groth協議生成proving_key.json和verification_key.json

snarkjs setup — protocol groth

STEP 3:生成見證(私有輸入)。這一步需要輸入,因此應當將你的輸入存入input.json,就像下面這樣:

// input.json
{“x”:3, “y”:5, “z”: 100}

使用下面的命令生成見證文件witness.json:

snarkjs calculatewitness

STEP 4:使用如下的snarkjs命令生成證據:

snarkjs proof

結果是得到proof.json、public.json。在public.json中包含了公開輸入,例如:

// public.json
{
  “115”, // → out
  “100” // → z:100
}

STEP 5:使用如下snarkjs命令進行驗證:

snarkjs verify

5、零知識證明實踐案例:zk rollup實現

zk rollup是一個二層解決方案,不過它和其他的二層方案不同。zk roolup將所有數據放在鏈上,使用zk-snark進行驗證。因此,不需要復雜的挑戰游戲。在zk rollup中,用戶的地址記錄在智能合約的merkle樹上,使用3字節的索引來表征用戶的地址(地址的原始大小是20字節),因此zk rollup可以通過減小數據大小來增加交易吞吐量。

為了便于理解,在下面的zk rollup實現中,我們有意忽略一些細節,原始的zk rollup教程可以參考 ZKRollup Tutorial。

首先,有一個記錄賬號的merkle樹,賬號記錄的內容是(公鑰,余額)。每個交易的內容是(發送方索引、接收方索引、金額)。流程如下:

1、檢查發送方賬號是否在merkle樹上 2、驗證發送方的簽名 3、更新發送方的余額并驗證中間merkle根 4、更新接收方的余額并更新merkle根

circom電路程序的變量定義如下:

// account tree
signal input account_root;
signal private input account_pubkey[2];
signal private input account_balance;  

// new account root after sender's balance is updated
signal private input new_sender_account_root;  

// tx
signal private input tx_sender_pubkey[2]
signal private input tx_sender_balance
signal private input tx_amount
signal private input tx_sender_sig_r[2]
signal private input tx_sender_sig_s
signal private input tx_sender_path_element[levels]
signal private input tx_sender_path_idx[levels]
signal private input tx_receiver_pubkey[2]
signal private input tx_receiver_balance
signal private input tx_receiver_path_element[levels]
signal private input tx_receiver_path_idx[levels]

// output new merkle root
signal output new_root;

在這個案例中幾乎所有的變量都是私有的,不管是公鑰、賬戶余額還是簽名等等,只有merkle根和更新后的merkle根是公開的。path_element是構建merkle根的中間值,path_idx是一個索引數組,用于保存merkle樹每一層的索引 —— 這時一個二叉樹,因此只有左右兩個分支,0表示左,1表示右。最終的路徑像一個二進制字符串:001011。

下面的circom代碼檢查發送方是否存在:

//__1. verify sender account existence
component senderLeaf = HashedLeaf();
senderLeaf.pubkey[0] <== tx_sender_pubkey[0];
senderLeaf.pubkey[1] <== tx_sender_pubkey[1];
senderLeaf.balance <== account_balance; 

component senderExistence = GetMerkleRoot(levels);
senderExistence.leaf <== senderLeaf.out; 

for (var i=0; i<levels; i++) {
   senderExistence.path_index[i] <== tx_sender_path_idx[i];
   senderExistence.path_elements[i] <== tx_sender_path_element[i];
}

senderExistence.out === account_root;

上面的代碼也比較簡單,哈希發送方的公鑰和賬戶余額,用merkle樹的中間值計算,然后得到merkle根(senderExistence.out)。檢查計算得到的merkle根和輸入是否一致(account_root)。

出于簡化考慮,我們省略了merkle樹和哈希函數的實現,你可以查看HashedLeaf和GetMerkleRoot。

下面的circom代碼檢查發送方的簽名:

//__2. verify signature
component msgHasher = MessageHash(5);
msgHasher.ins[0] <== tx_sender_pubkey[0];
msgHasher.ins[1] <== tx_sender_pubkey[1];
msgHasher.ins[2] <== tx_receiver_pubkey[0];
msgHasher.ins[3] <== tx_receiver_pubkey[1];
msgHasher.ins[4] <== tx_amount
    
component sigVerifier = EdDSAMiMCSpongeVerifier(); 
sigVerifier.enabled <== 1;
sigVerifier.Ax <== tx_sender_pubkey[0];
sigVerifier.Ay <== tx_sender_pubkey[1];
sigVerifier.R8x <== tx_sender_sig_r[0];
sigVerifier.R8y <== tx_sender_sig_r[1];
sigVerifier.S <== tx_sender_sig_s;
sigVerifier.M <== msgHasher.out;

就像區塊鏈交易需要驗證發送方的簽名一樣,在上面的代碼中,我們首先哈希消息然后進行簽名,然后調用不同的封裝函數。

更新發送方余額并檢查新的merkle根。

//__3. Check the root of new tree is equivalent
component newAccLeaf = HashedLeaf();
newAccLeaf.pubkey[0] <== tx_sender_pubkey[0];
newAccLeaf.pubkey[1] <== tx_sender_pubkey[1];
newAccLeaf.balance <== account_balance - tx_amount;

component newTreeExistence = GetMerkleRoot(levels);
newTreeExistence.leaf <== newAccLeaf.out;
for (var i=0; i<levels; i++) {
 newTreeExistence.path_index[i] <== tx_sender_path_idx[i];
 newTreeExistence.path_elements[i] <== tx_sender_path_element[i];
} newTreeExistence.out === new_sender_account_root;

前面的兩個步驟從發送方的角度檢查信息,然后更新發送方的余額并計算新的merkle根。最下面一行:newTreeExistence.out === new_sender_account_root;作用是檢查計算得到的merkle根和輸入(new_sender_account_root)是否一致。通過這個檢查,可以避免偽造或不正確的輸入。

下面的代碼更新接收方余額以及merkle樹:

//__5. update the root of account tree
component newReceiverLeaf = HashedLeaf();
newReceiverLeaf.pubkey[0] <== tx_receiver_pubkey[0];
newReceiverLeaf.pubkey[1] <== tx_receiver_pubkey[1];
newReceiverLeaf.balance <== tx_receiver_balance + tx_amount;

component newReceiverTreeExistence = GetMerkleRoot(levels);
newReceiverTreeExistence.leaf <== newReceiverLeaf.out;
for (var i=0; i<levels; i++) {
newReceiverTreeExistence.path_index[i]<==tx_receiver_path_idx[i];
newReceiverTreeExistence.path_elements[i] 
<==tx_receiver_path_element[i];
}

new_root <== newReceiverTreeExistence.out;

最后一步更新接收方余額,計算并輸出新的merkle根。一旦電路構建好,就像一個黑盒子。如果你輸入正確的值,那么輸出一定是正確的,因此用戶容易檢查以避免惡意中間人。這就是為什么我們需要在電路最后輸出一些東西的原因 —— 在這個案例里我們輸出的是merkle根。

看完上述內容,你們對circom/snarkjs實戰zk rollup的示例分析有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

札达县| 合山市| 封开县| 鄂托克前旗| 垣曲县| 新乡市| 临泽县| 岳普湖县| 澎湖县| 遂宁市| 浦北县| 沈丘县| 沛县| 通海县| 龙海市| 曲麻莱县| 镇雄县| 屏南县| 女性| 漳浦县| 邢台县| 龙岩市| 拉萨市| 本溪| 香港| 三江| 江城| 清镇市| 涪陵区| 凤山县| 南岸区| 梁山县| 怀宁县| 吉林市| 卓尼县| 岗巴县| 都昌县| 宽甸| 无为县| 容城县| 龙门县|