Bulletproofs 詳解:隱藏的金額如何被驗證

· 6 分鐘閱讀

Bulletproofs 是一種簡短的零知識範圍證明,它讓加密貨幣能夠隱藏每一筆交易金額,同時每個節點仍能檢查沒有憑空產生新幣。本文講解 Pedersen 承諾、隱藏的金額為什麼需要範圍證明、Bulletproofs 如何讓這些證明保持精簡,以及 Blocknet 如何在每個輸出上使用它們。

什麼是 Bulletproofs?

簡短回答

Bulletproofs 是一種簡短的零知識證明,由 Bünz、Bootle、Boneh、Poelstra、Wuille 與 Maxwell 於 2018 年發表。在加密貨幣中,它證明一個隱藏的金額位於有效範圍內,例如 0 到 2^64,而不透露這個金額。它不需要可信設定,證明大小只隨範圍的對數成長。

這篇論文 Bulletproofs: Short Proofs for Confidential Transactions and More 發表於 2018 年的 IEEE 安全與隱私研討會(IEEE Symposium on Security and Privacy)。作者為機密交易設計了它:在機密交易中,區塊鏈上的金額被替換為承諾。要理解為什麼需要這樣的證明,先從承諾說起。

什麼是 Pedersen 承諾?

承諾是密封信封的密碼學版本。你把一個數字放進去,把信封展示給所有人,之後可以證明裡面裝的是什麼。沒有人能從信封上讀出這個數字,你事後也無法換成另一個數字。

Pedersen 承諾由 Torben Pedersen 在 1991 年提出,它用橢圓曲線上的點來實現這一點。要對金額 v 做承諾,錢包會選一個隨機秘密 r,稱為盲化因子,然後計算:

C = v·G + r·H

G 與 H 是曲線上兩個固定的公開點,其選取方式確保沒有人知道如何把其中一個寫成另一個的倍數。結果 C 是一個 32 位元組的點。它有兩個性質:

節點如何檢查一筆它讀不懂的交易?

簡短回答

Pedersen 承諾可以相加。兩個承諾之和就是對兩個金額之和的承諾,盲化因子也隨之相加。節點把一筆交易的輸入承諾加總,再把輸出承諾加上手續費加總,檢查兩個總數是否相等,這樣不必看到任何金額就能確認收支平衡。

兩個承諾相加得到 (v1 + v2)·G + (r1 + r2)·H,它本身就是對 v1 + v2 的承諾。發送方會安排好盲化因子,使輸入的盲化因子總和等於輸出的總和。如果金額也平衡,輸入之和與輸出之和的差就恰好為零,任何節點都能驗證這一點。

網路手續費是交易中唯一公開的數字。節點把它轉換成盲化因子為零的承諾,加到輸出一側,於是檢查式就是:輸入 = 輸出 + 手續費。

隱藏的金額為什麼需要範圍證明?

承諾的運算是對一個非常大的數取模進行的,這個數就是曲線群的階,約為 2^252。在這種運算中,「負數」金額其實就是一個巨大的正數。有人可以花掉一個價值 10 個幣的輸入,建立兩個輸出,一個價值 11,一個價值「負 1」。承諾會完全平衡,於是 1 個幣憑空出現,而且所有觀察者都看不到。

範圍證明補上了這個漏洞。它證明承諾中的金額位於 0 到 2^64 之間,而不說出具體是多少。每個輸出都受到這樣的約束後,幾個輸出相加永遠不可能大到繞過群的階,因此承諾平衡就代表金額平衡。

早期的機密交易設計使用的範圍證明隨位元數線性成長。Bulletproofs 只隨位元數的對數成長,使一個 64 位元證明縮小到幾百位元組。

Bulletproofs 是如何運作的?

一個 Bulletproof 分三步證明一個範圍。

  1. 把金額拆成位元。 一個 64 位元金額變成一個由 64 個位元構成的向量。證明者對這個向量做承諾,並證明它的兩個事實:每一項都是 0 或 1,而且這些位元按 2 的冪加權後的和等於被承諾的金額。
  2. 把這些事實變成一個內積。 藉助隨機挑戰,證明者把所有這些條件摺疊成一個關於兩個向量內積的命題。由於挑戰是隨機的,一個虛假的命題只能以可忽略的機率通過。
  3. 透過減半來證明內積。 每一輪,證明者送出兩個曲線點 L 與 R,兩個向量都摺疊成原來一半的長度。經過 log2(64) = 6 輪後,只剩下一對數字。

證明的大小正是來自這種減半。論文摘要指出,對 n 位元的範圍,一個範圍證明只需 2·log2(n) + 9 個群元素與體元素。對 64 位元來說,就是六輪產生的 12 個點再加 9 個元素,共 21 個元素;每個元素 32 位元組時,總共 672 位元組。

這種證明是非互動式的。不需要驗證者即時送出挑戰,雙方都透過對證明紀錄做雜湊來推導挑戰,這是一種稱為 Fiat-Shamir 啟發式的標準技術。Bulletproofs 也不需要可信設定:生成元是公開的,推導過程也是公開的,安全性只依賴離散對數假設。多個證明可以聚合,只增加對數數量的元素,驗證也可以批次進行。

哪些專案使用 Bulletproofs?

Monero 在 2018 年 10 月 18 日的網路升級(v0.13.0 版本)中啟用了 Bulletproofs,以縮小交易大小。dalek-cryptography 專案的 Rust bulletproofs 函式庫 在 Curve25519 的 Ristretto 群上實作了它,Blocknet 的密碼學函式庫正是以這個函式庫為基礎建構的。

Blocknet 如何隱藏每一筆金額?

在 Blocknet 上,每筆交易的每個輸出都用 Pedersen 承諾取代金額,而且每個輸出都帶有自己的 64 位元 Bulletproof。隱私是交易格式的一部分,沒有透明模式,所以無法發送金額可見的付款。

節點在接受一筆交易之前會檢查以下內容:

你可以在 Blocknet 區塊瀏覽器上看到這一切。交易頁面把金額標為 “hidden · Pedersen commitments”,每個輸出都顯示它的承諾、一段加密備註,以及大小為 “672 bytes · Bulletproof” 的範圍證明,正是上面計算得出的大小。

接收方仍然能看到真實的金額。每個輸出都帶有用發送方與接收方錢包共享的秘密加密的金額,接收方的錢包用私有檢視金鑰解密它。金額只對付款雙方可見,其他人都看不到。

隱藏金額與 Blocknet 的其他隱私層協同運作:16 個輸出的環簽章隱藏發送方,一次性隱身地址隱藏接收方,Dandelion++ 隱藏交易進入網路的位置。Blocknet 隱私功能指南逐一介紹了每一層。

取得屬於你自己的私密 BNT

想取得金額隱藏的幣,一個簡單的方法就是挖礦。Blocknet 使用記憶體密集型的 Argon2id 工作量證明,一般電腦就能挖。seine 在你的 CPU 上挖礦,同時可以讓 NVIDIA 顯示卡一起挖,而且不需要任何設定就會自動調校。bntpool.com 發給你的每筆收益,都會以帶有承諾與 Bulletproof 的私密輸出入帳。挖礦指南帶你在幾分鐘內從下載走到份額被接受。

常見問題

Bulletproofs 需要可信設定嗎?

不需要。Bulletproofs 只依賴離散對數假設,也就是橢圓曲線簽章所依賴的同一個假設,並使用任何人都能推導出來的公開參數。它沒有設定儀式,也沒有事後必須銷毀的秘密。包括 Monero 與 Blocknet 在內的隱私幣都用它來做範圍證明。

Bulletproofs 範圍證明有多大?

一個 64 位元的 Bulletproof 包含 2 × log2(64) + 9 = 21 個元素。在 Ristretto 群上每個元素佔 32 位元組,所以每個證明都是 672 位元組,Blocknet 區塊瀏覽器對每個輸出顯示的正是這個大小。證明大小隨範圍的對數成長,所以位元數加倍只多出兩個元素。

誰能看到一筆 Blocknet 交易的金額?

只有發送方與接收方。鏈上為每個輸出儲存一個 Pedersen 承諾和一個範圍證明,以及用雙方錢包共享的秘密加密的金額。接收方的錢包用私有檢視金鑰解密它。網路手續費是唯一公開的數字,這樣節點才能把它計入餘額檢查。

金額都隱藏了,節點怎麼知道沒有憑空造幣?

每個節點會對每筆交易檢查兩件事。Pedersen 承諾必須能對上帳,也就是輸入等於輸出加手續費;每個輸出都必須帶有有效的範圍證明,證明其金額在 0 到 2^64 之間。兩者結合,就能在不洩露任何金額的情況下排除隱藏的增發。