
以太坊狀態的分片私密資訊檢索設計
本文提出了一種用於以太坊的分片私密資訊檢索(PIR)架構,透過將不同的數據切片與特定的 PIR 方案配對來優化性能,同時保持強大的隱私保證。
由 EF Private Reads 團隊的 Ali Atiia 與 Keewoo Lee 撰寫。
**
感謝 Ling Ren、Yue Chen、Dimitris Mouris、Will Scott、Soham、Adria、Dan、Andy、Divyá Ranjan 以及 Felix Lin 對草案提供的反饋與建議。
同時感謝 Alex Hoover、Nam、Vitalik Buterin 以及 Igor Barinov 早期對 PIR 的討論與實驗;感謝 Guillaume Ballet、Carlos Perez、Takamichi Tsutsumi 與 Tomás Arjovsky 在二元試行樹(binary tries)方面的討論與合作,以及 Leo 關於可證明的 UBT-MPT 等效性的討論。
內容摘要 (TLDR)
私密 資訊 檢索 (PIR) 可以讓以太坊用戶從遠端伺服器讀取鏈上數據,而伺服器無法得知用戶正在讀取什麼。不同的 PIR 方案具有不同的性能權衡以及用戶/伺服器開銷。另一方面,以太坊數據具有不同的更新特性,且在不同的情境下被使用,對延遲的敏感度也各不相同。
如果將以太坊數據進行分片(sharded),以便將每個數據集與其最佳 PIR 方案配對,我們就能在保持相同隱私保證的前提下,獲得比對整個以太坊狀態使用單一方案更好的整體性能——前提是用戶在進行真實查詢的同時,並行地向所有方案提交誘餌查詢(decoy queries)。
本文提出了一組以太坊狀態數據的切片,探討了 PIR 方案及將其與數據切片配對的決策樹,提出了一個分片系統的設計草圖,並觸及了一些可能進一步擴展整體系統的以太坊特定優化。
目錄
1. 簡介
以太坊用戶從遠端伺服器讀取鏈上數據,以了解並驗證感興趣的當前和歷史狀態,或構建與模擬交易。洩露讀取的內容(what)可能導致伺服器將用戶的鏈上與鏈下身份關聯起來,進而引發搶先交易(frontrunning)和其他榨取性 MEV 等問題。
「模糊讀取」(Oblivious Reads)的原語使客戶端能夠從資料庫主機伺服器讀取數據,而後者不知道正在讀取哪些數據。這與通過匿名路由實現的網路層不可連結性相結合,能為用戶帶來近乎完美的隱私。
其中一種原語是私密資訊檢索 (PIR),它允許客戶端從伺服器託管的資料庫中檢索一條分錄,而伺服器無法得知哪個分錄被訪問。一種常見構造(基於 FHE,儘管還有其他構造)的直觀原理是:客戶端的查詢被加密,伺服器處理加密查詢以產生加密響應——只有客戶端可以解密結果。
PIR 是實現模糊數據訪問的幾種方法之一,其他方法包括結合 ORAM 的受信任執行環境 (TEE+ORAM),這類方法通過硬體隔離和隱藏訪問模式來實現模糊性。TEE+ORAM 在實踐中比 PIR 快幾個數量級,但它依賴於對硬體的信任——具體來說,是信任 TEE 未被破解。我們專注於 PIR,因為它僅依賴於密碼學保證,而不依賴於硬體的可獲得性與信任。
本文提出了一個設計草圖,探討如何利用各種 PIR 方案(各有權衡)來服務不同切片的以太坊數據(各有特性),並應用於不同的使用情境(對延遲敏感度不同)。通過這種分片方法,我們可以獲得與對所有以太坊數據使用單一單體 PIR 引擎相同的隱私保證,同時保持針對每個使用情境量身定制的更好整體性能。
將以太坊數據拆分為 S 個分片,每個分片由針對其類型和訪問要求定制的 PIR 引擎提供服務,用戶查詢感興趣的引擎,但同時也向所有其他引擎提交誘餌查詢。這在隱私保護上等同於用戶向一個服務於全部鏈上數據的單體 PIR 引擎提交單個查詢。
2. 需求
-
狀態讀取的客戶端可驗證性是一項要求,這決定了 PIR 切片如何提取。例如,我們假設存儲讀取將被驗證,因此每次存儲讀取時,我們還必須讀取帳戶、Merkle 根和區塊頭。
-
「全有或全無」需求:如果除了(例如)getProof 之外的所有以太坊數據都受到 PIR 保護,那麼查詢未加密的數據就會「暴露」對加密數據的其他查詢,從而危害整體隱私。因此,必須保護所有用戶查詢的隱私。
-
向後兼容以太坊 RPC:PIR 引擎的查詢對用戶是透明的,用戶繼續使用現有的以太坊 RPC 規範查詢以太坊狀態。對於以太坊節點也是如此,它們無需修改即可響應來自同步 PIR 引擎的 RPC 調用。
-
我們僅專注於單伺服器 PIR,以避免協調非共謀方帶來的開銷。
3. 以太坊數據分片
3.1 使用情境
檢查在各種情境下查詢的區塊鏈數據類型(下圖)可以發現,幾乎所有類型的數據在所有情境中都會被查詢。
當我們考慮錢包和前端查詢背後的常見意圖時,這就很合理了:
-
我的餘額是多少? \rightarrow 狀態 (帳戶標頭 (ETH) 或合約存儲 (ERC* 代幣))
-
我是否收到了 ERC20 轉帳,或者我的 DeFi 存款是否成功 (cTokens) \rightarrow 收據 (Receipts)
-
我的交易是否已確認/最終確定? \rightarrow 區塊 或 交易
-
此地址的交易歷史是什麼? \rightarrow 存檔(歷史)區塊 或 交易,且指定的 blockNumber 早於最近的 128 個區塊。
讀取相關的 RPC 調用 (點擊查看更多細節)
3.2 以太坊狀態的數據切片
對 PIR 性能影響最大的因素是:
-
資料庫大小
-
更新頻率。
另一方面,某些用戶查詢非常頻繁且對延遲敏感:
-
我的餘額是多少?
-
我的匯入或匯出交易是否已被包含?
而其他查詢則頻率較低且/或對延遲較不敏感:
-
我的交易歷史是什麼:通常隱藏在錢包的多次點擊或前端的分頁/進一步點擊之後。
-
我能否獨立驗證我的餘額:驗證中依賴於內部(非數值)節點的部分,可以容忍由輕客戶端在後台運行。
-
我的餘額變動歷史是什麼:用於資產組合或會計目的。前者對於資產組合前端可能對延遲敏感,並且由於此類數據源自「巨大(Huge)」數據集(見下文)而代表一項挑戰。對於會計 dApp,這可以容忍高延遲,因為用戶習慣於會計/稅務計算需要較長時間。
考慮到這些不同的數據類型(例如可變 vs 僅追加)和情境:
下圖顯示了以太坊活動狀態和歷史狀態的一個切片示例,旨在根據此類頻率和敏感度指標進行隔離。
當我們考慮到我們可以修剪掉大量「死」狀態(例如 nonce 為 1 的古老帳戶、僅為了 Gas 退稅而部署的「垃圾」合約(在 SELFDESTRUCT 被去勢之前的時代)、已創建但從未被訪問的合約等)時,下面切片中的估算值可能會有所波動:
總體而言,上圖中的切片涵蓋了以太坊執行層(EL)的所有熱數據和存檔狀態數據。
「中型(Medium)」和「大型(Large)」切片特別具有挑戰性,因為它們體積龐大且頻繁變動。這可以通過按狀態樹的每一層進一步進行「水平」切片來適應。
「巨大(Huge)」數據集中的高更新頻率是指每個區塊向存檔狀態追加新的快照。這可以通過 5.2 節討論的主引擎+邊車設計,以及 8.4 節討論的存檔狀態潛在 SNARK 化來解決。
4. 私密資訊檢索 (PIR)
如簡介部分所述,PIR 是本文關注的私密讀取原語。
兩個範圍說明:
-
對稱 PIR (SPIR) 額外向客戶端隱藏資料庫內容——僅顯示被查詢的分錄。由於以太坊數據本質上是公開的,資料庫隱私在此並非需求,因此 SPIR 不在討論範圍內。
-
關鍵字 PIR (Keyword PIR)。標準 PIR 是基於索引的:客戶端通過其想要的分錄的數值索引進行查詢。關鍵字 PIR 允許通過鍵(例如以太坊地址)而非索引進行查詢,重要的是,其性能取決於資料庫的大小,而非關鍵字空間的大小。存在一種通過布穀鳥雜湊(cuckoo hashing)將索引 PIR 轉換為關鍵字 PIR 的通用變換。在實踐中,關鍵字 PIR 是更自然的介面——用戶通過地址查詢並接收餘額,而不是通過行號——因此在本文的其餘部分,我們簡稱為「PIR」,並默認關鍵字 PIR 是預期的訪問模式。
4.1 分類法
PIR 方案在許多維度上都有所不同——通信成本、單次查詢計算量等。我們在此根據其狀態架構進行分類:狀態存在於何處(客戶端、伺服器或兩者),以及它是如何建立的。這為為特定應用選擇合適方案提供了一個清晰且實用的視角。
客戶端無狀態 (Client-stateless) 方案要求客戶端在查詢之間不存儲任何內容。所有預處理都在伺服器端完成。當資料庫更新時,客戶端不受影響——僅伺服器重新進行預處理。在此類別中:
-
伺服器有狀態 (Server-stateful) 方案(例如 SealPIR、MulPIR、Spiral、Respire、VIA-C)要求伺服器緩存每個客戶端的密碼學材料,如 FHE 評估密鑰。伺服器的存儲空間隨客戶端數量增長,且每次查詢必須與正確的密鑰匹配——這使得來自同一客戶端的查詢在不同對話中具有可連結性,即使使用洋蔥路由等網路層隱私技術隱藏了客戶端的 IP。此類方案中的資料庫預處理成本通常極低(例如僅進行 FHE 明文編碼)。
-
伺服器無狀態 (Server-stateless) 方案(例如 HintlessPIR、YPIR、InsPIRe、VIA)完全不需要每個客戶端的狀態。伺服器將資料庫預處理成一個所有客戶端共享的結構。這是運作上最簡潔的類別。權衡之處在於:與伺服器有狀態方案相比,預處理成本往往更高,且在線通信量通常更大。然而,在此類別的前沿方案中,單次查詢的伺服器計算量通常表現更好。
客戶端有狀態 (Client-stateful) 方案要求客戶端下載或計算源自資料庫內容的「提示」(hints)。這些提示可以實現更快、更低通信量的在線查詢——但當資料庫更新時,提示會過時並必須刷新,這需要伺服器與客戶端之間的通信。子分類取決於提示生成期間的通信方向:
-
下載提示 (Download-hint) 方案(例如 SimplePIR、DoublePIR):提示生成僅限於伺服器→客戶端。伺服器計算提示材料並廣播;客戶端下載並本地存儲。
-
交互式提示 (Interactive-hint) 方案(例如 Piano、RMS24、Plinko):提示生成需要客戶端↔伺服器通信。通常,客戶端流式傳輸整個資料庫並將其壓縮成較小的提示。這是最繁瑣的設置,但在實用方案中,它是唯一實現次線性(伺服器不必觸及資料庫中的每個分錄)在線伺服器時間的方案——其擴展速度慢於資料庫大小。(原則上,客戶端在提示生成中的角色可以封裝在 FHE 下並委託給伺服器,但目前這在實踐中似乎過於昂貴。)
4.2 運作特性
| 類別 | 子類別 | 伺服器端每客戶端狀態 | 預處理成本 (伺服器) | 預處理成本 (客戶端) | 可連結性 | 示例 |
|---|---|---|---|---|---|---|
| 客戶端無狀態 | 伺服器有狀態 | 評估密鑰等 | 極小 (FHE 打包) | 無 | 是 | SealPIR, MulPIR, Spiral, Respire, VIA-C |
| 伺服器無狀態 | 無 | 中等 (客戶端共享) | 無 | 否 | HintlessPIR, YPIR, InsPIRe, VIA | |
| 客戶端有狀態 | 下載提示 | 通常無 | 中等 (客戶端共享) | 中等 (下載提示) | 否 | SimplePIR, DoublePIR |
| 交互式提示 | 通常無 | 中等 (每客戶端) | 通常沉重 (流式傳輸全庫) | 通常否 | Piano, RMS24, Plinko |
4.3 性能基準對比
下圖顯示了一組 PIR 方案示例以及用於探索其性能權衡的典型指標:
**
5. PIR 系統架構
5.1 分片
以太坊的邏輯切片具有不同的消費者特徵和情境,體積大小不一,且可能是熱數據且可變,或冷數據且不可變。
我們將這些數據屬性與 PIR 性能權衡相結合,構建一個自定義的分片私密讀取後端,該後端隱藏在穩定的介面(不受更換引擎/數據集的影響)之後,供不同的客戶端接入:錢包 [SDK]、前端、dApp 和節點。
關鍵觀察:考慮一個維護 k 個資料庫 d_1, d_2, \ldots, d_k 的伺服器。客戶端希望訪問其中一個資料庫(例如 d_i),同時隱藏其正在訪問哪一個。為此,客戶端按某種順序發出 k 個查詢 q_1, q_2, \ldots, q_k。查詢 q_i 是針對 d_i 的真實 PIR 查詢,而其餘查詢 { q_j }{j \ne i} 是誘餌查詢。每個查詢 q_j 落在託管資料庫 d_j 的引擎 n_j 上;每個引擎獨立處理其查詢並向客戶端返回響應。在這種構造下,產生的隱私保證等同於將 { q_1, \ldots, q_k } 中的一個或多個提交給託管整個資料庫 D = \bigcup{j=1}^{k} d_j 的單個引擎。當查詢並行處理時,這種方法具有性能優勢:如果目標資料庫 d_i 相對較小,與對整個資料庫 D 應用單體 PIR 相比,客戶端可以以更低的延遲獲得所需的響應。此外,在某個資料庫 d_j 顯著大於其他資料庫的情況下,總通信成本和總伺服器工作量仍與單體方法相當。
安全說明:定時側信道
[(點擊查看更多細節)](https://ethresear.ch/t/sharded-pir-design-for-the-ethereum-state/24552/1)
5.2 處理資料庫更新
(預處理)PIR 中的一個核心矛盾:伺服器和/或客戶端投入大量的預先工作——伺服器可能在資料庫上預計算數據結構,客戶端可能流式傳輸整個資料庫以將其處理成緊湊的提示——以實現快速、低通信的在線查詢。當底層資料庫發生變動時,這些預計算的結構和提示就會過時,必須重新推導。對於以太坊來說,狀態樹每 ~12 秒變化一次,如果預處理針對整個數據集,這是難以承受的。
我們根據資料庫的更新特性對其進行分類,並為每種情況提出架構策略。
更新問題的維度
我們從兩個維度描述每個資料庫的更新特性:
-
更新頻率(相對於資料庫大小)。更新發生時重新預處理的成本有多高?小型資料庫或更新罕見的資料庫可以簡單地重新運行預處理;大型且每個區塊都更新的資料庫則不行。
-
流失率 (Churn ratio)。每次更新中被修改的資料庫比例。僅追加數據(日誌、交易、收據)是低流失率的一種特殊情況——添加新分錄但不更改現有分錄。
這些維度產生了三種情況:
情況 1:每次更新的重新預處理成本較低
每次更新重新運行預處理不是主要問題。
這涵蓋了體積較小(無論頻率如何,重新預處理都很便宜)或體積較大但很少變動(重新預處理不頻繁)的資料庫。
| 以太坊示例 | 大小 | 更新頻率 | 為何適用 |
|---|---|---|---|
| 合約字節碼 | 小 | 從不 | 小 + 不可變 |
| 最新區塊頭 | 小 | 每個區塊 | 足夠小,每區塊重新預處理很便宜 |
| 存檔狀態快照 | 大 | 從不 (歷史) | 一旦最終確定即不可變 |
架構: 直接預處理。每次更新時重新預處理——這在經濟上是可行的,因為資料庫要麼很小(每次重新運行很便宜),要麼更新不頻繁(很少重新運行)。不需要特殊的更新機制。
情況 2a:更新頻率相對於資料庫大小較高,高流失率
無法避免重新運行預處理。盡量降低其成本。
當資料庫很大、更新頻繁且每次更新有很大比例的分錄發生變化時,增量方法幾乎無法節省成本——大多數提示無論如何都會失效。這種情況在以太坊中很少見(即使在峰值負載下,狀態流失也僅佔總樹的一小部分),但在其他領域可能會出現。
關鍵約束:避免使用客戶端有狀態 PIR 方案。 如果重新預處理不可避免且頻繁,客戶端依賴的預處理會加重雙方的負擔:客戶端必須在每次更新時重新完成其預處理工作,伺服器必須為每個客戶端重新完成每客戶端工作。兩者在高更新頻率下擴展性都很差。
情況 2b:更新頻率相對於資料庫大小較高,低流失率
這包括僅追加的情況。使用帶有延遲重新預處理的邊車架構。
資料庫很大且更新頻繁,但每次更新只有很小比例的分錄發生變化。現有提示大多仍然有效——我們只需要處理更新的分錄。
| 以太坊示例 | 大小 | 更新頻率 | 流失率 | 為何適用 |
|---|---|---|---|---|
| 活動狀態樹 | 大 | 每個區塊 | 低 (數十億個鍵中約數千個) | 大資料庫,頻繁更新,極小變更集 |
| 交易、日誌、收據 | 大 | 每個區塊 | 低 (僅新分錄) | 大資料庫,頻繁追加,無變動 |
| Blobs | 大 | 每個區塊 | 低 (僅新分錄) | 同上,且具有有限保留期 |
5.3 架構 — 邊車模式 (Sidecar pattern)
主 PIR 引擎託管大部分數據,並在某個參考快照處進行預處理。一個小型邊車 PIR 引擎託管自上次快照以來發生更改的鍵的完整更新分錄。為了回答查詢,客戶端並行查詢兩者:
-
主引擎用於基礎快照(使用預處理提示——快速、低通信)。
-
邊車引擎用於更新的分錄(資料庫很小,因此即使是非預處理方案在此也很便宜)。
由於邊車持有完整值,客戶端可以在邊車響應到達後立即使用它——如果查詢的鍵已更新,答案是自包含的,客戶端無需等待主引擎。只有當鍵在邊車中不存在時,客戶端才回退到主引擎的響應。
定期(延遲地——例如每 E 個區塊,或當邊車增長超過閾值時),邊車的分錄會併入主資料庫並重新運行預處理。然後重置邊車。關鍵屬性:重新預處理在後台以寬鬆的速度進行,不在每次更新的關鍵路徑上。 邊車吸收了實時更新壓力。在合併期間,舊的主引擎繼續服務查詢,同時構建新的預處理版本。一旦就緒,客戶端切換過來,邊車重置以僅累積自新快照以來更新的分錄。
對於僅追加資料庫,邊車甚至更簡單:它僅持有新分錄。主引擎的提示永遠不會失效,因此重新預處理主引擎純粹是為了吸收邊車累積的分錄,以保持邊車體積微小。
安全說明:**
重新預處理在各個資料庫之間必須保持一致——如果客戶端重新預處理了一個資料庫而沒有預處理另一個,這種差異可能會洩露它真正目標的是哪一個。
6. PIR 方案選擇
第 4 節中的分類法根據結構屬性對 PIR 方案進行了分類。下面的決策樹將其反轉:給定資料庫及其消費者的特徵,哪一組方案最合適?
7. 通用 PIR 介面
在以太坊情境下,任何 PIR 系統都必須適應兩個現實:
-
邊緣端(錢包、前端、dApp 等)必須能夠繼續使用與現在完全相同的以太坊 RPC 調用來表達其查詢。
-
PIR 後端必須能夠持續演進而不影響邊緣端:更換方案、更改數據切片、更改鍵到索引的適配器等。
挑戰在於建立一個中間件,通過清晰的抽象來滿足這兩個要求,使得任何一方的更改都不會影響另一方。中間件本身應該只感知一個抽象的 PIR 介面,該介面由每個 PIR 方案(引擎)具體實現。
一種可行的方法:
-
定義一個固定的 GraphQL Schema,因為以太坊狀態的結構和語義基本不變(特別是在 UBT 升級之後)。
-
實現一個位於規範 RPC 處理邏輯和 Schema 之間的客戶端適配器。在實際操作中,這將封裝客戶端現有的 RPC 處理邏輯。
關鍵考量:
-
適配器在邊緣端如何以及在哪裡集成。一個吸引人的選擇是在少數錢包 SDK 中(前端也會集成這些 SDK),這樣眾多集成的邊緣客戶端就無需承擔任何負擔。
-
如何處理需要客戶端依賴預處理的 PIR 方案,以及預處理邏輯和相關存儲如何與適配器緊密耦合。
下圖勾勒了一個粗略的設計(細節留待以後的文章討論)。
8. 持續研究與優化
8.1 用於 Merkle 樹的 PIR
(點擊查看更多細節)
8.2 可驗證的 UBT > MPT (點擊查看更多細節)
8.3 隔離可變性 (點擊查看更多細節)
8.4 將存檔狀態 SNARK 化以減小資料庫體積 (點擊查看更多細節)
8.5 在交互式提示方案中委託提示生成
(點擊查看更多細節)
8.6 具體高效的 DEPIR
(點擊查看更多細節)
9. 資源
-
規範 / 參考代碼: RMS24 & Plinko
-
文獻中報告的基準測試: Benchmarks
-
實作: Plinko RMS24 [InsPIRe] [2] [3] OnionPIRv2 Piano CwPIR DistributionalPIR DoublePIR FastPIR FrodoPIR HintlessPIR NPIR Pirouette Respire SealPIR SimplePIR Spiral XPIR YPIR
-
本文引用的 PIR 方案: SealPIR, MulPIR, Spiral, Respire, HintlessPIR, YPIR, InsPIRe, VIA, VIA-C, SimplePIR, DoublePIR, Piano, RMS24, Plinko
1 則貼文 - 1 位參與者 [閱讀完整主題](https://ethresear.ch/t/sharded-pir-design-for-the-ethereum-state/24552)