做者:林冠宏 / 指尖下的幽靈html
掘金:juejin.im/user/587f0d…git
博客:www.cnblogs.com/linguanh/github
GitHub : github.com/af913337456…網絡
騰訊雲專欄: cloud.tencent.com/developer/u…函數
蟲洞區塊鏈專欄:www.chongdongshequ.com/article/153…源碼分析
PS:本人技術書籍:《區塊鏈以太坊DApp開發實戰》已經出版並能夠網購了post
在這篇文章中,我將承接上一篇文章 詳細講解:零知識證實 之 zk-SNARK 開篇 (開篇中介紹了什麼是零知識證實及其它術語) 來從一個完整的交易流程
講解 ZCash
是如何利用零知識證實
的zk-SNARK
實現匿名交易的。區塊鏈
其中第六
部分 收款人如何獲取 note 的使用權
是目前國內網上全部的介紹 ZCash
的文章都沒有談及的,形成了讀者只知道交易的發出
,而不知道交易是憑藉什麼機制讓收款人有權限使用的
。加密
此外,"如今關於 ZCash 的文章和回答,不少都不許確,甚至是有誤導性的!"
此話---引自 woodstock.net
文章不從源碼分析的角度去展開,那樣的寫做和閱讀成本過高。
首先 ZCash
在交易的總體模式上,參考了 BTC
的 UTXO
模型,擁有交易輸入和交易輸出的概念,對於 UTXO
的講解,能夠自行網上搜索文章進行閱讀,目前介紹 UTXO
的優秀文章仍是不少的。
UTXO
是一種模型,模型是能夠被以不一樣的形式展示出的。在 ZCash
中,交易原始的輸入輸出結構體被形象成了代碼中的 note
結構體。
一個完整的 note
包含有以下的變量:
nullifier
表中,表明這條 note 已經被消費了,再次進行消費同一條 note的時候,會觸發雙花
錯誤,即交易雙花防禦機制。用向量組表明上面的 note,能夠表示爲:note = <a_pk , v , r , rho>
在 ZCash
中,存在兩種表格,分別是:commitment
和 nullifier
,下圖取自於 ZCash
的官方文檔 How Transactions Between Shielded Addresses Work 中,提示
:該文章內部並無指出 note 的收款人是如何對一筆 note 有使用權限的,看完也會有不少疑問。
圖中顯示出了 commitment
和 nullifier
表格的大體結構:
左邊的 hashed notes
就是 commitment
列表,右邊的 nullifier set
就是 nullifier
列表。
commitment
列表存儲的是全部的,注意!是全部。存儲全部 note 通過不可逆 hash 函數後生成的 hash 值 Hx
x∈ (1,2,3,4,5,6...N)
nullifier
列表存儲的是已經被消費
的 note 中的隨機數 r
生成的 hash 值 nfx
。r 就是 note 結構中的 r。nullifier
中文意思:做廢
,nullifier set
做廢集合。
注意一點
:對於兩個不一樣的 note,他們的 commitment hash 值必定不相同,從 hash 值又沒法推測出其背後的 note.。
如上圖所示,在右邊咱們能夠看到 r2 對應的 note2 的 nf1 已經被記錄到了 nullifier
列表中,這個 nf1 就是結構體中的 rho。被記錄到了這裏,表明着 note2 再也不是 UTXO
,再也不是沒被花費的輸出,它已經被消費了。
一條被花費的輸出 output
會致使一條新產生的交易輸入 input
。繼續以上圖爲例子,note2 做爲被消費了的輸出,據表能夠, note3 應該是它所產生的交易的輸入,此時 note3 還沒被消費,由於它的 nf3 還沒被記錄到 nullifier
列表。note2 相對於 note3 來講,note2 是 note3 的輸入。note3 做爲一條新的交易輸入,還沒輸出給其它的 note。
在認識交易被髮出前的操做,咱們現來認識下 ZCash 1.0
的公私鑰機制,下圖取自於官方文檔:
下面我將講解下這圖的主要要表達的意思,上面我列舉的 note ,是一個總體的講解,在實際的 ZCash
源碼中,note 其實還分爲兩種,分別是:SproutNote
和 SaplingNote
。目前 ZCash
使用的是第一種,本文所談的也是 SproutNote
。ZCash
的發展將會慢慢向第二種 SaplingNote
遷移。
由於 note 結構中有一個 a_pk 字段,在SproutNote
和 SaplingNote
中,內部的字段組成是不一樣的,源碼的定義以下圖所示:
SaplingNote
中,明顯 a_pk 不見了,多了其它的。回到下圖,咱們主要看左邊的 Sprout
,其中:
下圖的Sprout
中 a_sk 表明的是私鑰,由 a_sk 能夠生成第一個公鑰 a_pk
和 私鑰 sk_enc
,由 sk_enc 能夠生成第二個公鑰pk_enc
。意味着:
在ZCash 1.0 中,一個錢包地址裏面包含由兩個公鑰:a_pk , pk_enc
如今進行到轉帳人發出交易 note,假設轉帳人是A,收款人是B,A 要轉 5 個幣個B。
那麼 A 組裝 note 的過程以下:
UTXO
輸出,每條 note 中有對應的 value,咱們假設一條就足夠轉出,多條的狀況是若是一條 note 沒法知足目標轉出 value,纔會湊多條 note 做爲輸出。私鑰 sk_enc
解密 note 1,獲取 note 1 中的 value 和其它數據,假設 value 是8,此時8 > 5
。找零
解析見UTXO
模型介紹。PS: ( rho = nf = HASH (r) )
note4 = <B的a_pk ,v=5,r4,rho4>
note5 = <A的a_pk ,v=3,r5,rho5>
nf2=HASH (r1)
) 發往公鏈的節點網絡,即 note 1 的 rho,此時節點在收到 nf2 後會判斷是否已經在 nullifier
列表存在 nf2 了,是的話,那麼判斷 note 1 被雙花了。不然,就將 note 1 的 nf2 記錄下來了。發起交易
的流程。commitment
和 nullifier
表變成了以下的樣子。note hashs(commitments) | nullifier set |
---|---|
h1=HASH (note1) | nf1 = HASH (r2) |
h2=HASH (note2) | nf2 = HASH (r1) |
h3=HASH (note3) | |
h4=HASH (note4) | |
h5=HASH (note5) |
其實在上面小節中,讀者應該能理會到 B 是可使用本身的原始私鑰 a_sk 對本身獲取到的 note4 數據進行解密的,進而獲取到裏面的 <a_pk,v,r,rho>,到了這一步,B 保存好 note4 的 rho,那麼他就可以向 nullifier
表發送 note4 的 rho ,達到消費 note4 的目的。
至此,ZCash 的匿名交易流程造成了閉環
。
那麼爲何 a_sk
能對 sk_enc
簽名的數據,進行解密呢?由於在 ZCash 1.0 中,由地址的公私鑰生成規則,可知原始私鑰 a_sk 能夠導出 sk_enc。在ZCash 1.0 的公私鑰機制
小節中也作了說明。
答:對於 note 的全部權擁有者A 來講,好像除了公佈 note 裏面的內容外,好像沒其它手段來自我證實?這個時候零知識證實
就排上用場了,note 的擁有者在發佈使用該 note 的時候還要向節點出示稱爲 Π
的零知識證實憑據,根據 Π ,節點們做爲驗證者,可以驗證 note 的使用權的確屬於A。ZCash 在這裏應用到了零知識證實
,它的代碼是根據zk-SNARK
理論完成的,同時也參考了 Zerocash
。
答:不在本文的討論範圍內,詳細能夠見官方完整的文檔:完整文檔 的第4章
,關於 Balance 的描述。
爲了理清 ZCash 的匿名交易的最後一部分,也便是收款人是如何得到 note 的全部權的,使整個流程造成閉環
。
我查閱了不少文章都、文檔和諮詢了一位網友已經查看了部分源碼。目前網上的其它文章都沒有講到 收款人如何獲取 note 的使用權
這一部分。稍微較好的是對官方文檔 在隱藏地址之間如何進行交易的直接作了翻譯,可是因爲官方的這篇文章是個簡版,也沒有對 收款人如何獲取 note 的使用權
作出解析,因此,幾乎全部的翻譯文章都是沒答案的,並且大部分文章,自己還有一些錯誤,可能做者本身也只知其一;不知其二。
感謝下面的人和文給予了我有用的信息引導:
文: